489 lines
19 KiB
Python
489 lines
19 KiB
Python
|
from direct.directnotify import DirectNotifyGlobal
|
||
|
from direct.distributed.DistributedObjectGlobalUD import DistributedObjectGlobalUD
|
||
|
from direct.distributed.PyDatagram import *
|
||
|
|
||
|
from otp.otpbase import OTPGlobals
|
||
|
|
||
|
|
||
|
class FriendsOperation:
|
||
|
|
||
|
def __init__(self, friendsManager, sender):
|
||
|
self.friendsManager = friendsManager
|
||
|
self.sender = sender
|
||
|
|
||
|
def _handleDone(self):
|
||
|
# TODO
|
||
|
pass
|
||
|
|
||
|
def _handleError(self, error):
|
||
|
# TODO
|
||
|
pass
|
||
|
|
||
|
|
||
|
class GetFriendsListOperation(FriendsOperation):
|
||
|
|
||
|
def __init__(self, friendsManager, sender):
|
||
|
FriendsOperation.__init__(self, friendsManager, sender)
|
||
|
self.friendsList = None
|
||
|
self.tempFriendsList = None
|
||
|
self.onlineFriends = None
|
||
|
self.currentFriendIdx = None
|
||
|
|
||
|
def start(self):
|
||
|
self.friendsList = []
|
||
|
self.tempFriendsList = []
|
||
|
self.onlineFriends = []
|
||
|
self.currentFriendIdx = 0
|
||
|
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, self.sender,
|
||
|
self.__handleSenderRetrieved)
|
||
|
|
||
|
def __handleSenderRetrieved(self, dclass, fields):
|
||
|
if dclass != self.friendsManager.air.dclassesByName['DistributedToonUD']:
|
||
|
self._handleError('Retrieved sender is not a DistributedToonUD!')
|
||
|
return
|
||
|
|
||
|
self.tempFriendsList = fields['setFriendsList'][0]
|
||
|
if len(self.tempFriendsList) <= 0:
|
||
|
self._handleDone()
|
||
|
return
|
||
|
|
||
|
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, self.tempFriendsList[0][0],
|
||
|
self.__handleFriendRetrieved)
|
||
|
|
||
|
def __handleFriendRetrieved(self, dclass, fields):
|
||
|
if dclass != self.friendsManager.air.dclassesByName['DistributedToonUD']:
|
||
|
self._handleError('Retrieved friend is not a DistributedToonUD!')
|
||
|
return
|
||
|
|
||
|
friendId = self.tempFriendsList[self.currentFriendIdx][0]
|
||
|
self.friendsList.append([friendId, fields['setName'][0], fields['setDNAString'][0], fields['setPetId'][0]])
|
||
|
if len(self.friendsList) >= len(self.tempFriendsList):
|
||
|
self.__checkFriendsOnline()
|
||
|
return
|
||
|
|
||
|
self.currentFriendIdx += 1
|
||
|
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId,
|
||
|
self.tempFriendsList[self.currentFriendIdx][0],
|
||
|
self.__handleFriendRetrieved)
|
||
|
|
||
|
def __checkFriendsOnline(self):
|
||
|
self.currentFriendIdx = 0
|
||
|
for friendDetails in self.friendsList:
|
||
|
self.friendsManager.air.getActivated(friendDetails[0], self.__gotActivatedResp)
|
||
|
|
||
|
def __gotActivatedResp(self, avId, activated):
|
||
|
self.currentFriendIdx += 1
|
||
|
if activated:
|
||
|
self.onlineFriends.append(avId)
|
||
|
|
||
|
if self.currentFriendIdx >= len(self.friendsList):
|
||
|
self._handleDone()
|
||
|
|
||
|
def __sendFriendsList(self, success):
|
||
|
self.friendsManager.sendUpdateToAvatarId(self.sender, 'getFriendsListResponse', [success, self.friendsList if success else []])
|
||
|
for friendId in self.onlineFriends:
|
||
|
self.friendsManager.sendFriendOnline(self.sender, friendId, 0, 1)
|
||
|
|
||
|
def _handleDone(self):
|
||
|
self.__sendFriendsList(True)
|
||
|
FriendsOperation._handleDone(self)
|
||
|
|
||
|
def _handleError(self, error):
|
||
|
self.__sendFriendsList(False)
|
||
|
FriendsOperation._handleError(self, error)
|
||
|
|
||
|
|
||
|
class GetAvatarDetailsOperation(FriendsOperation):
|
||
|
|
||
|
def __init__(self, friendsManager, sender):
|
||
|
FriendsOperation.__init__(self, friendsManager, sender)
|
||
|
self.avId = None
|
||
|
self.dclass = None
|
||
|
self.fields = None
|
||
|
|
||
|
def start(self, avId):
|
||
|
self.avId = avId
|
||
|
self.fields = {}
|
||
|
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, avId,
|
||
|
self.__handleAvatarRetrieved)
|
||
|
|
||
|
def __handleAvatarRetrieved(self, dclass, fields):
|
||
|
if dclass not in (self.friendsManager.air.dclassesByName['DistributedToonUD'],
|
||
|
self.friendsManager.air.dclassesByName['DistributedPetAI']):
|
||
|
self._handleError('Retrieved avatar is not a DistributedToonUD or DistributedPetAI!')
|
||
|
return
|
||
|
|
||
|
self.dclass = dclass
|
||
|
self.fields = fields
|
||
|
self.fields['avId'] = self.avId
|
||
|
self._handleDone()
|
||
|
|
||
|
def __packAvatarDetails(self, dclass, fields):
|
||
|
# Pack required fields.
|
||
|
fieldPacker = DCPacker()
|
||
|
for i in range(dclass.getNumInheritedFields()):
|
||
|
field = dclass.getInheritedField(i)
|
||
|
if not field.isRequired() or field.asMolecularField():
|
||
|
continue
|
||
|
|
||
|
k = field.getName()
|
||
|
v = fields.get(k, None)
|
||
|
|
||
|
fieldPacker.beginPack(field)
|
||
|
if not v:
|
||
|
fieldPacker.packDefaultValue()
|
||
|
else:
|
||
|
field.packArgs(fieldPacker, v)
|
||
|
|
||
|
fieldPacker.endPack()
|
||
|
|
||
|
return fieldPacker.getBytes()
|
||
|
|
||
|
def __sendAvatarDetails(self, success):
|
||
|
datagram = PyDatagram()
|
||
|
datagram.addUint32(self.fields['avId']) # avId
|
||
|
datagram.addUint8(0 if success else 1) # returnCode
|
||
|
if success:
|
||
|
avatarDetails = self.__packAvatarDetails(self.dclass, self.fields)
|
||
|
datagram.appendData(avatarDetails) # fields
|
||
|
|
||
|
self.friendsManager.sendUpdateToAvatarId(self.sender, 'getAvatarDetailsResponse', [datagram.getMessage()])
|
||
|
|
||
|
def _handleDone(self):
|
||
|
self.__sendAvatarDetails(True)
|
||
|
FriendsOperation._handleDone(self)
|
||
|
|
||
|
def _handleError(self, error):
|
||
|
self.__sendAvatarDetails(False)
|
||
|
FriendsOperation._handleError(self, error)
|
||
|
|
||
|
|
||
|
class MakeFriendsOperation(FriendsOperation):
|
||
|
|
||
|
def __init__(self, friendsManager):
|
||
|
FriendsOperation.__init__(self, friendsManager, None)
|
||
|
self.avatarAId = None
|
||
|
self.avatarBId = None
|
||
|
self.flags = None
|
||
|
self.context = None
|
||
|
self.resultCode = None
|
||
|
self.onlineToons = None
|
||
|
self.avatarAFriendsList = None
|
||
|
self.avatarBFriendsList = None
|
||
|
|
||
|
def start(self, avatarAId, avatarBId, flags, context):
|
||
|
self.avatarAId = avatarAId
|
||
|
self.avatarBId = avatarBId
|
||
|
self.flags = flags
|
||
|
self.context = context
|
||
|
self.resultCode = 0
|
||
|
self.onlineToons = []
|
||
|
self.friendsManager.air.getActivated(self.avatarAId, self.__gotActivatedAvatarA)
|
||
|
|
||
|
def __handleActivatedResp(self, avId, activated):
|
||
|
if activated:
|
||
|
self.onlineToons.append(avId)
|
||
|
|
||
|
def __gotActivatedAvatarA(self, avId, activated):
|
||
|
self.__handleActivatedResp(avId, activated)
|
||
|
self.friendsManager.air.getActivated(self.avatarBId, self.__gotActivatedAvatarB)
|
||
|
|
||
|
def __handleMakeFriends(self, dclass, fields, friendId):
|
||
|
if dclass != self.friendsManager.air.dclassesByName['DistributedToonUD']:
|
||
|
self._handleError('Retrieved avatar is not a DistributedToonUD!')
|
||
|
return False, []
|
||
|
|
||
|
friendsList = fields['setFriendsList'][0]
|
||
|
if len(friendsList) >= OTPGlobals.MaxFriends:
|
||
|
self._handleError('Avatar\'s friends list is full!')
|
||
|
return False, []
|
||
|
|
||
|
newFriend = (friendId, self.flags)
|
||
|
if newFriend in friendsList:
|
||
|
self._handleError('Already friends!')
|
||
|
return False, []
|
||
|
|
||
|
friendsList.append(newFriend)
|
||
|
return True, friendsList
|
||
|
|
||
|
def __handleAvatarARetrieved(self, dclass, fields):
|
||
|
success, avatarAFriendsList = self.__handleMakeFriends(dclass, fields, self.avatarBId)
|
||
|
if success:
|
||
|
self.avatarAFriendsList = avatarAFriendsList
|
||
|
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, self.avatarBId,
|
||
|
self.__handleAvatarBRetrieved)
|
||
|
|
||
|
def __gotActivatedAvatarB(self, avId, activated):
|
||
|
self.__handleActivatedResp(avId, activated)
|
||
|
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, self.avatarAId,
|
||
|
self.__handleAvatarARetrieved)
|
||
|
|
||
|
def __handleAvatarBRetrieved(self, dclass, fields):
|
||
|
success, avatarBFriendsList = self.__handleMakeFriends(dclass, fields, self.avatarAId)
|
||
|
if success:
|
||
|
self.avatarBFriendsList = avatarBFriendsList
|
||
|
self._handleDone()
|
||
|
|
||
|
def __handleSetFriendsList(self, avId, friendsList):
|
||
|
if avId in self.onlineToons:
|
||
|
self.friendsManager.sendUpdateToAvatar(avId, 'setFriendsList', [friendsList])
|
||
|
else:
|
||
|
self.friendsManager.air.dbInterface.updateObject(self.friendsManager.air.dbId, avId,
|
||
|
self.friendsManager.air.dclassesByName[
|
||
|
'DistributedToonUD'],
|
||
|
{'setFriendsList': [friendsList]})
|
||
|
|
||
|
def _handleDone(self):
|
||
|
self.resultCode = 1
|
||
|
if self.avatarAFriendsList is not None and self.avatarBFriendsList is not None:
|
||
|
self.__handleSetFriendsList(self.avatarAId, self.avatarAFriendsList)
|
||
|
self.__handleSetFriendsList(self.avatarBId, self.avatarBFriendsList)
|
||
|
|
||
|
if self.avatarAId in self.onlineToons and self.avatarBId in self.onlineToons:
|
||
|
self.friendsManager.declareObject(self.avatarAId, self.avatarBId)
|
||
|
self.friendsManager.declareObject(self.avatarBId, self.avatarAId)
|
||
|
|
||
|
self.friendsManager.sendMakeFriendsResponse(self.avatarAId, self.avatarBId, self.resultCode, self.context)
|
||
|
FriendsOperation._handleDone(self)
|
||
|
|
||
|
def _handleError(self, error):
|
||
|
self.resultCode = 0
|
||
|
self.friendsManager.sendMakeFriendsResponse(self.avatarAId, self.avatarBId, self.resultCode, self.context)
|
||
|
FriendsOperation._handleError(self, error)
|
||
|
|
||
|
|
||
|
class RemoveFriendOperation(FriendsOperation):
|
||
|
|
||
|
def __init__(self, friendsManager, sender):
|
||
|
FriendsOperation.__init__(self, friendsManager, sender)
|
||
|
self.friendId = None
|
||
|
self.onlineToons = None
|
||
|
self.senderFriendsList = None
|
||
|
self.friendFriendsList = None
|
||
|
|
||
|
def start(self, friendId):
|
||
|
self.friendId = friendId
|
||
|
self.onlineToons = []
|
||
|
self.friendsManager.air.getActivated(self.sender, self.__gotSenderActivated)
|
||
|
|
||
|
def __handleActivatedResp(self, avId, activated):
|
||
|
if activated:
|
||
|
self.onlineToons.append(avId)
|
||
|
|
||
|
def __gotSenderActivated(self, avId, activated):
|
||
|
self.__handleActivatedResp(avId, activated)
|
||
|
self.friendsManager.air.getActivated(self.friendId, self.__gotFriendActivated)
|
||
|
|
||
|
def __gotFriendActivated(self, avId, activated):
|
||
|
self.__handleActivatedResp(avId, activated)
|
||
|
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, self.sender,
|
||
|
self.__handleSenderRetrieved)
|
||
|
|
||
|
def __handleRemoveFriend(self, dclass, fields, friendId):
|
||
|
if dclass != self.friendsManager.air.dclassesByName['DistributedToonUD']:
|
||
|
self._handleError('Retrieved sender is not a DistributedToonUD!')
|
||
|
return False, []
|
||
|
|
||
|
friendsList = fields['setFriendsList'][0]
|
||
|
removed = False
|
||
|
for index, friend in enumerate(friendsList):
|
||
|
if friend[0] == friendId:
|
||
|
del friendsList[index]
|
||
|
removed = True
|
||
|
break
|
||
|
|
||
|
if removed:
|
||
|
return True, friendsList
|
||
|
else:
|
||
|
self._handleError('Unable to remove friend!')
|
||
|
return False, []
|
||
|
|
||
|
def __handleSenderRetrieved(self, dclass, fields):
|
||
|
success, senderFriendsList = self.__handleRemoveFriend(dclass, fields, self.friendId)
|
||
|
if success:
|
||
|
self.senderFriendsList = senderFriendsList
|
||
|
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, self.friendId,
|
||
|
self.__handleFriendRetrieved)
|
||
|
|
||
|
def __handleFriendRetrieved(self, dclass, fields):
|
||
|
success, friendFriendsList = self.__handleRemoveFriend(dclass, fields, self.sender)
|
||
|
if success:
|
||
|
self.friendFriendsList = friendFriendsList
|
||
|
self._handleDone()
|
||
|
|
||
|
def __handleSetFriendsList(self, avId, friendsList):
|
||
|
if avId in self.onlineToons:
|
||
|
self.friendsManager.sendUpdateToAvatar(avId, 'setFriendsList', [friendsList])
|
||
|
else:
|
||
|
self.friendsManager.air.dbInterface.updateObject(self.friendsManager.air.dbId, avId,
|
||
|
self.friendsManager.air.dclassesByName[
|
||
|
'DistributedToonUD'],
|
||
|
{'setFriendsList': [friendsList]})
|
||
|
|
||
|
def _handleDone(self):
|
||
|
if self.senderFriendsList is not None and self.friendFriendsList is not None:
|
||
|
self.__handleSetFriendsList(self.sender, self.senderFriendsList)
|
||
|
self.__handleSetFriendsList(self.friendId, self.friendFriendsList)
|
||
|
|
||
|
if self.sender in self.onlineToons and self.friendId in self.onlineToons:
|
||
|
self.friendsManager.undeclareObject(self.sender, self.friendId)
|
||
|
self.friendsManager.undeclareObject(self.friendId, self.sender)
|
||
|
|
||
|
if self.friendId in self.onlineToons:
|
||
|
self.friendsManager.sendUpdateToAvatar(self.friendId, 'friendsNotify', [self.sender, 1])
|
||
|
|
||
|
FriendsOperation._handleDone(self)
|
||
|
|
||
|
|
||
|
class ComingOnlineOperation(FriendsOperation):
|
||
|
|
||
|
def __init__(self, friendsManager):
|
||
|
FriendsOperation.__init__(self, friendsManager, None)
|
||
|
self.avId = None
|
||
|
self.friendsList = None
|
||
|
self.currentFriendIdx = None
|
||
|
|
||
|
def start(self, avId, friendsList):
|
||
|
self.avId = avId
|
||
|
self.friendsList = friendsList
|
||
|
self.__checkFriendsOnline()
|
||
|
|
||
|
def __checkFriendsOnline(self):
|
||
|
self.currentFriendIdx = 0
|
||
|
for friendId in self.friendsList:
|
||
|
self.friendsManager.air.getActivated(friendId, self.__gotFriendActivated)
|
||
|
|
||
|
def __gotFriendActivated(self, avId, activated):
|
||
|
self.currentFriendIdx += 1
|
||
|
if activated:
|
||
|
self.friendsManager.declareObject(avId, self.avId)
|
||
|
self.friendsManager.declareObject(self.avId, avId)
|
||
|
self.friendsManager.sendFriendOnline(avId, self.avId, 0, 1)
|
||
|
|
||
|
if self.currentFriendIdx >= len(self.friendsList):
|
||
|
self._handleDone()
|
||
|
|
||
|
|
||
|
class GoingOfflineOperation(FriendsOperation):
|
||
|
|
||
|
def __init__(self, friendsManager):
|
||
|
FriendsOperation.__init__(self, friendsManager, None)
|
||
|
self.avId = None
|
||
|
self.friendsList = None
|
||
|
self.accId = None
|
||
|
self.currentFriendIdx = None
|
||
|
|
||
|
def start(self, avId):
|
||
|
self.avId = avId
|
||
|
self.friendsList = []
|
||
|
self.accId = 0
|
||
|
self.friendsManager.air.dbInterface.queryObject(self.friendsManager.air.dbId, self.avId, self.__handleAvatarRetrieved)
|
||
|
|
||
|
def __handleAvatarRetrieved(self, dclass, fields):
|
||
|
if dclass != self.friendsManager.air.dclassesByName['DistributedToonUD']:
|
||
|
self._handleError('Retrieved avatar is not a DistributedToonUD!')
|
||
|
return
|
||
|
|
||
|
self.friendsList = fields['setFriendsList'][0]
|
||
|
self.accId = fields['setDISLid'][0]
|
||
|
self.__checkFriendsOnline()
|
||
|
|
||
|
def __checkFriendsOnline(self):
|
||
|
self.currentFriendIdx = 0
|
||
|
for friendId, _ in self.friendsList:
|
||
|
self.friendsManager.air.getActivated(friendId, self.__gotFriendActivated)
|
||
|
|
||
|
def __gotFriendActivated(self, avId, activated):
|
||
|
self.currentFriendIdx += 1
|
||
|
if activated:
|
||
|
self.friendsManager.undeclareObject(avId, self.avId)
|
||
|
self.friendsManager.undeclareObject(self.accId, avId, isAccount=True)
|
||
|
self.friendsManager.sendFriendOffline(avId, self.avId)
|
||
|
|
||
|
if self.currentFriendIdx >= len(self.friendsList):
|
||
|
self._handleDone()
|
||
|
|
||
|
|
||
|
class ToontownFriendsManagerUD(DistributedObjectGlobalUD):
|
||
|
notify = DirectNotifyGlobal.directNotify.newCategory('ToontownFriendsManagerUD')
|
||
|
|
||
|
def __init__(self, air):
|
||
|
DistributedObjectGlobalUD.__init__(self, air)
|
||
|
self.operations = []
|
||
|
self.secrets = []
|
||
|
|
||
|
def sendMakeFriendsResponse(self, avatarAId, avatarBId, result, context):
|
||
|
self.sendUpdate('makeFriendsResponse', [avatarAId, avatarBId, result, context])
|
||
|
|
||
|
def declareObject(self, doId, objId):
|
||
|
datagram = PyDatagram()
|
||
|
datagram.addServerHeader(self.GetPuppetConnectionChannel(doId), self.air.ourChannel, CLIENTAGENT_DECLARE_OBJECT)
|
||
|
datagram.addUint32(objId)
|
||
|
datagram.addUint16(self.air.dclassesByName['DistributedToonUD'].getNumber())
|
||
|
self.air.send(datagram)
|
||
|
|
||
|
def undeclareObject(self, doId, objId, isAccount=False):
|
||
|
datagram = PyDatagram()
|
||
|
if isAccount:
|
||
|
datagram.addServerHeader(self.GetAccountConnectionChannel(doId), self.air.ourChannel,
|
||
|
CLIENTAGENT_UNDECLARE_OBJECT)
|
||
|
|
||
|
else:
|
||
|
datagram.addServerHeader(self.GetPuppetConnectionChannel(doId), self.air.ourChannel,
|
||
|
CLIENTAGENT_UNDECLARE_OBJECT)
|
||
|
datagram.addUint32(objId)
|
||
|
self.air.send(datagram)
|
||
|
|
||
|
def sendFriendOnline(self, avId, friendId, commonChatFlags, whitelistChatFlags):
|
||
|
self.sendUpdateToAvatarId(avId, 'friendOnline', [friendId, commonChatFlags, whitelistChatFlags])
|
||
|
|
||
|
def sendFriendOffline(self, avId, friendId):
|
||
|
self.sendUpdateToAvatarId(avId, 'friendOffline', [friendId])
|
||
|
|
||
|
def sendUpdateToAvatar(self, avId, fieldName, args=[]):
|
||
|
dclass = self.air.dclassesByName['DistributedToonUD']
|
||
|
if not dclass:
|
||
|
return
|
||
|
|
||
|
field = dclass.getFieldByName(fieldName)
|
||
|
if not field:
|
||
|
return
|
||
|
|
||
|
datagram = field.aiFormatUpdate(avId, avId, self.air.ourChannel, args)
|
||
|
self.air.send(datagram)
|
||
|
|
||
|
def runSenderOperation(self, operationType, *args):
|
||
|
sender = self.air.getAvatarIdFromSender()
|
||
|
if not sender:
|
||
|
return
|
||
|
|
||
|
newOperation = operationType(self, sender)
|
||
|
self.operations.append(newOperation)
|
||
|
newOperation.start(*args)
|
||
|
|
||
|
def runServerOperation(self, operationType, *args):
|
||
|
newOperation = operationType(self)
|
||
|
self.operations.append(newOperation)
|
||
|
newOperation.start(*args)
|
||
|
|
||
|
def getFriendsListRequest(self):
|
||
|
self.runSenderOperation(GetFriendsListOperation)
|
||
|
|
||
|
def getAvatarDetailsRequest(self, avId):
|
||
|
self.runSenderOperation(GetAvatarDetailsOperation, avId)
|
||
|
|
||
|
def makeFriends(self, avatarAId, avatarBId, flags, context):
|
||
|
self.runServerOperation(MakeFriendsOperation, avatarAId, avatarBId, flags, context)
|
||
|
|
||
|
def removeFriend(self, friendId):
|
||
|
self.runSenderOperation(RemoveFriendOperation, friendId)
|
||
|
|
||
|
def comingOnline(self, avId, friendsList):
|
||
|
self.runServerOperation(ComingOnlineOperation, avId, friendsList)
|
||
|
|
||
|
def goingOffline(self, avId):
|
||
|
self.runServerOperation(GoingOfflineOperation, avId)
|
||
|
|
||
|
def requestSecret(self, requesterId):
|
||
|
print('requestSecret')
|