class DistributedCogdoInterior(DistributedObject.DistributedObject): id = 0 cageHeights = [11.36, 0.01] def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.toons = [] self.activeIntervals = {} self.openSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_open.ogg') self.closeSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_close.ogg') self.suits = [] self.reserveSuits = [] self.joiningReserves = [] self.distBldgDoId = None self._CogdoGameRepeat = config.GetBool('cogdo-game-repeat', 0) self.currentFloor = -1 self.elevatorName = self.__uniqueName('elevator') self.floorModel = None self.elevatorOutOpen = 0 self.BottomFloor_SuitPositions = [Point3(0, 15, 0), Point3(10, 20, 0), Point3(-7, 24, 0), Point3(-10, 0, 0)] self.BottomFloor_SuitHs = [75, 170, -91, -44] self.Cubicle_SuitPositions = [Point3(0, 18, 0), Point3(10, 12, 0), Point3(-9, 11, 0), Point3(-3, 13, 0)] self.Cubicle_SuitHs = [170, 56, -52, 10] self.BossOffice_SuitPositions = [Point3(0, 15, 0), Point3(10, 20, 0), Point3(-10, 6, 0), Point3(-17, 30, 0)] self.BossOffice_SuitHs = [170, 120, 12, 38] self._wantBarrelRoom = config.GetBool('cogdo-want-barrel-room', 1) self.barrelRoom = CogdoBarrelRoom.CogdoBarrelRoom() self.brResults = [[], []] self.barrelRoomIntroTrack = None self.penthouseOutroTrack = None self.penthouseOutroChatDoneTrack = None self.penthouseIntroTrack = None self.waitMusic = base.loadMusic('phase_7/audio/bgm/encntr_toon_winning_indoor.ogg') self.elevatorMusic = base.loadMusic('phase_7/audio/bgm/tt_elevator.ogg') self.fsm = ClassicFSM.ClassicFSM('DistributedCogdoInterior', [State.State('WaitForAllToonsInside', self.enterWaitForAllToonsInside, self.exitWaitForAllToonsInside, ['Elevator']), State.State('Elevator', self.enterElevator, self.exitElevator, ['Game', 'BattleIntro', 'BarrelRoomIntro']), State.State('Game', self.enterGame, self.exitGame, ['Resting', 'Failed', 'BattleIntro', 'BarrelRoomIntro', 'Elevator']), State.State('BarrelRoomIntro', self.enterBarrelRoomIntro, self.exitBarrelRoomIntro, ['CollectBarrels', 'Off']), State.State('CollectBarrels', self.enterCollectBarrels, self.exitCollectBarrels, ['BarrelRoomReward', 'Off']), State.State('BarrelRoomReward', self.enterBarrelRoomReward, self.exitBarrelRoomReward, ['Battle', 'ReservesJoining', 'BattleIntro', 'Off']), State.State('BattleIntro', self.enterBattleIntro, self.exitBattleIntro, ['Battle', 'ReservesJoining', 'Off']), State.State('Battle', self.enterBattle, self.exitBattle, ['Resting', 'Reward', 'ReservesJoining']), State.State('ReservesJoining', self.enterReservesJoining, self.exitReservesJoining, ['Battle']), State.State('Resting', self.enterResting, self.exitResting, ['Elevator']), State.State('Reward', self.enterReward, self.exitReward, ['Off']), State.State('Failed', self.enterFailed, self.exitFailed, ['Off']), State.State('Off', self.enterOff, self.exitOff, ['Elevator', 'WaitForAllToonsInside', 'Battle'])], 'Off', 'Off') self.fsm.enterInitialState() self._haveEntranceElevator = StateVar(False) self._stashEntranceElevator = StateVar(False) self._stashEntranceElevatorFC = FunctionCall(self._doStashEntranceElevator, self._haveEntranceElevator, self._stashEntranceElevator) self._entranceElevCallbacks = [] self._doEntranceElevCallbacksFC = FunctionCall(self._doEntranceElevCallbacks, self._haveEntranceElevator) self.cage = None self.shopOwnerNpcId = None self.shopOwnerNpc = None self._movie = None self.SOSToonName = None self.FOType = None def setShopOwnerNpcId(self, npcId): self.shopOwnerNpcId = npcId def setSOSNpcId(self, npcId): self.SOSToonName = NPCToons.getNPCName(npcId) def setFOType(self, typeId): self.FOType = chr(typeId) def getFOType(self): return self.FOType def __uniqueName(self, name): DistributedCogdoInterior.id += 1 return name + '%d' % DistributedCogdoInterior.id def generate(self): DistributedObject.DistributedObject.generate(self) self.announceGenerateName = self.uniqueName('generate') self.accept(self.announceGenerateName, self.handleAnnounceGenerate) self.elevatorModelIn = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_csa_elevatorB') self.leftDoorIn = self.elevatorModelIn.find('**/left_door') self.rightDoorIn = self.elevatorModelIn.find('**/right_door') self.elevatorModelOut = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_csa_elevator') self.leftDoorOut = self.elevatorModelOut.find('**/left_door') self.rightDoorOut = self.elevatorModelOut.find('**/right_door') def __makeShopOwnerNpc(self): if self.shopOwnerNpc: return self.shopOwnerNpc = NPCToons.createLocalNPC(self.shopOwnerNpcId) if not self.shopOwnerNpc: self.notify.warning('No shopkeeper in this cogdominium, using FunnyFarm Sellbot FO NPCToons') random.seed(self.doId) shopkeeper = random.randint(7001, 7009) self.shopOwnerNpc = NPCToons.createLocalNPC(shopkeeper) self.shopOwnerNpc.addActive() self.shopOwnerNpc.reparentTo(self.cage) self.shopOwnerNpc.setPosHpr(0, -2, 0, 180, 0, 0) self.shopOwnerNpc.loop('neutral') def setElevatorLights(self, elevatorModel): npc = elevatorModel.findAllMatches('**/floor_light_?;+s') for i in xrange(npc.getNumPaths()): np = npc.getPath(i) np.setDepthOffset(120) floor = int(np.getName()[-1:]) - 1 if floor == self.currentFloor: np.setColor(LIGHT_ON_COLOR) elif floor < self.layout.getNumGameFloors() + (1 if self.FOType != "s" else 0): if self.isBossFloor(self.currentFloor): np.setColor(LIGHT_ON_COLOR) else: np.setColor(LIGHT_OFF_COLOR) else: np.hide() def startAlertElevatorLightIval(self, elevatorModel): light = elevatorModel.find('**/floor_light_%s' % (self.currentFloor + 1)) track = Sequence(Func(light.setColor, Vec4(1.0, 0.6, 0.6, 1.0)), Wait(0.9), Func(light.setColor, LIGHT_ON_COLOR), Wait(0.9)) self.activeIntervals['alertElevatorLight'] = track track.loop() def stopAlertElevatorLightIval(self, elevatorModel): self.__finishInterval('alertElevatorLight') self.setElevatorLights(elevatorModel) def handleAnnounceGenerate(self, obj): self.ignore(self.announceGenerateName) self.cageDoorSfx = loader.loadSfx('phase_5/audio/sfx/CHQ_SOS_cage_door.ogg') self.cageLowerSfx = loader.loadSfx('phase_5/audio/sfx/CHQ_SOS_cage_lower.ogg') self.sendUpdate('setAvatarJoined', []) def disable(self): self.fsm.requestFinalState() self.__cleanupIntervals() self.ignoreAll() self.__cleanup() self.__cleanupShopOwnerNpc() self.__cleanupPenthouseIntro() DistributedObject.DistributedObject.disable(self) def __cleanupShopOwnerNpc(self): if self.shopOwnerNpc: self.shopOwnerNpc.removeActive() self.shopOwnerNpc.delete() self.shopOwnerNpc = None def __cleanupPenthouseIntro(self): if hasattr(self, '_movie') and self._movie: self._movie.unload() self._movie = None def delete(self): self._stashEntranceElevatorFC.destroy() self._doEntranceElevCallbacksFC.destroy() self._haveEntranceElevator.destroy() self._stashEntranceElevator.destroy() self._entranceElevCallbacks = None del self.waitMusic del self.elevatorMusic del self.openSfx del self.closeSfx del self.fsm base.localAvatar.inventory.setBattleCreditMultiplier(1) DistributedObject.DistributedObject.delete(self) def isBossFloor(self, floorNum): return self.layout.hasBossBattle() and (self.layout.getBossBattleFloor() + 0) == floorNum def __cleanup(self): self.toons = [] self.suits = [] self.reserveSuits = [] self.joiningReserves = [] if self.elevatorModelIn != None: self.elevatorModelIn.removeNode() if self.elevatorModelOut != None: self.elevatorModelOut.removeNode() if self.floorModel != None: self.floorModel.removeNode() if self.cage != None: self.cage = None if self.barrelRoom != None: self.barrelRoom.destroy() self.barrelRoom = None self.leftDoorIn = None self.rightDoorIn = None self.leftDoorOut = None self.rightDoorOut = None def __addToon(self, toon): self.accept(toon.uniqueName('disable'), self.__handleUnexpectedExit, extraArgs=[toon]) def __handleUnexpectedExit(self, toon): self.notify.warning('handleUnexpectedExit() - toon: %d' % toon.doId) self.__removeToon(toon, unexpected=1) def __removeToon(self, toon, unexpected = 0): if self.toons.count(toon) == 1: self.toons.remove(toon) self.ignore(toon.uniqueName('disable')) def __finishInterval(self, name): if name in self.activeIntervals: interval = self.activeIntervals[name] if interval.isPlaying(): interval.finish() def __cleanupIntervals(self): for interval in self.activeIntervals.values(): interval.finish() self.activeIntervals = {} def __closeInElevator(self): self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) def getZoneId(self): return self.zoneId def setZoneId(self, zoneId): self.zoneId = zoneId def getExtZoneId(self): return self.extZoneId def setExtZoneId(self, extZoneId): self.extZoneId = extZoneId def getDistBldgDoId(self): return self.distBldgDoId def setDistBldgDoId(self, distBldgDoId): self.distBldgDoId = distBldgDoId def setNumFloors(self, numFloors): self.layout = CogdoLayout(numFloors) def getToonIds(self): toonIds = [] for toon in self.toons: toonIds.append(toon.doId) return toonIds def setToons(self, toonIds, hack): self.toonIds = toonIds oldtoons = self.toons self.toons = [] for toonId in toonIds: if toonId != 0: if toonId in self.cr.doId2do: toon = self.cr.doId2do[toonId] toon.stopSmooth() self.toons.append(toon) if oldtoons.count(toon) == 0: self.__addToon(toon) else: self.notify.warning('setToons() - no toon: %d' % toonId) for toon in oldtoons: if self.toons.count(toon) == 0: self.__removeToon(toon) def setSuits(self, suitIds, reserveIds, values): oldsuits = self.suits self.suits = [] self.joiningReserves = [] for suitId in suitIds: if suitId in self.cr.doId2do: suit = self.cr.doId2do[suitId] self.suits.append(suit) suit.fsm.request('Battle') suit.buildingSuit = 1 suit.reparentTo(render) if oldsuits.count(suit) == 0: self.joiningReserves.append(suit) if 'Elevator' in repr(self.fsm): # Fix the position. pos, h = BattleBase.BattleBase.suitPoints[len(suitIds) - 1][suitIds.index(suitId)] suit.setPos(pos) suit.setH(h) else: self.notify.warning('setSuits() - no suit: %d' % suitId) self.reserveSuits = [] for index in xrange(len(reserveIds)): suitId = reserveIds[index] if suitId in self.cr.doId2do: suit = self.cr.doId2do[suitId] self.reserveSuits.append((suit, values[index])) else: self.notify.warning('setSuits() - no suit: %d' % suitId) if len(self.joiningReserves) > 0: self.fsm.request('ReservesJoining') def setState(self, state, timestamp): self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def stashElevatorIn(self, stash = True): self._stashEntranceElevator.set(stash) def getEntranceElevator(self, callback): if self._haveEntranceElevator.get(): callback(self.elevIn) else: self._entranceElevCallbacks.append(callback) def _doEntranceElevCallbacks(self, haveElev): if haveElev: while len(self._entranceElevCallbacks): cbs = self._entranceElevCallbacks[:] self._entranceElevCallbacks = [] for callback in cbs: callback(self.elevIn) def _doStashEntranceElevator(self, haveElev, doStash): if haveElev: if doStash: self.elevIn.stash() else: self.elevIn.unstash() def d_elevatorDone(self): self.sendUpdate('elevatorDone', []) def d_reserveJoinDone(self): self.sendUpdate('reserveJoinDone', []) def enterOff(self, ts = 0): messenger.send('sellbotFieldOfficeChanged', [False]) return None def exitOff(self): return None def enterWaitForAllToonsInside(self, ts = 0): base.transitions.fadeOut(0) def exitWaitForAllToonsInside(self): return None def enterGame(self, ts = 0): base.cr.forbidCheesyEffects(1) def exitGame(self): base.cr.forbidCheesyEffects(0) def __playElevator(self, ts, name, callback): SuitHs = [] SuitPositions = [] if self.floorModel: self.floorModel.removeNode() self.floorModel = None if self.cage: self.cage = None if self.currentFloor == 0: SuitHs = self.BottomFloor_SuitHs SuitPositions = self.BottomFloor_SuitPositions if self.isBossFloor(self.currentFloor): self.notify.info('__playElevator: currentFloor %s is boss' % self.currentFloor) self.barrelRoom.unload() if self.FOType: penthouseName = SUITE_DICT.get(self.FOType) for i in xrange(4): self.floorModel = loader.loadModel('phase_5/models/cogdominium/%s' % penthouseName) self.cage = self.floorModel.find('**/cage') pos = self.cage.getPos() self.cagePos = [] for height in self.cageHeights: self.cagePos.append(Point3(pos[0], pos[1], height)) self.cageDoor = self.floorModel.find('**/cage_door') self.cageDoor.wrtReparentTo(self.cage) if self.FOType: paintingModelName = PAINTING_DICT.get(self.FOType) for i in xrange(4): paintingModel = loader.loadModel('phase_5/models/cogdominium/%s' % paintingModelName) loc = self.floorModel.find('**/loc_painting%d' % (i + 1)) paintingModel.reparentTo(loc) if not self.floorModel.find('**/trophyCase').isEmpty(): for i in xrange(4): goldEmblem = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy.bam') loc = self.floorModel.find('**/gold_0%d' % (i + 1)) goldEmblem.reparentTo(loc) for i in xrange(20): silverEmblem = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam') loc = self.floorModel.find('**/silver_0%d' % (i + 1)) silverEmblem.reparentTo(loc) SuitHs = self.BossOffice_SuitHs SuitPositions = self.BossOffice_SuitPositions self.__makeShopOwnerNpc() else: if self._wantBarrelRoom: self.barrelRoom.load() self.barrelRoom.hide() SuitHs = self.Cubicle_SuitHs SuitPositions = self.Cubicle_SuitPositions if self.floorModel: self.floorModel.reparentTo(render) if self.isBossFloor(self.currentFloor): self.notify.info('Load boss_suit_office') elevIn = self.floorModel.find(CogdoGameConsts.PenthouseElevatorInPath).copyTo(render) elevOut = self.floorModel.find(CogdoGameConsts.PenthouseElevatorOutPath) frame = self.elevatorModelOut.find('**/frame') if not frame.isEmpty(): frame.hide() frame = self.elevatorModelIn.find('**/frame') if not frame.isEmpty(): frame.hide() self.elevatorModelOut.reparentTo(elevOut) self.elevatorModelOut.setY(0) else: elevIn = self.floorModel.find('**/elevator-in') elevOut = self.floorModel.find('**/elevator-out') elif self._wantBarrelRoom and self.barrelRoom.isLoaded() and self.currentFloor == 2 and self.FOType == 'l': #i know this is really ugly elevIn = self.barrelRoom.model.find(CogdoBarrelRoomConsts.BarrelRoomElevatorInPath) elevOut = self.barrelRoom.model.find(CogdoBarrelRoomConsts.BarrelRoomElevatorOutPath) y = elevOut.getY(render) elevOut = elevOut.copyTo(render) elevOut.setY(render, y - 0.75) else: floorModel = loader.loadModel('phase_7/models/modules/boss_suit_office') elevIn = floorModel.find('**/elevator-in').copyTo(render) elevOut = floorModel.find('**/elevator-out').copyTo(render) floorModel.removeNode() self.elevIn = elevIn self.elevOut = elevOut self._haveEntranceElevator.set(True) for index in xrange(len(self.suits)): if not self.suits[index].isEmpty(): self.suits[index].setPos(SuitPositions[index]) if len(self.suits) > 2: self.suits[index].setH(SuitHs[index]) else: self.suits[index].setH(170) self.suits[index].loop('neutral') for toon in self.toons: toon.reparentTo(self.elevatorModelIn) index = self.toonIds.index(toon.doId) toon.setPos(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2]) toon.setHpr(180, 0, 0) toon.loop('neutral') self.elevatorModelIn.reparentTo(elevIn) self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) camera.reparentTo(self.elevatorModelIn) camera.setH(180) camera.setP(0) camera.setPos(0, 14, 4) base.playMusic(self.elevatorMusic, looping=1, volume=0.8) track = Sequence(Func(base.transitions.noTransitions), ElevatorUtils.getRideElevatorInterval(ELEVATOR_NORMAL), ElevatorUtils.getOpenInterval(self, self.leftDoorIn, self.rightDoorIn, self.openSfx, None, type=ELEVATOR_NORMAL), Func(camera.wrtReparentTo, render)) for toon in self.toons: track.append(Func(toon.wrtReparentTo, render)) track.append(Func(callback)) track.start(ts) self.activeIntervals[name] = track def enterElevator(self, ts = 0): if not self._CogdoGameRepeat: self.currentFloor += 1 self.cr.playGame.getPlace().currentFloor = self.currentFloor self.setElevatorLights(self.elevatorModelIn) self.setElevatorLights(self.elevatorModelOut) if not self.isBossFloor(self.currentFloor): self.elevatorModelOut.detachNode() messenger.send('sellbotFieldOfficeChanged', [True]) else: if self.FOType == 's': self._movie = CogdoElevatorMovie() self._movie.load() self._movie.play() self.__playElevator(ts, self.elevatorName, self.__handleElevatorDone) mult = ToontownBattleGlobals.getCreditMultiplier(self.currentFloor) base.localAvatar.inventory.setBattleCreditMultiplier(mult) def __handleElevatorDone(self): self.d_elevatorDone() def exitElevator(self): self.elevatorMusic.stop() if self._movie: self._movie.end() self.__cleanupPenthouseIntro() self.__finishInterval(self.elevatorName) def __setupBarrelRoom(self): self.currentFloor += 1 base.transitions.irisOut(0.0) self.elevatorModelOut.setY(-12) self.elevatorModelIn.reparentTo(self.barrelRoom.model.find(CogdoBarrelRoomConsts.BarrelRoomElevatorInPath)) self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) self._showExitElevator() self.barrelRoom.show() self.barrelRoom.placeToonsAtEntrance(self.toons) self.setElevatorLights(self.elevatorModelOut) def barrelRoomIntroDone(self): self.sendUpdate('toonBarrelRoomIntroDone', []) def enterBarrelRoomIntro(self, ts = 0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.__setupBarrelRoom() self.barrelRoomIntroTrack, trackName = self.barrelRoom.getIntroInterval() self.barrelRoomIntroDoneEvent = trackName self.accept(self.barrelRoomIntroDoneEvent, self.barrelRoomIntroDone) self.activeIntervals[trackName] = self.barrelRoomIntroTrack self.barrelRoomIntroTrack.start(ts) self._movie = CogdoBarrelRoomIntro() self._movie.load() self._movie.play() else: self._showExitElevator() def exitBarrelRoomIntro(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore(self.barrelRoomIntroDoneEvent) if self.barrelRoomIntroTrack: self.barrelRoomIntroTrack.finish() DelayDelete.cleanupDelayDeletes(self.barrelRoomIntroTrack) self.barrelRoomIntroTrack = None def __handleLocalToonLeftBarrelRoom(self): self.notify.info('Local toon teleported out of barrel room.') self.sendUpdate('toonLeftBarrelRoom', []) self.barrelRoom.deactivate() def enterCollectBarrels(self, ts = 0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.acceptOnce('localToonLeft', self.__handleLocalToonLeftBarrelRoom) self.barrelRoom.activate() base.playMusic(self.waitMusic, looping=1, volume=0.7) base.localAvatar.questMap.stop() def exitCollectBarrels(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore('localToonLeft') self.barrelRoom.deactivate() self.waitMusic.stop() def __brRewardDone(self, task = None): self.notify.info('Toon finished watching the barrel room reward.') self.sendUpdate('toonBarrelRoomRewardDone', []) self.fsm.request('Battle') def enterBarrelRoomReward(self, ts = 0): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('stopped') self.startAlertElevatorLightIval(self.elevatorModelOut) track, trackName = self.barrelRoom.showRewardUi(callback=self.__brRewardDone) self.activeIntervals[trackName] = track track.start() self.barrelRoom.placeToonsNearBattle(self.toons) def exitBarrelRoomReward(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('walk') self.stopAlertElevatorLightIval(self.elevatorModelOut) self.barrelRoom.hideRewardUi() def enterBattleIntro(self, ts = 0): self._movie = CogdoExecutiveSuiteIntro(self.shopOwnerNpc) self._movie.load() self._movie.play() def exitBattleIntro(self): self._movie.end() self.__cleanupPenthouseIntro() def __playCloseElevatorOut(self, name, delay = 0): track = Sequence(Wait(delay + SUIT_LEAVE_ELEVATOR_TIME), Parallel(SoundInterval(self.closeSfx), LerpPosInterval(self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut'), LerpPosInterval(self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut'))) track.start() self.activeIntervals[name] = track def enterBattle(self, ts = 0): if self._wantBarrelRoom and self.elevatorOutOpen == 1: self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'), delay=2) camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) def _showExitElevator(self): self.elevatorModelOut.reparentTo(self.elevOut) self.leftDoorOut.setPos(3.5, 0, 0) self.rightDoorOut.setPos(-3.5, 0, 0) if not self._wantBarrelRoom and self.elevatorOutOpen == 1: self.__playCloseElevatorOut(self.uniqueName('close-out-elevator')) camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) def exitBattle(self): if self.elevatorOutOpen == 1: self.__finishInterval(self.uniqueName('close-out-elevator')) self.elevatorOutOpen = 0 def __playReservesJoining(self, ts, name, callback): index = 0 for suit in self.joiningReserves: suit.reparentTo(render) suit.setPos(self.elevatorModelOut, Point3(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2])) index += 1 suit.setH(180) suit.loop('neutral') track = Sequence(Func(camera.wrtReparentTo, self.elevatorModelOut), Func(camera.setPos, Point3(0, -8, 2)), Func(camera.setHpr, Vec3(0, 10, 0)), Parallel(SoundInterval(self.openSfx), LerpPosInterval(self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), blendType='easeOut'), LerpPosInterval(self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), blendType='easeOut')), Wait(SUIT_HOLD_ELEVATOR_TIME), Func(camera.wrtReparentTo, render), Func(callback)) track.start(ts) self.activeIntervals[name] = track def enterReservesJoining(self, ts = 0): self.__playReservesJoining(ts, self.uniqueName('reserves-joining'), self.__handleReserveJoinDone) def __handleReserveJoinDone(self): self.joiningReserves = [] self.elevatorOutOpen = 1 self.d_reserveJoinDone() def exitReservesJoining(self): self.__finishInterval(self.uniqueName('reserves-joining')) def enterResting(self, ts = 0): self._showExitElevator() self._setAvPosFDC = FrameDelayedCall('setAvPos', self._setAvPosToExit) if self._wantBarrelRoom: self.barrelRoom.showBattleAreaLight(True) base.playMusic(self.waitMusic, looping=1, volume=0.7) self.__closeInElevator() self._haveEntranceElevator.set(False) self._stashEntranceElevator.set(False) def _setAvPosToExit(self): base.localAvatar.setPos(self.elevOut, 0, -22, 0) base.localAvatar.setHpr(self.elevOut, 0, 0, 0) base.cr.playGame.getPlace().fsm.request('walk') def exitResting(self): self._setAvPosFDC.destroy() self.waitMusic.stop() def enterReward(self, ts = 0): if self.isBossFloor(self.currentFloor): self.penthouseOutroTrack = self.__outroPenthouse() self.penthouseOutroTrack.start(ts) else: self.exitCogdoBuilding() def exitReward(self): self.notify.debug('exitReward') if self.penthouseOutroTrack: self.penthouseOutroTrack.finish() DelayDelete.cleanupDelayDeletes(self.penthouseOutroTrack) self.penthouseOutroTrack = None if not self.penthouseOutroChatDoneTrack: self.notify.debug('exitReward: instanting outroPenthouseChatDone track') self.__outroPenthouseChatDone() self.penthouseOutroChatDoneTrack.finish() self.penthouseOutroChatDoneTrack = None def enterFailed(self, ts = 0): self.exitCogdoBuilding() def exitFailed(self): self.notify.debug('exitFailed()') self.exitCogdoBuilding() def exitCogdoBuilding(self): if base.localAvatar.hp < 0: return base.localAvatar.b_setParent(ToontownGlobals.SPHidden) request = {'loader': ZoneUtil.getBranchLoaderName(self.extZoneId), 'where': ZoneUtil.getToonWhereName(self.extZoneId), 'how': 'elevatorIn', 'hoodId': ZoneUtil.getHoodId(self.extZoneId), 'zoneId': self.extZoneId, 'shardId': None, 'avId': -1, 'bldgDoId': self.distBldgDoId} messenger.send('DSIDoneEvent', [request]) def displayBadges(self): numFloors = self.layout.getNumGameFloors() if numFloors > 5 or numFloors < 3: pass else: self.notify.warning('Invalid floor number for display badges.') for player in xrange(len(self.toons)): goldBadge = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy') goldBadge.setScale(1.2) goldNode = render.find('**/gold_0' + str(player + 1)) goldBadge.reparentTo(goldNode) for floor in xrange(numFloors): silverBadge = loader.loadModel('phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam') silverBadge.setScale(1.2) silverNode = render.find('**/silver_0' + str(floor * 4 + (player + 1))) silverBadge.reparentTo(silverNode) def __outroPenthouse(self): avatar = base.localAvatar trackName = '__outroPenthouse-%d' % avatar.doId track = Parallel(name=trackName) base.cr.playGame.getPlace().fsm.request('stopped') if self.FOType == 'l': speech = TTLocalizer.CogdoExecutiveSuiteToonThankYouLawbot else: speech = TTLocalizer.CogdoExecutiveSuiteToonThankYou % self.SOSToonName track.append(Sequence(Func(camera.wrtReparentTo, localAvatar), Func(camera.setPos, 0, -9, 9), Func(camera.lookAt, Point3(5, 15, 0)), Parallel(self.cage.posInterval(0.75, self.cagePos[1], blendType='easeOut'), SoundInterval(self.cageLowerSfx, duration=0.5)), Parallel(self.cageDoor.hprInterval(0.5, VBase3(0, 90, 0), blendType='easeOut'), Sequence(SoundInterval(self.cageDoorSfx), duration=0)), Wait(0.25), Func(self.shopOwnerNpc.wrtReparentTo, render), Func(self.shopOwnerNpc.setScale, 1), Func(self.shopOwnerNpc.loop, 'walk'), Func(self.shopOwnerNpc.headsUp, Point3(0, 10, 0)), ParallelEndTogether(self.shopOwnerNpc.posInterval(1.5, Point3(0, 10, 0)), self.shopOwnerNpc.hprInterval(0.5, VBase3(180, 0, 0), blendType='easeInOut')), Func(self.shopOwnerNpc.setChatAbsolute, TTLocalizer.CagedToonYippee, CFSpeech), ActorInterval(self.shopOwnerNpc, 'jump'), Func(self.shopOwnerNpc.loop, 'neutral'), Func(self.shopOwnerNpc.headsUp, localAvatar), Func(self.shopOwnerNpc.setLocalPageChat, speech, 0), Func(camera.lookAt, self.shopOwnerNpc, Point3(0, 0, 2)))) self.activeIntervals[trackName] = track self.accept('doneChatPage', self.__outroPenthouseChatDone) return track def __outroPenthouseChatDone(self, elapsed = None): self.shopOwnerNpc.setChatAbsolute(TTLocalizer.CogdoExecutiveSuiteToonBye, CFSpeech) self.ignore('doneChatPage') track = Parallel(Sequence(ActorInterval(self.shopOwnerNpc, 'wave'), Func(self.shopOwnerNpc.loop, 'neutral')), Sequence(Wait(2.0), Func(self.exitCogdoBuilding), Func(base.camLens.setFov, settings['fov']))) track.start() self.penthouseOutroChatDoneTrack = track
class DistributedCogdoInterior(DistributedObject.DistributedObject): id = 0 cageHeights = [11.36, 0.01] def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.toons = [] self.activeIntervals = {} self.openSfx = base.loadSfx('phase_5/audio/sfx/elevator_door_open.ogg') self.closeSfx = base.loadSfx( 'phase_5/audio/sfx/elevator_door_close.ogg') self.suits = [] self.reserveSuits = [] self.joiningReserves = [] self.distBldgDoId = None self._CogdoGameRepeat = config.GetBool('cogdo-game-repeat', 0) self.currentFloor = -1 self.elevatorName = self.__uniqueName('elevator') self.floorModel = None self.elevatorOutOpen = 0 self.BottomFloor_SuitPositions = [ Point3(0, 15, 0), Point3(10, 20, 0), Point3(-7, 24, 0), Point3(-10, 0, 0) ] self.BottomFloor_SuitHs = [75, 170, -91, -44] self.Cubicle_SuitPositions = [ Point3(0, 18, 0), Point3(10, 12, 0), Point3(-9, 11, 0), Point3(-3, 13, 0) ] self.Cubicle_SuitHs = [170, 56, -52, 10] self.BossOffice_SuitPositions = [ Point3(0, 15, 0), Point3(10, 20, 0), Point3(-10, 6, 0), Point3(-17, 30, 0) ] self.BossOffice_SuitHs = [170, 120, 12, 38] self._wantBarrelRoom = config.GetBool('cogdo-want-barrel-room', 1) self.barrelRoom = CogdoBarrelRoom.CogdoBarrelRoom() self.brResults = [[], []] self.barrelRoomIntroTrack = None self.penthouseOutroTrack = None self.penthouseOutroChatDoneTrack = None self.penthouseIntroTrack = None self.waitMusic = base.loadMusic( 'phase_7/audio/bgm/encntr_toon_winning_indoor.ogg') self.elevatorMusic = base.loadMusic( 'phase_7/audio/bgm/tt_elevator.ogg') self.fsm = ClassicFSM.ClassicFSM('DistributedCogdoInterior', [ State.State('WaitForAllToonsInside', self.enterWaitForAllToonsInside, self.exitWaitForAllToonsInside, ['Elevator']), State.State('Elevator', self.enterElevator, self.exitElevator, ['Game', 'BattleIntro', 'BarrelRoomIntro']), State.State('Game', self.enterGame, self.exitGame, [ 'Resting', 'Failed', 'BattleIntro', 'BarrelRoomIntro', 'Elevator' ]), State.State('BarrelRoomIntro', self.enterBarrelRoomIntro, self.exitBarrelRoomIntro, ['CollectBarrels', 'Off']), State.State('CollectBarrels', self.enterCollectBarrels, self.exitCollectBarrels, ['BarrelRoomReward', 'Off']), State.State('BarrelRoomReward', self.enterBarrelRoomReward, self.exitBarrelRoomReward, ['Battle', 'ReservesJoining', 'BattleIntro', 'Off']), State.State('BattleIntro', self.enterBattleIntro, self.exitBattleIntro, ['Battle', 'ReservesJoining', 'Off']), State.State('Battle', self.enterBattle, self.exitBattle, ['Resting', 'Reward', 'ReservesJoining']), State.State('ReservesJoining', self.enterReservesJoining, self.exitReservesJoining, ['Battle']), State.State('Resting', self.enterResting, self.exitResting, ['Elevator']), State.State('Reward', self.enterReward, self.exitReward, ['Off']), State.State('Failed', self.enterFailed, self.exitFailed, ['Off']), State.State('Off', self.enterOff, self.exitOff, ['Elevator', 'WaitForAllToonsInside', 'Battle']) ], 'Off', 'Off') self.fsm.enterInitialState() self._haveEntranceElevator = StateVar(False) self._stashEntranceElevator = StateVar(False) self._stashEntranceElevatorFC = FunctionCall( self._doStashEntranceElevator, self._haveEntranceElevator, self._stashEntranceElevator) self._entranceElevCallbacks = [] self._doEntranceElevCallbacksFC = FunctionCall( self._doEntranceElevCallbacks, self._haveEntranceElevator) self.cage = None self.shopOwnerNpcId = None self.shopOwnerNpc = None self._movie = None self.SOSToonName = None self.FOType = None def setShopOwnerNpcId(self, npcId): self.shopOwnerNpcId = npcId def setSOSNpcId(self, npcId): self.SOSToonName = NPCToons.getNPCName(npcId) def setFOType(self, typeId): self.FOType = chr(typeId) def getFOType(self): return self.FOType def __uniqueName(self, name): DistributedCogdoInterior.id += 1 return name + '%d' % DistributedCogdoInterior.id def generate(self): DistributedObject.DistributedObject.generate(self) self.announceGenerateName = self.uniqueName('generate') self.accept(self.announceGenerateName, self.handleAnnounceGenerate) self.elevatorModelIn = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_csa_elevatorB') self.leftDoorIn = self.elevatorModelIn.find('**/left_door') self.rightDoorIn = self.elevatorModelIn.find('**/right_door') self.elevatorModelOut = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_csa_elevator') self.leftDoorOut = self.elevatorModelOut.find('**/left_door') self.rightDoorOut = self.elevatorModelOut.find('**/right_door') def __makeShopOwnerNpc(self): if self.shopOwnerNpc: return self.shopOwnerNpc = NPCToons.createLocalNPC(self.shopOwnerNpcId) if not self.shopOwnerNpc: self.notify.warning( 'No shopkeeper in this cogdominium, using FunnyFarm Sellbot FO NPCToons' ) random.seed(self.doId) shopkeeper = random.randint(7001, 7009) self.shopOwnerNpc = NPCToons.createLocalNPC(shopkeeper) self.shopOwnerNpc.addActive() self.shopOwnerNpc.reparentTo(self.cage) self.shopOwnerNpc.setPosHpr(0, -2, 0, 180, 0, 0) self.shopOwnerNpc.loop('neutral') def setElevatorLights(self, elevatorModel): npc = elevatorModel.findAllMatches('**/floor_light_?;+s') for i in xrange(npc.getNumPaths()): np = npc.getPath(i) np.setDepthOffset(120) floor = int(np.getName()[-1:]) - 1 if floor == self.currentFloor: np.setColor(LIGHT_ON_COLOR) elif floor < self.layout.getNumGameFloors() + ( 1 if self.FOType != "s" else 0): if self.isBossFloor(self.currentFloor): np.setColor(LIGHT_ON_COLOR) else: np.setColor(LIGHT_OFF_COLOR) else: np.hide() def startAlertElevatorLightIval(self, elevatorModel): light = elevatorModel.find('**/floor_light_%s' % (self.currentFloor + 1)) track = Sequence(Func(light.setColor, Vec4(1.0, 0.6, 0.6, 1.0)), Wait(0.9), Func(light.setColor, LIGHT_ON_COLOR), Wait(0.9)) self.activeIntervals['alertElevatorLight'] = track track.loop() def stopAlertElevatorLightIval(self, elevatorModel): self.__finishInterval('alertElevatorLight') self.setElevatorLights(elevatorModel) def handleAnnounceGenerate(self, obj): self.ignore(self.announceGenerateName) self.cageDoorSfx = loader.loadSfx( 'phase_5/audio/sfx/CHQ_SOS_cage_door.ogg') self.cageLowerSfx = loader.loadSfx( 'phase_5/audio/sfx/CHQ_SOS_cage_lower.ogg') self.sendUpdate('setAvatarJoined', []) def disable(self): self.fsm.requestFinalState() self.__cleanupIntervals() self.ignoreAll() self.__cleanup() self.__cleanupShopOwnerNpc() self.__cleanupPenthouseIntro() DistributedObject.DistributedObject.disable(self) def __cleanupShopOwnerNpc(self): if self.shopOwnerNpc: self.shopOwnerNpc.removeActive() self.shopOwnerNpc.delete() self.shopOwnerNpc = None def __cleanupPenthouseIntro(self): if hasattr(self, '_movie') and self._movie: self._movie.unload() self._movie = None def delete(self): self._stashEntranceElevatorFC.destroy() self._doEntranceElevCallbacksFC.destroy() self._haveEntranceElevator.destroy() self._stashEntranceElevator.destroy() self._entranceElevCallbacks = None del self.waitMusic del self.elevatorMusic del self.openSfx del self.closeSfx del self.fsm base.localAvatar.inventory.setBattleCreditMultiplier(1) DistributedObject.DistributedObject.delete(self) def isBossFloor(self, floorNum): if not self.layout.hasBossBattle(): return False return (self.layout.getBossBattleFloor() + 0) == floorNum def __cleanup(self): self.toons = [] self.suits = [] self.reserveSuits = [] self.joiningReserves = [] if self.elevatorModelIn != None: self.elevatorModelIn.removeNode() if self.elevatorModelOut != None: self.elevatorModelOut.removeNode() if self.floorModel != None: self.floorModel.removeNode() if self.cage != None: self.cage = None if self.barrelRoom != None: self.barrelRoom.destroy() self.barrelRoom = None self.leftDoorIn = None self.rightDoorIn = None self.leftDoorOut = None self.rightDoorOut = None def __addToon(self, toon): self.accept(toon.uniqueName('disable'), self.__handleUnexpectedExit, extraArgs=[toon]) def __handleUnexpectedExit(self, toon): self.notify.warning('handleUnexpectedExit() - toon: %d' % toon.doId) self.__removeToon(toon, unexpected=1) def __removeToon(self, toon, unexpected=0): if self.toons.count(toon) == 1: self.toons.remove(toon) self.ignore(toon.uniqueName('disable')) def __finishInterval(self, name): if name in self.activeIntervals: interval = self.activeIntervals[name] if interval.isPlaying(): interval.finish() def __cleanupIntervals(self): for interval in self.activeIntervals.values(): interval.finish() self.activeIntervals = {} def __closeInElevator(self): self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) def getZoneId(self): return self.zoneId def setZoneId(self, zoneId): self.zoneId = zoneId def getExtZoneId(self): return self.extZoneId def setExtZoneId(self, extZoneId): self.extZoneId = extZoneId def getDistBldgDoId(self): return self.distBldgDoId def setDistBldgDoId(self, distBldgDoId): self.distBldgDoId = distBldgDoId def setNumFloors(self, numFloors): self.layout = CogdoLayout(numFloors) def getToonIds(self): toonIds = [] for toon in self.toons: toonIds.append(toon.doId) return toonIds def setToons(self, toonIds, hack): self.toonIds = toonIds oldtoons = self.toons self.toons = [] for toonId in toonIds: if toonId != 0: if toonId in self.cr.doId2do: toon = self.cr.doId2do[toonId] toon.stopSmooth() self.toons.append(toon) if not oldtoons.count(toon): self.__addToon(toon) else: self.notify.warning('setToons() - no toon: %d' % toonId) for toon in oldtoons: if not self.toons.count(toon): self.__removeToon(toon) def setSuits(self, suitIds, reserveIds, values): oldsuits = self.suits self.suits = [] self.joiningReserves = [] for suitId in suitIds: if suitId in self.cr.doId2do: suit = self.cr.doId2do[suitId] self.suits.append(suit) suit.fsm.request('Battle') suit.buildingSuit = 1 suit.reparentTo(render) if not oldsuits.count(suit): self.joiningReserves.append(suit) if 'Elevator' in repr(self.fsm): pos, h = BattleBase.BattleBase.suitPoints[ len(suitIds) - 1][suitIds.index(suitId)] suit.setPos(pos) suit.setH(h) else: self.notify.warning('setSuits() - no suit: %d' % suitId) self.reserveSuits = [] for index in xrange(len(reserveIds)): suitId = reserveIds[index] if suitId in self.cr.doId2do: suit = self.cr.doId2do[suitId] self.reserveSuits.append((suit, values[index])) else: self.notify.warning('setSuits() - no suit: %d' % suitId) if len(self.joiningReserves) > 0: self.fsm.request('ReservesJoining') def setState(self, state, timestamp): self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def stashElevatorIn(self, stash=True): self._stashEntranceElevator.set(stash) def getEntranceElevator(self, callback): if self._haveEntranceElevator.get(): callback(self.elevIn) else: self._entranceElevCallbacks.append(callback) def _doEntranceElevCallbacks(self, haveElev): if haveElev: while len(self._entranceElevCallbacks): cbs = self._entranceElevCallbacks[:] self._entranceElevCallbacks = [] for callback in cbs: callback(self.elevIn) def _doStashEntranceElevator(self, haveElev, doStash): if haveElev: if doStash: self.elevIn.stash() else: self.elevIn.unstash() def d_elevatorDone(self): self.sendUpdate('elevatorDone', []) def d_reserveJoinDone(self): self.sendUpdate('reserveJoinDone', []) def enterOff(self, ts=0): messenger.send('sellbotFieldOfficeChanged', [False]) def exitOff(self): pass def enterWaitForAllToonsInside(self, ts=0): base.transitions.fadeOut(0) def exitWaitForAllToonsInside(self): pass def enterGame(self, ts=0): base.cr.forbidCheesyEffects(1) def exitGame(self): base.cr.forbidCheesyEffects(0) def __playElevator(self, ts, name, callback): SuitHs = [] SuitPositions = [] if self.floorModel: self.floorModel.removeNode() self.floorModel = None if self.cage: self.cage = None if self.currentFloor == 0: SuitHs = self.BottomFloor_SuitHs SuitPositions = self.BottomFloor_SuitPositions if self.isBossFloor(self.currentFloor): self.notify.info('__playElevator: currentFloor %s is boss' % self.currentFloor) self.barrelRoom.unload() if self.FOType: penthouseName = SUITE_DICT.get(self.FOType) for i in range(4): self.floorModel = loader.loadModel( 'phase_5/models/cogdominium/%s' % penthouseName) self.cage = self.floorModel.find('**/cage') pos = self.cage.getPos() self.cagePos = [] for height in self.cageHeights: self.cagePos.append(Point3(pos[0], pos[1], height)) self.cageDoor = self.floorModel.find('**/cage_door') self.cageDoor.wrtReparentTo(self.cage) if self.FOType: paintingModelName = PAINTING_DICT.get(self.FOType) for i in xrange(4): paintingModel = loader.loadModel( 'phase_5/models/cogdominium/%s' % paintingModelName) loc = self.floorModel.find('**/loc_painting%d' % (i + 1)) paintingModel.reparentTo(loc) if not self.floorModel.find('**/trophyCase').isEmpty(): for i in range(4): goldEmblem = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy.bam' ) loc = self.floorModel.find('**/gold_0%d' % (i + 1)) goldEmblem.reparentTo(loc) for i in range(20): silverEmblem = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam' ) loc = self.floorModel.find('**/silver_0%d' % (i + 1)) silverEmblem.reparentTo(loc) SuitHs = self.BossOffice_SuitHs SuitPositions = self.BossOffice_SuitPositions self.__makeShopOwnerNpc() else: if self._wantBarrelRoom: self.barrelRoom.load() self.barrelRoom.hide() SuitHs = self.Cubicle_SuitHs SuitPositions = self.Cubicle_SuitPositions if self.floorModel: self.floorModel.reparentTo(render) if self.isBossFloor(self.currentFloor): self.notify.info('Load boss_suit_office') elevIn = self.floorModel.find( CogdoGameConsts.PenthouseElevatorInPath).copyTo(render) elevOut = self.floorModel.find( CogdoGameConsts.PenthouseElevatorOutPath) frame = self.elevatorModelOut.find('**/frame') if not frame.isEmpty(): frame.hide() frame = self.elevatorModelIn.find('**/frame') if not frame.isEmpty(): frame.hide() self.elevatorModelOut.reparentTo(elevOut) self.elevatorModelOut.setY(0) else: elevIn = self.floorModel.find('**/elevator-in') elevOut = self.floorModel.find('**/elevator-out') elif self._wantBarrelRoom and self.barrelRoom.isLoaded( ) and self.currentFloor == 2 and self.FOType == 'l': elevIn = self.barrelRoom.model.find( CogdoBarrelRoomConsts.BarrelRoomElevatorInPath) elevOut = self.barrelRoom.model.find( CogdoBarrelRoomConsts.BarrelRoomElevatorOutPath) y = elevOut.getY(render) elevOut = elevOut.copyTo(render) elevOut.setY(render, y - 0.75) else: floorModel = loader.loadModel( 'phase_7/models/modules/boss_suit_office') elevIn = floorModel.find('**/elevator-in').copyTo(render) elevOut = floorModel.find('**/elevator-out').copyTo(render) floorModel.removeNode() self.elevIn = elevIn self.elevOut = elevOut self._haveEntranceElevator.set(True) for index in range(len(self.suits)): if not self.suits[index].isEmpty(): self.suits[index].setPos(SuitPositions[index]) if len(self.suits) > 2: self.suits[index].setH(SuitHs[index]) else: self.suits[index].setH(170) self.suits[index].loop('neutral') for toon in self.toons: toon.reparentTo(self.elevatorModelIn) index = self.toonIds.index(toon.doId) toon.setPos(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2]) toon.setHpr(180, 0, 0) toon.loop('neutral') self.elevatorModelIn.reparentTo(elevIn) self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) camera.reparentTo(self.elevatorModelIn) camera.setH(180) camera.setP(0) camera.setPos(0, 14, 4) base.playMusic(self.elevatorMusic, looping=1, volume=0.8) track = Sequence( Func(base.transitions.noTransitions), ElevatorUtils.getRideElevatorInterval(ELEVATOR_NORMAL), ElevatorUtils.getOpenInterval(self, self.leftDoorIn, self.rightDoorIn, self.openSfx, None, type=ELEVATOR_NORMAL), Func(camera.wrtReparentTo, render)) for toon in self.toons: track.append(Func(toon.wrtReparentTo, render)) track.append(Func(callback)) track.start(ts) self.activeIntervals[name] = track def enterElevator(self, ts=0): if not self._CogdoGameRepeat: self.currentFloor += 1 self.cr.playGame.getPlace().currentFloor = self.currentFloor self.setElevatorLights(self.elevatorModelIn) self.setElevatorLights(self.elevatorModelOut) if not self.isBossFloor(self.currentFloor): self.elevatorModelOut.detachNode() messenger.send('sellbotFieldOfficeChanged', [True]) else: if self.FOType == 's': self._movie = CogdoElevatorMovie() self._movie.load() self._movie.play() self.__playElevator(ts, self.elevatorName, self.__handleElevatorDone) mult = ToontownBattleGlobals.getCreditMultiplier(self.currentFloor) base.localAvatar.inventory.setBattleCreditMultiplier(mult) def __handleElevatorDone(self): self.d_elevatorDone() def exitElevator(self): self.elevatorMusic.stop() if self._movie: self._movie.end() self.__cleanupPenthouseIntro() self.__finishInterval(self.elevatorName) def __setupBarrelRoom(self): self.currentFloor += 1 base.transitions.irisOut(0.0) self.elevatorModelOut.setY(-12) self.elevatorModelIn.reparentTo( self.barrelRoom.model.find( CogdoBarrelRoomConsts.BarrelRoomElevatorInPath)) self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) self._showExitElevator() self.barrelRoom.show() self.barrelRoom.placeToonsAtEntrance(self.toons) self.setElevatorLights(self.elevatorModelOut) def barrelRoomIntroDone(self): self.sendUpdate('toonBarrelRoomIntroDone', []) def enterBarrelRoomIntro(self, ts=0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.__setupBarrelRoom() self.barrelRoomIntroTrack, trackName = self.barrelRoom.getIntroInterval( ) self.barrelRoomIntroDoneEvent = trackName self.accept(self.barrelRoomIntroDoneEvent, self.barrelRoomIntroDone) self.activeIntervals[trackName] = self.barrelRoomIntroTrack self.barrelRoomIntroTrack.start(ts) self._movie = CogdoBarrelRoomIntro() self._movie.load() self._movie.play() else: self._showExitElevator() def exitBarrelRoomIntro(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore(self.barrelRoomIntroDoneEvent) if self.barrelRoomIntroTrack: self.barrelRoomIntroTrack.finish() DelayDelete.cleanupDelayDeletes(self.barrelRoomIntroTrack) self.barrelRoomIntroTrack = None def __handleLocalToonLeftBarrelRoom(self): self.notify.info('Local toon teleported out of barrel room.') self.sendUpdate('toonLeftBarrelRoom', []) self.barrelRoom.deactivate() def enterCollectBarrels(self, ts=0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.acceptOnce('localToonLeft', self.__handleLocalToonLeftBarrelRoom) self.barrelRoom.activate() base.playMusic(self.waitMusic, looping=1, volume=0.7) base.localAvatar.questMap.stop() def exitCollectBarrels(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore('localToonLeft') self.barrelRoom.deactivate() self.waitMusic.stop() def __brRewardDone(self, task=None): self.notify.info('Toon finished watching the barrel room reward.') self.sendUpdate('toonBarrelRoomRewardDone', []) self.fsm.request('Battle') def enterBarrelRoomReward(self, ts=0): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('stopped') self.startAlertElevatorLightIval(self.elevatorModelOut) track, trackName = self.barrelRoom.showRewardUi( callback=self.__brRewardDone) self.activeIntervals[trackName] = track track.start() self.barrelRoom.placeToonsNearBattle(self.toons) def exitBarrelRoomReward(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('walk') self.stopAlertElevatorLightIval(self.elevatorModelOut) self.barrelRoom.hideRewardUi() def enterBattleIntro(self, ts=0): self._movie = CogdoExecutiveSuiteIntro(self.shopOwnerNpc) self._movie.load() self._movie.play() def exitBattleIntro(self): self._movie.end() self.__cleanupPenthouseIntro() def __playCloseElevatorOut(self, name, delay=0): track = Sequence( Wait(delay + SUIT_LEAVE_ELEVATOR_TIME), Parallel( SoundInterval(self.closeSfx), LerpPosInterval( self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut'), LerpPosInterval( self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut'))) track.start() self.activeIntervals[name] = track def enterBattle(self, ts=0): if self._wantBarrelRoom and self.elevatorOutOpen == 1: self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'), delay=2) camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) def _showExitElevator(self): self.elevatorModelOut.reparentTo(self.elevOut) self.leftDoorOut.setPos(3.5, 0, 0) self.rightDoorOut.setPos(-3.5, 0, 0) if not self._wantBarrelRoom and self.elevatorOutOpen == 1: self.__playCloseElevatorOut(self.uniqueName('close-out-elevator')) camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) def exitBattle(self): if self.elevatorOutOpen == 1: self.__finishInterval(self.uniqueName('close-out-elevator')) self.elevatorOutOpen = 0 def __playReservesJoining(self, ts, name, callback): index = 0 for suit in self.joiningReserves: suit.reparentTo(render) suit.setPos( self.elevatorModelOut, Point3(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2])) index += 1 suit.setH(180) suit.loop('neutral') if len(self.suits) == len(self.joiningReserves): camSequence = Sequence(Func(camera.wrtReparentTo, localAvatar), Func(camera.setPos, Point3(0, 5, 5)), Func(camera.headsUp, self.elevatorModelOut)) else: camSequence = Sequence( Func(camera.wrtReparentTo, self.elevatorModelOut), Func(camera.setPos, Point3(0, -8, 2)), Func(camera.setHpr, Vec3(0, 10, 0))) track = Sequence( camSequence, Parallel( SoundInterval(self.openSfx), LerpPosInterval( self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), blendType='easeOut'), LerpPosInterval( self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), blendType='easeOut')), Wait(SUIT_HOLD_ELEVATOR_TIME), Func(camera.wrtReparentTo, render), Func(callback)) track.start(ts) self.activeIntervals[name] = track def enterReservesJoining(self, ts=0): self.__playReservesJoining(ts, self.uniqueName('reserves-joining'), self.__handleReserveJoinDone) return None def __handleReserveJoinDone(self): self.joiningReserves = [] self.elevatorOutOpen = 1 self.d_reserveJoinDone() def exitReservesJoining(self): self.__finishInterval(self.uniqueName('reserves-joining')) return None def enterResting(self, ts=0): self._showExitElevator() self._setAvPosFDC = FrameDelayedCall('setAvPos', self._setAvPosToExit) if self._wantBarrelRoom: self.barrelRoom.showBattleAreaLight(True) base.playMusic(self.waitMusic, looping=1, volume=0.7) self.__closeInElevator() self._haveEntranceElevator.set(False) self._stashEntranceElevator.set(False) def _setAvPosToExit(self): base.localAvatar.setPos(self.elevOut, 0, -22, 0) base.localAvatar.setHpr(self.elevOut, 0, 0, 0) base.cr.playGame.getPlace().fsm.request('walk') def exitResting(self): self._setAvPosFDC.destroy() self.waitMusic.stop() def enterReward(self, ts=0): if self.isBossFloor(self.currentFloor): self.penthouseOutroTrack = self.__outroPenthouse() self.penthouseOutroTrack.start(ts) else: self.exitCogdoBuilding() def exitReward(self): self.notify.debug('exitReward') if self.penthouseOutroTrack: self.penthouseOutroTrack.finish() DelayDelete.cleanupDelayDeletes(self.penthouseOutroTrack) self.penthouseOutroTrack = None if not self.penthouseOutroChatDoneTrack: self.notify.debug( 'exitReward: instanting outroPenthouseChatDone track') self.__outroPenthouseChatDone() self.penthouseOutroChatDoneTrack.finish() self.penthouseOutroChatDoneTrack = None def enterFailed(self, ts=0): self.exitCogdoBuilding() def exitFailed(self): self.notify.debug('exitFailed()') self.exitCogdoBuilding() def exitCogdoBuilding(self): if base.localAvatar.hp < 0: return base.localAvatar.b_setParent(ToontownGlobals.SPHidden) request = { 'loader': ZoneUtil.getBranchLoaderName(self.extZoneId), 'where': ZoneUtil.getToonWhereName(self.extZoneId), 'how': 'elevatorIn', 'hoodId': ZoneUtil.getHoodId(self.extZoneId), 'zoneId': self.extZoneId, 'shardId': None, 'avId': -1, 'bldgDoId': self.distBldgDoId } messenger.send('DSIDoneEvent', [request]) def displayBadges(self): numFloors = self.layout.getNumGameFloors() if numFloors > 5 or numFloors < 3: pass else: self.notify.warning('Invalid floor number for display badges.') for player in xrange(len(self.toons)): goldBadge = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy') goldBadge.setScale(1.2) goldNode = render.find('**/gold_0' + str(player + 1)) goldBadge.reparentTo(goldNode) for floor in xrange(numFloors): silverBadge = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam') silverBadge.setScale(1.2) silverNode = render.find('**/silver_0' + str(floor * 4 + (player + 1))) silverBadge.reparentTo(silverNode) def __outroPenthouse(self): avatar = base.localAvatar trackName = '__outroPenthouse-%d' % avatar.doId track = Parallel(name=trackName) base.cr.playGame.getPlace().fsm.request('stopped') if self.FOType == "l": speech = TTLocalizer.CogdoLawbotExecutiveSuiteToonThankYou else: speech = TTLocalizer.CogdoExecutiveSuiteToonThankYou % self.SOSToonName track.append( Sequence( Func(camera.wrtReparentTo, localAvatar), Func(camera.setPos, 0, -9, 9), Func(camera.lookAt, Point3(5, 15, 0)), Parallel( self.cage.posInterval(0.75, self.cagePos[1], blendType='easeOut'), SoundInterval(self.cageLowerSfx, duration=0.5)), Parallel( self.cageDoor.hprInterval(0.5, VBase3(0, 90, 0), blendType='easeOut'), Sequence(SoundInterval(self.cageDoorSfx), duration=0)), Wait(0.25), Func(self.shopOwnerNpc.wrtReparentTo, render), Func(self.shopOwnerNpc.setScale, 1), Func(self.shopOwnerNpc.loop, 'walk'), Func(self.shopOwnerNpc.headsUp, Point3(0, 10, 0)), ParallelEndTogether( self.shopOwnerNpc.posInterval(1.5, Point3(0, 10, 0)), self.shopOwnerNpc.hprInterval(0.5, VBase3(180, 0, 0), blendType='easeInOut')), Func(self.shopOwnerNpc.setChatAbsolute, TTLocalizer.CagedToonYippee, CFSpeech), ActorInterval(self.shopOwnerNpc, 'jump'), Func(self.shopOwnerNpc.loop, 'neutral'), Func(self.shopOwnerNpc.headsUp, localAvatar), Func(self.shopOwnerNpc.setLocalPageChat, speech, 0), Func(camera.lookAt, self.shopOwnerNpc, Point3(0, 0, 2)))) self.activeIntervals[trackName] = track self.accept('doneChatPage', self.__outroPenthouseChatDone) return track def __outroPenthouseChatDone(self, elapsed=None): self.shopOwnerNpc.setChatAbsolute( TTLocalizer.CogdoExecutiveSuiteToonBye, CFSpeech) self.ignore('doneChatPage') track = Parallel( Sequence(ActorInterval(self.shopOwnerNpc, 'wave'), Func(self.shopOwnerNpc.loop, 'neutral')), Sequence(Wait(2.0), Func(self.exitCogdoBuilding), Func(base.camLens.setFov, settings['fieldofview']))) track.start() self.penthouseOutroChatDoneTrack = track
class TaskManager: notify = directNotify.newCategory("TaskManager") taskTimerVerbose = ConfigVariableBool('task-timer-verbose', False) extendedExceptions = ConfigVariableBool('extended-exceptions', False) pStatsTasks = ConfigVariableBool('pstats-tasks', False) MaxEpochSpeed = 1.0/30.0 def __init__(self): self.mgr = AsyncTaskManager.getGlobalPtr() self.resumeFunc = None self.globalClock = self.mgr.getClock() self.stepping = False self.running = False self.destroyed = False self.fKeyboardInterrupt = False self.interruptCount = 0 if signal: self.__prevHandler = signal.default_int_handler self._frameProfileQueue = [] # this will be set when it's safe to import StateVar self._profileFrames = None self._frameProfiler = None self._profileTasks = None self._taskProfiler = None self._taskProfileInfo = ScratchPad( taskId = None, profiled = False, session = None, ) def finalInit(self): # This function should be called once during startup, after # most things are imported. from direct.fsm.StatePush import StateVar self._profileTasks = StateVar(False) self.setProfileTasks(ConfigVariableBool('profile-task-spikes', 0).getValue()) self._profileFrames = StateVar(False) self.setProfileFrames(ConfigVariableBool('profile-frames', 0).getValue()) def destroy(self): # This should be safe to call multiple times. self.running = False self.notify.info("TaskManager.destroy()") self.destroyed = True self._frameProfileQueue.clear() self.mgr.cleanup() def setClock(self, clockObject): self.mgr.setClock(clockObject) self.globalClock = clockObject clock = property(lambda self: self.mgr.getClock(), setClock) def invokeDefaultHandler(self, signalNumber, stackFrame): print('*** allowing mid-frame keyboard interrupt.') # Restore default interrupt handler if signal: signal.signal(signal.SIGINT, self.__prevHandler) # and invoke it raise KeyboardInterrupt def keyboardInterruptHandler(self, signalNumber, stackFrame): self.fKeyboardInterrupt = 1 self.interruptCount += 1 if self.interruptCount == 1: print('* interrupt by keyboard') elif self.interruptCount == 2: print('** waiting for end of frame before interrupting...') # The user must really want to interrupt this process # Next time around invoke the default handler signal.signal(signal.SIGINT, self.invokeDefaultHandler) def getCurrentTask(self): """ Returns the task currently executing on this thread, or None if this is being called outside of the task manager. """ return Thread.getCurrentThread().getCurrentTask() def hasTaskChain(self, chainName): """ Returns true if a task chain with the indicated name has already been defined, or false otherwise. Note that setupTaskChain() will implicitly define a task chain if it has not already been defined, or modify an existing one if it has, so in most cases there is no need to check this method first. """ return self.mgr.findTaskChain(chainName) is not None def setupTaskChain(self, chainName, numThreads = None, tickClock = None, threadPriority = None, frameBudget = None, frameSync = None, timeslicePriority = None): """Defines a new task chain. Each task chain executes tasks potentially in parallel with all of the other task chains (if numThreads is more than zero). When a new task is created, it may be associated with any of the task chains, by name (or you can move a task to another task chain with task.setTaskChain()). You can have any number of task chains, but each must have a unique name. numThreads is the number of threads to allocate for this task chain. If it is 1 or more, then the tasks on this task chain will execute in parallel with the tasks on other task chains. If it is greater than 1, then the tasks on this task chain may execute in parallel with themselves (within tasks of the same sort value). If tickClock is True, then this task chain will be responsible for ticking the global clock each frame (and thereby incrementing the frame counter). There should be just one task chain responsible for ticking the clock, and usually it is the default, unnamed task chain. threadPriority specifies the priority level to assign to threads on this task chain. It may be one of TPLow, TPNormal, TPHigh, or TPUrgent. This is passed to the underlying threading system to control the way the threads are scheduled. frameBudget is the maximum amount of time (in seconds) to allow this task chain to run per frame. Set it to -1 to mean no limit (the default). It's not directly related to threadPriority. frameSync is true to force the task chain to sync to the clock. When this flag is false, the default, the task chain will finish all of its tasks and then immediately start from the first task again, regardless of the clock frame. When it is true, the task chain will finish all of its tasks and then wait for the clock to tick to the next frame before resuming the first task. This only makes sense for threaded tasks chains; non-threaded task chains are automatically synchronous. timeslicePriority is False in the default mode, in which each task runs exactly once each frame, round-robin style, regardless of the task's priority value; or True to change the meaning of priority so that certain tasks are run less often, in proportion to their time used and to their priority value. See AsyncTaskManager.setTimeslicePriority() for more. """ chain = self.mgr.makeTaskChain(chainName) if numThreads is not None: chain.setNumThreads(numThreads) if tickClock is not None: chain.setTickClock(tickClock) if threadPriority is not None: chain.setThreadPriority(threadPriority) if frameBudget is not None: chain.setFrameBudget(frameBudget) if frameSync is not None: chain.setFrameSync(frameSync) if timeslicePriority is not None: chain.setTimeslicePriority(timeslicePriority) def hasTaskNamed(self, taskName): """Returns true if there is at least one task, active or sleeping, with the indicated name. """ return bool(self.mgr.findTask(taskName)) def getTasksNamed(self, taskName): """Returns a list of all tasks, active or sleeping, with the indicated name. """ return list(self.mgr.findTasks(taskName)) def getTasksMatching(self, taskPattern): """Returns a list of all tasks, active or sleeping, with a name that matches the pattern, which can include standard shell globbing characters like \\*, ?, and []. """ return list(self.mgr.findTasksMatching(GlobPattern(taskPattern))) def getAllTasks(self): """Returns list of all tasks, active and sleeping, in arbitrary order. """ return list(self.mgr.getTasks()) def getTasks(self): """Returns list of all active tasks in arbitrary order. """ return list(self.mgr.getActiveTasks()) def getDoLaters(self): """Returns list of all sleeping tasks in arbitrary order. """ return list(self.mgr.getSleepingTasks()) def doMethodLater(self, delayTime, funcOrTask, name, extraArgs = None, sort = None, priority = None, taskChain = None, uponDeath = None, appendTask = False, owner = None): """Adds a task to be performed at some time in the future. This is identical to `add()`, except that the specified delayTime is applied to the Task object first, which means that the task will not begin executing until at least the indicated delayTime (in seconds) has elapsed. After delayTime has elapsed, the task will become active, and will run in the soonest possible frame thereafter. If you wish to specify a task that will run in the next frame, use a delayTime of 0. """ if delayTime < 0: assert self.notify.warning('doMethodLater: added task: %s with negative delay: %s' % (name, delayTime)) task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath) task.setDelay(delayTime) self.mgr.add(task) return task do_method_later = doMethodLater def add(self, funcOrTask, name = None, sort = None, extraArgs = None, priority = None, uponDeath = None, appendTask = False, taskChain = None, owner = None, delay = None): """ Add a new task to the taskMgr. The task will begin executing immediately, or next frame if its sort value has already passed this frame. Parameters: funcOrTask: either an existing Task object (not already added to the task manager), or a callable function object. If this is a function, a new Task object will be created and returned. You may also pass in a coroutine object. name (str): the name to assign to the Task. Required, unless you are passing in a Task object that already has a name. extraArgs (list): the list of arguments to pass to the task function. If this is omitted, the list is just the task object itself. appendTask (bool): If this is true, then the task object itself will be appended to the end of the extraArgs list before calling the function. sort (int): the sort value to assign the task. The default sort is 0. Within a particular task chain, it is guaranteed that the tasks with a lower sort value will all run before tasks with a higher sort value run. priority (int): the priority at which to run the task. The default priority is 0. Higher priority tasks are run sooner, and/or more often. For historical purposes, if you specify a priority without also specifying a sort, the priority value is understood to actually be a sort value. (Previously, there was no priority value, only a sort value, and it was called "priority".) uponDeath (bool): a function to call when the task terminates, either because it has run to completion, or because it has been explicitly removed. taskChain (str): the name of the task chain to assign the task to. owner: an optional Python object that is declared as the "owner" of this task for maintenance purposes. The owner must have two methods: ``owner._addTask(self, task)``, which is called when the task begins, and ``owner._clearTask(self, task)``, which is called when the task terminates. This is all the ownermeans. delay: an optional amount of seconds to wait before starting the task (equivalent to doMethodLater). Returns: The new Task object that has been added, or the original Task object that was passed in. """ task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath) if delay is not None: task.setDelay(delay) self.mgr.add(task) return task def __setupTask(self, funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath): if isinstance(funcOrTask, AsyncTask): task = funcOrTask elif hasattr(funcOrTask, '__call__') or \ hasattr(funcOrTask, 'cr_await') or \ isinstance(funcOrTask, types.GeneratorType): # It's a function, coroutine, or something emulating a coroutine. task = PythonTask(funcOrTask) if name is None: name = getattr(funcOrTask, '__qualname__', None) or \ getattr(funcOrTask, '__name__', None) else: self.notify.error( 'add: Tried to add a task that was not a Task or a func') if hasattr(task, 'setArgs'): # It will only accept arguments if it's a PythonTask. if extraArgs is None: extraArgs = [] appendTask = True task.setArgs(extraArgs, appendTask) elif extraArgs is not None: self.notify.error( 'Task %s does not accept arguments.' % (repr(task))) if name is not None: task.setName(name) assert task.hasName() # For historical reasons, if priority is specified but not # sort, it really means sort. if priority is not None and sort is None: task.setSort(priority) else: if priority is not None: task.setPriority(priority) if sort is not None: task.setSort(sort) if taskChain is not None: task.setTaskChain(taskChain) if owner is not None: task.setOwner(owner) if uponDeath is not None: task.setUponDeath(uponDeath) return task def remove(self, taskOrName): """Removes a task from the task manager. The task is stopped, almost as if it had returned task.done. (But if the task is currently executing, it will finish out its current frame before being removed.) You may specify either an explicit Task object, or the name of a task. If you specify a name, all tasks with the indicated name are removed. Returns the number of tasks removed. """ if isinstance(taskOrName, AsyncTask): return self.mgr.remove(taskOrName) elif isinstance(taskOrName, list): for task in taskOrName: self.remove(task) else: tasks = self.mgr.findTasks(taskOrName) return self.mgr.remove(tasks) def removeTasksMatching(self, taskPattern): """Removes all tasks whose names match the pattern, which can include standard shell globbing characters like \\*, ?, and []. See also :meth:`remove()`. Returns the number of tasks removed. """ tasks = self.mgr.findTasksMatching(GlobPattern(taskPattern)) return self.mgr.remove(tasks) def step(self): """Invokes the task manager for one frame, and then returns. Normally, this executes each task exactly once, though task chains that are in sub-threads or that have frame budgets might execute their tasks differently. """ startFrameTime = self.globalClock.getRealTime() # Replace keyboard interrupt handler during task list processing # so we catch the keyboard interrupt but don't handle it until # after task list processing is complete. self.fKeyboardInterrupt = 0 self.interruptCount = 0 if signal: self.__prevHandler = signal.signal(signal.SIGINT, self.keyboardInterruptHandler) try: self.mgr.poll() # This is the spot for an internal yield function nextTaskTime = self.mgr.getNextWakeTime() self.doYield(startFrameTime, nextTaskTime) finally: # Restore previous interrupt handler if signal: signal.signal(signal.SIGINT, self.__prevHandler) self.__prevHandler = signal.default_int_handler if self.fKeyboardInterrupt: raise KeyboardInterrupt def run(self): """Starts the task manager running. Does not return until an exception is encountered (including KeyboardInterrupt). """ if PandaSystem.getPlatform() == 'emscripten': return # Set the clock to have last frame's time in case we were # Paused at the prompt for a long time t = self.globalClock.getFrameTime() timeDelta = t - self.globalClock.getRealTime() self.globalClock.setRealTime(t) messenger.send("resetClock", [timeDelta]) if self.resumeFunc is not None: self.resumeFunc() if self.stepping: self.step() else: self.running = True while self.running: try: if len(self._frameProfileQueue) > 0: numFrames, session, callback = self._frameProfileQueue.pop(0) def _profileFunc(numFrames=numFrames): self._doProfiledFrames(numFrames) session.setFunc(_profileFunc) session.run() _profileFunc = None if callback: callback() session.release() else: self.step() except KeyboardInterrupt: self.stop() except SystemExit: self.stop() raise except IOError as ioError: code, message = self._unpackIOError(ioError) # Since upgrading to Python 2.4.1, pausing the execution # often gives this IOError during the sleep function: # IOError: [Errno 4] Interrupted function call # So, let's just handle that specific exception and stop. # All other IOErrors should still get raised. # Only problem: legit IOError 4s will be obfuscated. if code == 4: self.stop() else: raise except Exception as e: if self.extendedExceptions: self.stop() print_exc_plus() else: from direct.showbase import ExceptionVarDump if ExceptionVarDump.wantStackDumpLog and \ ExceptionVarDump.dumpOnExceptionInit: ExceptionVarDump._varDump__print(e) raise except: if self.extendedExceptions: self.stop() print_exc_plus() else: raise self.mgr.stopThreads() def _unpackIOError(self, ioError): # IOError unpack from http://www.python.org/doc/essays/stdexceptions/ # this needs to be in its own method, exceptions that occur inside # a nested try block are not caught by the inner try block's except try: (code, message) = ioError except: code = 0 message = ioError return code, message def stop(self): # Set a flag so we will stop before beginning next frame self.running = False def __tryReplaceTaskMethod(self, task, oldMethod, newFunction): if not isinstance(task, PythonTask): return 0 method = task.getFunction() if isinstance(method, types.MethodType): function = method.__func__ else: function = method if function == oldMethod: newMethod = types.MethodType(newFunction, method.__self__) task.setFunction(newMethod) # Found a match return 1 return 0 def replaceMethod(self, oldMethod, newFunction): numFound = 0 for task in self.getAllTasks(): numFound += self.__tryReplaceTaskMethod(task, oldMethod, newFunction) return numFound def popupControls(self): # Don't use a regular import, to prevent ModuleFinder from picking # it up as a dependency when building a .p3d package. TaskManagerPanel = importlib.import_module('direct.tkpanels.TaskManagerPanel') return TaskManagerPanel.TaskManagerPanel(self) def getProfileSession(self, name=None): # call to get a profile session that you can modify before passing to profileFrames() if name is None: name = 'taskMgrFrameProfile' # Defer this import until we need it: some Python # distributions don't provide the profile and pstats modules. PS = importlib.import_module('direct.showbase.ProfileSession') return PS.ProfileSession(name) def profileFrames(self, num=None, session=None, callback=None): if num is None: num = 1 if session is None: session = self.getProfileSession() # make sure the profile session doesn't get destroyed before we're done with it session.acquire() self._frameProfileQueue.append((num, session, callback)) def _doProfiledFrames(self, numFrames): for i in range(numFrames): self.step() def getProfileFrames(self): return self._profileFrames.get() def getProfileFramesSV(self): return self._profileFrames def setProfileFrames(self, profileFrames): self._profileFrames.set(profileFrames) if (not self._frameProfiler) and profileFrames: # import here due to import dependencies FP = importlib.import_module('direct.task.FrameProfiler') self._frameProfiler = FP.FrameProfiler() def getProfileTasks(self): return self._profileTasks.get() def getProfileTasksSV(self): return self._profileTasks def setProfileTasks(self, profileTasks): self._profileTasks.set(profileTasks) if (not self._taskProfiler) and profileTasks: # import here due to import dependencies TP = importlib.import_module('direct.task.TaskProfiler') self._taskProfiler = TP.TaskProfiler() def logTaskProfiles(self, name=None): if self._taskProfiler: self._taskProfiler.logProfiles(name) def flushTaskProfiles(self, name=None): if self._taskProfiler: self._taskProfiler.flush(name) def _setProfileTask(self, task): if self._taskProfileInfo.session: self._taskProfileInfo.session.release() self._taskProfileInfo.session = None self._taskProfileInfo = ScratchPad( taskFunc = task.getFunction(), taskArgs = task.getArgs(), task = task, profiled = False, session = None, ) # Temporarily replace the task's own function with our # _profileTask method. task.setFunction(self._profileTask) task.setArgs([self._taskProfileInfo], True) def _profileTask(self, profileInfo, task): # This is called instead of the task function when we have # decided to profile a task. assert profileInfo.task == task # don't profile the same task twice in a row assert not profileInfo.profiled # Restore the task's proper function for next time. appendTask = False taskArgs = profileInfo.taskArgs if taskArgs and taskArgs[-1] == task: appendTask = True taskArgs = taskArgs[:-1] task.setArgs(taskArgs, appendTask) task.setFunction(profileInfo.taskFunc) # Defer this import until we need it: some Python # distributions don't provide the profile and pstats modules. PS = importlib.import_module('direct.showbase.ProfileSession') profileSession = PS.ProfileSession('profiled-task-%s' % task.getName(), Functor(profileInfo.taskFunc, *profileInfo.taskArgs)) ret = profileSession.run() # set these values *after* profiling in case we're profiling the TaskProfiler profileInfo.session = profileSession profileInfo.profiled = True return ret def _hasProfiledDesignatedTask(self): # have we run a profile of the designated task yet? return self._taskProfileInfo.profiled def _getLastTaskProfileSession(self): return self._taskProfileInfo.session def _getRandomTask(self): # Figure out when the next frame is likely to expire, so we # won't grab any tasks that are sleeping for a long time. now = self.globalClock.getFrameTime() avgFrameRate = self.globalClock.getAverageFrameRate() if avgFrameRate < .00001: avgFrameDur = 0. else: avgFrameDur = (1. / self.globalClock.getAverageFrameRate()) next = now + avgFrameDur # Now grab a task at random, until we find one that we like. tasks = self.mgr.getTasks() i = random.randrange(tasks.getNumTasks()) task = tasks.getTask(i) while not isinstance(task, PythonTask) or \ task.getWakeTime() > next: tasks.removeTask(i) i = random.randrange(tasks.getNumTasks()) task = tasks.getTask(i) return task def __repr__(self): return str(self.mgr) # In the event we want to do frame time managment, this is the # function to replace or overload. def doYield(self, frameStartTime, nextScheduledTaskTime): pass #def doYieldExample(self, frameStartTime, nextScheduledTaskTime): # minFinTime = frameStartTime + self.MaxEpochSpeed # if nextScheduledTaskTime > 0 and nextScheduledTaskTime < minFinTime: # print(' Adjusting Time') # minFinTime = nextScheduledTaskTime # delta = minFinTime - self.globalClock.getRealTime() # while delta > 0.002: # print ' sleep %s'% (delta) # time.sleep(delta) # delta = minFinTime - self.globalClock.getRealTime() if __debug__: # to catch memory leaks during the tests at the bottom of the file def _startTrackingMemLeaks(self): pass def _stopTrackingMemLeaks(self): pass def _checkMemLeaks(self): pass def _runTests(self): if __debug__: tm = TaskManager() tm.setClock(ClockObject()) tm.setupTaskChain("default", tickClock = True) # check for memory leaks after every test tm._startTrackingMemLeaks() tm._checkMemLeaks() # run-once task l = [] def _testDone(task, l=l): l.append(None) return task.done tm.add(_testDone, 'testDone') tm.step() assert len(l) == 1 tm.step() assert len(l) == 1 _testDone = None tm._checkMemLeaks() # remove by name def _testRemoveByName(task): return task.done tm.add(_testRemoveByName, 'testRemoveByName') assert tm.remove('testRemoveByName') == 1 assert tm.remove('testRemoveByName') == 0 _testRemoveByName = None tm._checkMemLeaks() # duplicate named tasks def _testDupNamedTasks(task): return task.done tm.add(_testDupNamedTasks, 'testDupNamedTasks') tm.add(_testDupNamedTasks, 'testDupNamedTasks') assert tm.remove('testRemoveByName') == 0 _testDupNamedTasks = None tm._checkMemLeaks() # continued task l = [] def _testCont(task, l = l): l.append(None) return task.cont tm.add(_testCont, 'testCont') tm.step() assert len(l) == 1 tm.step() assert len(l) == 2 tm.remove('testCont') _testCont = None tm._checkMemLeaks() # continue until done task l = [] def _testContDone(task, l = l): l.append(None) if len(l) >= 2: return task.done else: return task.cont tm.add(_testContDone, 'testContDone') tm.step() assert len(l) == 1 tm.step() assert len(l) == 2 tm.step() assert len(l) == 2 assert not tm.hasTaskNamed('testContDone') _testContDone = None tm._checkMemLeaks() # hasTaskNamed def _testHasTaskNamed(task): return task.done tm.add(_testHasTaskNamed, 'testHasTaskNamed') assert tm.hasTaskNamed('testHasTaskNamed') tm.step() assert not tm.hasTaskNamed('testHasTaskNamed') _testHasTaskNamed = None tm._checkMemLeaks() # task sort l = [] def _testPri1(task, l = l): l.append(1) return task.cont def _testPri2(task, l = l): l.append(2) return task.cont tm.add(_testPri1, 'testPri1', sort = 1) tm.add(_testPri2, 'testPri2', sort = 2) tm.step() assert len(l) == 2 assert l == [1, 2,] tm.step() assert len(l) == 4 assert l == [1, 2, 1, 2,] tm.remove('testPri1') tm.remove('testPri2') _testPri1 = None _testPri2 = None tm._checkMemLeaks() # task extraArgs l = [] def _testExtraArgs(arg1, arg2, l=l): l.extend([arg1, arg2,]) return done tm.add(_testExtraArgs, 'testExtraArgs', extraArgs=[4,5]) tm.step() assert len(l) == 2 assert l == [4, 5,] _testExtraArgs = None tm._checkMemLeaks() # task appendTask l = [] def _testAppendTask(arg1, arg2, task, l=l): l.extend([arg1, arg2,]) return task.done tm.add(_testAppendTask, '_testAppendTask', extraArgs=[4,5], appendTask=True) tm.step() assert len(l) == 2 assert l == [4, 5,] _testAppendTask = None tm._checkMemLeaks() # task uponDeath l = [] def _uponDeathFunc(task, l=l): l.append(task.name) def _testUponDeath(task): return done tm.add(_testUponDeath, 'testUponDeath', uponDeath=_uponDeathFunc) tm.step() assert len(l) == 1 assert l == ['testUponDeath'] _testUponDeath = None _uponDeathFunc = None tm._checkMemLeaks() # task owner class _TaskOwner: def _addTask(self, task): self.addedTaskName = task.name def _clearTask(self, task): self.clearedTaskName = task.name to = _TaskOwner() l = [] def _testOwner(task): return done tm.add(_testOwner, 'testOwner', owner=to) tm.step() assert getattr(to, 'addedTaskName', None) == 'testOwner' assert getattr(to, 'clearedTaskName', None) == 'testOwner' _testOwner = None del to _TaskOwner = None tm._checkMemLeaks() doLaterTests = [0,] # doLater l = [] def _testDoLater1(task, l=l): l.append(1) def _testDoLater2(task, l=l): l.append(2) def _monitorDoLater(task, tm=tm, l=l, doLaterTests=doLaterTests): if task.time > .03: assert l == [1, 2,] doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLater1, 'testDoLater1') tm.doMethodLater(.02, _testDoLater2, 'testDoLater2') doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLater, 'monitorDoLater', sort=10) _testDoLater1 = None _testDoLater2 = None _monitorDoLater = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # doLater sort l = [] def _testDoLaterPri1(task, l=l): l.append(1) def _testDoLaterPri2(task, l=l): l.append(2) def _monitorDoLaterPri(task, tm=tm, l=l, doLaterTests=doLaterTests): if task.time > .02: assert l == [1, 2,] doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLaterPri1, 'testDoLaterPri1', sort=1) tm.doMethodLater(.01, _testDoLaterPri2, 'testDoLaterPri2', sort=2) doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLaterPri, 'monitorDoLaterPri', sort=10) _testDoLaterPri1 = None _testDoLaterPri2 = None _monitorDoLaterPri = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # doLater extraArgs l = [] def _testDoLaterExtraArgs(arg1, l=l): l.append(arg1) def _monitorDoLaterExtraArgs(task, tm=tm, l=l, doLaterTests=doLaterTests): if task.time > .02: assert l == [3,] doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLaterExtraArgs, 'testDoLaterExtraArgs', extraArgs=[3,]) doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLaterExtraArgs, 'monitorDoLaterExtraArgs', sort=10) _testDoLaterExtraArgs = None _monitorDoLaterExtraArgs = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # doLater appendTask l = [] def _testDoLaterAppendTask(arg1, task, l=l): assert task.name == 'testDoLaterAppendTask' l.append(arg1) def _monitorDoLaterAppendTask(task, tm=tm, l=l, doLaterTests=doLaterTests): if task.time > .02: assert l == [4,] doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLaterAppendTask, 'testDoLaterAppendTask', extraArgs=[4,], appendTask=True) doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLaterAppendTask, 'monitorDoLaterAppendTask', sort=10) _testDoLaterAppendTask = None _monitorDoLaterAppendTask = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # doLater uponDeath l = [] def _testUponDeathFunc(task, l=l): assert task.name == 'testDoLaterUponDeath' l.append(10) def _testDoLaterUponDeath(arg1, l=l): return done def _monitorDoLaterUponDeath(task, tm=tm, l=l, doLaterTests=doLaterTests): if task.time > .02: assert l == [10,] doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLaterUponDeath, 'testDoLaterUponDeath', uponDeath=_testUponDeathFunc) doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLaterUponDeath, 'monitorDoLaterUponDeath', sort=10) _testUponDeathFunc = None _testDoLaterUponDeath = None _monitorDoLaterUponDeath = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # doLater owner class _DoLaterOwner: def _addTask(self, task): self.addedTaskName = task.name def _clearTask(self, task): self.clearedTaskName = task.name doLaterOwner = _DoLaterOwner() l = [] def _testDoLaterOwner(l=l): pass def _monitorDoLaterOwner(task, tm=tm, l=l, doLaterOwner=doLaterOwner, doLaterTests=doLaterTests): if task.time > .02: assert getattr(doLaterOwner, 'addedTaskName', None) == 'testDoLaterOwner' assert getattr(doLaterOwner, 'clearedTaskName', None) == 'testDoLaterOwner' doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLaterOwner, 'testDoLaterOwner', owner=doLaterOwner) doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLaterOwner, 'monitorDoLaterOwner', sort=10) _testDoLaterOwner = None _monitorDoLaterOwner = None del doLaterOwner _DoLaterOwner = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # run the doLater tests while doLaterTests[0] > 0: tm.step() del doLaterTests tm._checkMemLeaks() # getTasks def _testGetTasks(task): return task.cont # No doLaterProcessor in the new world. assert len(tm.getTasks()) == 0 tm.add(_testGetTasks, 'testGetTasks1') assert len(tm.getTasks()) == 1 assert (tm.getTasks()[0].name == 'testGetTasks1' or tm.getTasks()[1].name == 'testGetTasks1') tm.add(_testGetTasks, 'testGetTasks2') tm.add(_testGetTasks, 'testGetTasks3') assert len(tm.getTasks()) == 3 tm.remove('testGetTasks2') assert len(tm.getTasks()) == 2 tm.remove('testGetTasks1') tm.remove('testGetTasks3') assert len(tm.getTasks()) == 0 _testGetTasks = None tm._checkMemLeaks() # getDoLaters def _testGetDoLaters(): pass assert len(tm.getDoLaters()) == 0 tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater1') assert len(tm.getDoLaters()) == 1 assert tm.getDoLaters()[0].name == 'testDoLater1' tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater2') tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater3') assert len(tm.getDoLaters()) == 3 tm.remove('testDoLater2') assert len(tm.getDoLaters()) == 2 tm.remove('testDoLater1') tm.remove('testDoLater3') assert len(tm.getDoLaters()) == 0 _testGetDoLaters = None tm._checkMemLeaks() # duplicate named doLaters removed via taskMgr.remove def _testDupNameDoLaters(): pass # the doLaterProcessor is always running tm.doMethodLater(.1, _testDupNameDoLaters, 'testDupNameDoLater') tm.doMethodLater(.1, _testDupNameDoLaters, 'testDupNameDoLater') assert len(tm.getDoLaters()) == 2 tm.remove('testDupNameDoLater') assert len(tm.getDoLaters()) == 0 _testDupNameDoLaters = None tm._checkMemLeaks() # duplicate named doLaters removed via remove() def _testDupNameDoLatersRemove(): pass # the doLaterProcessor is always running dl1 = tm.doMethodLater(.1, _testDupNameDoLatersRemove, 'testDupNameDoLaterRemove') dl2 = tm.doMethodLater(.1, _testDupNameDoLatersRemove, 'testDupNameDoLaterRemove') assert len(tm.getDoLaters()) == 2 dl2.remove() assert len(tm.getDoLaters()) == 1 dl1.remove() assert len(tm.getDoLaters()) == 0 _testDupNameDoLatersRemove = None # nameDict etc. isn't cleared out right away with task.remove() tm._checkMemLeaks() # getTasksNamed def _testGetTasksNamed(task): return task.cont assert len(tm.getTasksNamed('testGetTasksNamed')) == 0 tm.add(_testGetTasksNamed, 'testGetTasksNamed') assert len(tm.getTasksNamed('testGetTasksNamed')) == 1 assert tm.getTasksNamed('testGetTasksNamed')[0].name == 'testGetTasksNamed' tm.add(_testGetTasksNamed, 'testGetTasksNamed') tm.add(_testGetTasksNamed, 'testGetTasksNamed') assert len(tm.getTasksNamed('testGetTasksNamed')) == 3 tm.remove('testGetTasksNamed') assert len(tm.getTasksNamed('testGetTasksNamed')) == 0 _testGetTasksNamed = None tm._checkMemLeaks() # removeTasksMatching def _testRemoveTasksMatching(task): return task.cont tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching') assert len(tm.getTasksNamed('testRemoveTasksMatching')) == 1 tm.removeTasksMatching('testRemoveTasksMatching') assert len(tm.getTasksNamed('testRemoveTasksMatching')) == 0 tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching1') tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching2') assert len(tm.getTasksNamed('testRemoveTasksMatching1')) == 1 assert len(tm.getTasksNamed('testRemoveTasksMatching2')) == 1 tm.removeTasksMatching('testRemoveTasksMatching*') assert len(tm.getTasksNamed('testRemoveTasksMatching1')) == 0 assert len(tm.getTasksNamed('testRemoveTasksMatching2')) == 0 tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching1a') tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching2a') assert len(tm.getTasksNamed('testRemoveTasksMatching1a')) == 1 assert len(tm.getTasksNamed('testRemoveTasksMatching2a')) == 1 tm.removeTasksMatching('testRemoveTasksMatching?a') assert len(tm.getTasksNamed('testRemoveTasksMatching1a')) == 0 assert len(tm.getTasksNamed('testRemoveTasksMatching2a')) == 0 _testRemoveTasksMatching = None tm._checkMemLeaks() # create Task object and add to mgr l = [] def _testTaskObj(task, l=l): l.append(None) return task.cont t = Task(_testTaskObj) tm.add(t, 'testTaskObj') tm.step() assert len(l) == 1 tm.step() assert len(l) == 2 tm.remove('testTaskObj') tm.step() assert len(l) == 2 _testTaskObj = None tm._checkMemLeaks() # remove Task via task.remove() l = [] def _testTaskObjRemove(task, l=l): l.append(None) return task.cont t = Task(_testTaskObjRemove) tm.add(t, 'testTaskObjRemove') tm.step() assert len(l) == 1 tm.step() assert len(l) == 2 t.remove() tm.step() assert len(l) == 2 del t _testTaskObjRemove = None tm._checkMemLeaks() # this test fails, and it's not clear what the correct behavior should be. # sort passed to Task.__init__ is always overridden by taskMgr.add() # even if no sort is specified, and calling Task.setSort() has no # effect on the taskMgr's behavior. # set/get Task sort #l = [] #def _testTaskObjSort(arg, task, l=l): # l.append(arg) # return task.cont #t1 = Task(_testTaskObjSort, sort=1) #t2 = Task(_testTaskObjSort, sort=2) #tm.add(t1, 'testTaskObjSort1', extraArgs=['a',], appendTask=True) #tm.add(t2, 'testTaskObjSort2', extraArgs=['b',], appendTask=True) #tm.step() #assert len(l) == 2 #assert l == ['a', 'b'] #assert t1.getSort() == 1 #assert t2.getSort() == 2 #t1.setSort(3) #assert t1.getSort() == 3 #tm.step() #assert len(l) == 4 #assert l == ['a', 'b', 'b', 'a',] #t1.remove() #t2.remove() #tm.step() #assert len(l) == 4 #del t1 #del t2 #_testTaskObjSort = None #tm._checkMemLeaks() del l tm.destroy() del tm
def getValue(self): return StateVar.get(self)
class TaskManager(): notify = directNotify.newCategory('TaskManager') extendedExceptions = False MaxEpochSpeed = 1.0 / 30.0 def __init__(self): self.mgr = AsyncTaskManager.getGlobalPtr() self.resumeFunc = None self.globalClock = self.mgr.getClock() self.stepping = False self.running = False self.destroyed = False self.fKeyboardInterrupt = False self.interruptCount = 0 self._frameProfileQueue = Queue() self._profileFrames = None self._frameProfiler = None self._profileTasks = None self._taskProfiler = None self._taskProfileInfo = ScratchPad(taskId=None, profiled=False, session=None) return def finalInit(self): from direct.fsm.StatePush import StateVar self._profileTasks = StateVar(False) self.setProfileTasks( ConfigVariableBool('profile-task-spikes', 0).getValue()) self._profileFrames = StateVar(False) self.setProfileFrames( ConfigVariableBool('profile-frames', 0).getValue()) def destroy(self): self.running = False self.notify.info('TaskManager.destroy()') self.destroyed = True self._frameProfileQueue.clear() self.mgr.cleanup() def setClock(self, clockObject): self.mgr.setClock(clockObject) self.globalClock = clockObject def invokeDefaultHandler(self, signalNumber, stackFrame): print '*** allowing mid-frame keyboard interrupt.' if signal: signal.signal(signal.SIGINT, signal.default_int_handler) raise KeyboardInterrupt def keyboardInterruptHandler(self, signalNumber, stackFrame): self.fKeyboardInterrupt = 1 self.interruptCount += 1 if self.interruptCount == 1: print '* interrupt by keyboard' else: if self.interruptCount == 2: print '** waiting for end of frame before interrupting...' signal.signal(signal.SIGINT, self.invokeDefaultHandler) def getCurrentTask(self): return Thread.getCurrentThread().getCurrentTask() def hasTaskChain(self, chainName): return self.mgr.findTaskChain(chainName) != None def setupTaskChain(self, chainName, numThreads=None, tickClock=None, threadPriority=None, frameBudget=None, frameSync=None, timeslicePriority=None): chain = self.mgr.makeTaskChain(chainName) if numThreads is not None: chain.setNumThreads(numThreads) if tickClock is not None: chain.setTickClock(tickClock) if threadPriority is not None: chain.setThreadPriority(threadPriority) if frameBudget is not None: chain.setFrameBudget(frameBudget) if frameSync is not None: chain.setFrameSync(frameSync) if timeslicePriority is not None: chain.setTimeslicePriority(timeslicePriority) return def hasTaskNamed(self, taskName): return bool(self.mgr.findTask(taskName)) def getTasksNamed(self, taskName): return self.__makeTaskList(self.mgr.findTasks(taskName)) def getTasksMatching(self, taskPattern): return self.__makeTaskList( self.mgr.findTasksMatching(GlobPattern(taskPattern))) def getAllTasks(self): return self.__makeTaskList(self.mgr.getTasks()) def getTasks(self): return self.__makeTaskList(self.mgr.getActiveTasks()) def getDoLaters(self): return self.__makeTaskList(self.mgr.getSleepingTasks()) def __makeTaskList(self, taskCollection): l = [] for i in range(taskCollection.getNumTasks()): l.append(taskCollection.getTask(i)) return l def doMethodLater(self, delayTime, funcOrTask, name, extraArgs=None, sort=None, priority=None, taskChain=None, uponDeath=None, appendTask=False, owner=None): if delayTime < 0: pass task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath) task.setDelay(delayTime) self.mgr.add(task) return task def add(self, funcOrTask, name=None, sort=None, extraArgs=None, priority=None, uponDeath=None, appendTask=False, taskChain=None, owner=None): task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath) self.mgr.add(task) return task def __setupTask(self, funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath): if isinstance(funcOrTask, AsyncTask): task = funcOrTask else: if hasattr(funcOrTask, '__call__'): task = PythonTask(funcOrTask) else: self.notify.error( 'add: Tried to add a task that was not a Task or a func') if hasattr(task, 'setArgs'): if extraArgs is None: extraArgs = [] appendTask = True task.setArgs(extraArgs, appendTask) else: if extraArgs is not None: self.notify.error('Task %s does not accept arguments.' % repr(task)) if name is not None: task.setName(name) if priority is not None and sort is None: task.setSort(priority) else: if priority is not None: task.setPriority(priority) if sort is not None: task.setSort(sort) if taskChain is not None: task.setTaskChain(taskChain) if owner is not None: task.setOwner(owner) if uponDeath is not None: task.setUponDeath(uponDeath) return task def remove(self, taskOrName): if isinstance(taskOrName, types.StringTypes): tasks = self.mgr.findTasks(taskOrName) return self.mgr.remove(tasks) if isinstance(taskOrName, AsyncTask): return self.mgr.remove(taskOrName) if isinstance(taskOrName, types.ListType): for task in taskOrName: self.remove(task) else: self.notify.error('remove takes a string or a Task') def removeTasksMatching(self, taskPattern): tasks = self.mgr.findTasksMatching(GlobPattern(taskPattern)) return self.mgr.remove(tasks) def step(self): self.fKeyboardInterrupt = 0 self.interruptCount = 0 if signal: signal.signal(signal.SIGINT, self.keyboardInterruptHandler) startFrameTime = self.globalClock.getRealTime() self.mgr.poll() nextTaskTime = self.mgr.getNextWakeTime() self.doYield(startFrameTime, nextTaskTime) if signal: signal.signal(signal.SIGINT, signal.default_int_handler) if self.fKeyboardInterrupt: raise KeyboardInterrupt def run(self): t = self.globalClock.getFrameTime() timeDelta = t - self.globalClock.getRealTime() self.globalClock.setRealTime(t) messenger.send('resetClock', [timeDelta]) if self.resumeFunc != None: self.resumeFunc() if self.stepping: self.step() else: self.running = True while self.running: try: if len(self._frameProfileQueue): numFrames, session, callback = self._frameProfileQueue.pop( ) def _profileFunc(numFrames=numFrames): self._doProfiledFrames(numFrames) session.setFunc(_profileFunc) session.run() _profileFunc = None if callback: callback() session.release() else: self.step() except KeyboardInterrupt: self.stop() except SystemExit: self.stop() raise except IOError as ioError: code, message = self._unpackIOError(ioError) if code == 4: self.stop() else: raise except Exception as e: if self.extendedExceptions: self.stop() print_exc_plus() else: if ExceptionVarDump.wantStackDumpLog and ExceptionVarDump.dumpOnExceptionInit: ExceptionVarDump._varDump__print(e) raise except: if self.extendedExceptions: self.stop() print_exc_plus() else: raise self.mgr.stopThreads() return def _unpackIOError(self, ioError): try: code, message = ioError except: code = 0 message = ioError return (code, message) def stop(self): self.running = False def __tryReplaceTaskMethod(self, task, oldMethod, newFunction): if not isinstance(task, PythonTask): return 0 method = task.getFunction() if type(method) == types.MethodType: function = method.im_func else: function = method if function == oldMethod: newMethod = types.MethodType(newFunction, method.im_self, method.im_class) task.setFunction(newMethod) return 1 return 0 def replaceMethod(self, oldMethod, newFunction): numFound = 0 for task in self.getAllTasks(): numFound += self.__tryReplaceTaskMethod(task, oldMethod, newFunction) return numFound def popupControls(self): from direct.tkpanels import TaskManagerPanel return TaskManagerPanel.TaskManagerPanel(self) def getProfileSession(self, name=None): if name is None: name = 'taskMgrFrameProfile' from direct.showbase.ProfileSession import ProfileSession return ProfileSession(name) def profileFrames(self, num=None, session=None, callback=None): if num is None: num = 1 if session is None: session = self.getProfileSession() session.acquire() self._frameProfileQueue.push((num, session, callback)) return def _doProfiledFrames(self, numFrames): for i in xrange(numFrames): result = self.step() return result def getProfileFrames(self): return self._profileFrames.get() def getProfileFramesSV(self): return self._profileFrames def setProfileFrames(self, profileFrames): self._profileFrames.set(profileFrames) if not self._frameProfiler and profileFrames: from direct.task.FrameProfiler import FrameProfiler self._frameProfiler = FrameProfiler() def getProfileTasks(self): return self._profileTasks.get() def getProfileTasksSV(self): return self._profileTasks def setProfileTasks(self, profileTasks): self._profileTasks.set(profileTasks) if not self._taskProfiler and profileTasks: from direct.task.TaskProfiler import TaskProfiler self._taskProfiler = TaskProfiler() def logTaskProfiles(self, name=None): if self._taskProfiler: self._taskProfiler.logProfiles(name) def flushTaskProfiles(self, name=None): if self._taskProfiler: self._taskProfiler.flush(name) def _setProfileTask(self, task): if self._taskProfileInfo.session: self._taskProfileInfo.session.release() self._taskProfileInfo.session = None self._taskProfileInfo = ScratchPad(taskFunc=task.getFunction(), taskArgs=task.getArgs(), task=task, profiled=False, session=None) task.setFunction(self._profileTask) task.setArgs([self._taskProfileInfo], True) return def _profileTask(self, profileInfo, task): appendTask = False taskArgs = profileInfo.taskArgs if taskArgs and taskArgs[-1] == task: appendTask = True taskArgs = taskArgs[:-1] task.setArgs(taskArgs, appendTask) task.setFunction(profileInfo.taskFunc) from direct.showbase.ProfileSession import ProfileSession profileSession = ProfileSession( 'profiled-task-%s' % task.getName(), Functor(profileInfo.taskFunc, *profileInfo.taskArgs)) ret = profileSession.run() profileInfo.session = profileSession profileInfo.profiled = True return ret def _hasProfiledDesignatedTask(self): return self._taskProfileInfo.profiled def _getLastTaskProfileSession(self): return self._taskProfileInfo.session def _getRandomTask(self): now = globalClock.getFrameTime() avgFrameRate = globalClock.getAverageFrameRate() if avgFrameRate < 1e-05: avgFrameDur = 0.0 else: avgFrameDur = 1.0 / globalClock.getAverageFrameRate() next = now + avgFrameDur tasks = self.mgr.getTasks() i = random.randrange(tasks.getNumTasks()) task = tasks.getTask(i) while not isinstance(task, PythonTask) or task.getWakeTime() > next: tasks.removeTask(i) i = random.randrange(tasks.getNumTasks()) task = tasks.getTask(i) return task def __repr__(self): return str(self.mgr) def doYield(self, frameStartTime, nextScheduledTaskTime): pass def _runTests(self): pass
class TaskManager: notify = directNotify.newCategory("TaskManager") extendedExceptions = False MaxEpochSpeed = 1.0/30.0 def __init__(self): self.mgr = AsyncTaskManager.getGlobalPtr() self.resumeFunc = None self.globalClock = self.mgr.getClock() self.stepping = False self.running = False self.destroyed = False self.fKeyboardInterrupt = False self.interruptCount = 0 self._frameProfileQueue = Queue() # this will be set when it's safe to import StateVar self._profileFrames = None self._frameProfiler = None self._profileTasks = None self._taskProfiler = None self._taskProfileInfo = ScratchPad( taskId = None, profiled = False, session = None, ) def finalInit(self): # This function should be called once during startup, after # most things are imported. from direct.fsm.StatePush import StateVar self._profileTasks = StateVar(False) self.setProfileTasks(ConfigVariableBool('profile-task-spikes', 0).getValue()) self._profileFrames = StateVar(False) self.setProfileFrames(ConfigVariableBool('profile-frames', 0).getValue()) def destroy(self): # This should be safe to call multiple times. self.running = False self.notify.info("TaskManager.destroy()") self.destroyed = True self._frameProfileQueue.clear() self.mgr.cleanup() def setClock(self, clockObject): self.mgr.setClock(clockObject) self.globalClock = clockObject clock = property(lambda self: self.mgr.getClock(), setClock) def invokeDefaultHandler(self, signalNumber, stackFrame): print('*** allowing mid-frame keyboard interrupt.') # Restore default interrupt handler if signal: signal.signal(signal.SIGINT, signal.default_int_handler) # and invoke it raise KeyboardInterrupt def keyboardInterruptHandler(self, signalNumber, stackFrame): self.fKeyboardInterrupt = 1 self.interruptCount += 1 if self.interruptCount == 1: print('* interrupt by keyboard') elif self.interruptCount == 2: print('** waiting for end of frame before interrupting...') # The user must really want to interrupt this process # Next time around invoke the default handler signal.signal(signal.SIGINT, self.invokeDefaultHandler) def getCurrentTask(self): """ Returns the task currently executing on this thread, or None if this is being called outside of the task manager. """ return Thread.getCurrentThread().getCurrentTask() def hasTaskChain(self, chainName): """ Returns true if a task chain with the indicated name has already been defined, or false otherwise. Note that setupTaskChain() will implicitly define a task chain if it has not already been defined, or modify an existing one if it has, so in most cases there is no need to check this method first. """ return (self.mgr.findTaskChain(chainName) != None) def setupTaskChain(self, chainName, numThreads = None, tickClock = None, threadPriority = None, frameBudget = None, frameSync = None, timeslicePriority = None): """Defines a new task chain. Each task chain executes tasks potentially in parallel with all of the other task chains (if numThreads is more than zero). When a new task is created, it may be associated with any of the task chains, by name (or you can move a task to another task chain with task.setTaskChain()). You can have any number of task chains, but each must have a unique name. numThreads is the number of threads to allocate for this task chain. If it is 1 or more, then the tasks on this task chain will execute in parallel with the tasks on other task chains. If it is greater than 1, then the tasks on this task chain may execute in parallel with themselves (within tasks of the same sort value). If tickClock is True, then this task chain will be responsible for ticking the global clock each frame (and thereby incrementing the frame counter). There should be just one task chain responsible for ticking the clock, and usually it is the default, unnamed task chain. threadPriority specifies the priority level to assign to threads on this task chain. It may be one of TPLow, TPNormal, TPHigh, or TPUrgent. This is passed to the underlying threading system to control the way the threads are scheduled. frameBudget is the maximum amount of time (in seconds) to allow this task chain to run per frame. Set it to -1 to mean no limit (the default). It's not directly related to threadPriority. frameSync is true to force the task chain to sync to the clock. When this flag is false, the default, the task chain will finish all of its tasks and then immediately start from the first task again, regardless of the clock frame. When it is true, the task chain will finish all of its tasks and then wait for the clock to tick to the next frame before resuming the first task. This only makes sense for threaded tasks chains; non-threaded task chains are automatically synchronous. timeslicePriority is False in the default mode, in which each task runs exactly once each frame, round-robin style, regardless of the task's priority value; or True to change the meaning of priority so that certain tasks are run less often, in proportion to their time used and to their priority value. See AsyncTaskManager.setTimeslicePriority() for more. """ chain = self.mgr.makeTaskChain(chainName) if numThreads is not None: chain.setNumThreads(numThreads) if tickClock is not None: chain.setTickClock(tickClock) if threadPriority is not None: chain.setThreadPriority(threadPriority) if frameBudget is not None: chain.setFrameBudget(frameBudget) if frameSync is not None: chain.setFrameSync(frameSync) if timeslicePriority is not None: chain.setTimeslicePriority(timeslicePriority) def hasTaskNamed(self, taskName): """Returns true if there is at least one task, active or sleeping, with the indicated name. """ return bool(self.mgr.findTask(taskName)) def getTasksNamed(self, taskName): """Returns a list of all tasks, active or sleeping, with the indicated name. """ return self.__makeTaskList(self.mgr.findTasks(taskName)) def getTasksMatching(self, taskPattern): """Returns a list of all tasks, active or sleeping, with a name that matches the pattern, which can include standard shell globbing characters like *, ?, and []. """ return self.__makeTaskList(self.mgr.findTasksMatching(GlobPattern(taskPattern))) def getAllTasks(self): """Returns list of all tasks, active and sleeping, in arbitrary order. """ return self.__makeTaskList(self.mgr.getTasks()) def getTasks(self): """Returns list of all active tasks in arbitrary order. """ return self.__makeTaskList(self.mgr.getActiveTasks()) def getDoLaters(self): """Returns list of all sleeping tasks in arbitrary order. """ return self.__makeTaskList(self.mgr.getSleepingTasks()) def __makeTaskList(self, taskCollection): l = [] for i in range(taskCollection.getNumTasks()): l.append(taskCollection.getTask(i)) return l def doMethodLater(self, delayTime, funcOrTask, name, extraArgs = None, sort = None, priority = None, taskChain = None, uponDeath = None, appendTask = False, owner = None): """Adds a task to be performed at some time in the future. This is identical to add(), except that the specified delayTime is applied to the Task object first, which means that the task will not begin executing until at least the indicated delayTime (in seconds) has elapsed. After delayTime has elapsed, the task will become active, and will run in the soonest possible frame thereafter. If you wish to specify a task that will run in the next frame, use a delayTime of 0. """ if delayTime < 0: assert self.notify.warning('doMethodLater: added task: %s with negative delay: %s' % (name, delayTime)) task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath) task.setDelay(delayTime) self.mgr.add(task) return task do_method_later = doMethodLater def add(self, funcOrTask, name = None, sort = None, extraArgs = None, priority = None, uponDeath = None, appendTask = False, taskChain = None, owner = None): """ Add a new task to the taskMgr. The task will begin executing immediately, or next frame if its sort value has already passed this frame. The parameters are: funcOrTask - either an existing Task object (not already added to the task manager), or a callable function object. If this is a function, a new Task object will be created and returned. name - the name to assign to the Task. Required, unless you are passing in a Task object that already has a name. extraArgs - the list of arguments to pass to the task function. If this is omitted, the list is just the task object itself. appendTask - a boolean flag. If this is true, then the task object itself will be appended to the end of the extraArgs list before calling the function. sort - the sort value to assign the task. The default sort is 0. Within a particular task chain, it is guaranteed that the tasks with a lower sort value will all run before tasks with a higher sort value run. priority - the priority at which to run the task. The default priority is 0. Higher priority tasks are run sooner, and/or more often. For historical purposes, if you specify a priority without also specifying a sort, the priority value is understood to actually be a sort value. (Previously, there was no priority value, only a sort value, and it was called "priority".) uponDeath - a function to call when the task terminates, either because it has run to completion, or because it has been explicitly removed. taskChain - the name of the task chain to assign the task to. owner - an optional Python object that is declared as the "owner" of this task for maintenance purposes. The owner must have two methods: owner._addTask(self, task), which is called when the task begins, and owner._clearTask(self, task), which is called when the task terminates. This is all the owner means. The return value of add() is the new Task object that has been added, or the original Task object that was passed in. """ task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath) self.mgr.add(task) return task def __setupTask(self, funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath): if isinstance(funcOrTask, AsyncTask): task = funcOrTask elif hasattr(funcOrTask, '__call__'): task = PythonTask(funcOrTask) else: self.notify.error( 'add: Tried to add a task that was not a Task or a func') if hasattr(task, 'setArgs'): # It will only accept arguments if it's a PythonTask. if extraArgs is None: extraArgs = [] appendTask = True task.setArgs(extraArgs, appendTask) elif extraArgs is not None: self.notify.error( 'Task %s does not accept arguments.' % (repr(task))) if name is not None: task.setName(name) assert task.hasName() # For historical reasons, if priority is specified but not # sort, it really means sort. if priority is not None and sort is None: task.setSort(priority) else: if priority is not None: task.setPriority(priority) if sort is not None: task.setSort(sort) if taskChain is not None: task.setTaskChain(taskChain) if owner is not None: task.setOwner(owner) if uponDeath is not None: task.setUponDeath(uponDeath) return task def remove(self, taskOrName): """Removes a task from the task manager. The task is stopped, almost as if it had returned task.done. (But if the task is currently executing, it will finish out its current frame before being removed.) You may specify either an explicit Task object, or the name of a task. If you specify a name, all tasks with the indicated name are removed. Returns the number of tasks removed. """ if isinstance(taskOrName, AsyncTask): return self.mgr.remove(taskOrName) elif isinstance(taskOrName, list): for task in taskOrName: self.remove(task) else: tasks = self.mgr.findTasks(taskOrName) return self.mgr.remove(tasks) def removeTasksMatching(self, taskPattern): """Removes all tasks whose names match the pattern, which can include standard shell globbing characters like *, ?, and []. See also remove(). Returns the number of tasks removed. """ tasks = self.mgr.findTasksMatching(GlobPattern(taskPattern)) return self.mgr.remove(tasks) def step(self): """Invokes the task manager for one frame, and then returns. Normally, this executes each task exactly once, though task chains that are in sub-threads or that have frame budgets might execute their tasks differently. """ # Replace keyboard interrupt handler during task list processing # so we catch the keyboard interrupt but don't handle it until # after task list processing is complete. self.fKeyboardInterrupt = 0 self.interruptCount = 0 if signal: signal.signal(signal.SIGINT, self.keyboardInterruptHandler) startFrameTime = self.globalClock.getRealTime() self.mgr.poll() # This is the spot for an internal yield function nextTaskTime = self.mgr.getNextWakeTime() self.doYield(startFrameTime, nextTaskTime) # Restore default interrupt handler if signal: signal.signal(signal.SIGINT, signal.default_int_handler) if self.fKeyboardInterrupt: raise KeyboardInterrupt def run(self): """Starts the task manager running. Does not return until an exception is encountered (including KeyboardInterrupt). """ if PandaSystem.getPlatform() == 'emscripten': return # Set the clock to have last frame's time in case we were # Paused at the prompt for a long time t = self.globalClock.getFrameTime() timeDelta = t - self.globalClock.getRealTime() self.globalClock.setRealTime(t) messenger.send("resetClock", [timeDelta]) if self.resumeFunc != None: self.resumeFunc() if self.stepping: self.step() else: self.running = True while self.running: try: if len(self._frameProfileQueue): numFrames, session, callback = self._frameProfileQueue.pop() def _profileFunc(numFrames=numFrames): self._doProfiledFrames(numFrames) session.setFunc(_profileFunc) session.run() _profileFunc = None if callback: callback() session.release() else: self.step() except KeyboardInterrupt: self.stop() except SystemExit: self.stop() raise except IOError as ioError: code, message = self._unpackIOError(ioError) # Since upgrading to Python 2.4.1, pausing the execution # often gives this IOError during the sleep function: # IOError: [Errno 4] Interrupted function call # So, let's just handle that specific exception and stop. # All other IOErrors should still get raised. # Only problem: legit IOError 4s will be obfuscated. if code == 4: self.stop() else: raise except Exception as e: if self.extendedExceptions: self.stop() print_exc_plus() else: if (ExceptionVarDump.wantStackDumpLog and ExceptionVarDump.dumpOnExceptionInit): ExceptionVarDump._varDump__print(e) raise except: if self.extendedExceptions: self.stop() print_exc_plus() else: raise self.mgr.stopThreads() def _unpackIOError(self, ioError): # IOError unpack from http://www.python.org/doc/essays/stdexceptions/ # this needs to be in its own method, exceptions that occur inside # a nested try block are not caught by the inner try block's except try: (code, message) = ioError except: code = 0 message = ioError return code, message def stop(self): # Set a flag so we will stop before beginning next frame self.running = False def __tryReplaceTaskMethod(self, task, oldMethod, newFunction): if not isinstance(task, PythonTask): return 0 method = task.getFunction() if (type(method) == types.MethodType): function = method.__func__ else: function = method if (function == oldMethod): newMethod = types.MethodType(newFunction, method.__self__, method.__self__.__class__) task.setFunction(newMethod) # Found a match return 1 return 0 def replaceMethod(self, oldMethod, newFunction): numFound = 0 for task in self.getAllTasks(): numFound += self.__tryReplaceTaskMethod(task, oldMethod, newFunction) return numFound def popupControls(self): # Don't use a regular import, to prevent ModuleFinder from picking # it up as a dependency when building a .p3d package. TaskManagerPanel = importlib.import_module('direct.tkpanels.TaskManagerPanel') return TaskManagerPanel.TaskManagerPanel(self) def getProfileSession(self, name=None): # call to get a profile session that you can modify before passing to profileFrames() if name is None: name = 'taskMgrFrameProfile' # Defer this import until we need it: some Python # distributions don't provide the profile and pstats modules. PS = importlib.import_module('direct.showbase.ProfileSession') return PS.ProfileSession(name) def profileFrames(self, num=None, session=None, callback=None): if num is None: num = 1 if session is None: session = self.getProfileSession() # make sure the profile session doesn't get destroyed before we're done with it session.acquire() self._frameProfileQueue.push((num, session, callback)) def _doProfiledFrames(self, numFrames): for i in range(numFrames): result = self.step() return result def getProfileFrames(self): return self._profileFrames.get() def getProfileFramesSV(self): return self._profileFrames def setProfileFrames(self, profileFrames): self._profileFrames.set(profileFrames) if (not self._frameProfiler) and profileFrames: # import here due to import dependencies FP = importlib.import_module('direct.task.FrameProfiler') self._frameProfiler = FP.FrameProfiler() def getProfileTasks(self): return self._profileTasks.get() def getProfileTasksSV(self): return self._profileTasks def setProfileTasks(self, profileTasks): self._profileTasks.set(profileTasks) if (not self._taskProfiler) and profileTasks: # import here due to import dependencies TP = importlib.import_module('direct.task.TaskProfiler') self._taskProfiler = TP.TaskProfiler() def logTaskProfiles(self, name=None): if self._taskProfiler: self._taskProfiler.logProfiles(name) def flushTaskProfiles(self, name=None): if self._taskProfiler: self._taskProfiler.flush(name) def _setProfileTask(self, task): if self._taskProfileInfo.session: self._taskProfileInfo.session.release() self._taskProfileInfo.session = None self._taskProfileInfo = ScratchPad( taskFunc = task.getFunction(), taskArgs = task.getArgs(), task = task, profiled = False, session = None, ) # Temporarily replace the task's own function with our # _profileTask method. task.setFunction(self._profileTask) task.setArgs([self._taskProfileInfo], True) def _profileTask(self, profileInfo, task): # This is called instead of the task function when we have # decided to profile a task. assert profileInfo.task == task # don't profile the same task twice in a row assert not profileInfo.profiled # Restore the task's proper function for next time. appendTask = False taskArgs = profileInfo.taskArgs if taskArgs and taskArgs[-1] == task: appendTask = True taskArgs = taskArgs[:-1] task.setArgs(taskArgs, appendTask) task.setFunction(profileInfo.taskFunc) # Defer this import until we need it: some Python # distributions don't provide the profile and pstats modules. PS = importlib.import_module('direct.showbase.ProfileSession') profileSession = PS.ProfileSession('profiled-task-%s' % task.getName(), Functor(profileInfo.taskFunc, *profileInfo.taskArgs)) ret = profileSession.run() # set these values *after* profiling in case we're profiling the TaskProfiler profileInfo.session = profileSession profileInfo.profiled = True return ret def _hasProfiledDesignatedTask(self): # have we run a profile of the designated task yet? return self._taskProfileInfo.profiled def _getLastTaskProfileSession(self): return self._taskProfileInfo.session def _getRandomTask(self): # Figure out when the next frame is likely to expire, so we # won't grab any tasks that are sleeping for a long time. now = self.globalClock.getFrameTime() avgFrameRate = self.globalClock.getAverageFrameRate() if avgFrameRate < .00001: avgFrameDur = 0. else: avgFrameDur = (1. / self.globalClock.getAverageFrameRate()) next = now + avgFrameDur # Now grab a task at random, until we find one that we like. tasks = self.mgr.getTasks() i = random.randrange(tasks.getNumTasks()) task = tasks.getTask(i) while not isinstance(task, PythonTask) or \ task.getWakeTime() > next: tasks.removeTask(i) i = random.randrange(tasks.getNumTasks()) task = tasks.getTask(i) return task def __repr__(self): return str(self.mgr) # In the event we want to do frame time managment, this is the # function to replace or overload. def doYield(self, frameStartTime, nextScheduledTaskTime): pass """ def doYieldExample(self, frameStartTime, nextScheduledTaskTime): minFinTime = frameStartTime + self.MaxEpochSpeed if nextScheduledTaskTime > 0 and nextScheduledTaskTime < minFinTime: print ' Adjusting Time' minFinTime = nextScheduledTaskTime delta = minFinTime - self.globalClock.getRealTime() while(delta > 0.002): print ' sleep %s'% (delta) time.sleep(delta) delta = minFinTime - self.globalClock.getRealTime() """ if __debug__: # to catch memory leaks during the tests at the bottom of the file def _startTrackingMemLeaks(self): pass def _stopTrackingMemLeaks(self): pass def _checkMemLeaks(self): pass def _runTests(self): if __debug__: tm = TaskManager() tm.setClock(ClockObject()) tm.setupTaskChain("default", tickClock = True) # check for memory leaks after every test tm._startTrackingMemLeaks() tm._checkMemLeaks() # run-once task l = [] def _testDone(task, l=l): l.append(None) return task.done tm.add(_testDone, 'testDone') tm.step() assert len(l) == 1 tm.step() assert len(l) == 1 _testDone = None tm._checkMemLeaks() # remove by name def _testRemoveByName(task): return task.done tm.add(_testRemoveByName, 'testRemoveByName') assert tm.remove('testRemoveByName') == 1 assert tm.remove('testRemoveByName') == 0 _testRemoveByName = None tm._checkMemLeaks() # duplicate named tasks def _testDupNamedTasks(task): return task.done tm.add(_testDupNamedTasks, 'testDupNamedTasks') tm.add(_testDupNamedTasks, 'testDupNamedTasks') assert tm.remove('testRemoveByName') == 0 _testDupNamedTasks = None tm._checkMemLeaks() # continued task l = [] def _testCont(task, l = l): l.append(None) return task.cont tm.add(_testCont, 'testCont') tm.step() assert len(l) == 1 tm.step() assert len(l) == 2 tm.remove('testCont') _testCont = None tm._checkMemLeaks() # continue until done task l = [] def _testContDone(task, l = l): l.append(None) if len(l) >= 2: return task.done else: return task.cont tm.add(_testContDone, 'testContDone') tm.step() assert len(l) == 1 tm.step() assert len(l) == 2 tm.step() assert len(l) == 2 assert not tm.hasTaskNamed('testContDone') _testContDone = None tm._checkMemLeaks() # hasTaskNamed def _testHasTaskNamed(task): return task.done tm.add(_testHasTaskNamed, 'testHasTaskNamed') assert tm.hasTaskNamed('testHasTaskNamed') tm.step() assert not tm.hasTaskNamed('testHasTaskNamed') _testHasTaskNamed = None tm._checkMemLeaks() # task sort l = [] def _testPri1(task, l = l): l.append(1) return task.cont def _testPri2(task, l = l): l.append(2) return task.cont tm.add(_testPri1, 'testPri1', sort = 1) tm.add(_testPri2, 'testPri2', sort = 2) tm.step() assert len(l) == 2 assert l == [1, 2,] tm.step() assert len(l) == 4 assert l == [1, 2, 1, 2,] tm.remove('testPri1') tm.remove('testPri2') _testPri1 = None _testPri2 = None tm._checkMemLeaks() # task extraArgs l = [] def _testExtraArgs(arg1, arg2, l=l): l.extend([arg1, arg2,]) return done tm.add(_testExtraArgs, 'testExtraArgs', extraArgs=[4,5]) tm.step() assert len(l) == 2 assert l == [4, 5,] _testExtraArgs = None tm._checkMemLeaks() # task appendTask l = [] def _testAppendTask(arg1, arg2, task, l=l): l.extend([arg1, arg2,]) return task.done tm.add(_testAppendTask, '_testAppendTask', extraArgs=[4,5], appendTask=True) tm.step() assert len(l) == 2 assert l == [4, 5,] _testAppendTask = None tm._checkMemLeaks() # task uponDeath l = [] def _uponDeathFunc(task, l=l): l.append(task.name) def _testUponDeath(task): return done tm.add(_testUponDeath, 'testUponDeath', uponDeath=_uponDeathFunc) tm.step() assert len(l) == 1 assert l == ['testUponDeath'] _testUponDeath = None _uponDeathFunc = None tm._checkMemLeaks() # task owner class _TaskOwner: def _addTask(self, task): self.addedTaskName = task.name def _clearTask(self, task): self.clearedTaskName = task.name to = _TaskOwner() l = [] def _testOwner(task): return done tm.add(_testOwner, 'testOwner', owner=to) tm.step() assert getattr(to, 'addedTaskName', None) == 'testOwner' assert getattr(to, 'clearedTaskName', None) == 'testOwner' _testOwner = None del to _TaskOwner = None tm._checkMemLeaks() doLaterTests = [0,] # doLater l = [] def _testDoLater1(task, l=l): l.append(1) def _testDoLater2(task, l=l): l.append(2) def _monitorDoLater(task, tm=tm, l=l, doLaterTests=doLaterTests): if task.time > .03: assert l == [1, 2,] doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLater1, 'testDoLater1') tm.doMethodLater(.02, _testDoLater2, 'testDoLater2') doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLater, 'monitorDoLater', sort=10) _testDoLater1 = None _testDoLater2 = None _monitorDoLater = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # doLater sort l = [] def _testDoLaterPri1(task, l=l): l.append(1) def _testDoLaterPri2(task, l=l): l.append(2) def _monitorDoLaterPri(task, tm=tm, l=l, doLaterTests=doLaterTests): if task.time > .02: assert l == [1, 2,] doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLaterPri1, 'testDoLaterPri1', sort=1) tm.doMethodLater(.01, _testDoLaterPri2, 'testDoLaterPri2', sort=2) doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLaterPri, 'monitorDoLaterPri', sort=10) _testDoLaterPri1 = None _testDoLaterPri2 = None _monitorDoLaterPri = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # doLater extraArgs l = [] def _testDoLaterExtraArgs(arg1, l=l): l.append(arg1) def _monitorDoLaterExtraArgs(task, tm=tm, l=l, doLaterTests=doLaterTests): if task.time > .02: assert l == [3,] doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLaterExtraArgs, 'testDoLaterExtraArgs', extraArgs=[3,]) doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLaterExtraArgs, 'monitorDoLaterExtraArgs', sort=10) _testDoLaterExtraArgs = None _monitorDoLaterExtraArgs = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # doLater appendTask l = [] def _testDoLaterAppendTask(arg1, task, l=l): assert task.name == 'testDoLaterAppendTask' l.append(arg1) def _monitorDoLaterAppendTask(task, tm=tm, l=l, doLaterTests=doLaterTests): if task.time > .02: assert l == [4,] doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLaterAppendTask, 'testDoLaterAppendTask', extraArgs=[4,], appendTask=True) doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLaterAppendTask, 'monitorDoLaterAppendTask', sort=10) _testDoLaterAppendTask = None _monitorDoLaterAppendTask = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # doLater uponDeath l = [] def _testUponDeathFunc(task, l=l): assert task.name == 'testDoLaterUponDeath' l.append(10) def _testDoLaterUponDeath(arg1, l=l): return done def _monitorDoLaterUponDeath(task, tm=tm, l=l, doLaterTests=doLaterTests): if task.time > .02: assert l == [10,] doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLaterUponDeath, 'testDoLaterUponDeath', uponDeath=_testUponDeathFunc) doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLaterUponDeath, 'monitorDoLaterUponDeath', sort=10) _testUponDeathFunc = None _testDoLaterUponDeath = None _monitorDoLaterUponDeath = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # doLater owner class _DoLaterOwner: def _addTask(self, task): self.addedTaskName = task.name def _clearTask(self, task): self.clearedTaskName = task.name doLaterOwner = _DoLaterOwner() l = [] def _testDoLaterOwner(l=l): pass def _monitorDoLaterOwner(task, tm=tm, l=l, doLaterOwner=doLaterOwner, doLaterTests=doLaterTests): if task.time > .02: assert getattr(doLaterOwner, 'addedTaskName', None) == 'testDoLaterOwner' assert getattr(doLaterOwner, 'clearedTaskName', None) == 'testDoLaterOwner' doLaterTests[0] -= 1 return task.done return task.cont tm.doMethodLater(.01, _testDoLaterOwner, 'testDoLaterOwner', owner=doLaterOwner) doLaterTests[0] += 1 # make sure we run this task after the doLaters if they all occur on the same frame tm.add(_monitorDoLaterOwner, 'monitorDoLaterOwner', sort=10) _testDoLaterOwner = None _monitorDoLaterOwner = None del doLaterOwner _DoLaterOwner = None # don't check until all the doLaters are finished #tm._checkMemLeaks() # run the doLater tests while doLaterTests[0] > 0: tm.step() del doLaterTests tm._checkMemLeaks() # getTasks def _testGetTasks(task): return task.cont # No doLaterProcessor in the new world. assert len(tm.getTasks()) == 0 tm.add(_testGetTasks, 'testGetTasks1') assert len(tm.getTasks()) == 1 assert (tm.getTasks()[0].name == 'testGetTasks1' or tm.getTasks()[1].name == 'testGetTasks1') tm.add(_testGetTasks, 'testGetTasks2') tm.add(_testGetTasks, 'testGetTasks3') assert len(tm.getTasks()) == 3 tm.remove('testGetTasks2') assert len(tm.getTasks()) == 2 tm.remove('testGetTasks1') tm.remove('testGetTasks3') assert len(tm.getTasks()) == 0 _testGetTasks = None tm._checkMemLeaks() # getDoLaters def _testGetDoLaters(): pass assert len(tm.getDoLaters()) == 0 tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater1') assert len(tm.getDoLaters()) == 1 assert tm.getDoLaters()[0].name == 'testDoLater1' tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater2') tm.doMethodLater(.1, _testGetDoLaters, 'testDoLater3') assert len(tm.getDoLaters()) == 3 tm.remove('testDoLater2') assert len(tm.getDoLaters()) == 2 tm.remove('testDoLater1') tm.remove('testDoLater3') assert len(tm.getDoLaters()) == 0 _testGetDoLaters = None tm._checkMemLeaks() # duplicate named doLaters removed via taskMgr.remove def _testDupNameDoLaters(): pass # the doLaterProcessor is always running tm.doMethodLater(.1, _testDupNameDoLaters, 'testDupNameDoLater') tm.doMethodLater(.1, _testDupNameDoLaters, 'testDupNameDoLater') assert len(tm.getDoLaters()) == 2 tm.remove('testDupNameDoLater') assert len(tm.getDoLaters()) == 0 _testDupNameDoLaters = None tm._checkMemLeaks() # duplicate named doLaters removed via remove() def _testDupNameDoLatersRemove(): pass # the doLaterProcessor is always running dl1 = tm.doMethodLater(.1, _testDupNameDoLatersRemove, 'testDupNameDoLaterRemove') dl2 = tm.doMethodLater(.1, _testDupNameDoLatersRemove, 'testDupNameDoLaterRemove') assert len(tm.getDoLaters()) == 2 dl2.remove() assert len(tm.getDoLaters()) == 1 dl1.remove() assert len(tm.getDoLaters()) == 0 _testDupNameDoLatersRemove = None # nameDict etc. isn't cleared out right away with task.remove() tm._checkMemLeaks() # getTasksNamed def _testGetTasksNamed(task): return task.cont assert len(tm.getTasksNamed('testGetTasksNamed')) == 0 tm.add(_testGetTasksNamed, 'testGetTasksNamed') assert len(tm.getTasksNamed('testGetTasksNamed')) == 1 assert tm.getTasksNamed('testGetTasksNamed')[0].name == 'testGetTasksNamed' tm.add(_testGetTasksNamed, 'testGetTasksNamed') tm.add(_testGetTasksNamed, 'testGetTasksNamed') assert len(tm.getTasksNamed('testGetTasksNamed')) == 3 tm.remove('testGetTasksNamed') assert len(tm.getTasksNamed('testGetTasksNamed')) == 0 _testGetTasksNamed = None tm._checkMemLeaks() # removeTasksMatching def _testRemoveTasksMatching(task): return task.cont tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching') assert len(tm.getTasksNamed('testRemoveTasksMatching')) == 1 tm.removeTasksMatching('testRemoveTasksMatching') assert len(tm.getTasksNamed('testRemoveTasksMatching')) == 0 tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching1') tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching2') assert len(tm.getTasksNamed('testRemoveTasksMatching1')) == 1 assert len(tm.getTasksNamed('testRemoveTasksMatching2')) == 1 tm.removeTasksMatching('testRemoveTasksMatching*') assert len(tm.getTasksNamed('testRemoveTasksMatching1')) == 0 assert len(tm.getTasksNamed('testRemoveTasksMatching2')) == 0 tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching1a') tm.add(_testRemoveTasksMatching, 'testRemoveTasksMatching2a') assert len(tm.getTasksNamed('testRemoveTasksMatching1a')) == 1 assert len(tm.getTasksNamed('testRemoveTasksMatching2a')) == 1 tm.removeTasksMatching('testRemoveTasksMatching?a') assert len(tm.getTasksNamed('testRemoveTasksMatching1a')) == 0 assert len(tm.getTasksNamed('testRemoveTasksMatching2a')) == 0 _testRemoveTasksMatching = None tm._checkMemLeaks() # create Task object and add to mgr l = [] def _testTaskObj(task, l=l): l.append(None) return task.cont t = Task(_testTaskObj) tm.add(t, 'testTaskObj') tm.step() assert len(l) == 1 tm.step() assert len(l) == 2 tm.remove('testTaskObj') tm.step() assert len(l) == 2 _testTaskObj = None tm._checkMemLeaks() # remove Task via task.remove() l = [] def _testTaskObjRemove(task, l=l): l.append(None) return task.cont t = Task(_testTaskObjRemove) tm.add(t, 'testTaskObjRemove') tm.step() assert len(l) == 1 tm.step() assert len(l) == 2 t.remove() tm.step() assert len(l) == 2 del t _testTaskObjRemove = None tm._checkMemLeaks() """ # this test fails, and it's not clear what the correct behavior should be. # sort passed to Task.__init__ is always overridden by taskMgr.add() # even if no sort is specified, and calling Task.setSort() has no # effect on the taskMgr's behavior. # set/get Task sort l = [] def _testTaskObjSort(arg, task, l=l): l.append(arg) return task.cont t1 = Task(_testTaskObjSort, sort=1) t2 = Task(_testTaskObjSort, sort=2) tm.add(t1, 'testTaskObjSort1', extraArgs=['a',], appendTask=True) tm.add(t2, 'testTaskObjSort2', extraArgs=['b',], appendTask=True) tm.step() assert len(l) == 2 assert l == ['a', 'b'] assert t1.getSort() == 1 assert t2.getSort() == 2 t1.setSort(3) assert t1.getSort() == 3 tm.step() assert len(l) == 4 assert l == ['a', 'b', 'b', 'a',] t1.remove() t2.remove() tm.step() assert len(l) == 4 del t1 del t2 _testTaskObjSort = None tm._checkMemLeaks() """ del l tm.destroy() del tm
class DistributedCogdoInterior(DistributedObject.DistributedObject): """ """ if __debug__: notify = DirectNotifyGlobal.directNotify.newCategory( 'DistributedCogdoInterior') id = 0 cageHeights = [11.36, 0.01] def __init__(self, cr): DistributedObject.DistributedObject.__init__(self, cr) self.toons = [] self.activeIntervals = {} self.openSfx = base.loader.loadSfx( "phase_5/audio/sfx/elevator_door_open.mp3") self.closeSfx = base.loader.loadSfx( "phase_5/audio/sfx/elevator_door_close.mp3") self.suits = [] self.reserveSuits = [] self.joiningReserves = [] self.distBldgDoId = None self._CogdoGameRepeat = ConfigVariableBool('cogdo-game-repeat', 0).getValue() # we increment this each time we come out of an elevator: self.currentFloor = -1 self.elevatorName = self.__uniqueName('elevator') self.floorModel = None self.elevatorOutOpen = 0 # initial cog positions vary based on the cog office model self.BottomFloor_SuitPositions = [ Point3(0, 15, 0), Point3(10, 20, 0), Point3(-7, 24, 0), Point3(-10, 0, 0) ] self.BottomFloor_SuitHs = [75, 170, -91, -44] # Heading angles self.Cubicle_SuitPositions = [ Point3(0, 18, 0), Point3(10, 12, 0), Point3(-9, 11, 0), Point3(-3, 13, 0) ] self.Cubicle_SuitHs = [170, 56, -52, 10] self.BossOffice_SuitPositions = [ Point3(0, 15, 0), Point3(10, 20, 0), Point3(-10, 6, 0), Point3(-17, 30, 0), ] self.BossOffice_SuitHs = [170, 120, 12, 38] self._wantBarrelRoom = ConfigVariableBool('cogdo-want-barrel-room', 0).getValue() self.barrelRoom = CogdoBarrelRoom.CogdoBarrelRoom() self.brResults = [[], []] self.barrelRoomIntroTrack = None self.penthouseOutroTrack = None self.penthouseOutroChatDoneTrack = None self.penthouseIntroTrack = None self.waitMusic = base.loader.loadMusic( 'phase_7/audio/bgm/encntr_toon_winning_indoor.mid') self.elevatorMusic = base.loader.loadMusic( 'phase_7/audio/bgm/tt_elevator.mid') self.fsm = ClassicFSM.ClassicFSM( 'DistributedCogdoInterior', [ State.State('WaitForAllToonsInside', self.enterWaitForAllToonsInside, self.exitWaitForAllToonsInside, ['Elevator']), State.State('Elevator', self.enterElevator, self.exitElevator, ['Game']), State.State('Game', self.enterGame, self.exitGame, ['Resting', 'Failed', 'BattleIntro']), State.State('BarrelRoomIntro', self.enterBarrelRoomIntro, self.exitBarrelRoomIntro, ['CollectBarrels', 'Off']), State.State('CollectBarrels', self.enterCollectBarrels, self.exitCollectBarrels, ['BarrelRoomReward', 'Off']), State.State( 'BarrelRoomReward', self.enterBarrelRoomReward, self.exitBarrelRoomReward, ['Battle', 'ReservesJoining', 'BattleIntro', 'Off']), State.State('BattleIntro', self.enterBattleIntro, self.exitBattleIntro, ['Battle', 'ReservesJoining', 'Off']), State.State('Battle', self.enterBattle, self.exitBattle, ['Resting', 'Reward', 'ReservesJoining']), State.State('ReservesJoining', self.enterReservesJoining, self.exitReservesJoining, ['Battle']), State.State('Resting', self.enterResting, self.exitResting, ['Elevator']), State.State('Reward', self.enterReward, self.exitReward, ['Off']), State.State('Failed', self.enterFailed, self.exitFailed, ['Off']), State.State('Off', self.enterOff, self.exitOff, ['Elevator', 'WaitForAllToonsInside', 'Battle']), ], # Initial State 'Off', # Final State 'Off', ) # make sure we're in the initial state self.fsm.enterInitialState() self._haveEntranceElevator = StateVar(False) self._stashEntranceElevator = StateVar(False) self._stashEntranceElevatorFC = FunctionCall( self._doStashEntranceElevator, self._haveEntranceElevator, self._stashEntranceElevator) self._entranceElevCallbacks = [] self._doEntranceElevCallbacksFC = FunctionCall( self._doEntranceElevCallbacks, self._haveEntranceElevator) self.cage = None self.shopOwnerNpcId = None self.shopOwnerNpc = None self._movie = None self.SOSToonName = None self.FOType = None def setShopOwnerNpcId(self, npcId): self.shopOwnerNpcId = npcId def setSOSNpcId(self, npcId): self.SOSToonName = NPCToons.getNPCName(npcId) def setFOType(self, typeId): self.FOType = chr(typeId) def __uniqueName(self, name): DistributedCogdoInterior.id += 1 return (name + '%d' % DistributedCogdoInterior.id) def generate(self): """generate(self) This method is called when the DistributedObject is reintroduced to the world, either for the first time or from the cache. """ assert (self.notify.debug("generate()")) DistributedObject.DistributedObject.generate(self) # listen for the generate event, which will be thrown after the # required fields are filled in self.announceGenerateName = self.uniqueName('generate') self.accept(self.announceGenerateName, self.handleAnnounceGenerate) # Load the elevator model self.elevatorModelIn = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_csa_elevatorB') self.leftDoorIn = self.elevatorModelIn.find('**/left-door') self.rightDoorIn = self.elevatorModelIn.find('**/right-door') self.elevatorModelOut = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_csa_elevatorB') self.leftDoorOut = self.elevatorModelOut.find('**/left-door') self.rightDoorOut = self.elevatorModelOut.find('**/right-door') def __makeShopOwnerNpc(self): if self.shopOwnerNpc: return self.shopOwnerNpc = NPCToons.createLocalNPC(self.shopOwnerNpcId) if not self.shopOwnerNpc: self.notify.warning( "No shopkeeper in this cogdominium, using FunnyFarm Sellbot FO NPCToons" ) random.seed(self.doId) shopkeeper = random.randint(7001, 7009) self.shopOwnerNpc = NPCToons.createLocalNPC(shopkeeper) self.shopOwnerNpc.addActive() self.shopOwnerNpc.reparentTo(self.cage) self.shopOwnerNpc.setPosHpr(0, -2, 0, 180, 0, 0) self.shopOwnerNpc.loop('neutral') def setElevatorLights(self, elevatorModel): """ Sets up the lights on the interior elevators to represent the number of floors in the building, and to light up the current floor number. """ npc = elevatorModel.findAllMatches("**/floor_light_?;+s") for i in range(npc.getNumPaths()): np = npc.getPath(i) # Get the last character, and make it zero based: floor = int(np.getName()[-1:]) - 1 if (floor == self.currentFloor): np.setColor(LIGHT_ON_COLOR) elif floor < self.layout.getNumGameFloors(): if self.isBossFloor(self.currentFloor): np.setColor(LIGHT_ON_COLOR) else: np.setColor(LIGHT_OFF_COLOR) else: np.hide() def startAlertElevatorLightIval(self, elevatorModel): light = elevatorModel.find("**/floor_light_%s" % (self.currentFloor + 1)) track = Sequence(Func(light.setColor, Vec4(1.0, 0.6, 0.6, 1.0)), Wait(0.9), Func(light.setColor, LIGHT_ON_COLOR), Wait(0.9)) self.activeIntervals["alertElevatorLight"] = track track.loop() def stopAlertElevatorLightIval(self, elevatorModel): self.__finishInterval("alertElevatorLight") self.setElevatorLights(elevatorModel) def handleAnnounceGenerate(self, obj): """ handleAnnounceGenerate is called after all of the required fields are filled in 'obj' is another copy of self """ self.ignore(self.announceGenerateName) self.cageDoorSfx = loader.loadSfx( 'phase_5/audio/sfx/CHQ_SOS_cage_door.mp3') self.cageLowerSfx = loader.loadSfx( 'phase_5/audio/sfx/CHQ_SOS_cage_lower.mp3') assert (self.notify.debug('joining DistributedCogdoInterior')) # Update the minigame AI to join our local toon doId self.sendUpdate('setAvatarJoined', []) def disable(self): assert (self.notify.debug('disable()')) self.fsm.requestFinalState() self.__cleanupIntervals() self.ignoreAll() self.__cleanup() self.__cleanupShopOwnerNpc() self.__cleanupPenthouseIntro() DistributedObject.DistributedObject.disable(self) def __cleanupShopOwnerNpc(self): if self.shopOwnerNpc: self.shopOwnerNpc.removeActive() self.shopOwnerNpc.delete() self.shopOwnerNpc = None def __cleanupPenthouseIntro(self): if hasattr(self, '_movie') and self._movie: self._movie.unload() self._movie = None def delete(self): assert (self.notify.debug('delete()')) self._stashEntranceElevatorFC.destroy() self._doEntranceElevCallbacksFC.destroy() self._haveEntranceElevator.destroy() self._stashEntranceElevator.destroy() self._entranceElevCallbacks = None del self.waitMusic del self.elevatorMusic del self.openSfx del self.closeSfx del self.fsm # No more battle multiplier base.localAvatar.inventory.setBattleCreditMultiplier(1) DistributedObject.DistributedObject.delete(self) def isBossFloor(self, floorNum): if self.layout.hasBossBattle(): if self.layout.getBossBattleFloor() == floorNum: return True return False def __cleanup(self): self.toons = [] self.suits = [] self.reserveSuits = [] self.joiningReserves = [] # Clean up elevator models if (self.elevatorModelIn != None): self.elevatorModelIn.removeNode() if (self.elevatorModelOut != None): self.elevatorModelOut.removeNode() # Clean up current floor if (self.floorModel != None): self.floorModel.removeNode() # Clean up current cage if (self.cage != None): self.cage = None # Clean up current barrel room if (self.barrelRoom != None): self.barrelRoom.destroy() self.barrelRoom = None self.leftDoorIn = None self.rightDoorIn = None self.leftDoorOut = None self.rightDoorOut = None def __addToon(self, toon): assert (self.notify.debug('addToon(%d)' % toon.doId)) self.accept(toon.uniqueName('disable'), self.__handleUnexpectedExit, extraArgs=[toon]) def __handleUnexpectedExit(self, toon): self.notify.warning('handleUnexpectedExit() - toon: %d' % toon.doId) self.__removeToon(toon, unexpected=1) def __removeToon(self, toon, unexpected=0): assert (self.notify.debug('removeToon() - toon: %d' % toon.doId)) if (self.toons.count(toon) == 1): self.toons.remove(toon) self.ignore(toon.uniqueName('disable')) def __finishInterval(self, name): """ Force the specified interval to jump to the end """ if (name in self.activeIntervals): interval = self.activeIntervals[name] if (interval.isPlaying()): assert(self.notify.debug('finishInterval(): %s' % \ interval.getName())) interval.finish() def __cleanupIntervals(self): for interval in list(self.activeIntervals.values()): interval.finish() self.activeIntervals = {} def __closeInElevator(self): self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) ##### Messages from the server ##### def getZoneId(self): return self.zoneId def setZoneId(self, zoneId): self.zoneId = zoneId def getExtZoneId(self): return self.extZoneId def setExtZoneId(self, extZoneId): self.extZoneId = extZoneId def getDistBldgDoId(self): return self.distBldgDoId def setDistBldgDoId(self, distBldgDoId): self.distBldgDoId = distBldgDoId def setNumFloors(self, numFloors): self.layout = CogdoLayout(numFloors) def getToonIds(self): toonIds = [] for toon in self.toons: toonIds.append(toon.doId) return toonIds def setToons(self, toonIds, hack): assert (self.notify.debug('setToons(): %s' % toonIds)) self.toonIds = toonIds oldtoons = self.toons self.toons = [] for toonId in toonIds: if (toonId != 0): if (toonId in self.cr.doId2do): toon = self.cr.doId2do[toonId] toon.stopSmooth() self.toons.append(toon) if (oldtoons.count(toon) == 0): assert(self.notify.debug('setToons() - new toon: %d' % \ toon.doId)) self.__addToon(toon) else: self.notify.warning('setToons() - no toon: %d' % toonId) for toon in oldtoons: if (self.toons.count(toon) == 0): self.__removeToon(toon) def setSuits(self, suitIds, reserveIds, values): assert(self.notify.debug('setSuits(): active %s reserve %s values %s' \ % (suitIds, reserveIds, values))) oldsuits = self.suits self.suits = [] self.joiningReserves = [] for suitId in suitIds: if (suitId in self.cr.doId2do): suit = self.cr.doId2do[suitId] self.suits.append(suit) # Set this on the client suit.fsm.request('Battle') # This will allow client to respond to setState() from the # server from here on out suit.buildingSuit = 1 suit.reparentTo(render) if (oldsuits.count(suit) == 0): assert(self.notify.debug('setSuits() suit: %d joining' % \ suit.doId)) self.joiningReserves.append(suit) else: self.notify.warning('setSuits() - no suit: %d' % suitId) self.reserveSuits = [] assert (len(reserveIds) == len(values)) for index in range(len(reserveIds)): suitId = reserveIds[index] if (suitId in self.cr.doId2do): suit = self.cr.doId2do[suitId] self.reserveSuits.append((suit, values[index])) else: self.notify.warning('setSuits() - no suit: %d' % suitId) if (len(self.joiningReserves) > 0): assert (self.notify.debug('setSuits() reserves joining')) self.fsm.request('ReservesJoining') def setState(self, state, timestamp): assert(self.notify.debug("setState(%s, %d)" % \ (state, timestamp))) self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)]) def stashElevatorIn(self, stash=True): self._stashEntranceElevator.set(stash) def getEntranceElevator(self, callback): if self._haveEntranceElevator.get(): callback(self.elevIn) else: self._entranceElevCallbacks.append(callback) def _doEntranceElevCallbacks(self, haveElev): if haveElev: while len(self._entranceElevCallbacks): cbs = self._entranceElevCallbacks[:] self._entranceElevCallbacks = [] for callback in cbs: callback(self.elevIn) def _doStashEntranceElevator(self, haveElev, doStash): if haveElev: if doStash: self.elevIn.stash() else: self.elevIn.unstash() ##### Messages to the server ##### def d_elevatorDone(self): assert (self.notify.debug('network:elevatorDone(%d)' % base.localAvatar.doId)) self.sendUpdate('elevatorDone', []) def d_reserveJoinDone(self): assert (self.notify.debug('network:reserveJoinDone(%d)' % base.localAvatar.doId)) self.sendUpdate('reserveJoinDone', []) # Specific State Functions ##### Off state ##### def enterOff(self, ts=0): assert (self.notify.debug('enterOff()')) messenger.send('sellbotFieldOfficeChanged', [False]) return None def exitOff(self): return None ##### WaitForAllToonsInside state ##### def enterWaitForAllToonsInside(self, ts=0): assert (self.notify.debug('enterWaitForAllToonsInside()')) base.transitions.fadeOut(0) return None def exitWaitForAllToonsInside(self): return None def enterGame(self, ts=0): assert (self.notify.debug('enterElevator()')) base.cr.forbidCheesyEffects(1) def exitGame(self): base.cr.forbidCheesyEffects(0) ##### Elevator state ##### def __playElevator(self, ts, name, callback): # Load the floor model SuitHs = [] # Heading angles SuitPositions = [] if self.floorModel: self.floorModel.removeNode() self.floorModel = None if self.cage: self.cage = None if (self.currentFloor == 0): # bottom floor SuitHs = self.BottomFloor_SuitHs SuitPositions = self.BottomFloor_SuitPositions if self.isBossFloor(self.currentFloor): # Top floor self.barrelRoom.unload() self.floorModel = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_penthouse') self.cage = self.floorModel.find('**/cage') pos = self.cage.getPos() self.cagePos = [] for height in self.cageHeights: self.cagePos.append(Point3(pos[0], pos[1], height)) self.cageDoor = self.floorModel.find('**/cage_door') self.cageDoor.wrtReparentTo(self.cage) if self.FOType: paintingModelName = PAINTING_DICT.get(self.FOType) for i in range(4): paintingModel = loader.loadModel( 'phase_5/models/cogdominium/%s' % paintingModelName) loc = self.floorModel.find('**/loc_painting%d' % (i + 1)) paintingModel.reparentTo(loc) SuitHs = self.BossOffice_SuitHs SuitPositions = self.BossOffice_SuitPositions self.__makeShopOwnerNpc() else: if self._wantBarrelRoom: self.barrelRoom.load() self.barrelRoom.hide() # middle floor SuitHs = self.Cubicle_SuitHs SuitPositions = self.Cubicle_SuitPositions if self.floorModel: self.floorModel.reparentTo(render) if self.isBossFloor(self.currentFloor): self.notify.debug('Load boss_suit_office') elevIn = self.floorModel.find( CogdoGameConsts.PenthouseElevatorInPath).copyTo(render) elevOut = self.floorModel.find( CogdoGameConsts.PenthouseElevatorOutPath) frame = self.elevatorModelOut.find('**/frame') if not frame.isEmpty(): frame.hide() frame = self.elevatorModelIn.find('**/frame') if not frame.isEmpty(): frame.hide() self.elevatorModelOut.reparentTo(elevOut) else: # We need to name this something more useful (and we'll need the # location of the opposite elevator as well) elevIn = self.floorModel.find('**/elevator-in') elevOut = self.floorModel.find('**/elevator-out') elif self._wantBarrelRoom and self.barrelRoom.isLoaded(): elevIn = self.barrelRoom.dummyElevInNode elevOut = self.barrelRoom.model.find( CogdoBarrelRoomConsts.BarrelRoomElevatorOutPath) y = elevOut.getY(render) elevOut = elevOut.copyTo(render) elevOut.setY(render, y - 0.75) else: # TODO: TEMP floorModel = loader.loadModel( 'phase_7/models/modules/boss_suit_office') elevIn = floorModel.find('**/elevator-in').copyTo(render) elevOut = floorModel.find('**/elevator-out').copyTo(render) floorModel.removeNode() self.elevIn = elevIn # store elevOut until it's needed self.elevOut = elevOut self._haveEntranceElevator.set(True) # Position the suits assert (len(self.suits) <= 4) for index in range(len(self.suits)): assert(self.notify.debug('setting suit: %d to pos: %s' % \ (self.suits[index].doId, SuitPositions[index]))) self.suits[index].setPos(SuitPositions[index]) if (len(self.suits) > 2): self.suits[index].setH(SuitHs[index]) else: self.suits[index].setH( 170 ) # if there's 2 or 1 suits, make them face fwd since there's no other suits they would be to be talking to self.suits[index].loop('neutral') # Position the toons for toon in self.toons: toon.reparentTo(self.elevatorModelIn) assert (self.toonIds.count(toon.doId) == 1) index = self.toonIds.index(toon.doId) assert (index >= 0 and index <= 3) toon.setPos(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2]) toon.setHpr(180, 0, 0) toon.loop('neutral') # Show the elevator and position it in the correct place for the floor self.elevatorModelIn.reparentTo(elevIn) # Start with the doors in closed position self.leftDoorIn.setPos(3.5, 0, 0) self.rightDoorIn.setPos(-3.5, 0, 0) # Position the camera behind the toons camera.reparentTo(self.elevatorModelIn) camera.setH(180) camera.setP(0) camera.setPos(0, 14, 4) # Play elevator music base.playMusic(self.elevatorMusic, looping=1, volume=0.8) # Ride the elevator, then open the doors. track = Sequence( Func(base.transitions.noTransitions), ElevatorUtils.getRideElevatorInterval(ELEVATOR_NORMAL), ElevatorUtils.getOpenInterval(self, self.leftDoorIn, self.rightDoorIn, self.openSfx, None, type=ELEVATOR_NORMAL), Func(camera.wrtReparentTo, render), ) for toon in self.toons: track.append(Func(toon.wrtReparentTo, render)) track.append(Func(callback)) track.start(ts) self.activeIntervals[name] = track def enterElevator(self, ts=0): # Load model for the current floor and the suit models for the floor assert (self.notify.debug('enterElevator()')) if not self._CogdoGameRepeat: self.currentFloor += 1 self.cr.playGame.getPlace().currentFloor = self.currentFloor self.setElevatorLights(self.elevatorModelIn) self.setElevatorLights(self.elevatorModelOut) # hide elevator from previous floor (if any) # unless it's the top floor, in that case leave it where it is if not self.isBossFloor(self.currentFloor): self.elevatorModelOut.detachNode() messenger.send('sellbotFieldOfficeChanged', [True]) else: self._movie = CogdoElevatorMovie() self._movie.load() self._movie.play() self.__playElevator(ts, self.elevatorName, self.__handleElevatorDone) # Get the floor multiplier mult = ToontownBattleGlobals.getCreditMultiplier(self.currentFloor) # Now set the inventory battleCreditMult base.localAvatar.inventory.setBattleCreditMultiplier(mult) def __handleElevatorDone(self): assert (self.notify.debug('handleElevatorDone()')) self.d_elevatorDone() def exitElevator(self): self.elevatorMusic.stop() if self._movie: self._movie.end() self.__cleanupPenthouseIntro() self.__finishInterval(self.elevatorName) return None def __setupBarrelRoom(self): base.cr.playGame.getPlace().fsm.request('stopped') base.transitions.irisOut(0.0) self.elevatorModelIn.detachNode() self._showExitElevator() self.barrelRoom.show() self.barrelRoom.placeToonsAtEntrance(self.toons) def barrelRoomIntroDone(self): self.sendUpdate('toonBarrelRoomIntroDone', []) def enterBarrelRoomIntro(self, ts=0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.__setupBarrelRoom() self.barrelRoomIntroTrack, trackName = self.barrelRoom.getIntroInterval( ) self.barrelRoomIntroDoneEvent = trackName self.accept(self.barrelRoomIntroDoneEvent, self.barrelRoomIntroDone) self.activeIntervals[trackName] = self.barrelRoomIntroTrack self.barrelRoomIntroTrack.start(ts) else: self._showExitElevator() def exitBarrelRoomIntro(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore(self.barrelRoomIntroDoneEvent) if self.barrelRoomIntroTrack: self.barrelRoomIntroTrack.finish() DelayDelete.cleanupDelayDeletes(self.barrelRoomIntroTrack) self.barrelRoomIntroTrack = None return def __handleLocalToonLeftBarrelRoom(self): self.notify.info('Local toon teleported out of barrel room.') self.sendUpdate('toonLeftBarrelRoom', []) self.barrelRoom.deactivate() def enterCollectBarrels(self, ts=0): if not self.isBossFloor(self.currentFloor): if self._wantBarrelRoom: self.acceptOnce('localToonLeft', self.__handleLocalToonLeftBarrelRoom) self.barrelRoom.activate() base.playMusic(self.waitMusic, looping=1, volume=0.7) def exitCollectBarrels(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): self.ignore('localToonLeft') self.barrelRoom.deactivate() self.waitMusic.stop() def __brRewardDone(self, task=None): self.notify.info('Toon finished watching the barrel room reward.') self.sendUpdate('toonBarrelRoomRewardDone', []) def setBarrelRoomReward(self, avIds, laffs): self.brResults = [avIds, laffs] self.barrelRoom.setRewardResults(self.brResults) def enterBarrelRoomReward(self, ts=0): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('stopped') self.startAlertElevatorLightIval(self.elevatorModelOut) track, trackName = self.barrelRoom.showRewardUi( self.brResults, callback=self.__brRewardDone) self.activeIntervals[trackName] = track track.start() self.barrelRoom.placeToonsNearBattle(self.toons) def exitBarrelRoomReward(self): if self._wantBarrelRoom and not self.isBossFloor(self.currentFloor): base.cr.playGame.getPlace().fsm.request('walk') self.stopAlertElevatorLightIval(self.elevatorModelOut) self.barrelRoom.hideRewardUi() def enterBattleIntro(self, ts=0): self._movie = CogdoExecutiveSuiteIntro(self.shopOwnerNpc) self._movie.load() self._movie.play() def exitBattleIntro(self): self._movie.end() self.__cleanupPenthouseIntro() ##### Battle state ##### def __playCloseElevatorOut(self, name, delay=0): # Close the elevator doors track = Sequence( Wait(delay + SUIT_LEAVE_ELEVATOR_TIME), Parallel( SoundInterval(self.closeSfx), LerpPosInterval( self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut'), LerpPosInterval( self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), startPos=Point3(0, 0, 0), blendType='easeOut')), ) track.start() self.activeIntervals[name] = track def enterBattle(self, ts=0): assert (self.notify.debug('enterBattle()')) if self._wantBarrelRoom and self.elevatorOutOpen == 1: self.__playCloseElevatorOut(self.uniqueName('close-out-elevator'), delay=2) camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) def _showExitElevator(self): # now that we're in the barrel room, show the exit elevator # Show the elevator and position it in the correct place for the floor self.elevatorModelOut.reparentTo(self.elevOut) # Start with the doors in closed position self.leftDoorOut.setPos(3.5, 0, 0) self.rightDoorOut.setPos(-3.5, 0, 0) if not (self._wantBarrelRoom and self.elevatorOutOpen == 1): self.__playCloseElevatorOut(self.uniqueName('close-out-elevator')) # Watch reserve suits as they walk from the elevator camera.setPos(0, -15, 6) camera.headsUp(self.elevatorModelOut) return None def exitBattle(self): if (self.elevatorOutOpen == 1): self.__finishInterval(self.uniqueName('close-out-elevator')) self.elevatorOutOpen = 0 return None ##### ReservesJoining state ##### def __playReservesJoining(self, ts, name, callback): # Position the joining suits index = 0 assert (len(self.joiningReserves) <= 4) for suit in self.joiningReserves: suit.reparentTo(render) suit.setPos( self.elevatorModelOut, Point3(ElevatorPoints[index][0], ElevatorPoints[index][1], ElevatorPoints[index][2])) index += 1 suit.setH(180) suit.loop('neutral') if len(self.suits) == len(self.joiningReserves): camSequence = Sequence(Func(camera.wrtReparentTo, localAvatar), Func(camera.setPos, Point3(0, 5, 5)), Func(camera.headsUp, self.elevatorModelOut)) else: camSequence = Sequence( Func(camera.wrtReparentTo, self.elevatorModelOut), Func(camera.setPos, Point3(0, -8, 2)), Func(camera.setHpr, Vec3(0, 10, 0))) # Aim the camera at the far elevator track = Sequence( Func(camera.wrtReparentTo, self.elevatorModelOut), Func(camera.setPos, Point3(0, -8, 2)), Func(camera.setHpr, Vec3(0, 10, 0)), # Open the elevator doors Parallel( SoundInterval(self.openSfx), LerpPosInterval( self.leftDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getLeftClosePoint(ELEVATOR_NORMAL), blendType='easeOut'), LerpPosInterval( self.rightDoorOut, ElevatorData[ELEVATOR_NORMAL]['closeTime'], Point3(0, 0, 0), startPos=ElevatorUtils.getRightClosePoint(ELEVATOR_NORMAL), blendType='easeOut'), ), # Hold the camera angle for a couple of beats Wait(SUIT_HOLD_ELEVATOR_TIME), # Reparent the camera to render (enterWaitForInput will # position it properly again by the battle) Func(camera.wrtReparentTo, render), Func(callback), ) track.start(ts) self.activeIntervals[name] = track def enterReservesJoining(self, ts=0): assert (self.notify.debug('enterReservesJoining()')) self.__playReservesJoining(ts, self.uniqueName('reserves-joining'), self.__handleReserveJoinDone) return None def __handleReserveJoinDone(self): assert (self.notify.debug('handleReserveJoinDone()')) self.joiningReserves = [] self.elevatorOutOpen = 1 self.d_reserveJoinDone() def exitReservesJoining(self): self.__finishInterval(self.uniqueName('reserves-joining')) return None ##### Resting state ##### def enterResting(self, ts=0): assert (self.notify.debug('enterResting()')) self._showExitElevator() self._setAvPosFDC = FrameDelayedCall('setAvPos', self._setAvPosToExit) if self._wantBarrelRoom: self.barrelRoom.showBattleAreaLight(True) base.playMusic(self.waitMusic, looping=1, volume=0.7) self.__closeInElevator() self._haveEntranceElevator.set(False) self._stashEntranceElevator.set(False) return def _setAvPosToExit(self): base.localAvatar.setPos(self.elevOut, 0, -10, 0) base.localAvatar.setHpr(self.elevOut, 0, 0, 0) base.cr.playGame.getPlace().fsm.request('walk') def exitResting(self): self._setAvPosFDC.destroy() self.waitMusic.stop() return ##### Reward state ##### def enterReward(self, ts=0): assert (self.notify.debug('enterReward()')) if self.isBossFloor(self.currentFloor): self.penthouseOutroTrack = self.__outroPenthouse() self.penthouseOutroTrack.start(ts) else: self.exitCogdoBuilding() return None def exitReward(self): self.notify.debug('exitReward') if self.penthouseOutroTrack: self.penthouseOutroTrack.finish() DelayDelete.cleanupDelayDeletes(self.penthouseOutroTrack) self.penthouseOutroTrack = None if not self.penthouseOutroChatDoneTrack: self.notify.debug( 'exitReward: instanting outroPenthouseChatDone track') self.__outroPenthouseChatDone() self.penthouseOutroChatDoneTrack.finish() self.penthouseOutroChatDoneTrack = None return ##### Failed state ##### def enterFailed(self, ts=0): self.exitCogdoBuilding() return None def exitFailed(self): self.notify.debug('exitFailed()') self.exitCogdoBuilding() return None def exitCogdoBuilding(self): if base.localAvatar.hp < 0: return base.localAvatar.b_setParent(ToontownGlobals.SPHidden) request = { 'loader': ZoneUtil.getBranchLoaderName(self.extZoneId), 'where': ZoneUtil.getToonWhereName(self.extZoneId), 'how': 'elevatorIn', 'hoodId': ZoneUtil.getHoodId(self.extZoneId), 'zoneId': self.extZoneId, 'shardId': None, 'avId': -1, 'bldgDoId': self.distBldgDoId } messenger.send('DSIDoneEvent', [request]) return def displayBadges(self): numFloors = self.layout.getNumGameFloors() if numFloors > 5 or numFloors < 3: pass else: self.notify.warning('Invalid floor number for display badges.') for player in range(len(self.toons)): goldBadge = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_goldTrophy') goldBadge.setScale(1.2) goldNode = render.find('**/gold_0' + str(player + 1)) goldBadge.reparentTo(goldNode) for floor in range(numFloors): silverBadge = loader.loadModel( 'phase_5/models/cogdominium/tt_m_ara_crg_silverTrophy.bam') silverBadge.setScale(1.2) silverNode = render.find('**/silver_0' + str(floor * 4 + (player + 1))) silverBadge.reparentTo(silverNode) ##### Outro state ##### def __outroPenthouse(self): avatar = base.localAvatar trackName = '__outroPenthouse-%d' % avatar.doId track = Parallel(name=trackName) base.cr.playGame.getPlace().fsm.request('stopped') speech = TTLocalizer.CogdoExecutiveSuiteToonThankYou % self.SOSToonName track.append( Sequence( Func(camera.wrtReparentTo, localAvatar), Func(camera.setPos, 0, -9, 9), Func(camera.lookAt, Point3(5, 15, 0)), Parallel( self.cage.posInterval(0.75, self.cagePos[1], blendType='easeOut'), SoundInterval(self.cageLowerSfx, duration=0.5)), Parallel( self.cageDoor.hprInterval(0.5, VBase3(0, 90, 0), blendType='easeOut'), Sequence(SoundInterval(self.cageDoorSfx), duration=0)), Wait(0.25), Func(self.shopOwnerNpc.wrtReparentTo, render), Func(self.shopOwnerNpc.setScale, 1), Func(self.shopOwnerNpc.loop, 'walk'), Func(self.shopOwnerNpc.headsUp, Point3(0, 10, 0)), ParallelEndTogether( self.shopOwnerNpc.posInterval(1.5, Point3(0, 10, 0)), self.shopOwnerNpc.hprInterval(0.5, VBase3(180, 0, 0), blendType='easeInOut')), Func(self.shopOwnerNpc.setChatAbsolute, TTLocalizer.CagedToonYippee, CFSpeech), ActorInterval(self.shopOwnerNpc, 'jump'), Func(self.shopOwnerNpc.loop, 'neutral'), Func(self.shopOwnerNpc.headsUp, localAvatar), Func(self.shopOwnerNpc.setLocalPageChat, speech, 0), Func(camera.lookAt, self.shopOwnerNpc, Point3(0, 0, 2)))) self.activeIntervals[trackName] = track self.accept('doneChatPage', self.__outroPenthouseChatDone) return track def __outroPenthouseChatDone(self, elapsed=None): self.shopOwnerNpc.setChatAbsolute( TTLocalizer.CogdoExecutiveSuiteToonBye, CFSpeech) self.ignore('doneChatPage') track = Parallel( Sequence(ActorInterval(self.shopOwnerNpc, 'wave'), Func(self.shopOwnerNpc.loop, 'neutral')), Sequence( Wait(2.0), Func(self.exitCogdoBuilding), Func(base.camLens.setMinFov, ToontownGlobals.DefaultCameraFov), ), ) track.start() self.penthouseOutroChatDoneTrack = track
class TaskManager(): __module__ = __name__ notify = directNotify.newCategory('TaskManager') extendedExceptions = False MaxEpochSpeed = 1.0 / 30.0 def __init__(self): self.mgr = AsyncTaskManager.getGlobalPtr() self.resumeFunc = None self.globalClock = self.mgr.getClock() self.stepping = False self.running = False self.destroyed = False self.fKeyboardInterrupt = False self.interruptCount = 0 self._frameProfileQueue = Queue() self._profileFrames = None self._frameProfiler = None self._profileTasks = None self._taskProfiler = None self._taskProfileInfo = ScratchPad(taskId=None, profiled=False, session=None) return def finalInit(self): from direct.fsm.StatePush import StateVar self._profileTasks = StateVar(False) self.setProfileTasks(ConfigVariableBool('profile-task-spikes', 0).getValue()) self._profileFrames = StateVar(False) self.setProfileFrames(ConfigVariableBool('profile-frames', 0).getValue()) def destroy(self): self.notify.info('TaskManager.destroy()') self.destroyed = True self._frameProfileQueue.clear() self.mgr.cleanup() def setClock(self, clockObject): self.mgr.setClock(clockObject) self.globalClock = clockObject def invokeDefaultHandler(self, signalNumber, stackFrame): print '*** allowing mid-frame keyboard interrupt.' signal.signal(signal.SIGINT, signal.default_int_handler) raise KeyboardInterrupt def keyboardInterruptHandler(self, signalNumber, stackFrame): self.fKeyboardInterrupt = 1 self.interruptCount += 1 if self.interruptCount == 1: print '* interrupt by keyboard' elif self.interruptCount == 2: print '** waiting for end of frame before interrupting...' signal.signal(signal.SIGINT, self.invokeDefaultHandler) def getCurrentTask(self): return Thread.getCurrentThread().getCurrentTask() def hasTaskChain(self, chainName): return self.mgr.findTaskChain(chainName) != None def setupTaskChain(self, chainName, numThreads = None, tickClock = None, threadPriority = None, frameBudget = None, frameSync = None, timeslicePriority = None): chain = self.mgr.makeTaskChain(chainName) if numThreads is not None: chain.setNumThreads(numThreads) if tickClock is not None: chain.setTickClock(tickClock) if threadPriority is not None: chain.setThreadPriority(threadPriority) if frameBudget is not None: chain.setFrameBudget(frameBudget) if frameSync is not None: chain.setFrameSync(frameSync) if timeslicePriority is not None: chain.setTimeslicePriority(timeslicePriority) return def hasTaskNamed(self, taskName): return bool(self.mgr.findTask(taskName)) def getTasksNamed(self, taskName): return self.__makeTaskList(self.mgr.findTasks(taskName)) def getTasksMatching(self, taskPattern): return self.__makeTaskList(self.mgr.findTasksMatching(GlobPattern(taskPattern))) def getAllTasks(self): return self.__makeTaskList(self.mgr.getTasks()) def getTasks(self): return self.__makeTaskList(self.mgr.getActiveTasks()) def getDoLaters(self): return self.__makeTaskList(self.mgr.getSleepingTasks()) def __makeTaskList(self, taskCollection): l = [] for i in range(taskCollection.getNumTasks()): l.append(taskCollection.getTask(i)) return l def doMethodLater(self, delayTime, funcOrTask, name, extraArgs = None, sort = None, priority = None, taskChain = None, uponDeath = None, appendTask = False, owner = None): if delayTime < 0: pass task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath) task.setDelay(delayTime) self.mgr.add(task) return task def add(self, funcOrTask, name = None, sort = None, extraArgs = None, priority = None, uponDeath = None, appendTask = False, taskChain = None, owner = None): task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath) self.mgr.add(task) return task def __setupTask(self, funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath): if isinstance(funcOrTask, AsyncTask): task = funcOrTask elif hasattr(funcOrTask, '__call__'): task = PythonTask(funcOrTask) else: self.notify.error('add: Tried to add a task that was not a Task or a func') if hasattr(task, 'setArgs'): if extraArgs is None: extraArgs = [] appendTask = True task.setArgs(extraArgs, appendTask) elif extraArgs is not None: self.notify.error('Task %s does not accept arguments.' % repr(task)) if name is not None: task.setName(name) if priority is not None and sort is None: task.setSort(priority) else: if priority is not None: task.setPriority(priority) if sort is not None: task.setSort(sort) if taskChain is not None: task.setTaskChain(taskChain) if owner is not None: task.setOwner(owner) if uponDeath is not None: task.setUponDeath(uponDeath) return task def remove(self, taskOrName): if isinstance(taskOrName, types.StringTypes): tasks = self.mgr.findTasks(taskOrName) return self.mgr.remove(tasks) elif isinstance(taskOrName, AsyncTask): return self.mgr.remove(taskOrName) elif isinstance(taskOrName, types.ListType): for task in taskOrName: self.remove(task) else: self.notify.error('remove takes a string or a Task') def removeTasksMatching(self, taskPattern): tasks = self.mgr.findTasksMatching(GlobPattern(taskPattern)) return self.mgr.remove(tasks) def step(self): self.fKeyboardInterrupt = 0 self.interruptCount = 0 signal.signal(signal.SIGINT, self.keyboardInterruptHandler) startFrameTime = self.globalClock.getRealTime() self.mgr.poll() nextTaskTime = self.mgr.getNextWakeTime() self.doYield(startFrameTime, nextTaskTime) signal.signal(signal.SIGINT, signal.default_int_handler) if self.fKeyboardInterrupt: raise KeyboardInterrupt def run(self): t = self.globalClock.getFrameTime() timeDelta = t - self.globalClock.getRealTime() self.globalClock.setRealTime(t) messenger.send('resetClock', [timeDelta]) if self.resumeFunc != None: self.resumeFunc() if self.stepping: self.step() else: self.running = True while self.running: try: if len(self._frameProfileQueue): numFrames, session, callback = self._frameProfileQueue.pop() def _profileFunc(numFrames = numFrames): self._doProfiledFrames(numFrames) session.setFunc(_profileFunc) session.run() _profileFunc = None if callback: callback() session.release() else: self.step() except KeyboardInterrupt: self.stop() except IOError as ioError: code, message = self._unpackIOError(ioError) if code == 4: self.stop() else: raise except Exception as e: if self.extendedExceptions: self.stop() print_exc_plus() else: if ExceptionVarDump.wantStackDumpLog and ExceptionVarDump.dumpOnExceptionInit: ExceptionVarDump._varDump__print(e) raise except: if self.extendedExceptions: self.stop() print_exc_plus() else: raise self.mgr.stopThreads() return def _unpackIOError(self, ioError): try: code, message = ioError except: code = 0 message = ioError return (code, message) def stop(self): self.running = False def __tryReplaceTaskMethod(self, task, oldMethod, newFunction): if not isinstance(task, PythonTask): return 0 method = task.getFunction() if type(method) == types.MethodType: function = method.im_func else: function = method if function == oldMethod: import new newMethod = new.instancemethod(newFunction, method.im_self, method.im_class) task.setFunction(newMethod) return 1 return 0 def replaceMethod(self, oldMethod, newFunction): numFound = 0 for task in self.getAllTasks(): numFound += self.__tryReplaceTaskMethod(task, oldMethod, newFunction) return numFound def popupControls(self): from direct.tkpanels import TaskManagerPanel return TaskManagerPanel.TaskManagerPanel(self) def getProfileSession(self, name = None): if name is None: name = 'taskMgrFrameProfile' from direct.showbase.ProfileSession import ProfileSession return ProfileSession(name) def profileFrames(self, num = None, session = None, callback = None): if num is None: num = 1 if session is None: session = self.getProfileSession() session.acquire() self._frameProfileQueue.push((num, session, callback)) return def _doProfiledFrames(self, numFrames): for i in xrange(numFrames): result = self.step() return result def getProfileFrames(self): return self._profileFrames.get() def getProfileFramesSV(self): return self._profileFrames def setProfileFrames(self, profileFrames): self._profileFrames.set(profileFrames) if not self._frameProfiler and profileFrames: from direct.task.FrameProfiler import FrameProfiler self._frameProfiler = FrameProfiler() def getProfileTasks(self): return self._profileTasks.get() def getProfileTasksSV(self): return self._profileTasks def setProfileTasks(self, profileTasks): self._profileTasks.set(profileTasks) if not self._taskProfiler and profileTasks: from direct.task.TaskProfiler import TaskProfiler self._taskProfiler = TaskProfiler() def logTaskProfiles(self, name = None): if self._taskProfiler: self._taskProfiler.logProfiles(name) def flushTaskProfiles(self, name = None): if self._taskProfiler: self._taskProfiler.flush(name) def _setProfileTask(self, task): if self._taskProfileInfo.session: self._taskProfileInfo.session.release() self._taskProfileInfo.session = None self._taskProfileInfo = ScratchPad(taskFunc=task.getFunction(), taskArgs=task.getArgs(), task=task, profiled=False, session=None) task.setFunction(self._profileTask) task.setArgs([self._taskProfileInfo], True) return def _profileTask(self, profileInfo, task): appendTask = False taskArgs = profileInfo.taskArgs if taskArgs and taskArgs[-1] == task: appendTask = True taskArgs = taskArgs[:-1] task.setArgs(taskArgs, appendTask) task.setFunction(profileInfo.taskFunc) from direct.showbase.ProfileSession import ProfileSession profileSession = ProfileSession('profiled-task-%s' % task.getName(), Functor(profileInfo.taskFunc, *profileInfo.taskArgs)) ret = profileSession.run() profileInfo.session = profileSession profileInfo.profiled = True return ret def _hasProfiledDesignatedTask(self): return self._taskProfileInfo.profiled def _getLastTaskProfileSession(self): return self._taskProfileInfo.session def _getRandomTask(self): now = globalClock.getFrameTime() avgFrameRate = globalClock.getAverageFrameRate() if avgFrameRate < 1e-05: avgFrameDur = 0.0 else: avgFrameDur = 1.0 / globalClock.getAverageFrameRate() next = now + avgFrameDur tasks = self.mgr.getTasks() i = random.randrange(tasks.getNumTasks()) task = tasks.getTask(i) while not isinstance(task, PythonTask) or task.getWakeTime() > next: tasks.removeTask(i) i = random.randrange(tasks.getNumTasks()) task = tasks.getTask(i) return task def __repr__(self): return str(self.mgr) def doYield(self, frameStartTime, nextScheduledTaskTime): pass def _runTests(self): pass# decompiled 0 files: 0 okay, 1 failed, 0 verify failed