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
示例#2
0
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)