oldschool-toontown/toontown/hood/QuietZoneState.py

440 lines
18 KiB
Python
Raw Permalink Normal View History

from panda3d.core import *
from panda3d.toontown import *
2019-11-02 17:27:54 -05:00
from direct.showbase.PythonUtil import Functor, PriorityCallbacks
from direct.task import Task
from toontown.distributed.ToontownMsgTypes import *
from toontown.toonbase import ToontownGlobals
2019-11-02 17:27:54 -05:00
from otp.otpbase import OTPGlobals
from direct.directnotify import DirectNotifyGlobal
from direct.fsm import StateData
from direct.fsm import ClassicFSM, State
from direct.fsm import State
from . import ZoneUtil
2019-11-02 17:27:54 -05:00
class QuietZoneState(StateData.StateData):
notify = DirectNotifyGlobal.directNotify.newCategory('QuietZoneState')
Disable = False
Queue = []
def __init__(self, doneEvent):
StateData.StateData.__init__(self, doneEvent)
self.fsm = ClassicFSM.ClassicFSM('QuietZoneState', [State.State('off', self.enterOff, self.exitOff, ['waitForQuietZoneResponse']),
State.State('waitForQuietZoneResponse', self.enterWaitForQuietZoneResponse, self.exitWaitForQuietZoneResponse, ['waitForZoneRedirect']),
State.State('waitForZoneRedirect', self.enterWaitForZoneRedirect, self.exitWaitForZoneRedirect, ['waitForSetZoneResponse']),
State.State('waitForSetZoneResponse', self.enterWaitForSetZoneResponse, self.exitWaitForSetZoneResponse, ['waitForSetZoneComplete']),
State.State('waitForSetZoneComplete', self.enterWaitForSetZoneComplete, self.exitWaitForSetZoneComplete, ['waitForLocalAvatarOnShard']),
State.State('waitForLocalAvatarOnShard', self.enterWaitForLocalAvatarOnShard, self.exitWaitForLocalAvatarOnShard, ['off'])], 'off', 'off')
self._enqueueCount = 0
self.fsm.enterInitialState()
def load(self):
self.notify.debug('load()')
def unload(self):
self._dequeue()
self.notify.debug('unload()')
del self.fsm
@classmethod
def enqueueState(cls, state, requestStatus):
cls.Queue = [(state, requestStatus)] + cls.Queue
state._enqueueCount += 1
if len(cls.Queue) == 1:
cls.startNextQueuedState()
@classmethod
def dequeueState(cls, state):
s, requestStatus = cls.Queue.pop()
s._enqueueCount -= 1
if len(cls.Queue) > 0:
cls.startNextQueuedState()
@classmethod
def startNextQueuedState(cls):
state, requestStatus = cls.Queue[-1]
state._start(requestStatus)
def _dequeue(self):
newQ = []
for item in self.__class__.Queue:
state, requestStatus = item
if state is not self:
newQ.append(item)
self.__class__.Queue = newQ
def getEnterWaitForSetZoneResponseMsg(self):
return 'enterWaitForSetZoneResponse-%s' % (id(self),)
def getQuietZoneLeftEvent(self):
return '%s-%s' % (base.cr.getQuietZoneLeftEvent(), id(self))
def getSetZoneCompleteEvent(self):
return 'setZoneComplete-%s' % (id(self),)
def enter(self, requestStatus):
self.notify.debug('enter(requestStatus=' + str(requestStatus) + ')')
self._requestStatus = requestStatus
self._leftQuietZoneCallbacks = None
self._setZoneCompleteCallbacks = None
self._leftQuietZoneLocalCallbacks = {}
self._setZoneCompleteLocalCallbacks = {}
self.enqueueState(self, requestStatus)
return
def _start(self, requestStatus):
base.transitions.fadeScreen(1.0)
self.fsm.request('waitForQuietZoneResponse')
def getRequestStatus(self):
return self._requestStatus
def exit(self):
self.notify.debug('exit()')
del self._requestStatus
base.transitions.noTransitions()
self.fsm.request('off')
self._dequeue()
def waitForDatabase(self, description):
if base.endlessQuietZone:
return
base.cr.waitForDatabaseTimeout(requestName='quietZoneState-%s' % description)
def clearWaitForDatabase(self):
base.cr.cleanupWaitingForDatabase()
def addLeftQuietZoneCallback(self, callback, priority = None):
if self._leftQuietZoneCallbacks:
return self._leftQuietZoneCallbacks.add(callback, priority)
else:
token = PriorityCallbacks.GetToken()
fdc = SubframeCall(callback, taskMgr.getCurrentTask().getPriority() - 1)
self._leftQuietZoneLocalCallbacks[token] = fdc
return token
def removeLeftQuietZoneCallback(self, token):
if token is not None:
lc = self._leftQuietZoneLocalCallbacks.pop(token, None)
if lc:
lc.cleanup()
if self._leftQuietZoneCallbacks:
self._leftQuietZoneCallbacks.remove(token)
return
def addSetZoneCompleteCallback(self, callback, priority = None):
if self._setZoneCompleteCallbacks:
return self._setZoneCompleteCallbacks.add(callback, priority)
else:
token = PriorityCallbacks.GetToken()
fdc = SubframeCall(callback, taskMgr.getCurrentTask().getPriority() - 1)
self._setZoneCompleteLocalCallbacks[token] = fdc
return token
def removeSetZoneCompleteCallback(self, token):
if token is not None:
lc = self._setZoneCompleteLocalCallbacks.pop(token, None)
if lc:
lc.cleanup()
if self._setZoneCompleteCallbacks:
self._setZoneCompleteCallbacks.remove(token)
return
2021-06-29 12:57:22 -05:00
if not __astron__:
2019-11-17 15:29:23 -06:00
def handleWaitForQuietZoneResponse(self, msgType, di):
# self.notify.debug('handleWaitForQuietZoneResponse(' + 'msgType=' + str(msgType) + ', di=' + str(di) + ')')
2019-11-17 15:29:23 -06:00
if msgType == CLIENT_CREATE_OBJECT_REQUIRED:
base.cr.handleQuietZoneGenerateWithRequired(di)
elif msgType == CLIENT_CREATE_OBJECT_REQUIRED_OTHER:
base.cr.handleQuietZoneGenerateWithRequiredOther(di)
elif msgType == CLIENT_OBJECT_UPDATE_FIELD:
base.cr.handleQuietZoneUpdateField(di)
elif msgType in QUIET_ZONE_IGNORED_LIST:
self.notify.debug('ignoring unwanted message from previous zone')
else:
base.cr.handlePlayGame(msgType, di)
else:
def handleWaitForQuietZoneResponse(self, msgType, di):
# self.notify.debug('handleWaitForQuietZoneResponse(' + 'msgType=' + str(msgType) + ', di=' + str(di) + ')')
2019-11-17 15:29:23 -06:00
if msgType == CLIENT_ENTER_OBJECT_REQUIRED:
base.cr.handleQuietZoneGenerateWithRequired(di)
elif msgType == CLIENT_ENTER_OBJECT_REQUIRED_OTHER:
base.cr.handleQuietZoneGenerateWithRequiredOther(di)
elif msgType == CLIENT_OBJECT_SET_FIELD:
base.cr.handleQuietZoneUpdateField(di)
elif msgType in QUIET_ZONE_IGNORED_LIST:
self.notify.debug('ignoring unwanted message from previous zone')
else:
base.cr.handlePlayGame(msgType, di)
2019-11-02 17:27:54 -05:00
2021-06-29 12:57:22 -05:00
if not __astron__:
2019-12-05 20:38:58 -06:00
def handleWaitForZoneRedirect(self, msgType, di):
# self.notify.debug('handleWaitForZoneRedirect(' + 'msgType=' + str(msgType) + ', di=' + str(di) + ')')
2019-12-05 20:38:58 -06:00
if msgType == CLIENT_CREATE_OBJECT_REQUIRED:
base.cr.handleQuietZoneGenerateWithRequired(di)
elif msgType == CLIENT_CREATE_OBJECT_REQUIRED_OTHER:
base.cr.handleQuietZoneGenerateWithRequiredOther(di)
elif msgType == CLIENT_OBJECT_UPDATE_FIELD:
base.cr.handleQuietZoneUpdateField(di)
else:
base.cr.handlePlayGame(msgType, di)
else:
def handleWaitForZoneRedirect(self, msgType, di):
# self.notify.debug('handleWaitForZoneRedirect(' + 'msgType=' + str(msgType) + ', di=' + str(di) + ')')
2019-12-05 20:38:58 -06:00
if msgType == CLIENT_ENTER_OBJECT_REQUIRED:
base.cr.handleQuietZoneGenerateWithRequired(di)
elif msgType == CLIENT_ENTER_OBJECT_REQUIRED_OTHER:
base.cr.handleQuietZoneGenerateWithRequiredOther(di)
elif msgType == CLIENT_OBJECT_SET_FIELD:
base.cr.handleQuietZoneUpdateField(di)
else:
base.cr.handlePlayGame(msgType, di)
2019-11-02 17:27:54 -05:00
def enterOff(self):
self.notify.debug('enterOff()')
def exitOff(self):
self.notify.debug('exitOff()')
self._leftQuietZoneCallbacks = PriorityCallbacks()
self._setZoneCompleteCallbacks = PriorityCallbacks()
self._leftQuietZoneLocalCallbacks = {}
self._setZoneCompleteLocalCallbacks = {}
def enterWaitForQuietZoneResponse(self):
# self.notify.debug('enterWaitForQuietZoneResponse(doneStatus=' + str(self._requestStatus) + ')')
2019-11-02 17:27:54 -05:00
if not self.Disable:
base.cr.handler = self.handleWaitForQuietZoneResponse
base.cr.handlerArgs = self._requestStatus
base.cr.setInQuietZone(True)
self.setZoneDoneEvent = base.cr.getNextSetZoneDoneEvent()
self.acceptOnce(self.setZoneDoneEvent, self._handleQuietZoneComplete)
self.waitForDatabase('WaitForQuietZoneResponse')
if base.slowQuietZone:
def sQZR(task):
base.cr.sendQuietZoneRequest()
return Task.done
taskMgr.doMethodLater(base.slowQuietZoneDelay, sQZR, 'slowQuietZone-sendQuietZoneRequest')
else:
base.cr.sendQuietZoneRequest()
def _handleQuietZoneComplete(self):
self.fsm.request('waitForZoneRedirect')
def exitWaitForQuietZoneResponse(self):
self.notify.debug('exitWaitForQuietZoneResponse()')
self.clearWaitForDatabase()
base.cr.handler = base.cr.handlePlayGame
base.cr.handlerArgs = None
base.cr.setInQuietZone(False)
self.ignore(self.setZoneDoneEvent)
del self.setZoneDoneEvent
return
def enterWaitForZoneRedirect(self):
# self.notify.debug('enterWaitForZoneRedirect(requestStatus=' + str(self._requestStatus) + ')')
2019-11-02 17:27:54 -05:00
if not self.Disable:
base.cr.handler = self.handleWaitForZoneRedirect
base.cr.handlerArgs = self._requestStatus
base.cr.setInQuietZone(True)
self.waitForDatabase('WaitForZoneRedirect')
zoneId = self._requestStatus['zoneId']
avId = self._requestStatus.get('avId', -1)
allowRedirect = self._requestStatus.get('allowRedirect', 1)
if avId != -1:
allowRedirect = 0
if not base.cr.welcomeValleyManager:
newZoneId = ZoneUtil.getCanonicalZoneId(zoneId)
if newZoneId != zoneId:
self.gotZoneRedirect(newZoneId)
return
if allowRedirect and ZoneUtil.isWelcomeValley(zoneId):
self.notify.info('Requesting AI redirect from zone %s.' % zoneId)
if base.slowQuietZone:
def rZI(task, zoneId = zoneId, self = self):
base.cr.welcomeValleyManager.requestZoneId(zoneId, self.gotZoneRedirect)
return Task.done
taskMgr.doMethodLater(base.slowQuietZoneDelay, rZI, 'slowQuietZone-welcomeValleyRedirect')
else:
base.cr.welcomeValleyManager.requestZoneId(zoneId, self.gotZoneRedirect)
else:
self.fsm.request('waitForSetZoneResponse')
def gotZoneRedirect(self, zoneId):
if hasattr(self, 'fsm'):
self.notify.info('Redirecting to zone %s.' % zoneId)
base.cr.handlerArgs['zoneId'] = zoneId
base.cr.handlerArgs['hoodId'] = ZoneUtil.getHoodId(zoneId)
self.fsm.request('waitForSetZoneResponse')
2019-11-02 17:27:54 -05:00
def exitWaitForZoneRedirect(self):
self.notify.debug('exitWaitForZoneRedirect()')
self.clearWaitForDatabase()
base.cr.handler = base.cr.handlePlayGame
base.cr.handlerArgs = None
base.cr.setInQuietZone(False)
return
def enterWaitForSetZoneResponse(self):
# self.notify.debug('enterWaitForSetZoneResponse(requestStatus=' + str(self._requestStatus) + ')')
2019-11-02 17:27:54 -05:00
if not self.Disable:
messenger.send(self.getEnterWaitForSetZoneResponseMsg(), [self._requestStatus])
base.cr.handlerArgs = self._requestStatus
zoneId = self._requestStatus['zoneId']
where = self._requestStatus['where']
2019-11-02 17:27:54 -05:00
base.cr.dumpAllSubShardObjects()
base.cr.resetDeletedSubShardDoIds()
if __astron__:
# Add viszones to streets and Cog HQs:
visZones = []
if where == 'street':
visZones = self.getStreetViszones(zoneId)
if zoneId not in visZones:
visZones.append(zoneId)
base.cr.sendSetZoneMsg(zoneId, visZones)
elif where in ('cogHQExterior', 'factoryExterior'):
visZones = self.getCogHQViszones(zoneId)
if zoneId not in visZones:
visZones.append(zoneId)
if len(visZones) < 1 or (len(visZones) == 1 and visZones[0] == zoneId):
base.cr.sendSetZoneMsg(zoneId)
else:
base.cr.sendSetZoneMsg(zoneId, visZones)
else:
base.cr.sendSetZoneMsg(zoneId)
2019-11-02 17:27:54 -05:00
self.waitForDatabase('WaitForSetZoneResponse')
self.fsm.request('waitForSetZoneComplete')
if __astron__:
def getStreetViszones(self, zoneId):
visZones = [ZoneUtil.getBranchZone(zoneId)]
# Assuming that the DNA have been loaded by bulk load before this (see Street.py).
loader = base.cr.playGame.hood.loader
visZones += [loader.node2zone[x] for x in loader.nodeDict[zoneId]]
self.notify.debug(f'getStreetViszones(zoneId={zoneId}): returning visZones: {visZones}')
return visZones
def getCogHQViszones(self, zoneId):
loader = base.cr.playGame.hood.loader
if zoneId in (ToontownGlobals.LawbotOfficeExt, ToontownGlobals.BossbotHQ):
# There are no viszones for these zones, just return an empty list.
return []
# First, we need to load the DNA file for this Cog HQ.
dnaStore = DNAStorage()
dnaFileName = loader.genDNAFileName(zoneId)
loadDNAFileAI(dnaStore, dnaFileName)
# Next, we need to collect all of the visgroup zone IDs.
loader.zoneVisDict = {}
for i in range(dnaStore.getNumDNAVisGroupsAI()):
visGroup = dnaStore.getDNAVisGroupAI(i)
groupFullName = visGroup.getName()
visZoneId = int(base.cr.hoodMgr.extractGroupName(groupFullName))
visZoneId = ZoneUtil.getTrueZoneId(visZoneId, zoneId)
visibles = []
for i in range(visGroup.getNumVisibles()):
visibles.append(int(visGroup.getVisibleName(i)))
# Now we'll store it in the loader since we need them when we enter a Cog battle.
loader.zoneVisDict[visZoneId] = visibles
# Finally, we want interest in all visgroups due to this being a Cog HQ.
visZones = list(loader.zoneVisDict.values())[0]
self.notify.debug(f'getCogHQViszones(zoneId={zoneId}): returning visZones: {visZones}')
return visZones
2019-11-02 17:27:54 -05:00
def exitWaitForSetZoneResponse(self):
self.notify.debug('exitWaitForSetZoneResponse()')
self.clearWaitForDatabase()
base.cr.handler = base.cr.handlePlayGame
base.cr.handlerArgs = None
return
def enterWaitForSetZoneComplete(self):
# self.notify.debug('enterWaitForSetZoneComplete(requestStatus=' + str(self._requestStatus) + ')')
2019-11-02 17:27:54 -05:00
if not self.Disable:
base.cr.handlerArgs = self._requestStatus
if base.slowQuietZone:
def delayFunc(self = self):
def hSZC(task):
self._handleSetZoneComplete()
return Task.done
taskMgr.doMethodLater(base.slowQuietZoneDelay, hSZC, 'slowQuietZone-sendSetZoneComplete')
nextFunc = delayFunc
else:
nextFunc = self._handleSetZoneComplete
self.waitForDatabase('WaitForSetZoneComplete')
self.setZoneDoneEvent = base.cr.getLastSetZoneDoneEvent()
self.acceptOnce(self.setZoneDoneEvent, nextFunc)
if base.placeBeforeObjects:
self._leftQuietZoneCallbacks()
self._leftQuietZoneCallbacks = None
fdcs = list(self._leftQuietZoneLocalCallbacks.values())
2019-11-02 17:27:54 -05:00
self._leftQuietZoneLocalCallbacks = {}
for fdc in fdcs:
if not fdc.isFinished():
fdc.finish()
messenger.send(self.getQuietZoneLeftEvent())
return
def _handleSetZoneComplete(self):
self.fsm.request('waitForLocalAvatarOnShard')
def exitWaitForSetZoneComplete(self):
self.notify.debug('exitWaitForSetZoneComplete()')
self.clearWaitForDatabase()
base.cr.handler = base.cr.handlePlayGame
base.cr.handlerArgs = None
self.ignore(self.setZoneDoneEvent)
del self.setZoneDoneEvent
return
def enterWaitForLocalAvatarOnShard(self):
self.notify.debug('enterWaitForLocalAvatarOnShard()')
if not self.Disable:
base.cr.handlerArgs = self._requestStatus
self._onShardEvent = localAvatar.getArrivedOnDistrictEvent()
self.waitForDatabase('WaitForLocalAvatarOnShard')
if localAvatar.isGeneratedOnDistrict(localAvatar.defaultShard):
self._announceDone()
else:
self.acceptOnce(self._onShardEvent, self._announceDone)
def _announceDone(self):
base.localAvatar.startChat()
if base.endlessQuietZone:
self._dequeue()
return
doneEvent = self.doneEvent
requestStatus = self._requestStatus
self._setZoneCompleteCallbacks()
self._setZoneCompleteCallbacks = None
fdcs = list(self._setZoneCompleteLocalCallbacks.values())
2019-11-02 17:27:54 -05:00
self._setZoneCompleteLocalCallbacks = {}
for fdc in fdcs:
if not fdc.isFinished():
fdc.finish()
messenger.send(self.getSetZoneCompleteEvent(), [requestStatus])
messenger.send(doneEvent)
self._dequeue()
return
def exitWaitForLocalAvatarOnShard(self):
self.notify.debug('exitWaitForLocalAvatarOnShard()')
self.clearWaitForDatabase()
self.ignore(self._onShardEvent)
base.cr.handlerArgs = None
del self._onShardEvent
return