mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-23 19:52:37 -06:00
CSM: new tokens + holocaust dc imports
This commit is contained in:
parent
1303af5a13
commit
0b2107c04d
10 changed files with 275 additions and 294 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,5 +1,6 @@
|
||||||
# Python artifacts
|
# Python artifacts
|
||||||
*.pyc
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
|
||||||
# Batch
|
# Batch
|
||||||
*.bat
|
*.bat
|
||||||
|
@ -15,3 +16,6 @@
|
||||||
|
|
||||||
# Git
|
# Git
|
||||||
*.rej
|
*.rej
|
||||||
|
|
||||||
|
# Local config
|
||||||
|
dependencies/config/local.prc
|
||||||
|
|
1
dependencies/astron/dclass/stride.dc
vendored
1
dependencies/astron/dclass/stride.dc
vendored
|
@ -34,6 +34,7 @@ dclass Account {
|
||||||
string LAST_LOGIN db;
|
string LAST_LOGIN db;
|
||||||
string ACCOUNT_ID db;
|
string ACCOUNT_ID db;
|
||||||
uint16 ACCESS_LEVEL db;
|
uint16 ACCESS_LEVEL db;
|
||||||
|
uint64 LAST_LOGIN_TS db;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BarrierData {
|
struct BarrierData {
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
cd ../../../
|
|
||||||
|
|
||||||
"dependencies/panda/python/ppython.exe" "dev/tools/dcimports/parse_dcimports.py" -o "otp/distributed/DCClassImports.py" "dependencies/astron/dclass/stride.dc"
|
|
||||||
|
|
||||||
pause
|
|
|
@ -1,50 +0,0 @@
|
||||||
import argparse
|
|
||||||
|
|
||||||
from pandac.PandaModules import *
|
|
||||||
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument('--output', '-o', default='DCClassImports.py',
|
|
||||||
help='The filename of the generated Python module.')
|
|
||||||
parser.add_argument('filenames', nargs='+', default=['otp.dc', 'toon.dc'],
|
|
||||||
help='The DC class files to be included in the generated Python module.')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
dcFile = DCFile()
|
|
||||||
for filename in args.filenames:
|
|
||||||
dcFile.read(Filename.fromOsSpecific(filename))
|
|
||||||
|
|
||||||
dcImports = {}
|
|
||||||
for n in xrange(dcFile.getNumImportModules()):
|
|
||||||
moduleName = dcFile.getImportModule(n)[:].split('/', 1)[0]
|
|
||||||
if moduleName not in dcImports:
|
|
||||||
dcImports[moduleName] = []
|
|
||||||
importSymbols = []
|
|
||||||
for i in xrange(dcFile.getNumImportSymbols(n)):
|
|
||||||
symbolName = dcFile.getImportSymbol(n, i).split('/', 1)[0]
|
|
||||||
importSymbols.append(symbolName)
|
|
||||||
dcImports[moduleName].extend(importSymbols)
|
|
||||||
|
|
||||||
data = '''\
|
|
||||||
# This file was generated by the parse_dclass.py utility.
|
|
||||||
from pandac.PandaModules import *
|
|
||||||
|
|
||||||
|
|
||||||
hashVal = %r
|
|
||||||
|
|
||||||
|
|
||||||
''' % dcFile.getHash()
|
|
||||||
|
|
||||||
for moduleName, importSymbols in dcImports.items():
|
|
||||||
data += 'from %s import %s\n' % (moduleName, ', '.join(importSymbols))
|
|
||||||
|
|
||||||
data += '''
|
|
||||||
|
|
||||||
dcImports = locals().copy()
|
|
||||||
'''
|
|
||||||
|
|
||||||
print 'Writing %s...' % args.output
|
|
||||||
with open(args.output, 'w') as f:
|
|
||||||
f.write(data)
|
|
||||||
|
|
||||||
print 'Done writing %s.' % args.output
|
|
|
@ -1,48 +0,0 @@
|
||||||
# This file was generated by the parse_dclass.py utility.
|
|
||||||
from pandac.PandaModules import *
|
|
||||||
|
|
||||||
|
|
||||||
hashVal = 3796631281L
|
|
||||||
|
|
||||||
|
|
||||||
from toontown.coghq import DistributedCashbotBossSafe, DistributedCashbotBossCrane, DistributedBattleFactory, DistributedCashbotBossTreasure, DistributedCogHQDoor, DistributedCogHQExteriorDoor, DistributedSellbotHQDoor, DistributedFactoryElevatorExt, DistributedMintElevatorExt, DistributedLawOfficeElevatorExt, DistributedLawOfficeElevatorInt, LobbyManager, DistributedMegaCorp, DistributedFactory, DistributedLawOffice, DistributedLawOfficeFloor, DistributedLift, DistributedDoorEntity, DistributedSwitch, DistributedButton, DistributedTrigger, DistributedCrushableEntity, DistributedCrusherEntity, DistributedStomper, DistributedStomperPair, DistributedLaserField, DistributedGolfGreenGame, DistributedSecurityCamera, DistributedMover, DistributedElevatorMarker, DistributedBarrelBase, DistributedGagBarrel, DistributedBeanBarrel, DistributedHealBarrel, DistributedGrid, ActiveCell, DirectionalCell, CrusherCell, DistributedCrate, DistributedSinkingPlatform, BattleBlocker, DistributedMint, DistributedMintRoom, DistributedMintBattle, DistributedStage, DistributedStageRoom, DistributedStageBattle, DistributedLawbotBossGavel, DistributedLawbotCannon, DistributedLawbotChair, DistributedCogKart, DistributedCountryClub, DistributedCountryClubRoom, DistributedMoleField, DistributedCountryClubBattle, DistributedMaze, DistributedFoodBelt, DistributedBanquetTable, DistributedGolfSpot
|
|
||||||
from toontown.golf import DistributedPhysicsWorld, DistributedGolfHole, DistributedGolfCourse
|
|
||||||
from toontown.building import DistributedAnimatedProp, DistributedTrophyMgr, DistributedBuilding, DistributedBuildingQueryMgr, DistributedToonInterior, DistributedToonHallInterior, DistributedSuitInterior, DistributedHQInterior, DistributedGagshopInterior, DistributedPetshopInterior, DistributedKartShopInterior, DistributedDoor, DistributedKnockKnockDoor, DistributedElevator, DistributedElevatorFSM, DistributedElevatorExt, DistributedElevatorInt, DistributedElevatorFloor, DistributedBossElevator, DistributedVPElevator, DistributedCFOElevator, DistributedCJElevator, DistributedBBElevator, DistributedBoardingParty, DistributedTutorialInterior, DistributedClubElevator
|
|
||||||
from toontown.uberdog.DistributedPartyManager import DistributedPartyManager
|
|
||||||
from otp.friends import FriendManager
|
|
||||||
from otp.level import DistributedLevel, DistributedEntity, DistributedInteractiveEntity
|
|
||||||
from toontown.shtiker import DeleteManager, PurchaseManager, NewbiePurchaseManager
|
|
||||||
from toontown.groups import GroupManager
|
|
||||||
from toontown.uberdog.ClientServicesManager import ClientServicesManager
|
|
||||||
from toontown.ai import WelcomeValleyManager, NewsManager, DistributedAprilToonsMgr, DistributedBlackCatMgr, DistributedReportMgr, DistributedPolarPlaceEffectMgr, DistributedGreenToonEffectMgr, DistributedResistanceEmoteMgr, DistributedScavengerHuntTarget, DistributedTrickOrTreatTarget, DistributedWinterCarolingTarget, DistributedJorElCam
|
|
||||||
from otp.chat import ChatAgent
|
|
||||||
from toontown.parties.GlobalPartyManager import GlobalPartyManager
|
|
||||||
from toontown.racing.DistributedStartingBlock import DistributedViewingBlock
|
|
||||||
from toontown.suit import DistributedSuitPlanner, DistributedSuitBase, DistributedSuit, DistributedTutorialSuit, DistributedFactorySuit, DistributedMintSuit, DistributedStageSuit, DistributedSellbotBoss, DistributedCashbotBoss, DistributedCashbotBossGoon, DistributedGoon, DistributedGridGoon, DistributedLawbotBoss, DistributedLawbotBossSuit, DistributedBossbotBoss
|
|
||||||
from toontown.distributed import ToontownDistrict, ToontownDistrictStats, DistributedTimer
|
|
||||||
from toontown.effects import DistributedFireworkShow
|
|
||||||
from toontown.safezone import DistributedTrolley, DistributedPillow, DistributedPartyGate, DistributedBoat, DistributedButterfly, DistributedMMPiano, DistributedDGFlower, DistributedFishingSpot, SafeZoneManager, DistributedTreasure, DistributedGolfKart, DistributedPicnicBasket, DistributedPicnicTable, DistributedChineseCheckers, DistributedCheckers, DistributedFindFour
|
|
||||||
from toontown.fishing import DistributedFishingPond, DistributedFishingTarget, DistributedPondBingoManager
|
|
||||||
from toontown.minigame import DistributedMinigame, DistributedMinigameTemplate, DistributedRaceGame, DistributedCannonGame, DistributedPatternGame, DistributedRingGame, DistributedTagGame, DistributedMazeGame, DistributedTugOfWarGame, DistributedCatchGame, DistributedDivingGame, DistributedTargetGame, DistributedVineGame, DistributedIceGame, DistributedCogThiefGame, DistributedTwoDGame
|
|
||||||
from toontown.racing import DistributedVehicle, DistributedStartingBlock, DistributedRace, DistributedKartPad, DistributedRacePad, DistributedViewPad, DistributedStartingBlock, DistributedLeaderBoard, DistributedGag, DistributedProjectile
|
|
||||||
from toontown.catalog import CatalogManager, AccountDate
|
|
||||||
from toontown.parties import DistributedParty, DistributedPartyActivity, DistributedPartyTeamActivity, DistributedPartyCannon, DistributedPartyCannonActivity, DistributedPartyCatchActivity, DistributedPartyWinterCatchActivity, DistributedPartyCogActivity, DistributedPartyWinterCogActivity, DistributedPartyFireworksActivity, DistributedPartyDanceActivityBase, DistributedPartyDanceActivity, DistributedPartyDance20Activity, DistributedPartyValentineDanceActivity, DistributedPartyValentineDance20Activity, DistributedPartyTrampolineActivity, DistributedPartyValentineTrampolineActivity, DistributedPartyVictoryTrampolineActivity, DistributedPartyWinterTrampolineActivity, DistributedPartyTugOfWarActivity, DistributedPartyJukeboxActivityBase, DistributedPartyJukeboxActivity, DistributedPartyJukebox40Activity, DistributedPartyValentineJukeboxActivity, DistributedPartyValentineJukebox40Activity
|
|
||||||
from toontown.pets.DistributedPet import *
|
|
||||||
from toontown.friends import TTSFriendsManager
|
|
||||||
from toontown.cogdominium import DistributedCogdoInterior, DistributedCogdoBattleBldg, DistributedCogdoElevatorExt, DistributedCogdoElevatorInt, DistributedCogdoBarrel, DistCogdoGame, DistCogdoLevelGame, DistCogdoBoardroomGame, DistCogdoCraneGame, DistCogdoMazeGame, DistCogdoFlyingGame, DistCogdoCrane, DistCogdoCraneMoneyBag, DistCogdoCraneCog
|
|
||||||
from toontown.uberdog.GlobalLobbyManager import GlobalLobbyManager
|
|
||||||
from toontown.uberdog.ARGManager import ARGManager
|
|
||||||
from otp.distributed import Account, DistributedDistrict, DistributedDirectory
|
|
||||||
from toontown.estate import DistributedCannon, DistributedTarget, EstateManager, DistributedEstate, DistributedHouse, DistributedHouseInterior, DistributedGarden, DistributedHouseDoor, DistributedMailbox, DistributedFurnitureManager, DistributedFurnitureItem, DistributedBank, DistributedCloset, DistributedTrunk, DistributedPhone, DistributedFireworksCannon, DistributedLawnDecor, DistributedGardenPlot, DistributedGardenBox, DistributedFlower, DistributedGagTree, DistributedStatuary, DistributedToonStatuary, DistributedChangingStatuary, DistributedAnimatedStatuary, DistributedPlantBase, DistributedLawnDecor
|
|
||||||
from toontown.uberdog.DistributedLobbyManager import DistributedLobbyManager
|
|
||||||
from toontown.toon import DistributedToon, DistributedNPCToonBase, DistributedNPCToon, DistributedSmartNPC, DistributedNPCSpecialQuestGiver, DistributedNPCFlippyInToonHall, DistributedNPCScientist, DistributedNPCClerk, DistributedNPCTailor, DistributedNPCBlocker, DistributedNPCFisherman, DistributedNPCPartyPerson, DistributedNPCPetclerk, DistributedNPCKartClerk, DistributedNPCGlove, DistributedNPCLaffRestock
|
|
||||||
from toontown.tutorial import DistributedBattleTutorial, TutorialManager
|
|
||||||
from toontown.pets import DistributedPetProxy
|
|
||||||
from toontown.coderedemption.TTCodeRedemptionMgr import TTCodeRedemptionMgr
|
|
||||||
from direct.distributed import DistributedObject, DistributedNode, DistributedSmoothNode, DistributedCartesianGrid, DistributedCamera, DistributedObjectGlobal
|
|
||||||
from otp.ai import TimeManager, MagicWordManager
|
|
||||||
from otp.avatar import DistributedAvatar, DistributedPlayer, AvatarHandle
|
|
||||||
from toontown.battle import DistributedBattleBase, DistributedBattle, DistributedBattleBldg, DistributedBattleFinal, DistributedBattleWaiters, DistributedBattleDiners
|
|
||||||
|
|
||||||
|
|
||||||
dcImports = locals().copy()
|
|
|
@ -11,7 +11,7 @@ from direct.task import Task
|
||||||
from pandac.PandaModules import *
|
from pandac.PandaModules import *
|
||||||
from otp.avatar import Avatar, DistributedAvatar
|
from otp.avatar import Avatar, DistributedAvatar
|
||||||
from otp.avatar.DistributedPlayer import DistributedPlayer
|
from otp.avatar.DistributedPlayer import DistributedPlayer
|
||||||
from otp.distributed import DCClassImports, OtpDoGlobals
|
from otp.distributed import OtpDoGlobals
|
||||||
from otp.distributed.OtpDoGlobals import *
|
from otp.distributed.OtpDoGlobals import *
|
||||||
from otp.distributed.TelemetryLimiter import TelemetryLimiter
|
from otp.distributed.TelemetryLimiter import TelemetryLimiter
|
||||||
from otp.otpbase import OTPGlobals, OTPLocalizer
|
from otp.otpbase import OTPGlobals, OTPLocalizer
|
||||||
|
@ -218,50 +218,154 @@ class OTPClientRepository(ClientRepositoryBase):
|
||||||
self.dclassesByName = {}
|
self.dclassesByName = {}
|
||||||
self.dclassesByNumber = {}
|
self.dclassesByNumber = {}
|
||||||
self.hashVal = 0
|
self.hashVal = 0
|
||||||
try:
|
|
||||||
dcStream
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
self.notify.info('Detected DC file stream, reading it...')
|
|
||||||
dcFileNames = [dcStream]
|
|
||||||
|
|
||||||
if isinstance(dcFileNames, str):
|
if isinstance(dcFileNames, types.StringTypes):
|
||||||
|
# If we were given a single string, make it a list.
|
||||||
dcFileNames = [dcFileNames]
|
dcFileNames = [dcFileNames]
|
||||||
|
|
||||||
if dcFileNames is not None:
|
dcImports = {}
|
||||||
for dcFileName in dcFileNames:
|
if dcFileNames == None:
|
||||||
if isinstance(dcFileName, StringStream):
|
try:
|
||||||
readResult = dcFile.read(dcFileName, 'DC stream')
|
# For Nirai
|
||||||
else:
|
readResult = dcFile.read(dcStream, '__dc__')
|
||||||
readResult = dcFile.read(dcFileName)
|
del __builtin__.dcStream
|
||||||
if not readResult:
|
|
||||||
self.notify.error('Could not read DC file.')
|
|
||||||
else:
|
|
||||||
dcFile.readAll()
|
|
||||||
|
|
||||||
self.hashVal = DCClassImports.hashVal
|
except NameError:
|
||||||
for i in xrange(dcFile.getNumClasses()):
|
readResult = dcFile.readAll()
|
||||||
|
|
||||||
|
if not readResult:
|
||||||
|
self.notify.error("Could not read dc file.")
|
||||||
|
|
||||||
|
else:
|
||||||
|
searchPath = getModelPath().getValue()
|
||||||
|
for dcFileName in dcFileNames:
|
||||||
|
pathname = Filename(dcFileName)
|
||||||
|
vfs.resolveFilename(pathname, searchPath)
|
||||||
|
readResult = dcFile.read(pathname)
|
||||||
|
if not readResult:
|
||||||
|
self.notify.error("Could not read dc file: %s" % (pathname))
|
||||||
|
|
||||||
|
self.hashVal = dcFile.getHash()
|
||||||
|
|
||||||
|
# Now import all of the modules required by the DC file.
|
||||||
|
for n in range(dcFile.getNumImportModules()):
|
||||||
|
moduleName = dcFile.getImportModule(n)[:]
|
||||||
|
|
||||||
|
# Maybe the module name is represented as "moduleName/AI".
|
||||||
|
suffix = moduleName.split('/')
|
||||||
|
moduleName = suffix[0]
|
||||||
|
suffix=suffix[1:]
|
||||||
|
if self.dcSuffix in suffix:
|
||||||
|
moduleName += self.dcSuffix
|
||||||
|
elif self.dcSuffix == 'UD' and 'AI' in suffix: #HACK:
|
||||||
|
moduleName += 'AI'
|
||||||
|
|
||||||
|
importSymbols = []
|
||||||
|
for i in range(dcFile.getNumImportSymbols(n)):
|
||||||
|
symbolName = dcFile.getImportSymbol(n, i)
|
||||||
|
|
||||||
|
# Maybe the symbol name is represented as "symbolName/AI".
|
||||||
|
suffix = symbolName.split('/')
|
||||||
|
symbolName = suffix[0]
|
||||||
|
suffix=suffix[1:]
|
||||||
|
if self.dcSuffix in suffix:
|
||||||
|
symbolName += self.dcSuffix
|
||||||
|
elif self.dcSuffix == 'UD' and 'AI' in suffix: #HACK:
|
||||||
|
symbolName += 'AI'
|
||||||
|
|
||||||
|
importSymbols.append(symbolName)
|
||||||
|
|
||||||
|
self.importModule(dcImports, moduleName, importSymbols)
|
||||||
|
|
||||||
|
# Now get the class definition for the classes named in the DC
|
||||||
|
# file.
|
||||||
|
for i in range(dcFile.getNumClasses()):
|
||||||
dclass = dcFile.getClass(i)
|
dclass = dcFile.getClass(i)
|
||||||
number = dclass.getNumber()
|
number = dclass.getNumber()
|
||||||
className = dclass.getName()
|
className = dclass.getName() + self.dcSuffix
|
||||||
classDef = DCClassImports.dcImports.get(className)
|
|
||||||
|
# Does the class have a definition defined in the newly
|
||||||
|
# imported namespace?
|
||||||
|
classDef = dcImports.get(className)
|
||||||
|
if classDef is None and self.dcSuffix == 'UD': #HACK:
|
||||||
|
className = dclass.getName() + 'AI'
|
||||||
|
classDef = dcImports.get(className)
|
||||||
|
|
||||||
|
# Also try it without the dcSuffix.
|
||||||
|
if classDef == None:
|
||||||
|
className = dclass.getName()
|
||||||
|
classDef = dcImports.get(className)
|
||||||
if classDef is None:
|
if classDef is None:
|
||||||
self.notify.debug('No class definition for %s.' % className)
|
self.notify.debug("No class definition for %s." % (className))
|
||||||
else:
|
else:
|
||||||
if type(classDef) == types.ModuleType:
|
if type(classDef) == types.ModuleType:
|
||||||
if not hasattr(classDef, className):
|
if not hasattr(classDef, className):
|
||||||
self.notify.warning('Module %s does not define class %s.' % (className, className))
|
self.notify.warning("Module %s does not define class %s." % (className, className))
|
||||||
continue
|
continue
|
||||||
classDef = getattr(classDef, className)
|
classDef = getattr(classDef, className)
|
||||||
if (type(classDef) != types.ClassType) and (type(classDef) != types.TypeType):
|
|
||||||
self.notify.error('Symbol %s is not a class name.' % className)
|
if type(classDef) != types.ClassType and type(classDef) != types.TypeType:
|
||||||
|
self.notify.error("Symbol %s is not a class name." % (className))
|
||||||
else:
|
else:
|
||||||
dclass.setClassDef(classDef)
|
dclass.setClassDef(classDef)
|
||||||
|
|
||||||
self.dclassesByName[className] = dclass
|
self.dclassesByName[className] = dclass
|
||||||
if number >= 0:
|
if number >= 0:
|
||||||
self.dclassesByNumber[number] = dclass
|
self.dclassesByNumber[number] = dclass
|
||||||
|
|
||||||
|
# Owner Views
|
||||||
|
if self.hasOwnerView():
|
||||||
|
ownerDcSuffix = self.dcSuffix + 'OV'
|
||||||
|
# dict of class names (without 'OV') that have owner views
|
||||||
|
ownerImportSymbols = {}
|
||||||
|
|
||||||
|
# Now import all of the modules required by the DC file.
|
||||||
|
for n in range(dcFile.getNumImportModules()):
|
||||||
|
moduleName = dcFile.getImportModule(n)
|
||||||
|
|
||||||
|
# Maybe the module name is represented as "moduleName/AI".
|
||||||
|
suffix = moduleName.split('/')
|
||||||
|
moduleName = suffix[0]
|
||||||
|
suffix=suffix[1:]
|
||||||
|
if ownerDcSuffix in suffix:
|
||||||
|
moduleName = moduleName + ownerDcSuffix
|
||||||
|
|
||||||
|
importSymbols = []
|
||||||
|
for i in range(dcFile.getNumImportSymbols(n)):
|
||||||
|
symbolName = dcFile.getImportSymbol(n, i)
|
||||||
|
|
||||||
|
# Check for the OV suffix
|
||||||
|
suffix = symbolName.split('/')
|
||||||
|
symbolName = suffix[0]
|
||||||
|
suffix=suffix[1:]
|
||||||
|
if ownerDcSuffix in suffix:
|
||||||
|
symbolName += ownerDcSuffix
|
||||||
|
importSymbols.append(symbolName)
|
||||||
|
ownerImportSymbols[symbolName] = None
|
||||||
|
|
||||||
|
self.importModule(dcImports, moduleName, importSymbols)
|
||||||
|
|
||||||
|
# Now get the class definition for the owner classes named
|
||||||
|
# in the DC file.
|
||||||
|
for i in range(dcFile.getNumClasses()):
|
||||||
|
dclass = dcFile.getClass(i)
|
||||||
|
if ((dclass.getName()+ownerDcSuffix) in ownerImportSymbols):
|
||||||
|
number = dclass.getNumber()
|
||||||
|
className = dclass.getName() + ownerDcSuffix
|
||||||
|
|
||||||
|
# Does the class have a definition defined in the newly
|
||||||
|
# imported namespace?
|
||||||
|
classDef = dcImports.get(className)
|
||||||
|
if classDef is None:
|
||||||
|
self.notify.error("No class definition for %s." % className)
|
||||||
|
else:
|
||||||
|
if type(classDef) == types.ModuleType:
|
||||||
|
if not hasattr(classDef, className):
|
||||||
|
self.notify.error("Module %s does not define class %s." % (className, className))
|
||||||
|
classDef = getattr(classDef, className)
|
||||||
|
dclass.setOwnerClassDef(classDef)
|
||||||
|
self.dclassesByName[className] = dclass
|
||||||
|
|
||||||
def getGameDoId(self):
|
def getGameDoId(self):
|
||||||
return self.GameGlobalsId
|
return self.GameGlobalsId
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,9 @@ args = parser.parse_args()
|
||||||
for prc in args.config:
|
for prc in args.config:
|
||||||
loadPrcFile(prc)
|
loadPrcFile(prc)
|
||||||
|
|
||||||
|
if os.path.isfile('dependencies/config/local.prc'):
|
||||||
|
loadPrcFile('dependencies/config/local.prc')
|
||||||
|
|
||||||
localconfig = ''
|
localconfig = ''
|
||||||
if args.base_channel: localconfig += 'air-base-channel %s\n' % args.base_channel
|
if args.base_channel: localconfig += 'air-base-channel %s\n' % args.base_channel
|
||||||
if args.max_channels: localconfig += 'air-channel-allocation %s\n' % args.max_channels
|
if args.max_channels: localconfig += 'air-channel-allocation %s\n' % args.max_channels
|
||||||
|
|
|
@ -32,6 +32,9 @@ if __debug__:
|
||||||
loadPrcFile('dependencies/config/general.prc')
|
loadPrcFile('dependencies/config/general.prc')
|
||||||
loadPrcFile('dependencies/config/release/dev.prc')
|
loadPrcFile('dependencies/config/release/dev.prc')
|
||||||
|
|
||||||
|
if os.path.isfile('dependencies/config/local.prc'):
|
||||||
|
loadPrcFile('dependencies/config/local.prc')
|
||||||
|
|
||||||
defaultText = ""
|
defaultText = ""
|
||||||
|
|
||||||
def __inject_wx(_):
|
def __inject_wx(_):
|
||||||
|
|
|
@ -1,45 +1,74 @@
|
||||||
import anydbm
|
|
||||||
import base64
|
|
||||||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||||
from direct.distributed.DistributedObjectGlobalUD import DistributedObjectGlobalUD
|
from direct.distributed.DistributedObjectGlobalUD import DistributedObjectGlobalUD
|
||||||
from direct.distributed.PyDatagram import *
|
from direct.distributed.PyDatagram import *
|
||||||
from direct.fsm.FSM import FSM
|
from direct.fsm.FSM import FSM
|
||||||
import hashlib
|
|
||||||
import hmac
|
|
||||||
import json
|
|
||||||
from pandac.PandaModules import *
|
|
||||||
import time
|
|
||||||
import urllib2
|
|
||||||
import os
|
|
||||||
from otp.ai.MagicWordGlobal import *
|
from otp.ai.MagicWordGlobal import *
|
||||||
from otp.distributed import OtpDoGlobals
|
from otp.distributed import OtpDoGlobals
|
||||||
|
|
||||||
from toontown.makeatoon.NameGenerator import NameGenerator
|
from toontown.makeatoon.NameGenerator import NameGenerator
|
||||||
from toontown.toon.ToonDNA import ToonDNA
|
from toontown.toon.ToonDNA import ToonDNA
|
||||||
from toontown.toonbase import TTLocalizer
|
from toontown.toonbase import TTLocalizer
|
||||||
from toontown.uberdog import NameJudgeBlacklist
|
from toontown.uberdog import NameJudgeBlacklist
|
||||||
|
|
||||||
|
from pandac.PandaModules import *
|
||||||
|
|
||||||
# Import from PyCrypto only if we are using a database that requires it. This
|
import hashlib, hmac, json
|
||||||
# allows local hosted and developer builds of the game to run without it:
|
import anydbm, math, os
|
||||||
accountDBType = simbase.config.GetString('accountdb-type', 'developer')
|
import urllib2, time
|
||||||
|
|
||||||
|
def rejectConfig(issue, securityIssue=True, retarded=True):
|
||||||
|
print
|
||||||
|
print
|
||||||
|
print 'Lemme get this straight....'
|
||||||
|
print 'You are trying to use remote account database type...'
|
||||||
|
print 'However,', issue + '!!!!'
|
||||||
|
if securityIssue:
|
||||||
|
print 'Do you want this server to get hacked?'
|
||||||
|
if retarded:
|
||||||
|
print '"Either down\'s or autism"\n - JohnnyDaPirate, 2015'
|
||||||
|
print 'Go fix that!'
|
||||||
|
exit()
|
||||||
|
|
||||||
|
def entropy(string):
|
||||||
|
prob = [float(string.count(c)) / len(string) for c in dict.fromkeys(list(string))]
|
||||||
|
entropy = -sum([p * math.log(p) / math.log(2.0) for p in prob])
|
||||||
|
return entropy
|
||||||
|
|
||||||
|
def entropyIdeal(length):
|
||||||
|
prob = 1.0 / length
|
||||||
|
return -length * prob * math.log(prob) / math.log(2.0)
|
||||||
|
|
||||||
|
accountDBType = config.GetString('accountdb-type', 'developer')
|
||||||
|
accountServerSecret = config.GetString('account-server-secret', 'dev')
|
||||||
|
accountServerHashAlgo = config.GetString('account-server-hash-algo', 'sha512')
|
||||||
if accountDBType == 'remote':
|
if accountDBType == 'remote':
|
||||||
from Crypto.Cipher import AES
|
if accountServerSecret == 'dev':
|
||||||
|
rejectConfig('you have not changed the secret in config/local.prc')
|
||||||
|
|
||||||
# Sometimes we'll want to force a specific access level, such as on the
|
if len(accountServerSecret) < 16:
|
||||||
# developer server:
|
rejectConfig('the secret is too small! Make it 16+ bytes', retarded=False)
|
||||||
minAccessLevel = simbase.config.GetInt('min-access-level', 100)
|
|
||||||
|
|
||||||
accountServerEndpoint = simbase.config.GetString(
|
secretLength = len(accountServerSecret)
|
||||||
'account-server-endpoint', 'http://tigercat1.me/tmpremote/api/')
|
ideal = entropyIdeal(secretLength) / 2
|
||||||
accountServerSecret = simbase.config.GetString(
|
entropy = entropy(accountServerSecret)
|
||||||
'account-server-secret', '9sj6816aj1hs795j')
|
if entropy < ideal:
|
||||||
|
rejectConfig('the secret entropy is too low! For %d bytes,'
|
||||||
|
' it should be %d. Currently it is %d' % (secretLength, ideal, entropy),
|
||||||
|
retarded=False)
|
||||||
|
|
||||||
|
hashAlgo = getattr(hashlib, accountServerHashAlgo, None)
|
||||||
|
if not hashAlgo:
|
||||||
|
rejectConfig('%s is not a valid hash algo' % accountServerHashAlgo, securityIssue=False)
|
||||||
|
|
||||||
http = HTTPClient()
|
hashSize = len(hashAlgo('').digest())
|
||||||
http.setVerifySsl(0)
|
|
||||||
|
|
||||||
|
minAccessLevel = config.GetInt('min-access-level', 100)
|
||||||
|
|
||||||
def executeHttpRequest(url, **extras):
|
def executeHttpRequest(url, **extras):
|
||||||
|
# TO DO: THIS IS QUITE DISGUSTING
|
||||||
|
# INSTEAD OF USING THE SAME SECRET, WE SHOULD HAVE AN API KEY EXCLUSIVE TO THAT
|
||||||
|
# MOVE THIS TO ToontownInternalRepository (this might be interesting for AI)
|
||||||
request = urllib2.Request('http://tigercat1.me/tmpremote/api/' + url)
|
request = urllib2.Request('http://tigercat1.me/tmpremote/api/' + url)
|
||||||
timestamp = str(int(time.time()))
|
timestamp = str(int(time.time()))
|
||||||
signature = hashlib.sha256(timestamp + accountServerSecret + "h*^ahJGHA017JI&A&*uyhU07")
|
signature = hashlib.sha256(timestamp + accountServerSecret + "h*^ahJGHA017JI&A&*uyhU07")
|
||||||
|
@ -53,10 +82,10 @@ def executeHttpRequest(url, **extras):
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
notify = directNotify.newCategory('ClientServicesManagerUD')
|
notify = directNotify.newCategory('ClientServicesManagerUD')
|
||||||
|
|
||||||
def executeHttpRequestAndLog(url, **extras):
|
def executeHttpRequestAndLog(url, **extras):
|
||||||
|
# SEE ABOVE
|
||||||
response = executeHttpRequest(url, extras)
|
response = executeHttpRequest(url, extras)
|
||||||
|
|
||||||
if response is None:
|
if response is None:
|
||||||
|
@ -93,20 +122,17 @@ def judgeName(name):
|
||||||
|
|
||||||
# --- ACCOUNT DATABASES ---
|
# --- ACCOUNT DATABASES ---
|
||||||
# These classes make up the available account databases for Toontown Stride.
|
# These classes make up the available account databases for Toontown Stride.
|
||||||
# Databases with login tokens use the PyCrypto module for decrypting them.
|
|
||||||
# DeveloperAccountDB is a special database that accepts a username, and assigns
|
# DeveloperAccountDB is a special database that accepts a username, and assigns
|
||||||
# each user with 700 access automatically upon login.
|
# each user with 700 access automatically upon login.
|
||||||
|
|
||||||
|
|
||||||
class AccountDB:
|
class AccountDB:
|
||||||
notify = directNotify.newCategory('AccountDB')
|
notify = directNotify.newCategory('AccountDB')
|
||||||
|
|
||||||
def __init__(self, csm):
|
def __init__(self, csm):
|
||||||
self.csm = csm
|
self.csm = csm
|
||||||
|
|
||||||
filename = simbase.config.GetString(
|
filename = config.GetString('account-bridge-filename', 'account-bridge.db')
|
||||||
'account-bridge-filename', 'account-bridge.db')
|
filename = os.path.join('dependencies', filename)
|
||||||
filename = os.path.join("dependencies", filename)
|
|
||||||
|
|
||||||
self.dbm = anydbm.open(filename, 'c')
|
self.dbm = anydbm.open(filename, 'c')
|
||||||
|
|
||||||
|
@ -119,8 +145,20 @@ class AccountDB:
|
||||||
def removeNameRequest(self, avId):
|
def removeNameRequest(self, avId):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def lookup(self, username, callback):
|
def lookup(self, data, callback):
|
||||||
pass # Inheritors should override this.
|
userId = data['userId']
|
||||||
|
|
||||||
|
data['success'] = True
|
||||||
|
data['accessLevel'] = max(data['accessLevel'], minAccessLevel)
|
||||||
|
|
||||||
|
if str(userId) not in self.dbm:
|
||||||
|
data['accountId'] = 0
|
||||||
|
|
||||||
|
else:
|
||||||
|
data['accountId'] = int(self.dbm[str(userId)])
|
||||||
|
|
||||||
|
callback(data)
|
||||||
|
return data
|
||||||
|
|
||||||
def storeAccountID(self, userId, accountId, callback):
|
def storeAccountID(self, userId, accountId, callback):
|
||||||
self.dbm[str(userId)] = str(accountId) # anydbm only allows strings.
|
self.dbm[str(userId)] = str(accountId) # anydbm only allows strings.
|
||||||
|
@ -131,33 +169,20 @@ class AccountDB:
|
||||||
self.notify.warning('Unable to associate user %s with account %d!' % (userId, accountId))
|
self.notify.warning('Unable to associate user %s with account %d!' % (userId, accountId))
|
||||||
callback(False)
|
callback(False)
|
||||||
|
|
||||||
|
|
||||||
class DeveloperAccountDB(AccountDB):
|
class DeveloperAccountDB(AccountDB):
|
||||||
notify = directNotify.newCategory('DeveloperAccountDB')
|
notify = directNotify.newCategory('DeveloperAccountDB')
|
||||||
|
|
||||||
def lookup(self, username, callback):
|
def lookup(self, userId, callback):
|
||||||
# Let's check if this user's ID is in your account database bridge:
|
return AccountDB.lookup(self, {'userId': userId,
|
||||||
if str(username) not in self.dbm:
|
'accessLevel': 700,
|
||||||
# Nope. Let's associate them with a brand new Account object! We
|
'notAfter': 0},
|
||||||
# will assign them with 700 access just because they are a
|
callback)
|
||||||
# developer:
|
|
||||||
response = {
|
|
||||||
'success': True,
|
|
||||||
'userId': username,
|
|
||||||
'accountId': 0,
|
|
||||||
'accessLevel': max(700, minAccessLevel)
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
# We have an account already, let's return what we've got:
|
|
||||||
response = {
|
|
||||||
'success': True,
|
|
||||||
'userId': username,
|
|
||||||
'accountId': int(self.dbm[str(username)]),
|
|
||||||
}
|
|
||||||
callback(response)
|
|
||||||
return response
|
|
||||||
|
|
||||||
class RemoteAccountDB(AccountDB):
|
class RemoteAccountDB(AccountDB):
|
||||||
|
# TO DO FOR NAMES:
|
||||||
|
# CURRENTLY IT MAKES n REQUESTS FOR EACH AVATAR
|
||||||
|
# IN THE FUTURE, MAKE ONLY 1 REQUEST
|
||||||
|
# WHICH RETURNS ALL PENDING AVS
|
||||||
notify = directNotify.newCategory('RemoteAccountDB')
|
notify = directNotify.newCategory('RemoteAccountDB')
|
||||||
|
|
||||||
def addNameRequest(self, avId, name):
|
def addNameRequest(self, avId, name):
|
||||||
|
@ -171,105 +196,43 @@ class RemoteAccountDB(AccountDB):
|
||||||
return executeHttpRequest('names/remove', ID=str(avId))
|
return executeHttpRequest('names/remove', ID=str(avId))
|
||||||
|
|
||||||
def lookup(self, token, callback):
|
def lookup(self, token, callback):
|
||||||
# First, base64 decode the token:
|
'''
|
||||||
|
Token format:
|
||||||
|
The token is obfuscated a bit, but nothing too hard to read.
|
||||||
|
Most of the security is based on the hash.
|
||||||
|
|
||||||
|
I. Data contained in a token:
|
||||||
|
A json-encoded dict, which contains timestamp, userid and extra info
|
||||||
|
|
||||||
|
II. Token format
|
||||||
|
X = BASE64(ROT13(DATA)[::-1])
|
||||||
|
H = HASH(X)[::-1]
|
||||||
|
Token = BASE64(H + X)
|
||||||
|
'''
|
||||||
|
|
||||||
try:
|
try:
|
||||||
token = base64.b64decode(token)
|
token = token.decode('base64')
|
||||||
except TypeError:
|
hash, token = token[:hashSize], token[hashSize:]
|
||||||
self.notify.warning('Could not decode the provided token!')
|
|
||||||
response = {
|
|
||||||
'success': False,
|
|
||||||
'reason': "Can't decode this token."
|
|
||||||
}
|
|
||||||
callback(response)
|
|
||||||
return response
|
|
||||||
|
|
||||||
# Ensure this token is a valid size:
|
correctHash = hashAlgo(token + accountServerSecret).digest()
|
||||||
if (not token) or ((len(token) % 16) != 0):
|
if len(hash) != len(correctHash):
|
||||||
self.notify.warning('Invalid token length!')
|
raise ValueError('invalid hash')
|
||||||
response = {
|
|
||||||
'success': False,
|
|
||||||
'reason': 'Invalid token length.'
|
|
||||||
}
|
|
||||||
callback(response)
|
|
||||||
return response
|
|
||||||
|
|
||||||
# Next, decrypt the token using AES-128 in CBC mode:
|
value = 0
|
||||||
accountServerSecret = simbase.config.GetString(
|
for x, y in zip(hash[::-1], correctHash):
|
||||||
'account-server-secret', '9sj6816aj1hs795j')
|
value |= ord(x) ^ ord(y)
|
||||||
|
|
||||||
# Ensure that our secret is the correct size:
|
if value:
|
||||||
if len(accountServerSecret) > AES.block_size:
|
raise ValueError('invalid hash')
|
||||||
self.notify.warning('account-server-secret is too big!')
|
|
||||||
accountServerSecret = accountServerSecret[:AES.block_size]
|
|
||||||
elif len(accountServerSecret) < AES.block_size:
|
|
||||||
self.notify.warning('account-server-secret is too small!')
|
|
||||||
accountServerSecret += '\x80'
|
|
||||||
while len(accountServerSecret) < AES.block_size:
|
|
||||||
accountServerSecret += '\x00'
|
|
||||||
|
|
||||||
# Take the initialization vector off the front of the token:
|
token = json.loads(token.decode('base64')[::-1].decode('rot13'))
|
||||||
iv = token[:AES.block_size]
|
|
||||||
|
|
||||||
# Truncate the token to get our cipher text:
|
except:
|
||||||
cipherText = token[AES.block_size:]
|
resp = {'success': False}
|
||||||
|
callback(resp)
|
||||||
# Decrypt!
|
return resp
|
||||||
cipher = AES.new(accountServerSecret, mode=AES.MODE_CBC, IV=iv)
|
|
||||||
try:
|
|
||||||
token = json.loads(cipher.decrypt(cipherText).replace('\x00', ''))
|
|
||||||
if ('timestamp' not in token) or (not isinstance(token['timestamp'], int)):
|
|
||||||
raise ValueError
|
|
||||||
if ('userid' not in token) or (not isinstance(token['userid'], int)):
|
|
||||||
raise ValueError
|
|
||||||
if ('accesslevel' not in token) or (not isinstance(token['accesslevel'], int)):
|
|
||||||
raise ValueError
|
|
||||||
except ValueError, e:
|
|
||||||
print e
|
|
||||||
self.notify.warning('Invalid token.')
|
|
||||||
response = {
|
|
||||||
'success': False,
|
|
||||||
'reason': 'Invalid token.'
|
|
||||||
}
|
|
||||||
callback(response)
|
|
||||||
return response
|
|
||||||
|
|
||||||
# Next, check if this token has expired:
|
|
||||||
expiration = simbase.config.GetInt('account-token-expiration', 1800)
|
|
||||||
tokenDelta = int(time.time()) - token['timestamp']
|
|
||||||
if tokenDelta > expiration:
|
|
||||||
response = {
|
|
||||||
'success': False,
|
|
||||||
'reason': 'This token has expired.'
|
|
||||||
}
|
|
||||||
callback(response)
|
|
||||||
return response
|
|
||||||
|
|
||||||
# This token is valid. That's all we need to know. Next, let's check if
|
|
||||||
# this user's ID is in your account database bridge:
|
|
||||||
if str(token['userid']) not in self.dbm:
|
|
||||||
|
|
||||||
# Nope. Let's associate them with a brand new Account object!
|
|
||||||
response = {
|
|
||||||
'success': True,
|
|
||||||
'userId': token['userid'],
|
|
||||||
'accountId': 0,
|
|
||||||
'accessLevel': max(int(token['accesslevel']), minAccessLevel)
|
|
||||||
}
|
|
||||||
callback(response)
|
|
||||||
return response
|
|
||||||
|
|
||||||
else:
|
|
||||||
|
|
||||||
# Yep. Let's return their account ID and access level!
|
|
||||||
response = {
|
|
||||||
'success': True,
|
|
||||||
'userId': token['userid'],
|
|
||||||
'accountId': int(self.dbm[str(token['userid'])]),
|
|
||||||
'accessLevel': max(int(token['accesslevel']), minAccessLevel)
|
|
||||||
}
|
|
||||||
callback(response)
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
return AccountDB.lookup(self, token, callback)
|
||||||
|
|
||||||
# --- FSMs ---
|
# --- FSMs ---
|
||||||
class OperationFSM(FSM):
|
class OperationFSM(FSM):
|
||||||
|
@ -294,7 +257,6 @@ class OperationFSM(FSM):
|
||||||
else:
|
else:
|
||||||
del self.csm.account2fsm[self.target]
|
del self.csm.account2fsm[self.target]
|
||||||
|
|
||||||
|
|
||||||
class LoginAccountFSM(OperationFSM):
|
class LoginAccountFSM(OperationFSM):
|
||||||
notify = directNotify.newCategory('LoginAccountFSM')
|
notify = directNotify.newCategory('LoginAccountFSM')
|
||||||
TARGET_CONNECTION = True
|
TARGET_CONNECTION = True
|
||||||
|
@ -315,6 +277,7 @@ class LoginAccountFSM(OperationFSM):
|
||||||
self.userId = result.get('userId', 0)
|
self.userId = result.get('userId', 0)
|
||||||
self.accountId = result.get('accountId', 0)
|
self.accountId = result.get('accountId', 0)
|
||||||
self.accessLevel = result.get('accessLevel', 0)
|
self.accessLevel = result.get('accessLevel', 0)
|
||||||
|
self.notAfter = result.get('notAfter', 0)
|
||||||
if self.accountId:
|
if self.accountId:
|
||||||
self.demand('RetrieveAccount')
|
self.demand('RetrieveAccount')
|
||||||
else:
|
else:
|
||||||
|
@ -330,6 +293,12 @@ class LoginAccountFSM(OperationFSM):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.account = fields
|
self.account = fields
|
||||||
|
|
||||||
|
if self.notAfter:
|
||||||
|
if self.account.get('LAST_LOGIN_TS', 0) > self.notAfter:
|
||||||
|
self.notify.debug('Rejecting old token: %d, notAfter=%d' % (self.account.get('LAST_LOGIN_TS', 0), self.notAfter))
|
||||||
|
return self.__handleLookup({'success': False})
|
||||||
|
|
||||||
self.demand('SetAccount')
|
self.demand('SetAccount')
|
||||||
|
|
||||||
def enterCreateAccount(self):
|
def enterCreateAccount(self):
|
||||||
|
@ -339,6 +308,7 @@ class LoginAccountFSM(OperationFSM):
|
||||||
'ACCOUNT_AV_SET_DEL': [],
|
'ACCOUNT_AV_SET_DEL': [],
|
||||||
'CREATED': time.ctime(),
|
'CREATED': time.ctime(),
|
||||||
'LAST_LOGIN': time.ctime(),
|
'LAST_LOGIN': time.ctime(),
|
||||||
|
'LAST_LOGIN_TS': time.time(),
|
||||||
'ACCOUNT_ID': str(self.userId),
|
'ACCOUNT_ID': str(self.userId),
|
||||||
'ACCESS_LEVEL': self.accessLevel
|
'ACCESS_LEVEL': self.accessLevel
|
||||||
}
|
}
|
||||||
|
@ -403,7 +373,7 @@ class LoginAccountFSM(OperationFSM):
|
||||||
datagram.addChannel(self.csm.GetAccountConnectionChannel(self.accountId))
|
datagram.addChannel(self.csm.GetAccountConnectionChannel(self.accountId))
|
||||||
self.csm.air.send(datagram)
|
self.csm.air.send(datagram)
|
||||||
|
|
||||||
# Subscribe to any "staff" channels that the account has access to.
|
# Subscribe to any "staff" channels that the account has access to.
|
||||||
access = self.account.get('ADMIN_ACCESS', 0)
|
access = self.account.get('ADMIN_ACCESS', 0)
|
||||||
if access >= 200:
|
if access >= 200:
|
||||||
# Subscribe to the moderator channel.
|
# Subscribe to the moderator channel.
|
||||||
|
@ -449,6 +419,7 @@ class LoginAccountFSM(OperationFSM):
|
||||||
self.accountId,
|
self.accountId,
|
||||||
self.csm.air.dclassesByName['AccountUD'],
|
self.csm.air.dclassesByName['AccountUD'],
|
||||||
{'LAST_LOGIN': time.ctime(),
|
{'LAST_LOGIN': time.ctime(),
|
||||||
|
'LAST_LOGIN_TS': time.time(),
|
||||||
'ACCOUNT_ID': str(self.userId)})
|
'ACCOUNT_ID': str(self.userId)})
|
||||||
|
|
||||||
# We're done.
|
# We're done.
|
||||||
|
@ -547,7 +518,6 @@ class CreateAvatarFSM(OperationFSM):
|
||||||
self.csm.sendUpdateToAccountId(self.target, 'createAvatarResp', [self.avId])
|
self.csm.sendUpdateToAccountId(self.target, 'createAvatarResp', [self.avId])
|
||||||
self.demand('Off')
|
self.demand('Off')
|
||||||
|
|
||||||
|
|
||||||
class AvatarOperationFSM(OperationFSM):
|
class AvatarOperationFSM(OperationFSM):
|
||||||
POST_ACCOUNT_STATE = 'Off' # This needs to be overridden.
|
POST_ACCOUNT_STATE = 'Off' # This needs to be overridden.
|
||||||
|
|
||||||
|
@ -570,7 +540,6 @@ class AvatarOperationFSM(OperationFSM):
|
||||||
|
|
||||||
self.demand(self.POST_ACCOUNT_STATE)
|
self.demand(self.POST_ACCOUNT_STATE)
|
||||||
|
|
||||||
|
|
||||||
class GetAvatarsFSM(AvatarOperationFSM):
|
class GetAvatarsFSM(AvatarOperationFSM):
|
||||||
notify = directNotify.newCategory('GetAvatarsFSM')
|
notify = directNotify.newCategory('GetAvatarsFSM')
|
||||||
POST_ACCOUNT_STATE = 'QueryAvatars'
|
POST_ACCOUNT_STATE = 'QueryAvatars'
|
||||||
|
@ -807,7 +776,6 @@ class SetNamePatternFSM(AvatarOperationFSM):
|
||||||
self.csm.sendUpdateToAccountId(self.target, 'setNamePatternResp', [self.avId, 1])
|
self.csm.sendUpdateToAccountId(self.target, 'setNamePatternResp', [self.avId, 1])
|
||||||
self.demand('Off')
|
self.demand('Off')
|
||||||
|
|
||||||
|
|
||||||
class AcknowledgeNameFSM(AvatarOperationFSM):
|
class AcknowledgeNameFSM(AvatarOperationFSM):
|
||||||
notify = directNotify.newCategory('AcknowledgeNameFSM')
|
notify = directNotify.newCategory('AcknowledgeNameFSM')
|
||||||
POST_ACCOUNT_STATE = 'GetTargetAvatar'
|
POST_ACCOUNT_STATE = 'GetTargetAvatar'
|
||||||
|
@ -863,7 +831,6 @@ class AcknowledgeNameFSM(AvatarOperationFSM):
|
||||||
self.csm.sendUpdateToAccountId(self.target, 'acknowledgeAvatarNameResp', [])
|
self.csm.sendUpdateToAccountId(self.target, 'acknowledgeAvatarNameResp', [])
|
||||||
self.demand('Off')
|
self.demand('Off')
|
||||||
|
|
||||||
|
|
||||||
class LoadAvatarFSM(AvatarOperationFSM):
|
class LoadAvatarFSM(AvatarOperationFSM):
|
||||||
notify = directNotify.newCategory('LoadAvatarFSM')
|
notify = directNotify.newCategory('LoadAvatarFSM')
|
||||||
POST_ACCOUNT_STATE = 'GetTargetAvatar'
|
POST_ACCOUNT_STATE = 'GetTargetAvatar'
|
||||||
|
@ -1007,7 +974,6 @@ class UnloadAvatarFSM(OperationFSM):
|
||||||
self.csm.air.writeServerEvent('avatarUnload', self.avId)
|
self.csm.air.writeServerEvent('avatarUnload', self.avId)
|
||||||
self.demand('Off')
|
self.demand('Off')
|
||||||
|
|
||||||
|
|
||||||
# --- CLIENT SERVICES MANAGER UBERDOG ---
|
# --- CLIENT SERVICES MANAGER UBERDOG ---
|
||||||
class ClientServicesManagerUD(DistributedObjectGlobalUD):
|
class ClientServicesManagerUD(DistributedObjectGlobalUD):
|
||||||
notify = directNotify.newCategory('ClientServicesManagerUD')
|
notify = directNotify.newCategory('ClientServicesManagerUD')
|
||||||
|
|
|
@ -33,6 +33,9 @@ args = parser.parse_args()
|
||||||
for prc in args.config:
|
for prc in args.config:
|
||||||
loadPrcFile(prc)
|
loadPrcFile(prc)
|
||||||
|
|
||||||
|
if os.path.isfile('dependencies/config/local.prc'):
|
||||||
|
loadPrcFile('dependencies/config/local.prc')
|
||||||
|
|
||||||
localconfig = ''
|
localconfig = ''
|
||||||
if args.base_channel:
|
if args.base_channel:
|
||||||
localconfig += 'air-base-channel %s\n' % args.base_channel
|
localconfig += 'air-base-channel %s\n' % args.base_channel
|
||||||
|
|
Loading…
Reference in a new issue