general: push the 2013 TTO code
This commit is contained in:
parent
4e5cf131c0
commit
2c7d1a27da
1669 changed files with 432679 additions and 0 deletions
108
etc/Configrc.prc
Normal file
108
etc/Configrc.prc
Normal 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
0
otp/__init__.py
Normal file
175
otp/ai/AIBase.py
Normal file
175
otp/ai/AIBase.py
Normal 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
26
otp/ai/AIBaseGlobal.py
Normal 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()
|
8
otp/ai/AIInterestHandles.py
Normal file
8
otp/ai/AIInterestHandles.py
Normal 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
83
otp/ai/AIMsgTypes.py
Normal 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
217
otp/ai/AIZoneData.py
Normal 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
74
otp/ai/BanManagerAI.py
Normal 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
83
otp/ai/Barrier.py
Normal 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)
|
44
otp/ai/GarbageLeakServerEventAggregator.py
Normal file
44
otp/ai/GarbageLeakServerEventAggregator.py
Normal 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
875
otp/ai/MagicWordManager.py
Normal 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
350
otp/ai/TimeManager.py
Normal 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
0
otp/ai/__init__.py
Normal file
587
otp/avatar/Avatar.py
Normal file
587
otp/avatar/Avatar.py
Normal 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
26
otp/avatar/AvatarDNA.py
Normal 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
|
51
otp/avatar/AvatarDetail.py
Normal file
51
otp/avatar/AvatarDetail.py
Normal 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
|
24
otp/avatar/AvatarHandle.py
Normal file
24
otp/avatar/AvatarHandle.py
Normal 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
75
otp/avatar/AvatarPanel.py
Normal 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
|
262
otp/avatar/DistributedAvatar.py
Normal file
262
otp/avatar/DistributedAvatar.py
Normal 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
|
101
otp/avatar/DistributedAvatarAI.py
Normal file
101
otp/avatar/DistributedAvatarAI.py
Normal 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)
|
455
otp/avatar/DistributedPlayer.py
Normal file
455
otp/avatar/DistributedPlayer.py
Normal 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
|
129
otp/avatar/DistributedPlayerAI.py
Normal file
129
otp/avatar/DistributedPlayerAI.py
Normal 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
22
otp/avatar/Emote.py
Normal 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
1215
otp/avatar/LocalAvatar.py
Normal file
File diff suppressed because it is too large
Load diff
18
otp/avatar/PlayerBase.py
Normal file
18
otp/avatar/PlayerBase.py
Normal 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
|
94
otp/avatar/PositionExaminer.py
Normal file
94
otp/avatar/PositionExaminer.py
Normal 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
134
otp/avatar/ShadowCaster.py
Normal 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
|
91
otp/avatar/SpeedMonitor.py
Normal file
91
otp/avatar/SpeedMonitor.py
Normal 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
0
otp/avatar/__init__.py
Normal file
29
otp/chat/ChatGarbler.py
Normal file
29
otp/chat/ChatGarbler.py
Normal 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
53
otp/chat/ChatGlobals.py
Normal 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
161
otp/chat/ChatInputNormal.py
Normal 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
182
otp/chat/ChatInputTyped.py
Normal 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)
|
345
otp/chat/ChatInputWhiteListFrame.py
Normal file
345
otp/chat/ChatInputWhiteListFrame.py
Normal 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
517
otp/chat/ChatManager.py
Normal 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
753
otp/chat/TalkAssistant.py
Normal 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
19
otp/chat/TalkGlobals.py
Normal 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
41
otp/chat/TalkHandle.py
Normal 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
96
otp/chat/TalkMessage.py
Normal 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
51
otp/chat/WhiteList.py
Normal 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
0
otp/chat/__init__.py
Normal file
6
otp/distributed/Account.py
Normal file
6
otp/distributed/Account.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
from direct.distributed import DistributedObject
|
||||||
|
|
||||||
|
class Account(DistributedObject.DistributedObject):
|
||||||
|
|
||||||
|
def __init__(self, cr):
|
||||||
|
pass
|
29
otp/distributed/CentralLogger.py
Normal file
29
otp/distributed/CentralLogger.py
Normal 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])
|
58
otp/distributed/ClsendTracker.py
Normal file
58
otp/distributed/ClsendTracker.py
Normal 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
|
4
otp/distributed/DistributedDirectory.py
Normal file
4
otp/distributed/DistributedDirectory.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
from direct.distributed.DistributedObject import DistributedObject
|
||||||
|
|
||||||
|
class DistributedDirectory(DistributedObject):
|
||||||
|
pass
|
35
otp/distributed/DistributedDistrict.py
Normal file
35
otp/distributed/DistributedDistrict.py
Normal 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')
|
34
otp/distributed/DistributedTestObject.py
Normal file
34
otp/distributed/DistributedTestObject.py
Normal 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
|
133
otp/distributed/GameServerTestSuite.py
Normal file
133
otp/distributed/GameServerTestSuite.py
Normal 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())
|
2219
otp/distributed/OTPClientRepository.py
Normal file
2219
otp/distributed/OTPClientRepository.py
Normal file
File diff suppressed because it is too large
Load diff
11
otp/distributed/ObjectServer.py
Normal file
11
otp/distributed/ObjectServer.py
Normal 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
|
89
otp/distributed/OtpDoGlobals.py
Normal file
89
otp/distributed/OtpDoGlobals.py
Normal 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
|
22
otp/distributed/PotentialAvatar.py
Normal file
22
otp/distributed/PotentialAvatar.py
Normal 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
|
12
otp/distributed/PotentialShard.py
Normal file
12
otp/distributed/PotentialShard.py
Normal 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
|
22
otp/distributed/TelemetryLimited.py
Normal file
22
otp/distributed/TelemetryLimited.py
Normal 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)
|
113
otp/distributed/TelemetryLimiter.py
Normal file
113
otp/distributed/TelemetryLimiter.py
Normal 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
|
0
otp/distributed/__init__.py
Normal file
0
otp/distributed/__init__.py
Normal file
41
otp/friends/AvatarFriendInfo.py
Normal file
41
otp/friends/AvatarFriendInfo.py
Normal 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
|
109
otp/friends/AvatarFriendsManager.py
Normal file
109
otp/friends/AvatarFriendsManager.py
Normal 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
46
otp/friends/FriendInfo.py
Normal 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
|
111
otp/friends/FriendManager.py
Normal file
111
otp/friends/FriendManager.py
Normal 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])
|
6
otp/friends/FriendResponseCodes.py
Normal file
6
otp/friends/FriendResponseCodes.py
Normal 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
555
otp/friends/FriendSecret.py
Normal 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
407
otp/friends/GuildManager.py
Normal 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)
|
263
otp/friends/PlayerFriendsManager.py
Normal file
263
otp/friends/PlayerFriendsManager.py
Normal 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
0
otp/friends/__init__.py
Normal file
28
otp/launcher/DownloadWatcher.py
Normal file
28
otp/launcher/DownloadWatcher.py
Normal 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()
|
157
otp/launcher/DummyLauncherBase.py
Normal file
157
otp/launcher/DummyLauncherBase.py
Normal 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
1877
otp/launcher/LauncherBase.py
Normal file
File diff suppressed because it is too large
Load diff
0
otp/launcher/__init__.py
Normal file
0
otp/launcher/__init__.py
Normal file
43
otp/launcher/procapi.py
Normal file
43
otp/launcher/procapi.py
Normal 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
39
otp/level/AmbientSound.py
Normal 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
30
otp/level/AttribDesc.py
Normal 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
131
otp/level/BasicEntities.py
Normal 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)
|
45
otp/level/CollisionSolidEntity.py
Normal file
45
otp/level/CollisionSolidEntity.py
Normal 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
99
otp/level/CutScene.py
Normal 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,)
|
50
otp/level/DistributedEntity.py
Normal file
50
otp/level/DistributedEntity.py
Normal 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)
|
45
otp/level/DistributedEntityAI.py
Normal file
45
otp/level/DistributedEntityAI.py
Normal 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)
|
69
otp/level/DistributedInteractiveEntity.py
Normal file
69
otp/level/DistributedInteractiveEntity.py
Normal 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
|
586
otp/level/DistributedLevel.py
Normal file
586
otp/level/DistributedLevel.py
Normal 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
|
180
otp/level/DistributedLevelAI.py
Normal file
180
otp/level/DistributedLevelAI.py
Normal 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
4
otp/level/EditMgr.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import EditMgrBase
|
||||||
|
|
||||||
|
class EditMgr(EditMgrBase.EditMgrBase):
|
||||||
|
pass
|
41
otp/level/EditMgrAI.py
Normal file
41
otp/level/EditMgrAI.py
Normal 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
25
otp/level/EditMgrBase.py
Normal 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
|
40
otp/level/EditorGlobals.py
Normal file
40
otp/level/EditorGlobals.py
Normal 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
101
otp/level/Entity.py
Normal 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
|
49
otp/level/EntityCreator.py
Normal file
49
otp/level/EntityCreator.py
Normal 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)
|
48
otp/level/EntityCreatorAI.py
Normal file
48
otp/level/EntityCreatorAI.py
Normal 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)
|
27
otp/level/EntityCreatorBase.py
Normal file
27
otp/level/EntityCreatorBase.py
Normal 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)
|
35
otp/level/EntityStateVarSet.py
Normal file
35
otp/level/EntityStateVarSet.py
Normal 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)
|
85
otp/level/EntityTypeDesc.py
Normal file
85
otp/level/EntityTypeDesc.py
Normal 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)
|
99
otp/level/EntityTypeRegistry.py
Normal file
99
otp/level/EntityTypeRegistry.py
Normal 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
176
otp/level/EntityTypes.py
Normal 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'
|
40
otp/level/EntrancePoint.py
Normal file
40
otp/level/EntrancePoint.py
Normal 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
261
otp/level/Level.py
Normal 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)
|
5
otp/level/LevelConstants.py
Normal file
5
otp/level/LevelConstants.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
MinZoneNum = 0
|
||||||
|
MaxZoneNum = 999
|
||||||
|
UberZoneEntId = 0
|
||||||
|
LevelMgrEntId = 1000
|
||||||
|
EditMgrEntId = 1001
|
46
otp/level/LevelMgr.py
Normal file
46
otp/level/LevelMgr.py
Normal 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
33
otp/level/LevelMgrAI.py
Normal 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
10
otp/level/LevelMgrBase.py
Normal 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
422
otp/level/LevelSpec.py
Normal 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
40
otp/level/LevelUtil.py
Normal 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
Loading…
Reference in a new issue