649 lines
No EOL
23 KiB
Python
649 lines
No EOL
23 KiB
Python
from direct.directnotify import DirectNotifyGlobal
|
|
from direct.distributed.DistributedObjectAI import DistributedObjectAI
|
|
import functools
|
|
|
|
from direct.directnotify import DirectNotifyGlobal
|
|
from direct.distributed.DistributedObjectAI import DistributedObjectAI
|
|
from direct.fsm.FSM import FSM
|
|
|
|
from toontown.estate import HouseGlobals
|
|
from toontown.estate.DistributedHouseAI import DistributedHouseAI
|
|
from toontown.toon import ToonDNA
|
|
|
|
|
|
class LoadHouseOperation(FSM):
|
|
def __init__(self, mgr, estate, index, avatar, callback):
|
|
FSM.__init__(self, 'LoadHouseOperation')
|
|
self.mgr = mgr
|
|
self.estate = estate
|
|
self.index = index
|
|
self.avatar = avatar
|
|
self.callback = callback
|
|
self.done = False
|
|
self.houseId = None
|
|
self.house = None
|
|
self.gender = None
|
|
|
|
def start(self):
|
|
# We have a few different cases here:
|
|
if self.avatar is None:
|
|
# Case #1: There isn't an avatar in that estate slot. Make a blank house.
|
|
# Because this state completes so fast, we'll use taskMgr to delay
|
|
# it until the next iteration. This solves reentrancy problems.
|
|
taskMgr.doMethodLater(0.0, self.demand, 'makeBlankHouse-%s' % id(self), extraArgs=['MakeBlankHouse'])
|
|
return
|
|
|
|
style = ToonDNA.ToonDNA()
|
|
style.makeFromNetString(self.avatar.get('setDNAString')[0])
|
|
self.houseId = self.avatar.get('setHouseId', [0])[0]
|
|
self.gender = style.gender
|
|
if self.houseId == 0:
|
|
# Case #2: There is an avatar, but no setHouseId. Make a new house:
|
|
self.demand('CreateHouse')
|
|
else:
|
|
# Case #3: Avatar with a setHouseId. Load it:
|
|
self.demand('LoadHouse')
|
|
|
|
def enterMakeBlankHouse(self):
|
|
self.house = DistributedHouseAI(self.mgr.air)
|
|
self.house.setHousePos(self.index)
|
|
self.house.setColor(self.index)
|
|
self.house.generateWithRequired(self.estate.zoneId)
|
|
self.estate.houses[self.index] = self.house
|
|
self.demand('Off')
|
|
|
|
def enterCreateHouse(self):
|
|
self.mgr.air.dbInterface.createObject(self.mgr.air.dbId, self.mgr.air.dclassesByName['DistributedHouseAI'],
|
|
{'setName': [self.avatar['setName'][0]],
|
|
'setAvatarId': [self.avatar['avId']]}, self.__handleHouseCreated)
|
|
|
|
def __handleHouseCreated(self, houseId):
|
|
if self.state != 'CreateHouse':
|
|
# This operation was likely aborted.
|
|
return
|
|
|
|
# Update the avatar's houseId:
|
|
av = self.mgr.air.doId2do.get(self.avatar['avId'])
|
|
if av:
|
|
av.b_setHouseId(houseId)
|
|
else:
|
|
self.mgr.air.dbInterface.updateObject(self.mgr.air.dbId, self.avatar['avId'],
|
|
self.mgr.air.dclassesByName['DistributedToonAI'],
|
|
{'setHouseId': [houseId]})
|
|
|
|
self.houseId = houseId
|
|
self.demand('LoadHouse')
|
|
|
|
def enterLoadHouse(self):
|
|
# Activate the house:
|
|
self.mgr.air.sendActivate(self.houseId, self.mgr.air.districtId, self.estate.zoneId,
|
|
self.mgr.air.dclassesByName['DistributedHouseAI'],
|
|
{'setHousePos': [self.index],
|
|
'setColor': [self.index],
|
|
'setName': [self.avatar['setName'][0]],
|
|
'setAvatarId': [self.avatar['avId']]})
|
|
|
|
# Wait for the house to generate:
|
|
self.acceptOnce('generate-%d' % self.houseId, self.__handleHouseGenerated)
|
|
|
|
def __handleHouseGenerated(self, house):
|
|
# The house will need to be able to reference
|
|
# the estate for setting up gardens, so:
|
|
house.estate = self.estate
|
|
|
|
# Initialize our interior:
|
|
house.interior.gender = self.gender
|
|
house.interior.start()
|
|
|
|
self.house = house
|
|
self.estate.houses[self.index] = self.house
|
|
if config.GetBool('want-gardening', False):
|
|
# Initialize our garden:
|
|
self.house.createGardenManager()
|
|
|
|
self.demand('Off')
|
|
|
|
def exitLoadHouse(self):
|
|
self.ignore('generate-%d' % self.houseId)
|
|
|
|
def enterOff(self):
|
|
self.done = True
|
|
self.callback(self.house)
|
|
|
|
|
|
class LoadEstateOperation(FSM):
|
|
def __init__(self, mgr, callback):
|
|
FSM.__init__(self, 'LoadEstateOperation')
|
|
self.mgr = mgr
|
|
self.callback = callback
|
|
self.estate = None
|
|
self.accId = None
|
|
self.zoneId = None
|
|
self.avIds = None
|
|
self.avatars = None
|
|
self.houseOperations = None
|
|
self.petOperations = None
|
|
|
|
def start(self, accId, zoneId):
|
|
self.accId = accId
|
|
self.zoneId = zoneId
|
|
self.demand('QueryAccount')
|
|
|
|
def enterQueryAccount(self):
|
|
self.mgr.air.dbInterface.queryObject(self.mgr.air.dbId, self.accId, self.__handleQueryAccount)
|
|
|
|
def __handleQueryAccount(self, dclass, fields):
|
|
if self.state != 'QueryAccount':
|
|
# This operation was likely aborted.
|
|
return
|
|
|
|
if dclass != self.mgr.air.dclassesByName['AccountAI']:
|
|
self.mgr.notify.warning('Account %d has non-account dclass %d!' % (self.accId, dclass))
|
|
self.demand('Failure')
|
|
return
|
|
|
|
self.accFields = fields
|
|
self.estateId = fields.get('ESTATE_ID', 0)
|
|
self.demand('QueryAvatars')
|
|
|
|
def enterQueryAvatars(self):
|
|
self.avIds = self.accFields.get('ACCOUNT_AV_SET', [0] * 6)
|
|
self.avatars = {}
|
|
for index, avId in enumerate(self.avIds):
|
|
if avId == 0:
|
|
self.avatars[index] = None
|
|
continue
|
|
|
|
self.mgr.air.dbInterface.queryObject(self.mgr.air.dbId, avId,
|
|
functools.partial(self.__handleQueryAvatar, index=index))
|
|
|
|
def __handleQueryAvatar(self, dclass, fields, index):
|
|
if self.state != 'QueryAvatars':
|
|
# This operation was likely aborted.
|
|
return
|
|
|
|
if dclass != self.mgr.air.dclassesByName['DistributedToonAI']:
|
|
self.mgr.notify.warning(
|
|
'Account %d has avatar %d with non-Toon dclass %d!' % (self.accId, self.avIds[index], dclass))
|
|
self.demand('Failure')
|
|
return
|
|
|
|
fields['avId'] = self.avIds[index]
|
|
self.avatars[index] = fields
|
|
if len(self.avatars) == 6:
|
|
self.__gotAllAvatars()
|
|
|
|
def __gotAllAvatars(self):
|
|
# We have all of our avatars, so now we can handle the estate.
|
|
if self.estateId:
|
|
# We already have an estate, so let's load that:
|
|
self.demand('LoadEstate')
|
|
else:
|
|
# We don't yet have an estate, so let's make one:
|
|
self.demand('CreateEstate')
|
|
|
|
def enterCreateEstate(self):
|
|
# Create a blank estate object:
|
|
self.mgr.air.dbInterface.createObject(self.mgr.air.dbId, self.mgr.air.dclassesByName['DistributedEstateAI'], {},
|
|
self.__handleEstateCreated)
|
|
|
|
def __handleEstateCreated(self, estateId):
|
|
if self.state != 'CreateEstate':
|
|
# This operation was likely aborted.
|
|
return
|
|
|
|
self.estateId = estateId
|
|
|
|
# Store the new estate object on our account:
|
|
self.mgr.air.dbInterface.updateObject(self.mgr.air.dbId, self.accId, self.mgr.air.dclassesByName['AccountAI'],
|
|
{'ESTATE_ID': estateId})
|
|
|
|
self.demand('LoadEstate')
|
|
|
|
def enterLoadEstate(self):
|
|
# Set the estate fields:
|
|
fields = {'setSlot%dToonId' % i: (avId,) for i, avId in enumerate(self.avIds)}
|
|
|
|
# Activate the estate:
|
|
self.mgr.air.sendActivate(self.estateId, self.mgr.air.districtId, self.zoneId,
|
|
self.mgr.air.dclassesByName['DistributedEstateAI'], fields)
|
|
|
|
# Wait for the estate to generate:
|
|
self.acceptOnce('generate-%d' % self.estateId, self.__handleEstateGenerated)
|
|
|
|
def __handleEstateGenerated(self, estate):
|
|
# Get the estate:
|
|
self.estate = estate
|
|
|
|
# For keeping track of pets in this estate:
|
|
self.estate.pets = []
|
|
|
|
# Map the owner to the estate:
|
|
ownerId = self.mgr.getOwnerFromZone(self.estate.zoneId)
|
|
owner = self.mgr.air.doId2do.get(ownerId)
|
|
if owner:
|
|
self.mgr.toon2estate[owner] = self.estate
|
|
|
|
# Set the estate's ID list:
|
|
self.estate.b_setIdList(self.avIds)
|
|
|
|
# Load houses:
|
|
self.demand('LoadHouses')
|
|
|
|
def exitLoadEstate(self):
|
|
self.ignore('generate-%d' % self.estateId)
|
|
|
|
def enterLoadHouses(self):
|
|
self.houseOperations = []
|
|
for houseIndex in xrange(6):
|
|
houseOperation = LoadHouseOperation(self.mgr, self.estate, houseIndex, self.avatars[houseIndex],
|
|
self.__handleHouseLoaded)
|
|
self.houseOperations.append(houseOperation)
|
|
houseOperation.start()
|
|
|
|
def __handleHouseLoaded(self, house):
|
|
if self.state != 'LoadHouses':
|
|
# We aren't loading houses, so we probably got cancelled. Therefore,
|
|
# the only sensible thing to do is simply destroy the house.
|
|
house.requestDelete()
|
|
return
|
|
|
|
# A house operation just finished! Let's see if all of them are done:
|
|
if all(houseOperation.done for houseOperation in self.houseOperations):
|
|
# Load our pets:
|
|
self.demand('LoadPets')
|
|
|
|
def enterLoadPets(self):
|
|
self.petOperations = []
|
|
for houseIndex in xrange(6):
|
|
av = self.avatars[houseIndex]
|
|
if av and av['setPetId'][0] != 0:
|
|
petOperation = LoadPetOperation(self.mgr, self.estate, av, self.__handlePetLoaded)
|
|
self.petOperations.append(petOperation)
|
|
petOperation.start()
|
|
|
|
if not self.petOperations:
|
|
taskMgr.doMethodLater(0, lambda: self.demand('Finished'), 'no-pets', extraArgs=[])
|
|
|
|
def __handlePetLoaded(self, pet):
|
|
if self.state != 'LoadPets':
|
|
pet.requestDelete()
|
|
return
|
|
|
|
# A pet operation just finished! Let's see if all of them are done:
|
|
if all(petOperation.done for petOperation in self.petOperations):
|
|
self.demand('Finished')
|
|
|
|
def enterFinished(self):
|
|
self.petOperations = []
|
|
self.callback(True)
|
|
|
|
def enterFailure(self):
|
|
self.cancel()
|
|
self.callback(False)
|
|
|
|
def cancel(self):
|
|
if self.estate:
|
|
self.estate.destroy()
|
|
self.estate = None
|
|
|
|
self.demand('Off')
|
|
|
|
|
|
class LoadPetOperation(FSM):
|
|
def __init__(self, mgr, estate, toon, callback):
|
|
FSM.__init__(self, 'LoadPetFSM')
|
|
self.mgr = mgr
|
|
self.estate = estate
|
|
self.toon = toon
|
|
self.callback = callback
|
|
self.done = False
|
|
self.petId = 0
|
|
|
|
def start(self):
|
|
if type(self.toon) == dict:
|
|
self.petId = self.toon['setPetId'][0]
|
|
else:
|
|
self.petId = self.toon.getPetId()
|
|
|
|
if self.petId not in self.mgr.air.doId2do:
|
|
self.mgr.air.sendActivate(self.petId, self.mgr.air.districtId, self.estate.zoneId)
|
|
self.acceptOnce('generate-%d' % self.petId, self.__generated)
|
|
else:
|
|
self.__generated(self.mgr.air.doId2do[self.petId])
|
|
|
|
def __generated(self, pet):
|
|
self.pet = pet
|
|
self.estate.pets.append(pet)
|
|
self.demand('Off')
|
|
|
|
def enterOff(self):
|
|
self.ignore('generate-%d' % self.petId)
|
|
self.done = True
|
|
self.callback(self.pet)
|
|
|
|
|
|
class EstateManagerAI(DistributedObjectAI):
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('EstateManagerAI')
|
|
|
|
def __init__(self, air):
|
|
DistributedObjectAI.__init__(self, air)
|
|
self.toon2estate = {}
|
|
self.estate = {}
|
|
self.estate2toons = {}
|
|
self.estate2timeout = {}
|
|
self.zone2toons = {}
|
|
self.zone2owner = {}
|
|
self.petOperations = []
|
|
|
|
def getEstateZone(self, avId, name):
|
|
# Thank you name, very cool!
|
|
senderId = self.air.getAvatarIdFromSender()
|
|
accId = self.air.getAccountIdFromSender()
|
|
senderAv = self.air.doId2do.get(senderId)
|
|
if not senderAv:
|
|
self.air.writeServerEvent('suspicious', senderId, 'Sent getEstateZone() but not on district!')
|
|
return
|
|
|
|
# If an avId has been provided, then the sender wants to visit a friend.
|
|
# In this case, we do not need to load the estate, we only need to check
|
|
# to see if it already exists.
|
|
if avId and avId != senderId:
|
|
av = self.air.doId2do.get(avId)
|
|
if av and av.dclass == self.air.dclassesByName['DistributedToonAI']:
|
|
estate = self.toon2estate.get(av)
|
|
if estate:
|
|
# Found an estate!
|
|
avId = estate.owner.doId
|
|
zoneId = estate.zoneId
|
|
self._mapToEstate(senderAv, estate)
|
|
|
|
# In case the sender is teleporting from their estate
|
|
# to another estate, we want to unload their estate.
|
|
self._unloadEstate(senderAv)
|
|
|
|
if senderAv and senderAv.getPetId() != 0:
|
|
pet = self.air.doId2do.get(senderAv.getPetId())
|
|
if pet:
|
|
self.acceptOnce(self.air.getAvatarExitEvent(senderAv.getPetId()), self.__handleLoadPet,
|
|
extraArgs=[estate, senderAv])
|
|
pet.requestDelete()
|
|
else:
|
|
self.__handleLoadPet(estate, senderAv)
|
|
|
|
# Now we want to send the sender to the estate.
|
|
if hasattr(senderAv, 'enterEstate'):
|
|
senderAv.enterEstate(avId, zoneId)
|
|
|
|
self.sendUpdateToAvatarId(senderId, 'setEstateZone', [avId, zoneId])
|
|
|
|
# We weren't able to find the given avId at an estate, that's pretty sad.
|
|
self.sendUpdateToAvatarId(senderId, 'setEstateZone', [0, 0])
|
|
return
|
|
|
|
# Otherwise, the sender wants to go to their own estate.
|
|
estate = getattr(senderAv, 'estate', None)
|
|
if estate:
|
|
# The sender already has an estate loaded, so let's send them there.
|
|
self._mapToEstate(senderAv, senderAv.estate)
|
|
|
|
if senderAv and senderAv.getPetId() != 0:
|
|
pet = self.air.doId2do.get(senderAv.getPetId())
|
|
if pet:
|
|
self.acceptOnce(self.air.getAvatarExitEvent(senderAv.getPetId()), self.__handleLoadPet,
|
|
extraArgs=[estate, senderAv])
|
|
pet.requestDelete()
|
|
else:
|
|
self.__handleLoadPet(estate, senderAv)
|
|
|
|
if hasattr(senderAv, 'enterEstate'):
|
|
senderAv.enterEstate(senderId, estate.zoneId)
|
|
|
|
self.sendUpdateToAvatarId(senderId, 'setEstateZone', [senderId, estate.zoneId])
|
|
|
|
# If a timeout is active, cancel it:
|
|
if estate in self.estate2timeout:
|
|
self.estate2timeout[estate].remove()
|
|
del self.estate2timeout[estate]
|
|
|
|
return
|
|
|
|
if getattr(senderAv, 'loadEstateOperation', None):
|
|
# We already have a loading operation underway; ignore this second
|
|
# request since the first operation will setEstateZone() when it
|
|
# finishes anyway.
|
|
return
|
|
|
|
zoneId = self.air.allocateZone()
|
|
self.zone2owner[zoneId] = avId
|
|
|
|
def estateLoaded(success):
|
|
if success:
|
|
senderAv.estate = senderAv.loadEstateOperation.estate
|
|
senderAv.estate.owner = senderAv
|
|
self._mapToEstate(senderAv, senderAv.estate)
|
|
if hasattr(senderAv, 'enterEstate'):
|
|
senderAv.enterEstate(senderId, zoneId)
|
|
|
|
self.sendUpdateToAvatarId(senderId, 'setEstateZone', [senderId, zoneId])
|
|
else:
|
|
# Estate loading failed. Sad!
|
|
self.sendUpdateToAvatarId(senderId, 'setEstateZone', [0, 0])
|
|
|
|
# Might as well free up the zoneId as well.
|
|
self.air.deallocateZone(zoneId)
|
|
del self.zone2owner[zoneId]
|
|
|
|
senderAv.loadEstateOperation = None
|
|
|
|
self.acceptOnce(self.air.getAvatarExitEvent(senderAv.doId), self.__handleUnexpectedExit, extraArgs=[senderAv])
|
|
|
|
if senderAv and senderAv.getPetId() != 0:
|
|
pet = self.air.doId2do.get(senderAv.getPetId())
|
|
if pet:
|
|
self.acceptOnce(self.air.getAvatarExitEvent(senderAv.getPetId()), self.__handleLoadEstate,
|
|
extraArgs=[senderAv, estateLoaded, accId, zoneId])
|
|
pet.requestDelete()
|
|
return
|
|
|
|
self.__handleLoadEstate(senderAv, estateLoaded, accId, zoneId)
|
|
|
|
def __handleUnexpectedExit(self, senderAv):
|
|
self._unmapFromEstate(senderAv)
|
|
self._unloadEstate(senderAv)
|
|
|
|
def exitEstate(self):
|
|
senderId = self.air.getAvatarIdFromSender()
|
|
senderAv = self.air.doId2do.get(senderId)
|
|
if not senderAv:
|
|
self.air.writeServerEvent('suspicious', senderId, 'Sent exitEstate() but not on district!')
|
|
return
|
|
|
|
self._unmapFromEstate(senderAv)
|
|
self._unloadEstate(senderAv)
|
|
|
|
def removeFriend(self, ownerId, avId):
|
|
if not (ownerId or avId):
|
|
return
|
|
|
|
owner = self.air.doId2do.get(ownerId)
|
|
if not owner:
|
|
return
|
|
|
|
friend = self.air.doId2do.get(avId)
|
|
if not friend:
|
|
return
|
|
|
|
estate = self.estate.get(ownerId)
|
|
if not estate:
|
|
return
|
|
|
|
if ownerId not in estate.getIdList():
|
|
return
|
|
|
|
toons = self.estate2toons.get(estate, [])
|
|
if owner not in toons and friend not in toons:
|
|
return
|
|
|
|
friendInList = False
|
|
for friendPair in owner.getFriendsList():
|
|
if type(friendPair) == tuple:
|
|
friendId = friendPair[0]
|
|
else:
|
|
friendId = friendPair
|
|
|
|
if friendId == avId:
|
|
friendInList = True
|
|
break
|
|
|
|
if not friendInList:
|
|
self.sendUpdateToAvatarId(friend.doId, 'sendAvToPlayground', [friend.doId, 1])
|
|
|
|
def _unloadEstate(self, av):
|
|
if getattr(av, 'estate', None):
|
|
estate = av.estate
|
|
if estate not in self.estate2timeout:
|
|
self.estate2timeout[estate] = taskMgr.doMethodLater(HouseGlobals.BOOT_GRACE_PERIOD, self._cleanupEstate,
|
|
estate.uniqueName('unload-estate'),
|
|
extraArgs=[estate])
|
|
|
|
# Send warning:
|
|
self._sendToonsToPlayground(av.estate, 0)
|
|
|
|
if getattr(av, 'loadEstateOperation', None):
|
|
self.air.deallocateZone(av.loadEstateOperation.zoneId)
|
|
av.loadEstateOperation.cancel()
|
|
av.loadEstateOperation = None
|
|
|
|
if av and hasattr(av, 'exitEstate') and hasattr(av, 'isInEstate') and av.isInEstate():
|
|
av.exitEstate()
|
|
|
|
if av and av.getPetId() != 0:
|
|
self.ignore(self.air.getAvatarExitEvent(av.getPetId()))
|
|
pet = self.air.doId2do.get(av.getPetId())
|
|
if pet:
|
|
pet.requestDelete()
|
|
|
|
self.ignore(self.air.getAvatarExitEvent(av.doId))
|
|
|
|
def _mapToEstate(self, av, estate):
|
|
self._unmapFromEstate(av)
|
|
self.estate[av.doId] = estate
|
|
self.estate2toons.setdefault(estate, []).append(av)
|
|
if av not in self.toon2estate:
|
|
self.toon2estate[av] = estate
|
|
|
|
self.zone2toons.setdefault(estate.zoneId, []).append(av.doId)
|
|
|
|
def _unmapFromEstate(self, av):
|
|
estate = self.toon2estate.get(av)
|
|
if not estate:
|
|
return
|
|
|
|
try:
|
|
del self.estate[av.doId]
|
|
except KeyError:
|
|
pass
|
|
|
|
del self.toon2estate[av]
|
|
try:
|
|
self.estate2toons[estate].remove(av)
|
|
except (KeyError, ValueError):
|
|
pass
|
|
|
|
try:
|
|
self.zone2toons[estate.zoneId].remove(av.doId)
|
|
except (KeyError, ValueError):
|
|
pass
|
|
|
|
def _cleanupEstate(self, estate):
|
|
# Boot all avatars from estate:
|
|
self._sendToonsToPlayground(estate, 1)
|
|
|
|
# Clean up avatar <-> estate mappings:
|
|
for av in self.estate2toons.get(estate, []):
|
|
try:
|
|
del self.estate[av.doId]
|
|
del self.toon2estate[av]
|
|
except KeyError:
|
|
pass
|
|
|
|
try:
|
|
del self.estate2toons[estate]
|
|
except KeyError:
|
|
pass
|
|
|
|
try:
|
|
del self.zone2toons[estate.zoneId]
|
|
except KeyError:
|
|
pass
|
|
|
|
# Clean up timeout, if it exists:
|
|
if estate in self.estate2timeout:
|
|
del self.estate2timeout[estate]
|
|
|
|
# Destroy estate and unmap from owner:
|
|
estate.destroy()
|
|
estate.owner.estate = None
|
|
|
|
# Destroy pets:
|
|
for pet in estate.pets:
|
|
pet.requestDelete()
|
|
|
|
estate.pets = []
|
|
|
|
# Free estate's zone:
|
|
self.air.deallocateZone(estate.zoneId)
|
|
del self.zone2owner[estate.zoneId]
|
|
|
|
def _sendToonsToPlayground(self, estate, reason):
|
|
for toon in self.estate2toons.get(estate, []):
|
|
self.sendUpdateToAvatarId(toon.doId, 'sendAvToPlayground', [toon.doId, reason])
|
|
|
|
def getEstateZones(self, ownerId):
|
|
toon = self.air.doId2do.get(ownerId)
|
|
if not toon:
|
|
return []
|
|
|
|
estate = self.toon2estate.get(toon)
|
|
if not estate:
|
|
return []
|
|
|
|
return [estate.zoneId]
|
|
|
|
def getEstateHouseZones(self, ownerId):
|
|
houseZones = []
|
|
toon = self.air.doId2do.get(ownerId)
|
|
if not toon:
|
|
return houseZones
|
|
|
|
estate = self.toon2estate.get(toon)
|
|
if not estate:
|
|
return houseZones
|
|
|
|
houses = estate.houses
|
|
for house in houses:
|
|
houseZones.append(house.interiorZone)
|
|
|
|
return houseZones
|
|
|
|
def _lookupEstate(self, toon):
|
|
return self.toon2estate.get(toon)
|
|
|
|
def getOwnerFromZone(self, zoneId):
|
|
return self.zone2owner.get(zoneId, 0)
|
|
|
|
def __handleLoadPet(self, estate, av):
|
|
petOperation = LoadPetOperation(self, estate, av, self.__handlePetLoaded)
|
|
self.petOperations.append(petOperation)
|
|
petOperation.start()
|
|
|
|
def __handlePetLoaded(self, _):
|
|
# A pet operation just finished! Let's see if all of them are done:
|
|
if all(petOperation.done for petOperation in self.petOperations):
|
|
self.petOperations = []
|
|
|
|
def __handleLoadEstate(self, av, callback, accId, zoneId):
|
|
self._unmapFromEstate(av)
|
|
av.loadEstateOperation = LoadEstateOperation(self, callback)
|
|
av.loadEstateOperation.start(accId, zoneId) |