historical/toontown-classic.git/otp/friends/FriendManagerAI.py
2024-01-16 11:20:27 -06:00

302 lines
12 KiB
Python

import datetime
import json
import os
import random
from direct.directnotify import DirectNotifyGlobal
from direct.distributed.DistributedObjectAI import DistributedObjectAI
from direct.distributed.PyDatagram import *
from otp.otpbase import OTPGlobals
class FriendManagerAI(DistributedObjectAI):
notify = DirectNotifyGlobal.directNotify.newCategory('FriendManagerAI')
serverDataFolder = simbase.config.GetString('server-data-folder', '')
def __init__(self, air):
DistributedObjectAI.__init__(self, air)
self.currentContext = 0
self.requests = {}
self.shard = str(air.districtId)
self.filename = self.getFilename()
self.tfCodes = self.loadTrueFriendCodes()
taskMgr.add(self.__trueFriendCodesTask, 'tf-codes-clear-task')
def friendQuery(self, inviteeId):
avId = self.air.getAvatarIdFromSender()
av = self.air.doId2do.get(avId)
if not av:
return
if inviteeId not in self.air.doId2do:
self.air.writeServerEvent('suspicious', avId, 'Player tried to friend a player that does not exist!')
return
context = self.currentContext
self.requests[context] = [[avId, inviteeId], 'friendQuery']
self.currentContext += 1
self.sendUpdateToAvatarId(inviteeId, 'inviteeFriendQuery', [avId, av.getName(), av.getDNAString(), context])
def cancelFriendQuery(self, context):
avId = self.air.getAvatarIdFromSender()
if not avId:
return
if context not in self.requests:
self.air.writeServerEvent('suspicious', avId, 'Player tried to cancel a request that doesn\'t exist!')
return
if avId != self.requests[context][0][0]:
self.air.writeServerEvent('suspicious', avId, 'Player tried to cancel someone else\'s request!')
return
self.requests[context][1] = 'cancelled'
self.sendUpdateToAvatarId(self.requests[context][0][1], 'inviteeCancelFriendQuery', [context])
def inviteeFriendConsidering(self, yesNo, context):
avId = self.air.getAvatarIdFromSender()
if not avId:
return
if context not in self.requests:
self.air.writeServerEvent('suspicious', avId,
'Player tried to consider a friend request that doesn\'t exist!')
return
if avId != self.requests[context][0][1]:
self.air.writeServerEvent('suspicious', avId, 'Player tried to consider for someone else!')
return
if self.requests[context][1] != 'friendQuery':
self.air.writeServerEvent('suspicious', avId, 'Player tried to reconsider friend request!')
return
if yesNo != 1:
self.sendUpdateToAvatarId(self.requests[context][0][0], 'friendConsidering', [yesNo, context])
del self.requests[context]
return
self.requests[context][1] = 'friendConsidering'
self.sendUpdateToAvatarId(self.requests[context][0][0], 'friendConsidering', [yesNo, context])
def inviteeFriendResponse(self, response, context):
avId = self.air.getAvatarIdFromSender()
if not avId:
return
if context not in self.requests:
self.air.writeServerEvent('suspicious', avId,
'Player tried to respond to a friend request that doesn\'t exist!')
return
if avId != self.requests[context][0][1]:
self.air.writeServerEvent('suspicious', avId, 'Player tried to respond to someone else\'s request!')
return
if self.requests[context][1] == 'cancelled':
self.air.writeServerEvent('suspicious', avId, 'Player tried to respond to a non-active friend request!')
return
self.sendUpdateToAvatarId(self.requests[context][0][0], 'friendResponse', [response, context])
if response == 1:
requestedAv = self.air.doId2do.get(self.requests[context][0][1])
if not requestedAv:
del self.requests[context]
return
requesterAv = self.air.doId2do.get(self.requests[context][0][0])
if not requesterAv:
del self.requests[context]
return
dg = PyDatagram()
dg.addServerHeader(self.GetPuppetConnectionChannel(requestedAv.getDoId()), self.air.ourChannel,
CLIENTAGENT_DECLARE_OBJECT)
dg.addUint32(requesterAv.getDoId())
dg.addUint16(self.air.dclassesByName['DistributedToonAI'].getNumber())
self.air.send(dg)
dg = PyDatagram()
dg.addServerHeader(self.GetPuppetConnectionChannel(requesterAv.getDoId()), self.air.ourChannel,
CLIENTAGENT_DECLARE_OBJECT)
dg.addUint32(requestedAv.getDoId())
dg.addUint16(self.air.dclassesByName['DistributedToonAI'].getNumber())
self.air.send(dg)
requestedAv.extendFriendsList(requesterAv.getDoId(), 0)
requesterAv.extendFriendsList(requestedAv.getDoId(), 0)
requestedAv.d_setFriendsList(requestedAv.getFriendsList())
requesterAv.d_setFriendsList(requesterAv.getFriendsList())
del self.requests[context]
def inviteeAcknowledgeCancel(self, context):
avId = self.air.getAvatarIdFromSender()
if not avId:
return
if context not in self.requests:
self.air.writeServerEvent('suspicious', avId,
'Player tried to acknowledge the cancel of a friend request that doesn\'t exist!')
return
if avId != self.requests[context][0][1]:
self.air.writeServerEvent('suspicious', avId, 'Player tried to acknowledge someone else\'s cancel!')
return
if self.requests[context][1] != 'cancelled':
self.air.writeServerEvent('suspicious', avId, 'Player tried to cancel non-cancelled request!')
return
del self.requests[context]
def requestSecret(self):
avId = self.air.getAvatarIdFromSender()
av = self.air.doId2do.get(avId)
if not av:
return
if len(av.getFriendsList()) >= OTPGlobals.MaxFriends:
self.d_requestSecretResponse(avId, 0, '')
else:
day = datetime.datetime.now().day
tfCode = self.generateTrueFriendCode()
self.tfCodes[tfCode] = (avId, day)
self.updateTrueFriendCodesFile()
self.d_requestSecretResponse(avId, 1, tfCode)
self.air.writeServerEvent('tf-code-requested', avId=avId, tfCode=tfCode)
def generateTrueFriendCode(self):
chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
def randomChar():
return random.choice(chars)
tfCode = '%s%s%s %s%s%s' % (randomChar(), randomChar(), randomChar(), randomChar(), randomChar(), randomChar())
return tfCode
def d_requestSecretResponse(self, avId, result, secret):
if not avId:
return
self.sendUpdateToAvatarId(avId, 'requestSecretResponse', [result, secret])
def submitSecret(self, secret):
avId = self.air.getAvatarIdFromSender()
av = self.air.doId2do.get(avId)
if not av:
return
secretInfo = self.tfCodes.get(secret)
if not secretInfo:
self.d_submitSecretResponse(avId, 0, 0)
return
friendId = secretInfo[0]
friend = self.air.doId2do.get(friendId)
if av:
if friend:
if avId == friendId:
self.d_submitSecretResponse(avId, 3, 0)
self.removeSecret(secret)
elif len(friend.getFriendsList()) >= OTPGlobals.MaxFriends or len(
av.getFriendsList()) >= OTPGlobals.MaxFriends:
self.d_submitSecretResponse(avId, 2, friendId)
else:
dg = PyDatagram()
dg.addServerHeader(self.GetPuppetConnectionChannel(friendId), self.air.ourChannel,
CLIENTAGENT_DECLARE_OBJECT)
dg.addUint32(avId)
dg.addUint16(self.air.dclassesByName['DistributedToonAI'].getNumber())
self.air.send(dg)
dg = PyDatagram()
dg.addServerHeader(self.GetPuppetConnectionChannel(avId), self.air.ourChannel,
CLIENTAGENT_DECLARE_OBJECT)
dg.addUint32(friendId)
dg.addUint16(self.air.dclassesByName['DistributedToonAI'].getNumber())
self.air.send(dg)
friend.extendFriendsList(avId, 1)
av.extendFriendsList(friendId, 1)
friend.d_setFriendsList(friend.getFriendsList())
av.d_setFriendsList(av.getFriendsList())
self.d_submitSecretResponse(avId, 1, friendId)
self.removeSecret(secret)
else:
# Friend is offline!
def handleAvatar(dclass, fields):
if dclass != self.air.dclassesByName['DistributedToonAI']:
return
newFriendsList = []
oldFriendsList = fields['setFriendsList'][0]
if len(oldFriendsList) >= OTPGlobals.MaxFriends:
self.d_submitSecretResponse(avId, 2, friendId)
return
for oldFriend in oldFriendsList:
newFriendsList.append(oldFriend)
newFriendsList.append((avId, 1))
self.air.dbInterface.updateObject(self.air.dbId, friendId,
self.air.dclassesByName['DistributedToonAI'],
{'setFriendsList': [newFriendsList]})
av.extendFriendsList(friendId, 1)
av.d_setFriendsList(av.getFriendsList())
self.d_submitSecretResponse(avId, 1, friendId)
self.removeSecret(secret)
self.air.dbInterface.queryObject(self.air.dbId, friendId, handleAvatar)
self.air.writeServerEvent('tf-code-submitted', avId=avId, friendId=friendId, tfCode=secret)
def d_submitSecretResponse(self, avId, result, friendId):
if not avId:
return
self.sendUpdateToAvatarId(avId, 'submitSecretResponse', [result, friendId])
def removeSecret(self, secret):
if secret in self.tfCodes:
del self.tfCodes[secret]
self.updateTrueFriendCodesFile()
def getFilename(self):
return '%s%s%s%s.json' % (self.serverDataFolder, 'trueFriendCodes/', 'trueFriendCodes_', self.shard)
def loadTrueFriendCodes(self):
try:
tfCodesFile = open(self.filename, 'r')
tfCodesData = json.load(tfCodesFile)
return tfCodesData
except:
return {}
def updateTrueFriendCodesFile(self):
try:
if not os.path.exists(os.path.dirname(self.filename)):
os.makedirs(os.path.dirname(self.filename))
tfCodesFile = open(self.filename, 'w')
tfCodesFile.seek(0)
json.dump(self.tfCodes, tfCodesFile)
tfCodesFile.close()
except:
pass
def __trueFriendCodesTask(self, task):
for tfCode in self.tfCodes.keys():
tfCodeInfo = self.tfCodes[tfCode]
tfCodeDay = tfCodeInfo[1]
today = datetime.datetime.now().day
if tfCodeDay + 2 == today:
self.notify.info('Removing 2-day-old True Friend code: %s' % tfCode)
self.removeSecret(tfCode)
return task.again