class TestGameStateManager(unittest.TestCase): """ Teste les différentes fonctionnalités du GameStateManager """ def setUp(self): self.field = Field.Field(Ball.Ball()) self.my_team = Team.Team(True) self.other_team = Team.Team(False) self.GameStateManager1 = GameState() self.GameStateManager2 = GameState() def test_singleton(self): """ Teste si le Manager est un singleton, i.e. s'il ne peut y avoir qu'une seule instance du manager """ self.assertTrue(self.GameStateManager1 is self.GameStateManager2) def test_update_ball_position(self): new_ball_position = Position.Position(1500, 1500, 0) self.GameStateManager2._update_ball_position(new_ball_position) self.assertEqual(new_ball_position, self.GameStateManager1.get_ball_position()) def test_update_field(self): new_ball_position = Position.Position(2500, 2500, 0) self.field.move_ball(new_ball_position, 5) self.GameStateManager2._update_field(self.field) self.assertEqual(self.GameStateManager1.get_ball_position(), new_ball_position) def test_update_player(self): new_player_pose = Pose.Pose(Position.Position(1700, 1700, 0), 25) self.GameStateManager2._update_player(3, new_player_pose, True) self.assertEqual(new_player_pose, self.GameStateManager1.get_player_pose(3, True)) self.GameStateManager2._update_player(3, new_player_pose, False) self.assertEqual(new_player_pose, self.GameStateManager1.get_player_pose(3, False)) def test_update_team(self): new_player_pose = Pose.Pose(Position.Position(1000, 1000, 0), 25) for i in range(PLAYER_PER_TEAM): self.my_team.move_and_rotate_player(i, new_player_pose) new_player_pose.position += 200 self.GameStateManager2._update_team(self.my_team, True) for i in range(PLAYER_PER_TEAM): self.assertEqual(self.GameStateManager1.get_player_pose(i, True), self.my_team.players[i].pose) new_player_pose = Pose.Pose(Position.Position(1000, 1000, 0), 25) for i in range(PLAYER_PER_TEAM): self.other_team.move_and_rotate_player(i, new_player_pose) new_player_pose.position += 100 self.GameStateManager2._update_team(self.other_team, False) for i in range(PLAYER_PER_TEAM): self.assertEqual(self.GameStateManager1.get_player_pose(i, False), self.other_team.players[i].pose) def test_update_timestamp(self): new_timestamp = 123.25 self.GameStateManager2._update_timestamp(new_timestamp) self.assertEqual(self.GameStateManager1.timestamp, new_timestamp) def test_update(self): new_timestamp = 145.36 new_ball_position = Position.Position(500, 500, 0) self.field.move_ball(new_ball_position, 5) new_player_pose = Pose.Pose(Position.Position(1000, 1000, 0), 25) for i in range(PLAYER_PER_TEAM): self.my_team.move_and_rotate_player(i, new_player_pose) new_player_pose.position += 200 new_player_pose = Pose.Pose(Position.Position(1000, 1000, 0), 25) for i in range(PLAYER_PER_TEAM): self.other_team.move_and_rotate_player(i, new_player_pose) new_player_pose.position += 100 new_game_state = r_GameState(field=self.field, referee=Referee.Referee(), friends=self.my_team, enemies=self.other_team, timestamp=new_timestamp, debug='Test') self.GameStateManager2.update(new_game_state) self.assertEqual(new_game_state.field.ball.position, self.GameStateManager1.get_ball_position()) for i in range(PLAYER_PER_TEAM): self.assertEqual(self.GameStateManager1.get_player_pose(i, False), self.other_team.players[i].pose) self.assertEqual(self.GameStateManager1.get_player_pose(i, False), self.other_team.players[i].pose) self.assertEqual(new_game_state.timestamp, self.GameStateManager1.timestamp)
class Coach(Process): MAX_EXCESS_TIME = 0.05 def __init__(self, framework): super().__init__(name=__name__) self.framework = framework self.logger = logging.getLogger(self.__class__.__name__) # Managers for shared memory between process self.engine_game_state = self.framework.game_state self.field = self.framework.field # Queues for process communication self.ai_queue = self.framework.ai_queue self.referee_queue = self.framework.referee_queue self.ui_send_queue = self.framework.ui_send_queue self.ui_recv_queue = self.framework.ui_recv_queue # States self.game_state = GameState() self.play_state = PlayState() # Executors self.play_executor = PlayExecutor(self.play_state, self.ui_send_queue, self.referee_queue) self.debug_executor = DebugExecutor(self.play_state, self.play_executor, self.ui_send_queue, self.ui_recv_queue) # fps and limitation self.fps = config['GAME']['fps'] self.frame_count = 0 self.last_frame_count = 0 self.dt = 0.0 self.last_time = 0.0 def callback(excess_time): if excess_time > Coach.MAX_EXCESS_TIME: self.logger.debug('Overloaded (%.1f ms behind schedule)', 1000*excess_time) self.fps_sleep = create_fps_timer(self.fps, on_miss_callback=callback) # profiling self.profiler = None def wait_for_geometry(self): self.logger.debug('Waiting for field\'s geometry from the Engine.') start = time() while not self.field: self.fps_sleep() self.game_state.const = self.field self.logger.debug('Geometry received from the Engine in {:0.2f} seconds.'.format(time() - start)) def wait_for_referee(self): if Config()['GAME']['competition_mode']: self.logger.debug('Waiting for commands from the referee') while self.referee_queue.qsize() == 0: self.logger.debug('Referee is not active or port is set incorrectly, current port is {})'.format( Config()['COMMUNICATION']['referee_port'])) sleep(1) self.logger.debug('Referee command detected') def run(self): try: self.logger.debug('Running with process ID {} at {} fps.'.format(os.getpid(), self.fps)) # profiling self.profiler = cProfile.Profile() if self.framework.profiling: self.profiler.enable() self.wait_for_geometry() self.wait_for_referee() while True: self.frame_count += 1 self.update_time() self.main_loop() self.fps_sleep() self.framework.coach_watchdog.value = time() except KeyboardInterrupt: self.logger.debug('Interrupted.') except BrokenPipeError: self.logger.exception('A connection was broken.') except: self.logger.exception('An error occurred.') finally: self.stop() def main_loop(self): self.game_state.update(self.engine_game_state) self.debug_executor.exec() engine_commands = self.play_executor.exec() try: self.ai_queue.put_nowait(engine_commands) except Full: self.logger.critical('The Engine queue is full.') def update_time(self): current_time = time() self.dt = current_time - self.last_time self.last_time = current_time def dump_profiling_stats(self): if self.framework.profiling: self.profiler.dump_stats(config['GAME']['profiling_filename']) self.logger.debug('Profiling data written to {}.'.format(config['GAME']['profiling_filename'])) def is_alive(self): if config['GAME']['competition_mode']: if time() - self.framework.coach_watchdog.value > self.framework.MAX_HANGING_TIME: self.logger.critical('Process is hanging. Shutting down.') return False return super().is_alive() def stop(self): self.dump_profiling_stats() self.logger.info('Stopped.')