historical/toontown-classic.git/toontown/uberdog/TTGameServicesManagerUD.py
2024-01-16 11:20:27 -06:00

369 lines
17 KiB
Python

from otp.uberdog.GameServicesManagerUD import *
from toontown.makeatoon.NameGenerator import NameGenerator
from toontown.toon.ToonDNA import ToonDNA
from toontown.toonbase import TTLocalizer
def judgeName(name):
return True # TODO: Make this useful.
class SetNamePatternOperation(AvatarOperation):
notify = DirectNotifyGlobal.directNotify.newCategory('SetNamePatternOperation')
postAccountState = 'RetrieveAvatar'
def __init__(self, gameServicesManager, target):
AvatarOperation.__init__(self, gameServicesManager, target)
self.avId = None
self.pattern = None
def enterStart(self, avId, pattern):
# Store these values.
self.avId = avId
self.pattern = pattern
# Retrieve the account.
self.demand('RetrieveAccount')
def enterRetrieveAvatar(self):
# Retrieves the avatar from the database.
if self.avId and self.avId not in self.avList:
# The avatar exists, but it's not an avatar that is
# associated with this account. Kill the connection.
self.demand('Kill', 'Tried to name an avatar not in the account!')
return
# Query the database for the avatar. self.__handleAvatar is
# our callback which will be called upon queryObject's completion.
self.gameServicesManager.air.dbInterface.queryObject(self.gameServicesManager.air.dbId, self.avId,
self.__handleAvatar)
def __handleAvatar(self, dclass, fields):
if dclass != self.gameServicesManager.air.dclassesByName['DistributedToonUD']:
# This dclass is not a valid avatar! Kill the connection.
self.demand('Kill', 'One of the account\'s avatars is invalid!')
return
if fields['WishNameState'][0] != 'OPEN':
# This avatar's wish name state is not set
# to a nameable state. Kill the connection.
self.demand('Kill', 'Avatar is not in a nameable state!')
# Otherwise, we can set the name, so let's enter the SetName state.
self.demand('SetName')
def enterSetName(self):
# Stringify this pattern.
parts = []
for p, f in self.pattern:
part = self.gameServicesManager.nameGenerator.nameDictionary.get(p, ('', ''))[1]
if f:
part = part[:1].upper() + part[1:]
else:
part = part.lower()
parts.append(part)
# This will merge 2 & 3 (the last name), as there should be no space.
parts[2] += parts.pop(3)
while '' in parts:
parts.remove('')
# Construct the final name string.
name = ' '.join(parts)
# We can now update the avatar object with the name.
self.gameServicesManager.air.dbInterface.updateObject(self.gameServicesManager.air.dbId, self.avId,
self.gameServicesManager.air.dclassesByName[
'DistributedToonUD'], {'WishNameState': ('LOCKED',),
'WishName': ('',),
'setName': (name,)})
# We're done. We can now send off the namePatternResponse update through
# the GameServicesManager, and set this operation's state to Off.
self.gameServicesManager.air.writeServerEvent('avatar-named', self.avId, name)
self.gameServicesManager.sendUpdateToAccountId(self.target, 'namePatternResponse', [self.avId, 1])
self.demand('Off')
class SetNameTypedOperation(AvatarOperation):
notify = DirectNotifyGlobal.directNotify.newCategory('SetNameTypedOperation')
postAccountState = 'RetrieveAvatar'
def __init__(self, gameServicesManager, target):
AvatarOperation.__init__(self, gameServicesManager, target)
self.avId = None
self.name = None
def enterStart(self, avId, name):
# SetNameTypedOperation judges the submitted name
# & then sets the avatars wish name state accordingly.
self.avId = avId
self.name = name
if self.avId:
# If avId is not 0, the user is submitting this name,
# so we need to retrieve the account.
self.demand('RetrieveAccount')
return
# Otherwise, avId is 0, meaning that a check request was sent.
self.demand('JudgeName')
def enterRetrieveAvatar(self):
# Retrieves the avatar from the database.
if self.avId and self.avId not in self.avList:
# The avatar exists, but it's not an avatar that is
# associated with this account. Kill the connection.
self.demand('Kill', 'Tried to name an avatar not in the account!')
return
# Query the database for the avatar. self.__handleAvatar is
# our callback which will be called upon queryObject's completion.
self.gameServicesManager.air.dbInterface.queryObject(self.gameServicesManager.air.dbId, self.avId,
self.__handleAvatar)
def __handleAvatar(self, dclass, fields):
if dclass != self.gameServicesManager.air.dclassesByName['DistributedToonUD']:
# This dclass is not a valid avatar! Kill the connection.
self.demand('Kill', 'One of the account\'s avatars is invalid!')
return
if fields['WishNameState'][0] != 'OPEN':
# This avatar's wish name state is not set
# to a nameable state. Kill the connection.
self.demand('Kill', 'Avatar is not in a nameable state!')
# Now we can move on to the judging!
self.demand('JudgeName')
def enterJudgeName(self):
# Let's see if the name is valid.
status = judgeName(self.name)
if self.avId and status:
# Cool, this is a valid name, and we have an avId.
# Let's update their avatar with the new wish name & status.
self.gameServicesManager.air.dbInterface.updateObject(self.gameServicesManager.air.dbId, self.avId,
self.gameServicesManager.air.dclassesByName[
'DistributedToonUD'],
{'WishNameState': ('PENDING',),
'WishName': (self.name,)})
if self.avId:
# If the avId is not 0, log this server event, as the avatar's
# wish name & state have been modified.
self.gameServicesManager.air.writeServerEvent('avatar-wish-name', self.avId, self.name)
# Otherwise, we're done! We can now send the response update
# through the GameServicesManager & set our state to Off.
self.gameServicesManager.sendUpdateToAccountId(self.target, 'nameTypedResponse', [self.avId, status])
self.demand('Off')
class CreateAvatarOperation(GameOperation):
notify = DirectNotifyGlobal.directNotify.newCategory('CreateAvatarOperation')
def __init__(self, gameServicesManager, target):
GameOperation.__init__(self, gameServicesManager, target)
self.index = None
self.dna = None
def enterStart(self, dna, index):
# First, perform some basic sanity checking.
if index >= 6:
# This index is invalid! Kill the connection.
self.demand('Kill', 'Invalid index specified!')
return
if not ToonDNA().isValidNetString(dna):
# This DNA string is invalid! Kill the connection.
self.demand('Kill', 'Invalid DNA specified!')
return
# Store these values.
self.index = index
self.dna = dna
# Now we can query their account.
self.demand('RetrieveAccount')
def enterRetrieveAccount(self):
# Query the sender's account. self.__handleRetrieve is the
# callback that will be called upon queryObject's competion.
self.gameServicesManager.air.dbInterface.queryObject(self.gameServicesManager.air.dbId, self.target,
self.__handleRetrieve)
def __handleRetrieve(self, dclass, fields):
if dclass != self.gameServicesManager.air.dclassesByName['AccountUD']:
# This is not an account object! Kill the connection.
self.demand('Kill', 'Your account object (%s) was not found in the database!' % dclass)
return
# Now we will get our avList.
self.account = fields
self.avList = self.account['ACCOUNT_AV_SET']
# We will now sanitize the avList.
self.avList = self.avList[:6]
self.avList += [0] * (6 - len(self.avList))
# Check if the index is open:
if self.avList[self.index]:
# This index is not open! Kill the connection.
self.demand('Kill', 'This avatar slot is already taken by another avatar!')
return
# All set, now let's create the avatar!
self.demand('CreateAvatar')
def enterCreateAvatar(self):
# We will now construct a new Toon with the given values.
dna = ToonDNA()
dna.makeFromNetString(self.dna)
colorString = TTLocalizer.NumToColor[dna.headColor]
animalType = TTLocalizer.AnimalToSpecies[dna.getAnimal()]
name = ' '.join((colorString, animalType))
toonFields = {'setName': (name,),
'WishNameState': ('OPEN',),
'WishName': ('',),
'setDNAString': (self.dna,),
'setDISLid': (self.target,)}
# Create this new Toon object in the database. self.__handleCreate is the
# callback that will be called upon the completion of createObject.
self.gameServicesManager.air.dbInterface.createObject(self.gameServicesManager.air.dbId,
self.gameServicesManager.air.dclassesByName[
'DistributedToonUD'], toonFields, self.__handleCreate)
def __handleCreate(self, avId):
if not avId:
# The database was unable to create a new avatar object! Kill the connection.
self.demand('Kill', 'Database failed to create the new avatar object!')
return
# We can now store the avatar.
self.avId = avId
self.demand('StoreAvatar')
def enterStoreAvatar(self):
# We will now associate the avatar with the account. self.__handleStoreAvatar is the
# callback which will be called upon the completion of updateObject.
self.avList[self.index] = self.avId
self.gameServicesManager.air.dbInterface.updateObject(self.gameServicesManager.air.dbId, self.target,
self.gameServicesManager.air.dclassesByName['AccountUD'],
{'ACCOUNT_AV_SET': self.avList},
{'ACCOUNT_AV_SET': self.account['ACCOUNT_AV_SET']},
self.__handleStoreAvatar)
def __handleStoreAvatar(self, fields):
if fields:
# The new avatar was not associated with the account! Kill the connection.
self.demand('Kill', 'Database failed to associate the new avatar to your account!')
return
# Otherwise, we're done! We can now send the createAvatarResponse update
# through the GameServicesManager & set this operation's state to Off.
self.gameServicesManager.air.writeServerEvent('avatar-created', self.avId, self.target, self.dna.encode('hex'),
self.index)
self.gameServicesManager.sendUpdateToAccountId(self.target, 'createAvatarResponse', [self.avId])
self.demand('Off')
class AcknowledgeNameOperation(AvatarOperation):
notify = DirectNotifyGlobal.directNotify.newCategory('AcknowledgeNameFSM')
postAccountState = 'GetTargetAvatar'
def __init__(self, gameServicesManager, target):
AvatarOperation.__init__(self, gameServicesManager, target)
self.avId = None
def enterStart(self, avId):
# Store this value & move on to RetrieveAccount.
self.avId = avId
self.demand('RetrieveAccount')
def enterGetTargetAvatar(self):
# Make sure that the target avatar is part of the account:
if self.avId not in self.avList:
# The sender tried to acknowledge name on an avatar not on the account!
# Kill the connection.
self.demand('Kill', 'Tried to acknowledge name on an avatar not in the account!')
return
# We can now query the database for the avatar. self.__handleAvatar is the
# callback which will be called upon the completion of queryObject.
self.gameServicesManager.air.dbInterface.queryObject(self.gameServicesManager.air.dbId, self.avId,
self.__handleAvatar)
def __handleAvatar(self, dclass, fields):
if dclass != self.gameServicesManager.air.dclassesByName['DistributedToonUD']:
# This dclass is not a valid avatar! Kill the connection.
self.demand('Kill', 'One of the account\'s avatars is invalid!')
return
# Process the WishNameState change.
wishNameState = fields['WishNameState'][0]
wishName = fields['WishName'][0]
name = fields['setName'][0]
if wishNameState == 'APPROVED':
wishNameState = 'LOCKED'
name = wishName
wishName = ''
elif wishNameState == 'REJECTED':
wishNameState = 'OPEN'
wishName = ''
else:
# The sender is trying to acknowledge name on avatar in invalid state! Kill the connection.
self.demand('Kill', 'Tried to acknowledge name on an avatar in invalid state (%s) !' % wishNameState)
return
# We can now update the avatar object in the database with the changes!
self.gameServicesManager.air.dbInterface.updateObject(self.gameServicesManager.air.dbId, self.avId,
self.gameServicesManager.air.dclassesByName[
'DistributedToonUD'],
{'WishNameState': (wishNameState,),
'WishName': (wishName,),
'setName': (name,)},
{'WishNameState': fields['WishNameState'],
'WishName': fields['WishName'],
'setName': fields['setName']})
# We're done. We can now send off the acknowledgeAvatarNameResponse update
# through the GameServicesManager, and set this operation's state to Off.
self.gameServicesManager.sendUpdateToAccountId(self.target, 'acknowledgeAvatarNameResponse', [])
self.demand('Off')
class TTGameServicesManagerUD(GameServicesManagerUD):
notify = DirectNotifyGlobal.directNotify.newCategory('TTGameServicesManagerUD')
avatarDclass = 'DistributedToonUD'
def __init__(self, air):
GameServicesManagerUD.__init__(self, air)
self.nameGenerator = None
def announceGenerate(self):
GameServicesManagerUD.announceGenerate(self)
# This is for processing name patterns.
self.nameGenerator = NameGenerator()
def setNamePattern(self, avId, p1, f1, p2, f2, p3, f3, p4, f4):
# Someone has used a pattern name; run a SetNamePatternOperation.
self.runOperation(SetNamePatternOperation, avId, [(p1, f1), (p2, f2),
(p3, f3), (p4, f4)])
def setNameTyped(self, avId, name):
# Someone has typed a name; run a SetNameTypedOperation.
self.runOperation(SetNameTypedOperation, avId, name)
def createAvatar(self, dna, index):
# Someone wants to create a new avatar;
# run a CreateAvatarOperation.
self.runOperation(CreateAvatarOperation, dna, index)
def acknowledgeAvatarName(self, avId):
# Someone has acknowledged their name; run an AcknowledgeNameOperation.
self.runOperation(AcknowledgeNameOperation, avId)