def save(self, db): super(Trader, self).save(db) # mark self as a trader db("UPDATE player SET is_trader = 1 WHERE rowid = ?", self.worldid) for ship in self.ships: # prepare values ship_state = self.ships[ship] remaining_ticks = None # get current callback in scheduler, according to ship state, to retrieve # the number of ticks, when the call will actually be done current_callback = None if ship_state == self.shipStates.reached_warehouse: current_callback = Callback(self.ship_idle, ship) if current_callback is not None: # current state has a callback calls = Scheduler().get_classinst_calls(self, current_callback) assert len(calls) == 1, "got %s calls for saving %s: %s" %(len(calls), current_callback, calls) remaining_ticks = max(calls.values()[0], 1) targeted_warehouse = None if ship.worldid not in self.office else self.office[ship.worldid].worldid # put them in the database db("INSERT INTO trader_ships(rowid, state, remaining_ticks, targeted_warehouse) \ VALUES(?, ?, ?, ?)", ship.worldid, ship_state.index, remaining_ticks, targeted_warehouse)
def end(self): self.log.debug("Ending session") self.is_alive = False LastActivePlayerSettlementManager().remove() LastActivePlayerSettlementManager.destroy_instance() self.gui.session = None Scheduler().rem_all_classinst_calls(self) ExtScheduler().rem_all_classinst_calls(self) if horizons.main.fife.get_fife_setting("PlaySounds"): for emitter in horizons.main.fife.sound.emitter['ambient'][:]: emitter.stop() horizons.main.fife.sound.emitter['ambient'].remove(emitter) horizons.main.fife.sound.emitter['effects'].stop() horizons.main.fife.sound.emitter['speech'].stop() if hasattr(self, "cursor"): # the line below would crash uglily on ^C self.cursor.remove() self.cursor = None self.world = None self.keylistener = None self.ingame_gui = None self.view = None self.manager = None self.timer = None self.scenario_eventhandler = None Scheduler.destroy_instance() self.selected_instances = None self.selection_groups = None
def __init__(self, db, rng_seed=None): """ Unfortunately, right now there is no other way to setup Dummy versions of the GUI, View etc., unless we want to patch the references in the session module. """ super(LivingObject, self).__init__() self.gui = Dummy() self.db = db self.savecounter = 0 # this is a new game. self.is_alive = True WorldObject.reset() NamedObject.reset() AIPlayer.clear_caches() # Game self.current_tick = 0 self.random = self.create_rng(rng_seed) self.timer = self.create_timer() Scheduler.create_instance(self.timer) ExtScheduler.create_instance(Dummy) self.manager = self.create_manager() self.view = Dummy() self.view.renderer = Dummy() Entities.load(self.db) self.scenario_eventhandler = Dummy() self.campaign = {} self.selected_instances = [] # GUI self.gui.session = self self.ingame_gui = Dummy() GAME_SPEED.TICKS_PER_SECOND = 16
def end(self): self.log.debug("Ending session") self.is_alive = False self.gui.session = None Scheduler().rem_all_classinst_calls(self) ExtScheduler().rem_all_classinst_calls(self) if horizons.main.fife.get_fife_setting("PlaySounds"): for emitter in horizons.main.fife.emitter['ambient'][:]: emitter.stop() horizons.main.fife.emitter['ambient'].remove(emitter) horizons.main.fife.emitter['effects'].stop() horizons.main.fife.emitter['speech'].stop() self.cursor = None self.world = None self.keylistener = None self.ingame_gui = None self.view = None self.manager = None self.timer = None self.scenario_eventhandler = None Scheduler.destroy_instance() self.selected_instances = None self.selection_groups = None
def save(self, db): super(Pirate, self).save(db) db("UPDATE player SET is_pirate = 1 WHERE rowid = ?", self.worldid) db("INSERT INTO pirate_home_point(x, y) VALUES(?, ?)", self.home_point.x, self.home_point.y) current_callback = Callback(self.tick) calls = Scheduler().get_classinst_calls(self, current_callback) assert len(calls) == 1, "got %s calls for saving %s: %s" % (len(calls), current_callback, calls) remaining_ticks = max(calls.values()[0], 1) current_callback_long = Callback(self.tick_long) calls = Scheduler().get_classinst_calls(self, current_callback_long) assert len(calls) == 1, "got %s calls for saving %s: %s" % (len(calls), current_callback_long, calls) remaining_ticks_long = max(calls.values()[0], 1) db("INSERT INTO ai_pirate(rowid, remaining_ticks, remaining_ticks_long) VALUES(?, ?, ?)", self.worldid, remaining_ticks, remaining_ticks_long) for ship in self.ships: ship_state = self.ships[ship] db("INSERT INTO pirate_ships(rowid, state) VALUES(?, ?)", ship.worldid, ship_state.index) # save unit manager self.unit_manager.save(db) # save combat manager self.combat_manager.save(db) # save strategy manager self.strategy_manager.save(db) # save behavior manager self.behavior_manager.save(db)
def save(self, db): super(AIPlayer, self).save(db) # save the player db("UPDATE player SET client_id = 'AIPlayer' WHERE rowid = ?", self.worldid) current_callback = Callback(self.tick) calls = Scheduler().get_classinst_calls(self, current_callback) assert len(calls) == 1, "got %s calls for saving %s: %s" % (len(calls), current_callback, calls) remaining_ticks = max(calls.values()[0], 1) db("INSERT INTO ai_player(rowid, need_more_ships, need_feeder_island, remaining_ticks) VALUES(?, ?, ?, ?)", \ self.worldid, self.need_more_ships, self.need_feeder_island, remaining_ticks) # save the ships for ship, state in self.ships.iteritems(): db("INSERT INTO ai_ship(rowid, owner, state) VALUES(?, ?, ?)", ship.worldid, self.worldid, state.index) # save the land managers for land_manager in self.islands.itervalues(): land_manager.save(db) # save the settlement managers for settlement_manager in self.settlement_managers: settlement_manager.save(db) # save the missions for mission in self.missions: mission.save(db) # save the personality manager self.personality_manager.save(db)
def save(self, db): super(Collector, self).save(db) # save state and remaining ticks for next callback # retrieve remaining ticks according current callback according to state current_callback = None remaining_ticks = None if self.state == self.states.idle: current_callback = self.search_job elif self.state == self.states.working: current_callback = self.finish_working if current_callback is not None: calls = Scheduler().get_classinst_calls(self, current_callback) assert len(calls) == 1, 'Collector should have callback %s scheduled, but has %s' % \ (current_callback, [ str(i) for i in Scheduler().get_classinst_calls(self).keys() ]) remaining_ticks = max(calls.values()[0], 1) # save a number > 0 db("INSERT INTO collector(rowid, state, remaining_ticks, start_hidden) VALUES(?, ?, ?, ?)", self.worldid, self.state.index, remaining_ticks, self.start_hidden) # save the job if self.job is not None: obj_id = -1 if self.job.object is None else self.job.object.worldid # this is not in 3rd normal form since the object is saved multiple times but # it preserves compatiblity with old savegames this way. for entry in self.job.reslist: db("INSERT INTO collector_job(collector, object, resource, amount) VALUES(?, ?, ?, ?)", self.worldid, obj_id, entry.res, entry.amount)
def end(self): self.log.debug("Ending session") self.is_alive = False # Has to be done here, cause the manager uses Scheduler! Scheduler().rem_all_classinst_calls(self) ExtScheduler().rem_all_classinst_calls(self) horizons.globals.fife.sound.end() # these will call end() if the attribute still exists by the LivingObject magic self.ingame_gui = None # keep this before world self.world.end() # must be called before the world ref is gone self.world = None self.view = None self.manager = None self.timer = None self.scenario_eventhandler = None Scheduler().end() Scheduler.destroy_instance() self.selected_instances = None self.selection_groups = None horizons.main._modules.session = None self._clear_caches() # subscriptions shouldn't survive listeners (except the main Gui) self.gui.unsubscribe() SettingChanged.unsubscribe(self._on_setting_changed) MessageBus().reset() self.gui.subscribe()
def __init__(self, gui, db): super(Session, self).__init__() self.log.debug("Initing session") self.gui = gui # main gui, not ingame gui self.db = db # main db for game data (game.sqlite) # this saves how often the current game has been saved self.savecounter = 0 self.is_alive = True WorldObject.reset() NamedObject.reset() #game self.random = self.create_rng() self.timer = Timer() Scheduler.create_instance(self.timer) self.manager = self.create_manager() self.view = View(self, (15, 15)) Entities.load(self.db) self.scenario_eventhandler = ScenarioEventHandler(self) # dummy handler with no events self.campaign = {} #GUI self.gui.session = self self.ingame_gui = IngameGui(self, self.gui) self.keylistener = IngameKeyListener(self) self.display_speed() self.selected_instances = set() self.selection_groups = [set()] * 10 # List of sets that holds the player assigned unit groups.
def end(self): self.log.debug("Ending session") self.is_alive = False # Has to be done here, cause the manager uses Scheduler! Scheduler().rem_all_classinst_calls(self) ExtScheduler().rem_all_classinst_calls(self) horizons.globals.fife.sound.end() # these will call end() if the attribute still exists by the LivingObject magic self.ingame_gui = None # keep this before world if hasattr(self, 'world'): # must be called before the world ref is gone, but may not exist yet while loading self.world.end() self.world = None self.view = None self.manager = None self.timer = None self.scenario_eventhandler = None Scheduler().end() Scheduler.destroy_instance() self.selected_instances = None self.selection_groups = None self._clear_caches() # discard() in case loading failed and we did not yet subscribe SettingChanged.discard(self._on_setting_changed) MessageBus().reset()
def __init__(self, db, rng_seed=None, ingame_gui_class=IngameGui): super(Session, self).__init__() assert isinstance(db, horizons.util.uhdbaccessor.UhDbAccessor) self.log.debug("Initing session") self.db = db # main db for game data (game.sql) # this saves how often the current game has been saved self.savecounter = 0 self.is_alive = True self._clear_caches() #game self.random = self.create_rng(rng_seed) assert isinstance(self.random, Random) self.timer = self.create_timer() Scheduler.create_instance(self.timer) self.manager = self.create_manager() self.view = View() Entities.load(self.db) self.scenario_eventhandler = ScenarioEventHandler(self) # dummy handler with no events #GUI self._ingame_gui_class = ingame_gui_class self.selected_instances = set() # List of sets that holds the player assigned unit groups. self.selection_groups = [set()] * 10 self._old_autosave_interval = None
def cleanup(cls): """ If a test uses manual session management, we cannot be sure that session.end was called before a crash, leaving the game in an unclean state. This method should return the game to a valid state. """ Scheduler.destroy_instance()
def setUp(self): self.inventory = GenericStorage() self.owner_inventory = GenericStorage() class Instance: def __init__(self, comp): self.comp = comp self.owner = None # type: Optional[Instance] def get_component(self, x): class Comp: inventory = self.comp return Comp() self.tradepost = TradePostComponent() self.tradepost.instance = Instance(self.inventory) self.tradepost.instance.owner = Instance(self.owner_inventory) self.tradepost.initialize() class Timer: def add_call(self, x): pass def get_ticks(self, x): return 100 Scheduler.create_instance(timer=Timer())
def end(self): self.log.debug("Ending session") self.is_alive = False self.gui.session = None # Has to be done here, cause the manager uses Scheduler! self.end_production_finished_icon_manager() Scheduler().rem_all_classinst_calls(self) ExtScheduler().rem_all_classinst_calls(self) if horizons.globals.fife.get_fife_setting("PlaySounds"): for emitter in horizons.globals.fife.sound.emitter['ambient'][:]: emitter.stop() horizons.globals.fife.sound.emitter['ambient'].remove(emitter) horizons.globals.fife.sound.emitter['effects'].stop() horizons.globals.fife.sound.emitter['speech'].stop() if hasattr(self, "cursor"): # the line below would crash uglily on ^C self.cursor.remove() if hasattr(self, 'cursor') and self.cursor is not None: self.cursor.end() # these will call end() if the attribute still exists by the LivingObject magic self.ingame_gui = None # keep this before world LastActivePlayerSettlementManager().remove() # keep after ingame_gui LastActivePlayerSettlementManager.destroy_instance() self.cursor = None self.world.end() # must be called before the world ref is gone self.world = None self.keylistener = None self.view = None self.manager = None self.timer = None self.scenario_eventhandler = None Scheduler().end() Scheduler.destroy_instance() self.selected_instances = None self.selection_groups = None self.status_icon_manager.end() self.status_icon_manager = None horizons.main._modules.session = None self._clear_caches() # subscriptions shouldn't survive listeners (except the main Gui) self.gui.unsubscribe() AutosaveIntervalChanged.unsubscribe(self._on_autosave_interval_changed) MessageBus().reset() self.gui.subscribe()
def end(self): self.log.debug("Ending session") self.is_alive = False self.gui.session = None Scheduler().rem_all_classinst_calls(self) ExtScheduler().rem_all_classinst_calls(self) if horizons.main.fife.get_fife_setting("PlaySounds"): for emitter in horizons.main.fife.sound.emitter['ambient'][:]: emitter.stop() horizons.main.fife.sound.emitter['ambient'].remove(emitter) horizons.main.fife.sound.emitter['effects'].stop() horizons.main.fife.sound.emitter['speech'].stop() if hasattr(self, "cursor"): # the line below would crash uglily on ^C self.cursor.remove() if hasattr(self, 'cursor') and self.cursor is not None: self.cursor.end() # these will call end() if the attribute still exists by the LivingObject magic self.ingame_gui = None # keep this before world LastActivePlayerSettlementManager().remove() # keep after ingame_gui LastActivePlayerSettlementManager.destroy_instance() self.cursor = None try: # This is likely to throw when the game state is invalid. # Try to continue cleanup afterwards even if this fails. # NOTE: This is not a proper solution, separating sessions by design (e.g. single processes) would be. self.world.end() # must be called before the world ref is gone except Exception: import traceback traceback.print_exc() print 'Exception on world end(), trying to continue to cleanup' self.world = None self.keylistener = None self.view = None self.manager = None self.timer = None self.scenario_eventhandler = None Scheduler().end() Scheduler.destroy_instance() self.selected_instances = None self.selection_groups = None self.status_icon_manager = None self.message_bus = None horizons.main._modules.session = None self._clear_caches()
def save(self, db): super(AIPlayer, self).save(db) # save the player db("UPDATE player SET client_id = 'AIPlayer' WHERE rowid = ?", self.worldid) current_callback = Callback(self.tick) calls = Scheduler().get_classinst_calls(self, current_callback) assert len(calls) == 1, "got {0!s} calls for saving {1!s}: {2!s}".format(len(calls), current_callback, calls) remaining_ticks = max(calls.values()[0], 1) current_callback_long = Callback(self.tick_long) calls = Scheduler().get_classinst_calls(self, current_callback_long) assert len(calls) == 1, "got {0!s} calls for saving {1!s}: {2!s}".format(len(calls), current_callback_long, calls) remaining_ticks_long = max(calls.values()[0], 1) db("INSERT INTO ai_player(rowid, need_more_ships, need_more_combat_ships, need_feeder_island, remaining_ticks, remaining_ticks_long) VALUES(?, ?, ?, ?, ?, ?)", self.worldid, self.need_more_ships, self.need_more_combat_ships, self.need_feeder_island, remaining_ticks, remaining_ticks_long) # save the ships for ship, state in self.ships.iteritems(): db("INSERT INTO ai_ship(rowid, owner, state) VALUES(?, ?, ?)", ship.worldid, self.worldid, state.index) # save the land managers for land_manager in self.islands.itervalues(): land_manager.save(db) # save the settlement managers for settlement_manager in self.settlement_managers: settlement_manager.save(db) # save the missions for mission in self.missions: mission.save(db) # save the personality manager self.personality_manager.save(db) # save the unit manager self.unit_manager.save(db) # save the combat manager self.combat_manager.save(db) # save the strategy manager self.strategy_manager.save(db) # save the behavior manager self.behavior_manager.save(db)
def save(self, db): super(WildAnimal, self).save(db) # save members db("INSERT INTO wildanimal(rowid, health, can_reproduce) VALUES(?, ?, ?)", \ self.worldid, self.health, int(self.can_reproduce)) # set island as owner db("UPDATE unit SET owner = ? WHERE rowid = ?", self.home_island.worldid, self.worldid) # save remaining ticks when in waiting state if self.state == self.states.no_job_waiting: calls = Scheduler().get_classinst_calls(self, self.handle_no_possible_job) assert(len(calls) == 1), 'calls: %s' % calls remaining_ticks = max(calls.values()[0], 1) # we have to save a number > 0 db("UPDATE collector SET remaining_ticks = ? WHERE rowid = ?", \ remaining_ticks, self.worldid)
def save(self, db): super(Pirate, self).save(db) db("UPDATE player SET is_pirate = 1 WHERE rowid = ?", self.worldid) db("INSERT INTO pirate_home_point(x, y) VALUES(?, ?)", self.home_point.x, self.home_point.y) for ship in self.ships: # prepare values ship_state = self.ships[ship] current_callback = Callback(self.lookout, ship) calls = Scheduler().get_classinst_calls(self, current_callback) assert len(calls) == 1, "got %s calls for saving %s: %s" %(len(calls), current_callback, calls) remaining_ticks = max(calls.values()[0], 1) db("INSERT INTO pirate_ships(rowid, state, remaining_ticks) VALUES(?, ?, ?)", ship.worldid, ship_state.index, remaining_ticks)
def end(self): self.log.debug("Ending session") self.is_alive = False self.gui.session = None Scheduler().rem_all_classinst_calls(self) ExtScheduler().rem_all_classinst_calls(self) if horizons.main.fife.get_fife_setting("PlaySounds"): for emitter in horizons.main.fife.sound.emitter['ambient'][:]: emitter.stop() horizons.main.fife.sound.emitter['ambient'].remove(emitter) horizons.main.fife.sound.emitter['effects'].stop() horizons.main.fife.sound.emitter['speech'].stop() if hasattr(self, "cursor"): # the line below would crash uglily on ^C self.cursor.remove() if hasattr(self, 'cursor') and self.cursor is not None: self.cursor.end() # these will call end() if the attribute still exists by the LivingObject magic self.ingame_gui = None # keep this before world LastActivePlayerSettlementManager().remove() # keep after ingame_gui LastActivePlayerSettlementManager.destroy_instance() self.cursor = None self.world.end() # must be called before the world ref is gone self.world = None self.keylistener = None self.view = None self.manager = None self.timer = None self.scenario_eventhandler = None Scheduler().end() Scheduler.destroy_instance() self.selected_instances = None self.selection_groups = None self.status_icon_manager = None self.message_bus = None horizons.main._modules.session = None self._clear_caches()
def __init__(self, gui, db, rng_seed=None): super(Session, self).__init__() assert isinstance(db, horizons.util.uhdbaccessor.UhDbAccessor) self.log.debug("Initing session") self.gui = gui # main gui, not ingame gui self.db = db # main db for game data (game.sql) # this saves how often the current game has been saved self.savecounter = 0 self.is_alive = True self._clear_caches() #game self.random = self.create_rng(rng_seed) assert isinstance(self.random, Random) self.timer = self.create_timer() Scheduler.create_instance(self.timer) self.manager = self.create_manager() self.view = View(self) Entities.load(self.db) self.scenario_eventhandler = ScenarioEventHandler(self) # dummy handler with no events self.campaign = {} #GUI self.gui.session = self self.ingame_gui = IngameGui(self, self.gui) self.keylistener = IngameKeyListener(self) self.coordinates_tooltip = None self.display_speed() LastActivePlayerSettlementManager.create_instance(self) self.status_icon_manager = StatusIconManager( renderer=self.view.renderer['GenericRenderer'], layer=self.view.layers[LAYERS.OBJECTS] ) self.production_finished_icon_manager = None self.create_production_finished_icon_manager() self.selected_instances = set() self.selection_groups = [set() for _ in range(10)] # List of sets that holds the player assigned unit groups. self._old_autosave_interval = None
def __init__(self, gui, db, rng_seed=None): super(Session, self).__init__() assert isinstance(gui, Gui) assert isinstance(db, horizons.util.uhdbaccessor.UhDbAccessor) self.log.debug("Initing session") self.gui = gui # main gui, not ingame gui self.db = db # main db for game data (game.sql) # this saves how often the current game has been saved self.savecounter = 0 self.is_alive = True self.message_bus = MessageBus() # misc WorldObject.reset() NamedComponent.reset() AIPlayer.clear_caches() #game self.random = self.create_rng(rng_seed) assert isinstance(self.random, Random) self.timer = self.create_timer() Scheduler.create_instance(self.timer) self.manager = self.create_manager() self.view = View(self) Entities.load(self.db) self.scenario_eventhandler = ScenarioEventHandler(self) # dummy handler with no events self.campaign = {} #GUI self.gui.session = self self.ingame_gui = IngameGui(self, self.gui) self.keylistener = IngameKeyListener(self) self.coordinates_tooltip = None self.display_speed() LastActivePlayerSettlementManager.create_instance(self) self.status_icon_manager = StatusIconManager(self) self.selected_instances = set() self.selection_groups = [set()] * 10 # List of sets that holds the player assigned unit groups.
def __init__(self, db, rng_seed=None): """ Unfortunately, right now there is no other way to setup Dummy versions of the GUI, View etc., unless we want to patch the references in the session module. """ super(LivingObject, self).__init__() self.gui = Dummy() self.db = db self.savecounter = 0 # this is a new game. self.is_alive = True WorldObject.reset() NamedComponent.reset() AIPlayer.clear_caches() # Game self.random = self.create_rng(rng_seed) self.timer = self.create_timer() Scheduler.create_instance(self.timer) ExtScheduler.create_instance(Dummy) self.manager = self.create_manager() self.view = Dummy() self.view.renderer = Dummy() Entities.load(self.db) self.scenario_eventhandler = Dummy() self.campaign = {} self.message_bus = MessageBus() self.status_icon_manager = StatusIconManager(self) # GUI self.gui.session = self self.ingame_gui = Dummy() LastActivePlayerSettlementManager.create_instance(self) self.selected_instances = set() self.selection_groups = [set()] * 10 # List of sets that holds the player assigned unit groups. GAME_SPEED.TICKS_PER_SECOND = 16
def save(self, db): super(Collector, self).save(db) # save state and remaining ticks for next callback # retrieve remaining ticks according current callback according to state current_callback = None remaining_ticks = None if self.state == self.states.idle: current_callback = self.search_job elif self.state == self.states.working: current_callback = self.finish_working if current_callback is not None: calls = Scheduler().get_classinst_calls(self, current_callback) assert len(calls) == 1, "Collector should have callback %s scheduled, but has %s" % ( current_callback, [str(i) for i in Scheduler().get_classinst_calls(self).keys()], ) remaining_ticks = max(calls.values()[0], 1) # save a number > 0 db( "INSERT INTO collector(rowid, state, remaining_ticks, start_hidden) VALUES(?, ?, ?, ?)", self.worldid, self.state.index, remaining_ticks, self.start_hidden, ) # save the job if self.job is not None: obj_id = -1 if self.job.object is None else self.job.object.worldid db( "INSERT INTO collector_job(rowid, object, resource, amount) VALUES(?, ?, ?, ?)", self.worldid, obj_id, self.job.res, self.job.amount, )
def remove(self): """Clean up""" Scheduler.rem_all_classinst_calls(self) self.__inventory_copy = None self.__storage_component = None self.__message_class = None
def recover(self, building): super(FireDisaster, self).recover(building) RemoveStatusIcon.broadcast(self, building, FireStatusIcon) Scheduler().rem_call(self, Callback(self.wreak_havoc, building)) self._affected_buildings.remove(building)
def remove(self): self._instance.getLocationRef().getLayer().deleteInstance( self._instance) self._instance = None Scheduler().rem_all_classinst_calls(self) super().remove()
def schedule_action(self, action): if self.sleep_ticks_remaining > 0: Scheduler().add_new_object(Callback(action, self.session), self, run_in=self.sleep_ticks_remaining) else: action(self.session)
def test_create_then_register_with_timer(self): # create a new scheduler but do not reset timer mock Scheduler.destroy_instance() Scheduler.create_instance(self.timer) self.scheduler = Scheduler() self.timer.add_call.assert_called_once_with(self.scheduler.tick)
def load(self, options): """Loads a map. Key method for starting a game.""" """ TUTORIAL: Here you see how the vital game elements (and some random things that are also required) are initialised. """ if options.is_scenario: # game_identifier is a yaml file, that contains reference to actual map file self.scenario_eventhandler = ScenarioEventHandler( self, options.game_identifier) # scenario maps can be normal maps or scenario maps: map_filename = self.scenario_eventhandler.get_map_file() options.game_identifier = os.path.join( SavegameManager.scenario_maps_dir, map_filename) if not os.path.exists(options.game_identifier): options.game_identifier = os.path.join( SavegameManager.maps_dir, map_filename) options.is_map = True self.log.debug("Session: Loading from %s", options.game_identifier) savegame_db = SavegameAccessor( options.game_identifier, options.is_map) # Initialize new dbreader savegame_data = SavegameManager.get_metadata(savegame_db.db_path) self.view.resize_layers(savegame_db) # load how often the game has been saved (used to know the difference between # a loaded and a new game) self.savecounter = savegame_data.get('savecounter', 0) if savegame_data.get('rng_state', None): rng_state_list = json.loads(savegame_data['rng_state']) # json treats tuples as lists, but we need tuples here, so convert back def rec_list_to_tuple(x): if isinstance(x, list): return tuple(rec_list_to_tuple(i) for i in x) else: return x rng_state_tuple = rec_list_to_tuple(rng_state_list) # changing the rng is safe for mp, as all players have to have the same map self.random.setstate(rng_state_tuple) self.world = World( self ) # Load horizons.world module (check horizons/world/__init__.py) self.world._init(savegame_db, options.force_player_id, disasters_enabled=options.disasters_enabled) self.view.load(savegame_db) # load view if not self.is_game_loaded(): options.init_new_world(self) else: # try to load scenario data self.scenario_eventhandler.load(savegame_db) self.manager.load( savegame_db ) # load the manager (there might me old scheduled ticks). self.world.init_fish_indexer() # now the fish should exist if self.is_game_loaded(): LastActivePlayerSettlementManager().load( savegame_db) # before ingamegui self.ingame_gui.load( savegame_db) # load the old gui positions and stuff for instance_id in savegame_db( "SELECT id FROM selected WHERE `group` IS NULL" ): # Set old selected instance obj = WorldObject.get_object_by_id(instance_id[0]) self.selected_instances.add(obj) obj.get_component(SelectableComponent).select() for group in xrange(len( self.selection_groups)): # load user defined unit groups for instance_id in savegame_db( "SELECT id FROM selected WHERE `group` = ?", group): self.selection_groups[group].add( WorldObject.get_object_by_id(instance_id[0])) # cursor has to be inited last, else player interacts with a not inited world with it. self.current_cursor = 'default' self.cursor = SelectionTool(self) # Set cursor correctly, menus might need to be opened. # Open menus later; they may need unit data not yet inited self.cursor.apply_select() Scheduler().before_ticking() savegame_db.close() assert hasattr(self.world, "player"), 'Error: there is no human player' """
def finish_production_now(self): """Makes the production finish now""" if self._state != PRODUCTION.STATES.producing: return Scheduler().rem_call(self, self._get_producing_callback()) self._finished_producing()
def buy_resource(self, ship_worldid, resource_id, amount, add_error_type=False, suppress_messages=False): """ Attempt to buy the given amount of resource from the ship, return the amount bought @param add_error_type: if True, return tuple where second item is ERROR_TYPE""" ship = WorldObject.get_object_by_id(ship_worldid) def err(string, err_type): if not suppress_messages and ship.owner.is_local_player: self.session.ingame_gui.message_widget.add_custom( string, point=ship.position) return 0 if not add_error_type else 0, err_type if resource_id not in self.buy_list: return err(T("The trade partner does not buy this."), TRADE_ERROR_TYPE.PERMANENT) price = int( self.session.db.get_res_value(resource_id) * TRADER.PRICE_MODIFIER_SELL) # price per ton of resource assert price > 0 # can't buy more than the ship has amount = min( amount, ship.get_component(StorageComponent).inventory[resource_id]) if amount <= 0: return err(T("You do not possess this."), TRADE_ERROR_TYPE.PERMANENT) # can't buy more than we can fit in the inventory amount = min(amount, self.get_inventory().get_free_space_for(resource_id)) if amount <= 0: return err(T("The trade partner can not store more of this."), TRADE_ERROR_TYPE.TEMPORARY) # can't buy more than we can afford amount = min(amount, self.get_owner_inventory()[RES.GOLD] // price) if amount <= 0: return err(T("The trade partner can not afford to buy this."), TRADE_ERROR_TYPE.TEMPORARY) # can't buy more than we are trying to buy according to the settings amount = min( amount, self.slots[self.buy_list[resource_id]].limit - self.get_inventory()[resource_id]) if amount <= 0: return err(T("The trade partner does not buy more of this."), TRADE_ERROR_TYPE.TEMPORARY) total_price = price * amount assert self.get_owner_inventory().alter(RES.GOLD, -total_price) == 0 assert ship.owner.get_component(StorageComponent).inventory.alter( RES.GOLD, total_price) == 0 assert self.get_inventory().alter(resource_id, amount) == 0 assert ship.get_component(StorageComponent).inventory.alter( resource_id, -amount) == 0 self.trade_history.append((Scheduler().cur_tick, ship.owner.worldid, resource_id, amount, -total_price)) self.buy_history[Scheduler().cur_tick] = (resource_id, amount, total_price) self.total_expenses += total_price self._changed() return amount if not add_error_type else amount, TRADE_ERROR_TYPE.TEMPORARY
def hide(self): super(BoatbuilderTab, self).hide() Scheduler().rem_all_classinst_calls(self)
def _clean_job_history_log(self): """ remove too old entries """ first_relevant_tick = Scheduler().cur_tick - self.get_utilization_history_length() while len(self._job_history) > 1 and self._job_history[1][0] < first_relevant_tick: self._job_history.popleft()
def show(self): super(BoatbuilderTab, self).show() Scheduler().add_new_object(Callback(self.refresh), self, run_in=GAME_SPEED.TICKS_PER_SECOND, loops=-1)
def save(self, db): ticks = Scheduler().get_remaining_ticks(self, self.run, True) db("INSERT INTO disaster_manager(remaining_ticks) VALUES(?)", ticks) for disaster in self._active_disaster.values(): disaster.save(db)
def time_passed(session, seconds): """Returns whether at least *seconds* seconds have passed since the game started.""" return (Scheduler().cur_tick >= Scheduler().get_ticks(seconds))
def load(self, db, worldid): super(ColorOverlayComponent, self).load(db, worldid) Scheduler().add_new_object(self.initialize, self, run_in=0)
def get_age(self): return Scheduler().cur_tick - self._creation_tick
def remove(self): """Clean up""" Scheduler().rem_all_classinst_calls(self) self.__inventory_copy = None self.__storage_component = None self.__message_class = None
def end(self): Scheduler().rem_all_classinst_calls(self) self.session = None self._events = None self._data = None
def setUp(self): self.callback = Mock() self.timer = Mock() Scheduler.create_instance(self.timer) self.scheduler = Scheduler() self.timer.reset_mock()
def handle_no_possible_job(self): """Called when we can't find a job. default is to wait and try again in a few secs""" self.log.debug("%s: found no possible job, retry in %s ticks", self, COLLECTORS.DEFAULT_WAIT_TICKS) Scheduler().add_new_object(self.search_job, self, COLLECTORS.DEFAULT_WAIT_TICKS)
def save(self, db): super(ProductionBuilder, self).save(db) translated_last_collector_improvement_storage = self.last_collector_improvement_storage - Scheduler( ).cur_tick # pre-translate for the loading process translated_last_collector_improvement_road = self.last_collector_improvement_road - Scheduler( ).cur_tick # pre-translate for the loading process db( "INSERT INTO ai_production_builder(rowid, settlement_manager, last_collector_improvement_storage, last_collector_improvement_road) VALUES(?, ?, ?, ?)", self.worldid, self.settlement_manager.worldid, translated_last_collector_improvement_storage, translated_last_collector_improvement_road) for (x, y), (purpose, _) in self.plan.iteritems(): db( "INSERT INTO ai_production_builder_plan(production_builder, x, y, purpose) VALUES(?, ?, ?, ?)", self.worldid, x, y, purpose)
def ship_idle(self, ship): """Called if a ship is idle. Sends ship to a random place. @param ship: ship instance""" self.log.debug("%s %s: idle, moving to random location", self.__class__.__name__, self.worldid) Scheduler().add_new_object(Callback(self.send_ship, ship), self)
def tearDown(self): Scheduler.destroy_instance()
def init_new_world(self, trader_enabled, pirate_enabled, natural_resource_multiplier): """ This should be called if a new map is loaded (not a savegame, a fresh map). In other words, when it is loaded for the first time. NOTE: commands for creating the world objects are executed directly, bypassing the manager. This is necessary because else the commands would be transmitted over the wire in network games. @return: the coordinates of the players first ship """ # workaround: the creation of all the objects causes a lot of logging output we don't need. # therefore, reset the levels for now loggers_to_silence = {'world.production': None} for logger_name in loggers_to_silence: logger = logging.getLogger(logger_name) loggers_to_silence[logger_name] = logger.getEffectiveLevel() logger.setLevel(logging.WARN) # add a random number of environmental objects if natural_resource_multiplier != 0: self._add_nature_objects(natural_resource_multiplier) # reset loggers, see above for logger_name, level in loggers_to_silence.iteritems(): logging.getLogger(logger_name).setLevel(level) # add free trader if trader_enabled: self.trader = Trader(self.session, 99999, u"Free Trader", Color()) ret_coords = None for player in self.players: # Adding ships for the players # hack to place the ship on the development map point = self.get_random_possible_ship_position() # Execute command directly, not via manager, because else it would be transmitted over the # network to other players. Those however will do the same thing anyways. ship = CreateUnit(player.worldid, UNITS.PLAYER_SHIP, point.x, point.y)(issuer=self.session.world.player) # give ship basic resources for res, amount in self.session.db( "SELECT resource, amount FROM start_resources"): ship.get_component(StorageComponent).inventory.alter( res, amount) if player is self.player: ret_coords = point.to_tuple() # HACK: Store starting ship as first unit group, and select it def _preselect_player_ship(player_ship): sel_comp = player_ship.get_component(SelectableComponent) sel_comp.select(reset_cam=True) self.session.selected_instances = set([player_ship]) self.session.ingame_gui.handle_selection_group(1, True) sel_comp.show_menu() select_ship = partial(_preselect_player_ship, ship) Scheduler().add_new_object(select_ship, ship, run_in=0) # load the AI stuff only when we have AI players if any(isinstance(player, AIPlayer) for player in self.players): AIPlayer.load_abstract_buildings( self.session.db) # TODO: find a better place for this # add a pirate ship if pirate_enabled: self.pirate = Pirate(self.session, 99998, "Captain Blackbeard", Color()) assert ret_coords is not None, "Return coords are None. No players loaded?" return ret_coords
def start(self): # Add the check_events method to the scheduler to be checked every few seconds self.check_events("game_started") Scheduler().add_new_object(self._scheduled_check, self, run_in=Scheduler().get_ticks(self.CHECK_CONDITIONS_INTERVAL), loops=-1)
def hide(self): super().hide() Scheduler().rem_all_classinst_calls(self)
def schedule_check(self, condition): """Let check_events run in one tick for condition. Useful for lag prevetion if time is a critical factor, e.g. when the user has to wait for a function to return..""" if self.session.world.inited: # don't check while loading Scheduler().add_new_object(Callback(self.check_events, condition), self, run_in=self.sleep_ticks_remaining)
def on_queue_element_finished(self, production): """Callback used for the SingleUseProduction""" self.remove_production(production) Scheduler().add_new_object(self.start_next_production, self)
def __init__(self, player): super(PlayerStats, self).__init__() self.player = player self.db = player.session.db self._collect_info() self.collection_tick = Scheduler().cur_tick
def show(self): super(ProductionOverviewTab, self).show() Scheduler().add_new_object(Callback(self._refresh_utilization), self, run_in=GAME_SPEED.TICKS_PER_SECOND, loops=-1)
def end(self): Scheduler().rem_all_classinst_calls(self)
def get_latest_stats(self): if self._stats is None or self._stats.collection_tick + PLAYER.STATS_UPDATE_FREQUENCY < Scheduler( ).cur_tick: self._stats = PlayerStats(self) return self._stats
def notify_unit_path_blocked(self, unit): self.log.warning("%s %s: ship blocked", self.__class__.__name__, self.worldid) # retry moving ship in 2 secs Scheduler().add_new_object(Callback(self.ship_idle, unit), self, \ GAME_SPEED.TICKS_PER_SECOND * 2)
class TestScheduler(TestCase): def setUp(self): self.callback = Mock() self.timer = Mock() Scheduler.create_instance(self.timer) self.scheduler = Scheduler() self.timer.reset_mock() def tearDown(self): Scheduler.destroy_instance() def test_create_then_register_with_timer(self): # create a new scheduler but do not reset timer mock Scheduler.destroy_instance() Scheduler.create_instance(self.timer) self.scheduler = Scheduler() self.timer.add_call.assert_called_once_with(self.scheduler.tick) def test_end_then_unregister_from_timer(self): self.scheduler.end() self.timer.remove_call.assert_called_once_with(self.scheduler.tick) def test_multiple_sequential_ticks(self): self.scheduler.before_ticking() self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.assertEqual(Scheduler.FIRST_TICK_ID, self.scheduler.cur_tick) self.scheduler.tick(Scheduler.FIRST_TICK_ID+1) self.assertEqual(Scheduler.FIRST_TICK_ID+1, self.scheduler.cur_tick) self.scheduler.tick(Scheduler.FIRST_TICK_ID+2) self.assertEqual(Scheduler.FIRST_TICK_ID+2, self.scheduler.cur_tick) def test_fail_when_missing_start_tick(self): def tick(): self.scheduler.tick(Scheduler.FIRST_TICK_ID+1) self.scheduler.before_ticking() self.assertRaises(Exception, tick) def test_fail_when_same_tick_twice(self): def tick(): self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.scheduler.before_ticking() self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.assertRaises(Exception, tick) def test_add_callback_before_first_tick(self): self.scheduler.add_new_object(self.callback, None, run_in=0) self.scheduler.before_ticking() self.callback.assert_called_once_with() def test_add_callback_run_in_1_on_first_tick(self): self.scheduler.add_new_object(self.callback, None, run_in=1) self.scheduler.before_ticking() self.assertFalse(self.callback.called) self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.callback.assert_called_once_with() def test_add_callback_only_triggered_once(self): self.scheduler.before_ticking() self.scheduler.add_new_object(self.callback, None, run_in=2) self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.assertFalse(self.callback.called) self.scheduler.tick(Scheduler.FIRST_TICK_ID+1) # callback called here self.callback.reset_mock() self.scheduler.tick(Scheduler.FIRST_TICK_ID+2) self.assertFalse(self.callback.called) def test_started_ticking_then_add_callback_for_next_tick(self): self.scheduler.before_ticking() self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.scheduler.add_new_object(self.callback, None, run_in=0) self.assertFalse(self.callback.called) self.scheduler.tick(Scheduler.FIRST_TICK_ID+1) self.callback.assert_called_once_with() def test_started_ticking_then_add_callback_for_future(self): self.scheduler.before_ticking() self.scheduler.add_new_object(self.callback, None, run_in=2) self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.assertFalse(self.callback.called) self.scheduler.tick(Scheduler.FIRST_TICK_ID+1) self.callback.assert_called_once_with() def test_within_callback_add_new_callback_for_same_tick(self): self.scheduler.before_ticking() callback2 = Mock() def add_callback(): self.scheduler.add_new_object(callback2, None, run_in=0) self.callback.side_effect = add_callback self.scheduler.add_new_object(self.callback, None, run_in=1) self.scheduler.tick(Scheduler.FIRST_TICK_ID) callback2.assert_called_once_with() def test_within_callback_add_new_callback_for_future_tick(self): self.scheduler.before_ticking() callback2 = Mock() def add_callback(): self.scheduler.add_new_object(callback2, None, run_in=1) self.callback.side_effect = add_callback self.scheduler.add_new_object(self.callback, None, run_in=1) self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.assertFalse(callback2.called) self.scheduler.tick(Scheduler.FIRST_TICK_ID+1) callback2.assert_called_once_with() def test_add_periodic_callback_called_every_tick_3_times(self): self.scheduler.before_ticking() self.scheduler.add_new_object(self.callback, None, run_in=1, loops=4) for i in xrange(Scheduler.FIRST_TICK_ID, 4): self.scheduler.tick(i) self.callback.assert_called_once_with() self.callback.reset_mock() self.scheduler.tick(4) self.assertFalse(self.callback.called) def test_add_periodic_callback_run_every_other_tick_3_times(self): self.scheduler.before_ticking() self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.scheduler.add_new_object(self.callback, None, run_in=1, loops=3, loop_interval=2) for i in xrange(Scheduler.FIRST_TICK_ID+1, 7): self.scheduler.tick(i) if (i % 2 - 1 == 0): self.callback.assert_called_once_with() self.callback.reset_mock() else: self.assertFalse(self.callback.called) self.scheduler.tick(7) self.assertFalse(self.callback.called) def test_remove_call_from_instance(self): self.scheduler.before_ticking() instance1 = Mock() instance2 = Mock() self.scheduler.add_new_object(self.callback, instance1, run_in=1) self.scheduler.add_new_object(self.callback, instance2, run_in=1) self.scheduler.rem_call(instance1, self.callback) self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.callback.assert_called_once_with() # instance2 callback kept def test_list_and_manually_remove_all_classinstance_callbacks(self): self.scheduler.before_ticking() instance1 = Mock() self.scheduler.add_new_object(self.callback, instance1, run_in=1) self.scheduler.add_new_object(self.callback, instance1, run_in=1) callbacks = self.scheduler.get_classinst_calls(instance1) for callback in callbacks: self.scheduler.rem_object(callback) self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.assertFalse(self.callback.called) def test_remove_all_classinstance_callbacks(self): self.scheduler.before_ticking() instance1 = Mock() self.scheduler.add_new_object(self.callback, instance1, run_in=1) self.scheduler.add_new_object(self.callback, instance1, run_in=1) self.scheduler.rem_all_classinst_calls(instance1) self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.assertFalse(self.callback.called) def test_get_remaining_tick_until_callback(self): self.scheduler.before_ticking() instance = Mock() self.scheduler.add_new_object(self.callback, instance, run_in=2) self.assertEqual(2, self.scheduler.get_remaining_ticks(instance, self.callback)) self.scheduler.tick(Scheduler.FIRST_TICK_ID) self.assertEqual(1, self.scheduler.get_remaining_ticks(instance, self.callback)) def test_get_remaining_tick_periodic_callback(self): self.scheduler.before_ticking() instance = Mock() self.scheduler.add_new_object(self.callback, instance, run_in=1, loops=2, loop_interval=3) self.assertEqual(1, self.scheduler.get_remaining_ticks(instance, self.callback)) self.scheduler.tick(Scheduler.FIRST_TICK_ID) # first time fired self.assertEqual(3, self.scheduler.get_remaining_ticks(instance, self.callback)) self.scheduler.tick(Scheduler.FIRST_TICK_ID+1) self.assertEqual(2, self.scheduler.get_remaining_ticks(instance, self.callback)) self.scheduler.tick(Scheduler.FIRST_TICK_ID+2) self.assertEqual(1, self.scheduler.get_remaining_ticks(instance, self.callback))
def remove(self): self._remove_listeners() Scheduler().rem_all_classinst_calls(self) super(Production, self).remove()
def update(self): if self.production_builder.last_collector_improvement_road + self.personality.collector_improvement_road_expires > Scheduler( ).cur_tick: # skip this goal leave time for the collectors to do their work self._problematic_buildings = None self._is_active = False else: self._problematic_buildings = self._get_problematic_collector_coverage_buildings( ) self._is_active = bool(self._problematic_buildings)