예제 #1
0
class GameRunner:
    def __init__(
        self,
        game_state_generator,
        communicator: DjangoCommunicator,
        port,
        turn_collector: "TurnCollector",
    ):
        super(GameRunner, self).__init__()

        self.game_state: "GameState" = game_state_generator(AvatarManager())
        self.communicator = communicator
        self.simulation_runner = ConcurrentSimulationRunner(
            communicator=self.communicator, game_state=self.game_state)
        self.turn_collector = turn_collector
        self.turn_collector.new_turn(self.game_state.turn_count)
        self._end_turn_callback = lambda: None

    def set_end_turn_callback(self, callback_method):
        self._end_turn_callback = callback_method

    def get_users_to_add(self, game_metadata):
        def player_is_new(_player):
            return (_player["id"] not in self.simulation_runner.game_state.
                    avatar_manager.avatars_by_id.keys())

        return [
            player["id"] for player in game_metadata["users"]
            if player_is_new(player)
        ]

    def get_users_to_delete(self, game_metadata):
        def player_in_avatar_manager_but_not_metadata(pid):
            return pid not in [
                player["id"] for player in game_metadata["users"]
            ]

        return [
            player_id for player_id in self.simulation_runner.game_state.
            avatar_manager.avatars_by_id.keys()
            if player_in_avatar_manager_but_not_metadata(player_id)
        ]

    async def update_avatars(self):
        try:
            game_metadata = await self.communicator.get_game_metadata()
            users_to_add = self.get_users_to_add(game_metadata)
            users_to_delete = self.get_users_to_delete(game_metadata)

            self.simulation_runner.add_avatars(users_to_add)
            self.simulation_runner.delete_avatars(users_to_delete)
        except GameMetadataFetchFailedError:
            LOGGER.error(
                "Game metadata fetch failed, not updating avatars this turn")
            pass

    async def update_simulation(self, player_id_to_serialized_actions):
        await self.simulation_runner.run_single_turn(
            player_id_to_serialized_actions)
        await self._end_turn_callback()
        self.game_state.turn_count += 1

    async def update(self):
        with GAME_TURN_TIME():
            await self.update_avatars()
            await self.update_simulation(self.turn_collector.collected_turns)
            self.game_state.avatar_manager.clear_all_avatar_logs()
            self.turn_collector.new_turn(self.game_state.turn_count)

    def _get_task_result_or_stop_loop(self, task):
        try:
            task.result()
        except Exception as e:
            LOGGER.exception(f"Unexpected error, stopping game loop: {e}")
            loop = asyncio.get_event_loop()
            loop.stop()

    async def run(self):
        while True:
            LOGGER.info(f"Starting turn {self.game_state.turn_count}")
            turn = asyncio.ensure_future(self.update())

            turn.add_done_callback(self._get_task_result_or_stop_loop)

            await asyncio.sleep(TURN_TIME)
            await turn
예제 #2
0
class GameRunner:
    def __init__(
        self,
        game_state_generator,
        django_api_url,
        port,
        worker_manager_class=WorkerManager,
    ):
        super(GameRunner, self).__init__()

        self.worker_manager = worker_manager_class(port=port)
        self.game_state = game_state_generator(AvatarManager())
        self.communicator = DjangoCommunicator(
            django_api_url=django_api_url, completion_url=django_api_url + "complete/"
        )
        self.simulation_runner = ConcurrentSimulationRunner(
            communicator=self.communicator, game_state=self.game_state
        )
        self._end_turn_callback = lambda: None

    def set_end_turn_callback(self, callback_method):
        self._end_turn_callback = callback_method

    def get_users_to_add(self, game_metadata):
        def player_is_new(_player):
            return _player["id"] not in self.worker_manager.player_id_to_worker.keys()

        return [
            player["id"] for player in game_metadata["users"] if player_is_new(player)
        ]

    def get_users_to_delete(self, game_metadata):
        def player_in_worker_manager_but_not_metadata(pid):
            return pid not in [player["id"] for player in game_metadata["users"]]

        return [
            player_id
            for player_id in self.worker_manager.player_id_to_worker.keys()
            if player_in_worker_manager_but_not_metadata(player_id)
        ]

    def update_main_user(self, game_metadata):
        self.game_state.main_avatar_id = game_metadata["main_avatar"]

    async def update_workers(self):
        game_metadata = self.communicator.get_game_metadata()["main"]

        users_to_add = self.get_users_to_add(game_metadata)
        users_to_delete = self.get_users_to_delete(game_metadata)

        await self.worker_manager.add_workers(users_to_add)
        await self.worker_manager.delete_workers(users_to_delete)
        self.simulation_runner.add_avatars(users_to_add)
        self.simulation_runner.delete_avatars(users_to_delete)
        await self.worker_manager.update_worker_codes(game_metadata["users"])

        self.update_main_user(game_metadata)
        self.worker_manager.fetch_all_worker_data(
            self.game_state.get_serialized_game_states_for_workers()
        )

    async def update_simulation(self, player_id_to_serialized_actions):
        await self.simulation_runner.run_single_turn(player_id_to_serialized_actions)
        await self._end_turn_callback()

    async def update(self):
        with GAME_TURN_TIME():
            await self.update_workers()
            await self.update_simulation(
                self.worker_manager.get_player_id_to_serialized_actions()
            )
            self.worker_manager.clear_logs()
            self.game_state.turn_count += 1

    async def run(self):
        while True:
            await self.update()
