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
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
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
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
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
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
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