async def _join_game(players, realtime, portconfig, save_replay_as=None, step_time_limit=None, game_time_limit=None, rgb_render_config=None): async with SC2Process() as server: await server.ping() client = Client(server._ws) try: result = await _play_game(players[1], client, realtime, portconfig, step_time_limit, game_time_limit, rgb_render_config=rgb_render_config) if save_replay_as is not None: await client.save_replay(save_replay_as) await client.leave() await client.quit() except ConnectionAlreadyClosed: logging.error(f"Connection was closed before the game ended") return None return result
async def _join_game( players, realtime, portconfig, save_replay_as=None, game_time_limit=None, ): async with SC2Process(fullscreen=players[1].fullscreen) as server: await server.ping() client = Client(server._ws) # Bot can decide if it wants to launch with 'raw_affects_selection=True' if not isinstance(players[1], Human) and getattr(players[1].ai, "raw_affects_selection", None) is not None: client.raw_affects_selection = players[1].ai.raw_affects_selection result = await _play_game(players[1], client, realtime, portconfig, game_time_limit) if save_replay_as is not None: await client.save_replay(save_replay_as) try: await client.leave() except ConnectionAlreadyClosed: logger.error("Connection was closed before the game ended") await client.quit() return result
async def _host_game_aiter( map_settings, players, realtime, portconfig=None, save_replay_as=None, game_time_limit=None, ): assert players, "Can't create a game without players" assert any(isinstance(p, (Human, Bot)) for p in players) async with SC2Process() as server: while True: await server.ping() client = await _setup_host_game(server, map_settings, players, realtime) if not isinstance(players[0], Human) and getattr(players[0].ai, "raw_affects_selection", None) is not None: client.raw_affects_selection = players[0].ai.raw_affects_selection try: result = await _play_game(players[0], client, realtime, portconfig, game_time_limit) if save_replay_as is not None: await client.save_replay(save_replay_as) await client.leave() except ConnectionAlreadyClosed: logger.error("Connection was closed before the game ended") return new_players = yield result if new_players is not None: players = new_players
async def _join_game( task_dict, players, aio_event, alive_evnet, req_kill_event, exc_queue, n_games, realtime=False, portconfig=None, save_replay_as=None, step_time_limit=None, game_time_limit=None, ): async with SC2Process() as server: try: for _ in range(n_games): # host에서 게임을 세팅할 때까지 기다림 await aio_event.wait() aio_event.clear() # 게임을 재시작했음을 부모 프로세스에 알림 alive_evnet.set() # 게임 시작 await server.ping() client = Client(server._ws) result = await _play_game( players[1], client, realtime, portconfig, step_time_limit, game_time_limit ) if save_replay_as is not None: await client.save_replay(save_replay_as) await client.leave() # await client.quit() # 게임 인스턴스 재시작을 위해 프로세스 종료하지 않음 except: # 예외가 발생하면 부모 프로세스에 전달 import traceback exc_queue.put(traceback.format_exc()) # n_games 만큼 게임을 반복했음을 부모 프로세스에 알림 # join에서 host를 죽이거나, host에서 join을 죽일 경우를 대비해서, # host와 join 양쪽에 req_kill_evnet를 set 해야함 # -> 어떤 경우에도 부모는 이 프로세스를 종료해야함을 알 수 있음 req_kill_event.set()
async def _host_game( map_settings, players, realtime=False, portconfig=None, save_replay_as=None, game_time_limit=None, rgb_render_config=None, random_seed=None, sc2_version=None, disable_fog=None, ): assert players, "Can't create a game without players" assert any(isinstance(p, (Human, Bot)) for p in players) async with SC2Process( fullscreen=players[0].fullscreen, render=rgb_render_config is not None, sc2_version=sc2_version ) as server: await server.ping() client = await _setup_host_game( server, map_settings, players, realtime, random_seed, disable_fog, save_replay_as ) # Bot can decide if it wants to launch with 'raw_affects_selection=True' if not isinstance(players[0], Human) and getattr(players[0].ai, "raw_affects_selection", None) is not None: client.raw_affects_selection = players[0].ai.raw_affects_selection result = await _play_game(players[0], client, realtime, portconfig, game_time_limit, rgb_render_config) if client.save_replay_path is not None: await client.save_replay(client.save_replay_path) try: await client.leave() except ConnectionAlreadyClosed: logger.error("Connection was closed before the game ended") await client.quit() return result
async def _join_game_aiter(players, realtime, portconfig): assert players, "Can't create a game without players" assert any(isinstance(p, (Human, Bot)) for p in players) async with SC2Process() as server: while True: await server.ping() client = Client(server._ws) try: result = await _play_game(players[1], client, realtime, portconfig) await client.leave() except ConnectionAlreadyClosed: print(f"Connection was closed before the game ended") return new_players = yield result if new_players is not None: players = new_players
async def _host_game( hostname, sock, task_dict, players, aio_event, alive_evnet, req_kill_event, exc_queue, n_games, realtime=False, portconfig=None, save_replay_as=None, step_time_limit=None, game_time_limit=None, rgb_render_config=None, random_seed=None, ): async with SC2Process(render=rgb_render_config is not None) as server: try: for _ in range(n_games): # Learner에게 다음에 실행할 게임 세팅을 요청 sock.send_multipart([CommandType.REQ_TASK]) task_dict.update(pickle.loads(sock.recv_multipart()[0])) # 게임 세팅 설정 # !주의!: join쪽 task_dict, players와 동일한 인스턴스를 유지해야 하기 때문에, # 절대 여기서 새로 생성하지 말고 업데이트만 해야함, # 불가: players = [_Bot(), _Bot()], 가능 players[0] = _Bot(); players[1] = _Bot() step_interval = task_dict['step_interval'] players[0] = _Bot(Race.Terran, MyBot(step_interval, hostname, sock)) players[1] = _Bot(Race.Terran, OppBot()) # 게임 세팅이 완료되면 event를 set해서 join 쪽도 다음 과정을 진행하도록 함 aio_event.set() # 게임이 새로 시작했음을 부모 프로세스에 알림 alive_evnet.set() # 게임 시작 map_settings = sc2.maps.get(task_dict['game_map']) await server.ping() client = await _setup_host_game(server, map_settings, players, realtime, random_seed) result = await _play_game(players[0], client, realtime, portconfig, step_time_limit, game_time_limit, rgb_render_config) if save_replay_as is not None: await client.save_replay(save_replay_as) await client.leave() # await client.quit() # 게임 인스턴스 재시작을 위해 프로세스 종료하지 않음 except: # 예외가 발생하면 부모 프로세스에 전달 import traceback exc_queue.put(traceback.format_exc()) # n_games 만큼 게임을 반복했음을 부모 프로세스에 알림 # join에서 host를 죽이거나, host에서 join을 죽일 경우를 대비해서, # host와 join 양쪽에 req_kill_evnet를 set 해야함 # -> 어떤 경우에도 부모는 이 프로세스를 종료해야함을 알 수 있음 req_kill_event.set()
async def maintain_SCII_count(count: int, controllers: List[Controller], proc_args: List[Dict] = None): """Modifies the given list of controllers to reflect the desired amount of SCII processes""" # kill unhealthy ones. if controllers: to_remove = [] alive = await asyncio.wait_for( asyncio.gather(*(c.ping() for c in controllers if not c._ws.closed), return_exceptions=True), timeout=20 ) i = 0 # for alive for controller in controllers: if controller._ws.closed: if not controller._process._session.closed: await controller._process._session.close() to_remove.append(controller) else: if not isinstance(alive[i], sc_pb.Response): try: await controller._process._close_connection() finally: to_remove.append(controller) i += 1 for c in to_remove: c._process._clean(verbose=False) if c._process in kill_switch._to_kill: kill_switch._to_kill.remove(c._process) controllers.remove(c) # spawn more if len(controllers) < count: needed = count - len(controllers) if proc_args: index = len(controllers) % len(proc_args) else: proc_args = [{} for _ in range(needed)] index = 0 extra = [SC2Process(**proc_args[(index + _) % len(proc_args)]) for _ in range(needed)] logger.info(f"Creating {needed} more SC2 Processes") for _ in range(3): if platform.system() == "Linux": # Works on linux: start one client after the other new_controllers = [await asyncio.wait_for(sc.__aenter__(), timeout=50) for sc in extra] else: # Doesnt seem to work on linux: starting 2 clients nearly at the same time new_controllers = await asyncio.wait_for( asyncio.gather(*[sc.__aenter__() for sc in extra], return_exceptions=True), timeout=50 ) controllers.extend(c for c in new_controllers if isinstance(c, Controller)) if len(controllers) == count: await asyncio.wait_for(asyncio.gather(*(c.ping() for c in controllers)), timeout=20) break extra = [ extra[i] for i, result in enumerate(new_controllers) if not isinstance(new_controllers, Controller) ] else: logger.critical("Could not launch sufficient SC2") raise RuntimeError # kill excess while len(controllers) > count: proc = controllers.pop() proc = proc._process logger.info(f"Removing SCII listening to {proc._port}") await proc._close_connection() proc._clean(verbose=False) if proc in kill_switch._to_kill: kill_switch._to_kill.remove(proc)
async def _host_replay(replay_path, ai, realtime, _portconfig, base_build, data_version, observed_id): async with SC2Process(fullscreen=False, base_build=base_build, data_hash=data_version) as server: client = await _setup_replay(server, replay_path, realtime, observed_id) result = await _play_replay(client, ai, realtime) return result
async def _host_game(hostname, sock, task_dict, players, aio_event, alive_evnet, req_kill_event, exc_queue, n_games, realtime=False, portconfig=None, save_replay_as=None, step_time_limit=None, game_time_limit=None, rgb_render_config=None, random_seed=None): async with SC2Process(render=rgb_render_config is not None) as server: try: for j in range(n_games): # Learner에게 다음에 실행할 게임 세팅을 요청 sock.send_multipart([CommandType.REQ_TASK]) tmp = sock.recv_multipart() task_dict.update(pickle.loads(tmp[0])) # 게임 세팅 설정 # !주의!: join쪽 task_dict, players와 동일한 인스턴스를 유지해야 하기 때문에, # 절대 여기서 새로 생성하지 말고 업데이트만 해야함, # 불가: players = [_Bot(), _Bot()], 가능 players[0] = _Bot(); players[1] = _Bot() step_interval = task_dict['step_interval'] # pool # set으로 중복 방지 # pool은 opp2bot 1개 + (배틀,밤까) 봇 1개 + 배틀 봇 1개 + 탱크 봇 1개 + 밴시 봇 1개 + 타 팀 봇(flash/magic) 6개 + pool 4개 = max 15개의 봇으로 구성 # pool = ["Opp2Bot", "OppBotBattle", "OppBotBattleNoRaven", \ # "OppBotTank", "OppBotBanshee", "OppBotFlash", "OppBotFlash", "OppBotFlashFast", "OppBotFlashFast", "OppBotMagic", "OppBotMagic"] pool = ["Opp2Bot", "OppBotBattle", "OppBotBattleNoRaven", \ "OppBotTank", "OppBotBanshee", "OppBotFlashNew", "OppBotFlashNewRaven", "OppBotFlashFast", "OppBotFlashFast", "OppBotMagic", "OppBotMagic"] for i in range(1, 4): model_path = pathlib.Path(__file__).parent / ( 'model' + str(i) + '.pt') if os.path.isfile(model_path): pool.append(str(i)) ''' win = pickle.loads(tmp[1]) rates = [] # 뽑을 확률 설정 probs = np.repeat(0.5 / len(pool), len(pool)) for p in pool: win_tmp = win[p] if len(win_tmp) > 10: win_tmp = win_tmp[-10:-1] if not win_tmp: # 비어있으면 => 게임 한판도 안했으면 rates.append(1 - 1 / len(pool)) else: rates.append(1 - np.mean(win_tmp)) for i, rate in enumerate(rates) : prob = (rate / np.sum(rates) / 2) probs[i] = probs[i] + prob bot_str = list(np.random.choice(pool, 1, False, probs))[0] players[0] = _Bot(Race.Terran, MyBot(step_interval, hostname, sock, bot_str)) ''' bot_str = list(np.random.choice(pool, 1))[0] players[0] = _Bot( Race.Terran, MyBot(step_interval, hostname, sock, bot_str)) if bot_str == "Opp2Bot": players[1] = _Bot(Race.Terran, Opp2Bot()) elif bot_str == "OppBotBattle": players[1] = _Bot(Race.Terran, OppBotBattle()) elif bot_str == "OppBotBattleNoRaven": players[1] = _Bot(Race.Terran, OppBotBattleNoRaven()) elif bot_str == "OppBotTank": players[1] = _Bot(Race.Terran, OppBotTank()) elif bot_str == "OppBotBanshee": players[1] = _Bot(Race.Terran, OppBotBanshee()) elif bot_str == "OppBotFlashNew": players[1] = _Bot(Race.Terran, OppBotFlashNew()) elif bot_str == "OppBotFlashNewRaven": players[1] = _Bot(Race.Terran, OppBotFlashNewRaven()) elif bot_str == "OppBotFlashFast": players[1] = _Bot(Race.Terran, OppBotFlashFast()) elif bot_str == "OppBotMagic": players[1] = _Bot(Race.Terran, OppBotMagic()) else: players[1] = _Bot( Race.Terran, MyBot(step_interval, hostname, None, None, bot_str)) # 게임 세팅이 완료되면 event를 set해서 join 쪽도 다음 과정을 진행하도록 함 aio_event.set() # 게임이 새로 시작했음을 부모 프로세스에 알림 alive_evnet.set() # 게임 시작 map_settings = sc2.maps.get(task_dict['game_map']) await server.ping() client = await _setup_host_game(server, map_settings, players, realtime, random_seed) result = await _play_game(players[0], client, realtime, portconfig, step_time_limit, game_time_limit, rgb_render_config) # Result.Defeat, Result.Tie, Result.Victory #if result == Result.Defeat : # self.win[bot_str].append(-1) #elif result == Result.Tie : # self.win[bot_str].append(0) #elif result == Result.Victory : # self.win[bot_str].append(1) # print(result) if save_replay_as is not None: await client.save_replay(save_replay_as) await client.leave() # await client.quit() # 게임 인스턴스 재시작을 위해 프로세스 종료하지 않음 except: # 예외가 발생하면 부모 프로세스에 전달 import traceback exc_queue.put(traceback.format_exc()) # n_games 만큼 게임을 반복했음을 부모 프로세스에 알림 # join에서 host를 죽이거나, host에서 join을 죽일 경우를 대비해서, # host와 join 양쪽에 req_kill_evnet를 set 해야함 # -> 어떤 경우에도 부모는 이 프로세스를 종료해야함을 알 수 있음 req_kill_event.set()