def main(self): self.set_config(os.path.join(os.path.dirname(os.path.realpath(__file__)), "SuperchargedBots.cfg")) self.teams = [] if self.get_bool_from_config("Options", "help_blue_team"): self.teams.append(0) print(f"SuperchargedBots: help_blue_team = {0 in self.teams}") if self.get_bool_from_config("Options", "help_orange_team"): self.teams.append(1) print(f"SuperchargedBots: help_orange_team = {1 in self.teams}") self.bots_only = self.get_bool_from_config("Options", "bots_only") print(f"SuperchargedBots: bots_only = {self.bots_only}") self.bonus_boost_accel_percent = self.get_float_from_config("Options", "bonus_boost_accel_percent") / 100 print(f"SuperchargedBots: bonus_boost_accel_percent = {self.bonus_boost_accel_percent * 100}%") self.bonus_boost_tank = self.get_int_from_config("Options", "bonus_boost_tank") print(f"SuperchargedBots: bonus_boost_tank = {self.bonus_boost_tank}") self.minimum_boost = self.get_int_from_config("Options", "minimum_boost") print(f"SuperchargedBots: minimum_boost = {self.minimum_boost}") self.bonus_hit_percent = self.get_int_from_config("Options", "bonus_hit_percent") print(f"SuperchargedBots: bonus_hit_percent = {self.bonus_hit_percent}") self.demo_helper = self.get_bool_from_config("Options", "demo_helper") print(f"SuperchargedBots: demo_helper = {self.demo_helper}") self.socket_relay = SocketRelay() self.socket_relay.player_input_change_handlers.append(self.input_change) self.non_blocking_socket_relay = Thread(target=self.socket_relay.connect_and_run, args=(False, True, False)) self.non_blocking_socket_relay.start() while 1: try: self.packet: GameTickPacket = self.wait_game_tick_packet() time = self.packet.game_info.seconds_elapsed self.delta_time = time - self.time self.time = time supercharged_bots = [] cars = dict() for car_index in range(self.packet.num_cars): car = self.packet.game_cars[car_index] if (self.bots_only and not car.is_bot) or car.team not in self.teams: continue if car.name not in self.tracker: self.tracker[car.name] = DEFAULT_CAR.copy() supercharged_bots.append(car.name) if not self.packet.game_info.is_round_active: continue if self.packet.game_info.is_kickoff_pause: self.tracker[car.name]['total_boost'] = BOOST_CONSUMPTION self.tracker[car.name]['last_boost'] = BOOST_CONSUMPTION continue velocity = None if self.demo_helper: for other_car_index in range(self.packet.num_cars): other_car = self.packet.game_cars[other_car_index] if car.team == other_car.team: continue car_location = Vector.from_vector(car.physics.location) other_car_location = Vector.from_vector(other_car.physics.location) if car_location.flat_dist(other_car_location) < 200 and abs(Vector.from_vector(car.physics.velocity).angle(other_car_location - car_location)) < 0.5: velocity = Vector.from_vector(car.physics.velocity).flatten().scale(2300) if self.tracker[car.name]['boosting']: if not self.tracker[car.name]['steering'] and (car.boost > self.minimum_boost): CP = math.cos(car.physics.rotation.pitch) SP = math.sin(car.physics.rotation.pitch) CY = math.cos(car.physics.rotation.yaw) SY = math.sin(car.physics.rotation.yaw) forward = Vector(CP*CY, CP*SY, SP) if velocity is None: velocity = Vector.from_vector(car.physics.velocity) + forward * (BOOST_ACCEL * self.delta_time * self.bonus_boost_accel_percent) self.tracker[car.name]['total_boost'] -= BOOST_CONSUMPTION * self.delta_time * (100 / self.bonus_boost_tank) boost_amount = None if car.boost > self.minimum_boost and car.boost > self.tracker[car.name]['last_boost']: self.tracker[car.name]['total_boost'] += car.boost - self.tracker[car.name]['last_boost'] elif car.boost < self.minimum_boost: self.tracker[car.name]['total_boost'] = self.minimum_boost self.tracker[car.name]['total_boost'] = cap(self.tracker[car.name]['total_boost'], 0, 100) floored_boost = math.floor(self.tracker[car.name]['total_boost']) if floored_boost != car.boost: boost_amount = floored_boost self.tracker[car.name]['last_boost'] = car.boost if boost_amount is None else boost_amount if velocity is None and boost_amount is None: continue cars[car_index] = CarState( Physics( velocity=None if velocity is None else Vector3(*velocity) ), boost_amount=boost_amount ) last_ball_touch = self.packet.game_ball.latest_touch ball = None if last_ball_touch.time_seconds > self.last_ball_touch_time: if (last_ball_touch.time_seconds - self.last_ball_touch_time) > 0.5: if not self.bots_only or self.packet.game_cars[last_ball_touch.player_index].is_bot: if last_ball_touch.team in self.teams: bonus_hit_multiplier = self.bonus_hit_percent / 100 + 1 ball_velocity = Vector.from_vector(self.packet.game_ball.physics.velocity) * Vector(bonus_hit_multiplier, bonus_hit_multiplier, 1 / bonus_hit_multiplier) ball = BallState(physics=Physics( velocity=Vector3(*ball_velocity) )) self.last_ball_touch_time = last_ball_touch.time_seconds game_state = GameState() if cars: game_state.cars = cars if ball is not None: game_state.ball = ball self.set_game_state(game_state) if self.last_packet_time == -1 or self.time - self.last_packet_time >= 0.1: self.matchcomms.outgoing_broadcast.put_nowait({ "supercharged_bots": supercharged_bots, "supercharged_config": { "bonus_boost_accel_percent": self.bonus_boost_accel_percent, "bonus_boost_tank": self.bonus_boost_tank, "minimum_boost": self.minimum_boost, "bonus_hit_percent": self.bonus_hit_percent, "demo_helper": self.demo_helper, } }) except Exception: print_exc()
def manage_game_state(challenge: dict, upgrades: dict, setup_manager: SetupManager) -> Tuple[bool, dict]: """ Continuously track the game and adjust state to respect challenge rules and upgrades. At the end of the game, calculate results and the challenge completion and return that """ early_failure = False, {} expected_player_count = challenge["humanTeamSize"] + len( challenge["opponentBots"]) # Wait for everything to be initialized packet = wait_till_cars_spawned(setup_manager, expected_player_count) if packet.num_cars == 0: print("The game was initialized with no cars") return early_failure tick_rate = 120 results = None max_boost = 0 if "boost-100" in upgrades: max_boost = 100 elif "boost-33" in upgrades: max_boost = 33 half_field = challenge.get("limitations", []).count("half-field") > 0 stats_tracker = ManualStatsTracker(challenge) last_boost_bump_time = time.monotonic() while True: try: eel.sleep(0) # yield to allow other gui threads to operate. packet = GameTickPacket() setup_manager.game_interface.fresh_live_data_packet( packet, 1000, WITNESS_ID) if packet.num_cars == 0: # User seems to have ended the match print("User ended the match") return early_failure stats_tracker.updateStats(packet) results = packet_to_game_results(packet) if has_user_perma_failed(challenge, stats_tracker.stats): time.sleep(1) setup_failure_freeplay(setup_manager, "You failed the challenge!") return early_failure if end_by_mercy(challenge, stats_tracker.stats, results): time.sleep(3) setup_failure_freeplay(setup_manager, "Challenge completed by mercy rule!", "green") return True, results human_info = packet.game_cars[0] game_state = GameState() human_desired_state = CarState() game_state.cars = {0: human_desired_state} changed = False # adjust boost if human_info.boost > max_boost and not half_field: # Adjust boost, unless in heatseeker mode human_desired_state.boost_amount = max_boost changed = True if "boost-recharge" in upgrades: # increase boost at 10% per second now = time.monotonic() if human_info.boost < max_boost and (now - last_boost_bump_time > 0.1): changed = True last_boost_bump_time = now human_desired_state.boost_amount = min( human_info.boost + 1, max_boost) if changed: setup_manager.game_interface.set_game_state(game_state) if packet.game_info.is_match_ended: break except KeyError: traceback.print_exc() # it means that the game was interrupted by the user print("Looks like the game is in a bad state") setup_failure_freeplay(setup_manager, "The game was interrupted.") return early_failure return calculate_completion(challenge, stats_tracker.stats, results), results