open-toontown/otp/uberdog/UberDog.py

381 lines
14 KiB
Python

"""
The Uber Distributed Obeject Globals server.
"""
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.fsm.ClassicFSM import ClassicFSM
from direct.fsm.State import State
from otp.otpbase import OTPGlobals
from otp.distributed import OtpDoGlobals
from otp.distributed.OtpDoGlobals import *
from otp.ai.AIRepository import AIRepository
from otp.ai import TimeManagerAI
from pandac.PandaModules import *
from otp.uberdog.AccountDetailRecord import AccountDetailRecord, SubDetailRecord
from otp.ai.AIMsgTypes import *
class UberDog(AIRepository):
notify = directNotify.newCategory("UberDog")
def __init__(
self, mdip, mdport, esip, esport, dcFileNames,
serverId, minChannel, maxChannel):
AIRepository.__init__(
self, mdip, mdport, esip, esport, dcFileNames,
serverId, minChannel, maxChannel, dcSuffix = 'UD')
# We're responsible for keeping track of who's online with which avatar
self.onlineAccountDetails = {}
self.onlineAvatars = {}
self.onlinePlayers = {}
self.pending={}
self.doId2doCache={}
if hasattr(self, 'setVerbose'):
if self.config.GetBool('verbose-uberrepository'):
self.setVerbose(1)
# The AI State machine
self.fsm = ClassicFSM(
'UberDog', [
State('off',
self.enterOff,
self.exitOff,
['connect']),
State('connect',
self.enterConnect,
self.exitConnect,
['noConnection', 'playGame',]),
State('playGame',
self.enterPlayGame,
self.exitPlayGame,
['noConnection']),
State('noConnection',
self.enterNoConnection,
self.exitNoConnection,
['connect'])],
# initial state
'off',
# final state
'off',
)
self.fsm.enterInitialState()
self.fsm.request("connect")
def _connected(self):
"""
Callback for when we successfully connect to the otp_server cluster.
"""
self.setConnectionName("UberDog")
AIRepository._connected(self)
# Listen for Account and Avatar online/offline messages
self.registerForChannel(CHANNEL_PUPPET_ACTION)
self.fsm.request("playGame")
def dispatchUpdateToDoId(self, dclassName, fieldName, doId, args, channelId=None):
# dispatch immediately to local object if it's local, otherwise send
# it over the wire
obj = self.doId2do.get(doId)
if obj is not None:
assert obj.__class__.__name__ == (dclassName + self.dcSuffix)
method = getattr(obj, fieldName)
apply(method, args)
else:
self.sendUpdateToDoId(dclassName, fieldName, doId, args, channelId)
def dispatchUpdateToGlobalDoId(self, dclassName, fieldName, doId, args):
# dispatch immediately to local object if it's local, otherwise send
# it over the wire
obj = self.doId2do.get(doId)
if obj is not None:
assert obj.__class__.__name__ == dclassName
method = getattr(obj, fieldName)
apply(method, args)
else:
self.sendUpdateToGlobalDoId(dclassName, fieldName, doId, args)
@report(types = ['args'], dConfigParam = 'avatarmgr')
def handleAccountUsage(self, di):
priorAccount = di.getUint32() # Historic - used only in __dev__ atm
newAccount = di.getUint32()
if priorAccount == 0 and newAccount == 0:
assert self.notify.debug("priorAccount==0 and newAccount==0, ignoring accountUsage message")
return
accountDetailRecord = AccountDetailRecord()
accountDetailRecord.openChatEnabled = (di.getString() == "YES")
accountDetailRecord.createFriendsWithChat = (di.getString() == "YES")
accountDetailRecord.chatCodeCreation = (di.getString() == "YES")
access = di.getString()
if access == "VELVET":
access = OTPGlobals.AccessVelvetRope
elif access == "FULL":
access = OTPGlobals.AccessFull
else:
access = OTPGlobals.AccessUnknown
accountDetailRecord.piratesAccess = access
accountDetailRecord.familyAccountId = di.getInt32()
accountDetailRecord.playerAccountId = di.getInt32()
accountDetailRecord.playerName = di.getString()
accountDetailRecord.playerNameApproved = di.getInt8()
accountDetailRecord.maxAvatars = di.getInt32()
accountDetailRecord.numFamilyMembers = di.getInt16()
accountDetailRecord.familyMembers = []
for i in range(accountDetailRecord.numFamilyMembers):
accountDetailRecord.familyMembers.append(di.getInt32())
logoutReason = di.getInt32()
# Now retrieve the subscription information
accountDetailRecord.numSubs = di.getUint16()
for i in range(accountDetailRecord.numSubs):
subDetailRecord = SubDetailRecord()
subDetailRecord.subId = di.getUint32()
subDetailRecord.subOwnerId = di.getUint32()
subDetailRecord.subName = di.getString()
subDetailRecord.subActive = di.getString()
access = di.getString()
if access == "VELVET":
access = OTPGlobals.AccessVelvetRope
elif access == "FULL":
access = OTPGlobals.AccessFull
else:
access = OTPGlobals.AccessUnknown
subDetailRecord.subAccess = access
subDetailRecord.subLevel = di.getUint8()
subDetailRecord.subNumAvatars = di.getUint8()
subDetailRecord.subNumConcur = di.getUint8()
subDetailRecord.subFounder = (di.getString() == "YES")
# Add this subscription to the dict on the account record
accountDetailRecord.subDetails[subDetailRecord.subId] = subDetailRecord
# How many avatar slots total do you get in this game?
accountDetailRecord.maxAvatarSlots = di.getInt8()
assert self.notify.debug("accountDetailRecord: %s" % accountDetailRecord)
if priorAccount:
# Send any previous account offline
self.accountOffline(priorAccount)
pass
if newAccount:
# Set up the new guy
self.accountOnline(newAccount, accountDetailRecord)
pass
pass
@report(types = ['args'], dConfigParam = 'avatarmgr')
def handleAvatarUsage(self, di):
priorAvatar = di.getUint32()
newAvatar = di.getUint32()
if priorAvatar == 0 and newAvatar == 0:
assert self.notify.debug("priorAvatar==0 and newAvatar==0, ignoring avatarUsage message")
return
newAvatarType = di.getUint16()
accountId = di.getUint32()
openChatEnabled = di.getString()
createFriendsWithChat = di.getString()
chatCodeCreation = di.getString()
piratesAccess = di.getString()
familyAccountId = di.getInt32()
playerAccountId = di.getInt32()
playerName = di.getString()
playerNameApproved = di.getInt8()
maxAvatars = di.getInt32()
numFamilyMembers = di.getInt16()
familyMembers = []
for i in range(numFamilyMembers):
familyMembers.append(di.getInt32())
if openChatEnabled == "YES":
openChatEnabled = 1
else:
openChatEnabled = 0
if priorAvatar:
# Send any previous avatar offline
self.avatarOffline(accountId, priorAvatar)
pass
if newAvatar:
# Set up the new guy
self.avatarOnline(newAvatar, newAvatarType,
playerAccountId,
playerName,
playerNameApproved,
openChatEnabled,
createFriendsWithChat,
chatCodeCreation)
pass
pass
@report(types = ['args'], dConfigParam = 'avatarmgr')
def accountOnline(self, accountId, accountDetailRecord):
self.writeServerEvent('accountOnline', accountId, '')
self.onlineAccountDetails[accountId] = accountDetailRecord
messenger.send('accountOnline', [accountId])
pass
@report(types = ['args'], dConfigParam = 'avatarmgr')
def accountOffline(self, accountId):
self.writeServerEvent('accountOffline', accountId, '')
self.onlineAccountDetails.pop(accountId, None)
self.onlinePlayers.pop(accountId, None)
messenger.send('accountOffline', [accountId])
pass
@report(types = ['args'], dConfigParam = 'avatarmgr')
def getAccountDetails(self, accountId):
return self.onlineAccountDetails.get(accountId)
@report(types = ['args'], dConfigParam = 'avatarmgr')
def isAccountOnline(self, accountId):
return accountId in self.onlineAccountDetails
@report(types = ['args'], dConfigParam = 'avatarmgr')
def isAvatarOnline(self, avatarId):
return avatarId in self.onlineAvatars
@report(types = ['args'], dConfigParam = 'avatarmgr')
def getAvatarAccountOnline(self, avatarId):
return self.onlineAvatars.get(avatarId, 0)
@report(types = ['args'], dConfigParam = 'avatarmgr')
def getAccountOnlineAvatar(self, accountId):
return self.onlinePlayers.get(accountId, 0)
@report(types = ['args'], dConfigParam = 'avatarmgr')
def checkAccountId(self, accountId):
if not accountId:
# SUSPICIOUS
self.notify.warning("Bogus accountId: %s" % accountId)
self.writeServerEvent('suspicious', accountId, 'bogus accountId in OtpAvatarManagerUD')
elif not self.isAccountOnline(accountId):
# SUSPICIOUS
self.notify.warning("Got request from account not online: %s" % accountId)
self.writeServerEvent('suspicious', accountId, 'request from offline account in OtpAvatarManagerUD')
else:
# Everything checks out
return True
return False
@report(types = ['args'], dConfigParam = 'avatarmgr')
def avatarOnline(self, avatarId, avatarType, accountId, playerName, playerNameApproved,
openChatEnabled, createFriendsWithChat, chatCodeCreation):
self.writeServerEvent('avatarOnline', avatarId, '%s|%s|%s|%s|%s|%s' % (
accountId, playerName, playerNameApproved, openChatEnabled,
createFriendsWithChat, chatCodeCreation))
self.onlineAvatars[avatarId] = accountId
self.onlinePlayers[accountId] = avatarId
simpleInfo = [avatarId, avatarType]
fullInfo = [avatarId,
accountId,
playerName,
playerNameApproved,
openChatEnabled,
createFriendsWithChat,
chatCodeCreation]
# necessary for local UD manager objects
messenger.send("avatarOnline", simpleInfo)
messenger.send("avatarOnlinePlusAccountInfo", fullInfo)
pass
@report(types = ['args'], dConfigParam = 'avatarmgr')
def avatarOffline(self, accountId, avatarId):
self.writeServerEvent('avatarOffline', avatarId, '')
self.onlinePlayers.pop(accountId, None)
self.onlineAvatars.pop(avatarId, None)
# necessary for local UD manager objects
messenger.send("avatarOffline", [avatarId])
pass
###################################
# Assumed Obsolete as of 6/29/09
#
# If you're reading this and there
# haven't been any strange UD crashes
# here lately, you can probably delete
# the next few functions.
###################################
def _addObject(self, context, distributedObject):
"""
Handle a new distributed object arriving by adding
it to the cache calling self.handleGotDo().
"""
assert False, 'JCW: Testing for obsolete functions. If this crashes, let Josh know'
doId=distributedObject.getDoId()
assert not self.doId2doCache.has_key(doId)
if not self.doId2doCache.has_key(doId):
self.doId2doCache[doId]=distributedObject
self.handleGotDo(distributedObject)
def handleGotDo(self, distributedObject):
"""
This allows derived classes to override the handling
of new distributed objects arriving in the cache.
By default, this will loop through the pending calls
for that object and make the function calls. It
will also remove the handled calls from the pending set.
"""
assert False, 'JCW: Testing for obsolete functions. If this crashes, let Josh know'
assert self.doId2doCache.has_key(doId)
pending=self.pending.get(doId)
if pending is not None:
del self.pending[doId]
for i in pending:
apply(i[0], i[2])
def deleteObject(self, doId):
"""
Ask for the object to be removed from the private
distributed object cache.
"""
assert False, 'JCW: Testing for obsolete functions. If this crashes, let Josh know'
if self.doId2doCache.had_key(doId):
self.unregisterForChannel(doId)
#self.deleteObject(doId)
del self.doId2doCache[doId]
#HACK:
self.unregisterForChannel(doId)
AIRepository.deleteObject(self.doId)
def uniqueName(self, desc):
return desc
if __dev__:
"""
Early warning system for unsupported use of the Uberdog Repository
"""
def deleteObjects(self):
assert 0
def createDistrict(self, districtId, districtName):
assert 0
def deleteDistrict(self, districtId):
assert 0
def enterDistrictReset(self):
assert 0
def exitDistrictReset(self):
assert 0