Example #1
0
    def step(self):
        """ 'step' to the next state of the game
        Returns a new gamestate object that represents current state of the game"""
        # Keep looping until we get a REPLAY message
        self.processingtime = time.time() - self._frametimestamp
        gamestate = GameState(self.ai_port, self.opponent_port)
        frame_ended = False
        while not frame_ended:
            msg = self._slippstream.read_message()
            if msg:
                if CommType(msg['type']) == CommType.REPLAY:
                    events = msg['payload']['data']
                    frame_ended = self.__handle_slippstream_events(events, gamestate)

                # We can basically just ignore keepalives
                elif CommType(msg['type']) == CommType.KEEPALIVE:
                    pass

                elif CommType(msg['type']) == CommType.HANDSHAKE:
                    handshake = msg['payload']
                    print("Connected to console '{}' (Slippi Nintendont {})".format(
                        handshake['nick'],
                        handshake['nintendontVersion'],
                    ))
                # Handle menu-state event
                elif CommType(msg['type']) == CommType.MENU:
                    events = msg['payload']['data']
                    self.__handle_slippstream_menu_event(events, gamestate)
                    frame_ended = True

        self.__fixframeindexing(gamestate)
        self.__fixiasa(gamestate)
        # Start the processing timer now that we're done reading messages
        self._frametimestamp = time.time()
        return gamestate
Example #2
0
    def step(self):
        # Keep looping until we get a REPLAY message
        self.processingtime = time.time() - self._frametimestamp
        gamestate = GameState(self.ai_port, self.opponent_port)
        frame_ended = False
        while not frame_ended:
            msg = self.slippstream.read_message()
            if msg:
                if (CommType(msg['type']) == CommType.REPLAY):
                    events = msg['payload']['data']
                    frame_ended = self.__handle_slippstream_events(
                        events, gamestate)
                    # Start the processing timer now that we're done reading messages
                    self._frametimestamp = time.time()
                    continue

                # We can basically just ignore keepalives
                elif (CommType(msg['type']) == CommType.KEEPALIVE):
                    print("Keepalive")
                    continue

                elif (CommType(msg['type']) == CommType.HANDSHAKE):
                    p = msg['payload']
                    print("Connected to console '{}' (Slippi Nintendont {})".
                          format(
                              p['nick'],
                              p['nintendontVersion'],
                          ))
                    continue

        self.__fixframeindexing(gamestate)
        self.__fixiasa(gamestate)
        return gamestate
Example #3
0
    def step(self):
        """ 'step' to the next state of the game and flushes all controllers

        Returns:
            GameState object that represents new current state of the game"""
        self.processingtime = time.time() - self._frametimestamp

        # Flush the controllers
        for controler in self.controllers:
            controler.flush()

        if self._temp_gamestate is None:
            self._temp_gamestate = GameState()

        frame_ended = False
        while not frame_ended:
            message = self._slippstream.dispatch(self._polling_mode)
            if message:
                if message["type"] == "connect_reply":
                    self.connected = True
                    self.nick = message["nick"]
                    self.version = message["version"]
                    self.cursor = message["cursor"]

                elif message["type"] == "game_event":
                    if len(message["payload"]) > 0:
                        if self.is_dolphin:
                            frame_ended = self.__handle_slippstream_events(
                                base64.b64decode(message["payload"]),
                                self._temp_gamestate)
                        else:
                            frame_ended = self.__handle_slippstream_events(
                                message["payload"], self._temp_gamestate)

                elif message["type"] == "menu_event":
                    if len(message["payload"]) > 0:
                        self.__handle_slippstream_menu_event(
                            base64.b64decode(message["payload"]),
                            self._temp_gamestate)
                        frame_ended = True

                elif self._use_manual_bookends and message[
                        "type"] == "frame_end" and self._frame != -10000:
                    frame_ended = True
            else:
                return None

        gamestate = self._temp_gamestate
        self._temp_gamestate = None
        self.__fixframeindexing(gamestate)
        self.__fixiasa(gamestate)
        # Start the processing timer now that we're done reading messages
        self._frametimestamp = time.time()
        return gamestate
