def _launch_game(self): # Reserve a whole bunch of ports for the weird multiplayer implementation. if self._num_agents > 1: self._ports = portspicker.pick_unused_ports(self._num_agents * 2) logging.info("Ports used for multiplayer: %s", self._ports) else: self._ports = [] # Actually launch the game processes. self._sc2_procs = [ self._run_config.start(extra_ports=self._ports, want_rgb=interface.HasField("render")) for interface in self._interface_options ] self._controllers = [p.controller for p in self._sc2_procs] if self._battle_net_map: available_maps = self._controllers[0].available_maps() available_maps = set(available_maps.battlenet_map_names) unavailable = [ m.name for m in self._maps if m.battle_net not in available_maps ] if unavailable: raise ValueError( "Requested map(s) not in the battle.net cache: %s" % ",".join(unavailable))
def _launch_mp(self, map_inst, interfaces): # Reserve a whole bunch of ports for the weird multiplayer implementation. self._ports = portspicker.pick_unused_ports(self._num_agents * 2) logging.info("Ports used for multiplayer: %s", self._ports) # Actually launch the game processes. self._sc2_procs = [ self._run_config.start(extra_ports=self._ports, want_rgb=interface.HasField("render")) for interface in interfaces ] self._controllers = [p.controller for p in self._sc2_procs] # Save the maps so they can access it. Don't do it in parallel since SC2 # doesn't respect tmpdir on windows, which leads to a race condition: # https://github.com/Blizzard/s2client-proto/issues/102 for c in self._controllers: c.save_map(map_inst.path, map_inst.data(self._run_config)) # Create the game. Set the first instance as the host. create = sc_pb.RequestCreateGame( local_map=sc_pb.LocalMap(map_path=map_inst.path), disable_fog=self._disable_fog, realtime=self._realtime) if self._random_seed is not None: create.random_seed = self._random_seed for p in self._players: if isinstance(p, Agent): create.player_setup.add(type=sc_pb.Participant) else: create.player_setup.add(type=sc_pb.Computer, race=p.race, difficulty=p.difficulty) self._controllers[0].create_game(create) # Create the join requests. agent_players = (p for p in self._players if isinstance(p, Agent)) join_reqs = [] for agent_index, p in enumerate(agent_players): ports = self._ports[:] join = sc_pb.RequestJoinGame(options=interfaces[agent_index]) join.shared_port = 0 # unused join.server_ports.game_port = ports.pop(0) join.server_ports.base_port = ports.pop(0) for _ in range(self._num_agents - 1): join.client_ports.add(game_port=ports.pop(0), base_port=ports.pop(0)) join.race = p.race join.player_name = p.name join_reqs.append(join) # Join the game. This must be run in parallel because Join is a blocking # call to the game that waits until all clients have joined. self._parallel.run((c.join_game, join) for c, join in zip(self._controllers, join_reqs)) # Save them for restart. self._create_req = create self._join_reqs = join_reqs
def __init__(self): self._num_agents = 2 self._run_config = run_configs.get() self._processes = [] self._controllers = [] self._saved_maps = set() # Reserve LAN ports. self._lan_ports = portspicker.pick_unused_ports(self._num_agents * 2) # Start SC2 processes. for _ in range(self._num_agents): process = self._run_config.start(extra_ports=self._lan_ports) self._processes.append(process) self._controllers.append(process.controller)
def test_multi_player(self): players = 2 run_config = run_configs.get() parallel = run_parallel.RunParallel() map_inst = maps.get("Simple64") screen_size_px = point.Point(64, 64) minimap_size_px = point.Point(32, 32) interface = sc_pb.InterfaceOptions() screen_size_px.assign_to(interface.feature_layer.resolution) minimap_size_px.assign_to(interface.feature_layer.minimap_resolution) # Reserve a whole bunch of ports for the weird multiplayer implementation. ports = portspicker.pick_unused_ports(players * 2) logging.info("Valid Ports: %s", ports) # Actually launch the game processes. print_stage("start") sc2_procs = [run_config.start(extra_ports=ports) for _ in range(players)] controllers = [p.controller for p in sc2_procs] try: # Save the maps so they can access it. map_path = os.path.basename(map_inst.path) print_stage("save_map") parallel.run((c.save_map, map_path, map_inst.data(run_config)) for c in controllers) # Create the create request. create = sc_pb.RequestCreateGame( local_map=sc_pb.LocalMap(map_path=map_path)) for _ in range(players): create.player_setup.add(type=sc_pb.Participant) # Create the join request. join = sc_pb.RequestJoinGame(race=sc_common.Random, options=interface) join.shared_port = 0 # unused join.server_ports.game_port = ports.pop(0) join.server_ports.base_port = ports.pop(0) for _ in range(players - 1): join.client_ports.add(game_port=ports.pop(0), base_port=ports.pop(0)) # Play a few short games. for _ in range(2): # 2 episodes # Create and Join print_stage("create") controllers[0].create_game(create) print_stage("join") parallel.run((c.join_game, join) for c in controllers) print_stage("run") for game_loop in range(1, 10): # steps per episode # Step the game parallel.run(c.step for c in controllers) # Observe obs = parallel.run(c.observe for c in controllers) for p_id, o in enumerate(obs): self.assertEqual(o.observation.game_loop, game_loop) self.assertEqual(o.observation.player_common.player_id, p_id + 1) # Act actions = [sc_pb.Action() for _ in range(players)] for action in actions: pt = (point.Point.unit_rand() * minimap_size_px).floor() pt.assign_to(action.action_feature_layer.camera_move.center_minimap) parallel.run((c.act, a) for c, a in zip(controllers, actions)) # Done this game. print_stage("leave") parallel.run(c.leave for c in controllers) finally: print_stage("quit") # Done, shut down. Don't depend on parallel since it might be broken. for c in controllers: c.quit() for p in sc2_procs: p.close() portspicker.return_ports(ports)
def testInvalidReservation(self): with self.assertRaises(ValueError): portspicker.pick_unused_ports(0)
def testNonContiguousReservation(self, num_ports): reserved = portspicker.pick_unused_ports(num_ports) self.assertLen(reserved, num_ports) portspicker.return_ports(reserved)
def test_observe_players(self): players = 2 # Can be 1. run_config = run_configs.get() parallel = run_parallel.RunParallel() map_inst = maps.get("Simple64") screen_size_px = point.Point(64, 64) minimap_size_px = point.Point(32, 32) interface = sc_pb.InterfaceOptions(raw=True, score=True) screen_size_px.assign_to(interface.feature_layer.resolution) minimap_size_px.assign_to(interface.feature_layer.minimap_resolution) # Reserve a whole bunch of ports for the weird multiplayer implementation. ports = portspicker.pick_unused_ports((players + 2) * 2) logging.info("Valid Ports: %s", ports) # Actually launch the game processes. print_stage("start") sc2_procs = [run_config.start(extra_ports=ports, want_rgb=False) for _ in range(players + 1)] controllers = [p.controller for p in sc2_procs] try: # Save the maps so they can access it. map_path = os.path.basename(map_inst.path) print_stage("save_map") parallel.run((c.save_map, map_path, map_inst.data(run_config)) for c in controllers) # Create the create request. create = sc_pb.RequestCreateGame( local_map=sc_pb.LocalMap(map_path=map_path)) create.player_setup.add(type=sc_pb.Participant) if players == 1: create.player_setup.add(type=sc_pb.Computer, race=sc_common.Random, difficulty=sc_pb.VeryEasy) else: create.player_setup.add(type=sc_pb.Participant) create.player_setup.add(type=sc_pb.Observer) # Create the join request. joins = [] portIdx = 2 for i in range(players + 1): join = sc_pb.RequestJoinGame(options=interface) if i < players: join.race = sc_common.Random else: join.observed_player_id = 0 join.host_ip = sc2_procs[0].host join.shared_port = 0 # unused join.server_ports.game_port = ports[0] join.server_ports.base_port = ports[1] join.client_ports.add(game_port=ports[portIdx], base_port=ports[portIdx + 1]) portIdx = portIdx + 2 joins.append(join) # Create and Join print_stage("create") controllers[0].create_game(create) print_stage("join") parallel.run((c.join_game, join) for c, join in zip(controllers, joins)) print_stage("run") for game_loop in range(1, 10): # steps per episode # Step the game parallel.run((c.step, 16) for c in controllers) # Observe obs = parallel.run(c.observe for c in controllers) for p_id, o in enumerate(obs): self.assertEqual(o.observation.game_loop, game_loop * 16) if p_id == players: # ie the observer self.assertEqual(o.observation.player_common.player_id, 0) else: self.assertEqual(o.observation.player_common.player_id, p_id + 1) # Act actions = [sc_pb.Action() for _ in range(players)] for action in actions: pt = (point.Point.unit_rand() * minimap_size_px).floor() pt.assign_to(action.action_feature_layer.camera_move.center_minimap) parallel.run((c.act, a) for c, a in zip(controllers[:players], actions)) # Done this game. print_stage("leave") parallel.run(c.leave for c in controllers) finally: print_stage("quit") # Done, shut down. Don't depend on parallel since it might be broken. for c in controllers: c.quit() for p in sc2_procs: p.close() portspicker.return_ports(ports)
def start_game(self, show_cloaked=True, disable_fog=False, players=2): """Start a multiplayer game with options.""" self._disable_fog = disable_fog run_config = run_configs.get() self._parallel = run_parallel.RunParallel() # Needed for multiplayer. map_inst = maps.get("Flat64") self._map_data = map_inst.data(run_config) self._ports = portspicker.pick_unused_ports(4) if players == 2 else [] self._sc2_procs = [ run_config.start(extra_ports=self._ports, want_rgb=False) for _ in range(players) ] self._controllers = [p.controller for p in self._sc2_procs] if players == 2: for c in self._controllers: # Serial due to a race condition on Windows. c.save_map(map_inst.path, self._map_data) self._interface = sc_pb.InterfaceOptions() self._interface.raw = True self._interface.raw_crop_to_playable_area = True self._interface.show_cloaked = show_cloaked self._interface.score = False self._interface.feature_layer.width = 24 self._interface.feature_layer.resolution.x = 64 self._interface.feature_layer.resolution.y = 64 self._interface.feature_layer.minimap_resolution.x = 64 self._interface.feature_layer.minimap_resolution.y = 64 create = sc_pb.RequestCreateGame( random_seed=1, disable_fog=self._disable_fog, local_map=sc_pb.LocalMap(map_path=map_inst.path)) for _ in range(players): create.player_setup.add(type=sc_pb.Participant) if players == 1: create.local_map.map_data = self._map_data create.player_setup.add(type=sc_pb.Computer, race=sc_common.Random, difficulty=sc_pb.VeryEasy) join = sc_pb.RequestJoinGame(race=sc_common.Protoss, options=self._interface) if players == 2: join.shared_port = 0 # unused join.server_ports.game_port = self._ports[0] join.server_ports.base_port = self._ports[1] join.client_ports.add(game_port=self._ports[2], base_port=self._ports[3]) self._controllers[0].create_game(create) self._parallel.run((c.join_game, join) for c in self._controllers) self._info = self._controllers[0].game_info() self._features = features.features_from_game_info(self._info, use_raw_units=True) self._map_size = point.Point.build(self._info.start_raw.map_size) print("Map size:", self._map_size) self.in_game = True self.step() # Get into the game properly.
def _launch_mp(self, map_inst, interfaces): # Reserve a whole bunch of ports for the weird multiplayer implementation. self._ports = portspicker.pick_unused_ports((self._num_agents + self._num_observers + 1) * 2)