ai: Remove old magic word code
This commit is contained in:
parent
346e9ae704
commit
e641fe0a45
10 changed files with 5 additions and 1740 deletions
|
@ -6,7 +6,6 @@ from direct.distributed import DistributedCamera/AI/OV
|
||||||
from otp.distributed import Account/AI/UD
|
from otp.distributed import Account/AI/UD
|
||||||
from otp.distributed import AstronAccount/AI/UD
|
from otp.distributed import AstronAccount/AI/UD
|
||||||
from otp.ai import TimeManager/AI
|
from otp.ai import TimeManager/AI
|
||||||
from otp.ai import MagicWordManager/AI
|
|
||||||
from otp.avatar import DistributedAvatar/AI/UD
|
from otp.avatar import DistributedAvatar/AI/UD
|
||||||
from otp.avatar import DistributedPlayer/AI
|
from otp.avatar import DistributedPlayer/AI
|
||||||
from otp.friends import FriendManager/AI
|
from otp.friends import FriendManager/AI
|
||||||
|
@ -257,12 +256,6 @@ dclass DistributedPlayer : DistributedAvatar {
|
||||||
setAsGM(bool = 0) required ram broadcast ownrecv airecv;
|
setAsGM(bool = 0) required ram broadcast ownrecv airecv;
|
||||||
};
|
};
|
||||||
|
|
||||||
dclass MagicWordManager : DistributedObject {
|
|
||||||
setMagicWord(string, uint32, uint32, string(0-256)) airecv clsend;
|
|
||||||
setMagicWordResponse(string) airecv;
|
|
||||||
setWho(uint32[]) airecv clsend;
|
|
||||||
};
|
|
||||||
|
|
||||||
dclass OtpAvatarManager : DistributedObject {
|
dclass OtpAvatarManager : DistributedObject {
|
||||||
online();
|
online();
|
||||||
requestAvatarList(uint32) airecv clsend;
|
requestAvatarList(uint32) airecv clsend;
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
from direct.directnotify import DirectNotifyGlobal
|
|
||||||
from direct.distributed.DistributedObjectAI import DistributedObjectAI
|
|
||||||
|
|
||||||
class DistributedBlackCatMgrAI(DistributedObjectAI):
|
|
||||||
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedBlackCatMgrAI')
|
|
|
@ -1,875 +0,0 @@
|
||||||
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 otp.otpbase.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 = list(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 range(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 list(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 builtins
|
|
||||||
builtins.magicWord = magicWord
|
|
|
@ -1,5 +0,0 @@
|
||||||
from direct.directnotify import DirectNotifyGlobal
|
|
||||||
from direct.distributed.DistributedObjectAI import DistributedObjectAI
|
|
||||||
|
|
||||||
class MagicWordManagerAI(DistributedObjectAI):
|
|
||||||
notify = DirectNotifyGlobal.directNotify.newCategory('MagicWordManagerAI')
|
|
|
@ -457,6 +457,8 @@ class DistributedPlayer(DistributedAvatar.DistributedAvatar, PlayerBase.PlayerBa
|
||||||
|
|
||||||
def setAccessLevel(self, accessLevel):
|
def setAccessLevel(self, accessLevel):
|
||||||
self.accessLevel = accessLevel
|
self.accessLevel = accessLevel
|
||||||
|
if self.isLocal():
|
||||||
|
self.cr.wantMagicWords = self.accessLevel > OTPGlobals.AccessLevelName2Int.get('NO_ACCESS')
|
||||||
|
|
||||||
def getAccessLevel(self):
|
def getAccessLevel(self):
|
||||||
return self.accessLevel
|
return self.accessLevel
|
||||||
|
|
|
@ -617,7 +617,7 @@ class TalkAssistant(DirectObject.DirectObject):
|
||||||
|
|
||||||
def sendOpenTalk(self, message):
|
def sendOpenTalk(self, message):
|
||||||
error = None
|
error = None
|
||||||
if base.cr.magicWordManager and base.localAvatar.getAccessLevel() > OTPGlobals.AccessLevelName2Int.get('NO_ACCESS') and len(message) > 0 and message[0] == base.cr.magicWordManager.chatPrefix:
|
if base.cr.magicWordManager and base.cr.wantMagicWords and len(message) > 0 and message[0] == base.cr.magicWordManager.chatPrefix:
|
||||||
messenger.send('magicWord', [message])
|
messenger.send('magicWord', [message])
|
||||||
self.receiveDeveloperMessage(message)
|
self.receiveDeveloperMessage(message)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -161,7 +161,7 @@ class OTPClientRepository(ClientRepositoryBase):
|
||||||
else:
|
else:
|
||||||
self.notify.error('The required-login was not recognized.')
|
self.notify.error('The required-login was not recognized.')
|
||||||
|
|
||||||
self.wantMagicWords = base.config.GetString('want-magic-words', '')
|
self.wantMagicWords = False
|
||||||
if self.launcher and hasattr(self.launcher, 'http'):
|
if self.launcher and hasattr(self.launcher, 'http'):
|
||||||
self.http = self.launcher.http
|
self.http = self.launcher.http
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,840 +0,0 @@
|
||||||
from direct.interval.IntervalGlobal import *
|
|
||||||
from direct.distributed import PyDatagram
|
|
||||||
from direct.distributed.MsgTypes import MsgName2Id
|
|
||||||
from pandac.PandaModules import *
|
|
||||||
from direct.distributed import DistributedObject
|
|
||||||
from toontown.toon import DistributedToon
|
|
||||||
from direct.directnotify import DirectNotifyGlobal
|
|
||||||
from toontown.town import TownBattleAttackPanel
|
|
||||||
from toontown.suit import RoguesGallery
|
|
||||||
from otp.avatar import Avatar
|
|
||||||
from otp.chat import ChatManager
|
|
||||||
from toontown.toonbase import ToontownGlobals
|
|
||||||
from toontown.toonbase import ToontownBattleGlobals
|
|
||||||
import string
|
|
||||||
from toontown.toon import Toon
|
|
||||||
from direct.showbase import PythonUtil
|
|
||||||
from toontown.suit import DistributedSuitPlanner
|
|
||||||
from toontown.suit import DistributedBossCog
|
|
||||||
from otp.otpbase import OTPGlobals
|
|
||||||
from direct.distributed.ClockDelta import *
|
|
||||||
from otp.ai import MagicWordManager
|
|
||||||
from toontown.hood import ZoneUtil
|
|
||||||
from toontown.battle import Fanfare
|
|
||||||
from toontown.golf import GolfGlobals
|
|
||||||
from toontown.distributed import ToontownDistrictStats
|
|
||||||
from toontown.coderedemption import TTCodeRedemptionConsts
|
|
||||||
from toontown.rpc import AwardManagerConsts
|
|
||||||
if base.wantKarts:
|
|
||||||
from toontown.racing.KartDNA import *
|
|
||||||
from toontown.racing.KartShopGui import *
|
|
||||||
if (__debug__):
|
|
||||||
import pdb
|
|
||||||
|
|
||||||
class ToontownMagicWordManager(MagicWordManager.MagicWordManager):
|
|
||||||
notify = DirectNotifyGlobal.directNotify.newCategory('ToontownMagicWordManager')
|
|
||||||
neverDisable = 1
|
|
||||||
GameAvatarClass = DistributedToon.DistributedToon
|
|
||||||
|
|
||||||
def __init__(self, cr):
|
|
||||||
MagicWordManager.MagicWordManager.__init__(self, cr)
|
|
||||||
self.rogues = None
|
|
||||||
self.ruler = None
|
|
||||||
self.dbg_running_fast = 0
|
|
||||||
return
|
|
||||||
|
|
||||||
def generate(self):
|
|
||||||
MagicWordManager.MagicWordManager.generate(self)
|
|
||||||
self.accept('magicWord', self.b_setMagicWord)
|
|
||||||
|
|
||||||
def doLoginMagicWords(self):
|
|
||||||
MagicWordManager.MagicWordManager.doLoginMagicWords(self)
|
|
||||||
if base.config.GetBool('want-chat', 0):
|
|
||||||
self.d_setMagicWord('~chat', base.localAvatar.doId, 0)
|
|
||||||
if base.config.GetBool('want-run', 0) or base.config.GetBool('want-toontown-run', 0):
|
|
||||||
self.toggleRun()
|
|
||||||
if base.config.GetBool('immortal-mode', 0):
|
|
||||||
self.d_setMagicWord('~immortal', base.localAvatar.doId, 0)
|
|
||||||
mintFloor = base.config.GetInt('mint-floor', -1)
|
|
||||||
if mintFloor != -1:
|
|
||||||
self.d_setMagicWord('~mintFloor %s' % mintFloor, base.localAvatar.doId, 0)
|
|
||||||
mintId = base.config.GetInt('mint-id', -1)
|
|
||||||
if mintId != -1:
|
|
||||||
self.d_setMagicWord('~mint %s' % mintId, base.localAvatar.doId, 0)
|
|
||||||
autoRestock = base.config.GetInt('auto-restock', -1)
|
|
||||||
if autoRestock != -1:
|
|
||||||
self.d_setMagicWord('~autoRestock %s' % autoRestock, base.localAvatar.doId, 0)
|
|
||||||
autoRich = base.config.GetInt('auto-rich', -1)
|
|
||||||
if autoRich != -1:
|
|
||||||
self.d_setMagicWord('~autoRich %s' % autoRich, base.localAvatar.doId, 0)
|
|
||||||
autoResistanceRestock = base.config.GetInt('auto-resistance-restock', -1)
|
|
||||||
if autoResistanceRestock != -1:
|
|
||||||
self.d_setMagicWord('~autoResistanceRestock %s' % autoResistanceRestock, base.localAvatar.doId, 0)
|
|
||||||
autoRestockSOS = base.config.GetInt('auto-restock-sos', -1)
|
|
||||||
if autoRestockSOS != -1:
|
|
||||||
self.d_setMagicWord('~autoRestockSOS %s' % autoRestockSOS, base.localAvatar.doId, 0)
|
|
||||||
autoRestockPinkSlips = base.config.GetInt('auto-restock-pink-slips', -1)
|
|
||||||
if autoRestockPinkSlips != -1:
|
|
||||||
self.d_setMagicWord('~autoRestockPinkSlips %s' % autoRestockPinkSlips, base.localAvatar.doId, 0)
|
|
||||||
autoRestockSummons = base.config.GetInt('auto-restock-summons', -1)
|
|
||||||
if autoRestockSummons != -1:
|
|
||||||
self.d_setMagicWord('~autoRestockSummons %s' % autoRestockSummons, base.localAvatar.doId, 0)
|
|
||||||
paidStatus = base.config.GetString('force-paid-status', 'none')
|
|
||||||
if paidStatus != 'none':
|
|
||||||
self.d_setMagicWord('~setPaid %s' % choice(paidStatus == 'paid', 1, 0), localAvatar.doId, 0)
|
|
||||||
self.doConfigMagicWords()
|
|
||||||
|
|
||||||
def doConfigMagicWords(self):
|
|
||||||
autoMagicWords = base.config.GetString('auto-magic-words', '').split('|')
|
|
||||||
for command in autoMagicWords:
|
|
||||||
if command:
|
|
||||||
self.d_setMagicWord(command.strip(), base.localAvatar.doId, 0)
|
|
||||||
|
|
||||||
def disable(self):
|
|
||||||
self.ignore('magicWord')
|
|
||||||
if self.dbg_running_fast:
|
|
||||||
self.toggleRun()
|
|
||||||
MagicWordManager.MagicWordManager.disable(self)
|
|
||||||
|
|
||||||
def doMagicWord(self, word, avId, zoneId):
|
|
||||||
wordIs = Functor(self.wordIs, word)
|
|
||||||
if MagicWordManager.MagicWordManager.doMagicWord(self, word, avId, zoneId) == 1:
|
|
||||||
pass
|
|
||||||
elif wordIs('~fanfare'):
|
|
||||||
go = Fanfare.makeFanfareWithMessageImage(0, base.localAvatar, 1, "You just did a ~fanfare. Here's a rake.", Vec2(0, 0.2), 0.08, base.localAvatar.inventory.buttonLookup(1, 1), Vec3(0, 0, 0), 4)
|
|
||||||
Sequence(go[0], Func(go[1].show), LerpColorScaleInterval(go[1], duration=0.5, startColorScale=Vec4(1, 1, 1, 0), colorScale=Vec4(1, 1, 1, 1)), Wait(2), LerpColorScaleInterval(go[1], duration=0.5, startColorScale=Vec4(1, 1, 1, 1), colorScale=Vec4(1, 1, 1, 0)), Func(go[1].remove)).start()
|
|
||||||
elif wordIs('~endgame'):
|
|
||||||
print('Requesting minigame abort...')
|
|
||||||
messenger.send('minigameAbort')
|
|
||||||
elif wordIs('~wingame'):
|
|
||||||
print('Requesting minigame victory...')
|
|
||||||
messenger.send('minigameVictory')
|
|
||||||
elif wordIs('~walk'):
|
|
||||||
try:
|
|
||||||
fsm = base.cr.playGame.getPlace().fsm
|
|
||||||
fsm.forceTransition('walk')
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
elif wordIs('~movie'):
|
|
||||||
try:
|
|
||||||
fsm = base.cr.playGame.getPlace().fsm
|
|
||||||
fsm.forceTransition('movie')
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
elif wordIs('~sit'):
|
|
||||||
try:
|
|
||||||
base.cr.playGame.getPlace().fsm.request('sit')
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
elif wordIs('~rogues'):
|
|
||||||
suitname = None
|
|
||||||
if len(word) > 7:
|
|
||||||
suitname = word[7:].split(' ')[1]
|
|
||||||
self.rogues = RoguesGallery.RoguesGallery(suitname)
|
|
||||||
self.rogues.enter()
|
|
||||||
if suitname != None:
|
|
||||||
self.rogues.animate()
|
|
||||||
self.acceptOnce('mouse1', self.exit_rogues)
|
|
||||||
elif wordIs('~showPaths'):
|
|
||||||
for obj in list(self.cr.doId2do.values()):
|
|
||||||
if isinstance(obj, DistributedSuitPlanner.DistributedSuitPlanner):
|
|
||||||
obj.showPaths()
|
|
||||||
|
|
||||||
place = base.cr.playGame.getPlace()
|
|
||||||
if hasattr(place, 'showPaths'):
|
|
||||||
place.showPaths()
|
|
||||||
elif wordIs('~hidePaths'):
|
|
||||||
for obj in list(self.cr.doId2do.values()):
|
|
||||||
if isinstance(obj, DistributedSuitPlanner.DistributedSuitPlanner):
|
|
||||||
obj.hidePaths()
|
|
||||||
|
|
||||||
place = base.cr.playGame.getPlace()
|
|
||||||
if hasattr(place, 'hidePaths'):
|
|
||||||
place.hidePaths()
|
|
||||||
elif wordIs('~raceForever'):
|
|
||||||
base.raceForever = True
|
|
||||||
elif wordIs('~listen'):
|
|
||||||
base.localAvatar.garbleChat = 0
|
|
||||||
elif wordIs('~nochat') or wordIs('~chat') or wordIs('~superchat'):
|
|
||||||
base.localAvatar.garbleChat = 1
|
|
||||||
elif wordIs('~exec'):
|
|
||||||
ChatManager.ChatManager.execChat = 1
|
|
||||||
elif wordIs('~photoshoot'):
|
|
||||||
base.cr.playGame.hood.sky.hide()
|
|
||||||
base.cr.playGame.getPlace().loader.geom.hide()
|
|
||||||
base.win.setClearColor(VBase4(1, 1, 1, 1))
|
|
||||||
base.localAvatar.stopLookAroundNow()
|
|
||||||
base.localAvatar.stopBlink()
|
|
||||||
base.localAvatar.setNameVisible(0)
|
|
||||||
elif wordIs('~hideAttack'):
|
|
||||||
TownBattleAttackPanel.hideAttackPanel(1)
|
|
||||||
elif wordIs('~showAttack'):
|
|
||||||
TownBattleAttackPanel.hideAttackPanel(0)
|
|
||||||
elif wordIs('~collisions_on'):
|
|
||||||
base.localAvatar.collisionsOn()
|
|
||||||
elif wordIs('~collisions_off'):
|
|
||||||
base.localAvatar.collisionsOff()
|
|
||||||
elif wordIs('~battle_detect_off'):
|
|
||||||
from toontown.suit import DistributedSuit
|
|
||||||
DistributedSuit.ALLOW_BATTLE_DETECT = 0
|
|
||||||
elif wordIs('~battle_detect_on'):
|
|
||||||
from toontown.suit import DistributedSuit
|
|
||||||
DistributedSuit.ALLOW_BATTLE_DETECT = 1
|
|
||||||
elif wordIs('~battles'):
|
|
||||||
base.localAvatar.setWantBattles(not base.localAvatar.wantBattles)
|
|
||||||
if base.localAvatar.wantBattles:
|
|
||||||
response = 'battles ON'
|
|
||||||
else:
|
|
||||||
response = 'battles OFF'
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
elif wordIs('~skipBattleMovie') or wordIs('~sbm'):
|
|
||||||
ToontownBattleGlobals.SkipMovie = not ToontownBattleGlobals.SkipMovie
|
|
||||||
if ToontownBattleGlobals.SkipMovie:
|
|
||||||
response = 'battle movies will be skipped'
|
|
||||||
else:
|
|
||||||
response = 'battle movies will be played'
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
elif wordIs('~addCameraPosition'):
|
|
||||||
base.localAvatar.addCameraPosition()
|
|
||||||
elif wordIs('~removeCameraPosition'):
|
|
||||||
base.localAvatar.removeCameraPosition()
|
|
||||||
elif wordIs('~printCameraPosition'):
|
|
||||||
base.localAvatar.printCameraPosition(base.localAvatar.cameraIndex)
|
|
||||||
elif wordIs('~printCameraPositions'):
|
|
||||||
base.localAvatar.printCameraPositions()
|
|
||||||
elif wordIs('~worldCam') or wordIs('~wc'):
|
|
||||||
myCam = render.find('**/camera')
|
|
||||||
if not myCam.isEmpty():
|
|
||||||
camParent = myCam.getParent()
|
|
||||||
myCam.wrtReparentTo(render)
|
|
||||||
pos = myCam.getPos()
|
|
||||||
hpr = myCam.getHpr()
|
|
||||||
response = '(%.2f, %.2f, %.2f,) (%.2f, %.2f, %.2f)' % (pos[0],
|
|
||||||
pos[1],
|
|
||||||
pos[2],
|
|
||||||
hpr[0],
|
|
||||||
hpr[1],
|
|
||||||
hpr[2])
|
|
||||||
if not camParent.isEmpty():
|
|
||||||
myCam.wrtReparentTo(camParent)
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
print(response)
|
|
||||||
elif wordIs('~sync'):
|
|
||||||
tm = base.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)
|
|
||||||
base.cr.stopPeriodTimer()
|
|
||||||
base.cr.resetPeriodTimer(seconds)
|
|
||||||
base.cr.startPeriodTimer()
|
|
||||||
if base.cr.periodTimerExpired:
|
|
||||||
response = 'Period timer has expired.'
|
|
||||||
elif base.cr.periodTimerStarted:
|
|
||||||
elapsed = globalClock.getFrameTime() - base.cr.periodTimerStarted
|
|
||||||
secondsRemaining = base.cr.periodTimerSecondsRemaining - elapsed
|
|
||||||
response = 'Period timer expires in %s seconds.' % int(secondsRemaining)
|
|
||||||
else:
|
|
||||||
response = 'Period timer not set.'
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
elif wordIs('~net'):
|
|
||||||
if base.cr.networkPlugPulled():
|
|
||||||
base.cr.restoreNetworkPlug()
|
|
||||||
base.cr.startHeartbeat()
|
|
||||||
response = 'Network restored.'
|
|
||||||
else:
|
|
||||||
base.cr.pullNetworkPlug()
|
|
||||||
base.cr.stopHeartbeat()
|
|
||||||
response = 'Network disconnected.'
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
elif wordIs('~lag'):
|
|
||||||
if not hasattr(base.cr, 'magicLag'):
|
|
||||||
base.cr.startDelay(0.1, 0.35)
|
|
||||||
base.cr.magicLag = None
|
|
||||||
response = 'Simulated Lag On'
|
|
||||||
else:
|
|
||||||
base.cr.stopDelay()
|
|
||||||
del base.cr.magicLag
|
|
||||||
response = 'Simulated Lag Off'
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
elif wordIs('~endlessquietzone'):
|
|
||||||
base.endlessQuietZone = not base.endlessQuietZone
|
|
||||||
response = 'endless quiet zone %s' % choice(base.endlessQuietZone, 'ON', 'OFF')
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
elif wordIs('~cogPageFull'):
|
|
||||||
base.localAvatar.suitPage.updateAllCogs(3)
|
|
||||||
elif wordIs('~mintId'):
|
|
||||||
args = word.split()
|
|
||||||
postName = 'mintIdOverride'
|
|
||||||
if len(args) < 2:
|
|
||||||
if bboard.has(postName):
|
|
||||||
bboard.remove(postName)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
id = int(args[1])
|
|
||||||
foo = ToontownGlobals.MintNumRooms[id]
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
bboard.post(postName, id)
|
|
||||||
|
|
||||||
elif wordIs('~mintRoom'):
|
|
||||||
args = word.split()
|
|
||||||
postName = 'mintRoom'
|
|
||||||
if len(args) < 2:
|
|
||||||
if bboard.has(postName):
|
|
||||||
bboard.remove(postName)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
id = int(args[1])
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
bboard.post(postName, id)
|
|
||||||
|
|
||||||
elif wordIs('~mintWarp'):
|
|
||||||
args = word.split()
|
|
||||||
if len(args) < 2:
|
|
||||||
self.setMagicWordResponse('Usage: ~mintWarp roomId')
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
roomNum = int(args[1])
|
|
||||||
except:
|
|
||||||
self.setMagicWordResponse('roomId not found: %s' % args[1])
|
|
||||||
return
|
|
||||||
|
|
||||||
if not bboard.has('mint'):
|
|
||||||
self.setMagicWordResponse('not in a mint')
|
|
||||||
return
|
|
||||||
mint = bboard.get('mint')
|
|
||||||
if not mint.warpToRoom(roomNum):
|
|
||||||
self.setMagicWordResponse('invalid roomId or roomId not in this mint: %s' % args[1])
|
|
||||||
return
|
|
||||||
elif wordIs('~mintLayouts'):
|
|
||||||
from toontown.coghq import MintLayout
|
|
||||||
MintLayout.printAllCashbotInfo()
|
|
||||||
self.setMagicWordResponse('logged mint layouts')
|
|
||||||
elif wordIs('~edit'):
|
|
||||||
if not __dev__:
|
|
||||||
self.setMagicWordResponse('client not running in dev mode')
|
|
||||||
return
|
|
||||||
from otp.level import EditorGlobals
|
|
||||||
level = bboard.get(EditorGlobals.EditTargetPostName)
|
|
||||||
if level == None:
|
|
||||||
self.setMagicWordResponse('no level available for editing')
|
|
||||||
return
|
|
||||||
from toontown.coghq import DistributedInGameEditor
|
|
||||||
EditorGlobals.assertReadyToEdit()
|
|
||||||
editUsername = EditorGlobals.getEditUsername()
|
|
||||||
editors = base.cr.doFindAll('DistributedInGameEditor')
|
|
||||||
for e in editors:
|
|
||||||
if isinstance(e, DistributedInGameEditor.DistributedInGameEditor):
|
|
||||||
if e.getLevelDoId() == level.doId:
|
|
||||||
if e.editorIsLocalToon() or e.getEditUsername() == editUsername:
|
|
||||||
self.setMagicWordResponse("you ('%s') are already editing this level" % editUsername)
|
|
||||||
return
|
|
||||||
|
|
||||||
cmd = '~inGameEdit %s %s' % (level.doId, editUsername)
|
|
||||||
self.b_setMagicWord(cmd)
|
|
||||||
elif wordIs('~fshow'):
|
|
||||||
from toontown.coghq import DistributedFactory
|
|
||||||
factories = base.cr.doFindAll('DistributedFactory')
|
|
||||||
factory = None
|
|
||||||
for f in factories:
|
|
||||||
if isinstance(f, DistributedFactory.DistributedFactory):
|
|
||||||
factory = f
|
|
||||||
break
|
|
||||||
|
|
||||||
if factory is None:
|
|
||||||
self.setMagicWordResponse('factory not found')
|
|
||||||
return
|
|
||||||
factory.setColorZones(not factory.fColorZones)
|
|
||||||
elif wordIs('~fzone'):
|
|
||||||
args = word.split()
|
|
||||||
if len(args) < 2:
|
|
||||||
self.setMagicWordResponse('Usage: ~fzone <zoneNum>')
|
|
||||||
return
|
|
||||||
zoneId = int(args[1])
|
|
||||||
from toontown.coghq import DistributedFactory
|
|
||||||
factories = base.cr.doFindAll('DistributedFactory')
|
|
||||||
factory = None
|
|
||||||
for f in factories:
|
|
||||||
if isinstance(f, DistributedFactory.DistributedFactory):
|
|
||||||
factory = f
|
|
||||||
break
|
|
||||||
|
|
||||||
if factory is None:
|
|
||||||
self.setMagicWordResponse('factory not found')
|
|
||||||
return
|
|
||||||
factory.warpToZone(zoneId)
|
|
||||||
elif wordIs('~undead'):
|
|
||||||
try:
|
|
||||||
goons = base.cr.doFindAll('Goon')
|
|
||||||
for goon in goons:
|
|
||||||
goon.undead()
|
|
||||||
|
|
||||||
except:
|
|
||||||
self.notify.warning('Error in undead')
|
|
||||||
|
|
||||||
elif wordIs('~resyncGoons'):
|
|
||||||
try:
|
|
||||||
goons = base.cr.doFindAll('Goon')
|
|
||||||
for goon in goons:
|
|
||||||
goon.resync()
|
|
||||||
|
|
||||||
except:
|
|
||||||
self.notify.warning('Error in resyncing')
|
|
||||||
|
|
||||||
elif wordIs('~catalog'):
|
|
||||||
self.doCatalog(word)
|
|
||||||
elif wordIs('~petCam') and base.wantPets:
|
|
||||||
if hasattr(base, 'petCamPrevParent'):
|
|
||||||
base.cam.reparentTo(base.petCamPrevParent)
|
|
||||||
del base.petCamPrevParent
|
|
||||||
else:
|
|
||||||
petId = base.localAvatar.getPetId()
|
|
||||||
pet = self.cr.doId2do.get(petId)
|
|
||||||
if pet:
|
|
||||||
if not hasattr(pet, 'camNode'):
|
|
||||||
pet.camNode = pet.attachNewNode('camNode')
|
|
||||||
pet.camNode.setPos(0, 0, 2.5)
|
|
||||||
base.petCamPrevParent = base.cam.getParent()
|
|
||||||
base.cam.reparentTo(pet.camNode)
|
|
||||||
elif wordIs('~lockPet') and base.wantPets:
|
|
||||||
petId = base.localAvatar.getPetId()
|
|
||||||
pet = self.cr.doId2do.get(petId)
|
|
||||||
if pet:
|
|
||||||
if not pet.isLockedDown():
|
|
||||||
pet.lockPet()
|
|
||||||
elif wordIs('~unlockPet') and base.wantPets:
|
|
||||||
petId = base.localAvatar.getPetId()
|
|
||||||
pet = self.cr.doId2do.get(petId)
|
|
||||||
if pet:
|
|
||||||
if pet.isLockedDown():
|
|
||||||
pet.unlockPet()
|
|
||||||
elif wordIs('~resetPetTutorial') and base.wantPets:
|
|
||||||
base.localAvatar.setPetTutorialDone(False)
|
|
||||||
response = 'Pet Tutorial flag reset'
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
elif wordIs('~bossBattle'):
|
|
||||||
self.doBossBattle(word)
|
|
||||||
elif wordIs('~RaceChat'):
|
|
||||||
base.localAvatar.chatMgr.chatInputSpeedChat.addKartRacingMenu()
|
|
||||||
elif wordIs('~BuyKart'):
|
|
||||||
if base.wantKarts:
|
|
||||||
|
|
||||||
def doShtikerLater(task):
|
|
||||||
base.localAvatar.addKartPage()
|
|
||||||
return 0
|
|
||||||
|
|
||||||
if base.localAvatar.hasKart():
|
|
||||||
response = 'Returning Kart %s' % base.localAvatar.getKartBodyType()
|
|
||||||
base.localAvatar.requestKartDNAFieldUpdate(KartDNA.bodyType, InvalidEntry)
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
else:
|
|
||||||
base.localAvatar.requestKartDNAFieldUpdate(KartDNA.rimsType, getDefaultRim())
|
|
||||||
taskMgr.doMethodLater(1.0, doShtikerLater, 'doShtikerLater')
|
|
||||||
response = 'Kart %s has been purchased with body and accessory color %s.' % (word[9], getDefaultColor())
|
|
||||||
base.localAvatar.requestKartDNAFieldUpdate(KartDNA.bodyType, int(word[9]))
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
else:
|
|
||||||
self.setMagicWordResponse('Enable wantKarts in Config.prc')
|
|
||||||
elif wordIs('~leaveRace'):
|
|
||||||
messenger.send('leaveRace')
|
|
||||||
elif wordIs('~kartParticles'):
|
|
||||||
b = ConfigVariableBool('want-kart-particles', 0)
|
|
||||||
b.setValue(not b)
|
|
||||||
elif wordIs('~gardenGame'):
|
|
||||||
messenger.send('gardenGame')
|
|
||||||
response = 'You must be on your estate'
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
elif wordIs('~verboseState'):
|
|
||||||
base.localAvatar.verboseState()
|
|
||||||
elif wordIs('~golf'):
|
|
||||||
self.doGolf(word)
|
|
||||||
elif wordIs('~whiteList'):
|
|
||||||
base.localAvatar.chatMgr.chatInputSpeedChat.addWhiteList()
|
|
||||||
elif wordIs('~updateWhiteList'):
|
|
||||||
self.notify.info('Updating WhiteList')
|
|
||||||
base.whiteList.redownloadWhitelist()
|
|
||||||
elif wordIs('~noWhiteList'):
|
|
||||||
base.localAvatar.chatMgr.chatInputSpeedChat.removeWhiteList()
|
|
||||||
elif wordIs('~setPaid'):
|
|
||||||
args = word.split()
|
|
||||||
if len(args) > 1:
|
|
||||||
paid = int(args[1])
|
|
||||||
statusString = base.config.GetString('force-paid-status', 'none')
|
|
||||||
if paid:
|
|
||||||
paid = 1
|
|
||||||
if statusString != 'none':
|
|
||||||
if statusString == 'VELVET':
|
|
||||||
ConfigVariableString('force-paid-status').setValue('FULL')
|
|
||||||
elif statusString == 'unpaid':
|
|
||||||
ConfigVariableString('force-paid-status').setValue('paid')
|
|
||||||
base.cr.setIsPaid(1)
|
|
||||||
else:
|
|
||||||
paid = 0
|
|
||||||
if statusString != 'none':
|
|
||||||
if statusString == 'FULL':
|
|
||||||
ConfigVariableString('force-paid-status').setValue('VELVET')
|
|
||||||
elif statusString == 'paid':
|
|
||||||
ConfigVariableString('force-paid-status').setValue('unpaid')
|
|
||||||
base.cr.setIsPaid(0)
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
elif wordIs('~party'):
|
|
||||||
self.doParty(word, avId, zoneId)
|
|
||||||
elif wordIs('~news'):
|
|
||||||
self.doNews(word, avId, zoneId)
|
|
||||||
elif wordIs('~bgui'):
|
|
||||||
if not hasattr(self, 'groupPanel'):
|
|
||||||
from toontown.toon import GroupPanel
|
|
||||||
self.groupPanel = GroupPanel.GroupPanel(base.localAvatar.boardingParty)
|
|
||||||
self.groupPanel.frame.show()
|
|
||||||
else:
|
|
||||||
self.groupPanel.frame.hide()
|
|
||||||
self.groupPanel.cleanup()
|
|
||||||
del self.groupPanel
|
|
||||||
elif wordIs('~generateOrder'):
|
|
||||||
args = word.split()
|
|
||||||
if len(args) > 1:
|
|
||||||
newOrder = int(args[1])
|
|
||||||
if newOrder >= 0 and newOrder <= 2:
|
|
||||||
datagram = PyDatagram.PyDatagram()
|
|
||||||
datagram.addUint16(MsgName2Id['CLIENT_CHANGE_GENERATE_ORDER'])
|
|
||||||
datagram.addUint32(newOrder)
|
|
||||||
base.cr.send(datagram)
|
|
||||||
response = 'changing generate order to %s' % newOrder
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
else:
|
|
||||||
response = 'args: 0 default, 1 reversed, 2 shuffled'
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
elif wordIs('~ruler'):
|
|
||||||
response = 'Each unit is equal to one foot'
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
if self.ruler:
|
|
||||||
self.ruler.detachNode()
|
|
||||||
del self.ruler
|
|
||||||
self.ruler = loader.loadModel('phase_3/models/props/xyzAxis')
|
|
||||||
self.ruler.reparentTo(render)
|
|
||||||
self.ruler.setPos(base.localAvatar.getPos())
|
|
||||||
self.ruler.place()
|
|
||||||
elif wordIs('~toonIdTags'):
|
|
||||||
otherToons = base.cr.doFindAllOfType('DistributedToon')
|
|
||||||
if otherToons:
|
|
||||||
for toon in otherToons[0]:
|
|
||||||
toon.setNametagStyle(0)
|
|
||||||
|
|
||||||
messenger.send('nameTagShowAvId', [])
|
|
||||||
base.idTags = 1
|
|
||||||
elif wordIs('~code'):
|
|
||||||
args = word.split()
|
|
||||||
if len(args) > 1:
|
|
||||||
code = word[len(args[0]) + 1:]
|
|
||||||
base.codeRedemptionMgr.redeemCode(code, self._handleCodeRedemptionResponse)
|
|
||||||
response = 'sending code %s to server...' % code
|
|
||||||
else:
|
|
||||||
response = '~code <code>'
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
return
|
|
||||||
|
|
||||||
def _handleCodeRedemptionResponse(self, result, awardMgrResult):
|
|
||||||
if not result:
|
|
||||||
msg = 'code redeemed'
|
|
||||||
else:
|
|
||||||
if result != TTCodeRedemptionConsts.RedeemErrors.AwardCouldntBeGiven:
|
|
||||||
errMsg = TTCodeRedemptionConsts.RedeemErrorStrings[result]
|
|
||||||
else:
|
|
||||||
errMsg = AwardManagerConsts.GiveAwardErrorStrings[awardMgrResult]
|
|
||||||
msg = 'code NOT redeemed (%s)' % (errMsg,)
|
|
||||||
base.localAvatar.setChatAbsolute(msg, CFSpeech | CFTimeout)
|
|
||||||
|
|
||||||
def doParty(self, word, av, zoneId):
|
|
||||||
args = word.split()
|
|
||||||
response = None
|
|
||||||
action = None
|
|
||||||
if len(args) == 1:
|
|
||||||
return
|
|
||||||
action = args[1]
|
|
||||||
if action == 'plan':
|
|
||||||
base.localAvatar.aboutToPlanParty = True
|
|
||||||
base.localAvatar.creatingNewPartyWithMagicWord = False
|
|
||||||
elif action == 'new':
|
|
||||||
base.localAvatar.aboutToPlanParty = False
|
|
||||||
base.localAvatar.creatingNewPartyWithMagicWord = True
|
|
||||||
elif action == 'start':
|
|
||||||
base.localAvatar.creatingNewPartyWithMagicWord = False
|
|
||||||
base.localAvatar.aboutToPlanParty = False
|
|
||||||
hoodId = ToontownGlobals.PartyHood
|
|
||||||
ToontownDistrictStats.refresh('shardInfoUpdated')
|
|
||||||
curShardTuples = base.cr.listActiveShards()
|
|
||||||
lowestPop = 100000000000000000
|
|
||||||
shardId = None
|
|
||||||
for shardInfo in curShardTuples:
|
|
||||||
pop = shardInfo[2]
|
|
||||||
if pop < lowestPop:
|
|
||||||
lowestPop = pop
|
|
||||||
shardId = shardInfo[0]
|
|
||||||
|
|
||||||
if shardId == base.localAvatar.defaultShard:
|
|
||||||
shardId = None
|
|
||||||
base.cr.playGame.getPlace().requestLeave({'loader': 'safeZoneLoader',
|
|
||||||
'where': 'party',
|
|
||||||
'how': 'teleportIn',
|
|
||||||
'hoodId': hoodId,
|
|
||||||
'zoneId': -1,
|
|
||||||
'shardId': shardId,
|
|
||||||
'avId': -1})
|
|
||||||
elif action == 'unreleasedClient':
|
|
||||||
newVal = base.cr.partyManager.toggleAllowUnreleasedClient()
|
|
||||||
response = 'Allow Unreleased Client = %s' % newVal
|
|
||||||
elif action == 'showdoid':
|
|
||||||
newVal = base.cr.partyManager.toggleShowDoid()
|
|
||||||
response = 'show doid = %s' % newVal
|
|
||||||
elif action == 'debugGrid':
|
|
||||||
newVal = not ConfigVariableBool('show-debug-party-grid')
|
|
||||||
ConfigVariableBool('show-debug-party-grid').setValue(newVal)
|
|
||||||
response = 'Grid: %s; re-enter party to see changes.' % newVal
|
|
||||||
if response is not None:
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
return
|
|
||||||
|
|
||||||
def doCatalog(self, word):
|
|
||||||
args = word.split()
|
|
||||||
if len(args) == 1:
|
|
||||||
return
|
|
||||||
elif args[1] == 'reload':
|
|
||||||
phone = base.cr.doFind('phone')
|
|
||||||
if phone and phone.phoneGui:
|
|
||||||
phone.phoneGui.reload()
|
|
||||||
response = 'Reloaded catalog screen'
|
|
||||||
else:
|
|
||||||
response = 'Phone is not active.'
|
|
||||||
elif args[1] == 'dump':
|
|
||||||
if len(args) <= 2:
|
|
||||||
response = 'Specify output filename.'
|
|
||||||
else:
|
|
||||||
from toontown.catalog import CatalogGenerator
|
|
||||||
cg = CatalogGenerator.CatalogGenerator()
|
|
||||||
cg.outputSchedule(args[2])
|
|
||||||
response = 'Catalog schedule written to file %s.' % args[2]
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
|
|
||||||
def toggleRun(self):
|
|
||||||
if self.dbg_running_fast:
|
|
||||||
self.dbg_running_fast = 0
|
|
||||||
OTPGlobals.ToonForwardSpeed = self.save_fwdspeed
|
|
||||||
OTPGlobals.ToonReverseSpeed = self.save_revspeed
|
|
||||||
OTPGlobals.ToonRotateSpeed = self.save_rotspeed
|
|
||||||
base.localAvatar.setWalkSpeedNormal()
|
|
||||||
else:
|
|
||||||
self.dbg_running_fast = 1
|
|
||||||
self.save_fwdspeed = OTPGlobals.ToonForwardSpeed
|
|
||||||
self.save_revspeed = OTPGlobals.ToonReverseSpeed
|
|
||||||
self.save_rotspeed = OTPGlobals.ToonRotateSpeed
|
|
||||||
OTPGlobals.ToonForwardSpeed = 60
|
|
||||||
OTPGlobals.ToonReverseSpeed = 30
|
|
||||||
OTPGlobals.ToonRotateSpeed = 100
|
|
||||||
base.localAvatar.setWalkSpeedNormal()
|
|
||||||
|
|
||||||
def requestTeleport(self, loaderId, whereId, hoodId, zoneId, avId):
|
|
||||||
place = base.cr.playGame.getPlace()
|
|
||||||
if loaderId == '':
|
|
||||||
loaderId = ZoneUtil.getBranchLoaderName(zoneId)
|
|
||||||
if whereId == '':
|
|
||||||
whereId = ZoneUtil.getToonWhereName(zoneId)
|
|
||||||
if hoodId == 0:
|
|
||||||
hoodId = place.loader.hood.id
|
|
||||||
if avId == 0:
|
|
||||||
avId = -1
|
|
||||||
place.fsm.forceTransition('teleportOut', [{'loader': loaderId,
|
|
||||||
'where': whereId,
|
|
||||||
'how': 'teleportIn',
|
|
||||||
'hoodId': hoodId,
|
|
||||||
'zoneId': zoneId,
|
|
||||||
'shardId': None,
|
|
||||||
'avId': avId}])
|
|
||||||
return
|
|
||||||
|
|
||||||
def exit_rogues(self):
|
|
||||||
self.rogues.exit()
|
|
||||||
del self.rogues
|
|
||||||
self.rogues = None
|
|
||||||
return
|
|
||||||
|
|
||||||
def identifyDistributedObjects(self, name):
|
|
||||||
result = []
|
|
||||||
lowerName = string.lower(name)
|
|
||||||
for obj in list(base.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 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 |= ToontownGlobals.WallBitmask
|
|
||||||
elif w == 'floor':
|
|
||||||
bitmask |= ToontownGlobals.FloorBitmask
|
|
||||||
elif w == 'cam':
|
|
||||||
bitmask |= ToontownGlobals.CameraBitmask
|
|
||||||
elif w == 'catch':
|
|
||||||
bitmask |= ToontownGlobals.CatchBitmask
|
|
||||||
elif w == 'ghost':
|
|
||||||
bitmask |= ToontownGlobals.GhostBitmask
|
|
||||||
elif w == 'furniture':
|
|
||||||
bitmask |= ToontownGlobals.FurnitureSideBitmask | ToontownGlobals.FurnitureTopBitmask | ToontownGlobals.FurnitureDragBitmask
|
|
||||||
elif w == 'furnitureside':
|
|
||||||
bitmask |= ToontownGlobals.FurnitureSideBitmask
|
|
||||||
elif w == 'furnituretop':
|
|
||||||
bitmask |= ToontownGlobals.FurnitureTopBitmask
|
|
||||||
elif w == 'furnituredrag':
|
|
||||||
bitmask |= ToontownGlobals.FurnitureDragBitmask
|
|
||||||
elif w == 'pie':
|
|
||||||
bitmask |= ToontownGlobals.PieBitmask
|
|
||||||
else:
|
|
||||||
invalid += ' ' + w
|
|
||||||
|
|
||||||
if invalid:
|
|
||||||
self.setMagicWordResponse('Unknown CS keyword(s): %s' % invalid)
|
|
||||||
return bitmask
|
|
||||||
|
|
||||||
def getFontByName(self, fontname):
|
|
||||||
if fontname == 'toon':
|
|
||||||
return ToontownGlobals.getToonFont()
|
|
||||||
elif fontname == 'building':
|
|
||||||
return ToontownGlobals.getBuildingNametagFont()
|
|
||||||
elif fontname == 'minnie':
|
|
||||||
return ToontownGlobals.getMinnieFont()
|
|
||||||
elif fontname == 'suit':
|
|
||||||
return ToontownGlobals.getSuitFont()
|
|
||||||
else:
|
|
||||||
return MagicWordManager.MagicWordManager.getFontByName(self, fontname)
|
|
||||||
|
|
||||||
def doBossBattle(self, word):
|
|
||||||
args = word.split()
|
|
||||||
bossCog = None
|
|
||||||
for distObj in list(self.cr.doId2do.values()):
|
|
||||||
if isinstance(distObj, DistributedBossCog.DistributedBossCog):
|
|
||||||
bossCog = distObj
|
|
||||||
break
|
|
||||||
|
|
||||||
response = None
|
|
||||||
if len(args) == 1:
|
|
||||||
pass
|
|
||||||
elif args[1] == 'safe':
|
|
||||||
if len(args) <= 2:
|
|
||||||
flag = not bossCog.localToonIsSafe
|
|
||||||
else:
|
|
||||||
flag = int(args[2])
|
|
||||||
bossCog.localToonIsSafe = flag
|
|
||||||
if flag:
|
|
||||||
response = 'LocalToon is now safe from boss attacks'
|
|
||||||
else:
|
|
||||||
response = 'LocalToon is now vulnerable to boss attacks'
|
|
||||||
elif args[1] == 'stun':
|
|
||||||
bossCog.stunAllGoons()
|
|
||||||
elif args[1] == 'destroy':
|
|
||||||
bossCog.destroyAllGoons()
|
|
||||||
elif args[1] == 'avatarEnter':
|
|
||||||
bossCog.d_avatarEnter()
|
|
||||||
response = 'called d_avatarEnter'
|
|
||||||
if response:
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
return
|
|
||||||
|
|
||||||
def doGolf(self, word):
|
|
||||||
args = word.split()
|
|
||||||
response = None
|
|
||||||
if len(args) == 1:
|
|
||||||
pass
|
|
||||||
elif args[1] == 'debugBarrier':
|
|
||||||
golfHole = base.cr.doFind('DistributedGolfHole')
|
|
||||||
if golfHole:
|
|
||||||
if hasattr(golfHole, 'golfBarrier') and not golfHole.golfBarrier.isEmpty():
|
|
||||||
if golfHole.golfBarrier.isHidden():
|
|
||||||
golfHole.golfBarrier.show()
|
|
||||||
response = 'showing golf barrier'
|
|
||||||
else:
|
|
||||||
golfHole.golfBarrier.hide()
|
|
||||||
response = 'hiding golf barrier'
|
|
||||||
else:
|
|
||||||
response = 'no golf hole'
|
|
||||||
elif args[1] == 'contact':
|
|
||||||
messenger.send('ode toggle contacts')
|
|
||||||
elif args[1] == 'power':
|
|
||||||
if len(args) > 2:
|
|
||||||
base.golfPower = args[2]
|
|
||||||
response = 'setting power to %s' % args[2]
|
|
||||||
else:
|
|
||||||
base.golfPower = None
|
|
||||||
response = 'unsetting power'
|
|
||||||
elif args[1] == 'heading':
|
|
||||||
if len(args) > 2:
|
|
||||||
golfHole = base.cr.doFind('DistributedGolfHole')
|
|
||||||
if golfHole:
|
|
||||||
golfHole.doMagicWordHeading(args[2])
|
|
||||||
response = 'setting heading to %s' % args[2]
|
|
||||||
else:
|
|
||||||
response = 'need heading parameter'
|
|
||||||
elif args[1] == 'list':
|
|
||||||
response = ''
|
|
||||||
for holeId in GolfGlobals.HoleInfo:
|
|
||||||
if holeId < 18:
|
|
||||||
response += '%d: %s\n' % (holeId, GolfGlobals.getHoleName(holeId))
|
|
||||||
|
|
||||||
elif args[1] == 'list2':
|
|
||||||
response = ''
|
|
||||||
for holeId in GolfGlobals.HoleInfo:
|
|
||||||
if holeId >= 18:
|
|
||||||
response += '%d: %s\n' % (holeId, GolfGlobals.getHoleName(holeId))
|
|
||||||
|
|
||||||
if response:
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
return
|
|
||||||
|
|
||||||
def doNews(self, word, av, zoneId):
|
|
||||||
args = word.split()
|
|
||||||
response = None
|
|
||||||
action = None
|
|
||||||
if len(args) == 1:
|
|
||||||
return
|
|
||||||
action = args[1]
|
|
||||||
if action == 'frame':
|
|
||||||
NametagGlobals.setMasterArrowsOn(0)
|
|
||||||
from toontown.shtiker import InGameNewsFrame
|
|
||||||
base.newsFrame = InGameNewsFrame.InGameNewsFrame()
|
|
||||||
base.newsFrame.activate()
|
|
||||||
response = 'putting in game news direct frame up'
|
|
||||||
elif action == 'snapshot':
|
|
||||||
response = localAvatar.newsPage.doSnapshot()
|
|
||||||
if response is not None:
|
|
||||||
self.setMagicWordResponse(response)
|
|
||||||
return
|
|
|
@ -1,5 +0,0 @@
|
||||||
from direct.directnotify import DirectNotifyGlobal
|
|
||||||
from direct.distributed.DistributedObjectAI import DistributedObjectAI
|
|
||||||
|
|
||||||
class ToontownMagicWordManagerAI(DistributedObjectAI):
|
|
||||||
notify = DirectNotifyGlobal.directNotify.newCategory('ToontownMagicWordManagerAI')
|
|
|
@ -674,7 +674,7 @@ class ToontownClientRepository(OTPClientRepository.OTPClientRepository):
|
||||||
else:
|
else:
|
||||||
self.notify.info('dumpAllSubShardObjects: defaultShard is %s' % localAvatar.defaultShard)
|
self.notify.info('dumpAllSubShardObjects: defaultShard is %s' % localAvatar.defaultShard)
|
||||||
|
|
||||||
ignoredClasses = ('MagicWordManager', 'TimeManager', 'DistributedDistrict', 'FriendManager', 'NewsManager', 'ToontownMagicWordManager', 'WelcomeValleyManager', 'DistributedTrophyMgr', 'CatalogManager', 'DistributedBankMgr', 'EstateManager', 'RaceManager', 'SafeZoneManager', 'DeleteManager', 'TutorialManager', 'ToontownDistrict', 'DistributedDeliveryManager', 'DistributedPartyManager', 'AvatarFriendsManager', 'InGameNewsMgr', 'WhitelistMgr', 'TTCodeRedemptionMgr')
|
ignoredClasses = ('TimeManager', 'DistributedDistrict', 'FriendManager', 'NewsManager', 'ToontownMagicWordManager', 'WelcomeValleyManager', 'DistributedTrophyMgr', 'CatalogManager', 'DistributedBankMgr', 'EstateManager', 'RaceManager', 'SafeZoneManager', 'DeleteManager', 'TutorialManager', 'ToontownDistrict', 'DistributedDeliveryManager', 'DistributedPartyManager', 'AvatarFriendsManager', 'InGameNewsMgr', 'WhitelistMgr', 'TTCodeRedemptionMgr')
|
||||||
messenger.send('clientCleanup')
|
messenger.send('clientCleanup')
|
||||||
for avId, pad in list(self.__queryAvatarMap.items()):
|
for avId, pad in list(self.__queryAvatarMap.items()):
|
||||||
pad.delayDelete.destroy()
|
pad.delayDelete.destroy()
|
||||||
|
|
Loading…
Reference in a new issue