Example #4
0
    def __init__(self,
                 path=None,
                 is_dolphin=True,
                 dolphin_home_path=None,
                 tmp_home_directory=True,
                 slippi_address="127.0.0.1",
                 slippi_port=51441,
                 online_delay=2,
                 blocking_input=False,
                 polling_mode=False,
                 allow_old_version=False,
                 logger=None):
        """Create a Console object

        Args:
            path (str): Path to the directory where your dolphin executable is located.
                If None, will assume the dolphin is remote and won't try to configure it.
            dolphin_home_path (str): Path to dolphin user directory. Optional.
            is_dolphin (bool): Is this console a dophin instance, or SLP file?
            tmp_home_directory (bool): Use a temporary directory for the dolphin User path
                This is useful so instances don't interfere with each other.
            slippi_address (str): IP address of the Dolphin / Wii to connect to.
            slippi_port (int): UDP port that slippi will listen on
            online_delay (int): How many frames of delay to apply in online matches
            blocking_input (bool): Should dolphin block waiting for bot input
                This is only really useful if you're doing ML training.
            polling_mode (bool): Polls input to console rather than blocking for it
                When set, step() will always return immediately, but may be None if no
                gamestate is available yet.
            allow_old_version (bool): Allow SLP versions older than 3.0.0 (rollback era)
                Only enable if you know what you're doing. You probably don't want this.
                Gamestates will be missing key information, come in really late, or possibly not work at all
            logger (logger.Logger): Logger instance to use. None for no logger.
        """
        self.logger = logger
        self.is_dolphin = is_dolphin
        self.path = path
        self.dolphin_home_path = dolphin_home_path
        if tmp_home_directory and self.is_dolphin:
            temp_dir = tempfile.mkdtemp(prefix='libmelee_')
            temp_dir += "/User/"
            _copytree_safe(self._get_dolphin_home_path(), temp_dir)
            self.dolphin_home_path = temp_dir

        self.processingtime = 0
        self._frametimestamp = time.time()
        self.slippi_address = slippi_address
        """(str): IP address of the Dolphin / Wii to connect to."""
        self.slippi_port = slippi_port
        """(int): UDP port of slippi server. Default 51441"""
        self.eventsize = [0] * 0x100
        self.connected = False
        self.nick = ""
        """(str): The nickname the console has given itself."""
        self.version = ""
        """(str): The Slippi version of the console"""
        self.cursor = 0
        self.controllers = []
        self._current_stage = enums.Stage.NO_STAGE
        self._frame = 0
        self._polling_mode = polling_mode
        self.slp_version = "unknown"
        """(str): The SLP version this stream/file currently is."""
        self._allow_old_version = allow_old_version
        self._use_manual_bookends = False
        self._costumes = {0:0, 1:0, 2:0, 3:0}
        self._cpu_level = {0:0, 1:0, 2:0, 3:0}
        self._invuln_start = {1:(0,0), 2:(0,0), 3:(0,0), 4:(0,0)}

        # Keep a running copy of the last gamestate produced
        self._prev_gamestate = GameState()
        # Half-completed gamestate not yet ready to add to the list
        self._temp_gamestate = None
        self._process = None
        if self.is_dolphin:
            self._slippstream = SlippstreamClient(self.slippi_address, self.slippi_port)
            if self.path:
                # Setup some dolphin config options
                dolphin_ini_path = self._get_dolphin_config_path() + "Dolphin.ini"
                if not os.path.isfile(dolphin_ini_path):
                    raise InvalidDolphinPath(self._get_dolphin_config_path())
                config = configparser.ConfigParser()
                config.read(dolphin_ini_path)
                config.set("Core", 'slippienablespectator', "True")
                config.set("Core", 'slippispectatorlocalport', str(self.slippi_port))
                # Set online delay
                config.set("Core", 'slippionlinedelay', str(online_delay))
                # Turn on background input so we don't need to have window focus on dolphin
                config.set("Input", 'backgroundinput', "True")
                config.set("Core", 'BlockingPipes', str(blocking_input))
                with open(dolphin_ini_path, 'w') as dolphinfile:
                    config.write(dolphinfile)
        else:
            self._slippstream = SLPFileStreamer(self.path)

        # Prepare some structures for fixing melee data
        path = os.path.dirname(os.path.realpath(__file__))
        with open(path + "/actiondata.csv") as csvfile:
            #A list of dicts containing the frame data
            actiondata = list(csv.DictReader(csvfile))
            #Dict of sets
            self.zero_indices = defaultdict(set)
            for line in actiondata:
                if line["zeroindex"] == "True":
                    self.zero_indices[int(line["character"])].add(int(line["action"]))

        # Read the character data csv
        self.characterdata = dict()
        with open(path + "/characterdata.csv") as csvfile:
            reader = csv.DictReader(csvfile)
            for line in reader:
                del line["Character"]
                #Convert all fields to numbers
                for key, value in line.items():
                    line[key] = float(value)
                self.characterdata[enums.Character(line["CharacterIndex"])] = line