예제 #3
0
class GameRunner:
    def __init__(
        self,
        game_state_generator,
        communicator: DjangoCommunicator,
        port,
        worker_manager_class=WorkerManager,
    ):
        super(GameRunner, self).__init__()

        self.worker_manager = worker_manager_class(port=port)
        self.game_state = game_state_generator(AvatarManager())
        self.communicator = communicator
        self.simulation_runner = ConcurrentSimulationRunner(
            communicator=self.communicator, game_state=self.game_state
        )
        self._end_turn_callback = lambda: None

    def set_end_turn_callback(self, callback_method):
        self._end_turn_callback = callback_method

    def get_users_to_add(self, game_metadata):
        def player_is_new(_player):
            return _player["id"] not in self.worker_manager.player_id_to_worker.keys()

        return [
            player["id"] for player in game_metadata["users"] if player_is_new(player)
        ]

    def get_users_to_delete(self, game_metadata):
        def player_in_worker_manager_but_not_metadata(pid):
            return pid not in [player["id"] for player in game_metadata["users"]]

        return [
            player_id
            for player_id in self.worker_manager.player_id_to_worker.keys()
            if player_in_worker_manager_but_not_metadata(player_id)
        ]

    def update_main_user(self, game_metadata):
        self.game_state.main_avatar_id = game_metadata["main_avatar"]

    async def update_workers(self):
        game_metadata = self.communicator.get_game_metadata()

        users_to_add = self.get_users_to_add(game_metadata)
        users_to_delete = self.get_users_to_delete(game_metadata)

        await self.worker_manager.add_workers(users_to_add)
        await self.worker_manager.delete_workers(users_to_delete)
        self.simulation_runner.add_avatars(users_to_add)
        self.simulation_runner.delete_avatars(users_to_delete)
        await self.worker_manager.update_worker_codes(game_metadata["users"])

        self.update_main_user(game_metadata)
        await self.worker_manager.fetch_all_worker_data(
            self.game_state.get_serialized_game_states_for_workers()
        )

    async def update_simulation(self, player_id_to_serialized_actions):
        await self.simulation_runner.run_single_turn(player_id_to_serialized_actions)
        await self._end_turn_callback()

    async def update(self):
        with GAME_TURN_TIME():
            await self.update_workers()
            await self.update_simulation(
                self.worker_manager.get_player_id_to_serialized_actions()
            )
            self.worker_manager.clear_logs()
            self.game_state.avatar_manager.clear_all_avatar_logs()
            self.game_state.turn_count += 1

    def _get_task_result_or_stop_loop(self, task):
        try:
            task.result()
        except Exception as e:
            LOGGER.exception(f"Unexpected error, stopping game loop: {e}")
            loop = asyncio.get_event_loop()
            loop.stop()

    async def run(self):
        while True:
            LOGGER.info(f"Starting turn {self.game_state.turn_count}")
            turn = asyncio.ensure_future(self.update())

            turn.add_done_callback(self._get_task_result_or_stop_loop)

            await asyncio.sleep(TURN_TIME)
            await turn