def replay_turn_after_load(): """ When loading a savegame, the AI will already have issued orders for this turn. To avoid duplicate orders, generally try not to replay turns. However, for debugging purposes it is often useful to replay the turn and observe varying results after code changes. Set the replay_after_load flag in the AI config to let the AI issue new orders after a game load. Note that the orders from the original savegame are still being issued and the AIstate was saved after those orders were issued. Return True is we should abort order generation. """ replay_option_is_set = check_bool(get_option_dict().get( "replay_turn_after_load", "False")) turn_is_already_played = fo.currentTurn() == get_aistate().last_turn_played # TODO: Consider adding an option to clear AI orders after load (must save AIstate at turn start then) if turn_is_already_played: info("The AIstate indicates that this turn was already played.") if replay_option_is_set: info("Issuing new orders anyway.") return False else: info( "Aborting new order generation. Orders from savegame will still be issued." ) return True else: return False
def init_handlers(config_str, search_dir): handlers = split(get_option_dict()[HANDLERS]) for handler in handlers: module = os.path.basename(handler)[:-3] # There is 3 way to specify path: # - absolute path to module # - single name, then module should be in same directory as config # - relative path, then use python as base path. if os.path.exists(handler): module_path = os.path.dirname(handler) elif not os.path.dirname(handler): module_path = os.path.dirname(config_str) else: module_path = os.path.join(search_dir, '..', os.path.dirname(handler)) sys.path.insert(0, module_path) try: __import__(module) except Exception as e: for p in sys.path: print p print >> sys.stderr, "Fail to import handler %s with error %s" % ( handler, e) print_exc() exit(1) register_pre_handler('generateOrders', charting_text)
def init_handlers(config_str, search_dir): handlers = split(get_option_dict()[HANDLERS]) for handler in handlers: module = os.path.basename(handler)[:-3] # There is 3 way to specify path: # - absolute path to module # - single name, then module should be in same directory as config # - relative path, then use python as base path. if os.path.exists(handler): module_path = os.path.dirname(handler) elif not os.path.dirname(handler): module_path = os.path.dirname(config_str) else: module_path = os.path.join(search_dir, '..', os.path.dirname(handler)) sys.path.insert(0, module_path) try: __import__(module) except Exception as e: for p in sys.path: print p print >> sys.stderr, "Fail to import handler %s with error %s" % (handler, e) print_exc() exit(1) register_pre_handler('generateOrders', charting_text)
def init_handlers(config_str, search_dir): try: handlers = split(get_option_dict()[HANDLERS]) except KeyError: error("Missing key in option dict: %s", HANDLERS) handlers = [] for handler in handlers: module = os.path.basename(handler)[:-3] # There is 3 way to specify path: # - absolute path to module # - single name, then module should be in same directory as config # - relative path, then use python as base path. if os.path.exists(handler): module_path = os.path.dirname(handler) elif not os.path.dirname(handler): module_path = os.path.dirname(config_str) else: module_path = os.path.join(search_dir, '..', os.path.dirname(handler)) sys.path.insert(0, module_path) try: __import__(module) except Exception as e: for p in sys.path: error(p) error("Fail to import handler %s with error %s" % (handler, e)) print_exc() exit(1)
def handleChatMessage(sender_id, message_text): # pylint: disable=invalid-name """Called when this player receives a chat message. sender_id is the player who sent the message, and message_text is the text of the sent message.""" empire = fo.getEmpire() if empire is None: fatal("This client has no empire. Doing nothing to handle chat message.") return if empire.eliminated: debug("This empire has been eliminated. Ignoring chat message") return # debug("Received chat message from " + str(senderID) + " that says: " + messageText + " - ignoring it") # perhaps it is a debugging interaction if get_option_dict().get('allow_debug_chat', False) and handle_debug_chat(sender_id, message_text): return if not diplomatic_corp: DiplomaticCorp.handle_pregame_chat(sender_id, message_text) else: diplomatic_corp.handle_midgame_chat(sender_id, message_text)
def generateOrders(): # pylint: disable=invalid-name """Called once per turn to tell the Python AI to generate and issue orders to control its empire. at end of this function, fo.doneTurn() should be called to indicate to the client that orders are finished and can be sent to the server for processing.""" try: rules = fo.getGameRules() debug("Defined game rules:") for rule_name, rule_value in rules.getRulesAsStrings().items(): debug("%s: %s", rule_name, rule_value) debug("Rule RULE_NUM_COMBAT_ROUNDS value: " + str(rules.getInt("RULE_NUM_COMBAT_ROUNDS"))) except Exception as e: error("Exception %s when trying to get game rules" % e, exc_info=True) empire = fo.getEmpire() if empire is None: fatal("This client has no empire. Doing nothing to generate orders.") try: # early abort if no empire. no need to do meter calculations # on last-seen gamestate if nothing can be ordered anyway... # # note that doneTurn() is issued on behalf of the client network # id, not the empire id, so not having a correct empire id does # not invalidate doneTurn() fo.doneTurn() except Exception as e: error("Exception %s in doneTurn() on non-existent empire" % e, exc_info=True) return if empire.eliminated: debug("This empire has been eliminated. Aborting order generation") try: # early abort if already eliminated. no need to do meter calculations # on last-seen gamestate if nothing can be ordered anyway... fo.doneTurn() except Exception as e: error("Exception %s while trying doneTurn() on eliminated empire" % e, exc_info=True) return # This code block is required for correct AI work. info("Meter / Resource Pool updating...") fo.initMeterEstimatesDiscrepancies() fo.updateMeterEstimates(False) fo.updateResourcePools() turn = fo.currentTurn() aistate = get_aistate() turn_uid = aistate.set_turn_uid() debug("\n\n\n" + "=" * 20) debug("Starting turn %s (%s) of game: %s" % (turn, turn_uid, aistate.uid)) debug("=" * 20 + "\n") turn_timer.start("AI planning") # set the random seed (based on galaxy seed, empire name and current turn) # for game-reload consistency. random_seed = str(fo.getGalaxySetupData().seed) + "%05d%s" % (turn, fo.getEmpire().name) random.seed(random_seed) universe = fo.getUniverse() empire = fo.getEmpire() planet_id = PlanetUtilsAI.get_capital() planet = None if planet_id is not None: planet = universe.getPlanet(planet_id) aggression_name = get_trait_name_aggression(aistate.character) debug("***************************************************************************") debug("******* Log info for AI progress chart script. Do not modify. **********") debug("Generating Orders") debug("EmpireID: {empire.empireID}" " Name: {empire.name}_{empire.empireID}_pid:{p_id}_{p_name}RIdx_{res_idx}_{aggression}" " Turn: {turn}".format(empire=empire, p_id=fo.playerID(), p_name=fo.playerName(), res_idx=ResearchAI.get_research_index(), turn=turn, aggression=aggression_name.capitalize())) debug("EmpireColors: {0.colour.r} {0.colour.g} {0.colour.b} {0.colour.a}".format(empire)) if planet: debug("CapitalID: " + str(planet_id) + " Name: " + planet.name + " Species: " + planet.speciesName) else: debug("CapitalID: None Currently Name: None Species: None ") debug("***************************************************************************") debug("***************************************************************************") # When loading a savegame, the AI will already have issued orders for this turn. # To avoid duplicate orders, generally try not to replay turns. However, for debugging # purposes it is often useful to replay the turn and observe varying results after # code changes. Set the replay_after_load flag in the AI config to let the AI issue # new orders after a game load. Note that the orders from the original savegame are # still being issued and the AIstate was saved after those orders were issued. # TODO: Consider adding an option to clear AI orders after load (must save AIstate at turn start then) if fo.currentTurn() == aistate.last_turn_played: info("The AIstate indicates that this turn was already played.") if not check_bool(get_option_dict().get('replay_turn_after_load', 'False')): info("Aborting new order generation. Orders from savegame will still be issued.") try: fo.doneTurn() except Exception as e: error("Exception %s while trying doneTurn()" % e, exc_info=True) return else: info("Issuing new orders anyway.") if turn == 1: human_player = fo.empirePlayerID(1) greet = diplomatic_corp.get_first_turn_greet_message() fo.sendChatMessage(human_player, '%s (%s): [[%s]]' % (empire.name, get_trait_name_aggression(aistate.character), greet)) aistate.prepare_for_new_turn() turn_state.state.update() debug("Calling AI Modules") # call AI modules action_list = [ColonisationAI.survey_universe, ProductionAI.find_best_designs_this_turn, PriorityAI.calculate_priorities, ExplorationAI.assign_scouts_to_explore_systems, ColonisationAI.assign_colony_fleets_to_colonise, InvasionAI.assign_invasion_fleets_to_invade, MilitaryAI.assign_military_fleets_to_systems, FleetUtilsAI.generate_fleet_orders_for_fleet_missions, FleetUtilsAI.issue_fleet_orders_for_fleet_missions, ResearchAI.generate_research_orders, ProductionAI.generate_production_orders, ResourcesAI.generate_resources_orders, ] for action in action_list: try: main_timer.start(action.__name__) action() main_timer.stop() except Exception as e: error("Exception %s while trying to %s" % (e, action.__name__), exc_info=True) main_timer.stop_print_and_clear() turn_timer.stop_print_and_clear() debug('Size of issued orders: ' + str(fo.getOrders().size)) turn_timer.start("Server_Processing") try: fo.doneTurn() except Exception as e: error("Exception %s while trying doneTurn()" % e, exc_info=True) # TODO move it to cycle above finally: aistate.last_turn_played = fo.currentTurn() if using_statprof: try: statprof.stop() statprof.display() statprof.start() except: pass
import os import freeOrionAIInterface as fo from common import six from common.timers import Timer from common.option_tools import get_option_dict, check_bool, DEFAULT_SUB_DIR from common.option_tools import TIMERS_TO_FILE, TIMERS_USE_TIMERS, TIMERS_DUMP_FOLDER import sys # setup module options = get_option_dict() try: USE_TIMERS = check_bool(options[TIMERS_USE_TIMERS]) DUMP_TO_FILE = check_bool(options[TIMERS_TO_FILE]) TIMERS_DIR = os.path.join(fo.getUserDataDir(), DEFAULT_SUB_DIR, options[TIMERS_DUMP_FOLDER]) except KeyError: USE_TIMERS = False def make_header(*args): return ['%-8s ' % x for x in args] def _get_timers_dir(): try: if os.path.isdir(fo.getUserDataDir()) and not os.path.isdir(TIMERS_DIR): os.makedirs(TIMERS_DIR) except OSError: sys.stderr.write("AI Config Error: could not create path %s\n" % TIMERS_DIR) return False
def generateOrders(): # pylint: disable=invalid-name """ Called once per turn to tell the Python AI to generate and issue orders, i.e. to control its empire. After leaving this function, the AI's turn will be finished and its orders will be sent to the server. """ try: rules = fo.getGameRules() debug("Defined game rules:") for rule_name, rule_value in rules.getRulesAsStrings().items(): debug("%s: %s", rule_name, rule_value) debug("Rule RULE_NUM_COMBAT_ROUNDS value: " + str(rules.getInt("RULE_NUM_COMBAT_ROUNDS"))) except Exception as e: error("Exception %s when trying to get game rules" % e, exc_info=True) # If nothing can be ordered anyway, exit early. # Note that there is no need to update meters etc. in this case. empire = fo.getEmpire() if empire is None: fatal("This client has no empire. Aborting order generation.") return if empire.eliminated: info("This empire has been eliminated. Aborting order generation.") return # This code block is required for correct AI work. info("Meter / Resource Pool updating...") fo.initMeterEstimatesDiscrepancies() fo.updateMeterEstimates(False) fo.updateResourcePools() turn = fo.currentTurn() aistate = get_aistate() debug("\n\n\n" + "=" * 20) debug(f"Starting turn {turn}") debug("=" * 20 + "\n") turn_timer.start("AI planning") # set the random seed (based on galaxy seed, empire name and current turn) # for game-reload consistency. random_seed = str( fo.getGalaxySetupData().seed) + "%05d%s" % (turn, fo.getEmpire().name) random.seed(random_seed) empire = fo.getEmpire() aggression_name = get_trait_name_aggression(aistate.character) debug( "***************************************************************************" ) debug( "******* Log info for AI progress chart script. Do not modify. **********" ) debug("Generating Orders") name_parts = ( empire.name, empire.empireID, "pid", fo.playerID(), fo.playerName(), "RIdx", ResearchAI.get_research_index(), aggression_name.capitalize(), ) empire_name = "_".join(str(part) for part in name_parts) debug(f"EmpireID: {empire.empireID} Name: {empire_name} Turn: {turn}") debug(f"EmpireColors: {empire.colour}") planet_id = PlanetUtilsAI.get_capital() if planet_id: planet = fo.getUniverse().getPlanet(planet_id) debug("CapitalID: " + str(planet_id) + " Name: " + planet.name + " Species: " + planet.speciesName) else: debug("CapitalID: None Currently Name: None Species: None ") debug( "***************************************************************************" ) debug( "***************************************************************************" ) # When loading a savegame, the AI will already have issued orders for this turn. # To avoid duplicate orders, generally try not to replay turns. However, for debugging # purposes it is often useful to replay the turn and observe varying results after # code changes. Set the replay_after_load flag in the AI config to let the AI issue # new orders after a game load. Note that the orders from the original savegame are # still being issued and the AIstate was saved after those orders were issued. # TODO: Consider adding an option to clear AI orders after load (must save AIstate at turn start then) if fo.currentTurn() == aistate.last_turn_played: info("The AIstate indicates that this turn was already played.") if not check_bool(get_option_dict().get("replay_turn_after_load", "False")): info( "Aborting new order generation. Orders from savegame will still be issued." ) return info("Issuing new orders anyway.") if turn == 1: human_player = fo.empirePlayerID(1) greet = diplomatic_corp.get_first_turn_greet_message() fo.sendChatMessage( human_player, "%s (%s): [[%s]]" % (empire.name, get_trait_name_aggression(aistate.character), greet)) aistate.prepare_for_new_turn() debug("Calling AI Modules") # call AI modules action_list = [ ColonisationAI.survey_universe, ShipDesignAI.Cache.update_for_new_turn, PriorityAI.calculate_priorities, ExplorationAI.assign_scouts_to_explore_systems, ColonisationAI.assign_colony_fleets_to_colonise, InvasionAI.assign_invasion_fleets_to_invade, MilitaryAI.assign_military_fleets_to_systems, FleetUtilsAI.generate_fleet_orders_for_fleet_missions, FleetUtilsAI.issue_fleet_orders_for_fleet_missions, ResearchAI.generate_research_orders, ProductionAI.generate_production_orders, ResourcesAI.generate_resources_orders, ] for action in action_list: try: main_timer.start(action.__name__) action() main_timer.stop() except Exception as e: error("Exception %s while trying to %s" % (e, action.__name__), exc_info=True) main_timer.stop_print_and_clear() turn_timer.stop_print_and_clear() turn_timer.start("Server_Processing") aistate.last_turn_played = fo.currentTurn()
import os import freeOrionAIInterface as fo from common.timers import Timer from common.option_tools import get_option_dict, check_bool, DEFAULT_SUB_DIR from common.option_tools import TIMERS_TO_FILE, TIMERS_USE_TIMERS, TIMERS_DUMP_FOLDER import sys # setup module options = get_option_dict() try: USE_TIMERS = check_bool(options[TIMERS_USE_TIMERS]) DUMP_TO_FILE = check_bool(options[TIMERS_TO_FILE]) TIMERS_DIR = os.path.join(fo.getUserDataDir(), DEFAULT_SUB_DIR, options[TIMERS_DUMP_FOLDER]) except KeyError: USE_TIMERS = False def make_header(*args): return ['%-8s ' % x for x in args] def _get_timers_dir(): try: if os.path.isdir(fo.getUserDataDir()) and not os.path.isdir(TIMERS_DIR): os.makedirs(TIMERS_DIR) except OSError: sys.stderr.write("AI Config Error: could not create path %s\n" % TIMERS_DIR) return False return TIMERS_DIR
from logging import debug from common.option_tools import check_bool, get_option_dict # minimum evaluation score that a planet must reach so it is considered for outposting or colonizing MINIMUM_COLONY_SCORE = 60 # resource production is evaluated as production * priority_for_the_resource * RESOURCE_PRIORITY_MULTIPLIER RESOURCE_PRIORITY_MULTIPLIER = 0.5 DEBUG_COLONY_RATING = check_bool(get_option_dict().get("debug_planet_rating", "False")) def debug_rating(*args, **kwargs): if DEBUG_COLONY_RATING: debug(*args, **kwargs)
def configure_debug_chat(empire_id: int) -> None: global _chat_handler if get_option_dict().get('allow_debug_chat', False): _chat_handler = DebugChatHandler(empire_id) else: _chat_handler = NormalChatHandler()