from direct.distributed.ClockDelta import * from otp.level import DistributedEntityAI from direct.directnotify import DirectNotifyGlobal from direct.task import Task from direct.fsm import ClassicFSM, State from direct.fsm import State import LiftConstants class DistributedLiftAI(DistributedEntityAI.DistributedEntityAI): notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLiftAI') def __init__(self, level, entId, initialState = LiftConstants.Down): DistributedEntityAI.DistributedEntityAI.__init__(self, level, entId) self.name = 'Lift%s:%s' % (self.levelDoId, self.entId) self.startMoveTaskName = '%s-StartMove' % self.name self.moveDoneTaskName = '%s-MoveDone' % self.name self.state = initialState self.fromState = initialState self.stateTimestamp = globalClock.getFrameTime() self.boardedAvs = [] def generate(self): self.notify.debug('generate') DistributedEntityAI.DistributedEntityAI.generate(self) self.fsm = ClassicFSM.ClassicFSM('DistributedLiftAI', [State.State('off', self.enterOff, self.exitOff, ['waiting']), State.State('waiting', self.enterWaiting, self.exitWaiting, ['moving', 'waiting']), State.State('moving', self.enterMoving, self.exitMoving, ['waiting'])], 'off', 'off') self.fsm.enterInitialState() self.fsm.request('waiting') def delete(self): self.notify.debug('delete') DistributedEntityAI.DistributedEntityAI.delete(self) self.ignoreAll() taskMgr.remove(self.startMoveTaskName) taskMgr.remove(self.moveDoneTaskName) del self.fsm def b_setStateTransition(self, toState, fromState, arrivalTimestamp): self.d_setStateTransition(toState, fromState, arrivalTimestamp) self.setStateTransition(toState, fromState, arrivalTimestamp) def d_setStateTransition(self, toState, fromState, arrivalTimestamp): self.sendUpdate('setStateTransition', [toState, fromState, arrivalTimestamp]) def setStateTransition(self, toState, fromState, arrivalTimestamp): self.state = toState self.fromState = fromState self.stateTimestamp = arrivalTimestamp def getStateTransition(self): return (self.state, self.fromState, self.stateTimestamp) def setAvatarEnter(self): avId = self.air.getAvatarIdFromSender() avatar = self.air.doId2do.get(avId) if not avatar: self.air.writeServerEvent('suspicious', avId, 'LiftAI.setAvatarEnter avId not valid') return self.notify.debug('setAvatarEnter: %s' % avId) if avId in self.boardedAvs: self.notify.warning('avatar %s already in list' % avId) else: self.boardedAvs.append(avId) def handleExitedAvatar(self = self, avId = avId): self.notify.debug('avatar %s exited' % avId) self.avatarLeft(avId) self.acceptOnce(self.air.getAvatarExitEvent(avId), handleExitedAvatar) self.setMoveLater(self.moveDelay) def setAvatarLeave(self): avId = self.air.getAvatarIdFromSender() self.notify.debug('setAvatarLeave: %s' % avId) self.avatarLeft(avId) def avatarLeft(self, avId): if avId in self.boardedAvs: self.boardedAvs.remove(avId) self.ignore(self.air.getAvatarExitEvent(avId)) if len(self.boardedAvs) == 0: if self.fsm.getCurrentState().getName() == 'waiting': self.fsm.request('waiting') else: self.notify.warning('avatar %s tried to leave, but is not in list' % avId) def setMoveLater(self, delay): def startMoving(task, self = self): targetState = LiftConstants.oppositeState(self.state) self.fsm.request('moving', [targetState]) return Task.done self.cancelMoveLater() taskMgr.doMethodLater(delay, startMoving, self.startMoveTaskName) def cancelMoveLater(self): taskMgr.remove(self.startMoveTaskName) def enterOff(self): self.notify.debug('enterOff') def exitOff(self): pass def enterWaiting(self): self.notify.debug('enterWaiting') self.setMoveLater(self.autoMoveDelay) def exitWaiting(self): self.cancelMoveLater() def enterMoving(self, targetState): self.notify.debug('enterMoving, target=%s' % targetState) if self.state == targetState: self.notify.warning('already in state %s' % targetState) return arriveDelay = 1.0 + self.duration self.b_setStateTransition(targetState, self.state, globalClockDelta.localToNetworkTime(globalClock.getFrameTime() + arriveDelay, bits=32)) def doneMoving(task, self = self): self.fsm.request('waiting') return Task.done taskMgr.doMethodLater(arriveDelay, doneMoving, self.moveDoneTaskName) def exitMoving(self): pass