class LifeSpan(object): ''' Used by anything which may end at some point (e.g., level, trigger, server). Allows registration of things which should also be torn down when this LifeSpan ends. ''' def __init__(self, parent=None, parents=None): self.ended = False self.onEnded = Event([]) if parent: parent.onEnded.addListener(self.stop) if parents: for p in parents: p.onEnded.addListener(self.stop) def stop(self): if self.ended: return self.ended = True self.onEnded() # Prevent this lifespan being used after it's ended self.onEnded.clear() self.onEnded = None
class AIAgent(ConcreteAgent): ''' Base class for an AI agent. ''' def __init__(self, game, aiClass, fromLevel, nick=None, *args, **kwargs): super(AIAgent, self).__init__(game=game, *args, **kwargs) self.aiClass = aiClass self.fromLevel = fromLevel self._initialisationNick = nick self.ai = None self.team = None self.requestedNick = None self._onBotSet = Event() self._loop = WeakLoopingCall(self, '_tick') def start(self, team=None): self.team = team self._loop.start(2) def stop(self): super(AIAgent, self).stop() self._loop.stop() if self.ai: self.ai.disable() self.ai = None def _tick(self): if self.ai is not None: return if self.fromLevel and self._initialisationNick: nick = self._initialisationNick else: nick = self.aiClass.nick if self.team is None: teamId = NEUTRAL_TEAM_ID else: teamId = self.team.id self._joinGame(nick, teamId) def _joinGame(self, nick, teamId): self.requestedNick = nick self.sendJoinRequest(teamId, nick, bot=True, fromLevel=self.fromLevel) @CannotJoinMsg.handler def _joinFailed(self, msg): r = msg.reasonId nick = self.requestedNick if r == GAME_FULL_REASON: message = 'full' elif r == UNAUTHORISED_REASON: message = 'not authenticated' elif r == NICK_USED_REASON: message = 'nick in use' elif r == USER_IN_GAME_REASON: message = 'user already in game' # Should never happen elif r == ALREADY_JOINED_REASON: message = 'tried to join twice' # Should never happen else: message = repr(r) log.error('Join failed for AI %r (%s)', nick, message) self.stop() def setPlayer(self, player): if player is None and self.ai: self.ai.disable() self.ai = None super(AIAgent, self).setPlayer(player) if player: self.requestedNick = None self.ai = self.aiClass(self.world, self.localState.player, self) self._onBotSet(self.ai) self._onBotSet.clear() def getBot(self): ''' @return: a Deferred which fires with this agent's Bot object, as soon as it has one. ''' d = defer.Deferred() if self.ai is not None: d.callback(self.ai) else: self._onBotSet.addListener(d.callback, weak=False) return d @TickMsg.handler def handle_TickMsg(self, msg): super(AIAgent, self).handle_TickMsg(msg) if self.ai: self.ai.consumeMsg(msg) @ResyncPlayerMsg.handler def handle_ResyncPlayerMsg(self, msg): super(AIAgent, self).handle_ResyncPlayerMsg(msg) if self.ai: self.ai.playerResynced() def defaultHandler(self, msg): super(AIAgent, self).defaultHandler(msg) if self.ai: self.ai.consumeMsg(msg)