general: push the 2013 TTO code

This commit is contained in:
John Cote 2019-11-02 18:27:54 -04:00
parent 4e5cf131c0
commit 2c7d1a27da
1669 changed files with 432679 additions and 0 deletions

108
etc/Configrc.prc Normal file
View file

@ -0,0 +1,108 @@
cull-bin gui-popup 60 unsorted
want-render2dp 1
text-encoding utf8
direct-wtext 0
text-never-break-before ,.-:?!;
ime-aware 1
ime-hide 1
textures-power-2 down
paranoid-clock 1
lock-to-one-cpu 1
collect-tcp 1
collect-tcp-interval 0.2
server-version sv1.0.47.38
server-version-suffix
cull-bin shadow 15 fixed
cull-bin ground 14 fixed
model-path .
sound-path .
plugin-path .
dc-file phase_3/etc/toon.dc
dc-file phase_3/etc/otp.dc
window-title Toontown
verify-ssl 0
ssl-cipher-list DEFAULT
http-preapproved-server-certificate-filename ttown4.online.disney.com:46667 gameserver.txt
chan-config-sanity-check #f
require-window 0
language english
icon-filename toontown.ico
dx-management 1
tt-specific-login 1
decompressor-buffer-size 32768
extractor-buffer-size 32768
patcher-buffer-size 512000
downloader-timeout 15
downloader-timeout-retries 4
downloader-disk-write-frequency 4
downloader-byte-rate 125000
downloader-frequency 0.1
http-connect-timeout 20
http-timeout 30
contents-xml-dl-attempts 2
load-display pandadx9
aux-display pandadx9
aux-display pandadx8
aux-display pandagl
aux-display tinydisplay
win-size 800 600
fullscreen #t
load-file-type toontown
compress-channels #t
display-lists 0
early-random-seed 1
ssl-cipher-list DEFAULT
respect-prev-transform 1
notify-level-collide warning
notify-level-chan warning
notify-level-gobj warning
notify-level-loader warning
notify-timestamp #t
vfs-mount phase_3.mf . 0
vfs-mount phase_3.5.mf . 0
vfs-mount phase_4.mf . 0
vfs-mount phase_5.mf . 0
vfs-mount phase_5.5.mf . 0
vfs-mount phase_6.mf . 0
vfs-mount phase_7.mf . 0
vfs-mount phase_8.mf . 0
vfs-mount phase_9.mf . 0
vfs-mount phase_10.mf . 0
vfs-mount phase_11.mf . 0
default-model-extension .bam
decompressor-step-time 0.5
extractor-step-time 0.5
required-login playToken
server-failover 80 443
want-fog #t
dx-use-rangebased-fog #t
aspect-ratio 1.333333
on-screen-debug-font ImpressBT.ttf
temp-hpr-fix 1
vertex-buffers 0
dx-broken-max-index 1
vfs-case-sensitive 0
inactivity-timeout 180
merge-lod-bundles 0
early-event-sphere 1
accept-clock-skew 1
extra-ssl-handshake-time 20.0
clock-mode limited
clock-frame-rate 120
prefer-parasite-buffer 0
audio-library-name miles_audio
cursor-filename toonmono.cur
audio-loader mp3
audio-loader midi
audio-loader wav
audio-software-midi #t
audio-sfx-active #t
audio-music-active #t
audio-master-sfx-volume 1
audio-master-music-volume 1
server-type prod
##!
##!sig b1b9ca3e3322f3b65884483ec2b21300ec8f6f0bae1cfe70f8151b0d7c53fa2b
##!sig fb1cc546e32345e09b8eba50624ab167c684e87d1ff4debb11da5322eb573f05
##!sig c1dadb9a3589c86fbe0186afe1efa885223c4c64fd6ded3417f64ca17a5eaa12
##!sig 3f317329bf49ce60607de5b408bc730c6ccd54973a5166ea08782fb9fe31a0c2

0
otp/__init__.py Normal file
View file

175
otp/ai/AIBase.py Normal file
View file

@ -0,0 +1,175 @@
from pandac.PandaModules import *
from direct.directnotify.DirectNotifyGlobal import *
from direct.showbase.MessengerGlobal import *
from direct.showbase.BulletinBoardGlobal import *
from direct.task.TaskManagerGlobal import *
from direct.showbase.JobManagerGlobal import *
from direct.showbase.EventManagerGlobal import *
from direct.showbase.PythonUtil import *
from direct.showbase import PythonUtil
from direct.interval.IntervalManager import ivalMgr
from direct.task import Task
from direct.showbase import EventManager
from direct.showbase import ExceptionVarDump
import math
import sys
import time
import gc
class AIBase:
notify = directNotify.newCategory('AIBase')
def __init__(self):
self.config = getConfigShowbase()
__builtins__['__dev__'] = self.config.GetBool('want-dev', 0)
logStackDump = (self.config.GetBool('log-stack-dump', (not __dev__)) or self.config.GetBool('ai-log-stack-dump', (not __dev__)))
uploadStackDump = self.config.GetBool('upload-stack-dump', 0)
if logStackDump or uploadStackDump:
ExceptionVarDump.install(logStackDump, uploadStackDump)
if self.config.GetBool('use-vfs', 1):
vfs = VirtualFileSystem.getGlobalPtr()
else:
vfs = None
self.wantTk = self.config.GetBool('want-tk', 0)
self.AISleep = self.config.GetFloat('ai-sleep', 0.04)
self.AIRunningNetYield = self.config.GetBool('ai-running-net-yield', 0)
self.AIForceSleep = self.config.GetBool('ai-force-sleep', 0)
self.eventMgr = eventMgr
self.messenger = messenger
self.bboard = bulletinBoard
self.taskMgr = taskMgr
Task.TaskManager.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
Task.TaskManager.extendedExceptions = self.config.GetBool('extended-exceptions', 0)
self.sfxManagerList = None
self.musicManager = None
self.jobMgr = jobMgr
self.hidden = NodePath('hidden')
self.graphicsEngine = GraphicsEngine()
globalClock = ClockObject.getGlobalClock()
self.trueClock = TrueClock.getGlobalPtr()
globalClock.setRealTime(self.trueClock.getShortTime())
globalClock.setAverageFrameRateInterval(30.0)
globalClock.tick()
taskMgr.globalClock = globalClock
__builtins__['ostream'] = Notify.out()
__builtins__['globalClock'] = globalClock
__builtins__['vfs'] = vfs
__builtins__['hidden'] = self.hidden
AIBase.notify.info('__dev__ == %s' % __dev__)
PythonUtil.recordFunctorCreationStacks()
__builtins__['wantTestObject'] = self.config.GetBool('want-test-object', 0)
self.wantStats = self.config.GetBool('want-pstats', 0)
Task.TaskManager.pStatsTasks = self.config.GetBool('pstats-tasks', 0)
taskMgr.resumeFunc = PStatClient.resumeAfterPause
defaultValue = 1
if __dev__:
defaultValue = 0
wantFakeTextures = self.config.GetBool('want-fake-textures-ai', defaultValue)
if wantFakeTextures:
loadPrcFileData('aibase', 'textures-header-only 1')
self.wantPets = self.config.GetBool('want-pets', 1)
if self.wantPets:
if game.name == 'toontown':
from toontown.pets import PetConstants
self.petMoodTimescale = self.config.GetFloat('pet-mood-timescale', 1.0)
self.petMoodDriftPeriod = self.config.GetFloat('pet-mood-drift-period', PetConstants.MoodDriftPeriod)
self.petThinkPeriod = self.config.GetFloat('pet-think-period', PetConstants.ThinkPeriod)
self.petMovePeriod = self.config.GetFloat('pet-move-period', PetConstants.MovePeriod)
self.petPosBroadcastPeriod = self.config.GetFloat('pet-pos-broadcast-period', PetConstants.PosBroadcastPeriod)
self.wantBingo = self.config.GetBool('want-fish-bingo', 1)
self.wantKarts = self.config.GetBool('wantKarts', 1)
self.newDBRequestGen = self.config.GetBool('new-database-request-generate', 1)
self.waitShardDelete = self.config.GetBool('wait-shard-delete', 1)
self.blinkTrolley = self.config.GetBool('blink-trolley', 0)
self.fakeDistrictPopulations = self.config.GetBool('fake-district-populations', 0)
self.wantSwitchboard = self.config.GetBool('want-switchboard', 0)
self.wantSwitchboardHacks = self.config.GetBool('want-switchboard-hacks', 0)
self.GEMdemoWhisperRecipientDoid = self.config.GetBool('gem-demo-whisper-recipient-doid', 0)
self.sqlAvailable = self.config.GetBool('sql-available', 1)
self.createStats()
self.restart()
return
def setupCpuAffinities(self, minChannel):
if game.name == 'uberDog':
affinityMask = self.config.GetInt('uberdog-cpu-affinity-mask', -1)
else:
affinityMask = self.config.GetInt('ai-cpu-affinity-mask', -1)
if affinityMask != -1:
TrueClock.getGlobalPtr().setCpuAffinity(affinityMask)
else:
autoAffinity = self.config.GetBool('auto-single-cpu-affinity', 0)
if game.name == 'uberDog':
affinity = self.config.GetInt('uberdog-cpu-affinity', -1)
if autoAffinity and affinity == -1:
affinity = 2
else:
affinity = self.config.GetInt('ai-cpu-affinity', -1)
if autoAffinity and affinity == -1:
affinity = 1
if affinity != -1:
TrueClock.getGlobalPtr().setCpuAffinity(1 << affinity)
elif autoAffinity:
if game.name == 'uberDog':
channelSet = int(minChannel / 1000000)
channelSet -= 240
affinity = channelSet + 3
TrueClock.getGlobalPtr().setCpuAffinity(1 << affinity % 4)
def taskManagerDoYield(self, frameStartTime, nextScheuledTaksTime):
minFinTime = frameStartTime + self.MaxEpockSpeed
if nextScheuledTaksTime > 0 and nextScheuledTaksTime < minFinTime:
minFinTime = nextScheuledTaksTime
delta = minFinTime - globalClock.getRealTime()
while delta > 0.002:
time.sleep(delta)
delta = minFinTime - globalClock.getRealTime()
def createStats(self, hostname = None, port = None):
if not self.wantStats:
return False
if PStatClient.isConnected():
PStatClient.disconnect()
if hostname is None:
hostname = ''
if port is None:
port = -1
PStatClient.connect(hostname, port)
return PStatClient.isConnected()
def __sleepCycleTask(self, task):
time.sleep(self.AISleep)
return Task.cont
def __resetPrevTransform(self, state):
PandaNode.resetAllPrevTransform()
return Task.cont
def __ivalLoop(self, state):
ivalMgr.step()
return Task.cont
def __igLoop(self, state):
self.graphicsEngine.renderFrame()
return Task.cont
def shutdown(self):
self.taskMgr.remove('ivalLoop')
self.taskMgr.remove('igLoop')
self.taskMgr.remove('aiSleep')
self.eventMgr.shutdown()
def restart(self):
self.shutdown()
self.taskMgr.add(self.__resetPrevTransform, 'resetPrevTransform', priority=-51)
self.taskMgr.add(self.__ivalLoop, 'ivalLoop', priority=20)
self.taskMgr.add(self.__igLoop, 'igLoop', priority=50)
if self.AISleep >= 0 and (not self.AIRunningNetYield or self.AIForceSleep):
self.taskMgr.add(self.__sleepCycleTask, 'aiSleep', priority=55)
self.eventMgr.restart()
def getRepository(self):
return self.air
def run(self):
self.taskMgr.run()

26
otp/ai/AIBaseGlobal.py Normal file
View file

@ -0,0 +1,26 @@
from AIBase import *
__builtins__['simbase'] = AIBase()
__builtins__['ostream'] = Notify.out()
__builtins__['run'] = simbase.run
__builtins__['taskMgr'] = simbase.taskMgr
__builtins__['jobMgr'] = simbase.jobMgr
__builtins__['eventMgr'] = simbase.eventMgr
__builtins__['messenger'] = simbase.messenger
__builtins__['bboard'] = simbase.bboard
__builtins__['config'] = simbase.config
__builtins__['directNotify'] = directNotify
from direct.showbase import Loader
simbase.loader = Loader.Loader(simbase)
__builtins__['loader'] = simbase.loader
directNotify.setDconfigLevels()
def inspect(anObject):
from direct.tkpanels import Inspector
Inspector.inspect(anObject)
__builtins__['inspect'] = inspect
if not __debug__ and __dev__:
notify = directNotify.newCategory('ShowBaseGlobal')
notify.error("You must set 'want-dev' to false in non-debug mode.")
taskMgr.finalInit()

View file

@ -0,0 +1,8 @@
PIRATES_CARDGAME = 1
PIRATES_CREW = 2
PIRATES_GUILD = 3
PIRATES_FRIENDS = 4
PIRATES_BAND = 5
PIRATES_PVP_RESPAWN = 6
PIRATES_TREASUREMAP = 7
PIRATES_SHIPPVP = 8

83
otp/ai/AIMsgTypes.py Normal file
View file

@ -0,0 +1,83 @@
from otp.distributed.OtpDoGlobals import *
from direct.showbase.PythonUtil import invertDictLossless
OTP_SERVER_ROOT_DO_ID = 4007
CHANNEL_CLIENT_BROADCAST = 4014
BAD_CHANNEL_ID = 0
BAD_ZONE_ID = 0
BAD_DO_ID = 0
CONTROL_MESSAGE = 4001
CONTROL_SET_CHANNEL = 2001
CONTROL_REMOVE_CHANNEL = 2002
CONTROL_SET_CON_NAME = 2004
CONTROL_SET_CON_URL = 2005
CONTROL_ADD_RANGE = 2008
CONTROL_REMOVE_RANGE = 2009
CONTROL_ADD_POST_REMOVE = 2010
CONTROL_CLEAR_POST_REMOVE = 2011
AIMsgName2Id = {'STATESERVER_OBJECT_GENERATE_WITH_REQUIRED': 2001,
'STATESERVER_OBJECT_GENERATE_WITH_REQUIRED_OTHER': 2003,
'STATESERVER_OBJECT_UPDATE_FIELD': 2004,
'STATESERVER_OBJECT_UPDATE_FIELD_MULTIPLE': 2005,
'STATESERVER_OBJECT_DELETE_RAM': 2007,
'STATESERVER_OBJECT_SET_ZONE': 2008,
'STATESERVER_OBJECT_CHANGE_ZONE': 2009,
'STATESERVER_OBJECT_NOTFOUND': 2015,
'STATESERVER_QUERY_OBJECT_ALL': 2020,
'STATESERVER_QUERY_ZONE_OBJECT_ALL': 2021,
'STATESERVER_OBJECT_LOCATE': 2022,
'STATESERVER_OBJECT_LOCATE_RESP': 2023,
'STATESERVER_OBJECT_QUERY_FIELD': 2024,
'STATESERVER_QUERY_OBJECT_ALL_RESP': 2030,
'STATESERVER_SHARD_REST': 2061,
'STATESERVER_ADD_AI_RECV': 2045,
'STATESERVER_QUERY_ZONE_OBJECT_ALL_DONE': 2046,
'STATESERVER_OBJECT_CREATE_WITH_REQUIRED_CONTEXT': 2050,
'STATESERVER_OBJECT_CREATE_WITH_REQUIR_OTHER_CONTEXT': 2051,
'STATESERVER_OBJECT_CREATE_WITH_REQUIRED_CONTEXT_RESP': 2052,
'STATESERVER_OBJECT_CREATE_WITH_REQUIR_OTHER_CONTEXT_RESP': 2053,
'STATESERVER_OBJECT_DELETE_DISK': 2060,
'STATESERVER_OBJECT_QUERY_FIELD_RESP': 2062,
'STATESERVER_OBJECT_ENTERZONE_WITH_REQUIRED_OTHER': 2066,
'STATESERVER_OBJECT_ENTER_AI_RECV': 2067,
'STATESERVER_OBJECT_LEAVING_AI_INTEREST': 2033,
'STATESERVER_OBJECT_ENTER_OWNER_RECV': 2068,
'STATESERVER_OBJECT_CHANGE_OWNER_RECV': 2069,
'STATESERVER_OBJECT_SET_OWNER_RECV': 2070,
'STATESERVER_OBJECT_QUERY_FIELDS': 2080,
'STATESERVER_OBJECT_QUERY_FIELDS_RESP': 2081,
'STATESERVER_OBJECT_QUERY_FIELDS_STRING': 2082,
'STATESERVER_OBJECT_QUERY_MANAGING_AI': 2083,
'STATESERVER_BOUNCE_MESSAGE': 2086,
'STATESERVER_QUERY_OBJECT_CHILDREN_LOCAL': 2087,
'STATESERVER_QUERY_OBJECT_CHILDREN_LOCAL_DONE': 2089,
'STATESERVER_QUERY_OBJECT_CHILDREN_RESP': 2087,
'ACCOUNT_AVATAR_USAGE': 3005,
'ACCOUNT_ACCOUNT_USAGE': 3006,
'CLIENT_AGENT_OPEN_CHANNEL': 3104,
'CLIENT_AGENT_CLOSE_CHANNEL': 3105,
'CLIENT_AGENT_SET_INTEREST': 3106,
'CLIENT_AGENT_REMOVE_INTEREST': 3107,
'CHANNEL_PUPPET_ACTION': 4004,
'DBSERVER_MAKE_FRIENDS': 1017,
'DBSERVER_MAKE_FRIENDS_RESP': 1031,
'DBSERVER_REQUEST_SECRET': 1025,
'DBSERVER_REQUEST_SECRET_RESP': 1026,
'DBSERVER_SUBMIT_SECRET': 1027,
'DBSERVER_SUBMIT_SECRET_RESP': 1028,
'DBSERVER_CREATE_STORED_OBJECT': 1003,
'DBSERVER_CREATE_STORED_OBJECT_RESP': 1004,
'DBSERVER_DELETE_STORED_OBJECT': 1008,
'DBSERVER_GET_STORED_VALUES': 1012,
'DBSERVER_GET_STORED_VALUES_RESP': 1013,
'DBSERVER_SET_STORED_VALUES': 1014,
'SERVER_PING': 5002}
AIMsgId2Names = invertDictLossless(AIMsgName2Id)
if not isClient():
print 'EXECWARNING AIMsgTypes: %s' % AIMsgName2Id
printStack()
for name, value in AIMsgName2Id.items():
exec '%s = %s' % (name, value)
del name
del value
DBSERVER_ID = 4003

217
otp/ai/AIZoneData.py Normal file
View file

@ -0,0 +1,217 @@
from pandac.PandaModules import *
from direct.distributed import ParentMgr
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.task import Task
from direct.showbase import LeakDetectors
from otp.otpbase import OTPGlobals
import random
class AIZoneData:
notify = directNotify.newCategory('AIZoneData')
def __init__(self, air, parentId, zoneId):
self._air = air
self._parentId = parentId
self._zoneId = zoneId
self._data = self._air.getZoneDataStore().getDataForZone(self._parentId, self._zoneId)
def destroy(self):
del self._data
self._air.getZoneDataStore().releaseDataForZone(self._parentId, self._zoneId)
del self._zoneId
del self._parentId
del self._air
def __getattr__(self, attr):
return getattr(self._data, attr)
class AIZoneDataObj:
notify = directNotify.newCategory('AIZoneDataObj')
DefaultCTravName = 'default'
def __init__(self, parentId, zoneId):
self._parentId = parentId
self._zoneId = zoneId
self._refCount = 0
self._collTravs = {}
self._collTravsStarted = set()
def __str__(self):
output = str(self._collTravs)
output += '\n'
totalColliders = 0
totalTraversers = 0
for currCollTrav in self._collTravs.values():
totalTraversers += 1
totalColliders += currCollTrav.getNumColliders()
output += 'Num traversers: %s Num total colliders: %s' % (totalTraversers, totalColliders)
return output
def _incRefCount(self):
self._refCount += 1
def _decRefCount(self):
self._refCount -= 1
def _getRefCount(self):
return self._refCount
def destroy(self):
for name in list(self._collTravsStarted):
self.stopCollTrav(cTravName=name)
del self._collTravsStarted
del self._collTravs
if hasattr(self, '_nonCollidableParent'):
self._nonCollidableParent.removeNode()
del self._nonCollidableParent
if hasattr(self, '_render'):
if hasattr(self, '_renderLeakDetector'):
self._renderLeakDetector.destroy()
del self._renderLeakDetector
self._render.removeNode()
del self._render
if hasattr(self, '_parentMgr'):
self._parentMgr.destroy()
del self._parentMgr
del self._zoneId
del self._parentId
def getLocation(self):
return (self._parentId, self._zoneId)
def getRender(self):
if not hasattr(self, '_render'):
self._render = NodePath('render-%s-%s' % (self._parentId, self._zoneId))
if config.GetBool('leak-scene-graph', 0):
self._renderLeakDetector = LeakDetectors.SceneGraphLeakDetector(self._render)
return self._render
def getNonCollidableParent(self):
if not hasattr(self, '_nonCollidableParent'):
render = self.getRender()
self._nonCollidableParent = render.attachNewNode('nonCollidables')
if __dev__:
pass
return self._nonCollidableParent
def getParentMgr(self):
if not hasattr(self, '_parentMgr'):
self._parentMgr = ParentMgr.ParentMgr()
self._parentMgr.registerParent(OTPGlobals.SPHidden, hidden)
self._parentMgr.registerParent(OTPGlobals.SPRender, self.getRender())
return self._parentMgr
def hasCollTrav(self, name = None):
if name is None:
name = AIZoneDataObj.DefaultCTravName
return name in self._collTravs
def getCollTrav(self, name = None):
if name is None:
name = AIZoneDataObj.DefaultCTravName
if name not in self._collTravs:
self._collTravs[name] = CollisionTraverser('cTrav-%s-%s-%s' % (name, self._parentId, self._zoneId))
return self._collTravs[name]
def removeCollTrav(self, name):
if self._collTravs.has_key(name):
del self._collTravs[name]
def _getCTravTaskName(self, name = None):
if name is None:
name = AIZoneDataObj.DefaultCTravName
return 'collTrav-%s-%s-%s' % (name, self._parentId, self._zoneId)
def _doCollisions(self, task = None, topNode = None, cTravName = None):
render = self.getRender()
curTime = globalClock.getFrameTime()
render.setTag('lastTraverseTime', str(curTime))
if topNode is not None:
if not render.isAncestorOf(topNode):
self.notify.warning('invalid topNode for collision traversal in %s: %s' % (self.getLocation(), topNode))
else:
topNode = render
if cTravName is None:
cTravName = AIZoneDataObj.DefaultCTravName
collTrav = self._collTravs[cTravName]
messenger.send('preColl-' + collTrav.getName())
collTrav.traverse(topNode)
messenger.send('postColl-' + collTrav.getName())
return Task.cont
def doCollTrav(self, topNode = None, cTravName = None):
self.getCollTrav(cTravName)
self._doCollisions(topNode=topNode, cTravName=cTravName)
def startCollTrav(self, respectPrevTransform = 1, cTravName = None):
if cTravName is None:
cTravName = AIZoneDataObj.DefaultCTravName
if cTravName not in self._collTravsStarted:
self.getCollTrav(name=cTravName)
taskMgr.add(self._doCollisions, self._getCTravTaskName(name=cTravName), priority=OTPGlobals.AICollisionPriority, extraArgs=[self._zoneId])
self._collTravsStarted.add(cTravName)
self.setRespectPrevTransform(respectPrevTransform, cTravName=cTravName)
return
def stopCollTrav(self, cTravName = None):
if cTravName is None:
cTravName = AIZoneDataObj.DefaultCTravName
self.notify.debug('stopCollTrav(%s, %s, %s)' % (cTravName, self._parentId, self._zoneId))
if cTravName in self._collTravsStarted:
self.notify.info('removing %s collision traversal for (%s, %s)' % (cTravName, self._parentId, self._zoneId))
taskMgr.remove(self._getCTravTaskName(name=cTravName))
self._collTravsStarted.remove(cTravName)
return
def setRespectPrevTransform(self, flag, cTravName = None):
if cTravName is None:
cTravName = AIZoneDataObj.DefaultCTravName
self._collTravs[cTravName].setRespectPrevTransform(flag)
return
def getRespectPrevTransform(self, cTravName = None):
if cTravName is None:
cTravName = AIZoneDataObj.DefaultCTravName
return self._collTravs[cTravName].getRespectPrevTransform()
class AIZoneDataStore:
notify = directNotify.newCategory('AIZoneDataStore')
def __init__(self):
self._zone2data = {}
def destroy(self):
for zone, data in self._zone2data.items():
data.destroy()
del self._zone2data
def hasDataForZone(self, parentId, zoneId):
key = (parentId, zoneId)
return key in self._zone2data
def getDataForZone(self, parentId, zoneId):
key = (parentId, zoneId)
if key not in self._zone2data:
self._zone2data[key] = AIZoneDataObj(parentId, zoneId)
self.printStats()
data = self._zone2data[key]
data._incRefCount()
return data
def releaseDataForZone(self, parentId, zoneId):
key = (parentId, zoneId)
data = self._zone2data[key]
data._decRefCount()
refCount = data._getRefCount()
if refCount == 0:
del self._zone2data[key]
data.destroy()
self.printStats()
def printStats(self):
self.notify.debug('%s zones have zone data allocated' % len(self._zone2data))

74
otp/ai/BanManagerAI.py Normal file
View file

@ -0,0 +1,74 @@
import urllib
import os
from pandac.PandaModules import HTTPClient, Ramfile
from direct.directnotify import DirectNotifyGlobal
class BanManagerAI:
notify = DirectNotifyGlobal.directNotify.newCategory('BanManagerAI')
BanUrl = simbase.config.GetString('ban-base-url', 'http://vapps.disl.starwave.com:8005/dis-hold/action/event')
App = simbase.config.GetString('ban-app-name', 'TTWorldAI')
Product = simbase.config.GetString('ban-product', 'Toontown')
EventName = simbase.config.GetString('ban-event-name', 'tthackattempt')
def __init__(self):
self.curBanRequestNum = 0
self.channels = {}
self.ramFiles = {}
def ban(self, avatarId, dislid, comment):
parameters = ''
parameters += 'app=%s' % self.App
parameters += '&product=%s' % self.Product
parameters += '&user_id=%s' % dislid
parameters += '&event_name=%s' % self.EventName
commentWithAvatarId = 'avId-%s ' % avatarId
commentWithAvatarId += comment
parameters += '&comments=%s' % urllib.quote(str(commentWithAvatarId))
baseUrlToUse = self.BanUrl
osBaseUrl = os.getenv('BAN_URL')
if osBaseUrl:
baseUrlToUse = osBaseUrl
fullUrl = baseUrlToUse + '?' + parameters
self.notify.info('ban request %s dislid=%s comment=%s fullUrl=%s' % (self.curBanRequestNum,
dislid,
comment,
fullUrl))
simbase.air.writeServerEvent('ban_request', avatarId, '%s|%s|%s' % (dislid, comment, fullUrl))
if simbase.config.GetBool('do-actual-ban', True):
newTaskName = 'ban-task-%d' % self.curBanRequestNum
newTask = taskMgr.add(self.doBanUrlTask, newTaskName)
newTask.banRequestNum = self.curBanRequestNum
http = HTTPClient.getGlobalPtr()
channel = http.makeChannel(False)
self.channels[self.curBanRequestNum] = channel
rf = Ramfile()
self.ramFiles[self.curBanRequestNum] = rf
channel.beginGetDocument(fullUrl)
channel.downloadToRam(rf)
self.curBanRequestNum += 1
def cleanupBanReq(self, banReq):
channel = self.channels.get(banReq)
if channel:
del self.channels[banReq]
ramfile = self.ramFiles.get(banReq)
if ramfile:
del self.ramFiles[banReq]
def doBanUrlTask(self, task):
banReq = task.banRequestNum
channel = self.channels.get(banReq)
if channel:
if channel.run():
return task.cont
else:
self.notify.warning('no channel for ban req %s' % banReq)
self.cleanupBanReq(banReq)
return task.done
result = ''
ramfile = self.ramFiles.get(banReq)
if ramfile:
result = ramfile.getData()
self.notify.info('done processing ban request %s, ramFile=%s' % (banReq, result))
self.cleanupBanReq(banReq)
return task.done

83
otp/ai/Barrier.py Normal file
View file

@ -0,0 +1,83 @@
from otp.ai.AIBase import *
from direct.task import Task
from direct.showbase import DirectObject
import random
class Barrier(DirectObject.DirectObject):
notify = directNotify.newCategory('Barrier')
def __init__(self, name, uniqueName, avIdList, timeout, clearedFunc = None, timeoutFunc = None, doneFunc = None):
self.name = name
self.uniqueName = uniqueName + '-Barrier'
self.avIdList = avIdList[:]
self.pendingAvatars = self.avIdList[:]
self.timeout = timeout
self.clearedFunc = clearedFunc
self.timeoutFunc = timeoutFunc
self.doneFunc = doneFunc
if len(self.pendingAvatars) == 0:
self.notify.debug('%s: barrier with empty list' % self.uniqueName)
self.active = 0
if self.clearedFunc:
self.clearedFunc()
if self.doneFunc:
self.doneFunc(self.avIdList)
return
self.taskName = self.uniqueName + '-Timeout'
origTaskName = self.taskName
while taskMgr.hasTaskNamed(self.taskName):
self.taskName = origTaskName + '-' + str(random.randint(0, 10000))
taskMgr.doMethodLater(self.timeout, self.__timerExpired, self.taskName)
for avId in self.avIdList:
event = simbase.air.getAvatarExitEvent(avId)
self.acceptOnce(event, self.__handleUnexpectedExit, extraArgs=[avId])
self.notify.debug('%s: expecting responses from %s within %s seconds' % (self.uniqueName, self.avIdList, self.timeout))
self.active = 1
def cleanup(self):
if self.active:
taskMgr.remove(self.taskName)
self.active = 0
self.ignoreAll()
def clear(self, avId):
if avId not in self.pendingAvatars:
self.notify.warning('%s: tried to clear %s, who was not listed.' % (self.uniqueName, avId))
return
self.notify.debug('%s: clearing avatar %s' % (self.uniqueName, avId))
self.pendingAvatars.remove(avId)
if len(self.pendingAvatars) == 0:
self.notify.debug('%s: barrier cleared by %s' % (self.uniqueName, self.avIdList))
self.cleanup()
if self.clearedFunc:
self.clearedFunc()
if self.doneFunc:
self.doneFunc(self.avIdList)
def isActive(self):
return self.active
def getPendingAvatars(self):
return self.pendingAvatars[:]
def __timerExpired(self, task):
self.notify.warning('%s: timeout expired; responses not received from %s' % (self.uniqueName, self.pendingAvatars))
self.cleanup()
if self.timeoutFunc:
self.timeoutFunc(self.pendingAvatars[:])
if self.doneFunc:
clearedAvIds = self.avIdList[:]
for avId in self.pendingAvatars:
clearedAvIds.remove(avId)
self.doneFunc(clearedAvIds)
return Task.done
def __handleUnexpectedExit(self, avId):
if avId not in self.avIdList:
return
self.avIdList.remove(avId)
if avId in self.pendingAvatars:
self.clear(avId)

View file

@ -0,0 +1,44 @@
from direct.showbase.DirectObject import DirectObject
from direct.showbase import GarbageReport
class GarbageLeakServerEventAggregator(DirectObject):
def __init__(self, cr):
self.cr = cr
self._doLaterName = None
self._sentLeakDesc2num = {}
self._curLeakDesc2num = {}
self.accept(GarbageReport.GarbageCycleCountAnnounceEvent, self._handleCycleCounts)
return
def destroy(self):
self._stopSending()
self.ignoreAll()
del self.cr
def _handleCycleCounts(self, desc2num):
self._curLeakDesc2num = desc2num
self._startSending()
def _startSending(self):
if not self._doLaterName:
self._sendLeaks()
self._doLaterName = uniqueName('%s-sendGarbageLeakInfo' % self.__class__.__name__)
self.doMethodLater(60 * 60.0, self._sendLeaks, self._doLaterName)
def _stopSending(self):
if self._doLaterName:
self.removeTask(self._doLaterName)
self._doLaterName = None
return
def _sendLeaks(self, task = None):
for desc, curNum in self._curLeakDesc2num.iteritems():
self._sentLeakDesc2num.setdefault(desc, 0)
num = curNum - self._sentLeakDesc2num[desc]
if num > 0:
base.cr.timeManager.d_setClientGarbageLeak(num, desc)
self._sentLeakDesc2num[desc] = curNum
if task:
return task.again

875
otp/ai/MagicWordManager.py Normal file
View file

@ -0,0 +1,875 @@
from pandac.PandaModules import *
from direct.showbase import GarbageReport, ContainerReport, MessengerLeakDetector
from direct.distributed import DistributedObject
from direct.directnotify import DirectNotifyGlobal
from direct.showbase.InputStateGlobal import inputState
from direct.showbase.ObjectCount import ObjectCount
from direct.task import Task
from direct.task.TaskProfiler import TaskProfiler
from otp.avatar import Avatar
import string
from direct.showbase import PythonUtil
from direct.showbase.PythonUtil import Functor, DelayedCall, ScratchPad
from otp.otpbase import OTPGlobals
from direct.distributed.ClockDelta import *
from direct.showutil.TexViewer import TexViewer
class MagicWordManager(DistributedObject.DistributedObject):
notify = DirectNotifyGlobal.directNotify.newCategory('MagicWordManager')
neverDisable = 1
GameAvatarClass = None
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
self.shownFontNode = None
self.csShown = 0
self.guiPopupShown = 0
self.texViewer = None
return
def generate(self):
DistributedObject.DistributedObject.generate(self)
self.accept('magicWord', self.b_setMagicWord)
self.autoMagicWordEvent = localAvatar.getArrivedOnDistrictEvent()
if localAvatar.isGeneratedOnDistrict():
self.doLoginMagicWords()
else:
self.accept(self.autoMagicWordEvent, self.doLoginMagicWords)
def doLoginMagicWords(self):
pass
def disable(self):
self.ignore(self.autoMagicWordEvent)
del self.autoMagicWordEvent
self.ignore('magicWord')
self.hidefont()
DistributedObject.DistributedObject.disable(self)
def setMagicWord(self, word, avId, zoneId):
try:
self.doMagicWord(word, avId, zoneId)
except:
response = PythonUtil.describeException(backTrace=1)
self.notify.warning('Ignoring error in magic word:\n%s' % response)
self.setMagicWordResponse(response)
def wordIs(self, word, w):
return word == w or word[:len(w) + 1] == '%s ' % w
def getWordIs(self, word):
return Functor(self.wordIs, word)
def doMagicWord(self, word, avId, zoneId):
wordIs = self.getWordIs(word)
print word
if wordIs('~oobe'):
base.oobe()
elif wordIs('~oobeCull'):
base.oobeCull()
elif wordIs('~tex'):
self.doTex(word)
elif wordIs('~texmem'):
base.toggleTexMem()
elif wordIs('~verts'):
base.toggleShowVertices()
elif wordIs('~wire'):
base.toggleWireframe()
elif wordIs('~stereo'):
base.toggleStereo()
elif wordIs('~showfont'):
self.showfont(word[9:])
elif wordIs('~hidefont'):
self.hidefont()
elif wordIs('~guiPopup'):
self.toggleGuiPopup()
elif wordIs('~showCS') or wordIs('~showcs'):
bitmask = self.getCSBitmask(word[7:])
render.showCS(bitmask)
self.csShown = 1
elif wordIs('~hideCS') or wordIs('~hidecs'):
bitmask = self.getCSBitmask(word[7:])
render.hideCS(bitmask)
self.csShown = 0
elif wordIs('~cs'):
bitmask = self.getCSBitmask(word[3:])
if self.csShown:
render.hideCS(bitmask)
self.csShown = 0
else:
render.showCS(bitmask)
self.csShown = 1
elif wordIs('~showShadowCollisions'):
self.showShadowCollisions()
elif wordIs('~hideShadowCollisions'):
self.hideShadowCollisions()
elif wordIs('~showCollisions'):
self.showCollisions()
elif wordIs('~hideCollisions'):
self.hideCollisions()
elif wordIs('~showCameraCollisions'):
self.showCameraCollisions()
elif wordIs('~hideCameraCollisions'):
self.hideCameraCollisions()
elif wordIs('~collidespam'):
n = Notify.ptr().getCategory(':collide')
if hasattr(self, '_collideSpamSeverity'):
n.setSeverity(self._collideSpamSeverity)
del self._collideSpamSeverity
else:
self._collideSpamSeverity = n.getSeverity()
n.setSeverity(NSSpam)
elif wordIs('~notify'):
args = word.split()
n = Notify.ptr().getCategory(args[1])
n.setSeverity({'error': NSError,
'warning': NSWarning,
'info': NSInfo,
'debug': NSDebug,
'spam': NSSpam}[args[2]])
elif wordIs('~stress'):
factor = word[7:]
if factor:
factor = float(factor)
LOD.setStressFactor(factor)
response = 'Set LOD stress factor to %s' % factor
else:
factor = LOD.getStressFactor()
response = 'LOD stress factor is %s' % factor
self.setMagicWordResponse(response)
elif wordIs('~for'):
self.forAnother(word, avId, zoneId)
elif wordIs('~badname'):
word = '~for %s ~badname' % word[9:]
print 'word is %s' % word
self.forAnother(word, avId, zoneId)
elif wordIs('~avId'):
self.setMagicWordResponse(str(localAvatar.doId))
elif wordIs('~doId'):
name = string.strip(word[6:])
objs = self.identifyDistributedObjects(name)
if len(objs) == 0:
response = '%s is unknown.' % name
else:
response = ''
for name, obj in objs:
response += '\n%s %d' % (name, obj.doId)
response = response[1:]
self.setMagicWordResponse(response)
elif wordIs('~exec'):
from otp.chat import ChatManager
ChatManager.ChatManager.execChat = 1
elif wordIs('~run'):
self.toggleRun()
elif wordIs('~runFaster'):
if config.GetBool('want-running', 1):
args = word.split()
if len(args) > 1:
base.debugRunningMultiplier = float(args[1])
else:
base.debugRunningMultiplier = 10
inputState.set('debugRunning', True)
elif wordIs('~who'):
avIds = []
for av in Avatar.Avatar.ActiveAvatars:
if hasattr(av, 'getFriendsList'):
avIds.append(av.doId)
self.d_setWho(avIds)
elif wordIs('~sync'):
tm = self.cr.timeManager
if tm == None:
response = 'No TimeManager.'
self.setMagicWordResponse(response)
else:
tm.extraSkew = 0.0
skew = string.strip(word[5:])
if skew != '':
tm.extraSkew = float(skew)
globalClockDelta.clear()
tm.handleHotkey()
elif wordIs('~period'):
timeout = string.strip(word[7:])
if timeout != '':
seconds = int(timeout)
self.cr.stopPeriodTimer()
self.cr.resetPeriodTimer(seconds)
self.cr.startPeriodTimer()
if self.cr.periodTimerExpired:
response = 'Period timer has expired.'
elif self.cr.periodTimerStarted:
elapsed = globalClock.getFrameTime() - self.cr.periodTimerStarted
secondsRemaining = self.cr.periodTimerSecondsRemaining - elapsed
response = 'Period timer expires in %s seconds.' % int(secondsRemaining)
else:
response = 'Period timer not set.'
self.setMagicWordResponse(response)
elif wordIs('~DIRECT'):
args = word.split()
fEnableLight = 0
if len(args) > 1:
if direct and args[1] == 'CAM':
direct.enable()
taskMgr.removeTasksMatching('updateSmartCamera*')
camera.wrtReparentTo(render)
direct.cameraControl.enableMouseFly()
self.setMagicWordResponse('Enabled DIRECT camera')
return
elif args[1] == 'LIGHT':
fEnableLight = 1
base.startTk()
from direct.directtools import DirectSession
if fEnableLight:
direct.enableLight()
else:
direct.enable()
self.setMagicWordResponse('Enabled DIRECT')
elif wordIs('~TT'):
if not direct:
return
args = word.split()
if len(args) > 1:
if args[1] == 'CAM':
direct.cameraControl.disableMouseFly()
camera.wrtReparentTo(base.localAvatar)
base.localAvatar.startUpdateSmartCamera()
self.setMagicWordResponse('Disabled DIRECT camera')
return
direct.disable()
camera.wrtReparentTo(base.localAvatar)
base.localAvatar.startUpdateSmartCamera()
self.setMagicWordResponse('Disabled DIRECT')
elif wordIs('~net'):
if self.cr.networkPlugPulled():
self.cr.restoreNetworkPlug()
self.cr.startHeartbeat()
response = 'Network restored.'
else:
self.cr.pullNetworkPlug()
self.cr.stopHeartbeat()
response = 'Network disconnected.'
self.setMagicWordResponse(response)
elif wordIs('~disconnect'):
base.cr.distributedDistrict.sendUpdate('broadcastMessage')
elif wordIs('~model'):
args = word.split()
path = args[1]
model = loader.loadModel(path)
model.reparentTo(localAvatar)
model.wrtReparentTo(render)
self.setMagicWordResponse('loaded %s' % path)
elif wordIs('~axis'):
axis = loader.loadModel('models/misc/xyzAxis.bam')
axis.reparentTo(render)
axis.setPos(base.localAvatar, 0, 0, 0)
axis.setHpr(render, 0, 0, 0)
axis10 = loader.loadModel('models/misc/xyzAxis.bam')
axis10.reparentTo(render)
axis10.setPos(base.localAvatar, 0, 0, 0)
axis10.setScale(10)
axis10.setHpr(render, 0, 0, 0)
axis10.setColorScale(1, 1, 1, 0.4)
axis10.setTransparency(1)
elif wordIs('~clearAxes') or wordIs('~clearAxis'):
render.findAllMatches('**/xyzAxis.egg').detach()
elif wordIs('~myAxis'):
if hasattr(self, 'myAxis'):
self.myAxis.detachNode()
del self.myAxis
else:
self.myAxis = loader.loadModel('models/misc/xyzAxis.bam')
self.myAxis.reparentTo(localAvatar)
elif wordIs('~osd'):
onScreenDebug.enabled = not onScreenDebug.enabled
elif wordIs('~osdScale'):
args = word.split()
defScale = 0.05
if len(args) > 1:
scale = float(args[1])
else:
scale = 1.0
onScreenDebug.onScreenText.setScale(defScale * scale)
elif wordIs('~osdTaskMgr'):
if taskMgr.osdEnabled():
taskMgr.stopOsd()
else:
if not onScreenDebug.enabled:
onScreenDebug.enabled = True
taskMgr.startOsd()
elif wordIs('~fps'):
self.doFps(word, avId, zoneId)
elif wordIs('~sleep'):
args = word.split()
if len(args) > 1:
s = float(args[1])
base.setSleep(s)
response = 'sleeping %s' % s
else:
base.setSleep(0.0)
response = 'not sleeping'
self.setMagicWordResponse(response)
elif wordIs('~objects'):
args = word.split()
from direct.showbase import ObjectReport
report = ObjectReport.ObjectReport('client ~objects')
if 'all' in args:
self.notify.info('printing full object set...')
report.getObjectPool().printObjsByType(printReferrers='ref' in args)
if hasattr(self, 'baselineObjReport'):
self.notify.info('calculating diff from baseline ObjectReport...')
self.lastDiff = self.baselineObjReport.diff(report)
self.lastDiff.printOut(full='diff' in args or 'dif' in args)
if 'baseline' in args or not hasattr(self, 'baselineObjReport'):
self.notify.info('recording baseline ObjectReport...')
if hasattr(self, 'baselineObjReport'):
self.baselineObjReport.destroy()
self.baselineObjReport = report
self.setMagicWordResponse('objects logged')
elif wordIs('~objectcount'):
def handleObjectCountDone(objectCount):
self.setMagicWordResponse('object count logged')
oc = ObjectCount('~objectcount', doneCallback=handleObjectCountDone)
elif wordIs('~objecthg'):
import gc
objs = gc.get_objects()
type2count = {}
for obj in objs:
tn = safeTypeName(obj)
type2count.setdefault(tn, 0)
type2count[tn] += 1
count2type = invertDictLossless(type2count)
counts = count2type.keys()
counts.sort()
counts.reverse()
for count in counts:
print '%s: %s' % (count, count2type[count])
self.setMagicWordResponse('~aiobjecthg complete')
elif wordIs('~containers'):
args = word.split()
limit = 30
if 'full' in args:
limit = None
ContainerReport.ContainerReport('~containers', log=True, limit=limit, threaded=True)
elif wordIs('~garbage'):
args = word.split()
full = 'full' in args
safeMode = 'safe' in args
delOnly = 'delonly' in args
GarbageReport.GarbageLogger('~garbage', fullReport=full, threaded=True, safeMode=safeMode, delOnly=delOnly, doneCallback=self.garbageReportDone)
elif wordIs('~guicreates'):
base.printGuiCreates = True
self.setMagicWordResponse('printing gui creation stacks')
elif wordIs('~creategarbage'):
GarbageReport._createGarbage()
elif wordIs('~leakTask'):
def leakTask(task):
return task.cont
taskMgr.add(leakTask, uniqueName('leakedTask'))
leakTask = None
elif wordIs('~leakmessage'):
MessengerLeakDetector._leakMessengerObject()
self.down_setMagicWordResponse(senderId, 'messenger leak object created')
elif wordIs('~pstats'):
args = word.split()
hostname = None
port = None
if len(args) > 1:
hostname = args[1]
if len(args) > 2:
port = int(args[2])
base.wantStats = 1
Task.TaskManager.pStatsTasks = 1
result = base.createStats(hostname, port)
connectionName = '%s' % hostname
if port is not None:
connectionName += ':%s' % port
if result:
response = 'connected client pstats to %s' % connectionName
else:
response = 'could not connect pstats to %s' % connectionName
self.setMagicWordResponse(response)
elif wordIs('~profile'):
args = word.split()
if len(args) > 1:
num = int(args[1])
else:
num = 5
session = taskMgr.getProfileSession('~profile')
session.setLogAfterProfile(True)
taskMgr.profileFrames(num, session)
self.setMagicWordResponse('profiling %s client frames...' % num)
elif wordIs('~frameprofile'):
args = word.split()
wasOn = bool(taskMgr.getProfileFrames())
if len(args) > 1:
setting = bool(int(args[1]))
else:
setting = not wasOn
taskMgr.setProfileFrames(setting)
self.setMagicWordResponse('frame profiling %s%s' % (choice(setting, 'ON', 'OFF'), choice(wasOn == setting, ' already', '')))
elif wordIs('~taskprofile'):
args = word.split()
wasOn = bool(taskMgr.getProfileTasks())
if len(args) > 1:
setting = bool(int(args[1]))
else:
setting = not wasOn
taskMgr.setProfileTasks(setting)
self.setMagicWordResponse('task profiling %s%s' % (choice(setting, 'ON', 'OFF'), choice(wasOn == setting, ' already', '')))
elif wordIs('~taskspikethreshold'):
args = word.split()
if len(args) > 1:
threshold = float(args[1])
response = 'task spike threshold set to %ss' % threshold
else:
threshold = TaskProfiler.GetDefaultSpikeThreshold()
response = 'task spike threshold reset to %ss' % threshold
TaskProfiler.SetSpikeThreshold(threshold)
self.setMagicWordResponse(response)
elif wordIs('~logtaskprofiles'):
args = word.split()
if len(args) > 1:
name = args[1]
else:
name = None
taskMgr.logTaskProfiles(name)
response = 'logged task profiles%s' % choice(name, ' for %s' % name, '')
self.setMagicWordResponse(response)
elif wordIs('~taskprofileflush'):
args = word.split()
if len(args) > 1:
name = args[1]
else:
name = None
taskMgr.flushTaskProfiles(name)
response = 'flushed AI task profiles%s' % choice(name, ' for %s' % name, '')
self.setMagicWordResponse(response)
elif wordIs('~dobjectcount'):
base.cr.printObjectCount()
self.setMagicWordResponse('logging client distributed object count...')
elif wordIs('~taskmgr'):
print taskMgr
self.setMagicWordResponse('logging client taskMgr...')
elif wordIs('~jobmgr'):
print jobMgr
self.setMagicWordResponse('logging client jobMgr...')
elif wordIs('~jobtime'):
args = word.split()
if len(args) > 1:
time = float(args[1])
else:
time = None
response = ''
if time is None:
time = jobMgr.getDefaultTimeslice()
response = 'reset client jobMgr timeslice to %s ms' % time
else:
response = 'set client jobMgr timeslice to %s ms' % time
time = time / 1000.0
jobMgr.setTimeslice(time)
self.setMagicWordResponse(response)
elif wordIs('~detectleaks'):
started = self.cr.startLeakDetector()
self.setMagicWordResponse(choice(started, 'leak detector started', 'leak detector already started'))
elif wordIs('~taskthreshold'):
args = word.split()
if len(args) > 1.0:
threshold = float(args[1])
else:
threshold = None
response = ''
if threshold is None:
threshold = taskMgr.DefTaskDurationWarningThreshold
response = 'reset task duration warning threshold to %s' % threshold
else:
response = 'set task duration warning threshold to %s' % threshold
taskMgr.setTaskDurationWarningThreshold(threshold)
self.setMagicWordResponse(response)
elif wordIs('~messenger'):
print messenger
self.setMagicWordResponse('logging client messenger...')
elif wordIs('~clientcrash'):
DelayedCall(Functor(self.notify.error, '~clientcrash: simulating a client crash'))
elif wordIs('~badDelete'):
doId = 0
while doId in base.cr.doId2do:
doId += 1
DelayedCall(Functor(base.cr.deleteObjectLocation, ScratchPad(doId=doId), 1, 1))
self.setMagicWordResponse('doing bad delete')
elif wordIs('~idTags'):
messenger.send('nameTagShowAvId', [])
base.idTags = 1
elif wordIs('~nameTags'):
messenger.send('nameTagShowName', [])
base.idTags = 0
elif wordIs('~hideNames'):
if NametagGlobals.getMasterNametagsVisible():
NametagGlobals.setMasterNametagsVisible(0)
else:
NametagGlobals.setMasterNametagsVisible(1)
elif wordIs('~hideGui'):
if aspect2d.isHidden():
aspect2d.show()
else:
aspect2d.hide()
elif wordIs('~flush'):
base.cr.doDataCache.flush()
base.cr.cache.flush()
self.setMagicWordResponse('client object and data caches flushed')
elif wordIs('~prof'):
import time
name = 'default'
p = Point3()
ts = time.time()
for i in xrange(1000000):
p.set(1, 2, 3)
tf = time.time()
dt = tf - ts
response = 'prof(%s): %s secs' % (name, dt)
print response
self.setMagicWordResponse(response)
elif wordIs('~gptc'):
args = word.split()
if len(args) > 1.0 and hasattr(self.cr, 'leakDetector'):
gptcJob = self.cr.leakDetector.getPathsToContainers('~gptc', args[1], Functor(self._handleGPTCfinished, args[1]))
else:
self.setMagicWordResponse('error')
elif wordIs('~gptcn'):
args = word.split()
if len(args) > 1.0 and hasattr(self.cr, 'leakDetector'):
gptcnJob = self.cr.leakDetector.getPathsToContainersNamed('~gptcn', args[1], Functor(self._handleGPTCNfinished, args[1]))
else:
self.setMagicWordResponse('error')
else:
return 0
return 1
def toggleRun(self):
if config.GetBool('want-running', 1):
inputState.set('debugRunning', inputState.isSet('debugRunning') != True)
def d_setMagicWord(self, magicWord, avId, zoneId):
self.sendUpdate('setMagicWord', [magicWord,
avId,
zoneId,
base.cr.userSignature])
def b_setMagicWord(self, magicWord, avId=None, zoneId=None):
if self.cr.wantMagicWords:
if avId == None:
avId = base.localAvatar.doId
if zoneId == None:
try:
zoneId = self.cr.playGame.getPlace().getZoneId()
except:
pass
if zoneId == None:
zoneId = 0
self.d_setMagicWord(magicWord, avId, zoneId)
if magicWord.count("~crash"):
args = magicWord.split()
errorCode = 12
if len(args) > 1:
errorCode = int(args[1])
self.notify.info("Simulating client crash: exit error = %s" % errorCode)
base.exitShow(errorCode)
if magicWord.count("~exception"):
self.notify.error("~exception: simulating a client exception...")
s = ""
while 1:
s += "INVALIDNAME"
eval(s)
self.setMagicWord(magicWord, avId, zoneId)
def setMagicWordResponse(self, response):
self.notify.info(response)
base.localAvatar.setChatAbsolute(response, CFSpeech | CFTimeout)
base.talkAssistant.receiveDeveloperMessage(response)
def d_setWho(self, avIds):
self.sendUpdate('setWho', [avIds])
def _handleGPTCfinished(self, ct, gptcJob):
self.setMagicWordResponse('gptc(%s) finished' % ct)
def _handleGPTCNfinished(self, cn, gptcnJob):
self.setMagicWordResponse('gptcn(%s) finished' % cn)
def forAnother(self, word, avId, zoneId):
b = 5
while word[b:b + 2] != ' ~':
b += 1
if b >= len(word):
self.setMagicWordResponse('No next magic word!')
return
nextWord = word[b + 1:]
name = string.strip(word[5:b])
id = self.identifyAvatar(name)
if id == None:
self.setMagicWordResponse("Don't know who %s is." % name)
return
self.d_setMagicWord(nextWord, id, zoneId)
return
def identifyAvatar(self, name):
self.notify.error('Pure virtual - please override me.')
def identifyDistributedObjects(self, name):
result = []
lowerName = string.lower(name)
for obj in self.cr.doId2do.values():
className = obj.__class__.__name__
try:
name = obj.getName()
except:
name = className
if string.lower(name) == lowerName or string.lower(className) == lowerName or string.lower(className) == 'distributed' + lowerName:
result.append((name, obj))
return result
def doTex(self, word):
args = word.split()
if len(args) <= 1:
if self.texViewer:
self.texViewer.cleanup()
self.texViewer = None
return
base.toggleTexture()
return
if self.texViewer:
self.texViewer.cleanup()
self.texViewer = None
tex = TexturePool.findTexture(args[1])
if not tex:
tex = TexturePool.findTexture('*%s*' % args[1])
if not tex:
self.setMagicWordResponse('Unknown texture: %s' % args[1])
return
self.texViewer = TexViewer(tex)
return
def getCSBitmask(self, str):
words = string.lower(str).split()
if len(words) == 0:
return None
invalid = ''
bitmask = BitMask32.allOff()
for w in words:
if w == 'wall':
bitmask |= OTPGlobals.WallBitmask
elif w == 'floor':
bitmask |= OTPGlobals.FloorBitmask
elif w == 'cam':
bitmask |= OTPGlobals.CameraBitmask
elif w == 'catch':
bitmask |= OTPGlobals.CatchBitmask
elif w == 'ghost':
bitmask |= OTPGlobals.GhostBitmask
elif w == 'pet':
bitmask |= OTPGlobals.PetBitmask
elif w == 'furniture':
bitmask |= OTPGlobals.FurnitureSideBitmask | OTPGlobals.FurnitureTopBitmask | OTPGlobals.FurnitureDragBitmask
elif w == 'furnitureside':
bitmask |= OTPGlobals.FurnitureSideBitmask
elif w == 'furnituretop':
bitmask |= OTPGlobals.FurnitureTopBitmask
elif w == 'furnituredrag':
bitmask |= OTPGlobals.FurnitureDragBitmask
elif w == 'pie':
bitmask |= OTPGlobals.PieBitmask
else:
try:
bitmask |= BitMask32.bit(int(w))
print bitmask
except ValueError:
invalid += ' ' + w
if invalid:
self.setMagicWordResponse('Unknown CS keyword(s): %s' % invalid)
return bitmask
def getFontByName(self, fontname):
if fontname == 'default':
return TextNode.getDefaultFont()
elif fontname == 'interface':
return OTPGlobals.getInterfaceFont()
elif fontname == 'sign':
return OTPGlobals.getSignFont()
else:
return None
return None
def showfont(self, fontname):
fontname = string.strip(string.lower(fontname))
font = self.getFontByName(fontname)
if font == None:
self.setMagicWordResponse('Unknown font: %s' % fontname)
return
if not isinstance(font, DynamicTextFont):
self.setMagicWordResponse('Font %s is not dynamic.' % fontname)
return
self.hidefont()
self.shownFontNode = aspect2d.attachNewNode('shownFont')
tn = TextNode('square')
tn.setCardActual(0.0, 1.0, -1.0, 0.0)
tn.setFrameActual(0.0, 1.0, -1.0, 0.0)
tn.setCardColor(1, 1, 1, 0.5)
tn.setFrameColor(1, 1, 1, 1)
tn.setFont(font)
tn.setText(' ')
numXPages = 2
numYPages = 2
pageScale = 0.8
pageMargin = 0.1
numPages = font.getNumPages()
x = 0
y = 0
for pi in range(numPages):
page = font.getPage(pi)
tn.setCardTexture(page)
np = self.shownFontNode.attachNewNode(tn.generate())
np.setScale(pageScale)
(np.setPos(float(x) / numXPages * 2 - 1 + pageMargin, 0, 1 - float(y) / numYPages * 2 - pageMargin),)
x += 1
if x >= numXPages:
y += 1
x = 0
return
def hidefont(self):
if self.shownFontNode != None:
self.shownFontNode.removeNode()
self.shownFontNode = None
return
def showShadowCollisions(self):
try:
base.shadowTrav.showCollisions(render)
except:
self.setMagicWordResponse('CollisionVisualizer is not compiled in.')
def hideShadowCollisions(self):
base.shadowTrav.hideCollisions()
def showCollisions(self):
try:
base.cTrav.showCollisions(render)
except:
self.setMagicWordResponse('CollisionVisualizer is not compiled in.')
def hideCollisions(self):
base.cTrav.hideCollisions()
def showCameraCollisions(self):
try:
localAvatar.ccTrav.showCollisions(render)
except:
self.setMagicWordResponse('CollisionVisualizer is not compiled in.')
def hideCameraCollisions(self):
localAvatar.ccTrav.hideCollisions()
def doFps(self, word, avId, zoneId):
args = word.split()
response = None
if len(args) == 1 or args[1] == 'normal':
if globalClock.getMode() != ClockObject.MNormal:
globalClock.setMode(ClockObject.MNormal)
response = 'Normal frame rate set.'
else:
base.setFrameRateMeter(not base.frameRateMeter)
elif args[1] == 'forced':
fps = float(args[2])
globalClock.setMode(ClockObject.MForced)
globalClock.setDt(1.0 / fps)
response = 'Frame rate forced to %s fps.' % fps
base.setFrameRateMeter(1)
elif args[1] == 'degrade':
factor = float(args[2])
globalClock.setMode(ClockObject.MDegrade)
globalClock.setDegradeFactor(factor)
response = 'Frame rate degraded by factor of %s.' % factor
base.setFrameRateMeter(1)
elif args[1][-1] == '%':
percent = float(args[1][:-1])
if percent == 100:
globalClock.setMode(ClockObject.MNormal)
response = 'Normal frame rate set.'
else:
globalClock.setMode(ClockObject.MDegrade)
globalClock.setDegradeFactor(100.0 / percent)
response = 'Frame rate degraded to %s percent.' % percent
base.setFrameRateMeter(1)
else:
try:
fps = float(args[1])
except:
fps = None
if fps != None:
globalClock.setMode(ClockObject.MForced)
globalClock.setDt(1.0 / fps)
response = 'Frame rate forced to %s fps.' % fps
base.setFrameRateMeter(1)
else:
response = 'Unknown fps command: ~s' % args[1]
if base.frameRateMeter:
globalClock.setAverageFrameRateInterval(ConfigVariableDouble('average-frame-rate-interval').getValue())
if response != None:
self.setMagicWordResponse(response)
return
def identifyAvatar(self, name):
for av in Avatar.Avatar.ActiveAvatars:
if isinstance(av, self.GameAvatarClass) and av.getName() == name:
return av.doId
lowerName = string.lower(name)
for av in Avatar.Avatar.ActiveAvatars:
if isinstance(av, self.GameAvatarClass) and string.strip(string.lower(av.getName())) == lowerName:
return av.doId
try:
avId = int(name)
return avId
except:
pass
return None
def toggleGuiPopup(self):
if self.guiPopupShown:
base.mouseWatcherNode.hideRegions()
self.guiPopupShown = 0
else:
base.mouseWatcherNode.showRegions(render2d, 'gui-popup', 0)
self.guiPopupShown = 1
def garbageReportDone(self, garbageReport):
self.setMagicWordResponse('%s garbage cycles' % garbageReport.getNumCycles())
def magicWord(mw):
messenger.send('magicWord', [mw])
import __builtin__
__builtin__.magicWord = magicWord

350
otp/ai/TimeManager.py Normal file
View file

@ -0,0 +1,350 @@
from pandac.PandaModules import *
from direct.showbase.DirectObject import *
from direct.distributed.ClockDelta import *
from direct.task import Task
from direct.distributed import DistributedObject
from direct.directnotify import DirectNotifyGlobal
from otp.otpbase import OTPGlobals
from direct.showbase import PythonUtil
from direct.showbase import GarbageReport
import base64
import time
import os
import sys
import re
class TimeManager(DistributedObject.DistributedObject):
notify = DirectNotifyGlobal.directNotify.newCategory('TimeManager')
neverDisable = 1
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
self.updateFreq = base.config.GetFloat('time-manager-freq', 1800)
self.minWait = base.config.GetFloat('time-manager-min-wait', 10)
self.maxUncertainty = base.config.GetFloat('time-manager-max-uncertainty', 1)
self.maxAttempts = base.config.GetInt('time-manager-max-attempts', 5)
self.extraSkew = base.config.GetInt('time-manager-extra-skew', 0)
if self.extraSkew != 0:
self.notify.info('Simulating clock skew of %0.3f s' % self.extraSkew)
self.reportFrameRateInterval = base.config.GetDouble('report-frame-rate-interval', 300.0)
self.talkResult = 0
self.thisContext = -1
self.nextContext = 0
self.attemptCount = 0
self.start = 0
self.lastAttempt = -self.minWait * 2
self.setFrameRateInterval(self.reportFrameRateInterval)
self._numClientGarbage = 0
def generate(self):
self._gotFirstTimeSync = False
if self.cr.timeManager != None:
self.cr.timeManager.delete()
self.cr.timeManager = self
DistributedObject.DistributedObject.generate(self)
self.accept(OTPGlobals.SynchronizeHotkey, self.handleHotkey)
self.accept('clock_error', self.handleClockError)
if __dev__ and base.config.GetBool('enable-garbage-hotkey', 0):
self.accept(OTPGlobals.DetectGarbageHotkey, self.handleDetectGarbageHotkey)
if self.updateFreq > 0:
self.startTask()
return
def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self)
self.synchronize('TimeManager.announceGenerate')
def gotInitialTimeSync(self):
return self._gotFirstTimeSync
def disable(self):
self.ignore(OTPGlobals.SynchronizeHotkey)
if __dev__:
self.ignore(OTPGlobals.DetectGarbageHotkey)
self.ignore('clock_error')
self.stopTask()
taskMgr.remove('frameRateMonitor')
if self.cr.timeManager == self:
self.cr.timeManager = None
del self._gotFirstTimeSync
DistributedObject.DistributedObject.disable(self)
return
def delete(self):
self.ignore(OTPGlobals.SynchronizeHotkey)
self.ignore(OTPGlobals.DetectGarbageHotkey)
self.ignore('clock_error')
self.stopTask()
taskMgr.remove('frameRateMonitor')
if self.cr.timeManager == self:
self.cr.timeManager = None
DistributedObject.DistributedObject.delete(self)
return
def startTask(self):
self.stopTask()
taskMgr.doMethodLater(self.updateFreq, self.doUpdate, 'timeMgrTask')
def stopTask(self):
taskMgr.remove('timeMgrTask')
def doUpdate(self, task):
self.synchronize('timer')
taskMgr.doMethodLater(self.updateFreq, self.doUpdate, 'timeMgrTask')
return Task.done
def handleHotkey(self):
self.lastAttempt = -self.minWait * 2
if self.synchronize('user hotkey'):
self.talkResult = 1
else:
base.localAvatar.setChatAbsolute('Too soon.', CFSpeech | CFTimeout)
def handleClockError(self):
self.synchronize('clock error')
def synchronize(self, description):
now = globalClock.getRealTime()
if now - self.lastAttempt < self.minWait:
self.notify.debug('Not resyncing (too soon): %s' % description)
return 0
self.talkResult = 0
self.thisContext = self.nextContext
self.attemptCount = 0
self.nextContext = self.nextContext + 1 & 255
self.notify.info('Clock sync: %s' % description)
self.start = now
self.lastAttempt = now
self.sendUpdate('requestServerTime', [self.thisContext])
return 1
def serverTime(self, context, timestamp, timeOfDay):
end = globalClock.getRealTime()
aiTimeSkew = timeOfDay - self.cr.getServerTimeOfDay()
if context != self.thisContext:
self.notify.info('Ignoring TimeManager response for old context %d' % context)
return
elapsed = end - self.start
self.attemptCount += 1
self.notify.info('Clock sync roundtrip took %0.3f ms' % (elapsed * 1000.0))
self.notify.info('AI time delta is %s from server delta' % PythonUtil.formatElapsedSeconds(aiTimeSkew))
average = (self.start + end) / 2.0 - self.extraSkew
uncertainty = (end - self.start) / 2.0 + abs(self.extraSkew)
globalClockDelta.resynchronize(average, timestamp, uncertainty)
self.notify.info('Local clock uncertainty +/- %.3f s' % globalClockDelta.getUncertainty())
if globalClockDelta.getUncertainty() > self.maxUncertainty:
if self.attemptCount < self.maxAttempts:
self.notify.info('Uncertainty is too high, trying again.')
self.start = globalClock.getRealTime()
self.sendUpdate('requestServerTime', [self.thisContext])
return
self.notify.info('Giving up on uncertainty requirement.')
if self.talkResult:
base.localAvatar.setChatAbsolute('latency %0.0f ms, sync \xc2\xb1%0.0f ms' % (elapsed * 1000.0, globalClockDelta.getUncertainty() * 1000.0), CFSpeech | CFTimeout)
self._gotFirstTimeSync = True
messenger.send('gotTimeSync')
def setDisconnectReason(self, disconnectCode):
self.notify.info('Client disconnect reason %s.' % disconnectCode)
self.sendUpdate('setDisconnectReason', [disconnectCode])
def setExceptionInfo(self):
info = PythonUtil.describeException()
self.notify.info('Client exception: %s' % info)
self.sendUpdate('setExceptionInfo', [info])
self.cr.flush()
def setStackDump(self, dump):
self.notify.debug('Stack dump: %s' % fastRepr(dump))
maxLen = 900
dataLeft = base64.b64encode(dump)
index = 0
while dataLeft:
if len(dataLeft) >= maxLen:
data = dataLeft[:maxLen]
dataLeft = dataLeft[maxLen:]
else:
data = dataLeft
dataLeft = None
self.sendUpdate('setStackDump', [index, data])
index += 1
self.cr.flush()
return
def d_setSignature(self, signature, hash, pyc):
self.sendUpdate('setSignature', [signature, hash, pyc])
def sendCpuInfo(self):
if not base.pipe:
return
di = base.pipe.getDisplayInformation()
if di.getNumCpuCores() == 0 and hasattr(base.pipe, 'lookupCpuData'):
base.pipe.lookupCpuData()
di = base.pipe.getDisplayInformation()
di.updateCpuFrequency(0)
try:
cacheStatus = preloadCache()
except NameError:
cacheStatus = ''
ooghz = 1e-09
cpuSpeed = (di.getMaximumCpuFrequency() * ooghz, di.getCurrentCpuFrequency() * ooghz)
numCpuCores = di.getNumCpuCores()
numLogicalCpus = di.getNumLogicalCpus()
info = '%s|%s|%d|%d|%s|%s cpus' % (di.getCpuVendorString(),
di.getCpuBrandString(),
di.getCpuVersionInformation(),
di.getCpuBrandIndex(),
'%0.03f,%0.03f' % cpuSpeed,
'%d,%d' % (numCpuCores, numLogicalCpus))
print 'cpu info: %s' % info
self.sendUpdate('setCpuInfo', [info, cacheStatus])
def setFrameRateInterval(self, frameRateInterval):
if frameRateInterval == 0:
return
if not base.frameRateMeter:
maxFrameRateInterval = base.config.GetDouble('max-frame-rate-interval', 30.0)
globalClock.setAverageFrameRateInterval(min(frameRateInterval, maxFrameRateInterval))
taskMgr.remove('frameRateMonitor')
taskMgr.doMethodLater(frameRateInterval, self.frameRateMonitor, 'frameRateMonitor')
def frameRateMonitor(self, task):
from otp.avatar.Avatar import Avatar
vendorId = 0
deviceId = 0
processMemory = 0
pageFileUsage = 0
physicalMemory = 0
pageFaultCount = 0
osInfo = (os.name,
0,
0,
0)
cpuSpeed = (0, 0)
numCpuCores = 0
numLogicalCpus = 0
apiName = 'None'
if getattr(base, 'pipe', None):
di = base.pipe.getDisplayInformation()
if di.getDisplayState() == DisplayInformation.DSSuccess:
vendorId = di.getVendorId()
deviceId = di.getDeviceId()
di.updateMemoryInformation()
oomb = 1.0 / (1024.0 * 1024.0)
processMemory = di.getProcessMemory() * oomb
pageFileUsage = di.getPageFileUsage() * oomb
physicalMemory = di.getPhysicalMemory() * oomb
pageFaultCount = di.getPageFaultCount() / 1000.0
osInfo = (os.name,
di.getOsPlatformId(),
di.getOsVersionMajor(),
di.getOsVersionMinor())
if sys.platform == 'darwin':
osInfo = self.getMacOsInfo(osInfo)
di.updateCpuFrequency(0)
ooghz = 1e-09
cpuSpeed = (di.getMaximumCpuFrequency() * ooghz, di.getCurrentCpuFrequency() * ooghz)
numCpuCores = di.getNumCpuCores()
numLogicalCpus = di.getNumLogicalCpus()
apiName = base.pipe.getInterfaceName()
self.d_setFrameRate(max(0, globalClock.getAverageFrameRate()), max(0, globalClock.calcFrameRateDeviation()), len(Avatar.ActiveAvatars), base.locationCode or '', max(0, time.time() - base.locationCodeChanged), max(0, globalClock.getRealTime()), base.gameOptionsCode, vendorId, deviceId, processMemory, pageFileUsage, physicalMemory, pageFaultCount, osInfo, cpuSpeed, numCpuCores, numLogicalCpus, apiName)
return task.again
def d_setFrameRate(self, fps, deviation, numAvs, locationCode, timeInLocation, timeInGame, gameOptionsCode, vendorId, deviceId, processMemory, pageFileUsage, physicalMemory, pageFaultCount, osInfo, cpuSpeed, numCpuCores, numLogicalCpus, apiName):
info = '%0.1f fps|%0.3fd|%s avs|%s|%d|%d|%s|0x%04x|0x%04x|%0.1fMB|%0.1fMB|%0.1fMB|%d|%s|%s|%s cpus|%s' % (fps,
deviation,
numAvs,
locationCode,
timeInLocation,
timeInGame,
gameOptionsCode,
vendorId,
deviceId,
processMemory,
pageFileUsage,
physicalMemory,
pageFaultCount,
'%s.%d.%d.%d' % osInfo,
'%0.03f,%0.03f' % cpuSpeed,
'%d,%d' % (numCpuCores, numLogicalCpus),
apiName)
print 'frame rate: %s' % info
self.sendUpdate('setFrameRate', [fps,
deviation,
numAvs,
locationCode,
timeInLocation,
timeInGame,
gameOptionsCode,
vendorId,
deviceId,
processMemory,
pageFileUsage,
physicalMemory,
pageFaultCount,
osInfo,
cpuSpeed,
numCpuCores,
numLogicalCpus,
apiName])
if __dev__:
def handleDetectGarbageHotkey(self):
self._numClientGarbage = GarbageReport.b_checkForGarbageLeaks(wantReply=True)
if self._numClientGarbage:
s = '%s client garbage cycles found, see log' % self._numClientGarbage
else:
s = '0 client garbage cycles found'
localAvatar.setChatAbsolute(s, CFSpeech | CFTimeout)
def d_checkForGarbageLeaks(self, wantReply):
self.sendUpdate('checkForGarbageLeaks', [wantReply])
def setNumAIGarbageLeaks(self, numLeaks):
if self._numClientGarbage and numLeaks:
s = '%s client and %s AI garbage cycles found, see logs' % (self._numClientGarbage, numLeaks)
elif numLeaks:
s = '0 client and %s AI garbage cycles found, see log' % numLeaks
else:
s = '0 client and 0 AI garbage cycles found'
localAvatar.setChatAbsolute(s, CFSpeech | CFTimeout)
def d_setClientGarbageLeak(self, num, description):
self.sendUpdate('setClientGarbageLeak', [num, description])
def getMacOsInfo(self, defaultOsInfo):
result = defaultOsInfo
try:
theFile = open('/System/Library/CoreServices/SystemVersion.plist')
except IOError:
pass
else:
key = re.search('<key>ProductUserVisibleVersion</key>\\s*' + '<string>(.*?)</string>', theFile.read())
theFile.close()
if key is not None:
try:
verString = key.group(1)
parts = verString.split('.')
major = int(parts[0])
minor = int(parts[1])
bugfix = int(parts[2])
result = (sys.platform,
bugfix,
major,
minor)
except Exception, e:
self.notify.debug('getMacOsInfo %s' % str(e))
self.notify.debug('getMacOsInfo returning %s' % str(result))
return result
def checkAvOnDistrict(self, av, context):
self.sendUpdate('checkAvOnDistrict', [context, av.doId])
def checkAvOnDistrictResult(self, context, avId, present):
av = self.cr.getDo(avId)
if av:
av._zombieCheckResult(context, present)

0
otp/ai/__init__.py Normal file
View file

587
otp/avatar/Avatar.py Normal file
View file

@ -0,0 +1,587 @@
from pandac.PandaModules import *
from libotp import Nametag, NametagGroup
from libotp import CFSpeech, CFThought, CFTimeout, CFPageButton, CFNoQuitButton, CFQuitButton
from otp.otpbase import OTPGlobals
from otp.otpbase import OTPLocalizer
from direct.actor.Actor import Actor
from direct.directnotify import DirectNotifyGlobal
from direct.distributed import ClockDelta
from otp.avatar.ShadowCaster import ShadowCaster
import random
from otp.otpbase import OTPRender
from direct.showbase.PythonUtil import recordCreationStack
teleportNotify = DirectNotifyGlobal.directNotify.newCategory('Teleport')
teleportNotify.showTime = True
if config.GetBool('want-teleport-debug', 1):
teleportNotify.setDebug(1)
def reconsiderAllUnderstandable():
for av in Avatar.ActiveAvatars:
av.considerUnderstandable()
class Avatar(Actor, ShadowCaster):
notify = directNotify.newCategory('Avatar')
ActiveAvatars = []
ManagesNametagAmbientLightChanged = False
def __init__(self, other = None):
self.name = ''
try:
self.Avatar_initialized
return
except:
self.Avatar_initialized = 1
Actor.__init__(self, None, None, other, flattenable=0, setFinal=1)
ShadowCaster.__init__(self)
self.__font = OTPGlobals.getInterfaceFont()
self.soundChatBubble = None
self.avatarType = ''
self.nametagNodePath = None
self.__nameVisible = 1
self.nametag = NametagGroup()
self.nametag.setAvatar(self)
self.nametag.setFont(OTPGlobals.getInterfaceFont())
self.nametag2dContents = Nametag.CName | Nametag.CSpeech
self.nametag2dDist = Nametag.CName | Nametag.CSpeech
self.nametag2dNormalContents = Nametag.CName | Nametag.CSpeech
self.nametag3d = self.attachNewNode('nametag3d')
self.nametag3d.setTag('cam', 'nametag')
self.nametag3d.setLightOff()
if self.ManagesNametagAmbientLightChanged:
self.acceptNametagAmbientLightChange()
OTPRender.renderReflection(False, self.nametag3d, 'otp_avatar_nametag', None)
self.getGeomNode().showThrough(OTPRender.ShadowCameraBitmask)
self.nametag3d.hide(OTPRender.ShadowCameraBitmask)
self.collTube = None
self.battleTube = None
self.scale = 1.0
self.nametagScale = 1.0
self.height = 0.0
self.battleTubeHeight = 0.0
self.battleTubeRadius = 0.0
self.style = None
self.commonChatFlags = 0
self.understandable = 1
self.setPlayerType(NametagGroup.CCNormal)
self.ghostMode = 0
self.__chatParagraph = None
self.__chatMessage = None
self.__chatFlags = 0
self.__chatPageNumber = None
self.__chatAddressee = None
self.__chatDialogueList = []
self.__chatSet = 0
self.__chatLocal = 0
self.__currentDialogue = None
self.whitelistChatFlags = 0
return
def delete(self):
try:
self.Avatar_deleted
except:
self.deleteNametag3d()
Actor.cleanup(self)
if self.ManagesNametagAmbientLightChanged:
self.ignoreNametagAmbientLightChange()
self.Avatar_deleted = 1
del self.__font
del self.style
del self.soundChatBubble
del self.nametag
self.nametag3d.removeNode()
ShadowCaster.delete(self)
Actor.delete(self)
def acceptNametagAmbientLightChange(self):
self.accept('nametagAmbientLightChanged', self.nametagAmbientLightChanged)
def ignoreNametagAmbientLightChange(self):
self.ignore('nametagAmbientLightChanged')
def isLocal(self):
return 0
def isPet(self):
return False
def isProxy(self):
return False
def setPlayerType(self, playerType):
self.playerType = playerType
if not hasattr(self, 'nametag'):
self.notify.warning('no nametag attributed, but would have been used.')
return
if self.isUnderstandable():
self.nametag.setColorCode(self.playerType)
else:
self.nametag.setColorCode(NametagGroup.CCNoChat)
def setCommonChatFlags(self, commonChatFlags):
self.commonChatFlags = commonChatFlags
self.considerUnderstandable()
if self == base.localAvatar:
reconsiderAllUnderstandable()
def setWhitelistChatFlags(self, whitelistChatFlags):
self.whitelistChatFlags = whitelistChatFlags
self.considerUnderstandable()
if self == base.localAvatar:
reconsiderAllUnderstandable()
def considerUnderstandable(self):
speed = 0
if self.playerType in (NametagGroup.CCNormal, NametagGroup.CCFreeChat, NametagGroup.CCSpeedChat):
self.setPlayerType(NametagGroup.CCSpeedChat)
speed = 1
if hasattr(base, 'localAvatar') and self == base.localAvatar:
self.understandable = 1
self.setPlayerType(NametagGroup.CCFreeChat)
elif self.playerType == NametagGroup.CCSuit:
self.understandable = 1
self.setPlayerType(NametagGroup.CCSuit)
elif self.playerType not in (NametagGroup.CCNormal, NametagGroup.CCFreeChat, NametagGroup.CCSpeedChat):
self.understandable = 1
self.setPlayerType(NametagGroup.CCNoChat)
elif hasattr(base, 'localAvatar') and self.commonChatFlags & base.localAvatar.commonChatFlags & OTPGlobals.CommonChat:
self.understandable = 1
self.setPlayerType(NametagGroup.CCFreeChat)
elif self.commonChatFlags & OTPGlobals.SuperChat:
self.understandable = 1
self.setPlayerType(NametagGroup.CCFreeChat)
elif hasattr(base, 'localAvatar') and base.localAvatar.commonChatFlags & OTPGlobals.SuperChat:
self.understandable = 1
self.setPlayerType(NametagGroup.CCFreeChat)
elif base.cr.getFriendFlags(self.doId) & OTPGlobals.FriendChat:
self.understandable = 1
self.setPlayerType(NametagGroup.CCFreeChat)
elif base.cr.playerFriendsManager.findPlayerIdFromAvId(self.doId) is not None:
playerInfo = base.cr.playerFriendsManager.findPlayerInfoFromAvId(self.doId)
if playerInfo.openChatFriendshipYesNo:
self.understandable = 1
self.nametag.setColorCode(NametagGroup.CCFreeChat)
elif playerInfo.isUnderstandable():
self.understandable = 1
else:
self.understandable = 0
elif hasattr(base, 'localAvatar') and self.whitelistChatFlags & base.localAvatar.whitelistChatFlags:
self.understandable = 1
else:
self.understandable = 0
if not hasattr(self, 'nametag'):
self.notify.warning('no nametag attributed, but would have been used')
else:
self.nametag.setColorCode(self.playerType)
return
def isUnderstandable(self):
return self.understandable
def setDNAString(self, dnaString):
pass
def setDNA(self, dna):
pass
def getAvatarScale(self):
return self.scale
def setAvatarScale(self, scale):
if self.scale != scale:
self.scale = scale
self.getGeomNode().setScale(scale)
self.setHeight(self.height)
def getNametagScale(self):
return self.nametagScale
def setNametagScale(self, scale):
self.nametagScale = scale
self.nametag3d.setScale(scale)
def adjustNametag3d(self, parentScale = 1.0):
self.nametag3d.setPos(0, 0, self.height + 0.5)
def getHeight(self):
return self.height
def setHeight(self, height):
self.height = height
self.adjustNametag3d()
if self.collTube:
self.collTube.setPointB(0, 0, height - self.getRadius())
if self.collNodePath:
self.collNodePath.forceRecomputeBounds()
if self.battleTube:
self.battleTube.setPointB(0, 0, height - self.getRadius())
def getRadius(self):
return OTPGlobals.AvatarDefaultRadius
def getName(self):
return self.name
def getType(self):
return self.avatarType
def setName(self, name):
if hasattr(self, 'isDisguised'):
if self.isDisguised:
return
self.name = name
if hasattr(self, 'nametag'):
self.nametag.setName(name)
def setDisplayName(self, str):
if hasattr(self, 'isDisguised'):
if self.isDisguised:
return
self.nametag.setDisplayName(str)
def getFont(self):
return self.__font
def setFont(self, font):
self.__font = font
self.nametag.setFont(font)
def getStyle(self):
return self.style
def setStyle(self, style):
self.style = style
def getDialogueArray(self):
return None
def playCurrentDialogue(self, dialogue, chatFlags, interrupt = 1):
if interrupt and self.__currentDialogue is not None:
self.__currentDialogue.stop()
self.__currentDialogue = dialogue
if dialogue:
base.playSfx(dialogue, node=self)
elif chatFlags & CFSpeech != 0 and self.nametag.getNumChatPages() > 0:
self.playDialogueForString(self.nametag.getChat())
if self.soundChatBubble != None:
base.playSfx(self.soundChatBubble, node=self)
return
def playDialogueForString(self, chatString):
searchString = chatString.lower()
if searchString.find(OTPLocalizer.DialogSpecial) >= 0:
type = 'special'
elif searchString.find(OTPLocalizer.DialogExclamation) >= 0:
type = 'exclamation'
elif searchString.find(OTPLocalizer.DialogQuestion) >= 0:
type = 'question'
elif random.randint(0, 1):
type = 'statementA'
else:
type = 'statementB'
stringLength = len(chatString)
if stringLength <= OTPLocalizer.DialogLength1:
length = 1
elif stringLength <= OTPLocalizer.DialogLength2:
length = 2
elif stringLength <= OTPLocalizer.DialogLength3:
length = 3
else:
length = 4
self.playDialogue(type, length)
def playDialogue(self, type, length):
dialogueArray = self.getDialogueArray()
if dialogueArray == None:
return
sfxIndex = None
if type == 'statementA' or type == 'statementB':
if length == 1:
sfxIndex = 0
elif length == 2:
sfxIndex = 1
elif length >= 3:
sfxIndex = 2
elif type == 'question':
sfxIndex = 3
elif type == 'exclamation':
sfxIndex = 4
elif type == 'special':
sfxIndex = 5
else:
notify.error('unrecognized dialogue type: ', type)
if sfxIndex != None and sfxIndex < len(dialogueArray) and dialogueArray[sfxIndex] != None:
base.playSfx(dialogueArray[sfxIndex], node=self)
return
def getDialogueSfx(self, type, length):
retval = None
dialogueArray = self.getDialogueArray()
if dialogueArray == None:
return
sfxIndex = None
if type == 'statementA' or type == 'statementB':
if length == 1:
sfxIndex = 0
elif length == 2:
sfxIndex = 1
elif length >= 3:
sfxIndex = 2
elif type == 'question':
sfxIndex = 3
elif type == 'exclamation':
sfxIndex = 4
elif type == 'special':
sfxIndex = 5
else:
notify.error('unrecognized dialogue type: ', type)
if sfxIndex != None and sfxIndex < len(dialogueArray) and dialogueArray[sfxIndex] != None:
retval = dialogueArray[sfxIndex]
return retval
def setChatAbsolute(self, chatString, chatFlags, dialogue = None, interrupt = 1):
self.nametag.setChat(chatString, chatFlags)
self.playCurrentDialogue(dialogue, chatFlags, interrupt)
def setChatMuted(self, chatString, chatFlags, dialogue = None, interrupt = 1, quiet = 0):
pass
def displayTalk(self, chatString):
if not base.cr.avatarFriendsManager.checkIgnored(self.doId):
if base.talkAssistant.isThought(chatString):
self.nametag.setChat(base.talkAssistant.removeThoughtPrefix(chatString), CFThought)
else:
self.nametag.setChat(chatString, CFSpeech | CFTimeout)
def clearChat(self):
self.nametag.clearChat()
def isInView(self):
pos = self.getPos(camera)
eyePos = Point3(pos[0], pos[1], pos[2] + self.getHeight())
return base.camNode.isInView(eyePos)
def getNameVisible(self):
return self.__nameVisible
def setNameVisible(self, bool):
self.__nameVisible = bool
if bool:
self.showName()
if not bool:
self.hideName()
def hideName(self):
self.nametag.getNametag3d().setContents(Nametag.CSpeech | Nametag.CThought)
def showName(self):
if self.__nameVisible and not self.ghostMode:
self.nametag.getNametag3d().setContents(Nametag.CName | Nametag.CSpeech | Nametag.CThought)
def hideNametag2d(self):
self.nametag2dContents = 0
self.nametag.getNametag2d().setContents(self.nametag2dContents & self.nametag2dDist)
def showNametag2d(self):
self.nametag2dContents = self.nametag2dNormalContents
if self.ghostMode:
self.nametag2dContents = Nametag.CSpeech
self.nametag.getNametag2d().setContents(self.nametag2dContents & self.nametag2dDist)
def hideNametag3d(self):
self.nametag.getNametag3d().setContents(0)
def showNametag3d(self):
if self.__nameVisible and not self.ghostMode:
self.nametag.getNametag3d().setContents(Nametag.CName | Nametag.CSpeech | Nametag.CThought)
else:
self.nametag.getNametag3d().setContents(0)
def setPickable(self, flag):
self.nametag.setActive(flag)
def clickedNametag(self):
if self.nametag.hasButton():
self.advancePageNumber()
elif self.nametag.isActive():
messenger.send('clickedNametag', [self])
def setPageChat(self, addressee, paragraph, message, quitButton, extraChatFlags = None, dialogueList = [], pageButton = True):
self.__chatAddressee = addressee
self.__chatPageNumber = None
self.__chatParagraph = paragraph
self.__chatMessage = message
if extraChatFlags is None:
self.__chatFlags = CFSpeech
else:
self.__chatFlags = CFSpeech | extraChatFlags
self.__chatDialogueList = dialogueList
self.__chatSet = 0
self.__chatLocal = 0
self.__updatePageChat()
if addressee == base.localAvatar.doId:
if pageButton:
self.__chatFlags |= CFPageButton
if quitButton == None:
self.__chatFlags |= CFNoQuitButton
elif quitButton:
self.__chatFlags |= CFQuitButton
self.b_setPageNumber(self.__chatParagraph, 0)
return
def setLocalPageChat(self, message, quitButton, extraChatFlags = None, dialogueList = []):
self.__chatAddressee = base.localAvatar.doId
self.__chatPageNumber = None
self.__chatParagraph = None
self.__chatMessage = message
if extraChatFlags is None:
self.__chatFlags = CFSpeech
else:
self.__chatFlags = CFSpeech | extraChatFlags
self.__chatDialogueList = dialogueList
self.__chatSet = 1
self.__chatLocal = 1
self.__chatFlags |= CFPageButton
if quitButton == None:
self.__chatFlags |= CFNoQuitButton
elif quitButton:
self.__chatFlags |= CFQuitButton
if len(dialogueList) > 0:
dialogue = dialogueList[0]
else:
dialogue = None
self.clearChat()
self.setChatAbsolute(message, self.__chatFlags, dialogue)
self.setPageNumber(None, 0)
return
def setPageNumber(self, paragraph, pageNumber, timestamp = None):
if timestamp == None:
elapsed = 0.0
else:
elapsed = ClockDelta.globalClockDelta.localElapsedTime(timestamp)
self.__chatPageNumber = [paragraph, pageNumber]
self.__updatePageChat()
if hasattr(self, 'uniqueName'):
if pageNumber >= 0:
messenger.send(self.uniqueName('nextChatPage'), [pageNumber, elapsed])
else:
messenger.send(self.uniqueName('doneChatPage'), [elapsed])
elif pageNumber >= 0:
messenger.send('nextChatPage', [pageNumber, elapsed])
else:
messenger.send('doneChatPage', [elapsed])
return
def advancePageNumber(self):
if self.__chatAddressee == base.localAvatar.doId and self.__chatPageNumber != None and self.__chatPageNumber[0] == self.__chatParagraph:
pageNumber = self.__chatPageNumber[1]
if pageNumber >= 0:
pageNumber += 1
if pageNumber >= self.nametag.getNumChatPages():
pageNumber = -1
if self.__chatLocal:
self.setPageNumber(self.__chatParagraph, pageNumber)
else:
self.b_setPageNumber(self.__chatParagraph, pageNumber)
return
def __updatePageChat(self):
if self.__chatPageNumber != None and self.__chatPageNumber[0] == self.__chatParagraph:
pageNumber = self.__chatPageNumber[1]
if pageNumber >= 0:
if not self.__chatSet:
if len(self.__chatDialogueList) > 0:
dialogue = self.__chatDialogueList[0]
else:
dialogue = None
self.setChatAbsolute(self.__chatMessage, self.__chatFlags, dialogue)
self.__chatSet = 1
if pageNumber < self.nametag.getNumChatPages():
self.nametag.setPageNumber(pageNumber)
if pageNumber > 0:
if len(self.__chatDialogueList) > pageNumber:
dialogue = self.__chatDialogueList[pageNumber]
else:
dialogue = None
self.playCurrentDialogue(dialogue, self.__chatFlags)
else:
self.clearChat()
else:
self.clearChat()
return
def getAirborneHeight(self):
height = self.getPos(self.shadowPlacer.shadowNodePath)
return height.getZ() + 0.025
def initializeNametag3d(self):
self.deleteNametag3d()
nametagNode = self.nametag.getNametag3d()
self.nametagNodePath = self.nametag3d.attachNewNode(nametagNode)
iconNodePath = self.nametag.getNameIcon()
for cJoint in self.getNametagJoints():
cJoint.clearNetTransforms()
cJoint.addNetTransform(nametagNode)
def nametagAmbientLightChanged(self, newlight):
self.nametag3d.setLightOff()
if newlight:
self.nametag3d.setLight(newlight)
def deleteNametag3d(self):
if self.nametagNodePath:
self.nametagNodePath.removeNode()
self.nametagNodePath = None
return
def initializeBodyCollisions(self, collIdStr):
self.collTube = CollisionTube(0, 0, 0.5, 0, 0, self.height - self.getRadius(), self.getRadius())
self.collNode = CollisionNode(collIdStr)
self.collNode.addSolid(self.collTube)
self.collNodePath = self.attachNewNode(self.collNode)
if self.ghostMode:
self.collNode.setCollideMask(OTPGlobals.GhostBitmask)
else:
self.collNode.setCollideMask(OTPGlobals.WallBitmask)
def stashBodyCollisions(self):
if hasattr(self, 'collNodePath'):
self.collNodePath.stash()
def unstashBodyCollisions(self):
if hasattr(self, 'collNodePath'):
self.collNodePath.unstash()
def disableBodyCollisions(self):
if hasattr(self, 'collNodePath'):
self.collNodePath.removeNode()
del self.collNodePath
self.collTube = None
return
def addActive(self):
if base.wantNametags:
try:
Avatar.ActiveAvatars.remove(self)
except ValueError:
pass
Avatar.ActiveAvatars.append(self)
self.nametag.manage(base.marginManager)
self.accept(self.nametag.getUniqueId(), self.clickedNametag)
def removeActive(self):
if base.wantNametags:
try:
Avatar.ActiveAvatars.remove(self)
except ValueError:
pass
self.nametag.unmanage(base.marginManager)
self.ignore(self.nametag.getUniqueId())
def loop(self, animName, restart = 1, partName = None, fromFrame = None, toFrame = None):
return Actor.loop(self, animName, restart, partName, fromFrame, toFrame)

26
otp/avatar/AvatarDNA.py Normal file
View file

@ -0,0 +1,26 @@
from pandac.PandaModules import *
from direct.directnotify.DirectNotifyGlobal import *
import random
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
notify = directNotify.newCategory('AvatarDNA')
class AvatarDNA:
def __str__(self):
return 'avatar parent class: type undefined'
def makeNetString(self):
notify.error('called makeNetString on avatarDNA parent class')
def printNetString(self):
string = self.makeNetString()
dg = PyDatagram(string)
dg.dumpHex(ostream)
def makeFromNetString(self, string):
notify.error('called makeFromNetString on avatarDNA parent class')
def getType(self):
notify.error('Invalid DNA type: ', self.type)
return type

View file

@ -0,0 +1,51 @@
from direct.directnotify.DirectNotifyGlobal import directNotify
from otp.avatar import Avatar
class AvatarDetail:
notify = directNotify.newCategory('AvatarDetail')
def __init__(self, doId, callWhenDone):
self.id = doId
self.callWhenDone = callWhenDone
self.enterQuery()
def isReady(self):
return true
def getId(self):
return self.id
def enterQuery(self):
self.avatar = base.cr.doId2do.get(self.id)
if self.avatar != None and not self.avatar.ghostMode:
self.createdAvatar = 0
dclass = self.getDClass()
self.__handleResponse(True, self.avatar, dclass)
else:
self.avatar = self.createHolder()
self.createdAvatar = 1
self.avatar.doId = self.id
dclass = self.getDClass()
base.cr.getAvatarDetails(self.avatar, self.__handleResponse, dclass)
return
def exitQuery(self):
return true
def createHolder(self):
pass
def getDClass(self):
pass
def __handleResponse(self, gotData, avatar, dclass):
if avatar != self.avatar:
self.notify.warning('Ignoring unexpected request for avatar %s' % avatar.doId)
return
if gotData:
self.callWhenDone(self.avatar)
del self.callWhenDone
else:
self.callWhenDone(None)
del self.callWhenDone
return

View file

@ -0,0 +1,24 @@
class AvatarHandle:
dclassName = 'AvatarHandle'
def getName(self):
if __dev__:
pass
return ''
def isOnline(self):
if __dev__:
pass
return False
def isUnderstandable(self):
if __dev__:
pass
return True
def setTalkWhisper(self, fromAV, fromAC, avatarName, chat, mods, flags):
newText, scrubbed = localAvatar.scrubTalk(chat, mods)
base.talkAssistant.receiveWhisperTalk(fromAV, avatarName, fromAC, None, self.avatarId, self.getName(), newText, scrubbed)
return

75
otp/avatar/AvatarPanel.py Normal file
View file

@ -0,0 +1,75 @@
from pandac.PandaModules import *
from direct.gui.DirectGui import *
from direct.showbase import DirectObject
import Avatar
from direct.distributed import DistributedObject
class AvatarPanel(DirectObject.DirectObject):
currentAvatarPanel = None
def __init__(self, avatar, FriendsListPanel = None):
if AvatarPanel.currentAvatarPanel:
AvatarPanel.currentAvatarPanel.cleanup()
AvatarPanel.currentAvatarPanel = self
self.friendsListShown = False
self.FriendsListPanel = FriendsListPanel
if FriendsListPanel:
self.friendsListShown = FriendsListPanel.isFriendsListShown()
FriendsListPanel.hideFriendsList()
if avatar:
self.avatar = avatar
self.avName = avatar.getName()
else:
self.avatar = None
self.avName = 'Player'
if hasattr(avatar, 'uniqueName'):
self.avId = avatar.doId
self.avDisableName = avatar.uniqueName('disable')
self.avGenerateName = avatar.uniqueName('generate')
self.avHpChangeName = avatar.uniqueName('hpChange')
if base.cr.doId2do.has_key(self.avId):
self.avatar = base.cr.doId2do[self.avId]
else:
self.avDisableName = None
self.avGenerateName = None
self.avHpChangeName = None
self.avId = None
if self.avDisableName:
self.accept(self.avDisableName, self.__handleDisableAvatar)
return
def cleanup(self):
if AvatarPanel.currentAvatarPanel != self:
return
if self.avDisableName:
self.ignore(self.avDisableName)
if self.avGenerateName:
self.ignore(self.avGenerateName)
if self.avHpChangeName:
self.ignore(self.avHpChangeName)
AvatarPanel.currentAvatarPanel = None
return
def __handleClose(self):
self.cleanup()
AvatarPanel.currentAvatarPanel = None
if self.friendsListShown:
self.FriendsListPanel.showFriendsList()
return
def __handleDisableAvatar(self):
if AvatarPanel.currentAvatarPanel:
AvatarPanel.currentAvatarPanel.handleDisableAvatar()
else:
self.handleDisableAvatar()
def handleDisableAvatar(self):
self.cleanup()
AvatarPanel.currentAvatarPanel = None
return
def isHidden(self):
return 1
def getType(self):
return None

View file

@ -0,0 +1,262 @@
import time
import string
from pandac.PandaModules import *
from direct.distributed import DistributedNode
from direct.actor.DistributedActor import DistributedActor
from direct.task import Task
from direct.showbase import PythonUtil
from libotp import Nametag
from otp.otpbase import OTPGlobals
from otp.otpbase import OTPLocalizer
from otp.speedchat import SCDecoders
from otp.chat import ChatGarbler
from otp.chat import ChatManager
import random
from Avatar import Avatar
import AvatarDNA
class DistributedAvatar(DistributedActor, Avatar):
HpTextGenerator = TextNode('HpTextGenerator')
HpTextEnabled = 1
ManagesNametagAmbientLightChanged = True
def __init__(self, cr):
try:
self.DistributedAvatar_initialized
return
except:
self.DistributedAvatar_initialized = 1
Avatar.__init__(self)
DistributedActor.__init__(self, cr)
self.hpText = None
self.hp = None
self.maxHp = None
return
def disable(self):
try:
del self.DistributedAvatar_announced
except:
return
self.reparentTo(hidden)
self.removeActive()
self.disableBodyCollisions()
self.hideHpText()
self.hp = None
self.ignore('nameTagShowAvId')
self.ignore('nameTagShowName')
DistributedActor.disable(self)
return
def delete(self):
try:
self.DistributedAvatar_deleted
except:
self.DistributedAvatar_deleted = 1
Avatar.delete(self)
DistributedActor.delete(self)
def generate(self):
DistributedActor.generate(self)
if not self.isLocal():
self.addActive()
self.considerUnderstandable()
self.setParent(OTPGlobals.SPHidden)
self.setTag('avatarDoId', str(self.doId))
self.accept('nameTagShowAvId', self.__nameTagShowAvId)
self.accept('nameTagShowName', self.__nameTagShowName)
def announceGenerate(self):
try:
self.DistributedAvatar_announced
return
except:
self.DistributedAvatar_announced = 1
if not self.isLocal():
self.initializeBodyCollisions('distAvatarCollNode-' + str(self.doId))
DistributedActor.announceGenerate(self)
def __setTags(self, extra = None):
if hasattr(base, 'idTags'):
if base.idTags:
self.__nameTagShowAvId()
else:
self.__nameTagShowName()
def do_setParent(self, parentToken):
if not self.isDisabled():
if parentToken == OTPGlobals.SPHidden:
self.nametag2dDist &= ~Nametag.CName
else:
self.nametag2dDist |= Nametag.CName
self.nametag.getNametag2d().setContents(self.nametag2dContents & self.nametag2dDist)
DistributedActor.do_setParent(self, parentToken)
self.__setTags()
def toonUp(self, hpGained):
if self.hp == None or hpGained < 0:
return
oldHp = self.hp
if self.hp + hpGained <= 0:
self.hp += hpGained
else:
self.hp = min(max(self.hp, 0) + hpGained, self.maxHp)
hpGained = self.hp - max(oldHp, 0)
if hpGained > 0:
self.showHpText(hpGained)
self.hpChange(quietly=0)
return
def takeDamage(self, hpLost, bonus = 0):
if self.hp == None or hpLost < 0:
return
oldHp = self.hp
self.hp = max(self.hp - hpLost, 0)
hpLost = oldHp - self.hp
if hpLost > 0:
self.showHpText(-hpLost, bonus)
self.hpChange(quietly=0)
if self.hp <= 0 and oldHp > 0:
self.died()
return
def setHp(self, hitPoints):
justRanOutOfHp = (hitPoints is not None and self.hp is not None and self.hp - hitPoints > 0) and (hitPoints <= 0)
self.hp = hitPoints
self.hpChange(quietly=1)
if justRanOutOfHp:
self.died()
return
def hpChange(self, quietly = 0):
if hasattr(self, 'doId'):
if self.hp != None and self.maxHp != None:
messenger.send(self.uniqueName('hpChange'), [self.hp, self.maxHp, quietly])
if self.hp != None and self.hp > 0:
messenger.send(self.uniqueName('positiveHP'))
return
def died(self):
pass
def getHp(self):
return self.hp
def setMaxHp(self, hitPoints):
self.maxHp = hitPoints
self.hpChange()
def getMaxHp(self):
return self.maxHp
def getName(self):
return Avatar.getName(self)
def setName(self, name):
try:
self.node().setName('%s-%d' % (name, self.doId))
self.gotName = 1
except:
pass
return Avatar.setName(self, name)
def showHpText(self, number, bonus = 0, scale = 1):
if self.HpTextEnabled and not self.ghostMode:
if number != 0:
if self.hpText:
self.hideHpText()
self.HpTextGenerator.setFont(OTPGlobals.getSignFont())
if number < 0:
self.HpTextGenerator.setText(str(number))
else:
self.HpTextGenerator.setText('+' + str(number))
self.HpTextGenerator.clearShadow()
self.HpTextGenerator.setAlign(TextNode.ACenter)
if bonus == 1:
r = 1.0
g = 1.0
b = 0
a = 1
elif bonus == 2:
r = 1.0
g = 0.5
b = 0
a = 1
elif number < 0:
r = 0.9
g = 0
b = 0
a = 1
else:
r = 0
g = 0.9
b = 0
a = 1
self.HpTextGenerator.setTextColor(r, g, b, a)
self.hpTextNode = self.HpTextGenerator.generate()
self.hpText = self.attachNewNode(self.hpTextNode)
self.hpText.setScale(scale)
self.hpText.setBillboardPointEye()
self.hpText.setBin('fixed', 100)
self.hpText.setPos(0, 0, self.height / 2)
seq = Task.sequence(self.hpText.lerpPos(Point3(0, 0, self.height + 1.5), 1.0, blendType='easeOut'), Task.pause(0.85), self.hpText.lerpColor(Vec4(r, g, b, a), Vec4(r, g, b, 0), 0.1), Task.Task(self.hideHpTextTask))
taskMgr.add(seq, self.uniqueName('hpText'))
def showHpString(self, text, duration = 0.85, scale = 0.7):
if self.HpTextEnabled and not self.ghostMode:
if text != '':
if self.hpText:
self.hideHpText()
self.HpTextGenerator.setFont(OTPGlobals.getSignFont())
self.HpTextGenerator.setText(text)
self.HpTextGenerator.clearShadow()
self.HpTextGenerator.setAlign(TextNode.ACenter)
r = a = 1.0
g = b = 0.0
self.HpTextGenerator.setTextColor(r, g, b, a)
self.hpTextNode = self.HpTextGenerator.generate()
self.hpText = self.attachNewNode(self.hpTextNode)
self.hpText.setScale(scale)
self.hpText.setBillboardAxis()
self.hpText.setPos(0, 0, self.height / 2)
seq = Task.sequence(self.hpText.lerpPos(Point3(0, 0, self.height + 1.5), 1.0, blendType='easeOut'), Task.pause(duration), self.hpText.lerpColor(Vec4(r, g, b, a), Vec4(r, g, b, 0), 0.1), Task.Task(self.hideHpTextTask))
taskMgr.add(seq, self.uniqueName('hpText'))
def hideHpTextTask(self, task):
self.hideHpText()
return Task.done
def hideHpText(self):
if self.hpText:
taskMgr.remove(self.uniqueName('hpText'))
self.hpText.removeNode()
self.hpText = None
return
def getStareAtNodeAndOffset(self):
return (self, Point3(0, 0, self.height))
def getAvIdName(self):
return '%s\n%s' % (self.getName(), self.doId)
def __nameTagShowAvId(self, extra = None):
self.setDisplayName(self.getAvIdName())
def __nameTagShowName(self, extra = None):
self.setDisplayName(self.getName())
def askAvOnShard(self, avId):
if base.cr.doId2do.get(avId):
messenger.send('AvOnShard%s' % avId, [True])
else:
self.sendUpdate('checkAvOnShard', [avId])
def confirmAvOnShard(self, avId, onShard = True):
messenger.send('AvOnShard%s' % avId, [onShard])
def getDialogueArray(self):
return None

View file

@ -0,0 +1,101 @@
from otp.ai.AIBaseGlobal import *
from otp.otpbase import OTPGlobals
from direct.fsm import ClassicFSM
from direct.fsm import State
from direct.distributed import DistributedNodeAI
from direct.task import Task
class DistributedAvatarAI(DistributedNodeAI.DistributedNodeAI):
def __init__(self, air):
DistributedNodeAI.DistributedNodeAI.__init__(self, air)
self.hp = 0
self.maxHp = 0
def b_setName(self, name):
self.setName(name)
self.d_setName(name)
def d_setName(self, name):
self.sendUpdate('setName', [name])
def setName(self, name):
self.name = name
def getName(self):
return self.name
def b_setMaxHp(self, maxHp):
self.d_setMaxHp(maxHp)
self.setMaxHp(maxHp)
def d_setMaxHp(self, maxHp):
self.sendUpdate('setMaxHp', [maxHp])
def setMaxHp(self, maxHp):
self.maxHp = maxHp
def getMaxHp(self):
return self.maxHp
def b_setHp(self, hp):
self.d_setHp(hp)
self.setHp(hp)
def d_setHp(self, hp):
self.sendUpdate('setHp', [hp])
def setHp(self, hp):
self.hp = hp
def getHp(self):
return self.hp
def b_setLocationName(self, locationName):
self.d_setLocationName(locationName)
self.setLocationName(locationName)
def d_setLocationName(self, locationName):
pass
def setLocationName(self, locationName):
self.locationName = locationName
def getLocationName(self):
return self.locationName
def b_setActivity(self, activity):
self.d_setActivity(activity)
self.setActivity(activity)
def d_setActivity(self, activity):
pass
def setActivity(self, activity):
self.activity = activity
def getActivity(self):
return self.activity
def toonUp(self, num):
if self.hp >= self.maxHp:
return
self.hp = min(self.hp + num, self.maxHp)
self.b_setHp(self.hp)
def getRadius(self):
return OTPGlobals.AvatarDefaultRadius
def checkAvOnShard(self, avId):
senderId = self.air.getAvatarIdFromSender()
onShard = False
if simbase.air.doId2do.get(avId):
onShard = True
self.sendUpdateToAvatarId(senderId, 'confirmAvOnShard', [avId, onShard])
def setParentStr(self, parentToken):
if parentToken:
senderId = self.air.getAvatarIdFromSender()
self.air.writeServerEvent('Admin chat warning', senderId, 'using setParentStr to send "%s"' % parentToken)
self.notify.warning('Admin chat warning: %s using setParentStr to send "%s"' % (senderId, parentToken))
DistributedNodeAI.DistributedNodeAI.setParentStr(self, parentToken)

View file

@ -0,0 +1,455 @@
from pandac.PandaModules import *
from libotp import WhisperPopup
from libotp import CFQuicktalker, CFPageButton, CFQuitButton, CFSpeech, CFThought, CFTimeout
from otp.chat import ChatGarbler
import string
from direct.task import Task
from otp.otpbase import OTPLocalizer
from otp.speedchat import SCDecoders
from direct.showbase import PythonUtil
from otp.avatar import DistributedAvatar
import time
from otp.avatar import Avatar, PlayerBase
from otp.chat import TalkAssistant
from otp.otpbase import OTPGlobals
from otp.avatar.Avatar import teleportNotify
from otp.distributed.TelemetryLimited import TelemetryLimited
if base.config.GetBool('want-chatfilter-hacks', 0):
from otp.switchboard import badwordpy
import os
badwordpy.init(os.environ.get('OTP') + '\\src\\switchboard\\', '')
class DistributedPlayer(DistributedAvatar.DistributedAvatar, PlayerBase.PlayerBase, TelemetryLimited):
TeleportFailureTimeout = 60.0
chatGarbler = ChatGarbler.ChatGarbler()
def __init__(self, cr):
try:
self.DistributedPlayer_initialized
except:
self.DistributedPlayer_initialized = 1
DistributedAvatar.DistributedAvatar.__init__(self, cr)
PlayerBase.PlayerBase.__init__(self)
TelemetryLimited.__init__(self)
self.__teleportAvailable = 0
self.inventory = None
self.experience = None
self.friendsList = []
self.oldFriendsList = None
self.timeFriendsListChanged = None
self.ignoreList = []
self.lastFailedTeleportMessage = {}
self._districtWeAreGeneratedOn = None
self.DISLname = ''
self.DISLid = 0
self.autoRun = 0
self.whiteListEnabled = base.config.GetBool('whitelist-chat-enabled', 1)
return
@staticmethod
def GetPlayerGenerateEvent():
return 'DistributedPlayerGenerateEvent'
@staticmethod
def GetPlayerNetworkDeleteEvent():
return 'DistributedPlayerNetworkDeleteEvent'
@staticmethod
def GetPlayerDeleteEvent():
return 'DistributedPlayerDeleteEvent'
def networkDelete(self):
DistributedAvatar.DistributedAvatar.networkDelete(self)
messenger.send(self.GetPlayerNetworkDeleteEvent(), [self])
def disable(self):
DistributedAvatar.DistributedAvatar.disable(self)
messenger.send(self.GetPlayerDeleteEvent(), [self])
def delete(self):
try:
self.DistributedPlayer_deleted
except:
self.DistributedPlayer_deleted = 1
del self.experience
if self.inventory:
self.inventory.unload()
del self.inventory
DistributedAvatar.DistributedAvatar.delete(self)
def generate(self):
DistributedAvatar.DistributedAvatar.generate(self)
def announceGenerate(self):
DistributedAvatar.DistributedAvatar.announceGenerate(self)
messenger.send(self.GetPlayerGenerateEvent(), [self])
def setLocation(self, parentId, zoneId):
DistributedAvatar.DistributedAvatar.setLocation(self, parentId, zoneId)
if not (parentId in (0, None) and zoneId in (0, None)):
if not self.cr._isValidPlayerLocation(parentId, zoneId):
self.cr.disableDoId(self.doId)
self.cr.deleteObject(self.doId)
return None
def isGeneratedOnDistrict(self, districtId = None):
if districtId is None:
return self._districtWeAreGeneratedOn is not None
else:
return self._districtWeAreGeneratedOn == districtId
return
def getArrivedOnDistrictEvent(self, districtId = None):
if districtId is None:
return 'arrivedOnDistrict'
else:
return 'arrivedOnDistrict-%s' % districtId
return
def arrivedOnDistrict(self, districtId):
curFrameTime = globalClock.getFrameTime()
if hasattr(self, 'frameTimeWeArrivedOnDistrict') and curFrameTime == self.frameTimeWeArrivedOnDistrict:
if districtId == 0 and self._districtWeAreGeneratedOn:
self.notify.warning('ignoring arrivedOnDistrict 0, since arrivedOnDistrict %d occured on the same frame' % self._districtWeAreGeneratedOn)
return
self._districtWeAreGeneratedOn = districtId
self.frameTimeWeArrivedOnDistrict = globalClock.getFrameTime()
messenger.send(self.getArrivedOnDistrictEvent(districtId))
messenger.send(self.getArrivedOnDistrictEvent())
def setLeftDistrict(self):
self._districtWeAreGeneratedOn = None
return
def hasParentingRules(self):
if self is localAvatar:
return True
def setAccountName(self, accountName):
self.accountName = accountName
def setSystemMessage(self, aboutId, chatString, whisperType = WhisperPopup.WTSystem):
self.displayWhisper(aboutId, chatString, whisperType)
def displayWhisper(self, fromId, chatString, whisperType):
print 'Whisper type %s from %s: %s' % (whisperType, fromId, chatString)
def displayWhisperPlayer(self, playerId, chatString, whisperType):
print 'WhisperPlayer type %s from %s: %s' % (whisperType, playerId, chatString)
def whisperSCTo(self, msgIndex, sendToId, toPlayer):
if toPlayer:
base.cr.playerFriendsManager.sendSCWhisper(sendToId, msgIndex)
else:
messenger.send('wakeup')
self.sendUpdate('setWhisperSCFrom', [self.doId, msgIndex], sendToId)
def setWhisperSCFrom(self, fromId, msgIndex):
handle = base.cr.identifyAvatar(fromId)
if handle == None:
return
if base.cr.avatarFriendsManager.checkIgnored(fromId):
self.d_setWhisperIgnored(fromId)
return
if fromId in self.ignoreList:
self.d_setWhisperIgnored(fromId)
return
chatString = SCDecoders.decodeSCStaticTextMsg(msgIndex)
if chatString:
self.displayWhisper(fromId, chatString, WhisperPopup.WTQuickTalker)
base.talkAssistant.receiveAvatarWhisperSpeedChat(TalkAssistant.SPEEDCHAT_NORMAL, msgIndex, fromId)
return
def whisperSCCustomTo(self, msgIndex, sendToId, toPlayer):
if toPlayer:
base.cr.playerFriendsManager.sendSCCustomWhisper(sendToId, msgIndex)
return
messenger.send('wakeup')
self.sendUpdate('setWhisperSCCustomFrom', [self.doId, msgIndex], sendToId)
def _isValidWhisperSource(self, source):
return True
def setWhisperSCCustomFrom(self, fromId, msgIndex):
handle = base.cr.identifyAvatar(fromId)
if handle == None:
return
if not self._isValidWhisperSource(handle):
self.notify.warning('displayWhisper from non-toon %s' % fromId)
return
if base.cr.avatarFriendsManager.checkIgnored(fromId):
self.d_setWhisperIgnored(fromId)
return
if fromId in self.ignoreList:
self.d_setWhisperIgnored(fromId)
return
chatString = SCDecoders.decodeSCCustomMsg(msgIndex)
if chatString:
self.displayWhisper(fromId, chatString, WhisperPopup.WTQuickTalker)
base.talkAssistant.receiveAvatarWhisperSpeedChat(TalkAssistant.SPEEDCHAT_CUSTOM, msgIndex, fromId)
return
def whisperSCEmoteTo(self, emoteId, sendToId, toPlayer):
print 'whisperSCEmoteTo %s %s %s' % (emoteId, sendToId, toPlayer)
if toPlayer:
base.cr.playerFriendsManager.sendSCEmoteWhisper(sendToId, emoteId)
return
messenger.send('wakeup')
self.sendUpdate('setWhisperSCEmoteFrom', [self.doId, emoteId], sendToId)
def setWhisperSCEmoteFrom(self, fromId, emoteId):
handle = base.cr.identifyAvatar(fromId)
if handle == None:
return
if base.cr.avatarFriendsManager.checkIgnored(fromId):
self.d_setWhisperIgnored(fromId)
return
chatString = SCDecoders.decodeSCEmoteWhisperMsg(emoteId, handle.getName())
if chatString:
self.displayWhisper(fromId, chatString, WhisperPopup.WTEmote)
base.talkAssistant.receiveAvatarWhisperSpeedChat(TalkAssistant.SPEEDCHAT_EMOTE, emoteId, fromId)
return
def d_setWhisperIgnored(self, sendToId):
pass
def setChatAbsolute(self, chatString, chatFlags, dialogue = None, interrupt = 1, quiet = 0):
DistributedAvatar.DistributedAvatar.setChatAbsolute(self, chatString, chatFlags, dialogue, interrupt)
if not quiet:
pass
def b_setChat(self, chatString, chatFlags):
if self.cr.wantMagicWords and len(chatString) > 0 and chatString[0] == '~':
messenger.send('magicWord', [chatString])
else:
if base.config.GetBool('want-chatfilter-hacks', 0):
if base.config.GetBool('want-chatfilter-drop-offending', 0):
if badwordpy.test(chatString):
return
else:
chatString = badwordpy.scrub(chatString)
messenger.send('wakeup')
self.setChatAbsolute(chatString, chatFlags)
self.d_setChat(chatString, chatFlags)
def d_setChat(self, chatString, chatFlags):
self.sendUpdate('setChat', [chatString, chatFlags, 0])
def setTalk(self, fromAV, fromAC, avatarName, chat, mods, flags):
newText, scrubbed = self.scrubTalk(chat, mods)
self.displayTalk(newText)
if base.talkAssistant.isThought(newText):
newText = base.talkAssistant.removeThoughtPrefix(newText)
base.talkAssistant.receiveThought(fromAV, avatarName, fromAC, None, newText, scrubbed)
else:
base.talkAssistant.receiveOpenTalk(fromAV, avatarName, fromAC, None, newText, scrubbed)
return
def setTalkWhisper(self, fromAV, fromAC, avatarName, chat, mods, flags):
newText, scrubbed = self.scrubTalk(chat, mods)
self.displayTalkWhisper(fromAV, avatarName, chat, mods)
base.talkAssistant.receiveWhisperTalk(fromAV, avatarName, fromAC, None, self.doId, self.getName(), newText, scrubbed)
return
def displayTalkWhisper(self, fromId, avatarName, chatString, mods):
print 'TalkWhisper from %s: %s' % (fromId, chatString)
def scrubTalk(self, chat, mods):
return chat
def setChat(self, chatString, chatFlags, DISLid):
self.notify.error('Should call setTalk')
chatString = base.talkAssistant.whiteListFilterMessage(chatString)
if base.cr.avatarFriendsManager.checkIgnored(self.doId):
return
if base.localAvatar.garbleChat and not self.isUnderstandable():
chatString = self.chatGarbler.garble(self, chatString)
chatFlags &= ~(CFQuicktalker | CFPageButton | CFQuitButton)
if chatFlags & CFThought:
chatFlags &= ~(CFSpeech | CFTimeout)
else:
chatFlags |= CFSpeech | CFTimeout
self.setChatAbsolute(chatString, chatFlags)
def b_setSC(self, msgIndex):
self.setSC(msgIndex)
self.d_setSC(msgIndex)
def d_setSC(self, msgIndex):
messenger.send('wakeup')
self.sendUpdate('setSC', [msgIndex])
def setSC(self, msgIndex):
if base.cr.avatarFriendsManager.checkIgnored(self.doId):
return
if self.doId in base.localAvatar.ignoreList:
return
chatString = SCDecoders.decodeSCStaticTextMsg(msgIndex)
if chatString:
self.setChatAbsolute(chatString, CFSpeech | CFQuicktalker | CFTimeout, quiet=1)
base.talkAssistant.receiveOpenSpeedChat(TalkAssistant.SPEEDCHAT_NORMAL, msgIndex, self.doId)
def b_setSCCustom(self, msgIndex):
self.setSCCustom(msgIndex)
self.d_setSCCustom(msgIndex)
def d_setSCCustom(self, msgIndex):
messenger.send('wakeup')
self.sendUpdate('setSCCustom', [msgIndex])
def setSCCustom(self, msgIndex):
if base.cr.avatarFriendsManager.checkIgnored(self.doId):
return
if self.doId in base.localAvatar.ignoreList:
return
chatString = SCDecoders.decodeSCCustomMsg(msgIndex)
if chatString:
self.setChatAbsolute(chatString, CFSpeech | CFQuicktalker | CFTimeout)
base.talkAssistant.receiveOpenSpeedChat(TalkAssistant.SPEEDCHAT_CUSTOM, msgIndex, self.doId)
def b_setSCEmote(self, emoteId):
self.b_setEmoteState(emoteId, animMultiplier=self.animMultiplier)
def d_friendsNotify(self, avId, status):
self.sendUpdate('friendsNotify', [avId, status])
def friendsNotify(self, avId, status):
avatar = base.cr.identifyFriend(avId)
if avatar != None:
if status == 1:
self.setSystemMessage(avId, OTPLocalizer.WhisperNoLongerFriend % avatar.getName())
elif status == 2:
self.setSystemMessage(avId, OTPLocalizer.WhisperNowSpecialFriend % avatar.getName())
return
def d_teleportQuery(self, requesterId, sendToId = None):
teleportNotify.debug('sending teleportQuery%s' % ((requesterId, sendToId),))
self.sendUpdate('teleportQuery', [requesterId], sendToId)
def teleportQuery(self, requesterId):
teleportNotify.debug('receieved teleportQuery(%s)' % requesterId)
avatar = base.cr.playerFriendsManager.identifyFriend(requesterId)
if avatar != None:
teleportNotify.debug('avatar is not None')
if base.cr.avatarFriendsManager.checkIgnored(requesterId):
teleportNotify.debug('avatar ignored via avatarFriendsManager')
self.d_teleportResponse(self.doId, 2, 0, 0, 0, sendToId=requesterId)
return
if requesterId in self.ignoreList:
teleportNotify.debug('avatar ignored via ignoreList')
self.d_teleportResponse(self.doId, 2, 0, 0, 0, sendToId=requesterId)
return
if hasattr(base, 'distributedParty'):
if base.distributedParty.partyInfo.isPrivate:
if requesterId not in base.distributedParty.inviteeIds:
teleportNotify.debug('avatar not in inviteeIds')
self.d_teleportResponse(self.doId, 0, 0, 0, 0, sendToId=requesterId)
return
if base.distributedParty.isPartyEnding:
teleportNotify.debug('party is ending')
self.d_teleportResponse(self.doId, 0, 0, 0, 0, sendToId=requesterId)
return
if self.__teleportAvailable and not self.ghostMode and base.config.GetBool('can-be-teleported-to', 1):
teleportNotify.debug('teleport initiation successful')
self.setSystemMessage(requesterId, OTPLocalizer.WhisperComingToVisit % avatar.getName())
messenger.send('teleportQuery', [avatar, self])
return
teleportNotify.debug('teleport initiation failed')
if self.failedTeleportMessageOk(requesterId):
self.setSystemMessage(requesterId, OTPLocalizer.WhisperFailedVisit % avatar.getName())
teleportNotify.debug('sending try-again-later message')
self.d_teleportResponse(self.doId, 0, 0, 0, 0, sendToId=requesterId)
return
def failedTeleportMessageOk(self, fromId):
now = globalClock.getFrameTime()
lastTime = self.lastFailedTeleportMessage.get(fromId, None)
if lastTime != None:
elapsed = now - lastTime
if elapsed < self.TeleportFailureTimeout:
return 0
self.lastFailedTeleportMessage[fromId] = now
return 1
def d_teleportResponse(self, avId, available, shardId, hoodId, zoneId, sendToId = None):
teleportNotify.debug('sending teleportResponse%s' % ((avId,
available,
shardId,
hoodId,
zoneId,
sendToId),))
self.sendUpdate('teleportResponse', [avId,
available,
shardId,
hoodId,
zoneId], sendToId)
def teleportResponse(self, avId, available, shardId, hoodId, zoneId):
teleportNotify.debug('received teleportResponse%s' % ((avId,
available,
shardId,
hoodId,
zoneId),))
messenger.send('teleportResponse', [avId,
available,
shardId,
hoodId,
zoneId])
def d_teleportGiveup(self, requesterId, sendToId = None):
teleportNotify.debug('sending teleportGiveup(%s) to %s' % (requesterId, sendToId))
self.sendUpdate('teleportGiveup', [requesterId], sendToId)
def teleportGiveup(self, requesterId):
teleportNotify.debug('received teleportGiveup(%s)' % (requesterId,))
avatar = base.cr.identifyAvatar(requesterId)
if not self._isValidWhisperSource(avatar):
self.notify.warning('teleportGiveup from non-toon %s' % requesterId)
return
if avatar != None:
self.setSystemMessage(requesterId, OTPLocalizer.WhisperGiveupVisit % avatar.getName())
return
def b_teleportGreeting(self, avId):
self.d_teleportGreeting(avId)
self.teleportGreeting(avId)
def d_teleportGreeting(self, avId):
self.sendUpdate('teleportGreeting', [avId])
def teleportGreeting(self, avId):
avatar = base.cr.getDo(avId)
if isinstance(avatar, Avatar.Avatar):
self.setChatAbsolute(OTPLocalizer.TeleportGreeting % avatar.getName(), CFSpeech | CFTimeout)
elif avatar is not None:
self.notify.warning('got teleportGreeting from %s referencing non-toon %s' % (self.doId, avId))
return
def setTeleportAvailable(self, available):
self.__teleportAvailable = available
def getTeleportAvailable(self):
return self.__teleportAvailable
def getFriendsList(self):
return self.friendsList
def setFriendsList(self, friendsList):
self.oldFriendsList = self.friendsList
self.friendsList = friendsList
self.timeFriendsListChanged = globalClock.getFrameTime()
messenger.send('friendsListChanged')
Avatar.reconsiderAllUnderstandable()
def setDISLname(self, name):
self.DISLname = name
def setDISLid(self, id):
self.DISLid = id
def setAutoRun(self, value):
self.autoRun = value
def getAutoRun(self):
return self.autoRun

View file

@ -0,0 +1,129 @@
from direct.showbase import GarbageReport
from otp.ai.AIBaseGlobal import *
from otp.avatar import DistributedAvatarAI
from otp.avatar import PlayerBase
from otp.distributed.ClsendTracker import ClsendTracker
from otp.otpbase import OTPGlobals
class DistributedPlayerAI(DistributedAvatarAI.DistributedAvatarAI, PlayerBase.PlayerBase, ClsendTracker):
def __init__(self, air):
DistributedAvatarAI.DistributedAvatarAI.__init__(self, air)
PlayerBase.PlayerBase.__init__(self)
ClsendTracker.__init__(self)
self.friendsList = []
self.DISLname = ''
self.DISLid = 0
if __dev__:
def generate(self):
self._sentExitServerEvent = False
DistributedAvatarAI.DistributedAvatarAI.generate(self)
def announceGenerate(self):
DistributedAvatarAI.DistributedAvatarAI.announceGenerate(self)
ClsendTracker.announceGenerate(self)
self._doPlayerEnter()
def _announceArrival(self):
self.sendUpdate('arrivedOnDistrict', [self.air.districtId])
def _announceExit(self):
self.sendUpdate('arrivedOnDistrict', [0])
def _sendExitServerEvent(self):
self.air.writeServerEvent('avatarExit', self.doId, '')
if __dev__:
self._sentExitServerEvent = True
def delete(self):
if __dev__:
del self._sentExitServerEvent
self._doPlayerExit()
ClsendTracker.destroy(self)
if __dev__:
GarbageReport.checkForGarbageLeaks()
DistributedAvatarAI.DistributedAvatarAI.delete(self)
def isPlayerControlled(self):
return True
def setLocation(self, parentId, zoneId):
DistributedAvatarAI.DistributedAvatarAI.setLocation(self, parentId, zoneId)
if self.isPlayerControlled():
if not self.air._isValidPlayerLocation(parentId, zoneId):
self.notify.info('booting player %s for doing setLocation to (%s, %s)' % (self.doId, parentId, zoneId))
self.air.writeServerEvent('suspicious', self.doId, 'invalid setLocation: (%s, %s)' % (parentId, zoneId))
self.requestDelete()
def _doPlayerEnter(self):
self.incrementPopulation()
self._announceArrival()
def _doPlayerExit(self):
self._announceExit()
self.decrementPopulation()
def incrementPopulation(self):
self.air.incrementPopulation()
def decrementPopulation(self):
simbase.air.decrementPopulation()
def b_setChat(self, chatString, chatFlags):
self.setChat(chatString, chatFlags)
self.d_setChat(chatString, chatFlags)
def d_setChat(self, chatString, chatFlags):
self.sendUpdate('setChat', [chatString, chatFlags])
def setChat(self, chatString, chatFlags):
pass
def d_setMaxHp(self, maxHp):
DistributedAvatarAI.DistributedAvatarAI.d_setMaxHp(self, maxHp)
self.air.writeServerEvent('setMaxHp', self.doId, '%s' % maxHp)
def d_setSystemMessage(self, aboutId, chatString):
self.sendUpdate('setSystemMessage', [aboutId, chatString])
def d_setCommonChatFlags(self, flags):
self.sendUpdate('setCommonChatFlags', [flags])
def setCommonChatFlags(self, flags):
pass
def d_friendsNotify(self, avId, status):
self.sendUpdate('friendsNotify', [avId, status])
def friendsNotify(self, avId, status):
pass
def setAccountName(self, accountName):
self.accountName = accountName
def getAccountName(self):
return self.accountName
def setDISLid(self, id):
self.DISLid = id
def d_setFriendsList(self, friendsList):
self.sendUpdate('setFriendsList', [friendsList])
def setFriendsList(self, friendsList):
self.friendsList = friendsList
self.notify.debug('setting friends list to %s' % self.friendsList)
def getFriendsList(self):
return self.friendsList
def extendFriendsList(self, friendId, friendCode):
for i in range(len(self.friendsList)):
friendPair = self.friendsList[i]
if friendPair[0] == friendId:
self.friendsList[i] = (friendId, friendCode)
return
self.friendsList.append((friendId, friendCode))

22
otp/avatar/Emote.py Normal file
View file

@ -0,0 +1,22 @@
from otp.otpbase import OTPLocalizer
import types
class Emote:
EmoteClear = -1
EmoteEnableStateChanged = 'EmoteEnableStateChanged'
def __init__(self):
self.emoteFunc = None
return
def isEnabled(self, index):
if isinstance(index, types.StringType):
index = OTPLocalizer.EmoteFuncDict[index]
if self.emoteFunc == None:
return 0
elif self.emoteFunc[index][1] == 0:
return 1
return 0
globalEmote = None

1215
otp/avatar/LocalAvatar.py Normal file

File diff suppressed because it is too large Load diff

18
otp/avatar/PlayerBase.py Normal file
View file

@ -0,0 +1,18 @@
class PlayerBase:
def __init__(self):
self.gmState = False
def atLocation(self, locationId):
return True
def getLocation(self):
return []
def setAsGM(self, state):
self.gmState = state
def isGM(self):
return self.gmState

View file

@ -0,0 +1,94 @@
from pandac.PandaModules import *
from direct.showbase.DirectObject import DirectObject
from otp.otpbase import OTPGlobals
class PositionExaminer(DirectObject, NodePath):
def __init__(self):
try:
self.__initialized
return
except:
self.__initialized = 1
NodePath.__init__(self, hidden.attachNewNode('PositionExaminer'))
self.cRay = CollisionRay(0.0, 0.0, 6.0, 0.0, 0.0, -1.0)
self.cRayNode = CollisionNode('cRayNode')
self.cRayNode.addSolid(self.cRay)
self.cRayNodePath = self.attachNewNode(self.cRayNode)
self.cRayNodePath.hide()
self.cRayBitMask = OTPGlobals.FloorBitmask
self.cRayNode.setFromCollideMask(self.cRayBitMask)
self.cRayNode.setIntoCollideMask(BitMask32.allOff())
self.cSphere = CollisionSphere(0.0, 0.0, 0.0, 1.5)
self.cSphereNode = CollisionNode('cSphereNode')
self.cSphereNode.addSolid(self.cSphere)
self.cSphereNodePath = self.attachNewNode(self.cSphereNode)
self.cSphereNodePath.hide()
self.cSphereBitMask = OTPGlobals.WallBitmask
self.cSphereNode.setFromCollideMask(self.cSphereBitMask)
self.cSphereNode.setIntoCollideMask(BitMask32.allOff())
self.ccLine = CollisionSegment(0.0, 0.0, 0.0, 1.0, 0.0, 0.0)
self.ccLineNode = CollisionNode('ccLineNode')
self.ccLineNode.addSolid(self.ccLine)
self.ccLineNodePath = self.attachNewNode(self.ccLineNode)
self.ccLineNodePath.hide()
self.ccLineBitMask = OTPGlobals.CameraBitmask
self.ccLineNode.setFromCollideMask(self.ccLineBitMask)
self.ccLineNode.setIntoCollideMask(BitMask32.allOff())
self.cRayTrav = CollisionTraverser('PositionExaminer.cRayTrav')
self.cRayTrav.setRespectPrevTransform(False)
self.cRayQueue = CollisionHandlerQueue()
self.cRayTrav.addCollider(self.cRayNodePath, self.cRayQueue)
self.cSphereTrav = CollisionTraverser('PositionExaminer.cSphereTrav')
self.cSphereTrav.setRespectPrevTransform(False)
self.cSphereQueue = CollisionHandlerQueue()
self.cSphereTrav.addCollider(self.cSphereNodePath, self.cSphereQueue)
self.ccLineTrav = CollisionTraverser('PositionExaminer.ccLineTrav')
self.ccLineTrav.setRespectPrevTransform(False)
self.ccLineQueue = CollisionHandlerQueue()
self.ccLineTrav.addCollider(self.ccLineNodePath, self.ccLineQueue)
def delete(self):
del self.cRay
del self.cRayNode
self.cRayNodePath.removeNode()
del self.cRayNodePath
del self.cSphere
del self.cSphereNode
self.cSphereNodePath.removeNode()
del self.cSphereNodePath
del self.ccLine
del self.ccLineNode
self.ccLineNodePath.removeNode()
del self.ccLineNodePath
del self.cRayTrav
del self.cRayQueue
del self.cSphereTrav
del self.cSphereQueue
del self.ccLineTrav
del self.ccLineQueue
def consider(self, node, pos, eyeHeight):
self.reparentTo(node)
self.setPos(pos)
result = None
self.cRayTrav.traverse(render)
if self.cRayQueue.getNumEntries() != 0:
self.cRayQueue.sortEntries()
floorPoint = self.cRayQueue.getEntry(0).getSurfacePoint(self.cRayNodePath)
if abs(floorPoint[2]) <= 4.0:
pos += floorPoint
self.setPos(pos)
self.cSphereTrav.traverse(render)
if self.cSphereQueue.getNumEntries() == 0:
self.ccLine.setPointA(0, 0, eyeHeight)
self.ccLine.setPointB(-pos[0], -pos[1], eyeHeight)
self.ccLineTrav.traverse(render)
if self.ccLineQueue.getNumEntries() == 0:
result = pos
self.reparentTo(hidden)
self.cRayQueue.clearEntries()
self.cSphereQueue.clearEntries()
self.ccLineQueue.clearEntries()
return result

134
otp/avatar/ShadowCaster.py Normal file
View file

@ -0,0 +1,134 @@
from pandac.PandaModules import *
from pandac.PandaModules import *
from direct.directnotify import DirectNotifyGlobal
from direct.showbase.ShadowPlacer import ShadowPlacer
from otp.otpbase import OTPGlobals
globalDropShadowFlag = 1
def setGlobalDropShadowFlag(flag):
global globalDropShadowFlag
if flag != globalDropShadowFlag:
globalDropShadowFlag = flag
messenger.send('globalDropShadowFlagChanged')
globalDropShadowGrayLevel = 0.5
def setGlobalDropShadowGrayLevel(grayLevel):
global globalDropShadowGrayLevel
if grayLevel != globalDropShadowGrayLevel:
globalDropShadowGrayLevel = grayLevel
messenger.send('globalDropShadowGrayLevelChanged')
class ShadowCaster:
notify = DirectNotifyGlobal.directNotify.newCategory('ShadowCaster')
def __init__(self, squareShadow = False):
if squareShadow:
self.shadowFileName = 'phase_3/models/props/square_drop_shadow'
else:
self.shadowFileName = 'phase_3/models/props/drop_shadow'
self.dropShadow = None
self.shadowPlacer = None
self.activeShadow = 0
self.wantsActive = 1
self.storedActiveState = 0
if hasattr(base, 'wantDynamicShadows') and base.wantDynamicShadows:
messenger.accept('globalDropShadowFlagChanged', self, self.__globalDropShadowFlagChanged)
messenger.accept('globalDropShadowGrayLevelChanged', self, self.__globalDropShadowGrayLevelChanged)
return
def delete(self):
if hasattr(base, 'wantDynamicShadows') and base.wantDynamicShadows:
messenger.ignore('globalDropShadowFlagChanged', self)
messenger.ignore('globalDropShadowGrayLevelChanged', self)
self.deleteDropShadow()
self.shadowJoint = None
return
def initializeDropShadow(self, hasGeomNode = True):
self.deleteDropShadow()
if hasGeomNode:
self.getGeomNode().setTag('cam', 'caster')
dropShadow = loader.loadModel(self.shadowFileName)
dropShadow.setScale(0.4)
dropShadow.flattenMedium()
dropShadow.setBillboardAxis(2)
dropShadow.setColor(0.0, 0.0, 0.0, globalDropShadowGrayLevel, 1)
self.shadowPlacer = ShadowPlacer(base.shadowTrav, dropShadow, OTPGlobals.WallBitmask, OTPGlobals.FloorBitmask)
self.dropShadow = dropShadow
if not globalDropShadowFlag:
self.dropShadow.hide()
if self.getShadowJoint():
dropShadow.reparentTo(self.getShadowJoint())
else:
self.dropShadow.hide()
self.setActiveShadow(self.wantsActive)
self.__globalDropShadowFlagChanged()
self.__globalDropShadowGrayLevelChanged()
def update(self):
pass
def deleteDropShadow(self):
if self.shadowPlacer:
self.shadowPlacer.delete()
self.shadowPlacer = None
if self.dropShadow:
self.dropShadow.removeNode()
self.dropShadow = None
return
def setActiveShadow(self, isActive = 1):
isActive = isActive and self.wantsActive
if not globalDropShadowFlag:
self.storedActiveState = isActive
if self.shadowPlacer != None:
isActive = isActive and globalDropShadowFlag
if self.activeShadow != isActive:
self.activeShadow = isActive
if isActive:
self.shadowPlacer.on()
else:
self.shadowPlacer.off()
return
def setShadowHeight(self, shadowHeight):
if self.dropShadow:
self.dropShadow.setZ(-shadowHeight)
def getShadowJoint(self):
if hasattr(self, 'shadowJoint'):
return self.shadowJoint
shadowJoint = self.find('**/attachShadow')
if shadowJoint.isEmpty():
self.shadowJoint = NodePath(self)
else:
self.shadowJoint = shadowJoint
return self.shadowJoint
def hideShadow(self):
self.dropShadow.hide()
def showShadow(self):
if not globalDropShadowFlag:
self.dropShadow.hide()
else:
self.dropShadow.show()
def __globalDropShadowFlagChanged(self):
if self.dropShadow != None:
if globalDropShadowFlag == 0:
if self.activeShadow == 1:
self.storedActiveState = 1
self.setActiveShadow(0)
elif self.activeShadow == 0:
self.setActiveShadow(1)
self.showShadow()
return
def __globalDropShadowGrayLevelChanged(self):
if self.dropShadow != None:
self.dropShadow.setColor(0.0, 0.0, 0.0, globalDropShadowGrayLevel, 1)
return

View file

@ -0,0 +1,91 @@
from direct.showbase.PythonUtil import SerialNumGen
from direct.task import Task
class SpeedMonitor:
notify = directNotify.newCategory('SpeedMonitor')
SerialGen = SerialNumGen()
TrackingPeriod = 30.0
def __init__(self, name):
self._name = name
self._nodepaths = {}
self._maxSpeeds = {}
self._prevPosQueue = {}
self._speedLimits = {}
self._trackTask = taskMgr.add(self._trackSpeedsTask, 'speedMonitorTask-%s-%s' % (self._name, id(self)))
def destroy(self):
taskMgr.remove(self._trackTask)
def _allocToken(self):
return 'speedMonitorToken-%s-%s-%s' % (self._name, id(self), SpeedMonitor.SerialGen.next())
def addNodepath(self, nodepath):
token = self._allocToken()
self._nodepaths[token] = nodepath
self.resetMaxSpeed(token)
return token
def setSpeedLimit(self, token, limit, callback):
self._speedLimits[token] = (limit, callback)
def removeNodepath(self, token):
del self._nodepaths[token]
del self._maxSpeeds[token]
del self._prevPosQueue[token]
if token in self._speedLimits:
self._speedLimits.pop(token)
def getMaxSpeed(self, token):
return self._maxSpeeds[token]
def resetMaxSpeed(self, token):
self._maxSpeeds[token] = 0.0
nodepath = self._nodepaths[token]
self._prevPosQueue[token] = [
(nodepath.getPos(), globalClock.getFrameTime() - SpeedMonitor.TrackingPeriod, 0.0)]
def _trackSpeedsTask(self, task = None):
for (token, nodepath) in self._nodepaths.iteritems():
curT = globalClock.getFrameTime()
curPos = nodepath.getPos()
while len(self._prevPosQueue[token]) > 1:
(oldestPos, oldestT, oldestDistance) = self._prevPosQueue[token][1]
if curT - oldestT > SpeedMonitor.TrackingPeriod:
self._prevPosQueue[token] = self._prevPosQueue[token][1:]
else:
break
storeCurPos = False
if len(self._prevPosQueue[token]) == 0:
storeCurPos = True
curDistance = 0.0
else:
(prevPos, prevT, prevDistance) = self._prevPosQueue[token][-1]
if curPos != prevPos:
storeCurPos = True
curDistance = (curPos - prevPos).length()
if storeCurPos:
self._prevPosQueue[token].append((curPos, curT, curDistance))
if len(self._prevPosQueue[token]) > 1:
(oldestPos, oldestT, oldestDistance) = self._prevPosQueue[token][0]
(newestPos, newestT, newestDistance) = self._prevPosQueue[token][-1]
tDelta = newestT - oldestT
if tDelta >= SpeedMonitor.TrackingPeriod:
totalDistance = 0.0
for (pos, t, distance) in self._prevPosQueue[token][1:]:
totalDistance += distance
speed = totalDistance / tDelta
if speed > self._maxSpeeds[token]:
if self.notify.getDebug():
self.notify.debug('new max speed(%s): %s' % (nodepath, speed))
self._maxSpeeds[token] = speed
(limit, callback) = self._speedLimits[token]
if speed > limit:
self.notify.warning('%s over speed limit (%s, cur speed=%s)' % (nodepath, limit, speed))
callback(speed)
return Task.cont

0
otp/avatar/__init__.py Normal file
View file

29
otp/chat/ChatGarbler.py Normal file
View file

@ -0,0 +1,29 @@
import string
import random
from otp.otpbase import OTPLocalizer
class ChatGarbler:
def garble(self, avatar, message):
newMessage = ''
numWords = random.randint(1, 7)
wordlist = OTPLocalizer.ChatGarblerDefault
for i in range(1, numWords + 1):
wordIndex = random.randint(0, len(wordlist) - 1)
newMessage = newMessage + wordlist[wordIndex]
if i < numWords:
newMessage = newMessage + ' '
return newMessage
def garbleSingle(self, avatar, message):
newMessage = ''
numWords = 1
wordlist = OTPLocalizer.ChatGarblerDefault
for i in range(1, numWords + 1):
wordIndex = random.randint(0, len(wordlist) - 1)
newMessage = newMessage + wordlist[wordIndex]
if i < numWords:
newMessage = newMessage + ' '
return newMessage

53
otp/chat/ChatGlobals.py Normal file
View file

@ -0,0 +1,53 @@
import string
NORMAL_CHAT = 1
WHISPER_CHAT = 2
GUILD_CHAT = 3
CREW_CHAT = 4
SHIPPVP_CHAT = 5
ERROR_NONE = None
ERROR_NO_OPEN_CHAT = 1
ERROR_NOT_FRIENDS = 2
ERROR_NO_RECEIVER = 3
ERROR_NO_GUILD_CHAT = 4
ERROR_NO_CREW_CHAT = 5
ERROR_NO_SHIPPVP_CHAT = 6
TYPEDCHAT = 0
SPEEDCHAT_NORMAL = 1
SPEEDCHAT_EMOTE = 2
SPEEDCHAT_CUSTOM = 3
SYSTEMCHAT = 4
GAMECHAT = 5
GUILDCHAT = 6
PARTYCHAT = 7
SPEEDCHAT_QUEST = 8
FRIEND_UPDATE = 9
CREW_UPDATE = 10
GUILD_UPDATE = 11
AVATAR_UNAVAILABLE = 12
SHIPPVPCHAT = 13
GMCHAT = 14
ChatEvent = 'ChatEvent'
NormalChatEvent = 'NormalChatEvent'
SCChatEvent = 'SCChatEvent'
SCCustomChatEvent = 'SCCustomChatEvent'
SCEmoteChatEvent = 'SCEmoteChatEvent'
SCQuestEvent = 'SCQuestEvent'
OnScreen = 0
OffScreen = 1
Thought = 2
ThoughtPrefix = '.'
def isThought(message):
if len(message) == 0:
return 0
elif string.find(message, ThoughtPrefix, 0, len(ThoughtPrefix)) >= 0:
return 1
else:
return 0
def removeThoughtPrefix(message):
if isThought(message):
return message[len(ThoughtPrefix):]
else:
return message

161
otp/chat/ChatInputNormal.py Normal file
View file

@ -0,0 +1,161 @@
from direct.showbase import DirectObject
from otp.otpbase import OTPGlobals
import sys
from direct.gui.DirectGui import *
from pandac.PandaModules import *
from otp.otpbase import OTPLocalizer
class ChatInputNormal(DirectObject.DirectObject):
ExecNamespace = None
def __init__(self, chatMgr):
self.chatMgr = chatMgr
self.normalPos = Vec3(-1.083, 0, 0.804)
self.whisperPos = Vec3(0.0, 0, 0.71)
self.whisperAvatarName = None
self.whisperAvatarId = None
self.toPlayer = 0
wantHistory = 0
if __dev__:
wantHistory = 1
self.wantHistory = base.config.GetBool('want-chat-history', wantHistory)
self.history = ['']
self.historySize = base.config.GetInt('chat-history-size', 10)
self.historyIndex = 0
return
def typeCallback(self, extraArgs):
messenger.send('enterNormalChat')
def delete(self):
self.ignore('arrow_up-up')
self.ignore('arrow_down-up')
self.chatFrame.destroy()
del self.chatFrame
del self.chatButton
del self.cancelButton
del self.chatEntry
del self.whisperLabel
del self.chatMgr
def activateByData(self, whisperAvatarId = None, toPlayer = 0):
self.toPlayer = toPlayer
self.whisperAvatarId = whisperAvatarId
self.whisperAvatarName = base.talkAssistant.findName(self.whisperAvatarId, self.toPlayer)
if self.whisperAvatarId:
self.chatFrame.setPos(self.whisperPos)
self.whisperLabel['text'] = OTPLocalizer.ChatInputWhisperLabel % self.whisperAvatarName
self.whisperLabel.show()
else:
self.chatFrame.setPos(self.normalPos)
self.whisperLabel.hide()
self.chatEntry['focus'] = 1
self.chatFrame.show()
if self.wantHistory:
self.accept('arrow_up-up', self.getPrevHistory)
self.accept('arrow_down-up', self.getNextHistory)
def deactivate(self):
self.chatEntry.set('')
self.chatEntry['focus'] = 0
self.chatFrame.hide()
self.whisperLabel.hide()
base.win.closeIme()
self.ignore('arrow_up-up')
self.ignore('arrow_down-up')
def checkForOverRide(self):
return False
def sendChat(self, text):
if self.checkForOverRide():
self.chatEntry.enterText('')
return
self.deactivate()
self.chatMgr.fsm.request('mainMenu')
if text:
if self.toPlayer:
if self.whisperAvatarId:
self.whisperAvatarName = None
self.whisperAvatarId = None
self.toPlayer = 0
elif self.whisperAvatarId:
self.chatMgr.sendWhisperString(text, self.whisperAvatarId)
self.whisperAvatarName = None
self.whisperAvatarId = None
else:
if self.chatMgr.execChat:
if text[0] == '>':
text = self.__execMessage(text[1:])
base.localAvatar.setChatAbsolute(text, CFSpeech | CFTimeout)
return
base.talkAssistant.sendOpenTalk(text)
if self.wantHistory:
self.addToHistory(text)
return
def chatOverflow(self, overflowText):
self.sendChat(self.chatEntry.get())
def __execMessage(self, message):
if not ChatInputNormal.ExecNamespace:
ChatInputNormal.ExecNamespace = {}
exec 'from pandac.PandaModules import *' in globals(), self.ExecNamespace
self.importExecNamespace()
try:
if not isClient():
print 'EXECWARNING ChatInputNormal eval: %s' % message
printStack()
return str(eval(message, globals(), ChatInputNormal.ExecNamespace))
except SyntaxError:
try:
if not isClient():
print 'EXECWARNING ChatInputNormal exec: %s' % message
printStack()
exec message in globals(), ChatInputNormal.ExecNamespace
return 'ok'
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
def cancelButtonPressed(self):
self.chatEntry.set('')
self.chatMgr.fsm.request('mainMenu')
def chatButtonPressed(self):
self.sendChat(self.chatEntry.get())
def importExecNamespace(self):
pass
def addToHistory(self, text):
self.history = [text] + self.history[:self.historySize - 1]
self.historyIndex = 0
def getPrevHistory(self):
self.chatEntry.set(self.history[self.historyIndex])
self.historyIndex += 1
self.historyIndex %= len(self.history)
def getNextHistory(self):
self.chatEntry.set(self.history[self.historyIndex])
self.historyIndex -= 1
self.historyIndex %= len(self.history)
def setPos(self, posX, posY = None, posZ = None):
if posX and posY and posZ:
self.chatFrame.setPos(posX, posY, posZ)
else:
self.chatFrame.setPos(posX)

182
otp/chat/ChatInputTyped.py Normal file
View file

@ -0,0 +1,182 @@
from direct.showbase import DirectObject
from otp.otpbase import OTPGlobals
import sys
from direct.gui.DirectGui import *
from pandac.PandaModules import *
from otp.otpbase import OTPLocalizer
class ChatInputTyped(DirectObject.DirectObject):
ExecNamespace = None
def __init__(self, mainEntry = 0):
self.whisperName = None
self.whisperId = None
self.toPlayer = 0
self.mainEntry = mainEntry
wantHistory = 0
if __dev__:
wantHistory = 1
self.wantHistory = base.config.GetBool('want-chat-history', wantHistory)
self.history = ['']
self.historySize = base.config.GetInt('chat-history-size', 10)
self.historyIndex = 0
return
def typeCallback(self, extraArgs):
self.activate()
def delete(self):
self.ignore('arrow_up-up')
self.ignore('arrow_down-up')
self.chatFrame.destroy()
del self.chatFrame
del self.chatButton
del self.cancelButton
del self.chatEntry
del self.whisperLabel
del self.chatMgr
def show(self, whisperId = None, toPlayer = 0):
self.toPlayer = toPlayer
self.whisperId = whisperId
self.whisperName = None
if self.whisperId:
self.whisperName = base.talkAssistant.findName(whisperId, toPlayer)
if hasattr(self, 'whisperPos'):
self.chatFrame.setPos(self.whisperPos)
self.whisperLabel['text'] = OTPLocalizer.ChatInputWhisperLabel % self.whisperName
self.whisperLabel.show()
else:
if hasattr(self, 'normalPos'):
self.chatFrame.setPos(self.normalPos)
self.whisperLabel.hide()
self.chatEntry['focus'] = 1
self.chatEntry.set('')
self.chatFrame.show()
self.chatEntry.show()
self.cancelButton.show()
self.typedChatButton.hide()
self.typedChatBar.hide()
if self.wantHistory:
self.accept('arrow_up-up', self.getPrevHistory)
self.accept('arrow_down-up', self.getNextHistory)
return
def hide(self):
self.chatEntry.set('')
self.chatEntry['focus'] = 0
self.chatFrame.hide()
self.chatEntry.hide()
self.cancelButton.hide()
self.typedChatButton.show()
self.typedChatBar.show()
self.ignore('arrow_up-up')
self.ignore('arrow_down-up')
def activate(self):
self.chatEntry.set('')
self.chatEntry['focus'] = 1
self.chatFrame.show()
self.chatEntry.show()
self.cancelButton.show()
self.typedChatButton.hide()
self.typedChatBar.hide()
if self.whisperId:
print 'have id'
if self.toPlayer:
if not base.talkAssistant.checkWhisperTypedChatPlayer(self.whisperId):
messenger.send('Chat-Failed player typed chat test')
self.deactivate()
elif not base.talkAssistant.checkWhisperTypedChatAvatar(self.whisperId):
messenger.send('Chat-Failed avatar typed chat test')
self.deactivate()
elif not base.talkAssistant.checkOpenTypedChat():
messenger.send('Chat-Failed open typed chat test')
self.deactivate()
def deactivate(self):
self.chatEntry.set('')
self.chatEntry['focus'] = 0
self.chatFrame.show()
self.chatEntry.hide()
self.cancelButton.hide()
self.typedChatButton.show()
self.typedChatBar.show()
def sendChat(self, text):
self.deactivate()
if text:
if self.toPlayer:
if self.whisperId:
pass
elif self.whisperId:
pass
elif base.config.GetBool('exec-chat', 0) and text[0] == '>':
text = self.__execMessage(text[1:])
base.localAvatar.setChatAbsolute(text, CFSpeech | CFTimeout)
return
else:
base.talkAssistant.sendOpenTalk(text)
if self.wantHistory:
self.addToHistory(text)
self.chatEntry.set('')
def chatOverflow(self, overflowText):
self.sendChat(self.chatEntry.get())
def __execMessage(self, message):
if not ChatInputTyped.ExecNamespace:
ChatInputTyped.ExecNamespace = {}
exec 'from pandac.PandaModules import *' in globals(), self.ExecNamespace
self.importExecNamespace()
try:
if not isClient():
print 'EXECWARNING ChatInputNormal eval: %s' % message
printStack()
return str(eval(message, globals(), ChatInputTyped.ExecNamespace))
except SyntaxError:
try:
if not isClient():
print 'EXECWARNING ChatInputNormal exec: %s' % message
printStack()
exec message in globals(), ChatInputTyped.ExecNamespace
return 'ok'
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
def cancelButtonPressed(self):
self.chatEntry.set('')
self.deactivate()
def chatButtonPressed(self):
self.sendChat(self.chatEntry.get())
def importExecNamespace(self):
pass
def addToHistory(self, text):
self.history = [text] + self.history[:self.historySize - 1]
self.historyIndex = 0
def getPrevHistory(self):
self.chatEntry.set(self.history[self.historyIndex])
self.historyIndex += 1
self.historyIndex %= len(self.history)
def getNextHistory(self):
self.chatEntry.set(self.history[self.historyIndex])
self.historyIndex -= 1
self.historyIndex %= len(self.history)

View file

@ -0,0 +1,345 @@
from direct.fsm import FSM
from otp.otpbase import OTPGlobals
import sys
from direct.directnotify import DirectNotifyGlobal
from direct.gui.DirectGui import *
from pandac.PandaModules import *
from otp.otpbase import OTPLocalizer
from direct.task import Task
from otp.chat.ChatInputTyped import ChatInputTyped
class ChatInputWhiteListFrame(FSM.FSM, DirectFrame):
notify = DirectNotifyGlobal.directNotify.newCategory('ChatInputWhiteList')
ExecNamespace = None
def __init__(self, entryOptions, parent = None, **kw):
FSM.FSM.__init__(self, 'ChatInputWhiteListFrame')
self.okayToSubmit = True
self.receiverId = None
DirectFrame.__init__(self, parent=aspect2dp, pos=(0, 0, 0.3), relief=None, image=DGG.getDefaultDialogGeom(), image_scale=(1.6, 1, 1.4), image_pos=(0, 0, -0.05), image_color=OTPGlobals.GlobalDialogColor, borderWidth=(0.01, 0.01))
optiondefs = {'parent': self,
'relief': DGG.SUNKEN,
'scale': 0.05,
'frameSize': (-0.2,
25.3,
-0.5,
1.2),
'borderWidth': (0.1, 0.1),
'frameColor': (0.9, 0.9, 0.85, 0.8),
'pos': (-0.2, 0, 0.11),
'entryFont': OTPGlobals.getInterfaceFont(),
'width': 8.6,
'numLines': 3,
'cursorKeys': 1,
'backgroundFocus': 0,
'suppressKeys': 1,
'suppressMouse': 1,
'command': self.sendChat,
'failedCommand': self.sendFailed,
'focus': 0,
'text': '',
'sortOrder': DGG.FOREGROUND_SORT_INDEX}
entryOptions['parent'] = self
self.chatEntry = DirectEntry(**entryOptions)
self.whisperId = None
self.chatEntry.bind(DGG.OVERFLOW, self.chatOverflow)
wantHistory = 0
if __dev__:
wantHistory = 1
self.wantHistory = base.config.GetBool('want-chat-history', wantHistory)
self.history = ['']
self.historySize = base.config.GetInt('chat-history-size', 10)
self.historyIndex = 0
self.promoteWhiteList = 0
self.checkBeforeSend = base.config.GetBool('white-list-check-before-send', 0)
self.whiteList = None
self.active = 0
self.autoOff = 0
self.sendBy = 'Mode'
self.prefilter = 1
from direct.gui import DirectGuiGlobals
self.chatEntry.bind(DirectGuiGlobals.TYPE, self.applyFilter)
self.chatEntry.bind(DirectGuiGlobals.ERASE, self.applyFilter)
tpMgr = TextPropertiesManager.getGlobalPtr()
Red = tpMgr.getProperties('red')
Red.setTextColor(1.0, 0.0, 0.0, 1)
tpMgr.setProperties('WLRed', Red)
del tpMgr
self.origFrameColor = self.chatEntry['frameColor']
return
def destroy(self):
from direct.gui import DirectGuiGlobals
self.chatEntry.unbind(DGG.OVERFLOW)
self.chatEntry.unbind(DirectGuiGlobals.TYPE)
self.chatEntry.unbind(DirectGuiGlobals.ERASE)
self.chatEntry.ignoreAll()
DirectFrame.destroy(self)
def delete(self):
self.ignore('arrow_up-up')
self.ignore('arrow_down-up')
def requestMode(self, mode, *args):
return self.request(mode, *args)
def defaultFilter(self, request, *args):
if request == 'AllChat':
if not base.talkAssistant.checkAnyTypedChat():
messenger.send('Chat-Failed open typed chat test')
self.notify.warning('Chat-Failed open typed chat test')
return None
elif request == 'PlayerWhisper':
if not base.talkAssistant.checkWhisperTypedChatPlayer(self.whisperId):
messenger.send('Chat-Failed player typed chat test')
self.notify.warning('Chat-Failed player typed chat test')
return None
elif request == 'AvatarWhisper':
if not base.talkAssistant.checkWhisperTypedChatAvatar(self.whisperId):
messenger.send('Chat-Failed avatar typed chat test')
self.notify.warning('Chat-Failed avatar typed chat test')
return None
return FSM.FSM.defaultFilter(self, request, *args)
def enterOff(self):
self.deactivate()
localAvatar.chatMgr.fsm.request('mainMenu')
def exitOff(self):
self.activate()
def enterAllChat(self):
self.chatEntry['focus'] = 1
self.show()
def exitAllChat(self):
pass
def enterGuildChat(self):
self['focus'] = 1
self.show()
def exitGuildChat(self):
pass
def enterCrewChat(self):
self['focus'] = 1
self.show()
def exitCrewChat(self):
pass
def enterPlayerWhisper(self):
self.tempText = self.chatEntry.get()
self.activate()
def exitPlayerWhisper(self):
self.chatEntry.set(self.tempText)
self.whisperId = None
return
def enterAvatarWhisper(self):
self.tempText = self.chatEntry.get()
self.activate()
def exitAvatarWhisper(self):
self.chatEntry.set(self.tempText)
self.whisperId = None
return
def activateByData(self, receiverId = None, toPlayer = 0):
self.receiverId = receiverId
self.toPlayer = toPlayer
result = None
if not self.receiverId:
result = self.requestMode('AllChat')
elif self.receiverId and not self.toPlayer:
self.whisperId = receiverId
result = self.requestMode('AvatarWhisper')
elif self.receiverId and self.toPlayer:
self.whisperId = receiverId
result = self.requestMode('PlayerWhisper')
return result
def activate(self):
self.chatEntry['focus'] = 1
self.show()
self.active = 1
self.chatEntry.guiItem.setAcceptEnabled(False)
def deactivate(self):
self.chatEntry.set('')
self.chatEntry['focus'] = 0
self.hide()
self.active = 0
def isActive(self):
return self.active
def sendChat(self, text, overflow = False):
if not (len(text) > 0 and text[0] in ['~', '>']):
if self.prefilter:
words = text.split(' ')
newwords = []
for word in words:
if word == '' or self.whiteList.isWord(word) or self.promoteWhiteList:
newwords.append(word)
else:
newwords.append(base.whiteList.defaultWord)
text = ' '.join(newwords)
else:
text = self.chatEntry.get(plain=True)
if text:
self.chatEntry.set('')
if base.config.GetBool('exec-chat', 0) and text[0] == '>':
text = self.__execMessage(text[1:])
base.localAvatar.setChatAbsolute(text, CFSpeech | CFTimeout)
return
else:
self.sendChatBySwitch(text)
if self.wantHistory:
self.addToHistory(text)
else:
localAvatar.chatMgr.deactivateChat()
if not overflow:
self.hide()
if self.autoOff:
self.requestMode('Off')
localAvatar.chatMgr.messageSent()
def sendChatBySwitch(self, text):
if len(text) > 0 and text[0] == '~':
base.talkAssistant.sendOpenTalk(text)
elif self.sendBy == 'Mode':
self.sendChatByMode(text)
elif self.sendBy == 'Data':
self.sendChatByData(text)
else:
self.sendChatByMode(text)
def sendChatByData(self, text):
if not self.receiverId:
base.talkAssistant.sendOpenTalk(text)
elif self.receiverId and not self.toPlayer:
base.talkAssistant.sendWhisperTalk(text, self.receiverId)
elif self.receiverId and self.toPlayer:
base.talkAssistant.sendAccountTalk(text, self.receiverId)
def sendChatByMode(self, text):
state = self.getCurrentOrNextState()
messenger.send('sentRegularChat')
if state == 'PlayerWhisper':
base.talkAssistant.sendPlayerWhisperWLChat(text, self.whisperId)
elif state == 'AvatarWhisper':
base.talkAssistant.sendAvatarWhisperWLChat(text, self.whisperId)
elif state == 'GuildChat':
base.talkAssistant.sendAvatarGuildWLChat(text)
elif state == 'CrewChat':
base.talkAssistant.sendAvatarCrewWLChat(text)
elif len(text) > 0 and text[0] == '~':
base.talkAssistant.sendOpenTalk(text)
else:
base.talkAssistant.sendOpenTalk(text)
def sendFailed(self, text):
if not self.checkBeforeSend:
self.sendChat(text)
return
self.chatEntry['frameColor'] = (0.9, 0.0, 0.0, 0.8)
def resetFrameColor(task = None):
self.chatEntry['frameColor'] = self.origFrameColor
return Task.done
taskMgr.doMethodLater(0.1, resetFrameColor, 'resetFrameColor')
self.applyFilter(keyArgs=None, strict=True)
self.okayToSubmit = True
self.chatEntry.guiItem.setAcceptEnabled(True)
return
def chatOverflow(self, overflowText):
self.notify.debug('chatOverflow')
self.sendChat(self.chatEntry.get(plain=True), overflow=True)
def addToHistory(self, text):
self.history = [text] + self.history[:self.historySize - 1]
self.historyIndex = 0
def getPrevHistory(self):
self.chatEntry.set(self.history[self.historyIndex])
self.historyIndex += 1
self.historyIndex %= len(self.history)
def getNextHistory(self):
self.chatEntry.set(self.history[self.historyIndex])
self.historyIndex -= 1
self.historyIndex %= len(self.history)
def importExecNamespace(self):
pass
def __execMessage(self, message):
if not ChatInputTyped.ExecNamespace:
ChatInputTyped.ExecNamespace = {}
exec 'from pandac.PandaModules import *' in globals(), self.ExecNamespace
self.importExecNamespace()
try:
if not isClient():
print 'EXECWARNING ChatInputWhiteListFrame eval: %s' % message
printStack()
return str(eval(message, globals(), ChatInputTyped.ExecNamespace))
except SyntaxError:
try:
if not isClient():
print 'EXECWARNING ChatInputWhiteListFrame exec: %s' % message
printStack()
exec message in globals(), ChatInputTyped.ExecNamespace
return 'ok'
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
def applyFilter(self, keyArgs, strict = False):
text = self.chatEntry.get(plain=True)
if len(text) > 0 and text[0] in ['~', '>']:
self.okayToSubmit = True
else:
words = text.split(' ')
newwords = []
self.notify.debug('%s' % words)
self.okayToSubmit = True
for word in words:
if word == '' or self.whiteList.isWord(word):
newwords.append(word)
else:
if self.checkBeforeSend:
self.okayToSubmit = False
else:
self.okayToSubmit = True
newwords.append('\x01WLEnter\x01' + word + '\x02')
if not strict:
lastword = words[-1]
if lastword == '' or self.whiteList.isPrefix(lastword):
newwords[-1] = lastword
else:
newwords[-1] = '\x01WLEnter\x01' + lastword + '\x02'
newtext = ' '.join(newwords)
self.chatEntry.set(newtext)
self.chatEntry.guiItem.setAcceptEnabled(self.okayToSubmit)

517
otp/chat/ChatManager.py Normal file
View file

@ -0,0 +1,517 @@
import string
import sys
from direct.showbase import DirectObject
from otp.otpbase import OTPGlobals
from direct.fsm import ClassicFSM
from direct.fsm import State
from otp.login import SecretFriendsInfoPanel
from otp.login import PrivacyPolicyPanel
from otp.otpbase import OTPLocalizer
from direct.directnotify import DirectNotifyGlobal
from otp.login import LeaveToPayDialog
from direct.gui.DirectGui import *
from pandac.PandaModules import *
ChatEvent = 'ChatEvent'
NormalChatEvent = 'NormalChatEvent'
SCChatEvent = 'SCChatEvent'
SCCustomChatEvent = 'SCCustomChatEvent'
SCEmoteChatEvent = 'SCEmoteChatEvent'
OnScreen = 0
OffScreen = 1
Thought = 2
ThoughtPrefix = '.'
def isThought(message):
if len(message) == 0:
return 0
elif string.find(message, ThoughtPrefix, 0, len(ThoughtPrefix)) >= 0:
return 1
else:
return 0
def removeThoughtPrefix(message):
if isThought(message):
return message[len(ThoughtPrefix):]
else:
return message
class ChatManager(DirectObject.DirectObject):
notify = DirectNotifyGlobal.directNotify.newCategory('ChatManager')
execChat = base.config.GetBool('exec-chat', 0)
def __init__(self, cr, localAvatar):
self.cr = cr
self.localAvatar = localAvatar
self.wantBackgroundFocus = 1
self.__scObscured = 0
self.__normalObscured = 0
self.openChatWarning = None
self.unpaidChatWarning = None
self.teaser = None
self.paidNoParentPassword = None
self.noSecretChatAtAll = None
self.noSecretChatAtAllAndNoWhitelist = None
self.noSecretChatWarning = None
self.activateChatGui = None
self.chatMoreInfo = None
self.chatPrivacyPolicy = None
self.secretChatActivated = None
self.problemActivatingChat = None
self.leaveToPayDialog = None
self.fsm = ClassicFSM.ClassicFSM('chatManager', [State.State('off', self.enterOff, self.exitOff),
State.State('mainMenu', self.enterMainMenu, self.exitMainMenu),
State.State('speedChat', self.enterSpeedChat, self.exitSpeedChat),
State.State('normalChat', self.enterNormalChat, self.exitNormalChat),
State.State('whisper', self.enterWhisper, self.exitWhisper),
State.State('whisperChat', self.enterWhisperChat, self.exitWhisperChat),
State.State('whisperChatPlayer', self.enterWhisperChatPlayer, self.exitWhisperChatPlayer),
State.State('whisperSpeedChat', self.enterWhisperSpeedChat, self.exitWhisperSpeedChat),
State.State('whisperSpeedChatPlayer', self.enterWhisperSpeedChatPlayer, self.exitWhisperSpeedChatPlayer),
State.State('openChatWarning', self.enterOpenChatWarning, self.exitOpenChatWarning),
State.State('leaveToPayDialog', self.enterLeaveToPayDialog, self.exitLeaveToPayDialog),
State.State('unpaidChatWarning', self.enterUnpaidChatWarning, self.exitUnpaidChatWarning),
State.State('noSecretChatAtAll', self.enterNoSecretChatAtAll, self.exitNoSecretChatAtAll),
State.State('noSecretChatAtAllAndNoWhitelist', self.enterNoSecretChatAtAllAndNoWhitelist, self.exitNoSecretChatAtAllAndNoWhitelist),
State.State('noSecretChatWarning', self.enterNoSecretChatWarning, self.exitNoSecretChatWarning),
State.State('noFriendsWarning', self.enterNoFriendsWarning, self.exitNoFriendsWarning),
State.State('otherDialog', self.enterOtherDialog, self.exitOtherDialog),
State.State('activateChat', self.enterActivateChat, self.exitActivateChat),
State.State('chatMoreInfo', self.enterChatMoreInfo, self.exitChatMoreInfo),
State.State('chatPrivacyPolicy', self.enterChatPrivacyPolicy, self.exitChatPrivacyPolicy),
State.State('secretChatActivated', self.enterSecretChatActivated, self.exitSecretChatActivated),
State.State('problemActivatingChat', self.enterProblemActivatingChat, self.exitProblemActivatingChat),
State.State('whiteListOpenChat', self.enterWhiteListOpenChat, self.exitWhiteListOpenChat),
State.State('whiteListAvatarChat', self.enterWhiteListAvatarChat, self.exitWhiteListAvatarChat),
State.State('whiteListPlayerChat', self.enterWhiteListPlayerChat, self.exitWhiteListPlayerChat),
State.State('trueFriendTeaserPanel', self.enterTrueFriendTeaserPanel, self.exitTrueFriendTeaserPanel)], 'off', 'off')
self.fsm.enterInitialState()
return
def delete(self):
self.ignoreAll()
del self.fsm
if hasattr(self.chatInputNormal, 'destroy'):
self.chatInputNormal.destroy()
self.chatInputNormal.delete()
del self.chatInputNormal
self.chatInputSpeedChat.delete()
del self.chatInputSpeedChat
if self.openChatWarning:
self.openChatWarning.destroy()
self.openChatWarning = None
if self.unpaidChatWarning:
self.payButton = None
self.unpaidChatWarning.destroy()
self.unpaidChatWarning = None
if self.teaser:
self.teaser.cleanup()
self.teaser.unload()
self.teaser = None
if self.noSecretChatAtAll:
self.noSecretChatAtAll.destroy()
self.noSecretChatAtAll = None
if self.noSecretChatAtAllAndNoWhitelist:
self.noSecretChatAtAllAndNoWhitelist.destroy()
self.noSecretChatAtAllAndNoWhitelist = None
if self.noSecretChatWarning:
self.noSecretChatWarning.destroy()
self.noSecretChatWarning = None
if self.activateChatGui:
self.activateChatGui.destroy()
self.activateChatGui = None
if self.chatMoreInfo:
self.chatMoreInfo.destroy()
self.chatMoreInfo = None
if self.chatPrivacyPolicy:
self.chatPrivacyPolicy.destroy()
self.chatPrivacyPolicy = None
if self.secretChatActivated:
self.secretChatActivated.destroy()
self.secretChatActivated = None
if self.problemActivatingChat:
self.problemActivatingChat.destroy()
self.problemActivatingChat = None
del self.localAvatar
del self.cr
return
def obscure(self, normal, sc):
self.__scObscured = sc
if self.__scObscured:
self.scButton.hide()
self.__normalObscured = normal
if self.__normalObscured:
self.normalButton.hide()
def isObscured(self):
return (self.__normalObscured, self.__scObscured)
def stop(self):
self.fsm.request('off')
self.ignoreAll()
def start(self):
self.fsm.request('mainMenu')
def announceChat(self):
messenger.send(ChatEvent)
def announceSCChat(self):
messenger.send(SCChatEvent)
self.announceChat()
def sendChatString(self, message):
chatFlags = CFSpeech | CFTimeout
if base.cr.wantSwitchboardHacks:
from otp.switchboard import badwordpy
badwordpy.init('', '')
message = badwordpy.scrub(message)
if isThought(message):
message = removeThoughtPrefix(message)
chatFlags = CFThought
messenger.send(NormalChatEvent)
self.announceChat()
def sendWhisperString(self, message, whisperAvatarId):
pass
def sendSCChatMessage(self, msgIndex):
base.talkAssistant.sendOpenSpeedChat(1, msgIndex)
def sendSCWhisperMessage(self, msgIndex, whisperAvatarId, toPlayer):
if toPlayer:
base.talkAssistant.sendPlayerWhisperSpeedChat(1, msgIndex, whisperAvatarId)
else:
base.talkAssistant.sendAvatarWhisperSpeedChat(1, msgIndex, whisperAvatarId)
def sendSCCustomChatMessage(self, msgIndex):
base.talkAssistant.sendOpenSpeedChat(3, msgIndex)
def sendSCCustomWhisperMessage(self, msgIndex, whisperAvatarId, toPlayer):
if toPlayer:
base.talkAssistant.sendPlayerWhisperSpeedChat(3, msgIndex, whisperAvatarId)
else:
base.talkAssistant.sendAvatarWhisperSpeedChat(3, msgIndex, whisperAvatarId)
def sendSCEmoteChatMessage(self, emoteId):
base.talkAssistant.sendOpenSpeedChat(2, emoteId)
def sendSCEmoteWhisperMessage(self, emoteId, whisperAvatarId, toPlayer):
if toPlayer:
base.talkAssistant.sendPlayerWhisperSpeedChat(2, emoteId, whisperAvatarId)
else:
base.talkAssistant.sendAvatarWhisperSpeedChat(2, emoteId, whisperAvatarId)
def enterOff(self):
self.scButton.hide()
self.normalButton.hide()
self.ignoreAll()
def exitOff(self):
pass
def enterMainMenu(self):
self.checkObscurred()
if self.localAvatar.canChat() or self.cr.wantMagicWords:
if self.wantBackgroundFocus:
self.chatInputNormal.chatEntry['backgroundFocus'] = 1
self.acceptOnce('enterNormalChat', self.fsm.request, ['normalChat'])
def checkObscurred(self):
if not self.__scObscured:
self.scButton.show()
if not self.__normalObscured:
self.normalButton.show()
def exitMainMenu(self):
self.scButton.hide()
self.normalButton.hide()
self.ignore('enterNormalChat')
if self.wantBackgroundFocus:
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
def whisperTo(self, avatarName, avatarId, playerId = None):
self.fsm.request('whisper', [avatarName, avatarId, playerId])
def noWhisper(self):
self.fsm.request('mainMenu')
def handleWhiteListSelect(self):
self.fsm.request('whiteListOpenChat')
def enterWhiteListOpenChat(self):
self.checkObscurred()
if self.wantBackgroundFocus:
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
base.localAvatar.chatMgr.chatInputWhiteList.activateByData()
def exitWhiteListOpenChat(self):
pass
def enterWhiteListAvatarChat(self, receiverId):
if self.wantBackgroundFocus:
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
base.localAvatar.chatMgr.chatInputWhiteList.activateByData(receiverId, 0)
def exitWhiteListAvatarChat(self):
pass
def enterWhiteListPlayerChat(self, receiverId):
if self.wantBackgroundFocus:
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
base.localAvatar.chatMgr.chatInputWhiteList.activateByData(receiverId, 1)
def exitWhiteListPlayerChat(self):
pass
def enterWhisper(self, avatarName, avatarId, playerId = None):
self.whisperScButton['extraArgs'] = [avatarName, avatarId, playerId]
self.whisperButton['extraArgs'] = [avatarName, avatarId, playerId]
playerName = None
chatToToon = 1
online = 0
if self.cr.doId2do.has_key(avatarId):
online = 1
elif self.cr.isFriend(avatarId):
online = self.cr.isFriendOnline(avatarId)
hasManager = hasattr(base.cr, 'playerFriendsManager')
if hasManager:
if base.cr.playerFriendsManager.askAvatarOnline(avatarId):
online = 1
avatarUnderstandable = 0
playerUnderstandable = 0
av = None
if avatarId:
av = self.cr.identifyAvatar(avatarId)
if av != None:
avatarUnderstandable = av.isUnderstandable()
if playerId:
if base.cr.playerFriendsManager.playerId2Info.has_key(playerId):
playerInfo = base.cr.playerFriendsManager.playerId2Info.get(playerId)
playerName = playerInfo.playerName
online = 1
playerUnderstandable = playerInfo.understandableYesNo
if playerUnderstandable or not avatarId:
chatToToon = 0
if chatToToon:
chatName = avatarName
else:
chatName = playerName
normalButtonObscured, scButtonObscured = self.isObscured()
if (avatarUnderstandable or playerUnderstandable) and online and not normalButtonObscured:
self.whisperButton['state'] = 'normal'
self.enablewhisperButton()
else:
self.whisperButton['state'] = 'inactive'
self.disablewhisperButton()
if online:
self.whisperScButton['state'] = 'normal'
self.changeFrameText(OTPLocalizer.ChatManagerWhisperToName % chatName)
else:
self.whisperScButton['state'] = 'inactive'
self.changeFrameText(OTPLocalizer.ChatManagerWhisperOffline % chatName)
self.whisperFrame.show()
self.refreshWhisperFrame()
if avatarUnderstandable or playerUnderstandable:
if playerId and not chatToToon:
if self.wantBackgroundFocus:
self.chatInputNormal.chatEntry['backgroundFocus'] = 1
self.acceptOnce('enterNormalChat', self.fsm.request, ['whisperChatPlayer', [avatarName, playerId]])
elif online and chatToToon:
if self.wantBackgroundFocus:
self.chatInputNormal.chatEntry['backgroundFocus'] = 1
self.acceptOnce('enterNormalChat', self.fsm.request, ['whisperChat', [avatarName, avatarId]])
if base.cr.config.GetBool('force-typed-whisper-enabled', 0):
self.whisperButton['state'] = 'normal'
self.enablewhisperButton()
return
def disablewhisperButton(self):
pass
def enablewhisperButton(self):
pass
def refreshWhisperFrame(self):
pass
def changeFrameText(self, newText):
self.whisperFrame['text'] = newText
def exitWhisper(self):
self.whisperFrame.hide()
self.ignore('enterNormalChat')
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
def enterWhisperSpeedChat(self, avatarId):
self.whisperFrame.show()
if self.wantBackgroundFocus:
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
self.chatInputSpeedChat.show(avatarId)
def exitWhisperSpeedChat(self):
self.whisperFrame.hide()
self.chatInputSpeedChat.hide()
def enterWhisperSpeedChatPlayer(self, playerId):
self.whisperFrame.show()
if self.wantBackgroundFocus:
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
self.chatInputSpeedChat.show(playerId, 1)
def exitWhisperSpeedChatPlayer(self):
self.whisperFrame.hide()
self.chatInputSpeedChat.hide()
def enterWhisperChat(self, avatarName, avatarId):
result = self.chatInputNormal.activateByData(avatarId)
return result
def exitWhisperChat(self):
self.chatInputNormal.deactivate()
def enterWhisperChatPlayer(self, avatarName, playerId):
playerInfo = base.cr.playerFriendsManager.getFriendInfo(playerId)
if playerInfo:
avatarName = playerInfo.playerName
result = self.chatInputNormal.activateByData(playerId, 1)
return result
def exitWhisperChatPlayer(self):
self.chatInputNormal.deactivate()
def enterSpeedChat(self):
messenger.send('enterSpeedChat')
if not self.__scObscured:
self.scButton.show()
if not self.__normalObscured:
self.normalButton.show()
if self.wantBackgroundFocus:
self.chatInputNormal.chatEntry['backgroundFocus'] = 0
self.chatInputSpeedChat.show()
def exitSpeedChat(self):
self.scButton.hide()
self.normalButton.hide()
self.chatInputSpeedChat.hide()
def enterNormalChat(self):
result = self.chatInputNormal.activateByData()
return result
def exitNormalChat(self):
self.chatInputNormal.deactivate()
def enterOpenChatWarning(self):
self.notify.error('called enterOpenChatWarning() on parent class')
def exitOpenChatWarning(self):
self.notify.error('called exitOpenChatWarning() on parent class')
def enterLeaveToPayDialog(self):
if self.leaveToPayDialog == None:
self.leaveToPayDialog = LeaveToPayDialog.LeaveToPayDialog(self.paidNoParentPassword)
self.leaveToPayDialog.setCancel(self.__handleLeaveToPayCancel)
self.leaveToPayDialog.show()
return
def exitLeaveToPayDialog(self):
if self.leaveToPayDialog:
self.leaveToPayDialog.destroy()
self.leaveToPayDialog = None
return
def enterUnpaidChatWarning(self):
self.notify.error('called enterUnpaidChatWarning() on parent class')
def exitUnpaidChatWarning(self):
self.notify.error('called exitUnpaidChatWarning() on parent class')
def enterNoSecretChatAtAll(self):
self.notify.error('called enterNoSecretChatAtAll() on parent class')
def exitNoSecretChatAtAll(self):
self.notify.error('called exitNoSecretChatAtAll() on parent class')
def enterNoSecretChatAtAllAndNoWhitelist(self):
self.notify.error('called enterNoSecretChatAtAllAndNoWhitelist() on parent class')
def exitNoSecretChatAtAllAndNoWhitelist(self):
self.notify.error('called exitNoSecretChatAtAllAndNoWhitelist() on parent class')
def enterNoSecretChatWarning(self):
self.notify.error('called enterNoSecretChatWarning() on parent class')
def exitNoSecretChatWarning(self):
self.notify.error('called exitNoSecretChatWarning() on parent class')
def enterNoFriendsWarning(self):
self.notify.error('called enterNoFriendsWarning() on parent class')
def exitNoFriendsWarning(self):
self.notify.error('called exitNoFriendsWarning() on parent class')
def enterActivateChat(self):
self.notify.error('called enterActivateChat() on parent class')
def exitActivateChat(self):
self.notify.error('called exitActivateChat() on parent class')
def enterOtherDialog(self):
pass
def exitOtherDialog(self):
pass
def enterChatMoreInfo(self):
if self.chatMoreInfo == None:
self.chatMoreInfo = SecretFriendsInfoPanel.SecretFriendsInfoPanel('secretFriendsInfoDone')
self.chatMoreInfo.show()
self.accept('secretFriendsInfoDone', self.__secretFriendsInfoDone)
return
def exitChatMoreInfo(self):
self.chatMoreInfo.hide()
self.ignore('secretFriendsInfoDone')
def enterChatPrivacyPolicy(self):
if self.chatPrivacyPolicy == None:
self.chatPrivacyPolicy = PrivacyPolicyPanel.PrivacyPolicyPanel('privacyPolicyDone')
self.chatPrivacyPolicy.show()
self.accept('privacyPolicyDone', self.__privacyPolicyDone)
return
def exitChatPrivacyPolicy(self):
cleanupDialog('privacyPolicyDialog')
self.chatPrivacyPolicy = None
self.ignore('privacyPolicyDone')
return
def enterSecretChatActivated(self):
self.notify.error('called enterSecretChatActivated() on parent class')
def exitSecretChatActivated(self):
self.notify.error('called exitSecretChatActivated() on parent class')
def enterProblemActivatingChat(self):
self.notify.error('called enterProblemActivatingChat() on parent class')
def exitProblemActivatingChat(self):
self.notify.error('called exitProblemActivatingChat() on parent class')
def enterTrueFriendTeaserPanel(self):
self.notify.error('called enterTrueFriendTeaserPanel () on parent class')
def exitTrueFriendTeaserPanel(self):
self.notify.error('called exitTrueFriendTeaserPanel () on parent class')
def __handleLeaveToPayCancel(self):
self.fsm.request('mainMenu')
def __secretFriendsInfoDone(self):
self.fsm.request('activateChat')
def __privacyPolicyDone(self):
self.fsm.request('activateChat')

753
otp/chat/TalkAssistant.py Normal file
View file

@ -0,0 +1,753 @@
import string
import sys
from direct.showbase import DirectObject
from otp.otpbase import OTPLocalizer
from direct.directnotify import DirectNotifyGlobal
from otp.otpbase import OTPGlobals
from otp.speedchat import SCDecoders
from pandac.PandaModules import *
from otp.chat.TalkMessage import TalkMessage
from otp.chat.TalkHandle import TalkHandle
import time
from otp.chat.TalkGlobals import *
from otp.chat.ChatGlobals import *
from libotp import CFSpeech, CFTimeout, CFThought
ThoughtPrefix = '.'
class TalkAssistant(DirectObject.DirectObject):
ExecNamespace = None
notify = DirectNotifyGlobal.directNotify.newCategory('TalkAssistant')
execChat = base.config.GetBool('exec-chat', 0)
def __init__(self):
self.logWhispers = 1
self.whiteList = None
self.clearHistory()
self.zeroTimeDay = time.time()
self.zeroTimeGame = globalClock.getRealTime()
self.floodThreshold = 10.0
self.useWhiteListFilter = base.config.GetBool('white-list-filter-openchat', 0)
self.lastWhisperDoId = None
self.lastWhisperPlayerId = None
self.lastWhisper = None
self.SCDecoder = SCDecoders
return
def clearHistory(self):
self.historyComplete = []
self.historyOpen = []
self.historyUpdates = []
self.historyGuild = []
self.historyByDoId = {}
self.historyByDISLId = {}
self.floodDataByDoId = {}
self.spamDictByDoId = {}
self.labelGuild = OTPLocalizer.TalkGuild
self.handleDict = {}
self.messageCount = 0
self.shownWhiteListWarning = 0
def delete(self):
self.ignoreAll()
self.clearHistory()
def start(self):
pass
def stop(self):
pass
def countMessage(self):
self.messageCount += 1
return self.messageCount - 1
def getOpenText(self, numLines, startPoint = 0):
return self.historyOpen[startPoint:startPoint + numLines]
def getSizeOpenText(self):
return len(self.historyOpen)
def getCompleteText(self, numLines, startPoint = 0):
return self.historyComplete[startPoint:startPoint + numLines]
def getCompleteTextFromRecent(self, numLines, startPoint = 0):
start = len(self.historyComplete) - startPoint
if start < 0:
start = 0
backStart = max(start - numLines, 0)
text = self.historyComplete[backStart:start]
text.reverse()
return text
def getAllCompleteText(self):
return self.historyComplete
def getAllHistory(self):
return self.historyComplete
def getSizeCompleteText(self):
return len(self.historyComplete)
def getHandle(self, doId):
return self.handleDict.get(doId)
def doWhiteListWarning(self):
pass
def addToHistoryDoId(self, message, doId, scrubbed = 0):
if message.getTalkType() == TALK_WHISPER and doId != localAvatar.doId:
self.lastWhisperDoId = doId
self.lastWhisper = self.lastWhisperDoId
if not self.historyByDoId.has_key(doId):
self.historyByDoId[doId] = []
self.historyByDoId[doId].append(message)
if not self.shownWhiteListWarning and scrubbed and doId == localAvatar.doId:
self.doWhiteListWarning()
self.shownWhiteListWarning = 1
if not self.floodDataByDoId.has_key(doId):
self.floodDataByDoId[doId] = [0.0, self.stampTime(), message]
else:
oldTime = self.floodDataByDoId[doId][1]
newTime = self.stampTime()
timeDiff = newTime - oldTime
oldRating = self.floodDataByDoId[doId][0]
contentMult = 1.0
if len(message.getBody()) < 6:
contentMult += 0.2 * float(6 - len(message.getBody()))
if self.floodDataByDoId[doId][2].getBody() == message.getBody():
contentMult += 1.0
floodRating = max(0, 3.0 * contentMult + oldRating - timeDiff)
self.floodDataByDoId[doId] = [floodRating, self.stampTime(), message]
if floodRating > self.floodThreshold:
if oldRating < self.floodThreshold:
self.floodDataByDoId[doId] = [floodRating + 3.0, self.stampTime(), message]
return 1
else:
self.floodDataByDoId[doId] = [oldRating - timeDiff, self.stampTime(), message]
return 2
return 0
def addToHistoryDISLId(self, message, dISLId, scrubbed = 0):
if message.getTalkType() == TALK_ACCOUNT and dISLId != base.cr.accountDetailRecord.playerAccountId:
self.lastWhisperPlayerId = dISLId
self.lastWhisper = self.lastWhisperPlayerId
if not self.historyByDISLId.has_key(dISLId):
self.historyByDISLId[dISLId] = []
self.historyByDISLId[dISLId].append(message)
def addHandle(self, doId, message):
if doId == localAvatar.doId:
return
handle = self.handleDict.get(doId)
if not handle:
handle = TalkHandle(doId, message)
self.handleDict[doId] = handle
else:
handle.addMessageInfo(message)
def stampTime(self):
return globalClock.getRealTime() - self.zeroTimeGame
def findName(self, id, isPlayer = 0):
if isPlayer:
return self.findPlayerName(id)
else:
return self.findAvatarName(id)
def findAvatarName(self, id):
info = base.cr.identifyAvatar(id)
if info:
return info.getName()
else:
return ''
def findPlayerName(self, id):
info = base.cr.playerFriendsManager.getFriendInfo(id)
if info:
return info.playerName
else:
return ''
def whiteListFilterMessage(self, text):
if not self.useWhiteListFilter:
return text
elif not base.whiteList:
return 'no list'
words = text.split(' ')
newwords = []
for word in words:
if word == '' or base.whiteList.isWord(word):
newwords.append(word)
else:
newwords.append(base.whiteList.defaultWord)
newText = ' '.join(newwords)
return newText
def colorMessageByWhiteListFilter(self, text):
if not base.whiteList:
return text
words = text.split(' ')
newwords = []
for word in words:
if word == '' or base.whiteList.isWord(word):
newwords.append(word)
else:
newwords.append('\x01WLRed\x01' + word + '\x02')
newText = ' '.join(newwords)
return newText
def executeSlashCommand(self, text):
pass
def executeGMCommand(self, text):
pass
def isThought(self, message):
if not message:
return 0
elif len(message) == 0:
return 0
elif string.find(message, ThoughtPrefix, 0, len(ThoughtPrefix)) >= 0:
return 1
else:
return 0
def removeThoughtPrefix(self, message):
if self.isThought(message):
return message[len(ThoughtPrefix):]
else:
return message
def fillWithTestText(self):
hold = self.floodThreshold
self.floodThreshold = 1000.0
self.receiveOpenTalk(1001, 'Bob the Ghost', None, None, 'Hello from the machine')
self.receiveOpenTalk(1001, 'Bob the Ghost', None, None, 'More text for ya!')
self.receiveOpenTalk(1001, 'Bob the Ghost', None, None, 'Hope this makes life easier')
self.receiveOpenTalk(1002, 'Doug the Spirit', None, None, 'Now we need some longer text that will spill over onto two lines')
self.receiveOpenTalk(1002, 'Doug the Spirit', None, None, 'Maybe I will tell you')
self.receiveOpenTalk(1001, 'Bob the Ghost', None, None, 'If you are seeing this text it is because you are cool')
self.receiveOpenTalk(1002, 'Doug the Spirit', None, None, "That's right, there is no need to call tech support")
self.receiveOpenTalk(localAvatar.doId, localAvatar.getName, None, None, "Okay I won't call tech support, because I am cool")
self.receiveGMTalk(1003, 'God of Text', None, None, 'Good because I have seen it already')
self.floodThreshold = hold
return
def printHistoryComplete(self):
print 'HISTORY COMPLETE'
for message in self.historyComplete:
print '%s %s %s\n%s\n' % (message.getTimeStamp(),
message.getSenderAvatarName(),
message.getSenderAccountName(),
message.getBody())
def importExecNamespace(self):
pass
def execMessage(self, message):
print 'execMessage %s' % message
if not TalkAssistant.ExecNamespace:
TalkAssistant.ExecNamespace = {}
exec 'from pandac.PandaModules import *' in globals(), self.ExecNamespace
self.importExecNamespace()
try:
if not isClient():
print 'EXECWARNING TalkAssistant eval: %s' % message
printStack()
return str(eval(message, globals(), TalkAssistant.ExecNamespace))
except SyntaxError:
try:
if not isClient():
print 'EXECWARNING TalkAssistant exec: %s' % message
printStack()
exec message in globals(), TalkAssistant.ExecNamespace
return 'ok'
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
def checkOpenTypedChat(self):
if base.localAvatar.commonChatFlags & OTPGlobals.CommonChat:
return True
return False
def checkAnyTypedChat(self):
if base.localAvatar.commonChatFlags & OTPGlobals.CommonChat:
return True
if base.localAvatar.canChat():
return True
return False
def checkOpenSpeedChat(self):
return True
def checkWhisperTypedChatAvatar(self, avatarId):
remoteAvatar = base.cr.doId2do.get(avatarId)
if remoteAvatar:
if remoteAvatar.isUnderstandable():
return True
if base.localAvatar.commonChatFlags & OTPGlobals.SuperChat:
return True
remoteAvatarOrHandleOrInfo = base.cr.identifyAvatar(avatarId)
if remoteAvatarOrHandleOrInfo and hasattr(remoteAvatarOrHandleOrInfo, 'isUnderstandable'):
if remoteAvatarOrHandleOrInfo.isUnderstandable():
return True
info = base.cr.playerFriendsManager.findPlayerInfoFromAvId(avatarId)
if info:
if info.understandableYesNo:
return True
info = base.cr.avatarFriendsManager.getFriendInfo(avatarId)
if info:
if info.understandableYesNo:
return True
if base.cr.getFriendFlags(avatarId) & OTPGlobals.FriendChat:
return True
return False
def checkWhisperSpeedChatAvatar(self, avatarId):
return True
def checkWhisperTypedChatPlayer(self, playerId):
info = base.cr.playerFriendsManager.getFriendInfo(playerId)
if info:
if info.understandableYesNo:
return True
return False
def checkWhisperSpeedChatPlayer(self, playerId):
if base.cr.playerFriendsManager.isPlayerFriend(playerId):
return True
return False
def checkOpenSpeedChat(self):
return True
def checkWhisperSpeedChatAvatar(self, avatarId):
return True
def checkWhisperSpeedChatPlayer(self, playerId):
if base.cr.playerFriendsManager.isPlayerFriend(playerId):
return True
return False
def checkGuildTypedChat(self):
if localAvatar.guildId:
return True
return False
def checkGuildSpeedChat(self):
if localAvatar.guildId:
return True
return False
def receiveOpenTalk(self, senderAvId, avatarName, accountId, accountName, message, scrubbed = 0):
error = None
if not avatarName and senderAvId:
localAvatar.sendUpdate('logSuspiciousEvent', ['receiveOpenTalk: invalid avatar name (%s)' % senderAvId])
avatarName = self.findAvatarName(senderAvId)
if not accountName and accountId:
accountName = self.findPlayerName(accountId)
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, avatarName, accountId, accountName, None, None, None, None, TALK_OPEN, None)
if senderAvId != localAvatar.doId:
self.addHandle(senderAvId, newMessage)
reject = 0
if senderAvId:
reject = self.addToHistoryDoId(newMessage, senderAvId, scrubbed)
if accountId:
self.addToHistoryDISLId(newMessage, accountId)
if reject == 1:
newMessage.setBody(OTPLocalizer.AntiSpamInChat)
if reject != 2:
isSpam = self.spamDictByDoId.get(senderAvId) and reject
if not isSpam:
self.historyComplete.append(newMessage)
self.historyOpen.append(newMessage)
messenger.send('NewOpenMessage', [newMessage])
if newMessage.getBody() == OTPLocalizer.AntiSpamInChat:
self.spamDictByDoId[senderAvId] = 1
else:
self.spamDictByDoId[senderAvId] = 0
return error
def receiveWhisperTalk(self, avatarId, avatarName, accountId, accountName, toId, toName, message, scrubbed = 0):
error = None
print 'receiveWhisperTalk %s %s %s %s %s' % (avatarId,
avatarName,
accountId,
accountName,
message)
if not avatarName and avatarId:
avatarName = self.findAvatarName(avatarId)
if not accountName and accountId:
accountName = self.findPlayerName(accountId)
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, avatarId, avatarName, accountId, accountName, toId, toName, None, None, TALK_WHISPER, None)
if avatarId == localAvatar.doId:
self.addHandle(toId, newMessage)
else:
self.addHandle(avatarId, newMessage)
self.historyComplete.append(newMessage)
if avatarId:
self.addToHistoryDoId(newMessage, avatarId, scrubbed)
if accountId:
self.addToHistoryDISLId(newMessage, accountId)
messenger.send('NewOpenMessage', [newMessage])
return error
def receiveAccountTalk(self, avatarId, avatarName, accountId, accountName, toId, toName, message, scrubbed = 0):
if not accountName and base.cr.playerFriendsManager.playerId2Info.get(accountId):
accountName = base.cr.playerFriendsManager.playerId2Info.get(accountId).playerName
error = None
if not avatarName and avatarId:
avatarName = self.findAvatarName(avatarId)
if not accountName and accountId:
accountName = self.findPlayerName(accountId)
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, avatarId, avatarName, accountId, accountName, None, None, toId, toName, TALK_ACCOUNT, None)
self.historyComplete.append(newMessage)
if avatarId:
self.addToHistoryDoId(newMessage, avatarId, scrubbed)
if accountId:
self.addToHistoryDISLId(newMessage, accountId, scrubbed)
messenger.send('NewOpenMessage', [newMessage])
return error
def receiveGuildTalk(self, senderAvId, fromAC, avatarName, message, scrubbed = 0):
error = None
if not self.isThought(message):
accountName = self.findName(fromAC, 1)
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, avatarName, fromAC, accountName, None, None, None, None, TALK_GUILD, None)
reject = self.addToHistoryDoId(newMessage, senderAvId)
if reject == 1:
newMessage.setBody(OTPLocalizer.AntiSpamInChat)
if reject != 2:
isSpam = self.spamDictByDoId.get(senderAvId) and reject
if not isSpam:
self.historyComplete.append(newMessage)
self.historyGuild.append(newMessage)
messenger.send('NewOpenMessage', [newMessage])
if newMessage.getBody() == OTPLocalizer.AntiSpamInChat:
self.spamDictByDoId[senderAvId] = 1
else:
self.spamDictByDoId[senderAvId] = 0
return error
def receiveGMTalk(self, avatarId, avatarName, accountId, accountName, message, scrubbed = 0):
error = None
if not avatarName and avatarId:
avatarName = self.findAvatarName(avatarId)
if not accountName and accountId:
accountName = self.findPlayerName(accountId)
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, avatarId, avatarName, accountId, accountName, None, None, None, None, TALK_GM, None)
self.historyComplete.append(newMessage)
self.historyOpen.append(newMessage)
if avatarId:
self.addToHistoryDoId(newMessage, avatarId)
if accountId:
self.addToHistoryDISLId(newMessage, accountId)
messenger.send('NewOpenMessage', [newMessage])
return error
def receiveThought(self, avatarId, avatarName, accountId, accountName, message, scrubbed = 0):
error = None
if not avatarName and avatarId:
avatarName = self.findAvatarName(avatarId)
if not accountName and accountId:
accountName = self.findPlayerName(accountId)
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, avatarId, avatarName, accountId, accountName, None, None, None, None, AVATAR_THOUGHT, None)
if avatarId != localAvatar.doId:
self.addHandle(avatarId, newMessage)
reject = 0
if avatarId:
reject = self.addToHistoryDoId(newMessage, avatarId, scrubbed)
if accountId:
self.addToHistoryDISLId(newMessage, accountId)
if reject == 1:
newMessage.setBody(OTPLocalizer.AntiSpamInChat)
if reject != 2:
self.historyComplete.append(newMessage)
self.historyOpen.append(newMessage)
messenger.send('NewOpenMessage', [newMessage])
return error
def receiveGameMessage(self, message):
error = None
if not self.isThought(message):
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, None, None, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, INFO_GAME, None)
self.historyComplete.append(newMessage)
self.historyUpdates.append(newMessage)
messenger.send('NewOpenMessage', [newMessage])
return error
def receiveSystemMessage(self, message):
error = None
if not self.isThought(message):
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, None, None, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, INFO_SYSTEM, None)
self.historyComplete.append(newMessage)
self.historyUpdates.append(newMessage)
messenger.send('NewOpenMessage', [newMessage])
return error
def receiveDeveloperMessage(self, message):
error = None
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, None, None, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, INFO_DEV, None)
self.historyComplete.append(newMessage)
self.historyUpdates.append(newMessage)
messenger.send('NewOpenMessage', [newMessage])
return error
def receiveGuildMessage(self, message, senderAvId, senderName):
error = None
if not self.isThought(message):
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, senderName, None, None, None, None, None, None, TALK_GUILD, None)
self.historyComplete.append(newMessage)
self.historyGuild.append(newMessage)
messenger.send('NewOpenMessage', [newMessage])
return error
def receiveGuildUpdateMessage(self, message, senderId, senderName, receiverId, receiverName, extraInfo = None):
error = None
if not self.isThought(message):
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderId, senderName, None, None, receiverId, receiverName, None, None, INFO_GUILD, extraInfo)
self.historyComplete.append(newMessage)
self.historyGuild.append(newMessage)
messenger.send('NewOpenMessage', [newMessage])
return error
def receiveFriendUpdate(self, friendId, friendName, isOnline):
if isOnline:
onlineMessage = OTPLocalizer.FriendOnline
else:
onlineMessage = OTPLocalizer.FriendOffline
newMessage = TalkMessage(self.countMessage(), self.stampTime(), onlineMessage, friendId, friendName, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, UPDATE_FRIEND, None)
self.addHandle(friendId, newMessage)
self.historyComplete.append(newMessage)
self.historyUpdates.append(newMessage)
messenger.send('NewOpenMessage', [newMessage])
return
def receiveFriendAccountUpdate(self, friendId, friendName, isOnline):
if isOnline:
onlineMessage = OTPLocalizer.FriendOnline
else:
onlineMessage = OTPLocalizer.FriendOffline
newMessage = TalkMessage(self.countMessage(), self.stampTime(), onlineMessage, None, None, friendId, friendName, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, UPDATE_FRIEND, None)
self.historyComplete.append(newMessage)
self.historyUpdates.append(newMessage)
messenger.send('NewOpenMessage', [newMessage])
return
def receiveGuildUpdate(self, memberId, memberName, isOnline):
if base.cr.identifyFriend(memberId) is None:
if isOnline:
onlineMessage = OTPLocalizer.GuildMemberOnline
else:
onlineMessage = OTPLocalizer.GuildMemberOffline
newMessage = TalkMessage(self.countMessage(), self.stampTime(), onlineMessage, memberId, memberName, None, None, None, None, None, None, UPDATE_GUILD, None)
self.addHandle(memberId, newMessage)
self.historyComplete.append(newMessage)
self.historyUpdates.append(newMessage)
self.historyGuild.append(newMessage)
messenger.send('NewOpenMessage', [newMessage])
return
def receiveOpenSpeedChat(self, type, messageIndex, senderAvId, name = None):
error = None
if not name and senderAvId:
name = self.findName(senderAvId, 0)
if type == SPEEDCHAT_NORMAL:
message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
elif type == SPEEDCHAT_EMOTE:
message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, name)
elif type == SPEEDCHAT_CUSTOM:
message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
if message in (None, ''):
return
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, name, None, None, None, None, None, None, TALK_OPEN, None)
self.historyComplete.append(newMessage)
self.historyOpen.append(newMessage)
self.addToHistoryDoId(newMessage, senderAvId)
messenger.send('NewOpenMessage', [newMessage])
return error
def receiveAvatarWhisperSpeedChat(self, type, messageIndex, senderAvId, name = None):
error = None
if not name and senderAvId:
name = self.findName(senderAvId, 0)
if type == SPEEDCHAT_NORMAL:
message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
elif type == SPEEDCHAT_EMOTE:
message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, name)
elif type == SPEEDCHAT_CUSTOM:
message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, senderAvId, name, None, None, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, TALK_WHISPER, None)
self.historyComplete.append(newMessage)
self.historyOpen.append(newMessage)
self.addToHistoryDoId(newMessage, senderAvId)
messenger.send('NewOpenMessage', [newMessage])
return error
def receivePlayerWhisperSpeedChat(self, type, messageIndex, senderAvId, name = None):
error = None
if not name and senderAvId:
name = self.findName(senderAvId, 1)
if type == SPEEDCHAT_NORMAL:
message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
elif type == SPEEDCHAT_EMOTE:
message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, name)
elif type == SPEEDCHAT_CUSTOM:
message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, None, None, senderAvId, name, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, TALK_WHISPER, None)
self.historyComplete.append(newMessage)
self.historyOpen.append(newMessage)
self.addToHistoryDISLId(newMessage, senderAvId)
messenger.send('NewOpenMessage', [newMessage])
return error
def sendOpenTalk(self, message):
error = None
if base.cr.wantMagicWords and len(message) > 0 and message[0] == '~':
messenger.send('magicWord', [message])
self.receiveDeveloperMessage(message)
else:
chatFlags = CFSpeech | CFTimeout
if self.isThought(message):
chatFlags = CFThought
base.localAvatar.sendUpdate('setTalk', [0,
0,
'',
message,
[],
0])
messenger.send('chatUpdate', [message, chatFlags])
return error
def sendWhisperTalk(self, message, receiverAvId):
error = None
receiver = base.cr.doId2do.get(receiverAvId)
if receiver:
receiver.sendUpdate('setTalkWhisper', [0,
0,
'',
message,
[],
0])
else:
receiver = base.cr.identifyAvatar(receiverAvId)
if receiver:
base.localAvatar.sendUpdate('setTalkWhisper', [0,
0,
'',
message,
[],
0], sendToId=receiverAvId)
return error
def sendAccountTalk(self, message, receiverAccount):
error = None
base.cr.playerFriendsManager.sendUpdate('setTalkAccount', [receiverAccount,
0,
'',
message,
[],
0])
return error
def sendGuildTalk(self, message):
error = None
if self.checkGuildTypedChat():
base.cr.guildManager.sendTalk(message)
else:
print 'Guild chat error'
error = ERROR_NO_GUILD_CHAT
return error
def sendOpenSpeedChat(self, type, messageIndex):
error = None
if type == SPEEDCHAT_NORMAL:
messenger.send(SCChatEvent)
messenger.send('chatUpdateSC', [messageIndex])
base.localAvatar.b_setSC(messageIndex)
elif type == SPEEDCHAT_EMOTE:
messenger.send('chatUpdateSCEmote', [messageIndex])
messenger.send(SCEmoteChatEvent)
base.localAvatar.b_setSCEmote(messageIndex)
elif type == SPEEDCHAT_CUSTOM:
messenger.send('chatUpdateSCCustom', [messageIndex])
messenger.send(SCCustomChatEvent)
base.localAvatar.b_setSCCustom(messageIndex)
return error
def sendAvatarWhisperSpeedChat(self, type, messageIndex, receiverId):
error = None
if type == SPEEDCHAT_NORMAL:
base.localAvatar.whisperSCTo(messageIndex, receiverId, 0)
message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
elif type == SPEEDCHAT_EMOTE:
base.localAvatar.whisperSCEmoteTo(messageIndex, receiverId, 0)
message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, localAvatar.getName())
elif type == SPEEDCHAT_CUSTOM:
base.localAvatar.whisperSCCustomTo(messageIndex, receiverId, 0)
message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
if self.logWhispers:
avatarName = None
accountId = None
avatar = base.cr.identifyAvatar(receiverId)
if avatar:
avatarName = avatar.getName()
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, receiverId, avatarName, None, None, TALK_WHISPER, None)
self.historyComplete.append(newMessage)
self.addToHistoryDoId(newMessage, localAvatar.doId)
self.addToHistoryDISLId(newMessage, base.cr.accountDetailRecord.playerAccountId)
messenger.send('NewOpenMessage', [newMessage])
return error
def sendPlayerWhisperSpeedChat(self, type, messageIndex, receiverId):
error = None
if type == SPEEDCHAT_NORMAL:
base.cr.speedchatRelay.sendSpeedchat(receiverId, messageIndex)
message = self.SCDecoder.decodeSCStaticTextMsg(messageIndex)
elif type == SPEEDCHAT_EMOTE:
base.cr.speedchatRelay.sendSpeedchatEmote(receiverId, messageIndex)
message = self.SCDecoder.decodeSCEmoteWhisperMsg(messageIndex, localAvatar.getName())
return
elif type == SPEEDCHAT_CUSTOM:
base.cr.speedchatRelay.sendSpeedchatCustom(receiverId, messageIndex)
message = self.SCDecoder.decodeSCCustomMsg(messageIndex)
if self.logWhispers:
receiverName = self.findName(receiverId, 1)
newMessage = TalkMessage(self.countMessage(), self.stampTime(), message, localAvatar.doId, localAvatar.getName(), localAvatar.DISLid, localAvatar.DISLname, None, None, receiverId, receiverName, TALK_ACCOUNT, None)
self.historyComplete.append(newMessage)
self.addToHistoryDoId(newMessage, localAvatar.doId)
self.addToHistoryDISLId(newMessage, base.cr.accountDetailRecord.playerAccountId)
messenger.send('NewOpenMessage', [newMessage])
return error
def sendGuildSpeedChat(self, type, msgIndex):
error = None
if self.checkGuildSpeedChat():
base.cr.guildManager.sendSC(msgIndex)
else:
print 'Guild Speedchat error'
error = ERROR_NO_GUILD_CHAT
return error
def getWhisperReplyId(self):
if self.lastWhisper:
toPlayer = 0
if self.lastWhisper == self.lastWhisperPlayerId:
toPlayer = 1
return (self.lastWhisper, toPlayer)
return (0, 0)

19
otp/chat/TalkGlobals.py Normal file
View file

@ -0,0 +1,19 @@
TALK_NONE = 0
TALK_OPEN = 1
TALK_WHISPER = 2
TALK_ACCOUNT = 13
TALK_GM = 14
AVATAR_THOUGHT = 16
TALK_GUILD = 3
TALK_PARTY = 4
TALK_PVP = 5
UPDATE_GUILD = 6
UPDATE_FRIEND = 7
UPDATE_PARTY = 8
UPDATE_PVP = 9
INFO_SYSTEM = 10
INFO_GAME = 11
INFO_AVATAR_UNAVAILABLE = 12
INFO_OPEN = 15
INFO_DEV = 17
INFO_GUILD = 18

41
otp/chat/TalkHandle.py Normal file
View file

@ -0,0 +1,41 @@
from otp.avatar.AvatarHandle import AvatarHandle
class TalkHandle(AvatarHandle):
def __init__(self, doId, message):
self.avatarId = doId
self.avatarName = None
self.accountId = None
self.accountName = None
self.addMessageInfo(message)
return
def getName(self):
return self.avatarName
def isUnderstandable(self):
return False
def isOnline(self):
return False
def addMessageInfo(self, message):
if self.avatarId == message.getSenderAvatarId():
if not self.avatarName and message.getSenderAvatarName():
self.avatarName = message.getSenderAvatarName()
if not self.accountId and message.getSenderAccountId():
self.accountId = message.getSenderAccountId()
if not self.accountName and message.getSenderAccountName():
self.accountName = message.getSenderAccountName()
elif self.avatarId == message.getReceiverAvatarId():
if not self.avatarName and message.getReceiverAvatarName():
self.avatarName = message.getReceiverAvatarName()
if not self.accountId and message.getReceiverAccountId():
self.accountId = message.getReceiverAccountId()
if not self.accountName and message.getReceiverAccountName():
self.accountName = message.getReceiverAccountName()
def setTalkWhisper(self, fromAV, fromAC, avatarName, chat, mods, flags):
newText, scrubbed = localAvatar.scrubTalk(chat, mods)
base.talkAssistant.receiveWhisperTalk(fromAV, avatarName, fromAC, None, self.avatarId, self.getName(), newText, scrubbed)
return

96
otp/chat/TalkMessage.py Normal file
View file

@ -0,0 +1,96 @@
class TalkMessage:
def __init__(self, messageId, timeStamp, body, senderAvatarId, senderAvatarName, senderAccountId, senderAccountName, receiverAvatarId, receiverAvatarName, receiverAccountId, receiverAccountName, talkType, extraInfo = None):
self.timeStamp = timeStamp
self.body = body
self.senderAvatarId = senderAvatarId
self.senderAvatarName = senderAvatarName
self.senderAccountId = senderAccountId
self.senderAccountName = senderAccountName
self.receiverAvatarId = receiverAvatarId
self.receiverAvatarName = receiverAvatarName
self.receiverAccountId = receiverAccountId
self.receiverAccountName = receiverAccountName
self.talkType = talkType
self.extraInfo = extraInfo
self.messageId = messageId
def getMessageId(self):
return self.messageId
def setMessageId(self, id):
self.messageId = id
def getTimeStamp(self):
return self.timeStamp
def setTimeStamp(self, timeStamp):
self.timeStamp = timeStamp
def getBody(self):
return self.body
def setBody(self, body):
self.body = body
def getSenderAvatarId(self):
return self.senderAvatarId
def setSenderAvatarId(self, senderAvatarId):
self.senderAvatarId = senderAvatarId
def getSenderAvatarName(self):
return self.senderAvatarName
def setSenderAvatarName(self, senderAvatarName):
self.senderAvatarName = senderAvatarName
def getSenderAccountId(self):
return self.senderAccountId
def setSenderAccountId(self, senderAccountId):
self.senderAccountId = senderAccountId
def getSenderAccountName(self):
return self.senderAccountName
def setSenderAccountName(self, senderAccountName):
self.senderAccountName = senderAccountName
def getReceiverAvatarId(self):
return self.receiverAvatarId
def setReceiverAvatarId(self, receiverAvatarId):
self.receiverAvatarId = receiverAvatarId
def getReceiverAvatarName(self):
return self.receiverAvatarName
def setReceiverAvatarName(self, receiverAvatarName):
self.receiverAvatarName = receiverAvatarName
def getReceiverAccountId(self):
return self.receiverAccountId
def setReceiverAccountId(self, receiverAccountId):
self.receiverAccountId = receiverAccountId
def getReceiverAccountName(self):
return self.receiverAccountName
def setReceiverAccountName(self, receiverAccountName):
self.receiverAccountName = receiverAccountName
def getTalkType(self):
return self.talkType
def setTalkType(self, talkType):
self.talkType = talkType
def getExtraInfo(self):
return self.extraInfo
def setExtraInfo(self, extraInfo):
self.extraInfo = extraInfo

51
otp/chat/WhiteList.py Normal file
View file

@ -0,0 +1,51 @@
from bisect import bisect_left
import string
import sys
import os
class WhiteList:
def __init__(self, wordlist):
self.words = []
for line in wordlist:
self.words.append(line.strip('\n\r').lower())
self.words.sort()
self.numWords = len(self.words)
def cleanText(self, text):
text = text.strip('.,?!')
text = text.lower()
return text
def isWord(self, text):
text = self.cleanText(text)
i = bisect_left(self.words, text)
if i == self.numWords:
return False
return self.words[i] == text
def isPrefix(self, text):
text = self.cleanText(text)
i = bisect_left(self.words, text)
if i == self.numWords:
return False
return self.words[i].startswith(text)
def prefixCount(self, text):
text = self.cleanText(text)
i = bisect_left(self.words, text)
j = i
while j < self.numWords and self.words[j].startswith(text):
j += 1
return j - i
def prefixList(self, text):
text = self.cleanText(text)
i = bisect_left(self.words, text)
j = i
while j < self.numWords and self.words[j].startswith(text):
j += 1
return self.words[i:j]

0
otp/chat/__init__.py Normal file
View file

View file

@ -0,0 +1,6 @@
from direct.distributed import DistributedObject
class Account(DistributedObject.DistributedObject):
def __init__(self, cr):
pass

View file

@ -0,0 +1,29 @@
from direct.distributed.DistributedObjectGlobal import DistributedObjectGlobal
REPORT_PLAYER = 'REPORT_PLAYER'
ReportFoulLanguage = 'MODERATION_FOUL_LANGUAGE'
ReportPersonalInfo = 'MODERATION_PERSONAL_INFO'
ReportRudeBehavior = 'MODERATION_RUDE_BEHAVIOR'
ReportBadName = 'MODERATION_BAD_NAME'
ReportHacking = 'MODERATION_HACKING'
class CentralLogger(DistributedObjectGlobal):
PlayersReportedThisSession = {}
def hasReportedPlayer(self, targetDISLId, targetAvId):
return self.PlayersReportedThisSession.has_key((targetDISLId, targetAvId))
def reportPlayer(self, category, targetDISLId, targetAvId, description = 'None'):
if self.hasReportedPlayer(targetDISLId, targetAvId):
return False
self.PlayersReportedThisSession[targetDISLId, targetAvId] = 1
self.sendUpdate('sendMessage', [category,
REPORT_PLAYER,
targetDISLId,
targetAvId])
return True
def writeClientEvent(self, eventString):
self.sendUpdate('sendMessage', ['ClientEvent',
eventString,
0,
0])

View file

@ -0,0 +1,58 @@
from pandac.PandaModules import StringStream
from direct.distributed.PyDatagram import PyDatagram
import random
class ClsendTracker:
clsendNotify = directNotify.newCategory('clsend')
NumTrackersLoggingOverflow = 0
MaxTrackersLoggingOverflow = config.GetInt('max-clsend-loggers', 5)
def __init__(self):
self._logClsendOverflow = False
if self.isPlayerControlled():
if simbase.air.getTrackClsends():
if ClsendTracker.NumTrackersLoggingOverflow < ClsendTracker.MaxTrackersLoggingOverflow:
self._logClsendOverflow = random.random() < 1.0 / config.GetFloat('clsend-log-one-av-in-every', choice(__dev__, 4, 50))
if self._logClsendOverflow:
ClsendTracker.NumTrackersLoggingOverflow += 1
self._clsendMsgs = []
self._clsendBufLimit = 100
self._clsendFlushNum = 20
self._clsendCounter = 0
def announceGenerate(self):
if self._logClsendOverflow:
self.clsendNotify.info('logging all clsends for %s' % self.doId)
def destroy(self):
if self._logClsendOverflow:
ClsendTracker.NumTrackersLoggingOverflow -= 1
def trackClientSendMsg(self, dataStr):
self._clsendMsgs.append((self.air.getAvatarIdFromSender(), dataStr))
if len(self._clsendMsgs) >= self._clsendBufLimit:
self._trimClsend()
def _trimClsend(self):
for i in xrange(self._clsendFlushNum):
if self._logClsendOverflow:
self._logClsend(*self._clsendMsgs[0])
self._clsendMsgs = self._clsendMsgs[1:]
self._clsendCounter += 1
def _logClsend(self, senderId, dataStr):
msgStream = StringStream()
simbase.air.describeMessage(msgStream, '', dataStr)
readableStr = msgStream.getData()
sstream = StringStream()
PyDatagram(dataStr).dumpHex(sstream)
hexDump = sstream.getData()
self.clsendNotify.info('%s [%s]: %s%s' % (self.doId,
self._clsendCounter,
readableStr,
hexDump))
def dumpClientSentMsgs(self):
for msg in self._clsendMsgs:
self._logClsend(*msg)
self._clsendCounter += 1

View file

@ -0,0 +1,4 @@
from direct.distributed.DistributedObject import DistributedObject
class DistributedDirectory(DistributedObject):
pass

View file

@ -0,0 +1,35 @@
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.distributed.DistributedObject import DistributedObject
class DistributedDistrict(DistributedObject):
notify = directNotify.newCategory('DistributedDistrict')
neverDisable = 1
def __init__(self, cr):
DistributedObject.__init__(self, cr)
self.name = 'NotGiven'
self.available = 0
self.avatarCount = 0
self.newAvatarCount = 0
def announceGenerate(self):
DistributedObject.announceGenerate(self)
self.cr.activeDistrictMap[self.doId] = self
messenger.send('shardInfoUpdated')
def delete(self):
if base.cr.distributedDistrict is self:
base.cr.distributedDistrict = None
if self.cr.activeDistrictMap.has_key(self.doId):
del self.cr.activeDistrictMap[self.doId]
DistributedObject.delete(self)
messenger.send('shardInfoUpdated')
return
def setAvailable(self, available):
self.available = available
messenger.send('shardInfoUpdated')
def setName(self, name):
self.name = name
messenger.send('shardInfoUpdated')

View file

@ -0,0 +1,34 @@
from direct.distributed import DistributedObject
class DistributedTestObject(DistributedObject.DistributedObject):
def setRequiredField(self, r):
self.requiredField = r
def setB(self, B):
self.B = B
def setBA(self, BA):
self.BA = BA
def setBO(self, BO):
self.BO = BO
def setBR(self, BR):
self.BR = BR
def setBRA(self, BRA):
self.BRA = BRA
def setBRO(self, BRO):
self.BRO = BRO
def setBROA(self, BROA):
self.BROA = BROA
def gotNonReqThatWasntSet(self):
for field in ('B', 'BA', 'BO', 'BR', 'BRA', 'BRO', 'BROA'):
if hasattr(self, field):
return True
return False

View file

@ -0,0 +1,133 @@
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.showbase import DirectObject, TaskThreaded
class GameServerTestSuite(DirectObject.DirectObject, TaskThreaded.TaskThreaded):
notify = directNotify.newCategory('GarbageReport')
def __init__(self, cr):
self.cr = cr
TaskThreaded.TaskThreaded.__init__(self, self.__class__.__name__)
class TimeoutTest(DirectObject.DirectObject):
Timeout = 10
def _getTaskName(self, name):
return '%s-timeout-%s' % (self.__class__.__name__, name)
def startTimeout(self, name):
self.stopTimeout(name)
_taskName = self._getTaskName(name)
taskMgr.doMethodLater(self.Timeout, Functor(self._timeout, _taskName), _taskName)
def stopTimeout(self, name):
_taskName = self._getTaskName(name)
taskMgr.remove(_taskName)
def _timeout(self, taskName, task = None):
self.parent.notify.warning('TEST TIMED OUT: %s' % taskName)
import pdb
pdb.set_trace()
class MsgHandlerTest:
def installMsgHandler(self):
self.oldHandler = self.parent.handler
self.parent.handler = self.handleMsg
def removeMsgHandler(self):
self.parent.handler = self.oldHandler
del self.oldHandler
def handleMsg(self, msgType, di):
self.parent.cr.handler(msgType, di)
class TestGetAvatars(TaskThreaded.TaskThread, TimeoutTest, MsgHandlerTest):
def setUp(self):
self.state = 'request'
self.installMsgHandler()
def handleMsg(self, msgType, di):
if msgType == CLIENT_GET_AVATARS_RESP:
self.finished()
else:
MsgHandlerTest.handleMsg(self, msgType, di)
def run(self):
if self.state == 'request':
self.parent.cr.sendGetAvatarsMsg()
self.startTimeout('getAvatarList')
self.state = 'waitForList'
def tearDown(self):
self.stopTimeout('getAvatarList')
self.removeMsgHandler()
class TestInterestOpenAndClose(TaskThreaded.TaskThread, TimeoutTest):
def setUp(self):
self.state = 'open'
def run(self):
if self.state == 'open':
def openInterestDone():
self.stopTimeout(self.timeoutName)
self.state = 'modify'
doneEvent = uniqueName('openInterest')
self.acceptOnce(doneEvent, openInterestDone)
openInterestDone = None
self.timeoutName = 'openInterest'
self.startTimeout(self.timeoutName)
self.handle = self.parent.cr.addInterest(self.parent.cr.GameGlobalsId, 91504, 'testInterest', doneEvent)
self.state = 'waitOpenComplete'
elif self.state == 'modify':
def modifyInterestDone():
self.stopTimeout(self.timeoutName)
self.state = 'close'
doneEvent = uniqueName('openInterest')
self.acceptOnce(doneEvent, modifyInterestDone)
modifyInterestDone = None
self.timeoutName = 'modifyInterest'
self.startTimeout(self.timeoutName)
self.parent.cr.alterInterest(self.handle, self.parent.cr.GameGlobalsId, 91506, 'testInterest', doneEvent)
self.state = 'waitModifyComplete'
elif self.state == 'close':
def closeInterestDone():
self.stopTimeout(self.timeoutName)
self.state = 'done'
doneEvent = uniqueName('closeInterest')
self.acceptOnce(doneEvent, closeInterestDone)
closeInterestDone = None
self.timeoutName = 'closeInterest'
self.startTimeout(self.timeoutName)
self.handle = self.parent.cr.removeInterest(self.handle, doneEvent)
self.state = 'waitCloseComplete'
elif self.state == 'done':
self.finished()
return
class TestNonRequiredNonSetFields(TaskThreaded.TaskThread, TimeoutTest):
Timeout = 60
def setUp(self):
self.timeoutName = 'lookForObj'
self.startTimeout(self.timeoutName)
def run(self):
testObj = self.parent.cr.doFind('DistributedTestObject')
if testObj is not None:
self.finished()
return
def tearDown(self):
self.stopTimeout(self.timeoutName)
del self.timeoutName
self.scheduleThread(TestInterestOpenAndClose())
self.scheduleThread(TestNonRequiredNonSetFields())

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
from direct.directnotify import DirectNotifyGlobal
from direct.distributed import DistributedObject
class ObjectServer(DistributedObject.DistributedObject):
notify = DirectNotifyGlobal.directNotify.newCategory('ObjectServer')
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
def setName(self, name):
self.name = name

View file

@ -0,0 +1,89 @@
from direct.distributed.MsgTypes import *
OTP_DO_ID_SERVER_ROOT = 4007
OTP_DO_ID_FRIEND_MANAGER = 4501
OTP_DO_ID_LEADERBOARD_MANAGER = 4502
OTP_DO_ID_SERVER = 4600
OTP_DO_ID_UBER_DOG = 4601
OTP_CHANNEL_AI_AND_UD_BROADCAST = 4602
OTP_CHANNEL_UD_BROADCAST = 4603
OTP_CHANNEL_AI_BROADCAST = 4604
OTP_NET_MSGR_CHANNEL_ID_ALL_AI = 4605
OTP_NET_MSGR_CHANNEL_ID_UBER_DOG = 4606
OTP_NET_MSGR_CHANNEL_ID_AI_ONLY = 4607
OTP_DO_ID_COMMON = 4615
OTP_DO_ID_GATEWAY = 4616
OTP_DO_ID_PIRATES = 4617
OTP_DO_ID_TOONTOWN = 4618
OTP_DO_ID_FAIRIES = 4619
OTP_DO_ID_CARS = 4620
OTP_DO_ID_AVATARS = 4630
OTP_DO_ID_FRIENDS = 4640
OTP_DO_ID_GUILDS = 4650
OTP_DO_ID_ESCROW = 4660
OTP_DO_ID_PIRATES_AVATAR_MANAGER = 4674
OTP_DO_ID_PIRATES_CREW_MANAGER = 4675
OTP_DO_ID_PIRATES_INVENTORY_MANAGER = 4677
OTP_DO_ID_PIRATES_SPEEDCHAT_RELAY = 4711
OTP_DO_ID_PIRATES_SHIP_MANAGER = 4678
OTP_DO_ID_PIRATES_TRAVEL_AGENT = 4679
OTP_DO_ID_PIRATES_FRIENDS_MANAGER = 4680
OTP_DO_ID_CHAT_MANAGER = 4681
OTP_DO_ID_TOONTOWN_AVATAR_MANAGER = 4682
OTP_DO_ID_TOONTOWN_DELIVERY_MANAGER = 4683
OTP_DO_ID_TOONTOWN_TEMP_STORE_MANAGER = 4684
OTP_DO_ID_TOONTOWN_SPEEDCHAT_RELAY = 4712
OTP_DO_ID_SWITCHBOARD_MANAGER = 4685
OTP_DO_ID_AVATAR_FRIENDS_MANAGER = 4686
OTP_DO_ID_PLAYER_FRIENDS_MANAGER = 4687
OTP_DO_ID_CENTRAL_LOGGER = 4688
OTP_DO_ID_CARS_AVATAR_MANAGER = 4689
OTP_DO_ID_TOONTOWN_MAIL_MANAGER = 4690
OTP_DO_ID_TOONTOWN_PARTY_MANAGER = 4691
OTP_DO_ID_TOONTOWN_RAT_MANAGER = 4692
OTP_DO_ID_STATUS_DATABASE = 4693
OTP_DO_ID_TOONTOWN_AWARD_MANAGER = 4694
OTP_DO_ID_TOONTOWN_CODE_REDEMPTION_MANAGER = 4695
OTP_DO_ID_TOONTOWN_IN_GAME_NEWS_MANAGER = 4696
OTP_DO_ID_TOONTOWN_NON_REPEATABLE_RANDOM_SOURCE = 4697
OTP_DO_ID_AI_TRADE_AVATAR = 4698
OTP_DO_ID_TOONTOWN_WHITELIST_MANAGER = 4699
OTP_DO_ID_PIRATES_MATCH_MAKER = 4700
OTP_DO_ID_PIRATES_GUILD_MANAGER = 4701
OTP_DO_ID_PIRATES_AWARD_MAKER = 4702
OTP_DO_ID_PIRATES_CODE_REDEMPTION = 4703
OTP_DO_ID_PIRATES_SETTINGS_MANAGER = 4704
OTP_DO_ID_PIRATES_HOLIDAY_MANAGER = 4705
OTP_DO_ID_PIRATES_CREW_MATCH_MANAGER = 4706
OTP_DO_ID_PIRATES_AVATAR_ACCESSORIES_MANAGER = 4710
OTP_DO_ID_TOONTOWN_CPU_INFO_MANAGER = 4713
OTP_DO_ID_TOONTOWN_SECURITY_MANAGER = 4714
OTP_DO_ID_SNAPSHOT_DISPATCHER = 4800
OTP_DO_ID_SNAPSHOT_RENDERER = 4801
OTP_DO_ID_SNAPSHOT_RENDERER_01 = 4801
OTP_DO_ID_SNAPSHOT_RENDERER_02 = 4802
OTP_DO_ID_SNAPSHOT_RENDERER_03 = 4803
OTP_DO_ID_SNAPSHOT_RENDERER_04 = 4804
OTP_DO_ID_SNAPSHOT_RENDERER_05 = 4805
OTP_DO_ID_SNAPSHOT_RENDERER_06 = 4806
OTP_DO_ID_SNAPSHOT_RENDERER_07 = 4807
OTP_DO_ID_SNAPSHOT_RENDERER_08 = 4808
OTP_DO_ID_SNAPSHOT_RENDERER_09 = 4809
OTP_DO_ID_SNAPSHOT_RENDERER_10 = 4810
OTP_DO_ID_SNAPSHOT_RENDERER_11 = 4811
OTP_DO_ID_SNAPSHOT_RENDERER_12 = 4812
OTP_DO_ID_SNAPSHOT_RENDERER_13 = 4813
OTP_DO_ID_SNAPSHOT_RENDERER_14 = 4814
OTP_DO_ID_SNAPSHOT_RENDERER_15 = 4815
OTP_DO_ID_SNAPSHOT_RENDERER_16 = 4816
OTP_DO_ID_SNAPSHOT_RENDERER_17 = 4817
OTP_DO_ID_SNAPSHOT_RENDERER_18 = 4818
OTP_DO_ID_SNAPSHOT_RENDERER_19 = 4819
OTP_DO_ID_SNAPSHOT_RENDERER_20 = 4820
OTP_DO_ID_PIRATES_INVENTORY_MANAGER_BASE = 5001
OTP_ZONE_ID_INVALID = 0
OTP_ZONE_ID_OLD_QUIET_ZONE = 1
OTP_ZONE_ID_MANAGEMENT = 2
OTP_ZONE_ID_DISTRICTS = 3
OTP_ZONE_ID_DISTRICTS_STATS = 4
OTP_ZONE_ID_ELEMENTS = 5
OTP_NET_MESSENGER_CHANNEL = (OTP_DO_ID_UBER_DOG << 32) + OTP_ZONE_ID_MANAGEMENT

View file

@ -0,0 +1,22 @@
class PotentialAvatar:
def __init__(self, id, names, dna, position, allowedName, creator = 1, shared = 1, online = 0, wishState = 'CLOSED', wishName = '', defaultShard = 0, lastLogout = 0):
self.id = id
self.name = names[0]
self.dna = dna
self.avatarType = None
self.position = position
self.wantName = names[1]
self.approvedName = names[2]
self.rejectedName = names[3]
self.allowedName = allowedName
self.wishState = wishState
self.wishName = wishName
self.creator = creator
self.shared = shared
self.online = online
self.defaultShard = defaultShard
self.lastLogout = lastLogout
return

View file

@ -0,0 +1,12 @@
class PotentialShard:
def __init__(self, id):
self.id = id
self.name = None
self.population = 0
self.welcomeValleyPopulation = 0
self.active = 1
self.available = 1
return

View file

@ -0,0 +1,22 @@
class TelemetryLimited:
Sng = SerialNumGen()
def __init__(self):
self._telemetryLimiterId = self.Sng.next()
self._limits = set()
def getTelemetryLimiterId(self):
return self._telemetryLimiterId
def addTelemetryLimit(self, limit):
self._limits.add(limit)
def removeTelemetryLimit(self, limit):
if limit in self._limits:
self._limits.remove(limit)
def enforceTelemetryLimits(self):
for limit in self._limits:
limit(self)

View file

@ -0,0 +1,113 @@
from direct.showbase.DirectObject import DirectObject
from otp.avatar.DistributedPlayer import DistributedPlayer
from direct.task.Task import Task
class TelemetryLimiter(DirectObject):
TaskName = 'TelemetryLimiterEnforce'
LeakDetectEventName = 'telemetryLimiter'
def __init__(self):
self._objs = {}
self._task = taskMgr.add(self._enforceLimits, self.TaskName, priority=40)
def destroy(self):
taskMgr.remove(self._task)
del self._objs
def getNumObjs(self):
return len(self._objs)
def addObj(self, obj):
id = obj.getTelemetryLimiterId()
self._objs[id] = obj
self.accept(self._getDummyEventName(obj), self._dummyEventHandler)
def _getDummyEventName(self, obj):
return '%s-%s-%s-%s' % (self.LeakDetectEventName,
obj.getTelemetryLimiterId(),
id(obj),
obj.__class__.__name__)
def _dummyEventHandler(self, *args, **kargs):
pass
def removeObj(self, obj):
id = obj.getTelemetryLimiterId()
self._objs.pop(id)
self.ignore(self._getDummyEventName(obj))
def _enforceLimits(self, task = None):
for obj in self._objs.itervalues():
obj.enforceTelemetryLimits()
return Task.cont
class TelemetryLimit:
def __call__(self, obj):
pass
class RotationLimitToH(TelemetryLimit):
def __init__(self, pConst = 0.0, rConst = 0.0):
self._pConst = pConst
self._rConst = rConst
def __call__(self, obj):
obj.setHpr(obj.getH(), self._pConst, self._rConst)
class TLNull:
def __init__(self, *limits):
pass
def destroy(self):
pass
class TLGatherAllAvs(DirectObject):
def __init__(self, name, *limits):
self._name = name
self._avs = {}
self._limits = makeList(limits)
self._avId2limits = {}
avs = base.cr.doFindAllInstances(DistributedPlayer)
for av in avs:
self._handlePlayerArrive(av)
self.accept(DistributedPlayer.GetPlayerGenerateEvent(), self._handlePlayerArrive)
self.accept(DistributedPlayer.GetPlayerNetworkDeleteEvent(), self._handlePlayerLeave)
def _handlePlayerArrive(self, av):
if av is not localAvatar:
self._avs[av.doId] = av
limitList = []
for limit in self._limits:
l = limit()
limitList.append(l)
av.addTelemetryLimit(l)
self._avId2limits[av.doId] = limitList
base.cr.telemetryLimiter.addObj(av)
def _handlePlayerLeave(self, av):
if av is not localAvatar:
base.cr.telemetryLimiter.removeObj(av)
for limit in self._avId2limits[av.doId]:
av.removeTelemetryLimit(limit)
del self._avId2limits[av.doId]
del self._avs[av.doId]
def destroy(self):
self.ignoreAll()
while len(self._avs):
self._handlePlayerLeave(self._avs.values()[0])
del self._avs
del self._limits
del self._avId2limits

View file

View file

@ -0,0 +1,41 @@
from otp.avatar.AvatarHandle import AvatarHandle
class AvatarFriendInfo(AvatarHandle):
def __init__(self, avatarName = '', playerName = '', playerId = 0, onlineYesNo = 0, openChatEnabledYesNo = 0, openChatFriendshipYesNo = 0, wlChatEnabledYesNo = 0):
self.avatarName = avatarName
self.playerName = playerName
self.playerId = playerId
self.onlineYesNo = onlineYesNo
self.openChatEnabledYesNo = openChatEnabledYesNo
self.openChatFriendshipYesNo = openChatFriendshipYesNo
self.wlChatEnabledYesNo = wlChatEnabledYesNo
self.understandableYesNo = self.isUnderstandable()
def calcUnderstandableYesNo(self):
self.understandableYesNo = self.isUnderstandable()
def getName(self):
if self.avatarName:
return self.avatarName
elif self.playerName:
return self.playerName
else:
return ''
def isUnderstandable(self):
result = False
try:
if self.openChatFriendshipYesNo:
result = True
elif self.openChatEnabledYesNo and base.cr.openChatEnabled:
result = True
elif self.wlChatEnabledYesNo and base.cr.whiteListChatEnabled:
result = True
except:
pass
return result
def isOnline(self):
return self.onlineYesNo

View file

@ -0,0 +1,109 @@
from direct.distributed.DistributedObjectGlobal import DistributedObjectGlobal
from direct.directnotify.DirectNotifyGlobal import directNotify
from otp.uberdog.RejectCode import RejectCode
from otp.otpbase import OTPGlobals
from otp.otpbase import OTPLocalizer
class AvatarFriendsManager(DistributedObjectGlobal):
notify = directNotify.newCategory('AvatarFriendsManager')
def __init__(self, cr):
DistributedObjectGlobal.__init__(self, cr)
self.reset()
def reset(self):
self.avatarFriendsList = set()
self.avatarId2Info = {}
self.invitedAvatarsList = []
self.ignoredAvatarList = []
def addIgnore(self, avId):
if avId not in self.ignoredAvatarList:
self.ignoredAvatarList.append(avId)
base.cr.centralLogger.writeClientEvent('ignoring %s' % (avId,))
messenger.send('AvatarIgnoreChange')
def removeIgnore(self, avId):
if avId in self.ignoredAvatarList:
self.ignoredAvatarList.remove(avId)
base.cr.centralLogger.writeClientEvent('stopped ignoring %s' % (avId,))
messenger.send('AvatarIgnoreChange')
def checkIgnored(self, avId):
return avId and avId in self.ignoredAvatarList
def sendRequestInvite(self, avId):
self.notify.debugCall()
self.sendUpdate('requestInvite', [avId])
self.invitedAvatarsList.append(avId)
def sendRequestRemove(self, avId):
self.notify.debugCall()
self.sendUpdate('requestRemove', [avId])
if avId in self.invitedAvatarsList:
self.invitedAvatarsList.remove(avId)
def friendConsidering(self, avId):
self.notify.debugCall()
messenger.send(OTPGlobals.AvatarFriendConsideringEvent, [1, avId])
def invitationFrom(self, avId, avatarName):
self.notify.debugCall()
messenger.send(OTPGlobals.AvatarFriendInvitationEvent, [avId, avatarName])
def retractInvite(self, avId):
self.notify.debugCall()
messenger.send(OTPGlobals.AvatarFriendRetractInviteEvent, [avId])
if avId in self.invitedAvatarsList:
self.invitedAvatarsList.remove(avId)
def rejectInvite(self, avId, reason):
self.notify.debugCall()
messenger.send(OTPGlobals.AvatarFriendRejectInviteEvent, [avId, reason])
if avId in self.invitedAvatarsList:
self.invitedAvatarsList.remove(avId)
def rejectRemove(self, avId, reason):
self.notify.debugCall()
messenger.send(OTPGlobals.AvatarFriendRejectRemoveEvent, [avId, reason])
def updateAvatarFriend(self, avId, info):
if hasattr(info, 'avatarId') and not info.avatarId and avId:
info.avatarId = avId
if avId not in self.avatarFriendsList:
self.avatarFriendsList.add(avId)
self.avatarId2Info[avId] = info
messenger.send(OTPGlobals.AvatarFriendAddEvent, [avId, info])
if self.avatarId2Info[avId].onlineYesNo != info.onlineYesNo:
base.talkAssistant.receiveFriendUpdate(avId, info.getName(), info.onlineYesNo)
self.avatarId2Info[avId] = info
messenger.send(OTPGlobals.AvatarFriendUpdateEvent, [avId, info])
if avId in self.invitedAvatarsList:
self.invitedAvatarsList.remove(avId)
messenger.send(OTPGlobals.AvatarNewFriendAddEvent, [avId])
def removeAvatarFriend(self, avId):
self.avatarFriendsList.remove(avId)
self.avatarId2Info.pop(avId, None)
messenger.send(OTPGlobals.AvatarFriendRemoveEvent, [avId])
return
def setFriends(self, avatarIds):
self.notify.debugCall()
def isFriend(self, avId):
return self.isAvatarFriend(avId)
def isAvatarFriend(self, avId):
return avId in self.avatarFriendsList
def getFriendInfo(self, avId):
return self.avatarId2Info.get(avId)
def countTrueFriends(self):
count = 0
for id in self.avatarId2Info:
if self.avatarId2Info[id].openChatFriendshipYesNo:
count += 1
return count

46
otp/friends/FriendInfo.py Normal file
View file

@ -0,0 +1,46 @@
from otp.avatar.AvatarHandle import AvatarHandle
class FriendInfo(AvatarHandle):
def __init__(self, avatarName = '', playerName = '', onlineYesNo = 0, openChatEnabledYesNo = 0, openChatFriendshipYesNo = 0, wlChatEnabledYesNo = 0, location = '', sublocation = '', timestamp = 0, avatarId = 0, friendPrivs = 0, tokenPrivs = 0):
self.avatarName = avatarName
self.playerName = playerName
self.onlineYesNo = onlineYesNo
self.openChatEnabledYesNo = openChatEnabledYesNo
self.openChatFriendshipYesNo = openChatFriendshipYesNo
self.wlChatEnabledYesNo = wlChatEnabledYesNo
self.location = location
self.sublocation = sublocation
self.timestamp = timestamp
self.avatarId = avatarId
self.friendPrivs = friendPrivs
self.tokenPrivs = tokenPrivs
self.understandableYesNo = self.isUnderstandable()
def calcUnderstandableYesNo(self):
self.understandableYesNo = self.isUnderstandable()
def getName(self):
if self.avatarName:
return self.avatarName
elif self.playerName:
return self.playerName
else:
return ''
def isUnderstandable(self):
result = False
try:
if self.openChatFriendshipYesNo:
result = True
elif self.openChatEnabledYesNo and base.cr.openChatEnabled:
result = True
elif self.wlChatEnabledYesNo and base.cr.whiteListChatEnabled:
result = True
except:
pass
return result
def isOnline(self):
return self.onlineYesNo

View file

@ -0,0 +1,111 @@
from pandac.PandaModules import *
from direct.distributed import DistributedObject
from direct.directnotify import DirectNotifyGlobal
from otp.otpbase import OTPGlobals
class FriendManager(DistributedObject.DistributedObject):
notify = DirectNotifyGlobal.directNotify.newCategory('FriendManager')
neverDisable = 1
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
self.__available = 0
self.gameSpecificFunction = None
return
def setAvailable(self, available):
self.__available = available
if self.__available and self.gameSpecificFunction:
self.gameSpecificFunction()
def getAvailable(self):
return self.__available
def setGameSpecificFunction(self, function):
self.gameSpecificFunction = function
def executeGameSpecificFunction(self):
if self.__available and self.gameSpecificFunction:
self.gameSpecificFunction()
def generate(self):
if base.cr.friendManager != None:
base.cr.friendManager.delete()
base.cr.friendManager = self
DistributedObject.DistributedObject.generate(self)
return
def disable(self):
base.cr.friendManager = None
DistributedObject.DistributedObject.disable(self)
return
def delete(self):
self.gameSpecificFunction = None
base.cr.friendManager = None
DistributedObject.DistributedObject.delete(self)
return
def up_friendQuery(self, inviteeId):
self.sendUpdate('friendQuery', [inviteeId])
self.notify.debug('Client: friendQuery(%d)' % inviteeId)
def up_cancelFriendQuery(self, context):
self.sendUpdate('cancelFriendQuery', [context])
self.notify.debug('Client: cancelFriendQuery(%d)' % context)
def up_inviteeFriendConsidering(self, yesNo, context):
self.sendUpdate('inviteeFriendConsidering', [yesNo, context])
self.notify.debug('Client: inviteeFriendConsidering(%d, %d)' % (yesNo, context))
def up_inviteeFriendResponse(self, yesNoMaybe, context):
self.sendUpdate('inviteeFriendResponse', [yesNoMaybe, context])
self.notify.debug('Client: inviteeFriendResponse(%d, %d)' % (yesNoMaybe, context))
def up_inviteeAcknowledgeCancel(self, context):
self.sendUpdate('inviteeAcknowledgeCancel', [context])
self.notify.debug('Client: inviteeAcknowledgeCancel(%d)' % context)
def friendConsidering(self, yesNoAlready, context):
self.notify.info('Roger Client: friendConsidering(%d, %d)' % (yesNoAlready, context))
messenger.send('friendConsidering', [yesNoAlready, context])
def friendResponse(self, yesNoMaybe, context):
self.notify.debug('Client: friendResponse(%d, %d)' % (yesNoMaybe, context))
messenger.send('friendResponse', [yesNoMaybe, context])
def inviteeFriendQuery(self, inviterId, inviterName, inviterDna, context):
self.notify.debug('Client: inviteeFriendQuery(%d, %s, dna, %d)' % (inviterId, inviterName, context))
if not hasattr(base, 'localAvatar'):
self.up_inviteeFriendConsidering(0, context)
return
if inviterId in base.localAvatar.ignoreList:
self.up_inviteeFriendConsidering(4, context)
return
if not base.localAvatar.acceptingNewFriends:
self.up_inviteeFriendConsidering(6, context)
return
self.up_inviteeFriendConsidering(self.__available, context)
if self.__available:
messenger.send('friendInvitation', [inviterId,
inviterName,
inviterDna,
context])
def inviteeCancelFriendQuery(self, context):
self.notify.debug('Client: inviteeCancelFriendQuery(%d)' % context)
messenger.send('cancelFriendInvitation', [context])
self.up_inviteeAcknowledgeCancel(context)
def up_requestSecret(self):
self.notify.warning('Sending Request')
self.sendUpdate('requestSecret', [])
def requestSecretResponse(self, result, secret):
messenger.send('requestSecretResponse', [result, secret])
def up_submitSecret(self, secret):
self.sendUpdate('submitSecret', [secret])
def submitSecretResponse(self, result, avId):
messenger.send('submitSecretResponse', [result, avId])

View file

@ -0,0 +1,6 @@
INVITATION_RESP_OK = 0
INVITATION_RESP_DECLINE = 1
INVITATION_RESP_RETRACT = 2
INVITATION_RESP_CANCEL = 3
INVITATION_RESP_ALREADY_FRIENDS = 4
INVITATION_RESP_NEW_FRIENDS = 5

555
otp/friends/FriendSecret.py Normal file
View file

@ -0,0 +1,555 @@
from pandac.PandaModules import *
from direct.gui.DirectGui import *
from direct.directnotify import DirectNotifyGlobal
from direct.fsm import StateData
import string
from otp.otpbase import OTPLocalizer
from otp.otpbase import OTPGlobals
from otp.uberdog import RejectCode
globalFriendSecret = None
AccountSecret = 0
AvatarSecret = 1
BothSecrets = 2
def showFriendSecret(secretType = AvatarSecret):
global globalFriendSecret
if not base.cr.isPaid():
chatMgr = base.localAvatar.chatMgr
chatMgr.fsm.request('trueFriendTeaserPanel')
elif not base.cr.isParentPasswordSet():
chatMgr = base.localAvatar.chatMgr
if base.cr.productName in ['DisneyOnline-AP',
'DisneyOnline-UK',
'JP',
'DE',
'BR',
'FR']:
chatMgr = base.localAvatar.chatMgr
if not base.cr.isPaid():
chatMgr.fsm.request('unpaidChatWarning')
else:
chatMgr.paidNoParentPassword = 1
chatMgr.fsm.request('unpaidChatWarning')
else:
chatMgr.paidNoParentPassword = 1
chatMgr.fsm.request('noSecretChatAtAll')
elif not base.cr.allowSecretChat():
chatMgr = base.localAvatar.chatMgr
if base.cr.productName in ['DisneyOnline-AP',
'DisneyOnline-UK',
'JP',
'DE',
'BR',
'FR']:
chatMgr = base.localAvatar.chatMgr
if not base.cr.isPaid():
chatMgr.fsm.request('unpaidChatWarning')
else:
chatMgr.paidNoParentPassword = 1
chatMgr.fsm.request('unpaidChatWarning')
else:
chatMgr.fsm.request('noSecretChatAtAll')
elif base.cr.needParentPasswordForSecretChat():
unloadFriendSecret()
globalFriendSecret = FriendSecretNeedsParentLogin(secretType)
globalFriendSecret.enter()
else:
openFriendSecret(secretType)
def openFriendSecret(secretType):
global globalFriendSecret
if globalFriendSecret != None:
globalFriendSecret.unload()
globalFriendSecret = FriendSecret(secretType)
globalFriendSecret.enter()
return
def hideFriendSecret():
if globalFriendSecret != None:
globalFriendSecret.exit()
return
def unloadFriendSecret():
global globalFriendSecret
if globalFriendSecret != None:
globalFriendSecret.unload()
globalFriendSecret = None
return
class FriendSecretNeedsParentLogin(StateData.StateData):
notify = DirectNotifyGlobal.directNotify.newCategory('FriendSecretNeedsParentLogin')
def __init__(self, secretType):
StateData.StateData.__init__(self, 'friend-secret-needs-parent-login-done')
self.dialog = None
self.secretType = secretType
return
def enter(self):
StateData.StateData.enter(self)
base.localAvatar.chatMgr.fsm.request('otherDialog')
if self.dialog == None:
guiButton = loader.loadModel('phase_3/models/gui/quit_button')
buttons = loader.loadModel('phase_3/models/gui/dialog_box_buttons_gui')
nameBalloon = loader.loadModel('phase_3/models/props/chatbox_input')
optionsButtonImage = (guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR'))
okButtonImage = (buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr'))
cancelButtonImage = (buttons.find('**/CloseBtn_UP'), buttons.find('**/CloseBtn_DN'), buttons.find('**/CloseBtn_Rllvr'))
withParentAccount = False
try:
withParentAccount = base.cr.withParentAccount
except:
self.notify.warning('withParentAccount not found in base.cr')
if withParentAccount:
okPos = (-0.22, 0.0, -0.5)
textPos = (0, 0.25)
okCommand = self.__handleOKWithParentAccount
elif base.cr.productName != 'Terra-DMC':
okPos = (-0.22, 0.0, -0.5)
textPos = (0, 0.25)
okCommand = self.__oldHandleOK
else:
self.passwordEntry = None
okPos = (0, 0, -0.35)
textPos = (0, 0.125)
okCommand = self.__handleCancel
self.dialog = DirectFrame(parent=aspect2dp, pos=(0.0, 0.1, 0.2), relief=None, image=DGG.getDefaultDialogGeom(), image_color=OTPGlobals.GlobalDialogColor, image_scale=(1.4, 1.0, 1.25), image_pos=(0, 0, -0.1), text=OTPLocalizer.FriendSecretNeedsParentLoginWarning, text_wordwrap=21.5, text_scale=0.055, text_pos=textPos, textMayChange=1)
DirectButton(self.dialog, image=okButtonImage, relief=None, text=OTPLocalizer.FriendSecretNeedsPasswordWarningOK, text_scale=0.05, text_pos=(0.0, -0.1), textMayChange=0, pos=okPos, command=okCommand)
DirectLabel(parent=self.dialog, relief=None, pos=(0, 0, 0.35), text=OTPLocalizer.FriendSecretNeedsPasswordWarningTitle, textMayChange=0, text_scale=0.08)
if base.cr.productName != 'Terra-DMC':
self.usernameLabel = DirectLabel(parent=self.dialog, relief=None, pos=(-0.07, 0.0, -0.1), text=OTPLocalizer.ParentLogin, text_scale=0.06, text_align=TextNode.ARight, textMayChange=0)
self.usernameEntry = DirectEntry(parent=self.dialog, relief=None, image=nameBalloon, image1_color=(0.8, 0.8, 0.8, 1.0), scale=0.064, pos=(0.0, 0.0, -0.1), width=OTPGlobals.maxLoginWidth, numLines=1, focus=1, cursorKeys=1, obscured=1, command=self.__handleUsername)
self.passwordLabel = DirectLabel(parent=self.dialog, relief=None, pos=(-0.02, 0.0, -0.3), text=OTPLocalizer.ParentPassword, text_scale=0.06, text_align=TextNode.ARight, textMayChange=0)
self.passwordEntry = DirectEntry(parent=self.dialog, relief=None, image=nameBalloon, image1_color=(0.8, 0.8, 0.8, 1.0), scale=0.064, pos=(0.04, 0.0, -0.3), width=OTPGlobals.maxLoginWidth, numLines=1, focus=1, cursorKeys=1, obscured=1, command=okCommand)
DirectButton(self.dialog, image=cancelButtonImage, relief=None, text=OTPLocalizer.FriendSecretNeedsPasswordWarningCancel, text_scale=0.05, text_pos=(0.0, -0.1), textMayChange=1, pos=(0.2, 0.0, -0.5), command=self.__handleCancel)
if withParentAccount:
self.usernameEntry.enterText('')
self.usernameEntry['focus'] = 1
self.passwordEntry.enterText('')
else:
self.usernameEntry.hide()
self.usernameLabel.hide()
self.passwordEntry['focus'] = 1
self.passwordEntry.enterText('')
guiButton.removeNode()
buttons.removeNode()
nameBalloon.removeNode()
else:
self.dialog['text'] = OTPLocalizer.FriendSecretNeedsParentLoginWarning
if self.usernameEntry:
self.usernameEntry['focus'] = 1
self.usernameEntry.enterText('')
elif self.passwordEntry:
self.passwordEntry['focus'] = 1
self.passwordEntry.enterText('')
self.dialog.show()
return
def exit(self):
self.ignoreAll()
if self.dialog:
self.dialog.destroy()
self.dialog = None
if self.isEntered:
base.localAvatar.chatMgr.fsm.request('mainMenu')
StateData.StateData.exit(self)
return
def __handleUsername(self, *args):
if self.passwordEntry:
self.passwordEntry['focus'] = 1
self.passwordEntry.enterText('')
def __handleOKWithParentAccount(self, *args):
username = self.usernameEntry.get()
password = self.passwordEntry.get()
base.cr.parentUsername = username
base.cr.parentPassword = password
tt = base.cr.loginInterface
okflag, message = tt.authenticateParentUsernameAndPassword(localAvatar.DISLid, base.cr.password, username, password)
if okflag:
self.exit()
openFriendSecret(self.secretType)
elif message:
base.localAvatar.chatMgr.fsm.request('problemActivatingChat')
base.localAvatar.chatMgr.problemActivatingChat['text'] = OTPLocalizer.ProblemActivatingChat % message
else:
self.dialog['text'] = OTPLocalizer.FriendSecretNeedsPasswordWarningWrongPassword
self.passwordEntry['focus'] = 1
self.passwordEntry.enterText('')
def __oldHandleOK(self, *args):
username = self.usernameEntry.get()
password = self.passwordEntry.get()
base.cr.parentUsername = username
base.cr.parentPassword = password
tt = base.cr.loginInterface
okflag, message = tt.authenticateParentPassword(base.cr.userName, base.cr.password, password)
if okflag:
self.exit()
openFriendSecret(self.secretType)
elif message:
base.localAvatar.chatMgr.fsm.request('problemActivatingChat')
base.localAvatar.chatMgr.problemActivatingChat['text'] = OTPLocalizer.ProblemActivatingChat % message
else:
self.dialog['text'] = OTPLocalizer.FriendSecretNeedsPasswordWarningWrongPassword
self.passwordEntry['focus'] = 1
self.passwordEntry.enterText('')
def __handleOK(self, *args):
base.cr.parentUsername = self.usernameEntry.get()
base.cr.parentPassword = self.passwordEntry.get()
base.cr.playerFriendsManager.sendRequestUseLimitedSecret('', base.cr.parentUsername, base.cr.parentPassword)
self.accept(OTPGlobals.PlayerFriendRejectUseSecretEvent, self.__handleParentLogin)
self.exit()
def __handleParentLogin(self, reason):
if reason == 0:
self.exit()
openFriendSecret(self.secretType)
elif reason == 1:
self.dialog['text'] = OTPLocalizer.FriendSecretNeedsPasswordWarningWrongUsername
self.usernameEntry['focus'] = 1
self.usernameEntry.enterText('')
elif reason == 2:
self.dialog['text'] = OTPLocalizer.FriendSecretNeedsPasswordWarningWrongPassword
self.passwordEntry['focus'] = 1
self.passwordEntry.enterText('')
else:
base.localAvatar.chatMgr.fsm.request('problemActivatingChat')
base.localAvatar.chatMgr.problemActivatingChat['text'] = OTPLocalizer.ProblemActivatingChat % message
def __handleCancel(self):
self.exit()
class FriendSecret(DirectFrame, StateData.StateData):
notify = DirectNotifyGlobal.directNotify.newCategory('FriendSecret')
def __init__(self, secretType):
DirectFrame.__init__(self, parent=aspect2dp, pos=(0, 0, 0.3), relief=None, image=DGG.getDefaultDialogGeom(), image_scale=(1.6, 1, 1.4), image_pos=(0, 0, -0.05), image_color=OTPGlobals.GlobalDialogColor, borderWidth=(0.01, 0.01))
StateData.StateData.__init__(self, 'friend-secret-done')
self.initialiseoptions(FriendSecret)
self.prefix = OTPGlobals.getDefaultProductPrefix()
self.secretType = secretType
self.notify.debug('### secretType = %s' % self.secretType)
self.requestedSecretType = secretType
self.notify.debug('### requestedSecretType = %s' % self.requestedSecretType)
return
def unload(self):
if self.isLoaded == 0:
return None
self.isLoaded = 0
self.exit()
del self.introText
del self.getSecret
del self.enterSecretText
del self.enterSecret
del self.ok1
del self.ok2
del self.cancel
del self.secretText
del self.avatarButton
del self.accountButton
DirectFrame.destroy(self)
self.ignore('clientCleanup')
return None
def load(self):
if self.isLoaded == 1:
return None
self.isLoaded = 1
self.introText = DirectLabel(parent=self, relief=None, pos=(0, 0, 0.4), scale=0.05, text=OTPLocalizer.FriendSecretIntro, text_fg=(0, 0, 0, 1), text_wordwrap=30)
self.introText.hide()
guiButton = loader.loadModel('phase_3/models/gui/quit_button')
self.getSecret = DirectButton(parent=self, relief=None, pos=(0, 0, -0.11), image=(guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR')), image_scale=OTPLocalizer.FSgetSecret, text=OTPLocalizer.FriendSecretGetSecret, text_scale=OTPLocalizer.FSgetSecretButton, text_pos=(0, -0.02), command=self.__determineSecret)
self.getSecret.hide()
self.enterSecretText = DirectLabel(parent=self, relief=None, pos=OTPLocalizer.FSenterSecretTextPos, scale=0.05, text=OTPLocalizer.FriendSecretEnterSecret, text_fg=(0, 0, 0, 1), text_wordwrap=30)
self.enterSecretText.hide()
self.enterSecret = DirectEntry(parent=self, relief=DGG.SUNKEN, scale=0.06, pos=(-0.6, 0, -0.38), frameColor=(0.8, 0.8, 0.5, 1), borderWidth=(0.1, 0.1), numLines=1, width=20, frameSize=(-0.4,
20.4,
-0.4,
1.1), command=self.__enterSecret)
self.enterSecret.resetFrameSize()
self.enterSecret.hide()
self.ok1 = DirectButton(parent=self, relief=None, image=(guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR')), image_scale=OTPLocalizer.FSok1, text=OTPLocalizer.FriendSecretEnter, text_scale=0.06, text_pos=(0, -0.02), pos=(0, 0, -0.5), command=self.__ok1)
self.ok1.hide()
if base.cr.productName in ['JP',
'DE',
'BR',
'FR']:
class ShowHide:
def show(self):
pass
def hide(self):
pass
self.changeOptions = ShowHide()
self.ok2 = DirectButton(parent=self, relief=None, image=(guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR')), image_scale=OTPLocalizer.FSok2, text=OTPLocalizer.FriendSecretOK, text_scale=0.06, text_pos=(0, -0.02), pos=(0, 0, -0.57), command=self.__ok2)
self.ok2.hide()
self.cancel = DirectButton(parent=self, relief=None, text=OTPLocalizer.FriendSecretCancel, image=(guiButton.find('**/QuitBtn_UP'), guiButton.find('**/QuitBtn_DN'), guiButton.find('**/QuitBtn_RLVR')), image_scale=OTPLocalizer.FScancel, text_scale=0.06, text_pos=(0, -0.02), pos=(0, 0, -0.57), command=self.__cancel)
self.cancel.hide()
self.nextText = DirectLabel(parent=self, relief=None, pos=(0, 0, 0.3), scale=0.06, text='', text_scale=OTPLocalizer.FSnextText, text_fg=(0, 0, 0, 1), text_wordwrap=25.5)
self.nextText.hide()
self.secretText = DirectLabel(parent=self, relief=None, pos=(0, 0, -0.42), scale=0.1, text='', text_fg=(0, 0, 0, 1), text_wordwrap=30)
self.secretText.hide()
guiButton.removeNode()
self.makeFriendTypeButtons()
self.accept('clientCleanup', self.__handleCleanup)
self.accept('walkDone', self.__handleStop)
def __handleStop(self, message):
self.exit()
def __handleCleanup(self):
self.unload()
def makeFriendTypeButtons(self):
buttons = loader.loadModel('phase_3/models/gui/dialog_box_buttons_gui')
self.avatarButton = DirectButton(self, image=(buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr')), relief=None, text=OTPLocalizer.FriendSecretDetermineSecretAvatar, text_scale=0.07, text_pos=(0.0, -0.1), pos=(-0.35, 0.0, -0.05), command=self.__handleAvatar)
avatarText = DirectLabel(parent=self, relief=None, pos=Vec3(0.35, 0, -0.3), text=OTPLocalizer.FriendSecretDetermineSecretAvatarRollover, text_fg=(0, 0, 0, 1), text_pos=(0, 0), text_scale=0.055, text_align=TextNode.ACenter)
avatarText.reparentTo(self.avatarButton.stateNodePath[2])
self.avatarButton.hide()
self.accountButton = DirectButton(self, image=(buttons.find('**/ChtBx_OKBtn_UP'), buttons.find('**/ChtBx_OKBtn_DN'), buttons.find('**/ChtBx_OKBtn_Rllvr')), relief=None, text=OTPLocalizer.FriendSecretDetermineSecretAccount, text_scale=0.07, text_pos=(0.0, -0.1), pos=(0.35, 0.0, -0.05), command=self.__handleAccount)
accountText = DirectLabel(parent=self, relief=None, pos=Vec3(-0.35, 0, -0.3), text=OTPLocalizer.FriendSecretDetermineSecretAccountRollover, text_fg=(0, 0, 0, 1), text_pos=(0, 0), text_scale=0.055, text_align=TextNode.ACenter)
accountText.reparentTo(self.accountButton.stateNodePath[2])
self.accountButton.hide()
buttons.removeNode()
return
def enter(self):
if self.isEntered == 1:
return
self.isEntered = 1
if self.isLoaded == 0:
self.load()
self.show()
self.introText.show()
self.getSecret.show()
self.enterSecretText.show()
self.enterSecret.show()
self.ok1.show()
self.ok2.hide()
self.cancel.hide()
self.nextText.hide()
self.secretText.hide()
base.localAvatar.chatMgr.fsm.request('otherDialog')
self.enterSecret['focus'] = 1
NametagGlobals.setOnscreenChatForced(1)
def exit(self):
if self.isEntered == 0:
return
self.isEntered = 0
NametagGlobals.setOnscreenChatForced(0)
self.__cleanupFirstPage()
self.ignoreAll()
self.accept('clientCleanup', self.unload)
self.hide()
def __determineSecret(self):
if self.secretType == BothSecrets:
self.__cleanupFirstPage()
self.ok1.hide()
self.nextText['text'] = OTPLocalizer.FriendSecretDetermineSecret
self.nextText.setPos(0, 0, 0.3)
self.nextText.show()
self.avatarButton.show()
self.accountButton.show()
self.cancel.show()
else:
self.__getSecret()
def __handleAvatar(self):
self.requestedSecretType = AvatarSecret
self.__getSecret()
def __handleAccount(self):
self.requestedSecretType = AccountSecret
self.__getSecret()
def __handleCancel(self):
self.exit()
def __getSecret(self):
self.__cleanupFirstPage()
self.nextText['text'] = OTPLocalizer.FriendSecretGettingSecret
self.nextText.setPos(0, 0, 0.3)
self.nextText.show()
self.avatarButton.hide()
self.accountButton.hide()
self.ok1.hide()
self.cancel.show()
if self.requestedSecretType == AvatarSecret:
if not base.cr.friendManager:
self.notify.warning('No FriendManager available.')
self.exit()
return
base.cr.friendManager.up_requestSecret()
self.accept('requestSecretResponse', self.__gotAvatarSecret)
else:
if base.cr.needParentPasswordForSecretChat():
self.notify.info('### requestLimitedSecret')
base.cr.playerFriendsManager.sendRequestLimitedSecret(base.cr.parentUsername, base.cr.parentPassword)
else:
base.cr.playerFriendsManager.sendRequestUnlimitedSecret()
self.notify.info('### requestUnlimitedSecret')
self.accept(OTPGlobals.PlayerFriendNewSecretEvent, self.__gotAccountSecret)
self.accept(OTPGlobals.PlayerFriendRejectNewSecretEvent, self.__rejectAccountSecret)
def __gotAvatarSecret(self, result, secret):
self.ignore('requestSecretResponse')
if result == 1:
self.nextText['text'] = OTPLocalizer.FriendSecretGotSecret
self.nextText.setPos(*OTPLocalizer.FSgotSecretPos)
if self.prefix:
self.secretText['text'] = self.prefix + ' ' + secret
else:
self.secretText['text'] = secret
else:
self.nextText['text'] = OTPLocalizer.FriendSecretTooMany
self.nextText.show()
self.secretText.show()
self.cancel.hide()
self.ok1.hide()
self.ok2.show()
def __gotAccountSecret(self, secret):
self.ignore(OTPGlobals.PlayerFriendNewSecretEvent)
self.ignore(OTPGlobals.PlayerFriendRejectNewSecretEvent)
self.nextText['text'] = OTPLocalizer.FriendSecretGotSecret
self.nextText.setPos(0, 0, 0.47)
self.secretText['text'] = secret
self.nextText.show()
self.secretText.show()
self.cancel.hide()
self.ok1.hide()
self.ok2.show()
def __rejectAccountSecret(self, reason):
print '## rejectAccountSecret: reason = ', reason
self.ignore(OTPGlobals.PlayerFriendNewSecretEvent)
self.ignore(OTPGlobals.PlayerFriendRejectNewSecretEvent)
self.nextText['text'] = OTPLocalizer.FriendSecretTooMany
self.nextText.show()
self.secretText.show()
self.cancel.hide()
self.ok1.hide()
self.ok2.show()
def __enterSecret(self, secret):
self.enterSecret.set('')
secret = string.strip(secret)
if not secret:
self.exit()
return
if not base.cr.friendManager:
self.notify.warning('No FriendManager available.')
self.exit()
return
self.__cleanupFirstPage()
if self.prefix:
if secret[0:2] == self.prefix:
secret = secret[3:]
self.notify.info('### use TT secret')
self.accept('submitSecretResponse', self.__enteredSecret)
base.cr.friendManager.up_submitSecret(secret)
else:
self.accept(OTPGlobals.PlayerFriendUpdateEvent, self.__useAccountSecret)
self.accept(OTPGlobals.PlayerFriendRejectUseSecretEvent, self.__rejectUseAccountSecret)
if base.cr.needParentPasswordForSecretChat():
self.notify.info('### useLimitedSecret')
base.cr.playerFriendsManager.sendRequestUseLimitedSecret(secret, base.cr.parentUsername, base.cr.parentPassword)
else:
self.notify.info('### useUnlimitedSecret')
base.cr.playerFriendsManager.sendRequestUseUnlimitedSecret(secret)
self.nextText['text'] = OTPLocalizer.FriendSecretTryingSecret
self.nextText.setPos(0, 0, 0.3)
self.nextText.show()
self.ok1.hide()
self.cancel.show()
def __enteredSecret(self, result, avId):
self.ignore('submitSecretResponse')
if result == 1:
handle = base.cr.identifyAvatar(avId)
if handle != None:
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretSuccess % handle.getName()
else:
self.accept('friendsMapComplete', self.__nowFriends, [avId])
ready = base.cr.fillUpFriendsMap()
if ready:
self.__nowFriends(avId)
return
elif result == 0:
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretUnknown
elif result == 2:
handle = base.cr.identifyAvatar(avId)
if handle != None:
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretFull % handle.getName()
else:
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretFullNoName
elif result == 3:
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretSelf
elif result == 4:
self.nextText['text'] = OTPLocalizer.FriendSecretEnteredSecretWrongProduct % self.prefix
self.nextText.show()
self.cancel.hide()
self.ok1.hide()
self.ok2.show()
return
def __useAccountSecret(self, avId, friendInfo):
self.ignore(OTPGlobals.PlayerFriendUpdateEvent)
self.ignore(OTPGlobals.PlayerFriendRejectUseSecretEvent)
self.__enteredSecret(1, 0)
def __rejectUseAccountSecret(self, reason):
print '## rejectUseAccountSecret: reason = ', reason
self.ignore(OTPGlobals.PlayerFriendUpdateEvent)
self.ignore(OTPGlobals.PlayerFriendRejectUseSecretEvent)
if reason == RejectCode.RejectCode.FRIENDS_LIST_FULL:
self.__enteredSecret(2, 0)
elif reason == RejectCode.RejectCode.ALREADY_FRIENDS_WITH_SELF:
self.__enteredSecret(3, 0)
else:
self.__enteredSecret(0, 0)
def __nowFriends(self, avId):
self.ignore('friendsMapComplete')
handle = base.cr.identifyAvatar(avId)
if handle != None:
self.nextText['text'] = OTPLocalizer.FriendSecretNowFriends % handle.getName()
else:
self.nextText['text'] = OTPLocalizer.FriendSecretNowFriendsNoName
self.nextText.show()
self.cancel.hide()
self.ok1.hide()
self.ok2.show()
return
def __ok1(self):
secret = self.enterSecret.get()
self.__enterSecret(secret)
def __ok2(self):
self.exit()
def __cancel(self):
self.exit()
def __cleanupFirstPage(self):
self.introText.hide()
self.getSecret.hide()
self.enterSecretText.hide()
self.enterSecret.hide()
base.localAvatar.chatMgr.fsm.request('mainMenu')

407
otp/friends/GuildManager.py Normal file
View file

@ -0,0 +1,407 @@
from direct.distributed.DistributedObjectGlobal import DistributedObjectGlobal
from direct.directnotify.DirectNotifyGlobal import directNotify
from otp.distributed import OtpDoGlobals
from otp.otpbase import OTPLocalizer
from otp.otpbase import OTPGlobals
from otp.avatar.AvatarHandle import AvatarHandle
from otp.ai import AIInterestHandles
GUILDRANK_VETERAN = 4
GUILDRANK_GM = 3
GUILDRANK_OFFICER = 2
GUILDRANK_MEMBER = 1
import Queue
class GuildMemberInfo(AvatarHandle):
def __init__(self, name, isOnline, rank, bandId):
self.name = name
self.rank = rank
self.bandId = bandId
self.onlineYesNo = isOnline
def getName(self):
return self.name
def getRank(self):
return self.rank
def getBandId(self):
return self.bandId
def isOnline(self):
return self.onlineYesNo
def isUnderstandable(self):
return True
@report(types=['deltaStamp', 'args'], dConfigParam='teleport')
def sendTeleportQuery(self, sendToId, localBandMgrId, localBandId, localGuildId, localShardId):
base.cr.guildManager.d_reflectTeleportQuery(sendToId, localBandMgrId, localBandId, localGuildId, localShardId)
@report(types=['deltaStamp', 'args'], dConfigParam='teleport')
def sendTeleportResponse(self, available, shardId, instanceDoId, areaDoId, sendToId = None):
base.cr.guildManager.d_reflectTeleportResponse(available, shardId, instanceDoId, areaDoId, sendToId)
class GuildManager(DistributedObjectGlobal):
notify = directNotify.newCategory('GuildManager')
def __init__(self, cr):
DistributedObjectGlobal.__init__(self, cr)
self.id2Name = {}
self.id2BandId = {}
self.id2Rank = {}
self.id2Online = {}
self.pendingMsgs = []
self.whiteListEnabled = base.config.GetBool('whitelist-chat-enabled', 1)
self.emailNotification = 0
self.emailNotificationAddress = None
self.receivingNewList = False
self.spamGateOpen = True
return
def _allowMemberList(self, task):
self.spamGateOpen = True
return task.done
def memberList(self):
if self.spamGateOpen:
self.sendUpdate('memberList', [])
self.spamGateOpen = False
taskMgr.doMethodLater(60.0, self._allowMemberList, 'allowMemberList')
def createGuild(self):
messenger.send('declineGuildInvitation')
self.sendUpdate('createGuild', [])
def setWantName(self, newName):
self.sendUpdate('setWantName', [newName])
def removeMember(self, avatarId):
self.sendUpdate('removeMember', [avatarId])
def changeRank(self, avatarId, rank):
self.sendUpdate('changeRank', [avatarId, rank])
def changeRankAvocate(self, avatarId):
self.sendUpdate('changeRankAvocate', [avatarId])
def statusRequest(self):
self.sendUpdate('statusRequest', [])
def requestLeaderboardTopTen(self):
self.sendUpdate('requestLeaderboardTopTen', [])
def sendRequestInvite(self, avatarId):
self.sendUpdate('requestInvite', [avatarId])
def sendAcceptInvite(self):
self.sendUpdate('acceptInvite', [])
def sendDeclineInvite(self):
self.sendUpdate('declineInvite', [])
def sendTalk(self, msgText, chatFlags = 0):
self.sendUpdate('setTalkGroup', [0,
0,
'',
msgText,
[],
0])
def setTalkGroup(self, fromAv, fromAC, avatarName, chat, mods, flags):
if hasattr(base, 'localAvatar'):
message, scrubbed = localAvatar.scrubTalk(chat, mods)
base.talkAssistant.receiveGuildTalk(fromAv, fromAC, avatarName, message, scrubbed)
def sendSC(self, msgIndex):
self.sendUpdate('sendSC', [msgIndex])
def sendSCQuest(self, questInt, msgType, taskNum):
self.sendUpdate('sendSCQuest', [questInt, msgType, taskNum])
def sendTokenRequest(self):
self.sendUpdate('sendTokenRequest', [])
def sendTokenForJoinRequest(self, token):
name = base.localAvatar.getName()
self.sendUpdate('sendTokenForJoinRequest', [token, name])
def isInGuild(self, avId):
return avId in self.id2Name
def getRank(self, avId):
return self.id2Rank.get(avId)
def getBandId(self, avId):
return self.id2BandId.get(avId)
def getMemberInfo(self, avId):
if self.isInGuild(avId):
return GuildMemberInfo(self.id2Name[avId], self.id2Online[avId], self.id2Rank[avId], self.id2BandId[avId])
return None
def getOptionsFor(self, avId):
if self.isInGuild(avId):
myRank = self.id2Rank.get(localAvatar.doId, localAvatar.getGuildRank())
hisRank = self.id2Rank[avId]
canpromote = False
candemote = False
cankick = False
if myRank == GUILDRANK_GM:
canpromote = True
candemote = True
cankick = True
if myRank > GUILDRANK_MEMBER and myRank != GUILDRANK_VETERAN and (hisRank <= GUILDRANK_MEMBER or hisRank == GUILDRANK_VETERAN):
cankick = True
return (canpromote, candemote, cankick)
else:
return None
return None
def updateTokenRValue(self, tokenString, rValue):
rValue = int(rValue)
self.sendUpdate('sendTokenRValue', [tokenString, rValue])
if rValue == -1:
base.localAvatar.guiMgr.guildPage.receivePermTokenValue(tokenString)
def requestPermToken(self):
self.sendUpdate('sendPermToken', [])
def requestNonPermTokenCount(self):
self.sendUpdate('sendNonPermTokenCount', [])
def requestClearTokens(self, type):
self.sendUpdate('sendClearTokens', [type])
def receiveMember(self, member):
if not self.receivingNewList:
self.receivingNewList = True
self.newList = []
self.newList.append(member)
def clearMembers(self):
self.newList = []
self.receiveMembersDone()
def receiveMembersDone(self):
self.receivingNewList = False
memberlist = self.newList
self.newList = []
self.id2Name = {}
self.id2Rank = {}
self.id2BandId = {}
for guy in memberlist:
id = guy[0]
name = guy[1]
rank = guy[2]
isOnline = guy[3]
self.id2Name[id] = name
self.id2Rank[id] = rank
self.id2Online[id] = isOnline
self.id2BandId[id] = tuple(guy[4:6])
for id, msg in self.pendingMsgs:
if not self.cr.avatarFriendsManager.checkIgnored(id):
base.talkAssistant.receiveGuildMessage(msg, id, self.id2Name.get(id, 'Unknown'))
if localAvatar.getGuildId():
self.accept(self.cr.StopVisibilityEvent, self.handleLogout)
else:
self.ignore(self.cr.StopVisibilityEvent)
if hasattr(base, 'localAvatar'):
base.localAvatar.guiMgr.guildPage.receiveMembers(memberlist)
messenger.send('guildMemberUpdated', sentArgs=[localAvatar.doId])
def guildStatusUpdate(self, guildId, guildName, guildRank):
if hasattr(base, 'localAvatar'):
base.localAvatar.guildStatusUpdate(guildId, guildName, guildRank)
self.memberList()
def guildNameReject(self, guildId):
if hasattr(base, 'localAvatar'):
base.localAvatar.guildNameReject(guildId)
def guildNameChange(self, guildName, changeStatus):
if hasattr(base, 'localAvatar'):
base.localAvatar.guildNameChange(guildName, changeStatus)
def guildNameUpdate(self, avatarId, guildName):
print 'DEBUG - guildNameUpdate for ', avatarId, ' to ', guildName
def invitationFrom(self, avatarId, avatarName, guildId, guildName):
print 'GM invitationFrom %s(%d)' % (avatarName, avatarId)
if hasattr(base, 'localAvatar'):
base.localAvatar.guiMgr.handleGuildInvitation(avatarId, avatarName, guildId, guildName)
def retractInvite(self, avatarId):
print 'GM retraction'
def guildAcceptInvite(self, avatarId):
print 'sending accept event'
messenger.send(OTPGlobals.GuildAcceptInviteEvent, [avatarId])
def leaderboardTopTen(self, stuff):
base.localAvatar.guiMgr.handleTopTen(stuff)
def guildRejectInvite(self, avatarId, reason):
messenger.send(OTPGlobals.GuildRejectInviteEvent, [avatarId, reason])
def rejectInvite(self, avatarId, reason):
pass
def recvSC(self, senderId, msgIndex):
senderName = self.id2Name.get(senderId, None)
if senderName:
if not self.cr.avatarFriendsManager.checkIgnored(senderId):
displayMess = '%s %s %s' % (senderName, OTPLocalizer.GuildPrefix, OTPLocalizer.SpeedChatStaticText[msgIndex])
message = OTPLocalizer.SpeedChatStaticText[msgIndex]
base.talkAssistant.receiveGuildMessage(message, senderId, senderName)
else:
self.pendingMsgs.append([senderId, OTPLocalizer.SpeedChatStaticText[msgIndex]])
self.memberList()
return
def recvSCQuest(self, senderId, questInt, msgType, taskNum):
senderName = self.id2Name.get(senderId, None)
message = base.talkAssistant.SCDecoder.decodeSCQuestMsgInt(questInt, msgType, taskNum)
if senderName:
if not self.cr.avatarFriendsManager.checkIgnored(senderId):
displayMess = '%s %s %s' % (senderName, OTPLocalizer.GuildPrefix, message)
base.talkAssistant.receiveGuildMessage(message, senderId, senderName)
else:
self.pendingMsgs.append([senderId, message])
self.memberList()
return
def recvAvatarOnline(self, avatarId, avatarName, bandManagerId, bandId):
self.id2Online[avatarId] = True
if hasattr(base, 'localAvatar') and avatarId != base.localAvatar.doId:
if not self.cr.avatarFriendsManager.checkIgnored(avatarId):
base.talkAssistant.receiveGuildUpdate(avatarId, avatarName, True)
else:
return
messenger.send('guildMemberOnlineStatus', [avatarId, 1])
def recvAvatarOffline(self, avatarId, avatarName):
self.id2BandId[avatarId] = (0, 0)
self.id2Online[avatarId] = False
if hasattr(base, 'localAvatar') and avatarId != base.localAvatar.doId:
if not self.cr.avatarFriendsManager.checkIgnored(avatarId):
base.talkAssistant.receiveGuildUpdate(avatarId, avatarName, False)
messenger.send('guildMemberOnlineStatus', [avatarId, 0])
def recvMemberAdded(self, memberInfo, inviterId, inviterName):
avatarId, avatarName, rank, isOnline, bandManagerId, bandId = memberInfo
self.id2Name[avatarId] = avatarName
self.id2Rank[avatarId] = rank
self.id2BandId[avatarId] = (bandManagerId, bandId)
self.id2Online[avatarId] = isOnline
if hasattr(base, 'localAvatar'):
base.localAvatar.guiMgr.guildPage.addMember(memberInfo)
messenger.send('guildMemberUpdated', sentArgs=[avatarId])
def recvMemberRemoved(self, avatarId, senderId, avatarName, senderName):
if avatarId == localAvatar.doId:
self.clearMembers()
else:
self.id2Name.pop(avatarId, None)
self.id2Rank.pop(avatarId, None)
self.id2BandId.pop(avatarId, None)
self.id2Online.pop(avatarId, None)
if hasattr(base, 'localAvatar'):
base.localAvatar.guiMgr.guildPage.removeMember(avatarId)
messenger.send('guildMemberUpdated', sentArgs=[avatarId])
return
def recvMemberUpdateRank(self, avatarId, senderId, avatarName, senderName, rank, promote):
self.id2Rank[avatarId] = rank
if hasattr(base, 'localAvatar') and base.localAvatar.guiMgr:
base.localAvatar.guiMgr.guildPage.updateGuildMemberRank(avatarId, rank)
messenger.send('guildMemberUpdated', sentArgs=[avatarId])
def recvMemberUpdateBandId(self, avatarId, bandManagerId, bandId):
self.id2BandId[avatarId] = (bandManagerId, bandId)
messenger.send('guildMemberUpdated', sentArgs=[avatarId])
def recvTokenInviteValue(self, tokenValue, preExistPerm):
if hasattr(base, 'localAvatar') and base.localAvatar.guiMgr:
base.localAvatar.guiMgr.guildPage.displayInviteGuild(tokenValue, preExistPerm)
def recvTokenRedeemMessage(self, guildName):
if hasattr(base, 'localAvatar') and base.localAvatar.guiMgr:
if guildName == '***ERROR - GUILD CODE INVALID***':
base.localAvatar.guiMgr.guildPage.displayRedeemErrorMessage(OTPLocalizer.GuildRedeemErrorInvalidToken)
elif guildName == '***ERROR - GUILD FULL***':
base.localAvatar.guiMgr.guildPage.displayRedeemErrorMessage(OTPLocalizer.GuildRedeemErrorGuildFull)
else:
base.localAvatar.guiMgr.guildPage.displayRedeemConfirmMessage(guildName)
def recvTokenRedeemedByPlayerMessage(self, redeemerName):
if hasattr(base, 'localAvatar') and base.localAvatar.guiMgr:
base.localAvatar.guiMgr.guildPage.notifyTokenGeneratorOfRedeem(redeemerName)
def recvPermToken(self, token):
if hasattr(base, 'localAvatar') and base.localAvatar.guiMgr:
if token == '0':
base.localAvatar.guiMgr.guildPage.receivePermTokenValue(None)
else:
base.localAvatar.guiMgr.guildPage.receivePermTokenValue(token)
return
def requestEmailNotificationPref(self):
self.sendUpdate('sendRequestEmailNotificationPref', [])
def respondEmailNotificationPref(self, notify, emailAddress):
self.emailNotification = notify
if emailAddress == 'None':
self.emailNotificationAddress = None
else:
self.emailNotificationAddress = emailAddress
return
def getEmailNotificationPref(self):
return [self.emailNotification, self.emailNotificationAddress]
def requestEmailNotificationPrefUpdate(self, notify, emailAddress):
self.sendUpdate('sendEmailNotificationPrefUpdate', [notify, emailAddress])
self.emailNotification = notify
if emailAddress == 'None':
self.emailNotificationAddress = None
else:
self.emailNotificationAddress = emailAddress
return
def recvNonPermTokenCount(self, tCount):
if hasattr(base, 'localAvatar') and base.localAvatar.guiMgr:
base.localAvatar.guiMgr.guildPage.receiveNonPermTokenCount(tCount)
@report(types=['deltaStamp', 'args'], dConfigParam='teleport')
def d_reflectTeleportQuery(self, sendToId, localBandMgrId, localBandId, localGuildId, localShardId):
self.sendUpdate('reflectTeleportQuery', [sendToId,
localBandMgrId,
localBandId,
localGuildId,
localShardId])
@report(types=['deltaStamp', 'args'], dConfigParam='teleport')
def teleportQuery(self, requesterId, requesterBandMgrId, requesterBandId, requesterGuildId, requesterShardId):
if self.cr.teleportMgr:
self.cr.teleportMgr.handleAvatarTeleportQuery(requesterId, requesterBandMgrId, requesterBandId, requesterGuildId, requesterShardId)
@report(types=['deltaStamp', 'args'], dConfigParam='teleport')
def d_reflectTeleportResponse(self, available, shardId, instanceDoId, areaDoId, sendToId):
self.sendUpdate('reflectTeleportResponse', [sendToId,
available,
shardId,
instanceDoId,
areaDoId])
@report(types=['deltaStamp', 'args'], dConfigParam='teleport')
def teleportResponse(self, responderId, available, shardId, instanceDoId, areaDoId):
if self.cr.teleportMgr:
self.cr.teleportMgr.handleAvatarTeleportResponse(responderId, available, shardId, instanceDoId, areaDoId)
@report(types=['args'], dConfigParam='guildmgr')
def handleLogout(self, *args, **kw):
self.cr.removeAIInterest(AIInterestHandles.PIRATES_GUILD)

View file

@ -0,0 +1,263 @@
from direct.distributed.DistributedObjectGlobal import DistributedObjectGlobal
from direct.directnotify.DirectNotifyGlobal import directNotify
from otp.otpbase import OTPGlobals
from otp.avatar.Avatar import teleportNotify
from otp.friends import FriendResponseCodes
class PlayerFriendsManager(DistributedObjectGlobal):
notify = directNotify.newCategory('PlayerFriendsManager')
def __init__(self, cr):
DistributedObjectGlobal.__init__(self, cr)
self.playerFriendsList = set()
self.playerId2Info = {}
self.playerAvId2avInfo = {}
self.accept('gotExtraFriendHandles', self.__handleFriendHandles)
def delete(self):
self.ignoreAll()
def sendRequestInvite(self, playerId):
print 'PFM sendRequestInvite id:%s' % playerId
self.sendUpdate('requestInvite', [0, playerId, True])
def sendRequestDecline(self, playerId):
self.sendUpdate('requestDecline', [0, playerId])
def sendRequestRemove(self, playerId):
self.sendUpdate('requestRemove', [0, playerId])
def sendRequestUnlimitedSecret(self):
self.sendUpdate('requestUnlimitedSecret', [0])
def sendRequestLimitedSecret(self, username, password):
self.sendUpdate('requestLimitedSecret', [0, username, password])
def sendRequestUseUnlimitedSecret(self, secret):
pass
def sendRequestUseLimitedSecret(self, secret, username, password):
pass
def sendSCWhisper(self, recipientId, msgId):
self.sendUpdate('whisperSCTo', [0, recipientId, msgId])
def sendSCCustomWhisper(self, recipientId, msgId):
self.sendUpdate('whisperSCCustomTo', [0, recipientId, msgId])
def sendSCEmoteWhisper(self, recipientId, msgId):
self.sendUpdate('whisperSCEmoteTo', [0, recipientId, msgId])
def setTalkAccount(self, toAc, fromAc, fromName, message, mods, flags):
localAvatar.displayTalkAccount(fromAc, fromName, message, mods)
toName = None
friendInfo = self.getFriendInfo(toAc)
if friendInfo:
toName = friendInfo.playerName
elif toAc == localAvatar.DISLid:
toName = localAvatar.getName()
base.talkAssistant.receiveAccountTalk(None, None, fromAc, fromName, toAc, toName, message)
return
def invitationFrom(self, playerId, avatarName):
messenger.send(OTPGlobals.PlayerFriendInvitationEvent, [playerId, avatarName])
def retractInvite(self, playerId):
messenger.send(OTPGlobals.PlayerFriendRetractInviteEvent, [playerId])
def rejectInvite(self, playerId, reason):
messenger.send(OTPGlobals.PlayerFriendRejectInviteEvent, [playerId, reason])
def rejectRemove(self, playerId, reason):
messenger.send(OTPGlobals.PlayerFriendRejectRemoveEvent, [playerId, reason])
def secretResponse(self, secret):
print 'secretResponse %s' % secret
messenger.send(OTPGlobals.PlayerFriendNewSecretEvent, [secret])
def rejectSecret(self, reason):
print 'rejectSecret %s' % reason
messenger.send(OTPGlobals.PlayerFriendRejectNewSecretEvent, [reason])
def rejectUseSecret(self, reason):
print 'rejectUseSecret %s' % reason
messenger.send(OTPGlobals.PlayerFriendRejectUseSecretEvent, [reason])
def invitationResponse(self, playerId, respCode, context):
if respCode == FriendResponseCodes.INVITATION_RESP_DECLINE:
messenger.send(OTPGlobals.PlayerFriendRejectInviteEvent, [playerId, respCode])
elif respCode == FriendResponseCodes.INVITATION_RESP_NEW_FRIENDS:
pass
def updatePlayerFriend(self, id, info, isNewFriend):
self.notify.warning('updatePlayerFriend: %s, %s, %s' % (id, info, isNewFriend))
info.calcUnderstandableYesNo()
if info.playerName[0:5] == 'Guest':
info.playerName = 'Guest ' + info.playerName[5:]
if id not in self.playerFriendsList:
self.playerFriendsList.add(id)
self.playerId2Info[id] = info
messenger.send(OTPGlobals.PlayerFriendAddEvent, [id, info, isNewFriend])
elif self.playerId2Info.has_key(id):
if not self.playerId2Info[id].onlineYesNo and info.onlineYesNo:
self.playerId2Info[id] = info
messenger.send('playerOnline', [id])
base.talkAssistant.receiveFriendAccountUpdate(id, info.playerName, info.onlineYesNo)
elif self.playerId2Info[id].onlineYesNo and not info.onlineYesNo:
self.playerId2Info[id] = info
messenger.send('playerOffline', [id])
base.talkAssistant.receiveFriendAccountUpdate(id, info.playerName, info.onlineYesNo)
if not self.askAvatarKnownHere(info.avatarId):
self.requestAvatarInfo(info.avatarId)
self.playerId2Info[id] = info
av = base.cr.doId2do.get(info.avatarId, None)
if av is not None:
av.considerUnderstandable()
messenger.send(OTPGlobals.PlayerFriendUpdateEvent, [id, info])
return
def removePlayerFriend(self, id):
if id not in self.playerFriendsList:
return
self.playerFriendsList.remove(id)
info = self.playerId2Info.pop(id, None)
if info is not None:
av = base.cr.doId2do.get(info.avatarId, None)
if av is not None:
av.considerUnderstandable()
messenger.send(OTPGlobals.PlayerFriendRemoveEvent, [id])
return
def whisperSCFrom(self, playerId, msg):
base.talkAssistant.receivePlayerWhisperSpeedChat(msg, playerId)
def isFriend(self, pId):
return self.isPlayerFriend(pId)
def isPlayerFriend(self, pId):
if not pId:
return 0
return pId in self.playerFriendsList
def isAvatarOwnerPlayerFriend(self, avId):
pId = self.findPlayerIdFromAvId(avId)
if pId and self.isPlayerFriend(pId):
return True
else:
return False
def getFriendInfo(self, pId):
return self.playerId2Info.get(pId)
def findPlayerIdFromAvId(self, avId):
for playerId in self.playerId2Info:
if self.playerId2Info[playerId].avatarId == avId:
if self.playerId2Info[playerId].onlineYesNo:
return playerId
return None
def findAvIdFromPlayerId(self, pId):
pInfo = self.playerId2Info.get(pId)
if pInfo:
return pInfo.avatarId
else:
return None
return None
def findPlayerInfoFromAvId(self, avId):
playerId = self.findPlayerIdFromAvId(avId)
if playerId:
return self.getFriendInfo(playerId)
else:
return None
return None
def askAvatarOnline(self, avId):
returnValue = 0
if self.cr.doId2do.has_key(avId):
returnValue = 1
if self.playerAvId2avInfo.has_key(avId):
playerId = self.findPlayerIdFromAvId(avId)
if self.playerId2Info.has_key(playerId):
playerInfo = self.playerId2Info[playerId]
if playerInfo.onlineYesNo:
returnValue = 1
return returnValue
def countTrueFriends(self):
count = 0
for id in self.playerId2Info:
if self.playerId2Info[id].openChatFriendshipYesNo:
count += 1
return count
def askTransientFriend(self, avId):
if self.playerAvId2avInfo.has_key(avId) and not base.cr.isAvatarFriend(avId):
return 1
else:
return 0
def askAvatarKnown(self, avId):
if self.askAvatarKnownElseWhere(avId) or self.askAvatarKnownHere(avId):
return 1
else:
return 0
def askAvatarKnownElseWhere(self, avId):
if hasattr(base, 'cr'):
if base.cr.askAvatarKnown(avId):
return 1
return 0
def askAvatarKnownHere(self, avId):
if self.playerAvId2avInfo.has_key(avId):
return 1
else:
return 0
def requestAvatarInfo(self, avId):
if hasattr(base, 'cr'):
base.cr.queueRequestAvatarInfo(avId)
def __handleFriendHandles(self, handleList):
for handle in handleList:
self.playerAvId2avInfo[handle.getDoId()] = handle
messenger.send('friendsListChanged')
def getAvHandleFromId(self, avId):
if self.playerAvId2avInfo.has_key(avId):
return self.playerAvId2avInfo[avId]
else:
return None
return None
def identifyFriend(self, avId):
handle = None
teleportNotify.debug('identifyFriend(%s)' % avId)
handle = base.cr.identifyFriend(avId)
if not handle:
teleportNotify.debug('getAvHandleFromId(%s)' % avId)
handle = self.getAvHandleFromId(avId)
return handle
def getAllOnlinePlayerAvatars(self):
returnList = []
for avatarId in self.playerAvId2avInfo:
playerId = self.findPlayerIdFromAvId(avatarId)
if playerId:
if self.playerId2Info[playerId].onlineYesNo:
returnList.append(avatarId)
return returnList
def identifyAvatar(self, doId):
if base.cr.doId2do.has_key(doId):
return base.cr.doId2do[doId]
else:
return self.identifyFriend(doId)
def friendsListFull(self):
return len(self.playerFriendsList) >= OTPGlobals.MaxPlayerFriends

0
otp/friends/__init__.py Normal file
View file

View file

@ -0,0 +1,28 @@
from direct.task import Task
from otp.otpbase import OTPLocalizer
from direct.gui.DirectGui import *
from pandac.PandaModules import *
from direct.showbase.DirectObject import DirectObject
class DownloadWatcher(DirectObject):
def __init__(self, phaseNames):
self.phaseNames = phaseNames
self.text = DirectLabel(relief=None, guiId='DownloadWatcherText', pos=(-0.96, 0, -0.91), text=OTPLocalizer.DownloadWatcherInitializing, text_fg=(1, 1, 1, 1), text_scale=0.05, textMayChange=1, text_align=TextNode.ALeft, sortOrder=50)
self.bar = DirectWaitBar(guiId='DownloadWatcherBar', pos=(-0.81, 0, -0.96), relief=DGG.SUNKEN, frameSize=(-0.6,
0.6,
-0.1,
0.1), borderWidth=(0.02, 0.02), scale=0.25, range=100, sortOrder=50, frameColor=(0.5, 0.5, 0.5, 0.5), barColor=(0.2, 0.7, 0.2, 0.5), text='0%', text_scale=0.16, text_fg=(1, 1, 1, 1), text_align=TextNode.ACenter, text_pos=(0, -0.05))
self.accept('launcherPercentPhaseComplete', self.update)
return
def update(self, phase, percent, reqByteRate, actualByteRate):
phaseName = self.phaseNames[phase]
self.text['text'] = OTPLocalizer.DownloadWatcherUpdate % phaseName
self.bar['text'] = '%s %%' % percent
self.bar['value'] = percent
def cleanup(self):
self.text.destroy()
self.bar.destroy()
self.ignoreAll()

View file

@ -0,0 +1,157 @@
from pandac.PandaModules import *
import string
from direct.showbase.MessengerGlobal import *
from direct.showbase.DirectObject import DirectObject
from direct.showbase.EventManagerGlobal import *
from direct.task.TaskManagerGlobal import *
from direct.task.Task import Task
class DummyLauncherBase:
def __init__(self):
self.logPrefix = ''
self._downloadComplete = False
self.phaseComplete = {}
for phase in self.LauncherPhases:
self.phaseComplete[phase] = 0
self.firstPhase = self.LauncherPhases[0]
self.finalPhase = self.LauncherPhases[-1]
self.launcherFileDbHash = HashVal()
self.serverDbFileHash = HashVal()
self.setPandaErrorCode(0)
self.setServerVersion('dev')
def isDummy(self):
return 1
def startFakeDownload(self):
if ConfigVariableBool('fake-downloads', 0).getValue():
duration = ConfigVariableDouble('fake-download-duration', 60).getValue()
self.fakeDownload(duration)
else:
for phase in self.LauncherPhases:
self.phaseComplete[phase] = 100
self.downloadDoneTask(None)
return
def isTestServer(self):
return base.config.GetBool('is-test-server', 0)
def setPhaseCompleteArray(self, newPhaseComplete):
self.phaseComplete = newPhaseComplete
def setPhaseComplete(self, phase, percent):
self.phaseComplete[phase] = percent
def getPhaseComplete(self, phase):
return self.phaseComplete[phase] >= 100
def setPandaWindowOpen(self):
self.windowOpen = 1
def setPandaErrorCode(self, code):
self.pandaErrorCode = code
def getPandaErrorCode(self):
return self.pandaErrorCode
def setDisconnectDetailsNormal(self):
self.disconnectCode = 0
self.disconnectMsg = 'normal'
def setDisconnectDetails(self, newCode, newMsg):
self.disconnectCode = newCode
self.disconnectMsg = newMsg
def setServerVersion(self, version):
self.ServerVersion = version
def getServerVersion(self):
return self.ServerVersion
def getIsNewInstallation(self):
return base.config.GetBool('new-installation', 0)
def setIsNotNewInstallation(self):
pass
def getLastLogin(self):
if hasattr(self, 'lastLogin'):
return self.lastLogin
return ''
def setLastLogin(self, login):
self.lastLogin = login
def setUserLoggedIn(self):
self.userLoggedIn = 1
def setPaidUserLoggedIn(self):
self.paidUserLoggedIn = 1
def getGameServer(self):
return '206.16.11.19'
def getAccountServer(self):
return ''
def getDeployment(self):
return 'US'
def getBlue(self):
return None
def getPlayToken(self):
return None
def getDISLToken(self):
return None
def fakeDownloadPhaseTask(self, task):
percentComplete = min(100, int(round(task.time / float(task.timePerPhase) * 100)))
self.setPhaseComplete(task.phase, percentComplete)
messenger.send('launcherPercentPhaseComplete', [task.phase,
percentComplete,
0,
0])
if percentComplete >= 100.0:
messenger.send('phaseComplete-' + `(task.phase)`)
return Task.done
else:
return Task.cont
def downloadDoneTask(self, task):
self._downloadComplete = True
messenger.send('launcherAllPhasesComplete')
return Task.done
def fakeDownload(self, timePerPhase):
self.phaseComplete = {1: 100,
2: 100,
3: 0,
3.5: 0,
4: 0,
5: 0,
5.5: 0,
6: 0,
7: 0,
8: 0,
9: 0,
10: 0,
11: 0,
12: 0,
13: 0}
phaseTaskList = []
firstPhaseIndex = self.LauncherPhases.index(self.firstPhase)
for phase in self.LauncherPhases[firstPhaseIndex:]:
phaseTask = Task(self.fakeDownloadPhaseTask, 'phaseDownload' + str(phase))
phaseTask.timePerPhase = timePerPhase
phaseTask.phase = phase
phaseTaskList.append(phaseTask)
phaseTaskList.append(Task(self.downloadDoneTask))
downloadSequence = Task.sequence(*phaseTaskList)
taskMgr.remove('downloadSequence')
taskMgr.add(downloadSequence, 'downloadSequence')

1877
otp/launcher/LauncherBase.py Normal file

File diff suppressed because it is too large Load diff

0
otp/launcher/__init__.py Normal file
View file

43
otp/launcher/procapi.py Normal file
View file

@ -0,0 +1,43 @@
import ctypes
from ctypes.wintypes import *
TH32CS_SNAPPROCESS = 2
INVALID_HANDLE_VALUE = -1
cwk = ctypes.windll.kernel32
class PROCESSENTRY32(ctypes.Structure):
_fields_ = [('dwSize', DWORD),
('cntUsage', DWORD),
('th32ProcessID', DWORD),
('th32DefaultHeapId', HANDLE),
('th32ModuleID', DWORD),
('cntThreads', DWORD),
('th32ParentProcessID', DWORD),
('pcPriClassBase', LONG),
('dwFlags', DWORD),
('szExeFile', c_char * MAX_PATH)]
class ProcessEntryPY:
def __init__(self, name, pid):
self.name = name
self.pid = pid
def getProcessList():
hProcessSnap = cwk.CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
processList = []
if hProcessSnap != INVALID_HANDLE_VALUE:
pe32 = PROCESSENTRY32()
pe32.dwSize = sizeof(pe32)
if cwk.Process32First(hProcessSnap, ctypes.byref(pe32)):
while 1:
processList.append(ProcessEntryPY(pe32.szExeFile.lower(), int(pe32.th32ProcessID)))
if not cwk.Process32Next(hProcessSnap, ctypes.byref(pe32)):
break
cwk.CloseHandle(hProcessSnap)
return processList

39
otp/level/AmbientSound.py Normal file
View file

@ -0,0 +1,39 @@
from direct.interval.IntervalGlobal import *
import BasicEntities
import random
class AmbientSound(BasicEntities.NodePathEntity):
def __init__(self, level, entId):
BasicEntities.NodePathEntity.__init__(self, level, entId)
self.initSound()
def destroy(self):
self.destroySound()
BasicEntities.NodePathEntity.destroy(self)
def initSound(self):
if not self.enabled:
return
if self.soundPath == '':
return
self.sound = base.loadSfx(self.soundPath)
if self.sound is None:
return
self.soundIval = SoundInterval(self.sound, node=self, volume=self.volume)
self.soundIval.loop()
self.soundIval.setT(random.random() * self.sound.length())
return
def destroySound(self):
if hasattr(self, 'soundIval'):
self.soundIval.pause()
del self.soundIval
if hasattr(self, 'sound'):
del self.sound
if __dev__:
def attribChanged(self, *args):
self.destroySound()
self.initSound()

30
otp/level/AttribDesc.py Normal file
View file

@ -0,0 +1,30 @@
class AttribDesc:
def __init__(self, name, default, datatype = 'string', params = {}):
self.name = name
self.default = default
self.datatype = datatype
self.params = params
def getName(self):
return self.name
def getDefaultValue(self):
return self.default
def getDatatype(self):
return self.datatype
def getParams(self):
return self.params
def __str__(self):
return self.name
def __repr__(self):
return 'AttribDesc(%s, %s, %s, %s)' % (repr(self.name),
repr(self.default),
repr(self.datatype),
repr(self.params))

131
otp/level/BasicEntities.py Normal file
View file

@ -0,0 +1,131 @@
import Entity
import DistributedEntity
from pandac.PandaModules import NodePath
class NodePathEntityBase:
def initNodePathAttribs(self, doReparent = 1):
self.callSetters('pos', 'x', 'y', 'z', 'hpr', 'h', 'p', 'r', 'scale', 'sx', 'sy', 'sz')
if doReparent:
self.callSetters('parentEntId')
self.getNodePath().setName('%s-%s' % (self.__class__.__name__, self.entId))
if __dev__:
self.getNodePath().setTag('entity', '1')
def setParentEntId(self, parentEntId):
self.parentEntId = parentEntId
self.level.requestReparent(self, self.parentEntId)
def destroy(self):
if __dev__:
self.getNodePath().clearTag('entity')
class NodePathAttribs(NodePathEntityBase):
def initNodePathAttribs(self, doReparent = 1):
NodePathEntityBase.initNodePathAttribs(self, doReparent)
def destroy(self):
NodePathEntityBase.destroy(self)
def getNodePath(self):
return self
class NodePathAndAttribs(NodePathEntityBase, NodePath):
def __init__(self):
node = hidden.attachNewNode('EntityNodePath')
NodePath.__init__(self, node)
def initNodePathAttribs(self, doReparent = 1):
NodePathEntityBase.initNodePathAttribs(self, doReparent)
def destroy(self):
NodePathEntityBase.destroy(self)
self.removeNode()
def getNodePath(self):
return self
class NodePathAttribsProxy(NodePathEntityBase):
def initNodePathAttribs(self, doReparent = 1):
NodePathEntityBase.initNodePathAttribs(self, doReparent)
def destroy(self):
NodePathEntityBase.destroy(self)
def setPos(self, *args):
self.getNodePath().setPos(*args)
def setX(self, *args):
self.getNodePath().setX(*args)
def setY(self, *args):
self.getNodePath().setY(*args)
def setZ(self, *args):
self.getNodePath().setZ(*args)
def setHpr(self, *args):
self.getNodePath().setHpr(*args)
def setH(self, *args):
self.getNodePath().setH(*args)
def setP(self, *args):
self.getNodePath().setP(*args)
def setR(self, *args):
self.getNodePath().setR(*args)
def setScale(self, *args):
self.getNodePath().setScale(*args)
def setSx(self, *args):
self.getNodePath().setSx(*args)
def setSy(self, *args):
self.getNodePath().setSy(*args)
def setSz(self, *args):
self.getNodePath().setSz(*args)
def reparentTo(self, *args):
self.getNodePath().reparentTo(*args)
class NodePathEntity(Entity.Entity, NodePath, NodePathAttribs):
def __init__(self, level, entId):
node = hidden.attachNewNode('NodePathEntity')
NodePath.__init__(self, node)
Entity.Entity.__init__(self, level, entId)
self.initNodePathAttribs(self)
def destroy(self):
NodePathAttribs.destroy(self)
Entity.Entity.destroy(self)
self.removeNode()
class DistributedNodePathEntity(DistributedEntity.DistributedEntity, NodePath, NodePathAttribs):
def __init__(self, cr):
DistributedEntity.DistributedEntity.__init__(self, cr)
def generateInit(self):
DistributedEntity.DistributedEntity.generateInit(self)
node = hidden.attachNewNode('DistributedNodePathEntity')
NodePath.__init__(self, node)
def announceGenerate(self):
DistributedEntity.DistributedEntity.announceGenerate(self)
self.initNodePathAttribs(self)
def delete(self):
self.removeNode()
DistributedEntity.DistributedEntity.delete(self)

View file

@ -0,0 +1,45 @@
from pandac.PandaModules import *
from otp.otpbase import OTPGlobals
from direct.directnotify import DirectNotifyGlobal
import BasicEntities
class CollisionSolidEntity(BasicEntities.NodePathEntity):
notify = DirectNotifyGlobal.directNotify.newCategory('CollisionSolidEntity')
def __init__(self, level, entId):
self.collNodePath = None
BasicEntities.NodePathEntity.__init__(self, level, entId)
self.initSolid()
return
def destroy(self):
self.destroySolid()
BasicEntities.NodePathEntity.destroy(self)
def initSolid(self):
self.destroySolid()
if self.solidType == 'sphere':
solid = CollisionSphere(0, 0, 0, self.radius)
else:
solid = CollisionTube(0, 0, 0, 0, 0, self.length, self.radius)
node = CollisionNode(self.getUniqueName(self.__class__.__name__))
node.addSolid(solid)
node.setCollideMask(OTPGlobals.WallBitmask)
self.collNodePath = self.attachNewNode(node)
if __dev__:
if self.showSolid:
self.showCS()
else:
self.hideCS()
def destroySolid(self):
if self.collNodePath is not None:
self.collNodePath.removeNode()
self.collNodePath = None
return
if __dev__:
def attribChanged(self, attrib, value):
print 'attribChanged'
self.initSolid()

99
otp/level/CutScene.py Normal file
View file

@ -0,0 +1,99 @@
from direct.showbase import DirectObject
from direct.directnotify import DirectNotifyGlobal
import BasicEntities
from pandac.PandaModules import *
from pandac.PandaModules import *
from direct.interval.IntervalGlobal import *
from direct.distributed.ClockDelta import *
from toontown.toonbase import ToontownGlobals
from direct.directnotify import DirectNotifyGlobal
from direct.fsm import ClassicFSM
def nothing(self, track, subjectNodePath, duration):
return track
def irisInOut(self, track, subjectNodePath, duration):
track.append(Sequence(Func(base.transitions.irisOut, 0.5), Func(base.transitions.irisIn, 1.5), Wait(duration), Func(base.transitions.irisOut, 1.0), Func(base.transitions.irisIn, 0.5)))
return track
def letterBox(self, track, subjectNodePath, duration):
track.append(Sequence(Wait(duration)))
return track
def foo1(self, track, subjectNodePath, duration):
track.append(Sequence(Func(base.localAvatar.stopUpdateSmartCamera), PosHprInterval(camera, other=subjectNodePath, pos=Point3(-2, -35, 7.5), hpr=VBase3(-7, 0, 0)), LerpPosHprInterval(nodePath=camera, other=subjectNodePath, duration=duration, pos=Point3(2, -22, 7.5), hpr=VBase3(4, 0, 0), blendType='easeInOut'), PosHprInterval(camera, other=subjectNodePath, pos=Point3(0, -28, 7.5), hpr=VBase3(0, 0, 0)), Func(base.localAvatar.startUpdateSmartCamera)))
return track
def doorUnlock(self, track, subjectNodePath, duration):
track.append(Sequence(Func(base.localAvatar.stopUpdateSmartCamera), PosHprInterval(camera, other=self, pos=Point3(-2, -35, 7.5), hpr=VBase3(-7, 0, 0)), LerpPosHprInterval(nodePath=camera, other=self, duration=duration, pos=Point3(2, -22, 7.5), hpr=VBase3(4, 0, 0), blendType='easeInOut'), PosHprInterval(camera, other=self, pos=Point3(0, -28, 7.5), hpr=VBase3(0, 0, 0)), Func(base.localAvatar.startUpdateSmartCamera)))
return track
class CutScene(BasicEntities.NodePathEntity, DirectObject.DirectObject):
notify = DirectNotifyGlobal.directNotify.newCategory('CutScene')
effects = {'nothing': nothing,
'irisInOut': irisInOut,
'letterBox': letterBox}
motions = {'foo1': foo1,
'doorUnlock': doorUnlock}
def __init__(self, level, entId):
DirectObject.DirectObject.__init__(self)
BasicEntities.NodePathEntity.__init__(self, level, entId)
self.track = None
self.setEffect(self.effect)
self.setMotion(self.motion)
self.subjectNodePath = render.attachNewNode('CutScene')
self.subjectNodePath.setPos(self.pos)
self.subjectNodePath.setHpr(self.hpr)
self.setStartStop(self.startStopEvent)
return
def destroy(self):
self.ignore(self.startStopEvent)
self.startStopEvent = None
BasicEntities.NodePathEntity.destroy(self)
return
def setEffect(self, effect):
self.effect = effect
self.getEffect = self.effects[effect]
def setMotion(self, motion):
self.motionType = motion
self.getMotion = self.motions[motion]
def setSubjectNodePath(self, subjectNodePath):
self.subjectNodePath = subjectNodePath
def startOrStop(self, start):
trackName = 'cutSceneTrack-%d' % (id(self),)
if start:
if self.track:
self.track.finish()
self.track = None
track = Parallel(name=trackName)
track = self.getEffect(self, track, self.subjectNodePath, self.duration)
track = self.getMotion(self, track, self.subjectNodePath, self.duration)
track = Sequence(Wait(0.4), track)
track.start(0.0)
self.track = track
elif self.track:
self.track.pause()
self.track = None
base.localAvatar.startUpdateSmartCamera()
return
def setStartStop(self, event):
if self.startStopEvent:
self.ignore(self.startStopEvent)
self.startStopEvent = self.getOutputEventName(event)
if self.startStopEvent:
self.accept(self.startStopEvent, self.startOrStop)
def getName(self):
return 'switch-%s' % (self.entId,)

View file

@ -0,0 +1,50 @@
from direct.distributed import DistributedObject
import Entity
from direct.directnotify import DirectNotifyGlobal
class DistributedEntity(DistributedObject.DistributedObject, Entity.Entity):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedEntity')
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
Entity.Entity.__init__(self)
self.levelDoId = 0
self.entId = 0
self.level = None
return
def generateInit(self):
DistributedEntity.notify.debug('generateInit')
DistributedObject.DistributedObject.generateInit(self)
def generate(self):
DistributedEntity.notify.debug('generate')
DistributedObject.DistributedObject.generate(self)
def setLevelDoId(self, levelDoId):
DistributedEntity.notify.debug('setLevelDoId: %s' % levelDoId)
self.levelDoId = levelDoId
def setEntId(self, entId):
DistributedEntity.notify.debug('setEntId: %s' % entId)
self.entId = entId
def announceGenerate(self):
DistributedEntity.notify.debug('announceGenerate (%s)' % self.entId)
if self.levelDoId != 0:
level = base.cr.doId2do[self.levelDoId]
self.initializeEntity(level, self.entId)
self.level.onEntityCreate(self.entId)
else:
self.level = None
DistributedObject.DistributedObject.announceGenerate(self)
return
def disable(self):
DistributedEntity.notify.debug('disable (%s)' % self.entId)
self.destroy()
DistributedObject.DistributedObject.disable(self)
def delete(self):
DistributedEntity.notify.debug('delete')
DistributedObject.DistributedObject.delete(self)

View file

@ -0,0 +1,45 @@
from direct.distributed import DistributedObjectAI
import Entity
from direct.directnotify import DirectNotifyGlobal
class DistributedEntityAI(DistributedObjectAI.DistributedObjectAI, Entity.Entity):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedEntityAI')
def __init__(self, level, entId):
if hasattr(level, 'air'):
air = level.air
self.levelDoId = level.doId
else:
air = level
level = None
self.levelDoId = 0
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
Entity.Entity.__init__(self, level, entId)
return
def generate(self):
self.notify.debug('generate')
DistributedObjectAI.DistributedObjectAI.generate(self)
def destroy(self):
self.notify.debug('destroy')
Entity.Entity.destroy(self)
self.requestDelete()
def delete(self):
self.notify.debug('delete')
DistributedObjectAI.DistributedObjectAI.delete(self)
def getLevelDoId(self):
return self.levelDoId
def getEntId(self):
return self.entId
if __dev__:
def setParentEntId(self, parentEntId):
self.parentEntId = parentEntId
newZoneId = self.getZoneEntity().getZoneId()
if newZoneId != self.zoneId:
self.sendSetZone(newZoneId)

View file

@ -0,0 +1,69 @@
from pandac.PandaModules import *
from direct.distributed.ClockDelta import *
from direct.directnotify import DirectNotifyGlobal
from direct.fsm import ClassicFSM
import DistributedEntity
class DistributedInteractiveEntity(DistributedEntity.DistributedEntity):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedInteractiveEntity')
def __init__(self, cr):
DistributedEntity.DistributedEntity.__init__(self, cr)
self.fsm = ClassicFSM.ClassicFSM('DistributedInteractiveEntity', [State.State('off', self.enterOff, self.exitOff, ['playing', 'attract']), State.State('attract', self.enterAttract, self.exitAttract, ['playing']), State.State('playing', self.enterPlaying, self.exitPlaying, ['attract'])], 'off', 'off')
self.fsm.enterInitialState()
def generate(self):
DistributedEntity.DistributedEntity.generate(self)
def disable(self):
self.fsm.request('off')
DistributedEntity.DistributedEntity.disable(self)
def delete(self):
del self.fsm
DistributedEntity.DistributedEntity.delete(self)
def setAvatarInteract(self, avatarId):
self.avatarId = avatarId
def setOwnerDoId(self, ownerDoId):
self.ownerDoId = ownerDoId
def setState(self, state, timestamp):
if self.isGenerated():
self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)])
else:
self.initialState = state
self.initialStateTimestamp = timestamp
def enterTrigger(self, args = None):
messenger.send('DistributedInteractiveEntity_enterTrigger')
self.sendUpdate('requestInteract')
def exitTrigger(self, args = None):
messenger.send('DistributedInteractiveEntity_exitTrigger')
self.sendUpdate('requestExit')
def rejectInteract(self):
self.cr.playGame.getPlace().setState('walk')
def avatarExit(self, avatarId):
pass
def enterOff(self):
pass
def exitOff(self):
pass
def enterAttract(self, ts):
pass
def exitAttract(self):
pass
def enterPlaying(self, ts):
pass
def exitPlaying(self):
pass

View file

@ -0,0 +1,586 @@
from direct.distributed.ClockDelta import *
from pandac.PandaModules import *
from direct.showbase.PythonUtil import Functor, sameElements, list2dict, uniqueElements
from direct.interval.IntervalGlobal import *
from toontown.distributed.ToontownMsgTypes import *
from toontown.toonbase import ToontownGlobals
from otp.otpbase import OTPGlobals
from direct.distributed import DistributedObject
import Level
import LevelConstants
from direct.directnotify import DirectNotifyGlobal
import EntityCreator
from direct.gui import OnscreenText
from direct.task import Task
import LevelUtil
import random
class DistributedLevel(DistributedObject.DistributedObject, Level.Level):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLevel')
WantVisibility = config.GetBool('level-visibility', 1)
ColorZonesAllDOs = 0
FloorCollPrefix = 'zoneFloor'
OuchTaskName = 'ouchTask'
VisChangeTaskName = 'visChange'
EmulateEntrancePoint = True
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
Level.Level.__init__(self)
self.lastToonZone = None
self.lastCamZone = 0
self.titleColor = (1, 1, 1, 1)
self.titleText = OnscreenText.OnscreenText('', fg=self.titleColor, shadow=(0, 0, 0, 1), font=ToontownGlobals.getSuitFont(), pos=(0, -0.5), scale=0.16, drawOrder=0, mayChange=1)
self.smallTitleText = OnscreenText.OnscreenText('', fg=self.titleColor, font=ToontownGlobals.getSuitFont(), pos=(0.65, 0.9), scale=0.08, drawOrder=0, mayChange=1, bg=(0.5, 0.5, 0.5, 0.5), align=TextNode.ARight)
self.zonesEnteredList = []
self.fColorZones = 0
self.scenarioIndex = 0
return
def generate(self):
DistributedLevel.notify.debug('generate')
DistributedObject.DistributedObject.generate(self)
self.parent2pendingChildren = {}
self.curSpec = None
if base.cr.timeManager is not None:
base.cr.timeManager.synchronize('DistributedLevel.generate')
else:
self.notify.warning('generate(): no TimeManager!')
return
def setLevelZoneId(self, zoneId):
self.levelZone = zoneId
def setPlayerIds(self, avIdList):
self.avIdList = avIdList
def setEntranceId(self, entranceId):
self.entranceId = entranceId
def getEntranceId(self):
return self.entranceId
def setZoneIds(self, zoneIds):
DistributedLevel.notify.debug('setZoneIds: %s' % zoneIds)
self.zoneIds = zoneIds
def setStartTimestamp(self, timestamp):
DistributedLevel.notify.debug('setStartTimestamp: %s' % timestamp)
self.startTime = globalClockDelta.networkToLocalTime(timestamp, bits=32)
self.privGotAllRequired()
def privGotAllRequired(self):
self.levelAnnounceGenerate()
def levelAnnounceGenerate(self):
pass
def initializeLevel(self, levelSpec):
if __dev__:
self.candidateSpec = levelSpec
self.sendUpdate('requestCurrentLevelSpec', [levelSpec.stringHash(), levelSpec.entTypeReg.getHashStr()])
else:
self.privGotSpec(levelSpec)
if __dev__:
def reportModelSpecSyncError(self, msg):
DistributedLevel.notify.error('%s\n\nyour spec does not match the level model\nuse SpecUtil.updateSpec, then restart your AI and client' % msg)
def setSpecDeny(self, reason):
DistributedLevel.notify.error(reason)
def setSpecSenderDoId(self, doId):
DistributedLevel.notify.debug('setSpecSenderDoId: %s' % doId)
blobSender = base.cr.doId2do[doId]
def setSpecBlob(specBlob, blobSender = blobSender, self = self):
blobSender.sendAck()
from LevelSpec import LevelSpec
spec = eval(specBlob)
if spec is None:
spec = self.candidateSpec
del self.candidateSpec
self.privGotSpec(spec)
return
if blobSender.isComplete():
setSpecBlob(blobSender.getBlob())
else:
evtName = self.uniqueName('specDone')
blobSender.setDoneEvent(evtName)
self.acceptOnce(evtName, setSpecBlob)
def privGotSpec(self, levelSpec):
Level.Level.initializeLevel(self, self.doId, levelSpec, self.scenarioIndex)
modelZoneNums = self.zoneNums
specZoneNums = self.zoneNum2zoneId.keys()
if not sameElements(modelZoneNums, specZoneNums):
self.reportModelSpecSyncError('model zone nums (%s) do not match spec zone nums (%s)' % (modelZoneNums, specZoneNums))
self.initVisibility()
self.placeLocalToon()
def announceLeaving(self):
DistributedLevel.notify.debug('announceLeaving')
self.doneBarrier()
def placeLocalToon(self, moveLocalAvatar = True):
initialZoneEnt = None
if self.entranceId in self.entranceId2entity:
epEnt = self.entranceId2entity[self.entranceId]
if moveLocalAvatar:
epEnt.placeToon(base.localAvatar, self.avIdList.index(base.localAvatar.doId), len(self.avIdList))
initialZoneEnt = self.getEntity(epEnt.getZoneEntId())
elif self.EmulateEntrancePoint:
self.notify.debug('unknown entranceId %s' % self.entranceId)
if moveLocalAvatar:
base.localAvatar.reparentTo(render)
base.localAvatar.setPosHpr(0, 0, 0, 0, 0, 0)
self.notify.debug('showing all zones')
self.setColorZones(1)
zoneEntIds = list(self.entType2ids['zone'])
zoneEntIds.remove(LevelConstants.UberZoneEntId)
if len(zoneEntIds):
zoneEntId = random.choice(zoneEntIds)
initialZoneEnt = self.getEntity(zoneEntId)
if moveLocalAvatar:
base.localAvatar.setPos(render, initialZoneEnt.getZoneNode().getPos(render))
else:
initialZoneEnt = self.getEntity(LevelConstants.UberZoneEntId)
if moveLocalAvatar:
base.localAvatar.setPos(render, 0, 0, 0)
if initialZoneEnt is not None:
self.enterZone(initialZoneEnt.entId)
return
def createEntityCreator(self):
return EntityCreator.EntityCreator(level=self)
def onEntityTypePostCreate(self, entType):
Level.Level.onEntityTypePostCreate(self, entType)
if entType == 'levelMgr':
self.__handleLevelMgrCreated()
def __handleLevelMgrCreated(self):
levelMgr = self.getEntity(LevelConstants.LevelMgrEntId)
self.geom = levelMgr.geom
self.zoneNum2node = LevelUtil.getZoneNum2Node(self.geom)
self.zoneNums = self.zoneNum2node.keys()
self.zoneNums.sort()
self.zoneNumDict = list2dict(self.zoneNums)
DistributedLevel.notify.debug('zones from model: %s' % self.zoneNums)
self.fixupLevelModel()
def fixupLevelModel(self):
for zoneNum, zoneNode in self.zoneNum2node.items():
if zoneNum == LevelConstants.UberZoneEntId:
continue
allColls = zoneNode.findAllMatches('**/+CollisionNode')
floorColls = []
for coll in allColls:
bitmask = coll.node().getIntoCollideMask()
if not (bitmask & ToontownGlobals.FloorBitmask).isZero():
floorColls.append(coll)
if len(floorColls) > 0:
floorCollName = '%s%s' % (DistributedLevel.FloorCollPrefix, zoneNum)
others = zoneNode.findAllMatches('**/%s' % floorCollName)
for other in others:
other.setName('%s_renamed' % floorCollName)
for floorColl in floorColls:
floorColl.setName(floorCollName)
def handleZoneEnter(collisionEntry, self = self, zoneNum = zoneNum):
self.toonEnterZone(zoneNum)
floorNode = collisionEntry.getIntoNode()
if floorNode.hasTag('ouch'):
ouchLevel = int(self.getFloorOuchLevel())
self.startOuch(ouchLevel)
self.accept('enter%s' % floorCollName, handleZoneEnter)
def handleZoneExit(collisionEntry, self = self, zoneNum = zoneNum):
floorNode = collisionEntry.getIntoNode()
if floorNode.hasTag('ouch'):
self.stopOuch()
self.accept('exit%s' % floorCollName, handleZoneExit)
def getFloorOuchLevel(self):
return 1
def announceGenerate(self):
DistributedLevel.notify.debug('announceGenerate')
DistributedObject.DistributedObject.announceGenerate(self)
def disable(self):
DistributedLevel.notify.debug('disable')
if hasattr(self, 'geom'):
del self.geom
self.shutdownVisibility()
self.destroyLevel()
self.ignoreAll()
taskMgr.remove(self.uniqueName('titleText'))
if self.smallTitleText:
self.smallTitleText.cleanup()
self.smallTitleText = None
if self.titleText:
self.titleText.cleanup()
self.titleText = None
self.zonesEnteredList = []
DistributedObject.DistributedObject.disable(self)
return
def delete(self):
DistributedLevel.notify.debug('delete')
DistributedObject.DistributedObject.delete(self)
self.stopOuch()
def requestReparent(self, entity, parentId, wrt = False):
parent = self.getEntity(parentId)
if parent is not None:
if wrt:
entity.wrtReparentTo(parent.getNodePath())
else:
entity.reparentTo(parent.getNodePath())
else:
DistributedLevel.notify.debug('entity %s requesting reparent to %s, not yet created' % (entity, parentId))
entity.reparentTo(hidden)
if not self.parent2pendingChildren.has_key(parentId):
self.parent2pendingChildren[parentId] = []
def doReparent(parentId = parentId, self = self, wrt = wrt):
parent = self.getEntity(parentId)
for child in self.parent2pendingChildren[parentId]:
DistributedLevel.notify.debug('performing pending reparent of %s to %s' % (child, parent))
if wrt:
child.wrtReparentTo(parent.getNodePath())
else:
child.reparentTo(parent.getNodePath())
del self.parent2pendingChildren[parentId]
self.ignore(self.getEntityCreateEvent(parentId))
self.accept(self.getEntityCreateEvent(parentId), doReparent)
self.parent2pendingChildren[parentId].append(entity)
return
def getZoneNode(self, zoneEntId):
return self.zoneNum2node.get(zoneEntId)
def warpToZone(self, zoneNum):
zoneNode = self.getZoneNode(zoneNum)
if zoneNode is None:
return
base.localAvatar.setPos(zoneNode, 0, 0, 0)
base.localAvatar.setHpr(zoneNode, 0, 0, 0)
self.enterZone(zoneNum)
return
def showZone(self, zoneNum):
zone = self.getZoneNode(zoneNum)
zone.unstash()
zone.clearColor()
def setColorZones(self, fColorZones):
self.fColorZones = fColorZones
self.resetVisibility()
def getColorZones(self):
return self.fColorZones
def hideZone(self, zoneNum):
zone = self.getZoneNode(zoneNum)
if self.fColorZones:
zone.unstash()
zone.setColor(1, 0, 0)
else:
zone.stash()
def setTransparency(self, alpha, zone = None):
self.geom.setTransparency(1)
if zone is None:
node = self.geom
else:
node = self.getZoneNode(zoneNum)
node.setAlphaScale(alpha)
return
def initVisibility(self):
self.curVisibleZoneNums = list2dict(self.zoneNums)
del self.curVisibleZoneNums[LevelConstants.UberZoneEntId]
self.curZoneNum = None
self.visChangedThisFrame = 0
self.fForceSetZoneThisFrame = 0
def handleCameraRayFloorCollision(collEntry, self = self):
name = collEntry.getIntoNode().getName()
self.notify.debug('camera floor ray collided with: %s' % name)
prefixLen = len(DistributedLevel.FloorCollPrefix)
if name[:prefixLen] == DistributedLevel.FloorCollPrefix:
try:
zoneNum = int(name[prefixLen:])
except:
DistributedLevel.notify.warning('Invalid zone floor collision node: %s' % name)
else:
self.camEnterZone(zoneNum)
self.accept('on-floor', handleCameraRayFloorCollision)
if not DistributedLevel.WantVisibility:
zoneNums = list(self.zoneNums)
zoneNums.remove(LevelConstants.UberZoneEntId)
self.forceSetZoneThisFrame()
self.setVisibility(zoneNums)
taskMgr.add(self.visChangeTask, self.uniqueName(DistributedLevel.VisChangeTaskName), priority=49)
return
def shutdownVisibility(self):
taskMgr.remove(self.uniqueName(DistributedLevel.VisChangeTaskName))
def toonEnterZone(self, zoneNum, ouchLevel = None):
DistributedLevel.notify.debug('toonEnterZone%s' % zoneNum)
if zoneNum != self.lastToonZone:
self.lastToonZone = zoneNum
self.notify.debug('toon is standing in zone %s' % zoneNum)
messenger.send('factoryZoneChanged', [zoneNum])
def camEnterZone(self, zoneNum):
DistributedLevel.notify.debug('camEnterZone%s' % zoneNum)
self.enterZone(zoneNum)
if zoneNum != self.lastCamZone:
self.lastCamZone = zoneNum
self.smallTitleText.hide()
self.spawnTitleText()
def lockVisibility(self, zoneNum = None, zoneId = None):
if zoneId is not None:
zoneNum = self.getZoneNumFromId(zoneId)
self.notify.debug('lockVisibility to zoneNum %s' % zoneNum)
self.lockVizZone = zoneNum
self.enterZone(self.lockVizZone)
return
def unlockVisibility(self):
self.notify.debug('unlockVisibility')
if not hasattr(self, 'lockVizZone'):
self.notify.warning('visibility already unlocked')
else:
del self.lockVizZone
self.updateVisibility()
def enterZone(self, zoneNum):
DistributedLevel.notify.debug('entering zone %s' % zoneNum)
if not DistributedLevel.WantVisibility:
return
if zoneNum == self.curZoneNum:
return
if zoneNum not in self.zoneNumDict:
DistributedLevel.notify.error('no ZoneEntity for this zone (%s)!!' % zoneNum)
self.updateVisibility(zoneNum)
def updateVisibility(self, zoneNum = None):
if zoneNum is None:
zoneNum = self.curZoneNum
if zoneNum is None:
return
if hasattr(self, 'lockVizZone'):
zoneNum = self.lockVizZone
zoneEnt = self.getEntity(zoneNum)
visibleZoneNums = list2dict([zoneNum])
visibleZoneNums.update(list2dict(zoneEnt.getVisibleZoneNums()))
if not __debug__:
if self.lastToonZone not in visibleZoneNums:
if self.lastToonZone is not None:
self.notify.warning('adding zoneNum %s to visibility list because toon is standing in that zone!' % self.lastToonZone)
visibleZoneNums.update(list2dict([self.lastToonZone]))
zoneEntIds = list(self.entType2ids['zone'])
zoneEntIds.remove(LevelConstants.UberZoneEntId)
if len(zoneEntIds):
pass
vizZonesChanged = 1
addedZoneNums = []
removedZoneNums = []
allVZ = dict(visibleZoneNums)
allVZ.update(self.curVisibleZoneNums)
for vz, dummy in allVZ.items():
new = vz in visibleZoneNums
old = vz in self.curVisibleZoneNums
if new and old:
continue
if new:
addedZoneNums.append(vz)
else:
removedZoneNums.append(vz)
if not addedZoneNums and not removedZoneNums:
DistributedLevel.notify.debug('visible zone list has not changed')
vizZonesChanged = 0
else:
DistributedLevel.notify.debug('showing zones %s' % addedZoneNums)
for az in addedZoneNums:
self.showZone(az)
DistributedLevel.notify.debug('hiding zones %s' % removedZoneNums)
for rz in removedZoneNums:
self.hideZone(rz)
if vizZonesChanged or self.fForceSetZoneThisFrame:
self.setVisibility(visibleZoneNums.keys())
self.fForceSetZoneThisFrame = 0
self.curZoneNum = zoneNum
self.curVisibleZoneNums = visibleZoneNums
return
def setVisibility(self, vizList):
if self.fColorZones and DistributedLevel.ColorZonesAllDOs:
vizList = list(self.zoneNums)
vizList.remove(LevelConstants.UberZoneEntId)
uberZone = self.getZoneId(LevelConstants.UberZoneEntId)
visibleZoneIds = [OTPGlobals.UberZone, self.levelZone, uberZone]
for vz in vizList:
if vz is not LevelConstants.UberZoneEntId:
visibleZoneIds.append(self.getZoneId(vz))
DistributedLevel.notify.debug('new viz list: %s' % visibleZoneIds)
base.cr.sendSetZoneMsg(self.levelZone, visibleZoneIds)
def resetVisibility(self):
self.curVisibleZoneNums = list2dict(self.zoneNums)
del self.curVisibleZoneNums[LevelConstants.UberZoneEntId]
for vz, dummy in self.curVisibleZoneNums.items():
self.showZone(vz)
self.updateVisibility()
def handleVisChange(self):
Level.Level.handleVisChange(self)
self.visChangedThisFrame = 1
def forceSetZoneThisFrame(self):
self.fForceSetZoneThisFrame = 1
def visChangeTask(self, task):
if self.visChangedThisFrame or self.fForceSetZoneThisFrame:
self.updateVisibility()
self.visChangedThisFrame = 0
return Task.cont
if __dev__:
def setAttribChange(self, entId, attribName, valueStr, username):
value = eval(valueStr)
self.levelSpec.setAttribChange(entId, attribName, value, username)
def spawnTitleText(self):
def getDescription(zoneNum, self = self):
ent = self.entities.get(zoneNum)
if ent and hasattr(ent, 'description'):
return ent.description
return None
description = getDescription(self.lastCamZone)
if description and description != '':
taskMgr.remove(self.uniqueName('titleText'))
self.smallTitleText.setText(description)
self.titleText.setText(description)
self.titleText.setColor(Vec4(*self.titleColor))
self.titleText.setFg(self.titleColor)
titleSeq = None
if self.lastCamZone not in self.zonesEnteredList:
self.zonesEnteredList.append(self.lastCamZone)
titleSeq = Task.sequence(Task.Task(self.hideSmallTitleTextTask), Task.Task(self.showTitleTextTask), Task.pause(0.1), Task.pause(6.0), self.titleText.lerpColor(Vec4(self.titleColor[0], self.titleColor[1], self.titleColor[2], self.titleColor[3]), Vec4(self.titleColor[0], self.titleColor[1], self.titleColor[2], 0.0), 0.5))
smallTitleSeq = Task.sequence(Task.Task(self.hideTitleTextTask), Task.Task(self.showSmallTitleTask))
if titleSeq:
seq = Task.sequence(titleSeq, smallTitleSeq)
else:
seq = smallTitleSeq
taskMgr.add(seq, self.uniqueName('titleText'))
return
def showInfoText(self, text = 'hello world'):
description = text
if description and description != '':
taskMgr.remove(self.uniqueName('titleText'))
self.smallTitleText.setText(description)
self.titleText.setText(description)
self.titleText.setColor(Vec4(*self.titleColor))
self.titleText.setFg(self.titleColor)
titleSeq = None
titleSeq = Task.sequence(Task.Task(self.hideSmallTitleTextTask), Task.Task(self.showTitleTextTask), Task.pause(0.1), Task.pause(3.0), self.titleText.lerpColor(Vec4(self.titleColor[0], self.titleColor[1], self.titleColor[2], self.titleColor[3]), Vec4(self.titleColor[0], self.titleColor[1], self.titleColor[2], 0.0), 0.5))
if titleSeq:
seq = Task.sequence(titleSeq)
taskMgr.add(seq, self.uniqueName('titleText'))
return
def showTitleTextTask(self, task):
self.titleText.show()
return Task.done
def hideTitleTextTask(self, task):
if self.titleText:
self.titleText.hide()
return Task.done
def showSmallTitleTask(self, task):
if self.titleText:
self.titleText.hide()
self.smallTitleText.show()
return Task.done
def hideSmallTitleTextTask(self, task):
if self.smallTitleText:
self.smallTitleText.hide()
return Task.done
def startOuch(self, ouchLevel, period = 2):
self.notify.debug('startOuch %s' % ouchLevel)
if not hasattr(self, 'doingOuch'):
def doOuch(task, self = self, ouchLevel = ouchLevel, period = period):
self.b_setOuch(ouchLevel)
self.lastOuchTime = globalClock.getFrameTime()
taskMgr.doMethodLater(period, doOuch, DistributedLevel.OuchTaskName)
delay = 0
if hasattr(self, 'lastOuchTime'):
curFrameTime = globalClock.getFrameTime()
timeSinceLastOuch = curFrameTime - self.lastOuchTime
if timeSinceLastOuch < period:
delay = period - timeSinceLastOuch
if delay > 0:
taskMgr.doMethodLater(period, doOuch, DistributedLevel.OuchTaskName)
else:
doOuch(None)
self.doingOuch = 1
return
def stopOuch(self):
if hasattr(self, 'doingOuch'):
taskMgr.remove(DistributedLevel.OuchTaskName)
del self.doingOuch
def b_setOuch(self, penalty, anim = None):
self.notify.debug('b_setOuch %s' % penalty)
av = base.localAvatar
if not av.isStunned:
self.d_setOuch(penalty)
self.setOuch(penalty, anim)
def d_setOuch(self, penalty):
self.sendUpdate('setOuch', [penalty])
def setOuch(self, penalty, anim = None):
if anim == 'Squish':
if base.cr.playGame.getPlace():
base.cr.playGame.getPlace().fsm.request('squished')
elif anim == 'Fall':
if base.cr.playGame.getPlace():
base.cr.playGame.getPlace().fsm.request('fallDown')
av = base.localAvatar
av.stunToon()
av.playDialogueForString('!')
def complexVis(self):
return 1

View file

@ -0,0 +1,180 @@
from pandac import PandaModules as PM
from otp.ai.AIBaseGlobal import *
from direct.distributed.ClockDelta import *
from direct.distributed import DistributedObjectAI
import Level
from direct.directnotify import DirectNotifyGlobal
import EntityCreatorAI
from direct.showbase.PythonUtil import Functor, weightedChoice
class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI, Level.Level):
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLevelAI')
def __init__(self, air, zoneId, entranceId, avIds):
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
Level.Level.__init__(self)
self.zoneId = zoneId
self.entranceId = entranceId
if len(avIds) <= 0 or len(avIds) > 4:
self.notify.warning('How do we have this many avIds? avIds: %s' % avIds)
self.avIdList = avIds
self.numPlayers = len(self.avIdList)
self.presentAvIds = list(self.avIdList)
self.notify.debug('expecting avatars: %s' % str(self.avIdList))
if __dev__:
self.modified = 0
def setLevelSpec(self, levelSpec):
self.levelSpec = levelSpec
def generate(self, levelSpec=None):
self.notify.debug('generate')
DistributedObjectAI.DistributedObjectAI.generate(self)
if levelSpec == None:
levelSpec = self.levelSpec
self.initializeLevel(levelSpec)
self.sendUpdate('setZoneIds', [self.zoneIds])
self.sendUpdate('setStartTimestamp', [self.startTimestamp])
if __dev__:
pass
return
def getLevelZoneId(self):
return self.zoneId
def getPlayerIds(self):
return self.avIdList
def getEntranceId(self):
return self.entranceId
def getBattleCreditMultiplier(self):
return 1.0
def delete(self, deAllocZone=True):
self.notify.debug('delete')
if __dev__:
self.removeAutosaveTask()
self.destroyLevel()
self.ignoreAll()
if deAllocZone:
self.air.deallocateZone(self.zoneId)
DistributedObjectAI.DistributedObjectAI.delete(self)
def initializeLevel(self, levelSpec):
self.startTime = globalClock.getRealTime()
self.startTimestamp = globalClockDelta.localToNetworkTime(self.startTime, bits=32)
lol = zip([1] * levelSpec.getNumScenarios(), range(levelSpec.getNumScenarios()))
scenarioIndex = weightedChoice(lol)
Level.Level.initializeLevel(self, self.doId, levelSpec, scenarioIndex)
if __dev__:
self.accept(self.editMgrEntity.getSpecSaveEvent(), self.saveSpec)
for avId in self.avIdList:
self.acceptOnce(self.air.getAvatarExitEvent(avId), Functor(self.handleAvatarDisconnect, avId))
self.allToonsGoneBarrier = self.beginBarrier('allToonsGone', self.avIdList, 3 * 24 * 60 * 60, self.allToonsGone)
def handleAvatarDisconnect(self, avId):
try:
self.presentAvIds.remove(avId)
DistributedLevelAI.notify.warning('av %s has disconnected' % avId)
except:
DistributedLevelAI.notify.warning('got disconnect for av %s, not in list' % avId)
if not self.presentAvIds:
self.allToonsGone([])
def _levelControlsRequestDelete(self):
return True
def allToonsGone(self, toonsThatCleared):
DistributedLevelAI.notify.info('allToonsGone')
if hasattr(self, 'allToonsGoneBarrier'):
self.ignoreBarrier(self.allToonsGoneBarrier)
del self.allToonsGoneBarrier
for avId in self.avIdList:
self.ignore(self.air.getAvatarExitEvent(avId))
if self._levelControlsRequestDelete():
self.requestDelete()
def createEntityCreator(self):
return EntityCreatorAI.EntityCreatorAI(level=self)
def setOuch(self, penalty):
avId = self.air.getAvatarIdFromSender()
av = self.air.doId2do.get(avId)
self.notify.debug('setOuch %s' % penalty)
if av and penalty > 0:
av.takeDamage(penalty)
if av.getHp() <= 0:
av.inventory.zeroInv()
av.d_setInventory(av.inventory.makeNetString())
def requestCurrentLevelSpec(self, specHash, entTypeRegHash):
senderId = self.air.getAvatarIdFromSender()
self.notify.info('av %s: specHash %s, entTypeRegHash %s' % (senderId, specHash, entTypeRegHash))
if not __dev__:
self.notify.info('client is in dev mode and we are not')
self.sendUpdateToAvatarId(senderId, 'setSpecDeny', [
'AI server is not running in dev mode. Set want-dev to false on your client or true on the AI.'])
return
srvHash = self.levelSpec.entTypeReg.getHashStr()
self.notify.info('srv entTypeRegHash %s' % srvHash)
if srvHash != entTypeRegHash:
self.sendUpdateToAvatarId(senderId, 'setSpecDeny', [
'EntityTypeRegistry hashes do not match! (server:%s, client:%s' % (srvHash, entTypeRegHash)])
return
if self.levelSpec.stringHash() != specHash:
self.notify.info('spec hashes do not match, sending our spec')
spec = self.levelSpec
useDisk = simbase.air._specByDisk
else:
self.notify.info('spec hashes match, sending null spec')
spec = None
useDisk = 0
specStr = repr(spec)
from direct.directutil import DistributedLargeBlobSenderAI
largeBlob = DistributedLargeBlobSenderAI.DistributedLargeBlobSenderAI(self.air, self.zoneId, senderId, specStr, useDisk=useDisk)
self.sendUpdateToAvatarId(senderId, 'setSpecSenderDoId', [largeBlob.doId])
return
if __dev__:
def setAttribChange(self, entId, attribName, value, username='SYSTEM'):
DistributedLevelAI.notify.info('setAttribChange(%s): %s, %s = %s' % (username, entId, attribName, repr(value)))
self.sendUpdate('setAttribChange', [
entId, attribName, repr(value), username])
self.levelSpec.setAttribChange(entId, attribName, value, username)
self.modified = 1
self.scheduleAutosave()
AutosavePeriod = simbase.config.GetFloat('level-autosave-period-minutes', 5)
def scheduleAutosave(self):
if hasattr(self, 'autosaveTask'):
return
self.autosaveTaskName = self.uniqueName('autosaveSpec')
self.autosaveTask = taskMgr.doMethodLater(DistributedLevelAI.AutosavePeriod * 60, self.autosaveSpec, self.autosaveTaskName)
def removeAutosaveTask(self):
if hasattr(self, 'autosaveTask'):
taskMgr.remove(self.autosaveTaskName)
del self.autosaveTask
def autosaveSpec(self, task=None):
self.removeAutosaveTask()
if self.modified:
DistributedLevelAI.notify.info('autosaving spec')
filename = self.levelSpec.getFilename()
filename = '%s.autosave' % filename
self.levelSpec.saveToDisk(filename, makeBackup=0)
def saveSpec(self, task=None):
DistributedLevelAI.notify.info('saving spec')
self.removeAutosaveTask()
if not self.modified:
DistributedLevelAI.notify.info('no changes to save')
return
self.levelSpec.saveToDisk()
self.modified = 0

4
otp/level/EditMgr.py Normal file
View file

@ -0,0 +1,4 @@
import EditMgrBase
class EditMgr(EditMgrBase.EditMgrBase):
pass

41
otp/level/EditMgrAI.py Normal file
View file

@ -0,0 +1,41 @@
import EditMgrBase
if __dev__:
from direct.showbase.PythonUtil import list2dict
import EditorGlobals
class EditMgrAI(EditMgrBase.EditMgrBase):
if __dev__:
def setRequestNewEntity(self, data):
spec = self.level.levelSpec
entIds = spec.getAllEntIds()
entIdDict = list2dict(entIds)
allocRange = EditorGlobals.getEntIdAllocRange()
if not hasattr(self, 'lastAllocatedEntId'):
self.lastAllocatedEntId = allocRange[0]
idChosen = 0
while not idChosen:
for id in xrange(self.lastAllocatedEntId, allocRange[1]):
print id
if id not in entIdDict:
idChosen = 1
break
else:
if self.lastAllocatedEntId != allocRange[0]:
self.lastAllocatedEntId = allocRange[0]
else:
self.notify.error('out of entIds')
data.update({'entId': id})
self.lastAllocatedEntId = id
self.level.setAttribChange(self.entId, 'insertEntity', data)
self.level.levelSpec.doSetAttrib(self.entId, 'requestNewEntity', None)
return
def getSpecSaveEvent(self):
return 'requestSave-%s' % self.level.levelId
def setRequestSave(self, data):
messenger.send(self.getSpecSaveEvent())
self.level.levelSpec.doSetAttrib(self.entId, 'requestSave', None)
return

25
otp/level/EditMgrBase.py Normal file
View file

@ -0,0 +1,25 @@
import Entity
from direct.directnotify import DirectNotifyGlobal
class EditMgrBase(Entity.Entity):
notify = DirectNotifyGlobal.directNotify.newCategory('EditMgr')
def __init__(self, level, entId):
Entity.Entity.__init__(self, level, entId)
def destroy(self):
Entity.Entity.destroy(self)
self.ignoreAll()
if __dev__:
def setInsertEntity(self, data):
self.level.setEntityCreatorUsername(data['entId'], data['username'])
self.level.levelSpec.insertEntity(data['entId'], data['entType'], data['parentEntId'])
self.level.levelSpec.doSetAttrib(self.entId, 'insertEntity', None)
return
def setRemoveEntity(self, data):
self.level.levelSpec.removeEntity(data['entId'])
self.level.levelSpec.doSetAttrib(self.entId, 'removeEntity', None)
return

View file

@ -0,0 +1,40 @@
from direct.showbase.PythonUtil import uniqueElements
EditTargetPostName = 'inGameEditTarget'
EntIdRange = 10000
username2entIdBase = {'darren': 1 * EntIdRange,
'samir': 2 * EntIdRange,
'skyler': 3 * EntIdRange,
'joe': 4 * EntIdRange,
'DrEvil': 5 * EntIdRange,
'asad': 6 * EntIdRange,
'drose': 7 * EntIdRange,
'pappy': 8 * EntIdRange,
'patricia': 9 * EntIdRange,
'jloehrle': 10 * EntIdRange,
'rurbino': 11 * EntIdRange}
usernameConfigVar = 'level-edit-username'
undefinedUsername = 'UNDEFINED_USERNAME'
editUsername = config.GetString(usernameConfigVar, undefinedUsername)
def checkNotReadyToEdit():
if editUsername == undefinedUsername:
return "you must config '%s'; see %s.py" % (usernameConfigVar, __name__)
if editUsername not in username2entIdBase:
return "unknown editor username '%s'; see %s.py" % (editUsername, __name__)
return None
def assertReadyToEdit():
msg = checkNotReadyToEdit()
if msg is not None:
pass
return
def getEditUsername():
return editUsername
def getEntIdAllocRange():
baseId = username2entIdBase[editUsername]
return [baseId, baseId + EntIdRange]

101
otp/level/Entity.py Normal file
View file

@ -0,0 +1,101 @@
from direct.showbase.DirectObject import DirectObject
from direct.showbase.PythonUtil import lineInfo
import string
from direct.directnotify import DirectNotifyGlobal
class Entity(DirectObject):
notify = DirectNotifyGlobal.directNotify.newCategory('Entity')
def __init__(self, level = None, entId = None):
self.initializeEntity(level, entId)
def initializeEntity(self, level, entId):
self.level = level
self.entId = entId
if self.level is not None and self.entId is not None:
self.level.initializeEntity(self)
return
def __str__(self):
if hasattr(self, 'level') and self.level:
return 'ent%s(%s)' % (self.entId, self.level.getEntityType(self.entId))
elif hasattr(self, 'name'):
return self.name
elif hasattr(self, 'entId'):
return '%s-%s' % (self.__class__.__name__, self.entId)
else:
return self.__class__.__name__
def destroy(self):
Entity.notify.debug('Entity.destroy() %s' % self.entId)
if self.level:
if self.level.isInitialized():
self.level.onEntityDestroy(self.entId)
else:
Entity.notify.warning('Entity %s destroyed after level??' % self.entId)
self.ignoreAll()
del self.level
del self.entId
def getUniqueName(self, name, entId = None):
if entId is None:
entId = self.entId
return '%s-%s-%s' % (name, self.level.levelId, entId)
def getParentToken(self):
return self.level.getParentTokenForEntity(self.entId)
def getOutputEventName(self, entId = None):
if entId is None:
entId = self.entId
return self.getUniqueName('entityOutput', entId)
def getZoneEntId(self):
return self.level.getEntityZoneEntId(self.entId)
def getZoneEntity(self):
return self.level.getEntity(self.getZoneEntId())
def getZoneNode(self):
return self.getZoneEntity().getNodePath()
def privGetSetter(self, attrib):
setFuncName = 'set%s%s' % (string.upper(attrib[0]), attrib[1:])
if hasattr(self, setFuncName):
return getattr(self, setFuncName)
return None
def callSetters(self, *attribs):
self.privCallSetters(0, *attribs)
def callSettersAndDelete(self, *attribs):
self.privCallSetters(1, *attribs)
def privCallSetters(self, doDelete, *attribs):
for attrib in attribs:
if hasattr(self, attrib):
setter = self.privGetSetter(attrib)
if setter is not None:
value = getattr(self, attrib)
if doDelete:
delattr(self, attrib)
setter(value)
return
def setAttribInit(self, attrib, value):
self.__dict__[attrib] = value
if __dev__:
def handleAttribChange(self, attrib, value):
setter = self.privGetSetter(attrib)
if setter is not None:
setter(value)
else:
self.__dict__[attrib] = value
self.attribChanged(attrib, value)
return
def attribChanged(self, attrib, value):
pass

View file

@ -0,0 +1,49 @@
import CutScene
import EntityCreatorBase
import BasicEntities
from direct.directnotify import DirectNotifyGlobal
import EditMgr
import EntrancePoint
import LevelMgr
import LogicGate
import ZoneEntity
import ModelEntity
import PathEntity
import VisibilityExtender
import PropSpinner
import AmbientSound
import LocatorEntity
import CollisionSolidEntity
def nothing(*args):
return 'nothing'
def nonlocal(*args):
return 'nonlocal'
class EntityCreator(EntityCreatorBase.EntityCreatorBase):
def __init__(self, level):
EntityCreatorBase.EntityCreatorBase.__init__(self, level)
self.level = level
self.privRegisterTypes({'attribModifier': nothing,
'ambientSound': AmbientSound.AmbientSound,
'collisionSolid': CollisionSolidEntity.CollisionSolidEntity,
'cutScene': CutScene.CutScene,
'editMgr': EditMgr.EditMgr,
'entityGroup': nothing,
'entrancePoint': EntrancePoint.EntrancePoint,
'levelMgr': LevelMgr.LevelMgr,
'locator': LocatorEntity.LocatorEntity,
'logicGate': LogicGate.LogicGate,
'model': ModelEntity.ModelEntity,
'nodepath': BasicEntities.NodePathEntity,
'path': PathEntity.PathEntity,
'propSpinner': PropSpinner.PropSpinner,
'visibilityExtender': VisibilityExtender.VisibilityExtender,
'zone': ZoneEntity.ZoneEntity})
def doCreateEntity(self, ctor, entId):
return ctor(self.level, entId)

View file

@ -0,0 +1,48 @@
import EntityCreatorBase
import LogicGate
import EditMgrAI
import LevelMgrAI
import ZoneEntityAI
from direct.showbase.PythonUtil import Functor
def createDistributedEntity(AIclass, level, entId, zoneId):
ent = AIclass(level, entId)
ent.generateWithRequired(zoneId)
return ent
def createLocalEntity(AIclass, level, entId, zoneId):
ent = AIclass(level, entId)
return ent
def nothing(*args):
return 'nothing'
class EntityCreatorAI(EntityCreatorBase.EntityCreatorBase):
def __init__(self, level):
EntityCreatorBase.EntityCreatorBase.__init__(self, level)
cLE = createLocalEntity
self.privRegisterTypes({'attribModifier': nothing,
'ambientSound': nothing,
'collisionSolid': nothing,
'cutScene': nothing,
'editMgr': Functor(cLE, EditMgrAI.EditMgrAI),
'entityGroup': nothing,
'entrancePoint': nothing,
'levelMgr': Functor(cLE, LevelMgrAI.LevelMgrAI),
'locator': nothing,
'logicGate': Functor(cLE, LogicGate.LogicGate),
'model': nothing,
'nodepath': nothing,
'path': nothing,
'propSpinner': nothing,
'visibilityExtender': nothing,
'zone': Functor(cLE, ZoneEntityAI.ZoneEntityAI)})
def doCreateEntity(self, ctor, entId):
zoneId = self.level.getEntityZoneId(entId)
self.notify.debug('creating entity %s in zone %s' % (entId, zoneId))
return ctor(self.level, entId, zoneId)

View file

@ -0,0 +1,27 @@
from direct.directnotify import DirectNotifyGlobal
class EntityCreatorBase:
notify = DirectNotifyGlobal.directNotify.newCategory('EntityCreator')
def __init__(self, level):
self.level = level
self.entType2Ctor = {}
def createEntity(self, entId):
entType = self.level.getEntityType(entId)
if not self.entType2Ctor.has_key(entType):
self.notify.error('unknown entity type: %s (ent%s)' % (entType, entId))
ent = self.doCreateEntity(self.entType2Ctor[entType], entId)
return ent
def getEntityTypes(self):
return self.entType2Ctor.keys()
def privRegisterType(self, entType, ctor):
if self.entType2Ctor.has_key(entType):
self.notify.debug('replacing %s ctor %s with %s' % (entType, self.entType2Ctor[entType], ctor))
self.entType2Ctor[entType] = ctor
def privRegisterTypes(self, type2ctor):
for entType, ctor in type2ctor.items():
self.privRegisterType(entType, ctor)

View file

@ -0,0 +1,35 @@
from direct.fsm.StatePush import StateVar
from direct.showbase.PythonUtil import getSetterName
from otp.level.Entity import Entity
class EntityStateVarSet(Entity):
def __init__(self, entType):
self._entType = entType
self._attribNames = []
for attrib in self._entType.attribs:
name, defaultVal, type = attrib
self._addAttrib(name, defaultVal, type)
def initializeEntity(self, level, entId):
stateVars = {}
for attribName in self._attribNames:
stateVars[attribName] = getattr(self, attribName)
Entity.initializeEntity(self, level, entId)
for attribName in self._attribNames:
stateVars[attribName].set(getattr(self, attribName))
for attribName in self._attribNames:
setattr(self, attribName, stateVars[attribName])
def _getAttributeNames(self):
return self._attribNames[:]
def _setter(self, name, value):
getattr(self, name).set(value)
def _addAttrib(self, name, defaultVal, type):
setattr(self, name, StateVar(defaultVal))
setattr(self, getSetterName(name), Functor(self._setter, name))
self._attribNames.append(name)

View file

@ -0,0 +1,85 @@
from direct.directnotify import DirectNotifyGlobal
import AttribDesc
from direct.showbase.PythonUtil import mostDerivedLast
class EntityTypeDesc:
notify = DirectNotifyGlobal.directNotify.newCategory('EntityTypeDesc')
output = None
def __init__(self):
self.__class__.privCompileAttribDescs(self.__class__)
self.attribNames = []
self.attribDescDict = {}
attribDescs = self.__class__._attribDescs
for desc in attribDescs:
attribName = desc.getName()
self.attribNames.append(attribName)
self.attribDescDict[attribName] = desc
def isConcrete(self):
return not self.__class__.__dict__.has_key('abstract')
def isPermanent(self):
return self.__class__.__dict__.has_key('permanent')
def getOutputType(self):
return self.output
def getAttribNames(self):
return self.attribNames
def getAttribDescDict(self):
return self.attribDescDict
def getAttribsOfType(self, type):
names = []
for attribName, desc in self.attribDescDict.items():
if desc.getDatatype() == type:
names.append(attribName)
return names
@staticmethod
def privCompileAttribDescs(entTypeClass):
if entTypeClass.__dict__.has_key('_attribDescs'):
return
c = entTypeClass
EntityTypeDesc.notify.debug('compiling attrib descriptors for %s' % c.__name__)
for base in c.__bases__:
EntityTypeDesc.privCompileAttribDescs(base)
blockAttribs = c.__dict__.get('blockAttribs', [])
baseADs = []
bases = list(c.__bases__)
mostDerivedLast(bases)
for base in bases:
for desc in base._attribDescs:
if desc.getName() in blockAttribs:
continue
for d in baseADs:
if desc.getName() == d.getName():
EntityTypeDesc.notify.warning('%s inherits attrib %s from multiple bases' % (c.__name__, desc.getName()))
break
else:
baseADs.append(desc)
attribDescs = []
if c.__dict__.has_key('attribs'):
for attrib in c.attribs:
desc = AttribDesc.AttribDesc(*attrib)
if desc.getName() == 'type' and entTypeClass.__name__ != 'Entity':
EntityTypeDesc.notify.error("(%s): '%s' is a reserved attribute name" % (entTypeClass.__name__, desc.getName()))
for ad in baseADs:
if ad.getName() == desc.getName():
baseADs.remove(ad)
break
attribDescs.append(desc)
c._attribDescs = baseADs + attribDescs
def __str__(self):
return str(self.__class__)
def __repr__(self):
return str(self.__class__.__dict__.get('type', None)) + str(self.output) + str(self.attribDescDict)

View file

@ -0,0 +1,99 @@
from pandac.PandaModules import *
from direct.directnotify import DirectNotifyGlobal
import types
import AttribDesc
import EntityTypeDesc
from direct.showbase.PythonUtil import mostDerivedLast
import os
import string
class EntityTypeRegistry:
notify = DirectNotifyGlobal.directNotify.newCategory('EntityTypeRegistry')
def __init__(self, entityTypeModule):
self.entTypeModule = entityTypeModule
hv = HashVal()
import EntityTypes
reload(EntityTypes)
reload(self.entTypeModule)
def getPyExtVersion(filename):
base, ext = os.path.splitext(filename)
if ext == '.pyc' or ext == '.pyo':
filename = base + '.py'
return filename
fileLines = file(getPyExtVersion(EntityTypes.__file__)).readlines()
hv.hashString(string.join(fileLines, ''))
s = str(hv.asHex())
s += '.'
fileLines = file(getPyExtVersion(self.entTypeModule.__file__)).readlines()
hv.hashString(string.join(fileLines, ''))
s += str(hv.asHex())
self.hashStr = s
getPyExtVersion = None
classes = []
for key, value in entityTypeModule.__dict__.items():
if type(value) is types.ClassType:
if issubclass(value, EntityTypeDesc.EntityTypeDesc):
classes.append(value)
self.entTypeName2typeDesc = {}
mostDerivedLast(classes)
for c in classes:
if c.__dict__.has_key('type'):
if self.entTypeName2typeDesc.has_key(c.type):
EntityTypeRegistry.notify.debug("replacing %s with %s for entity type '%s'" % (self.entTypeName2typeDesc[c.type].__class__, c, c.type))
self.entTypeName2typeDesc[c.type] = c()
self.output2typeNames = {}
for typename, typeDesc in self.entTypeName2typeDesc.items():
if typeDesc.isConcrete():
if hasattr(typeDesc, 'output'):
outputType = typeDesc.output
self.output2typeNames.setdefault(outputType, [])
self.output2typeNames[outputType].append(typename)
self.permanentTypeNames = []
for typename, typeDesc in self.entTypeName2typeDesc.items():
if typeDesc.isPermanent():
self.permanentTypeNames.append(typename)
self.typeName2derivedTypeNames = {}
for typename, typeDesc in self.entTypeName2typeDesc.items():
typenames = []
for tn, td in self.entTypeName2typeDesc.items():
if td.isConcrete():
if issubclass(td.__class__, typeDesc.__class__):
typenames.append(tn)
self.typeName2derivedTypeNames[typename] = typenames
return
def getAllTypeNames(self):
return self.entTypeName2typeDesc.keys()
def getTypeDesc(self, entTypeName):
return self.entTypeName2typeDesc[entTypeName]
def getTypeNamesFromOutputType(self, outputType):
return self.output2typeNames.get(outputType, [])
def getDerivedTypeNames(self, entTypeName):
return self.typeName2derivedTypeNames[entTypeName]
def isDerivedAndBase(self, entType, baseEntType):
return entType in self.getDerivedTypeNames(baseEntType)
def getPermanentTypeNames(self):
return self.permanentTypeNames
def getHashStr(self):
return self.hashStr
def __hash__(self):
return hash(repr(self))
def __repr__(self):
return str(self.entTypeName2typeDesc)

176
otp/level/EntityTypes.py Normal file
View file

@ -0,0 +1,176 @@
from EntityTypeDesc import EntityTypeDesc
from toontown.coghq.SpecImports import *
class Entity(EntityTypeDesc):
abstract = 1
type = 'entity'
attribs = (('type', None, 'const'),
('name', '<unnamed>', 'string'),
('comment', '', 'string'),
('parentEntId', 0, 'entId'))
class LevelMgr(Entity):
type = 'levelMgr'
permanent = 1
attribs = (('name', 'LevelMgr', 'const'), ('parentEntId', 0, 'const'), ('modelFilename', '', 'const'))
class EditMgr(Entity):
type = 'editMgr'
permanent = 1
blockAttribs = ('comment',)
attribs = (('name', 'LevelMgr', 'const'),
('parentEntId', 0, 'const'),
('requestSave', None, 'const'),
('requestNewEntity', None, 'const'),
('insertEntity', None, 'const'),
('removeEntity', None, 'const'))
class AttribModifier(Entity):
type = 'attribModifier'
attribs = (('recursive', 0, 'bool'),
('typeName', '', 'string'),
('attribName', '', 'string'),
('value', '', 'string'))
class Locator(Entity):
type = 'locator'
attribs = (('searchPath', '', 'string'),)
class Nodepath(Entity):
type = 'nodepath'
attribs = (('parentEntId',
0,
'entId',
{'type': 'nodepath'}),
('pos', Point3(0, 0, 0), 'pos'),
('hpr', Vec3(0, 0, 0), 'hpr'),
('scale', 1, 'scale'))
class Zone(Nodepath):
type = 'zone'
permanent = 1
blockAttribs = ('pos', 'hpr')
attribs = (('parentEntId', 0, 'const'), ('description', '', 'string'), ('visibility', [], 'visZoneList'))
class EntrancePoint(Nodepath):
type = 'entrancePoint'
attribs = (('entranceId', -1, 'int'), ('radius',
15,
'float',
{'min': 0}), ('theta',
20,
'float',
{'min': 0}))
class LogicGate(Entity):
type = 'logicGate'
output = 'bool'
attribs = (('input1Event',
0,
'entId',
{'output': 'bool'}),
('input2Event',
0,
'entId',
{'output': 'bool'}),
('isInput1', 0, 'bool'),
('isInput2', 0, 'bool'),
('logicType',
'or',
'choice',
{'choiceSet': ['or',
'and',
'xor',
'nand',
'nor',
'xnor']}))
class CutScene(Entity):
type = 'cutScene'
output = 'bool'
attribs = (('pos', Point3(0, 0, 0), 'pos'),
('hpr', Vec3(0, 0, 0), 'hpr'),
('startStopEvent',
0,
'entId',
{'output': 'bool'}),
('effect',
'irisInOut',
'choice',
{'choiceSet': ['nothing', 'irisInOut', 'letterBox']}),
('motion',
'foo1',
'choice',
{'choiceSet': ['foo1']}),
('duration', 5.0, 'float'))
class CollisionSolid(Nodepath):
type = 'collisionSolid'
attribs = (('solidType',
'sphere',
'choice',
{'choiceSet': ['sphere', 'tube']}),
('radius', 1.0, 'float'),
('length', 0.0, 'float'),
('showSolid', 0, 'bool'))
class Model(Nodepath):
type = 'model'
attribs = (('loadType',
'loadModelCopy',
'choice',
{'choiceSet': ['loadModelCopy', 'loadModel', 'loadModelOnce']}),
('modelPath', None, 'bamfilename'),
('flattenType',
'light',
'choice',
{'choiceSet': ['none',
'light',
'medium',
'strong']}),
('collisionsOnly', 0, 'bool'),
('goonHatType',
'none',
'choice',
{'choiceSet': ['none', 'hardhat', 'security']}))
class Path(Nodepath):
type = 'path'
attribs = (('pathIndex', 0, 'int'), ('pathScale', 1.0, 'float'))
class VisibilityExtender(Entity):
type = 'visibilityExtender'
attribs = (('event',
None,
'entId',
{'output': 'bool'}), ('newZones', [], 'visZoneList'))
class AmbientSound(Nodepath):
type = 'ambientSound'
attribs = (('soundPath', '', 'bamfilename'), ('volume',
1,
'float',
{'min': 0,
'max': 1}), ('enabled', 1, 'bool'))
class PropSpinner(Entity):
type = 'propSpinner'
class EntityGroup(Entity):
type = 'entityGroup'

View file

@ -0,0 +1,40 @@
from toontown.toonbase.ToontownGlobals import *
from direct.directnotify import DirectNotifyGlobal
import BasicEntities
class EntrancePoint(BasicEntities.NodePathEntity):
def __init__(self, level, entId):
BasicEntities.NodePathEntity.__init__(self, level, entId)
self.rotator = self.attachNewNode('rotator')
self.placer = self.rotator.attachNewNode('placer')
self.initEntrancePoint()
def destroy(self):
self.destroyEntrancePoint()
self.placer.removeNode()
self.rotator.removeNode()
del self.placer
del self.rotator
BasicEntities.NodePathEntity.destroy(self)
def placeToon(self, toon, toonIndex, numToons):
self.placer.setY(-self.radius)
self.rotator.setH(-self.theta * (numToons - 1) * 0.5 + toonIndex * self.theta)
toon.setPosHpr(self.placer, 0, 0, 0, 0, 0, 0)
def initEntrancePoint(self):
if self.entranceId >= 0:
self.level.entranceId2entity[self.entranceId] = self
def destroyEntrancePoint(self):
if self.entranceId >= 0:
if self.level.entranceId2entity.has_key(self.entranceId):
del self.level.entranceId2entity[self.entranceId]
if __dev__:
def attribChanged(self, *args):
BasicEntities.NodePathEntity.attribChanged(self, *args)
self.destroyEntrancePoint()
self.initEntrancePoint()

261
otp/level/Level.py Normal file
View file

@ -0,0 +1,261 @@
from direct.directnotify import DirectNotifyGlobal
import string
import LevelConstants
from direct.showbase.PythonUtil import lineInfo, uniqueElements
import types
class Level:
notify = DirectNotifyGlobal.directNotify.newCategory('Level')
def __init__(self):
self.levelSpec = None
self.initialized = 0
return
def initializeLevel(self, levelId, levelSpec, scenarioIndex):
self.levelId = levelId
self.levelSpec = levelSpec
self.scenarioIndex = scenarioIndex
self.levelSpec.setScenario(self.scenarioIndex)
if __dev__:
self.levelSpec.setLevel(self)
self.entranceId2entity = {}
self.entId2createCallbacks = {}
self.createdEntIds = []
self.nonlocalEntIds = {}
self.nothingEntIds = {}
self.entityCreator = self.createEntityCreator()
self.entType2ids = self.levelSpec.getEntType2ids(self.levelSpec.getAllEntIds())
for entType in self.entityCreator.getEntityTypes():
self.entType2ids.setdefault(entType, [])
self.createAllEntities(priorityTypes=['levelMgr', 'zone', 'propSpinner'])
self.levelMgrEntity = self.getEntity(LevelConstants.LevelMgrEntId)
self.uberZoneEntity = self.getEntity(LevelConstants.UberZoneEntId)
self.initialized = 1
def isInitialized(self):
return self.initialized
def getLevelId(self):
return self.levelId
def destroyLevel(self):
self.destroyAllEntities()
if self.initialized:
del self.levelMgrEntity
del self.uberZoneEntity
del self.entityCreator
del self.entId2createCallbacks
del self.entranceId2entity
self.levelSpec.destroy()
del self.levelSpec
self.initialized = 0
del self.createdEntIds
del self.nonlocalEntIds
del self.nothingEntIds
if hasattr(self, 'entities'):
del self.entities
if hasattr(self, 'levelSpec'):
self.levelSpec.destroy()
del self.levelSpec
def createEntityCreator(self):
Level.notify.error('concrete Level class must override %s' % lineInfo()[2])
def createAllEntities(self, priorityTypes = []):
self.entities = {}
entTypes = self.entityCreator.getEntityTypes()
self.onLevelPreCreate()
for type in priorityTypes:
self.createAllEntitiesOfType(type)
entTypes.remove(type)
for type in entTypes:
self.createAllEntitiesOfType(type)
self.onLevelPostCreate()
def destroyAllEntities(self):
self.nonlocalEntIds = {}
self.nothingEntIds = {}
if not uniqueElements(self.createdEntIds):
Level.notify.warning('%s: self.createdEntIds is not unique: %s' % (getattr(self, 'doId', None), self.createdEntIds))
while len(self.createdEntIds) > 0:
entId = self.createdEntIds.pop()
entity = self.getEntity(entId)
if entity is not None:
Level.notify.debug('destroying %s %s' % (self.getEntityType(entId), entId))
entity.destroy()
else:
Level.notify.error('trying to destroy entity %s, but it is already gone' % entId)
return
def createAllEntitiesOfType(self, entType):
self.onEntityTypePreCreate(entType)
for entId in self.entType2ids[entType]:
self.createEntity(entId)
self.onEntityTypePostCreate(entType)
def createEntity(self, entId):
spec = self.levelSpec.getEntitySpec(entId)
Level.notify.debug('creating %s %s' % (spec['type'], entId))
entity = self.entityCreator.createEntity(entId)
announce = False
if entity is 'nonlocal':
self.nonlocalEntIds[entId] = None
elif entity is 'nothing':
self.nothingEntIds[entId] = None
announce = True
else:
self.createdEntIds.append(entId)
announce = True
if announce:
self.onEntityCreate(entId)
return entity
def initializeEntity(self, entity):
entId = entity.entId
spec = self.levelSpec.getEntitySpec(entId)
for key, value in spec.items():
if key in ('type', 'name', 'comment'):
continue
entity.setAttribInit(key, value)
self.entities[entId] = entity
def getEntity(self, entId):
if hasattr(self, 'entities'):
return self.entities.get(entId)
else:
return None
return None
def getEntityType(self, entId):
return self.levelSpec.getEntityType(entId)
def getEntityZoneEntId(self, entId):
return self.levelSpec.getEntityZoneEntId(entId)
def getEntityZoneId(self, entId):
zoneEntId = self.getEntityZoneEntId(entId)
if not hasattr(self, 'zoneNum2zoneId'):
return None
return self.zoneNum2zoneId.get(zoneEntId)
def getZoneId(self, zoneEntId):
return self.zoneNum2zoneId[zoneEntId]
def getZoneNumFromId(self, zoneId):
return self.zoneId2zoneNum[zoneId]
def getParentTokenForEntity(self, entId):
return entId
def getLevelPreCreateEvent(self):
return 'levelPreCreate-%s' % self.levelId
def getLevelPostCreateEvent(self):
return 'levelPostCreate-%s' % self.levelId
def getEntityTypePreCreateEvent(self, entType):
return 'entityTypePreCreate-%s-%s' % (self.levelId, entType)
def getEntityTypePostCreateEvent(self, entType):
return 'entityTypePostCreate-%s-%s' % (self.levelId, entType)
def getEntityCreateEvent(self, entId):
return 'entityCreate-%s-%s' % (self.levelId, entId)
def getEntityOfTypeCreateEvent(self, entType):
return 'entityOfTypeCreate-%s-%s' % (self.levelId, entType)
def onLevelPreCreate(self):
messenger.send(self.getLevelPreCreateEvent())
def onLevelPostCreate(self):
messenger.send(self.getLevelPostCreateEvent())
def onEntityTypePreCreate(self, entType):
messenger.send(self.getEntityTypePreCreateEvent(entType))
def onEntityTypePostCreate(self, entType):
messenger.send(self.getEntityTypePostCreateEvent(entType))
def onEntityCreate(self, entId):
messenger.send(self.getEntityCreateEvent(entId))
messenger.send(self.getEntityOfTypeCreateEvent(self.getEntityType(entId)), [entId])
if entId in self.entId2createCallbacks:
for callback in self.entId2createCallbacks[entId]:
callback()
del self.entId2createCallbacks[entId]
def setEntityCreateCallback(self, entId, callback):
ent = self.getEntity(entId)
if ent is not None:
callNow = True
elif entId in self.nothingEntIds:
callNow = True
else:
callNow = False
if callNow:
callback()
else:
self.entId2createCallbacks.setdefault(entId, [])
self.entId2createCallbacks[entId].append(callback)
return
def getEntityDestroyEvent(self, entId):
return 'entityDestroy-%s-%s' % (self.levelId, entId)
def onEntityDestroy(self, entId):
messenger.send(self.getEntityDestroyEvent(entId))
del self.entities[entId]
if entId in self.createdEntIds:
self.createdEntIds.remove(entId)
def handleVisChange(self):
pass
if __dev__:
def getAttribChangeEventName(self):
return 'attribChange-%s' % self.levelId
def getInsertEntityEventName(self):
return 'insertEntity-%s' % self.levelId
def getRemoveEntityEventName(self):
return 'removeEntity-%s' % self.levelId
def handleAttribChange(self, entId, attrib, value, username = None):
entity = self.getEntity(entId)
if entity is not None:
entity.handleAttribChange(attrib, value)
messenger.send(self.getAttribChangeEventName(), [entId,
attrib,
value,
username])
return
def setEntityCreatorUsername(self, entId, editUsername):
pass
def handleEntityInsert(self, entId):
self.entType2ids[self.getEntityType(entId)].append(entId)
self.createEntity(entId)
messenger.send(self.getInsertEntityEventName(), [entId])
def handleEntityRemove(self, entId):
messenger.send(self.getRemoveEntityEventName(), [entId])
if entId in self.createdEntIds:
entity = self.getEntity(entId)
entity.destroy()
elif entId in self.nothingEntIds:
del self.nothingEntIds[entId]
elif entId in self.nonlocalEntIds:
del self.nonlocalEntIds[entId]
self.entType2ids[self.getEntityType(entId)].remove(entId)

View file

@ -0,0 +1,5 @@
MinZoneNum = 0
MaxZoneNum = 999
UberZoneEntId = 0
LevelMgrEntId = 1000
EditMgrEntId = 1001

46
otp/level/LevelMgr.py Normal file
View file

@ -0,0 +1,46 @@
from direct.showbase.PythonUtil import Functor
import LevelMgrBase
class LevelMgr(LevelMgrBase.LevelMgrBase):
def __init__(self, level, entId):
LevelMgrBase.LevelMgrBase.__init__(self, level, entId)
self.geom = loader.loadModel(self.modelFilename)
if not self.geom:
import pdb
pdb.set_trace()
self.zoneNums = []
self.level.zoneNum2zoneId = {}
self.level.zoneId2zoneNum = {}
self.accept(self.level.getEntityOfTypeCreateEvent('zone'), self.handleZoneCreated)
def destroy(self):
del self.level.zoneIds
del self.level.zoneId2zoneNum
del self.level.zoneNum2zoneId
self.geom.removeNode()
del self.geom
LevelMgrBase.LevelMgrBase.destroy(self)
def handleZoneCreated(self, entId):
zoneEnt = self.level.getEntity(entId)
self.zoneNums.append(zoneEnt.entId)
self.privAssignZoneIds()
self.accept(self.level.getEntityDestroyEvent(entId), Functor(self.handleZoneDestroy, entId))
def handleZoneDestroy(self, entId):
zoneEnt = self.level.getEntity(entId)
del self.level.zoneId2zoneNum[self.level.zoneNum2zoneId[zoneEnt.entId]]
del self.level.zoneNum2zoneId[zoneEnt.entId]
self.zoneNums.remove(zoneEnt.entId)
self.privAssignZoneIds()
def privAssignZoneIds(self):
self.zoneNums.sort()
for i in range(len(self.zoneNums)):
zoneNum = self.zoneNums[i]
zoneEnt = self.level.getEntity(zoneNum)
zoneId = self.level.zoneIds[i]
zoneEnt.setZoneId(zoneId)
self.level.zoneNum2zoneId[zoneNum] = zoneId
self.level.zoneId2zoneNum[zoneId] = zoneNum

33
otp/level/LevelMgrAI.py Normal file
View file

@ -0,0 +1,33 @@
from direct.showbase.PythonUtil import Functor
import LevelMgrBase
class LevelMgrAI(LevelMgrBase.LevelMgrBase):
def __init__(self, level, entId):
LevelMgrBase.LevelMgrBase.__init__(self, level, entId)
self.level.zoneNum2zoneId = {}
self.level.zoneIds = []
self.accept(self.level.getEntityOfTypeCreateEvent('zone'), self.handleZoneCreated)
def destroy(self):
del self.level.zoneIds
del self.level.zoneNum2zoneId
LevelMgrBase.LevelMgrBase.destroy(self)
def handleZoneCreated(self, entId):
zoneEnt = self.level.getEntity(entId)
self.level.zoneNum2zoneId[zoneEnt.entId] = zoneEnt.getZoneId()
self.privCreateSortedZoneIdList()
self.accept(self.level.getEntityDestroyEvent(entId), Functor(self.handleZoneDestroy, entId))
def handleZoneDestroy(self, entId):
zoneEnt = self.level.getEntity(entId)
del self.level.zoneNum2zoneId[zoneEnt.entId]
self.privCreateSortedZoneIdList()
def privCreateSortedZoneIdList(self):
zoneNums = self.level.zoneNum2zoneId.keys()
zoneNums.sort()
self.level.zoneIds = []
for zoneNum in zoneNums:
self.level.zoneIds.append(self.level.zoneNum2zoneId[zoneNum])

10
otp/level/LevelMgrBase.py Normal file
View file

@ -0,0 +1,10 @@
import Entity
class LevelMgrBase(Entity.Entity):
def __init__(self, level, entId):
Entity.Entity.__init__(self, level, entId)
def destroy(self):
Entity.Entity.destroy(self)
self.ignoreAll()

422
otp/level/LevelSpec.py Normal file
View file

@ -0,0 +1,422 @@
from pandac import PandaModules as PM
from direct.directnotify import DirectNotifyGlobal
from direct.showbase.PythonUtil import list2dict, uniqueElements
import string
import LevelConstants
import types
if __dev__:
import os
class LevelSpec:
notify = DirectNotifyGlobal.directNotify.newCategory('LevelSpec')
SystemEntIds = (LevelConstants.UberZoneEntId, LevelConstants.LevelMgrEntId, LevelConstants.EditMgrEntId)
def __init__(self, spec = None, scenario = 0):
newSpec = 0
if type(spec) is types.ModuleType:
if __dev__:
reload(spec)
self.specDict = spec.levelSpec
if __dev__:
self.setFilename(spec.__file__)
elif type(spec) is types.DictType:
self.specDict = spec
elif spec is None:
if __dev__:
newSpec = 1
self.specDict = {'globalEntities': {},
'scenarios': [{}]}
self.entId2specDict = {}
self.entId2specDict.update(list2dict(self.getGlobalEntIds(), value=self.privGetGlobalEntityDict()))
for i in range(self.getNumScenarios()):
self.entId2specDict.update(list2dict(self.getScenarioEntIds(i), value=self.privGetScenarioEntityDict(i)))
self.setScenario(scenario)
if __dev__:
if newSpec:
import EntityTypes
import EntityTypeRegistry
etr = EntityTypeRegistry.EntityTypeRegistry(EntityTypes)
self.setEntityTypeReg(etr)
entId = LevelConstants.UberZoneEntId
self.insertEntity(entId, 'zone')
self.doSetAttrib(entId, 'name', 'UberZone')
entId = LevelConstants.LevelMgrEntId
self.insertEntity(entId, 'levelMgr')
self.doSetAttrib(entId, 'name', 'LevelMgr')
entId = LevelConstants.EditMgrEntId
self.insertEntity(entId, 'editMgr')
self.doSetAttrib(entId, 'name', 'EditMgr')
return
def destroy(self):
del self.specDict
del self.entId2specDict
del self.scenario
if hasattr(self, 'level'):
del self.level
if hasattr(self, 'entTypeReg'):
del self.entTypeReg
def getNumScenarios(self):
return len(self.specDict['scenarios'])
def setScenario(self, scenario):
self.scenario = scenario
def getScenario(self):
return self.scenario
def getGlobalEntIds(self):
return self.privGetGlobalEntityDict().keys()
def getScenarioEntIds(self, scenario = None):
if scenario is None:
scenario = self.scenario
return self.privGetScenarioEntityDict(scenario).keys()
def getAllEntIds(self):
return self.getGlobalEntIds() + self.getScenarioEntIds()
def getAllEntIdsFromAllScenarios(self):
entIds = self.getGlobalEntIds()
for scenario in xrange(self.getNumScenarios()):
entIds.extend(self.getScenarioEntIds(scenario))
return entIds
def getEntitySpec(self, entId):
specDict = self.entId2specDict[entId]
return specDict[entId]
def getCopyOfSpec(self, spec):
specCopy = {}
if not isClient():
print 'EXECWARNING LevelSpec exec: %s' % self.getSpecImportsModuleName()
printStack()
exec 'from %s import *' % self.getSpecImportsModuleName()
for key in spec.keys():
specCopy[key] = eval(repr(spec[key]))
return specCopy
def getEntitySpecCopy(self, entId):
specDict = self.entId2specDict[entId]
return self.getCopyOfSpec(specDict[entId])
def getEntityType(self, entId):
return self.getEntitySpec(entId)['type']
def getEntityZoneEntId(self, entId):
spec = self.getEntitySpec(entId)
type = spec['type']
if type == 'zone':
return entId
return self.getEntityZoneEntId(spec['parentEntId'])
def getEntType2ids(self, entIds):
entType2ids = {}
for entId in entIds:
type = self.getEntityType(entId)
entType2ids.setdefault(type, [])
entType2ids[type].append(entId)
return entType2ids
def privGetGlobalEntityDict(self):
return self.specDict['globalEntities']
def privGetScenarioEntityDict(self, scenario):
return self.specDict['scenarios'][scenario]
def printZones(self):
allIds = self.getAllEntIds()
type2id = self.getEntType2ids(allIds)
zoneIds = type2id['zone']
if 0 in zoneIds:
zoneIds.remove(0)
zoneIds.sort()
for zoneNum in zoneIds:
spec = self.getEntitySpec(zoneNum)
print 'zone %s: %s' % (zoneNum, spec['name'])
if __dev__:
def setLevel(self, level):
self.level = level
def hasLevel(self):
return hasattr(self, 'level')
def setEntityTypeReg(self, entTypeReg):
self.entTypeReg = entTypeReg
for entId in self.getAllEntIds():
spec = self.getEntitySpec(entId)
type = self.getEntityType(entId)
typeDesc = self.entTypeReg.getTypeDesc(type)
attribDescDict = typeDesc.getAttribDescDict()
for attribName, desc in attribDescDict.iteritems():
if attribName not in spec:
spec[attribName] = desc.getDefaultValue()
self.checkSpecIntegrity()
def hasEntityTypeReg(self):
return hasattr(self, 'entTypeReg')
def setFilename(self, filename):
self.filename = filename
def doSetAttrib(self, entId, attrib, value):
specDict = self.entId2specDict[entId]
specDict[entId][attrib] = value
def setAttribChange(self, entId, attrib, value, username):
LevelSpec.notify.info('setAttribChange(%s): %s, %s = %s' % (username,
entId,
attrib,
repr(value)))
self.doSetAttrib(entId, attrib, value)
if self.hasLevel():
self.level.handleAttribChange(entId, attrib, value, username)
def insertEntity(self, entId, entType, parentEntId = 'unspecified'):
LevelSpec.notify.info('inserting entity %s (%s)' % (entId, entType))
globalEnts = self.privGetGlobalEntityDict()
self.entId2specDict[entId] = globalEnts
globalEnts[entId] = {}
spec = globalEnts[entId]
attribDescs = self.entTypeReg.getTypeDesc(entType).getAttribDescDict()
for name, desc in attribDescs.items():
spec[name] = desc.getDefaultValue()
spec['type'] = entType
if parentEntId != 'unspecified':
spec['parentEntId'] = parentEntId
if self.hasLevel():
self.level.handleEntityInsert(entId)
else:
LevelSpec.notify.warning('no level to be notified of insertion')
def removeEntity(self, entId):
LevelSpec.notify.info('removing entity %s' % entId)
if self.hasLevel():
self.level.handleEntityRemove(entId)
else:
LevelSpec.notify.warning('no level to be notified of removal')
dict = self.entId2specDict[entId]
del dict[entId]
del self.entId2specDict[entId]
def removeZoneReferences(self, removedZoneNums):
type2ids = self.getEntType2ids(self.getAllEntIdsFromAllScenarios())
for type in type2ids:
typeDesc = self.entTypeReg.getTypeDesc(type)
visZoneListAttribs = typeDesc.getAttribsOfType('visZoneList')
if len(visZoneListAttribs) > 0:
for entId in type2ids[type]:
spec = self.getEntitySpec(entId)
for attribName in visZoneListAttribs:
for zoneNum in removedZoneNums:
while zoneNum in spec[attribName]:
spec[attribName].remove(zoneNum)
def getSpecImportsModuleName(self):
return 'toontown.coghq.SpecImports'
def getFilename(self):
return self.filename
def privGetBackupFilename(self, filename):
return '%s.bak' % filename
def saveToDisk(self, filename = None, makeBackup = 1):
if filename is None:
filename = self.filename
if filename.endswith('.pyc'):
filename = filename.replace('.pyc', '.py')
if makeBackup and self.privFileExists(filename):
try:
backupFilename = self.privGetBackupFilename(filename)
self.privRemoveFile(backupFilename)
os.rename(filename, backupFilename)
except OSError, e:
LevelSpec.notify.warning('error during backup: %s' % str(e))
LevelSpec.notify.info("writing to '%s'" % filename)
self.privRemoveFile(filename)
self.privSaveToDisk(filename)
return
def privSaveToDisk(self, filename):
retval = 1
f = file(filename, 'wb')
try:
f.write(self.getPrettyString())
except IOError:
retval = 0
f.close()
return retval
def privFileExists(self, filename):
try:
os.stat(filename)
return 1
except OSError:
return 0
def privRemoveFile(self, filename):
try:
os.remove(filename)
return 1
except OSError:
return 0
def getPrettyString(self):
import pprint
tabWidth = 4
tab = ' ' * tabWidth
globalEntitiesName = 'GlobalEntities'
scenarioEntitiesName = 'Scenario%s'
topLevelName = 'levelSpec'
def getPrettyEntityDictStr(name, dict, tabs = 0):
def t(n):
return (tabs + n) * tab
def sortList(lst, firstElements = []):
elements = list(lst)
result = []
for el in firstElements:
if el in elements:
result.append(el)
elements.remove(el)
elements.sort()
result.extend(elements)
return result
firstTypes = ('levelMgr', 'editMgr', 'zone')
firstAttribs = ('type', 'name', 'comment', 'parentEntId', 'pos', 'x', 'y', 'z', 'hpr', 'h', 'p', 'r', 'scale', 'sx', 'sy', 'sz', 'color', 'model')
str = t(0) + '%s = {\n' % name
entIds = dict.keys()
entType2ids = self.getEntType2ids(entIds)
types = sortList(entType2ids.keys(), firstTypes)
for type in types:
str += t(1) + '# %s\n' % string.upper(type)
entIds = entType2ids[type]
entIds.sort()
for entId in entIds:
str += t(1) + '%s: {\n' % entId
spec = dict[entId]
attribs = sortList(spec.keys(), firstAttribs)
for attrib in attribs:
str += t(2) + "'%s': %s,\n" % (attrib, repr(spec[attrib]))
str += t(2) + '}, # end entity %s\n' % entId
str += t(1) + '}\n'
return str
def getPrettyTopLevelDictStr(tabs = 0):
def t(n):
return (tabs + n) * tab
str = t(0) + '%s = {\n' % topLevelName
str += t(1) + "'globalEntities': %s,\n" % globalEntitiesName
str += t(1) + "'scenarios': [\n"
for i in range(self.getNumScenarios()):
str += t(2) + '%s,\n' % (scenarioEntitiesName % i)
str += t(2) + '],\n'
str += t(1) + '}\n'
return str
str = 'from %s import *\n' % self.getSpecImportsModuleName()
str += '\n'
str += getPrettyEntityDictStr('GlobalEntities', self.privGetGlobalEntityDict())
str += '\n'
numScenarios = self.getNumScenarios()
for i in range(numScenarios):
str += getPrettyEntityDictStr('Scenario%s' % i, self.privGetScenarioEntityDict(i))
str += '\n'
str += getPrettyTopLevelDictStr()
self.testPrettyString(prettyString=str)
return str
def _recurKeyTest(self, dict1, dict2):
s = ''
errorCount = 0
if set(dict1.keys()) != set(dict2.keys()):
return 0
for key in dict1:
if type(dict1[key]) == type({}) and type(dict2[key]) == type({}):
if not self._recurKeyTest(dict1[key], dict2[key]):
return 0
else:
strd1 = repr(dict1[key])
strd2 = repr(dict2[key])
if strd1 != strd2:
s += '\nBAD VALUE(%s): %s != %s\n' % (key, strd1, strd2)
errorCount += 1
print s
if errorCount == 0:
return 1
else:
return 0
def testPrettyString(self, prettyString = None):
if prettyString is None:
prettyString = self.getPrettyString()
if not isClient():
print 'EXECWARNING LevelSpec exec 2: %s' % prettyString
printStack()
exec prettyString
if self._recurKeyTest(levelSpec, self.specDict):
return 1
return
def checkSpecIntegrity(self):
entIds = self.getGlobalEntIds()
entIds = list2dict(entIds)
for i in range(self.getNumScenarios()):
for id in self.getScenarioEntIds(i):
entIds[id] = None
if self.entTypeReg is not None:
allEntIds = entIds
for entId in allEntIds:
spec = self.getEntitySpec(entId)
entType = spec['type']
typeDesc = self.entTypeReg.getTypeDesc(entType)
attribNames = typeDesc.getAttribNames()
attribDescs = typeDesc.getAttribDescDict()
for attrib in spec.keys():
if attrib not in attribNames:
LevelSpec.notify.warning("entId %s (%s): unknown attrib '%s', omitting" % (entId, spec['type'], attrib))
del spec[attrib]
for attribName in attribNames:
if not spec.has_key(attribName):
LevelSpec.notify.warning("entId %s (%s): missing attrib '%s'" % (entId, spec['type'], attribName))
return
def stringHash(self):
h = PM.HashVal()
h.hashString(repr(self))
return h.asHex()
def __hash__(self):
return hash(repr(self))
def __str__(self):
return 'LevelSpec'
def __repr__(self):
return 'LevelSpec(%s, scenario=%s)' % (repeatableRepr(self.specDict), repeatableRepr(self.scenario))

40
otp/level/LevelUtil.py Normal file
View file

@ -0,0 +1,40 @@
import string
import LevelConstants
def getZoneNum2Node(levelModel, logFunc = lambda str: str):
def findNumberedNodes(baseString, model, caseInsens = 1):
srch = '**/%s*' % baseString
if caseInsens:
srch += ';+i'
potentialNodes = model.findAllMatches(srch)
num2node = {}
for potentialNode in potentialNodes:
name = potentialNode.getName()
logFunc('potential match for %s: %s' % (baseString, name))
name = name[len(baseString):]
numDigits = 0
while numDigits < len(name):
if name[numDigits] not in string.digits:
break
numDigits += 1
if numDigits == 0:
continue
num = int(name[:numDigits])
if num == LevelConstants.UberZoneEntId:
logFunc('warning: cannot use UberZone zoneNum (%s). ignoring %s' % (LevelConstants.UberZoneEntId, potentialNode))
continue
if num < LevelConstants.MinZoneNum or num > LevelConstants.MaxZoneNum:
logFunc('warning: zone %s is out of range. ignoring %s' % (num, potentialNode))
continue
if num in num2node:
logFunc('warning: zone %s already assigned to %s. ignoring %s' % (num, num2node[num], potentialNode))
continue
num2node[num] = potentialNode
return num2node
zoneNum2node = findNumberedNodes('zone', levelModel)
zoneNum2node[LevelConstants.UberZoneEntId] = levelModel
return zoneNum2node

Some files were not shown because too many files have changed in this diff Show more