Example #5
0
    def __init__(self, is_dolphin, ai_port, opponent_port, opponent_type,
                 dolphin_executable_path=None, slippi_address="", logger=None):
        """Create a Console object

        Args:
            is_dolphin (boolean): Is this console a dolphin? (Or a Wii)
            ai_port (int): 1-4 for the controller port your bot will take
            opponent_port (int): 1-4 for the controller port your opponent will take
            opponent_type (:obj:`enums.ControllerType`): Enum of your opponent's controller type
            dolphin_executable_path (str): Path to the directory where your dolphin executable is
                located. (if applicable) None tells console to use the installed copy of the emulator
            slippi_address (str): IP address of the Dolphin / Wii to connect to.
                Empty string will try to autodiscover a nearby SlippiComm server
        """
        self.logger = logger
        self.ai_port = ai_port
        self.opponent_port = opponent_port
        self.is_dolphin = is_dolphin
        self.dolphin_executable_path = dolphin_executable_path
        self.processingtime = 0
        self._frametimestamp = time.time()
        self.slippi_address = slippi_address
        self.slippi_port = 51441
        self.eventsize = [0] * 0x100
        self.render = True

        # Keep a running copy of the last gamestate produced
        self._prev_gamestate = GameState(ai_port, opponent_port)
        self._process = None
        if self.is_dolphin:
            pipes_path = self._get_dolphin_home_path() + "Pipes/"
            path = os.path.dirname(os.path.realpath(__file__))

            if platform.system() != "Windows":
                #Create the Pipes directory if it doesn't already exist
                if not os.path.exists(pipes_path):
                    os.makedirs(pipes_path)
                    print("WARNING: Had to create a Pipes directory in Dolphin just now. " \
                          "You may need to restart Dolphin and this program in order for this to work. " \
                          "(You should only see this warning once)")

                pipes_path += "slippibot" + str(ai_port)
                if not os.path.exists(pipes_path):
                    os.mkfifo(pipes_path)

            #setup the controllers specified
            self.setup_dolphin_controller(ai_port)
            self.setup_dolphin_controller(opponent_port, opponent_type)
            self._slippstream = SlippstreamClient(self.slippi_address, self.slippi_port)

        # Prepare some structures for fixing melee data
        path = os.path.dirname(os.path.realpath(__file__))
        with open(path + "/actiondata.csv") as csvfile:
            #A list of dicts containing the frame data
            actiondata = list(csv.DictReader(csvfile))
            #Dict of sets
            self.zero_indices = defaultdict(set)
            for line in actiondata:
                if line["zeroindex"] == "True":
                    self.zero_indices[int(line["character"])].add(int(line["action"]))

        # Read the character data csv
        self.characterdata = dict()
        with open(path + "/characterdata.csv") as csvfile:
            reader = csv.DictReader(csvfile)
            for line in reader:
                del line["Character"]
                #Convert all fields to numbers
                for key, value in line.items():
                    line[key] = float(value)
                self.characterdata[enums.Character(line["CharacterIndex"])] = line
Example #6
0
    def __init__(self,
                 path=None,
                 is_dolphin=True,
                 slippi_address="127.0.0.1",
                 logger=None):
        """Create a Console object

        Args:
            path (str): Path to the directory where your dolphin executable is
                located. (if applicable) None tells console to use the installed copy of the emulator
            slippi_address (str): IP address of the Dolphin / Wii to connect to.
                Empty string will try to autodiscover a nearby SlippiComm server
            logger (logger.Logger): Logger instance to use. None for no logger.
        """
        self.logger = logger
        self.is_dolphin = is_dolphin
        self.path = path
        self.processingtime = 0
        self._frametimestamp = time.time()
        self.slippi_address = slippi_address
        """(str): IP address of the Dolphin / Wii to connect to."""
        self.slippi_port = 51441
        """(int): TCP port of slippi server. Default 51441"""
        self.eventsize = [0] * 0x100
        self.render = True
        self.connected = False
        self.nick = ""
        """(str): The nickname the console has given itself."""
        self.version = ""
        """(str): The Slippi version of the console"""
        self.cursor = 0
        self.controllers = []
        self._current_stage = enums.Stage.NO_STAGE
        self._frame = 0
        self.slp_version = "unknown"
        """(str): The SLP version this stream/file currently is."""

        # Keep a running copy of the last gamestate produced
        self._prev_gamestate = GameState()
        self._process = None
        if self.is_dolphin:
            self._slippstream = SlippstreamClient(self.slippi_address,
                                                  self.slippi_port)
        else:
            self._slippstream = SLPFileStreamer(self.path)

        # Prepare some structures for fixing melee data
        path = os.path.dirname(os.path.realpath(__file__))
        with open(path + "/actiondata.csv") as csvfile:
            #A list of dicts containing the frame data
            actiondata = list(csv.DictReader(csvfile))
            #Dict of sets
            self.zero_indices = defaultdict(set)
            for line in actiondata:
                if line["zeroindex"] == "True":
                    self.zero_indices[int(line["character"])].add(
                        int(line["action"]))

        # Read the character data csv
        self.characterdata = dict()
        with open(path + "/characterdata.csv") as csvfile:
            reader = csv.DictReader(csvfile)
            for line in reader:
                del line["Character"]
                #Convert all fields to numbers
                for key, value in line.items():
                    line[key] = float(value)
                self.characterdata[enums.Character(
                    line["CharacterIndex"])] = line
Example #7
0
    def __init__(self,
                 is_dolphin,
                 ai_port,
                 opponent_port,
                 opponent_type,
                 config_path="",
                 home_path="",
                 logger=None):
        self.logger = logger
        self.ai_port = ai_port
        self.opponent_port = opponent_port
        self.is_dolphin = is_dolphin
        self.config_path = config_path
        self.home_path = home_path

        self.processingtime = 0
        self._frametimestamp = time.time()
        self.slippi_address = ""
        self.slippi_port = 51441
        self.eventsize = [0] * 0x100

        # Keep a running copy of the last gamestate produced
        #   game info is only produced as diffs, not whole snapshots
        #   so if nothing changes, we need to know what the last value was
        self.render = True
        self._prev_gamestate = GameState(ai_port, opponent_port)
        self.process = None
        if self.is_dolphin:
            config_path = self.get_dolphin_home_path()
            pipes_path = config_path + "Pipes/"
            path = os.path.dirname(os.path.realpath(__file__))

            #Create the Pipes directory if it doesn't already exist
            if not os.path.exists(pipes_path):
                os.makedirs(pipes_path)
                print("WARNING: Had to create a Pipes directory in Dolphin just now. " \
                    "You may need to restart Dolphin and this program in order for this to work. " \
                    "(You should only see this warning once)")

            pipes_path += "Bot" + str(ai_port)
            if not os.path.exists(pipes_path):
                os.mkfifo(pipes_path)

            #setup the controllers specified
            self.setup_dolphin_controller(ai_port)
            self.setup_dolphin_controller(opponent_port, opponent_type)

        # Prepare some structures for fixing melee data
        path = os.path.dirname(os.path.realpath(__file__))
        with open(path + "/actiondata.csv") as csvfile:
            #A list of dicts containing the frame data
            actiondata = list(csv.DictReader(csvfile))
            #Dict of sets
            self.zero_indices = defaultdict(set)
            for line in actiondata:
                if line["zeroindex"] == "True":
                    self.zero_indices[int(line["character"])].add(
                        int(line["action"]))

        # Read the character data csv
        self.characterdata = dict()
        with open(path + "/characterdata.csv") as csvfile:
            reader = csv.DictReader(csvfile)
            for line in reader:
                del line["Character"]
                #Convert all fields to numbers
                for key, value in line.items():
                    line[key] = float(value)
                self.characterdata[enums.Character(
                    line["CharacterIndex"])] = line