Beispiel #1
0
 def detectLeaks(self):
     if not __dev__:
         return
     events = messenger.getAllAccepting(self)
     tasks = []
     if hasattr(self, '_taskList'):
         tasks = [ task.name for task in self._taskList.values() ]
     if len(events) or len(tasks):
         estr = choice(len(events), 'listening to events: %s' % events, '')
         andStr = choice(len(events) and len(tasks), ' and ', '')
         tstr = choice(len(tasks), '%srunning tasks: %s' % (andStr, tasks), '')
         notify = directNotify.newCategory('LeakDetect')
         func = choice(getRepository()._crashOnProactiveLeakDetect, self.notify.error, self.notify.warning)
         func('destroyed %s instance is still %s%s' % (self.__class__.__name__, estr, tstr))
Beispiel #2
0
    def __init__(self, width, height, depth):
        self.forms = {f.name: f for f in load_forms()}
        Block.FORMS = self.forms
        self.width = width
        self.height = height
        self.depth = depth

        self.size = core.Point3(self.width, self.height, self.depth)
        self.midpoint = core.Point3(self.width // 2, self.height // 2, self.depth // 2)

        self.blocks = {coords: None for coords in self.grid()}

        self.notify = directNotify.newCategory('world')
        messenger.accept('console-command', self, self.command)
def checkForGarbageLeaks():
    gc.collect()
    numGarbage = len(gc.garbage)
    if (numGarbage > 0 and config.GetBool('auto-garbage-logging', 0)):
        if (numGarbage != _CFGLGlobals.LastNumGarbage):
            print
            gr = GarbageReport('found garbage', threaded=False, collect=False)
            print
            _CFGLGlobals.LastNumGarbage = numGarbage
            _CFGLGlobals.LastNumCycles = gr.getNumCycles()
            messenger.send(GarbageCycleCountAnnounceEvent, [gr.getDesc2numDict()])
            gr.destroy()
        notify = directNotify.newCategory("GarbageDetect")
        if config.GetBool('allow-garbage-cycles', 1):
            func = notify.warning
        else:
            func = notify.error
        func('%s garbage cycles found, see info above' % _CFGLGlobals.LastNumCycles)
    return numGarbage
Beispiel #4
0
    def detectLeaks(self):
        if not __dev__:
            return

        # call this after the DirectObject instance has been destroyed
        # if it's leaking, will notify user

        # make sure we're not still listening for messenger events
        events = messenger.getAllAccepting(self)
        # make sure we're not leaking tasks
        # TODO: include tasks that were added directly to the taskMgr
        tasks = []
        if hasattr(self, '_taskList'):
            tasks = [task.name for task in self._taskList.values()]
        if len(events) or len(tasks):
            estr = choice(len(events), 'listening to events: %s' % events, '')
            andStr = choice(len(events) and len(tasks), ' and ', '')
            tstr = choice(len(tasks), '%srunning tasks: %s' % (andStr, tasks), '')
            notify = directNotify.newCategory('LeakDetect')
            func = choice(getRepository()._crashOnProactiveLeakDetect,
                          self.notify.error, self.notify.warning)
            func('destroyed %s instance is still %s%s' % (self.__class__.__name__, estr, tstr))
#!/usr/bin/env python

from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from direct.distributed.AstronInternalRepository import AstronInternalRepository
from direct.directnotify.DirectNotifyGlobal import directNotify
from panda3d.core import loadPrcFileData
from time import sleep

# Globally known object and channel IDs
from simple_example_globals_server import LoginManagerId, UDChannel, SSChannel

# No camera or window is needed, but notifications are.
loadPrcFileData("", "\n".join(["window-type none",
                               "notify-level-udserver debug"]))
notify = directNotify.newCategory("udserver")

# This class manages the UberDOGs, which in this case is just one, the login
# manager.
class SimpleServer(ShowBase):
    def __init__(self, server_framerate = 60):
        ShowBase.__init__(self)
        # First, set up the idle task that forces a sleep
        # that reduces the servers speed to a given framerate.
        self.server_frametime = 1./server_framerate
        self.taskMgr.add(self.idle, 'idle task', sort = 47)
        # Start UberDOG
        self.startUberDOG()

    # Idle task, so that the server doesn't eat 100% CPU
    def idle(self, task):
Beispiel #6
0
from direct.extensions_native import VBase4_extensions
from direct.extensions_native import NodePath_extensions


from panda3d.core import loadPrcFile


if __debug__:
    loadPrcFile("config/general.prc")
    loadPrcFile("config/release/dev.prc")


from direct.directnotify.DirectNotifyGlobal import directNotify


notify = directNotify.newCategory("ClientStart")
notify.setInfo(True)


from otp.settings.Settings import Settings


preferencesFilename = ConfigVariableString("preferences-filename", "preferences.json").getValue()
notify.info("Reading %s..." % preferencesFilename)
__builtin__.settings = Settings(preferencesFilename)
if "fullscreen" not in settings:
    settings["fullscreen"] = False
if "music" not in settings:
    settings["music"] = True
if "sfx" not in settings:
    settings["sfx"] = True
Beispiel #7
0
from toontown.toonbase.ToontownGlobals import *
from direct.directnotify.DirectNotifyGlobal import directNotify

zoneUtilNotify = directNotify.newCategory('ZoneUtil')
tutorialDict = None


def isGoofySpeedwayZone(zoneId):
    return zoneId == 8000


def isCogHQZone(zoneId):
    return zoneId >= 10000 and zoneId < 15000


def isMintInteriorZone(zoneId):
    return zoneId in (CashbotMintIntA, CashbotMintIntB, CashbotMintIntC)


def isDynamicZone(zoneId):
    return zoneId >= DynamicZonesBegin and zoneId < DynamicZonesEnd


def getStreetName(branchId):
    global tutorialDict
    if tutorialDict:
        return StreetNames[20000][-1]
    else:
        return StreetNames[branchId][-1]

class DropGag(Gag, LocationGag):
    notify = directNotify.newCategory('DropGag')

    def __init__(self, name, model, anim, damage, hitSfx, missSfx, scale,
                 playRate):
        Gag.__init__(self,
                     name,
                     model,
                     damage,
                     GagType.DROP,
                     hitSfx,
                     anim=anim,
                     playRate=playRate,
                     scale=scale,
                     autoRelease=True)
        LocationGag.__init__(self, 10, 50)
        self.missSfx = None
        self.fallSoundPath = 'phase_5/audio/sfx/incoming_whistleALT.ogg'
        self.fallSoundInterval = None
        self.fallSfx = None
        self.chooseLocFrame = 34
        self.completeFrame = 77
        self.collHandlerF = CollisionHandlerFloor()
        self.fallDuration = 0.75
        self.isDropping = False
        self.timeout = 3.0
        if game.process == 'client':
            self.missSfx = base.audio3d.loadSfx(missSfx)
            self.fallSfx = base.audio3d.loadSfx(self.fallSoundPath)
        self.crashSite = None
        self.crashSiteGag = None
        self.crashSiteShadow = None
        self.crashSiteIval = None
        self.crashStartPos = None
        self.crashEndPos = None
        self.crashBegun = False
        self.shadowIdleTaskName = 'Handle-IdleShadow'
        self.shadowIdleTime = 0.0
        return

    def tickShadowIdleTask(self, task):
        task.delayTime = 0.1
        self.shadowIdleTime += 0.1
        if self.shadowIdleTime >= 0.25:
            self.startCrashEffect()
        return task.again

    def __shadowMoved(self):
        self.shadowIdleTime = 0.0
        base.taskMgr.remove(self.shadowIdleTaskName)
        base.taskMgr.add(self.tickShadowIdleTask, self.shadowIdleTaskName)
        if self.crashSite:
            self.cleanupCrashIval()
            self.crashSite.hide()

    def startCrashEffect(self):
        if not self.getLocationSeeker() or self.crashBegun:
            return
        self.cleanupCrashIval()
        self.crashBegun = True
        if self.crashSite is None:
            self.crashSite = loader.loadModel('phase_6/models/props/piano.bam')
            self.crashSite.setScale(0.5)
            self.crashSite.setTransparency(TransparencyAttrib.MAlpha)
            self.crashSite.setColorScale(1.0, 1.0, 1.0, 0.25)
            self.crashSite.reparentTo(render)
            self.crashSiteGag = self.crashSite.find('**/crashed_piano')
            self.crashSiteGag.setTransparency(TransparencyAttrib.MAlpha)
            self.crashSiteShadow = self.crashSite.find('**/shadow_crack')
            for node in self.crashSite.findAllMatches('**/*coll*'):
                node.removeNode()

        self.crashSite.show()
        dropShadow = self.getLocationSeeker().getDropShadow()
        if not dropShadow:
            return
        location = self.getLocationSeeker().getDropShadow().getPos(render)
        self.crashSite.setPos(location.getX(), location.getY(),
                              location.getZ())
        self.crashEndPos = self.crashSiteShadow.getPos()
        self.crashStartPos = Point3(self.crashEndPos.getX(),
                                    self.crashEndPos.getY(),
                                    self.crashEndPos.getZ() + 8.5)
        self.crashSiteIval = Sequence(
            Func(self.crashSiteShadow.hide),
            Func(self.crashSiteGag.headsUp, base.localAvatar),
            Parallel(
                Sequence(
                    LerpPosHprInterval(self.crashSiteGag,
                                       duration=0.75,
                                       pos=self.crashEndPos,
                                       startPos=self.crashStartPos,
                                       startHpr=Point3(0.0, 15.0, 21.3),
                                       hpr=Point3(0.0, 0.0, 0.0)),
                    Func(self.crashSiteShadow.show))),
            LerpColorScaleInterval(self.crashSiteShadow,
                                   duration=0.75,
                                   colorScale=Vec4(1.0, 1.0, 1.0, 0.0),
                                   startColorScale=Vec4(1.0, 1.0, 1.0, 1.0)),
            Func(self.crashSiteShadow.hide),
            Func(self.crashSiteShadow.setColorScale, 1.0, 1.0, 1.0, 1.0))
        self.crashSiteIval.loop()
        return

    def resetCrashEffect(self):
        base.taskMgr.remove(self.shadowIdleTaskName)
        base.ignore(self.getLocationSeeker().getShadowMovedName())
        self.cleanupCrashIval()
        if self.crashSite:
            self.crashSite.removeNode()
            self.crashSite = None
            self.crashSiteGag = None
            self.crashSiteShadow = None
            self.crashStartPos = None
            self.crashEndPos = None
        return

    def cleanupCrashIval(self):
        self.crashBegun = False
        if self.crashSiteIval:
            self.crashSiteIval.pause()
            self.crashSiteIval = None
        return

    def completeDrop(self):
        LocationGag.complete(self)
        self.isDropping = False
        if game.process != 'client':
            return
        self.reset()

    def start(self):
        super(DropGag, self).start()
        LocationGag.start(self, self.avatar)
        if self.isLocal() and self.getName() == CIGlobals.GrandPiano:
            base.taskMgr.add(self.tickShadowIdleTask, self.shadowIdleTaskName)
            base.accept(self.getLocationSeeker().getShadowMovedName(),
                        self.__shadowMoved)

    def unEquip(self):
        LocationGag.cleanupLocationSeeker(self)
        super(DropGag, self).unEquip()
        if self.state != GagState.LOADED:
            self.completeDrop()

    def onActivate(self, ignore, suit):
        pass

    def buildCollisions(self):
        pass

    def onCollision(self, entry):
        if not self.gag:
            return
        intoNP = entry.getIntoNodePath()
        avNP = intoNP.getParent()
        hitCog = False
        self.fallSoundInterval.pause()
        self.fallSoundInterval = None
        shrinkTrack = Sequence()
        if self.avatar.doId == base.localAvatar.doId:
            for key in base.cr.doId2do.keys():
                obj = base.cr.doId2do[key]
                if obj.__class__.__name__ in CIGlobals.SuitClasses:
                    if obj.getKey() == avNP.getKey():
                        obj.sendUpdate('hitByGag', [self.getID()])
                        self.avatar.b_trapActivate(self.getID(),
                                                   self.avatar.doId, 0,
                                                   obj.doId)
                        hitCog = True

        gagObj = self.gag
        if hitCog:
            SoundInterval(self.hitSfx, node=self.gag).start()
            shrinkTrack.append(Wait(0.5))
        else:
            SoundInterval(self.missSfx, node=self.gag).start()
        shrinkTrack.append(Wait(0.25))
        shrinkTrack.append(
            LerpScaleInterval(self.gag,
                              0.3,
                              Point3(0.01, 0.01, 0.01),
                              startScale=self.gag.getScale()))
        shrinkTrack.append(Func(gagObj.removeNode))
        shrinkTrack.append(Func(self.cleanupGag))
        shrinkTrack.start()
        return

    def onSuitHit(self, suit):
        pass

    @abc.abstractmethod
    def startDrop(self):
        pass

    def cleanupGag(self):
        if not self.isDropping:
            super(DropGag, self).cleanupGag()

    def release(self):
        if self.isLocal():
            self.startTimeout()
            self.resetCrashEffect()
        LocationGag.release(self)
        self.build()
        self.isDropping = True
        actorTrack = LocationGag.getActorTrack(self)
        self.fallSoundInterval = LocationGag.getSoundTrack(self)
        if actorTrack:
            actorTrack.append(Func(self.startDrop))
            actorTrack.start()
            self.fallSoundInterval.append(
                Parallel(SoundInterval(self.fallSfx, node=self.avatar)))
            self.fallSoundInterval.start()
        if self.isLocal():
            base.localAvatar.sendUpdate('usedGag', [self.id])

    def setEndPos(self, x, y, z):
        LocationGag.setDropLoc(self, x, y, z)
Beispiel #9
0
class AvatarFriendsManager(DistributedObjectGlobal):
    """
    The Avatar Friends Manager is a global object.
    This object handles client requests on avatar-level (as opposed to player-level) friends.

    See Also:
        "otp/src/friends/AvatarFriendsManagerUD.py"
        "otp/src/friends/PlayerFriendsManager.py"
        "pirates/src/friends/PiratesFriendsList.py"
        "otp/src/configfiles/otp.dc"
        "pirates/src/configfiles/pirates.dc"
    """
    notify = directNotify.newCategory('AvatarFriendsManager')

    def __init__(self, cr):
        assert self.notify.debugCall()
        DistributedObjectGlobal.__init__(self, cr)
        self.reset()

    def reset(self):
        self.avatarFriendsList = set()
        self.avatarId2Info = {}
        self.invitedAvatarsList = []
        self.ignoredAvatarList = []

    #Client only functions
    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):
        """ 
        This should be checked before querying the user for 
        interaction or popping up guis requested by other
        avatars
        """
        return avId and avId in self.ignoredAvatarList

    #Client->UD request functions

    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)

    #Functions called from UD

    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])

#Functions called from UD

    def updateAvatarFriend(self, avId, info):
        if hasattr(info, "avatarId") and (not info.avatarId) and avId:
            #info.avatarId wasn't being populated, I think this is fixed now
            # though it's odd to have the data in two places
            info.avatarId = avId

        assert self.notify.debugCall()
        if not avId in self.avatarFriendsList:
            self.avatarFriendsList.add(avId)
            self.avatarId2Info[
                avId] = info  #get the data there before we tell you it's there
            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):
        assert self.notify.debugCall()
        self.avatarFriendsList.remove(avId)
        self.avatarId2Info.pop(avId, None)
        messenger.send(OTPGlobals.AvatarFriendRemoveEvent, [avId])

    def setFriends(self, avatarIds):
        self.notify.debugCall()
        assert 0, "setFriends should not be sent to client."

    # client-called helper functions

    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
Beispiel #10
0
class NamePage(StateData):
    notify = directNotify.newCategory('NamePage')

    def __init__(self, book, parentFSM):
        self.book = book
        self.parentFSM = parentFSM
        StateData.__init__(self, 'namePageDone')
        self.fsm = ClassicFSM('NamePage', [
            State('off', self.enterOff, self.exitOff),
            State('basePage', self.enterBasePage, self.exitBasePage)
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.parentFSM.getStateNamed('namePage').addChild(self.fsm)
        self.nameServ = base.cr.nameServicesManager
        self.baseRequestIndex = 0
        self.requestsPerCluster = 5

        # GUI elements
        self.requestsContainer = {}
        self.loadingLabel = None
        self.selectedName = None
        self.nameButtons = []
        self.avId2NameData = {}

        geom = CIGlobals.getDefaultBtnGeom()
        self.acceptBtn = DirectButton(
            geom=geom,
            text_scale=0.04,
            relief=None,
            scale=0.5,
            text="Accept",
            pos=(0.5, posY, 0),
            text_pos=(0, -0.01),
            command=self.acceptName,
        )
        self.acceptBtn.hide()
        self.declineBtn = DirectButton(
            geom=geom,
            text_scale=0.04,
            relief=None,
            scale=0.5,
            text="Decline",
            pos=(0.75, posY, 0),
            text_pos=(0, -0.01),
            command=self.declineName,
        )
        self.declineBtn.hide()
        self.avIdLbl = OnscreenText(text="",
                                    scale=0.08,
                                    pos=(0.3, 0, 0.5),
                                    align=TextNode.ACenter)
        self.avIdLbl.hide()
        self.accIdLbl = OnscreenText(text="",
                                     scale=0.08,
                                     pos=(0.3, 0, 0.3),
                                     align=TextNode.ACenter)
        self.accIdLbl.hide()

    def handleRequests(self):
        gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui.bam')
        self.nameList = DirectScrolledList(
            relief=None,
            pos=(-0.54, 0, 0.08),
            incButton_image=(gui.find('**/FndsLst_ScrollUp'),
                             gui.find('**/FndsLst_ScrollDN'),
                             gui.find('**/FndsLst_ScrollUp_Rllvr'),
                             gui.find('**/FndsLst_ScrollUp')),
            incButton_relief=None,
            incButton_scale=(arrowButtonScale, arrowButtonScale,
                             -arrowButtonScale),
            incButton_pos=(buttonXstart, 0, itemFrameZorigin - 0.999),
            incButton_image3_color=Vec4(1, 1, 1, 0.2),
            incButton_command=self.__moveItems,
            incButton_extraArgs=[1],
            decButton_image=(gui.find('**/FndsLst_ScrollUp'),
                             gui.find('**/FndsLst_ScrollDN'),
                             gui.find('**/FndsLst_ScrollUp_Rllvr'),
                             gui.find('**/FndsLst_ScrollUp')),
            decButton_relief=None,
            decButton_scale=(arrowButtonScale, arrowButtonScale,
                             arrowButtonScale),
            decButton_pos=(buttonXstart, 0, itemFrameZorigin + 0.125),
            decButton_image3_color=Vec4(1, 1, 1, 0.2),
            decButton_command=self.__moveItems,
            decButton_extraArgs=[0],
            itemFrame_pos=(itemFrameXorigin, 0, itemFrameZorigin),
            itemFrame_scale=1.0,
            itemFrame_relief=DGG.SUNKEN,
            itemFrame_frameSize=(listXorigin, listXorigin + listFrameSizeX,
                                 listZorigin, listZorigin + listFrameSizeZ),
            itemFrame_frameColor=(0.85, 0.95, 1, 1),
            itemFrame_borderWidth=(0.01, 0.01),
            numItemsVisible=5,
            forceHeight=0.075,
            items=self.nameButtons)
        self.__buildItems()

    def __moveItems(self, direction):
        if direction == 0:
            # Moving down!
            self.baseRequestIndex += 1
        elif direction == 1:
            # Moving up!
            self.baseRequestIndex -= 1
        self.clearItems()
        self.__buildItems()

    def clearItems(self):
        for btn in self.nameButtons:
            btn.destroy()
        self.nameButtons = []
        self.nameList.removeAndDestroyAllItems()

    def __buildItems(self):
        for i in xrange(self.requestsPerCluster):
            request = self.nameServ.getNameRequests()[self.baseRequestIndex +
                                                      i]
            date = request['date']
            date = date.replace(' ', '-')

            data = NameData(request['name'], date, request['avId'],
                            request['accId'])
            self.avId2NameData[data.avId] = data

            btn = DirectButton(relief=None,
                               text=data.name,
                               text_scale=0.07,
                               text_align=TextNode.ALeft,
                               text1_bg=textDownColor,
                               text2_bg=textRolloverColor,
                               text3_fg=textDisabledColor,
                               textMayChange=0,
                               command=self.__handleNameButton,
                               extraArgs=[data],
                               text_pos=(0, 0, 0.0))

            data.btn = btn

            self.nameButtons.append(btn)
        self.loadingLabel.hide()

    def __handleNameButton(self, data):
        self.selectedName = data
        data.btn['state'] = DGG.DISABLED
        self.avIdLbl.setText("Avatar ID:\n" + str(data.avId))
        self.avIdLbl.show()
        self.accIdLbl.setText("Account ID:\n" + str(data.accId))
        self.accIdLbl.show()
        self.acceptBtn.show()
        self.declineBtn.show()

    def acceptName(self):
        pass

    def load(self):
        StateData.load(self)
        self.loadingLabel = OnscreenText(text='Loading...',
                                         font=CIGlobals.getToonFont(),
                                         pos=(0, 0.1, 0),
                                         scale=0.08,
                                         parent=aspect2d)

    def unload(self):
        StateData.unload(self)
        self.loadingLabel.destroy()
        self.loadingLabel = None
        for request in self.requestsContainer.values():
            for element in request:
                element.destroy()
        self.requestsContainer = {}

    def enter(self):
        StateData.enter(self)
        self.fsm.request('basePage')
        base.acceptOnce(self.nameServ.getRequestCompleteName(),
                        self.handleRequests)
        self.nameServ.d_requestNameData()

    def exit(self):
        self.fsm.requestFinalState()
        StateData.exit(self)

    def enterBasePage(self):
        self.book.createPageButtons('adminPage', None)
        self.book.setTitle('Name Approval')

    def exitBasePage(self):
        self.book.deletePageButtons(True, False)
        self.book.clearTitle()

    def enterOff(self):
        pass

    def exitOff(self):
        pass
Beispiel #11
0
class DistributedDodgeballGameAI(DistributedToonFPSGameAI, TeamMinigameAI):
    """The winter dodgeball game (AI/server side)"""

    notify = directNotify.newCategory("DistributedDodgeballGameAI")

    GameOverTime = 15.0
    GameTime = 120

    def __init__(self, air):
        DistributedToonFPSGameAI.__init__(self, air)
        TeamMinigameAI.__init__(self)
        self.setZeroCommand(self.__gameOver_time)
        self.setInitialTime(self.GameTime)
        self.fsm = ClassicFSM.ClassicFSM('DDodgeballGameAI', [
            State.State('off', self.enterOff, self.exitOff),
            State.State('waitForChooseTeam', self.enterWaitForChooseTeam,
                        self.exitWaitForChooseTeam),
            State.State('play', self.enterPlay, self.exitPlay),
            State.State('roundIntermission', self.enterRoundIntermission,
                        self.exitRoundIntermission)
        ], 'off', 'off')
        self.fsm.enterInitialState()
        self.playersReadyToStart = 0
        self.resetNumFrozen()
        self.__resetSnowballOwners()
        self.availableSpawnsByTeam = {BLUE: [0, 1, 2, 3], RED: [0, 1, 2, 3]}
        self.announcedWinner = False
        self.winnerPrize = 200
        self.loserPrize = 0
        self.gameInAction = False

    def __resetSnowballOwners(self):
        self.doId2snowballIndex = {}

    def reqPickupSnowball(self, idx):
        sender = self.air.getAvatarIdFromSender()
        if (idx not in self.doId2snowballIndex.values()
                and sender not in self.doId2snowballIndex.keys()
                and self.gameInAction):
            self.doId2snowballIndex[sender] = idx
            self.sendUpdateToAvatarId(sender, 'snowballPickupResp', [1, idx])
        else:
            self.sendUpdateToAvatarId(sender, 'snowballPickupResp', [0, idx])

    def __clearSnowballOwner(self, idx):
        sender = self.air.getAvatarIdFromSender()
        if self.doId2snowballIndex.has_key(sender):
            if self.doId2snowballIndex[sender] == idx:
                del self.doId2snowballIndex[sender]
            else:
                self.notify.warning(
                    "Player {0} does not own snowball {1}".format(sender, idx))

    def snowballHitWall(self, snowballIndex):
        self.__clearSnowballOwner(snowballIndex)

    def snowballHitGround(self, snowballIndex):
        self.__clearSnowballOwner(snowballIndex)

    def snowballHitPlayer(self, damagedPlayer, throwerTeam, snowballIndex):
        self.__clearSnowballOwner(snowballIndex)

    def resetNumFrozen(self):
        self.numFrozenByTeam = {RED: 0, BLUE: 0}

    def enterRoundIntermission(self):
        pass

    def exitRoundIntermission(self):
        pass

    def __gameOver_time(self):
        self.__gameOver(1)

    def __decideWinner(self):
        teams = [BLUE, RED]
        teams.sort(key=lambda team: self.scoreByTeam[team], reverse=True)
        self.winnerTeam = teams[0]

    def __gameOver(self, timeRanOut=0):
        self.timeRanOutLastRound = timeRanOut
        self.fsm.request('off')
        self.resetNumFrozen()
        self.__resetSnowballOwners()
        self.gameInAction = False
        if self.round == MaxRounds:
            self.__decideWinner()
            self.sendUpdate('teamWon', [self.winnerTeam, timeRanOut])
        else:
            self.sendUpdate('roundOver', [timeRanOut])
            self.fsm.request('play')

    def enemyFrozeMe(self, myTeam, enemyTeam):
        if not self.gameInAction:
            return

        self.scoreByTeam[enemyTeam] += 1
        self.numFrozenByTeam[myTeam] += 1
        self.sendUpdate('incrementTeamScore', [enemyTeam])
        if self.numFrozenByTeam[myTeam] >= len(
                self.playerListByTeam[myTeam]) and not self.announcedWinner:
            # All of the players on this team are frozen! The enemy team wins!
            self.announcedWinner = True
            self.timeRanOutLastRound = 0
            self.fsm.request('off')
            self.resetNumFrozen()
            self.__resetSnowballOwners()
            self.gameInAction = False
            if self.round == MaxRounds:
                self.__decideWinner()
                self.sendUpdate('teamWon', [self.winnerTeam, 0])
                taskMgr.doMethodLater(self.GameOverTime, self.__gameOverTask,
                                      self.uniqueName("gameOverTask"))
            else:
                self.sendUpdate('roundOver', [0])
                self.fsm.request('play')

    def __gameOverTask(self, task):
        winners = list(self.playerListByTeam[self.winnerTeam])
        self.d_gameOver(1, winners)
        return task.done

    def teamMateUnfrozeMe(self, myTeam):
        self.numFrozenByTeam[myTeam] -= 1

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterWaitForChooseTeam(self):
        for avatar in self.avatars:
            self.sendUpdate('setupRemoteAvatar', [avatar.doId])
        self.sendUpdate('chooseUrTeam')

    def exitWaitForChooseTeam(self):
        pass

    def enterPlay(self):
        self.announcedWinner = False
        self.gameInAction = False
        self.setRound(self.getRound() + 1)
        if self.getRound() == 1:
            self.d_startGame()
            time = 18.0
        else:
            mult = 2
            if self.timeRanOutLastRound:
                mult = 3
            time = (2.05 * mult) + 8.0

        base.taskMgr.doMethodLater(time, self.__actuallyStarted,
                                   self.uniqueName('actuallyStarted'))

    def __actuallyStarted(self, task):
        self.gameInAction = True
        self.setInitialTime(self.GameTime)
        self.startTiming()
        return task.done

    def exitPlay(self):
        self.gameInAction = False
        self.stopTiming()
        base.taskMgr.remove(self.uniqueName('actuallyStarted'))

    def allAvatarsReady(self):
        self.fsm.request('waitForChooseTeam')

    def choseTeam(self, team):
        avId = self.air.getAvatarIdFromSender()

        # We'll send our own accepted message.
        isOnTeam = TeamMinigameAI.choseTeam(self,
                                            team,
                                            avId,
                                            sendAcceptedMsg=False)

        if isOnTeam:
            # Pick a spawn point for them
            spawnIndex = random.choice(self.availableSpawnsByTeam[team])
            self.availableSpawnsByTeam[team].remove(spawnIndex)

            self.sendUpdateToAvatarId(avId, 'acceptedIntoTeam', [spawnIndex])

    def readyToStart(self):
        self.playersReadyToStart += 1
        if self.playersReadyToStart == len(self.avatars):
            self.fsm.request('play')

    def delete(self):
        taskMgr.remove(self.uniqueName('gameOverTask'))
        self.fsm.requestFinalState()
        del self.fsm
        del self.playersReadyToStart
        del self.availableSpawnsByTeam
        del self.doId2snowballIndex
        TeamMinigameAI.cleanup(self)
        DistributedToonFPSGameAI.delete(self)
Beispiel #12
0
# This file is automatically generated by makepanda.py.  Do not modify.
from __future__ import absolute_import
from ._direct import *
### BEGIN direct/src/extensions_native/CInterval_extensions.py
from .core import Dtool_funcToMethod
from direct.directnotify.DirectNotifyGlobal import directNotify

CInterval.DtoolClassDict["notify"] = directNotify.newCategory("Interval")

#####################################################################
def setT(self, t):
    # Overridden from the C++ function to call privPostEvent
    # afterward.  We do this by renaming the C++ function in
    # FFIRename.
    self.setT_Old(t)
    self.privPostEvent()

CInterval.DtoolClassDict["setT_Old"] = CInterval.setT
Dtool_funcToMethod(setT, CInterval)
del setT
#####################################################################

def play(self, t0 = 0.0, duration = None, scale = 1.0):
    self.notify.error("CInterval.play() is deprecated, use start() instead")
    if duration:  # None or 0 implies full length
        self.start(t0, t0 + duration, scale)
    else:
        self.start(t0, -1, scale)

Dtool_funcToMethod(play, CInterval)
del play
import os, sys, socket, random
#from urllib import quote_plus
from pandac.PandaModules import HTTPClient
from pandac.PandaModules import HTTPCookie
from pandac.PandaModules import URLSpec
from pandac.PandaModules import Ramfile
from pandac.PandaModules import Ostream
from pandac.PandaModules import HTTPDate
from pandac.PandaModules import DocumentSpec
from direct.task.Task import Task
from direct.directnotify.DirectNotifyGlobal import directNotify
notify = directNotify.newCategory('UserFunnel')

class UserFunnel:

    def __init__(self):
        self.hitboxAcct = 'DM53030620EW'
        self.language = 'en-us'
        self.cgRoot = 'ToonTown_Online'
        self.cgBeta = 'Beta'
        self.cgRelease = 'Release'
        self.cgLocation = 'US'
        self.campaignID = ''
        self.cfCookieFile = 'cf.txt'
        self.dynamicVRFunnel = 'http://download.toontown.com/'
        self.hostDict = {0: 'Internal Disney PHP Collector Site',
         1: 'ehg-dig.hitbox.com/HG?',
         2: 'ehg-dig.hitbox.com/HG?',
         3: 'build64.online.disney.com:5020/index.php?'}
        self.CurrentHost = ''
        self.URLtoSend = ''
class SetNameTypedFSM(AvatarOperationFSM):
    notify = directNotify.newCategory('SetNameTypedFSM')
    POST_ACCOUNT_STATE = 'RetrieveAvatar'

    def enterStart(self, avId, name):
        self.avId = avId
        self.name = name
        if self.avId:
            self.demand('RetrieveAccount')
            return
        self.demand('JudgeName')

    def enterRetrieveAvatar(self):
        if self.avId and self.avId not in self.avList:
            self.demand(
                'Kill',
                'Tried to name an avatar (%d) not in the account!' % self.avId)
            return
        self.csm.air.dbInterface.queryObject(self.csm.air.dbId, self.avId,
                                             self.__handleAvatar)

    def __handleAvatar(self, dclass, fields):
        if dclass != self.csm.air.dclassesByName['DistributedToonUD']:
            self.demand(
                'Kill',
                "One of the account's avatars is invalid! Its DClass is %s, but it should be DistributedToonUD!"
                % dclass)
            return
        if fields['WishNameState'] != WISHNAME_OPEN:
            self.demand(
                'Kill',
                'Avatar %d is not supposed to be able to be named right now! Its name status is %d.'
                % (self.avId, fields['WishNameState']))
            return
        self.demand('JudgeName')

    def enterJudgeName(self):
        status = judgeName(self.name)
        if self.avId and status:
            if status == 2:
                self.csm.air.dbInterface.updateObject(
                    self.csm.air.dbId, self.avId,
                    self.csm.air.dclassesByName['DistributedToonUD'], {
                        'WishNameState': WISHNAME_LOCKED,
                        'WishName': '',
                        'setName': (self.name, )
                    })
            else:
                self.csm.air.dbInterface.updateObject(
                    self.csm.air.dbId, self.avId,
                    self.csm.air.dclassesByName['DistributedToonUD'], {
                        'WishNameState': WISHNAME_PENDING,
                        'WishName': self.name,
                        'WishNameTimestamp': int(time.time())
                    })
        if self.avId:
            self.csm.air.writeServerEvent('avatar-wishname', self.avId,
                                          self.name)
        self.csm.sendUpdateToAccountId(self.target, 'setNameTypedResp',
                                       [self.avId, status])
        self.demand('Off')
class SetNamePatternFSM(AvatarOperationFSM):
    notify = directNotify.newCategory('SetNamePatternFSM')
    POST_ACCOUNT_STATE = 'RetrieveAvatar'

    def enterStart(self, avId, pattern):
        self.avId = avId
        self.pattern = pattern
        self.demand('RetrieveAccount')

    def enterRetrieveAvatar(self):
        if self.avId and self.avId not in self.avList:
            self.demand(
                'Kill',
                'Tried to name an avatar (%d) not in the account!' % self.avId)
            return
        self.csm.air.dbInterface.queryObject(self.csm.air.dbId, self.avId,
                                             self.__handleAvatar)

    def __handleAvatar(self, dclass, fields):
        if dclass != self.csm.air.dclassesByName['DistributedToonUD']:
            self.demand(
                'Kill',
                "One of the account's avatars is invalid! Its DClass is %s, but it should be DistributedToonUD!"
                % dclass)
            return
        if fields['WishNameState'] != WISHNAME_OPEN:
            self.demand(
                'Kill',
                'Avatar %d is not supposed to be able to be named right now! Its name status is %d.'
                % (self.avId, fields['WishNameState']))
            return
        self.demand('SetName')

    def enterSetName(self):
        parts = []
        for p, f in self.pattern:
            if p == 213:
                p = 212
            part = self.csm.nameGenerator.nameDictionary.get(p, ('', ''))[1]
            if f:
                part = part[:1].upper() + part[1:]
            else:
                part = part.lower()
            parts.append(part)

        parts[2] += parts.pop(3)
        while '' in parts:
            parts.remove('')

        name = (' ').join(parts)
        self.csm.air.dbInterface.updateObject(
            self.csm.air.dbId, self.avId,
            self.csm.air.dclassesByName['DistributedToonUD'], {
                'WishNameState': WISHNAME_LOCKED,
                'WishName': '',
                'setName': (name, )
            })
        self.csm.air.writeServerEvent('avatar-named',
                                      avId=self.avId,
                                      name=name)
        self.csm.sendUpdateToAccountId(self.target, 'setNamePatternResp',
                                       [self.avId, 1])
        self.demand('Off')
class GetAvatarsFSM(AvatarOperationFSM):
    notify = directNotify.newCategory('GetAvatarsFSM')
    POST_ACCOUNT_STATE = 'QueryAvatars'

    def enterStart(self):
        self.demand('RetrieveAccount')

    def enterQueryAvatars(self):
        self.pendingAvatars = set()
        self.avatarFields = {}
        for avId in self.avList:
            if avId:
                self.pendingAvatars.add(avId)

                def response(dclass, fields, avId=avId):
                    if self.state != 'QueryAvatars':
                        return
                    if dclass != self.csm.air.dclassesByName[
                            'DistributedToonUD']:
                        self.demand(
                            'Kill',
                            "One of the account's avatars is invalid! Its DClass is %s, but it should be DistributedToonUD!"
                            % dclass)
                        return
                    if not fields.has_key('setDISLid'):
                        self.csm.air.dbInterface.updateObject(
                            self.csm.air.dbId, avId,
                            self.csm.air.dclassesByName['DistributedToonUD'],
                            {'setDISLid': [self.target]})
                    self.avatarFields[avId] = fields
                    self.pendingAvatars.remove(avId)
                    if not self.pendingAvatars:
                        self.demand('SendAvatars')

                self.csm.air.dbInterface.queryObject(self.csm.air.dbId, avId,
                                                     response)

        if not self.pendingAvatars:
            self.demand('SendAvatars')

    def enterSendAvatars(self):
        potentialAvs = []
        for avId, fields in self.avatarFields.items():
            index = self.avList.index(avId)
            wns = fields.get('WishNameState', WISHNAME_LOCKED)
            name = fields['setName'][0]
            if wns == WISHNAME_OPEN:
                nameState = 1
            else:
                if wns == WISHNAME_PENDING:
                    nameState = 2
                else:
                    if wns == WISHNAME_APPROVED:
                        nameState = 3
                        name = fields['WishName']
                    else:
                        if wns == WISHNAME_REJECTED:
                            nameState = 4
                        else:
                            if wns == WISHNAME_LOCKED:
                                nameState = 0
                            else:
                                self.csm.notify.warning(
                                    'Avatar %d is in unknown name state %s.' %
                                    (avId, wns))
                                nameState = 0
            potentialAvs.append(
                [avId, name, fields['setDNAString'][0], index, nameState])

        self.csm.sendUpdateToAccountId(self.target, 'setTrialer',
                                       [self.trialer])
        self.csm.sendUpdateToAccountId(self.target, 'setAvatars',
                                       [potentialAvs])
        self.demand('Off')
class CreateAvatarFSM(OperationFSM):
    notify = directNotify.newCategory('CreateAvatarFSM')

    def enterStart(self, dna, index, skipTutorial):
        if index >= 7:
            self.demand('Kill', 'Invalid index (%d) specified!' % index)
            return
        if not ToonDNA().isValidNetString(dna):
            self.demand('Kill', 'Invalid DNA specified!')
            return
        self.index = index
        self.dna = dna
        self.skipTutorial = skipTutorial
        self.demand('RetrieveAccount')

    def enterRetrieveAccount(self):
        self.csm.air.dbInterface.queryObject(self.csm.air.dbId, self.target,
                                             self.__handleRetrieve)

    def __handleRetrieve(self, dclass, fields):
        if dclass != self.csm.air.dclassesByName['AccountUD']:
            self.demand(
                'Kill',
                'Your account object (%s) was not found in the database!' %
                dclass)
            return
        self.account = fields
        self.avList = self.account['ACCOUNT_AV_SET']
        self.avList = self.avList[:7]
        self.avList += [0] * (7 - len(self.avList))
        if self.avList[self.index]:
            self.demand(
                'Kill',
                'Avatar slot %d is already taken by another avatar (%s)!' %
                (self.index, str(self.avList[self.index])))
            return
        self.demand('CreateAvatar')

    def enterCreateAvatar(self):
        dna = ToonDNA()
        dna.makeFromNetString(self.dna)
        colorstring = TTLocalizer.NumToColor[dna.headColor]
        animaltype = TTLocalizer.AnimalToSpecies[dna.getAnimal()]
        if self.index == 6:
            name = 'Episode Toon'
        else:
            name = colorstring + ' ' + animaltype
        toonFields = {
            'setName': (name, ),
            'WishNameState': WISHNAME_OPEN,
            'WishName': '',
            'setDNAString': (self.dna, ),
            'setTutorialAck': (int(self.skipTutorial), ),
            'setDISLid': (self.target, )
        }
        self.csm.air.dbInterface.createObject(
            self.csm.air.dbId,
            self.csm.air.dclassesByName['DistributedToonUD'], toonFields,
            self.__handleCreate)

    def __handleCreate(self, avId):
        if not avId:
            self.demand('Kill',
                        'Database failed to create the new avatar object!')
            return
        self.avId = avId
        self.demand('StoreAvatar')

    def enterStoreAvatar(self):
        self.avList[self.index] = self.avId
        self.csm.air.dbInterface.updateObject(
            self.csm.air.dbId, self.target,
            self.csm.air.dclassesByName['AccountUD'],
            {'ACCOUNT_AV_SET': self.avList},
            {'ACCOUNT_AV_SET': self.account['ACCOUNT_AV_SET']},
            self.__handleStoreAvatar)

    def __handleStoreAvatar(self, fields):
        if fields:
            self.demand(
                'Kill',
                'Database failed to associate the new avatar to your account!')
            return
        self.csm.air.writeServerEvent('avatar-created',
                                      avId=self.avId,
                                      accId=self.target,
                                      dna=self.dna.encode('hex'),
                                      slot=self.index)
        self.csm.sendUpdateToAccountId(self.target, 'createAvatarResp',
                                       [self.avId])
        self.demand('Off')
class LoginAccountFSM(OperationFSM):
    TARGET_CONNECTION = True
    notify = directNotify.newCategory('LoginAccountFSM')

    def enterStart(self, cookie):
        self.cookie = cookie
        self.demand('QueryAccountDB')

    def enterQueryAccountDB(self):
        self.csm.accountDB.lookup(self.cookie, self.__handleLookup)

    def __handleLookup(self, result):
        if not result.get('success'):
            self.csm.air.writeServerEvent('cookie-rejected',
                                          clientId=self.target,
                                          cookie=self.cookie)
            self.demand(
                'Kill',
                result.get('reason',
                           'The accounts database rejected your cookie.'))
            return
        self.databaseId = result.get('databaseId', 0)
        accountId = result.get('accountId', 0)
        self.adminAccess = result.get('adminAccess', 0)
        if self.adminAccess < simbase.config.GetInt('minimum-access', 100):
            self.csm.air.writeServerEvent('insufficient-access', self.target,
                                          self.cookie)
            self.demand(
                'Kill',
                result.get(
                    'reason',
                    'You have insufficient access to login.\nYou have access level %d and you need access level %d.'
                    % (self.adminAccess,
                       simbase.config.GetInt('minimum-access', 100))))
            return
        if accountId:
            self.accountId = accountId
            self.demand('RetrieveAccount')
        else:
            self.demand('CreateAccount')

    def enterRetrieveAccount(self):
        self.csm.air.dbInterface.queryObject(self.csm.air.dbId, self.accountId,
                                             self.__handleRetrieve)

    def __handleRetrieve(self, dclass, fields):
        if dclass != self.csm.air.dclassesByName['AccountUD']:
            self.demand(
                'Kill',
                'Your account object (%s) was not found in the database!' %
                dclass)
            return
        self.account = fields
        self.demand('SetAccount')

    def enterCreateAccount(self):
        self.account = {
            'ACCOUNT_AV_SET': [0] * 7,
            'ESTATE_ID': 0,
            'ACCOUNT_AV_SET_DEL': [],
            'CREATED': time.ctime(),
            'LAST_LOGIN': time.ctime(),
            'ACCOUNT_ID': str(self.databaseId),
            'ADMIN_ACCESS': self.adminAccess,
            'TRIALER': 0
        }
        self.csm.air.dbInterface.createObject(
            self.csm.air.dbId, self.csm.air.dclassesByName['AccountUD'],
            self.account, self.__handleCreate)

    def __handleCreate(self, accountId):
        if self.state != 'CreateAccount':
            self.notify.warning(
                'Received create account response outside of CreateAccount state.'
            )
            return
        if not accountId:
            self.notify.warning(
                'Database failed to construct an account object!')
            self.demand(
                'Kill',
                'Your account object could not be created in the game database.'
            )
            return
        self.csm.air.writeServerEvent('accountCreated', accountId)
        self.accountId = accountId
        self.demand('StoreAccountID')

    def enterStoreAccountID(self):
        self.csm.accountDB.storeAccountID(self.databaseId, self.accountId,
                                          self.__handleStored)

    def __handleStored(self, success=True):
        if not success:
            self.demand(
                'Kill',
                'The account server could not save your account DB ID!')
            return
        self.demand('SetAccount')

    def enterSetAccount(self):
        dg = PyDatagram()
        dg.addServerHeader(
            self.csm.GetAccountConnectionChannel(self.accountId),
            self.csm.air.ourChannel, CLIENTAGENT_EJECT)
        dg.addUint16(100)
        dg.addString('This account has been logged in elsewhere.')
        self.csm.air.send(dg)
        dg = PyDatagram()
        dg.addServerHeader(self.target, self.csm.air.ourChannel,
                           CLIENTAGENT_OPEN_CHANNEL)
        dg.addChannel(self.csm.GetAccountConnectionChannel(self.accountId))
        self.csm.air.send(dg)
        access = self.account.get('ADMIN_ACCESS', 0)
        if access >= 400:
            dg = PyDatagram()
            dg.addServerHeader(self.target, self.csm.air.ourChannel,
                               CLIENTAGENT_OPEN_CHANNEL)
            dg.addChannel(OtpDoGlobals.OTP_MOD_CHANNEL)
            self.csm.air.send(dg)
        if access >= 500:
            dg = PyDatagram()
            dg.addServerHeader(self.target, self.csm.air.ourChannel,
                               CLIENTAGENT_OPEN_CHANNEL)
            dg.addChannel(OtpDoGlobals.OTP_ADMIN_CHANNEL)
            self.csm.air.send(dg)
        dg = PyDatagram()
        dg.addServerHeader(self.target, self.csm.air.ourChannel,
                           CLIENTAGENT_SET_CLIENT_ID)
        dg.addChannel(self.accountId << 32)
        self.csm.air.send(dg)
        dg = PyDatagram()
        dg.addServerHeader(self.target, self.csm.air.ourChannel,
                           CLIENTAGENT_SET_STATE)
        dg.addUint16(2)
        self.csm.air.send(dg)
        self.csm.air.dbInterface.updateObject(
            self.csm.air.dbId, self.accountId,
            self.csm.air.dclassesByName['AccountUD'], {
                'LAST_LOGIN': time.ctime(),
                'ACCOUNT_ID': str(self.databaseId),
                'ADMIN_ACCESS': self.adminAccess
            })
        self.csm.air.writeServerEvent('account-login',
                                      clientId=self.target,
                                      accId=self.accountId,
                                      webAccId=self.databaseId,
                                      cookie=self.cookie)
        self.csm.sendUpdateToChannel(self.target, 'acceptLogin', [])
        self.demand('Off')
Beispiel #19
0
from direct.extensions_native import VBase4_extensions
from direct.extensions_native import NodePath_extensions


from panda3d.core import loadPrcFile


if __debug__:
    loadPrcFile('config/general.prc')
    loadPrcFile('config/release/dev.prc')


from direct.directnotify.DirectNotifyGlobal import directNotify


notify = directNotify.newCategory('ClientStart')
notify.setInfo(True)


from otp.settings.Settings import Settings


preferencesFilename = ConfigVariableString(
    'preferences-filename', 'preferences.json').getValue()
notify.info('Reading %s...' % preferencesFilename)
__builtin__.settings = Settings(preferencesFilename)
if 'fullscreen' not in settings:
    settings['fullscreen'] = False
if 'music' not in settings:
    settings['music'] = True
if 'sfx' not in settings:
class SuitPursueToonBehaviorAI(SuitPathBehaviorAI):
    notify = directNotify.newCategory('SuitPursueToonBehaviorAI')

    RemakePathDistance = 10.0
    DivertDistance = 5.0
    MaxNonSafeDistance = 40.0
    MaxAttackersPerTarget = 2
    AttackCooldownFactor = 6.0
    PickTargetRetryTime = 1.0

    def __init__(self, suit, pathFinder):
        SuitPathBehaviorAI.__init__(self, suit, False)
        self.fsm = ClassicFSM.ClassicFSM('SuitPursueToonBehaviorAI', [State.State('off', self.enterOff, self.exitOff),
         State.State('pursue', self.enterPursue, self.exitPursue),
         State.State('divert', self.enterDivert, self.exitDivert),
         State.State('attack', self.enterAttack, self.exitAttack)], 'off', 'off')
        self.fsm.enterInitialState()
        self.air = self.suit.air
        self.target = None
        self.targetId = None
        self.pathFinder = pathFinder
        self.suitList = None
        self.suitDict = None

    def setSuitList(self, sList):
        self.suitList = sList

    def setSuitDict(self, sDict):
        self.suitDict = sDict

    def enter(self):
        SuitPathBehaviorAI.enter(self)
        self.__tryPickAndPursue()

    def __tryPickAndPursue(self):
        if self.pickTarget():
            # Choose a distance that is good enough to attack this target.
            #                                 the more damage we do, the more distance we can have and still be effective
            dmgMod = self.suit.suitPlan.getCogClassAttrs().dmgMod
            self.attackSafeDistance = random.uniform(15 * dmgMod, 30 * dmgMod)
            # Now, chase them down!
            self.fsm.request('pursue')

    def setTarget(self, toon):
        self.targetId = toon.doId
        self.target = toon
        self.suit.sendUpdate('setChaseTarget', [self.targetId])

    def pickTarget(self):
        if not self.battle:
            return
        if len(self.battle.getAvatars()) == 0:
            # We have nothing to do.
            return

        # Choose the toon with the least amount of attackers to target (a maximum of two attackers per target).
        avIds = list(self.battle.getAvatars())
        avIds.sort(key = lambda avId: self.battle.getNumSuitsTargeting(avId))

        leastAmt = self.battle.getNumSuitsTargeting(avIds[0])
        for avId in self.battle.getAvatars():
            if self.battle.getNumSuitsTargeting(avId) != leastAmt and avId in avIds:
                avIds.remove(avId)

        #for avId in self.battle.getAvatars():
        #    numAttackers = len(self.suit.getBattleZone().getSuitsTargetingAvId(avId))
        #    if numAttackers  >= self.MaxAttackersPerTarget:
        #        # This toon has too many attackers already.
        #        print str(self.suit.doId) + ": Toon " + str(avId) + " already has " + str(numAttackers) + " attackers."
        #        avIds.remove(avId)

        # Temporary fix for district resets. TODO: Actually correct this.
        for avId in self.battle.getAvatars():
            av = self.air.doId2do.get(avId)
            if av is None and avId in avIds:
                avIds.remove(avId)
            elif av is not None and av.isDead() and avId in avIds:
                # Don't target dead toons.
                avIds.remove(avId)
            elif av is not None and (not self.isPlayerVisible(av)) and avId in avIds:
                avIds.remove(avId)

        # Make sure we found some avatars to pursue.
        if len(avIds) == 0:
            taskMgr.doMethodLater(self.PickTargetRetryTime, self.__pickTargetRetryTask, self.suit.uniqueName("PickTargetRetryTask"))
            return 0

        # At this point the avIds are only toons with the least amount of attackers.
        # For example, there may be two toons with no attackers, so randomly pick between those two toons.
        self.targetId = random.choice(avIds)

        self.target = self.air.doId2do.get(self.targetId)
        self.suit.sendUpdate('setChaseTarget', [self.targetId])
        self.suit.getBattleZone().newTarget(self.suit.doId, self.targetId)
        return 1

    def resetNextFrame(self):
        if not hasattr(self, 'suit') or not self.suit:
            return
        taskMgr.remove(self.suit.uniqueName('resetNextFrame'))
        taskMgr.doMethodLater(self.PickTargetRetryTime, self.reset, self.suit.taskName('resetNextFrame'))
        
    def reset(self, task = None):
        if not hasattr(self, 'suit') or not self.suit:
            return
            
        self.exit()
        self.enter()

        if task:
            return task.done

    def exit(self):
        taskMgr.remove(self.suit.uniqueName('resetNextFrame'))
        taskMgr.remove(self.suit.uniqueName("PickTargetRetryTask"))
        self.fsm.request('off')
        self.target = None
        self.targetId = None
        self.suit.getBattleZone().clearTargets(self.suit.doId)
        self.suit.sendUpdate('setChaseTarget', [0])
        SuitPathBehaviorAI.exit(self)

    def unload(self):
        self.mgr = None
        self.battle = None
        self.target = None
        self.targetId = None
        self.suitList = None
        self.suitDict = None
        self.air = None
        SuitPathBehaviorAI.unload(self)

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def __pickTargetRetryTask(self, task):
        self.__tryPickAndPursue()
        return task.done

    def enterAttack(self, useSafeDistance = True):
        taskMgr.add(self._attackTask, self.suit.uniqueName('attackToonTask'),
                    extraArgs = [useSafeDistance], appendTask = True)

    def _attackTask(self, useSafeDistance, task):
        if not self.isAvatarReachable(self.target) or not self.isPlayerVisible(self.target, checkVisionAngle = False):
            self.resetNextFrame()
            return task.done

        if useSafeDistance:
            safeDistance = self.attackSafeDistance
        else:
            safeDistance = SuitPursueToonBehaviorAI.MaxNonSafeDistance

        if self.suit.getDistance(self.target) > safeDistance:
            # Nope, we're too far away! We need to chase them down!
            self.fsm.request('pursue')
            return task.done

        if self.target.isDead():
            # They've died, stop attacking
            self.resetNextFrame()
            return task.done

        attack = SuitUtils.attack(self.suit, self.target)
        timeout = SuitAttacks.SuitAttacks.attack2attackClass[attack].length

        task.delayTime = timeout
        return task.again

    def exitAttack(self):
        taskMgr.remove(self.suit.uniqueName('attackToonTask'))

    def enterDivert(self):
        moveVector = Vec2()

        currPos = Point2(self.suit.getX(render), self.suit.getY(render))
        if self.suitList is not None:
            data = self.suitList
        elif self.suitDict is not None:
            data = self.suitDict.values()
        for suit in data:
            if suit == self.suit:
                continue

            otherPos = Point2(suit.getX(render), suit.getY(render))

            moveAway = currPos - otherPos

            if moveAway.length() > self.DivertDistance:
                continue
            moveMag = 1.0 / max(moveAway.lengthSquared(), 0.1)
            moveAway.normalize()
            moveAway *= moveMag

            moveVector += moveAway

        moveVector.normalize()
        x, y = currPos + (moveVector * self.DivertDistance)
        if not self.createPath(pos = (x, y, self.suit.getZ(render))):
            self.resetNextFrame()

    def walkDone(self):
        if self.fsm.getCurrentState().getName() == 'divert':
            self.fsm.request('pursue')

    def exitDivert(self):
        self.clearWalkTrack()

    def enterPursue(self):
        # Make our initial path to the toon.
        if not self.isAvatarReachable(self.target):
            self.resetNextFrame()
            return
            
        self.lastCheckedPos = self.target.getPos(render)
        
        if not self.isPlayerVisible(self.target, checkVisionAngle = False) or not self.createPath(self.target):
            # We couldn't figure out a good path to this target.
            # Try again in a little bit.
            self.resetNextFrame()
            return
            
        taskMgr.add(self._pursueTask, self.suit.uniqueName('pursueToonTask'))
        taskMgr.add(self._scanTask, self.suit.uniqueName('scanTask'))

    def _scanTask(self, task):
        if self.suitList is not None:
            data = self.suitList
        elif self.suitDict is not None:
            data = self.suitDict.values()
        else:
            return task.done

        myClass = self.suit.suitPlan.getCogClass()
        myLevel = self.suit.getLevel()

        for suit in data:
            if suit == self.suit or not suit.suitPlan:
                continue

            theirClass = suit.suitPlan.getCogClass()
            theirLevel = suit.getLevel()

            if theirClass < myClass:
                # Don't make way for a lower class than me.
                continue
            elif theirClass == myClass and theirLevel < myLevel:
                # If we are the same class, don't make way for a lower level than me.
                continue
            elif (theirLevel == myLevel and
                  suit.doId > self.suit.doId):
                # If we are the same level, don't make way for a younger cog.
                continue

            currPos = Point2(self.suit.getX(render), self.suit.getY(render))
            otherPos = Point2(suit.getX(render), suit.getY(render))
            if (currPos - otherPos).length() < self.DivertDistance:
                self.fsm.request('divert')
                return task.done

        return task.again

    def _pursueTask(self, task):
        if self.target:
            if self.target.isDead() or not hasattr(self, 'attackSafeDistance'):
                self.resetNextFrame()
                return task.done
            currPos = self.target.getPos(render)
            if self.suit.getDistance(self.target) <= self.attackSafeDistance and not self.target.isDead():
                # We're a good distance to attack this toon. Let's do it.
                self.fsm.request('attack')
                return task.done
            elif (currPos.getXy() - self.lastCheckedPos.getXy()).length() >= SuitPursueToonBehaviorAI.RemakePathDistance:
                # They're too far from where we're trying to go! Make a new path to where they are!
                self.lastCheckedPos = self.target.getPos(render)
                self.createPath(self.target)
        task.delayTime = 1.0
        return task.again

    def exitPursue(self):
        taskMgr.remove(self.suit.uniqueName('scanTask'))
        taskMgr.remove(self.suit.uniqueName('pursueToonTask'))
        if hasattr(self, 'lastCheckedPos'):
            del self.lastCheckedPos
        self.clearWalkTrack()

    def shouldStart(self):
        return True
class LoadAvatarFSM(AvatarOperationFSM):
    notify = directNotify.newCategory('LoadAvatarFSM')
    POST_ACCOUNT_STATE = 'GetTargetAvatar'

    def enterStart(self, avId):
        self.avId = avId
        self.demand('RetrieveAccount')

    def enterGetTargetAvatar(self):
        if self.avId not in self.avList:
            self.demand(
                'Kill',
                'Tried to play an avatar (%d) not in the account!' % self.avId)
            return
        self.csm.air.dbInterface.queryObject(self.csm.air.dbId, self.avId,
                                             self.__handleAvatar)

    def __handleAvatar(self, dclass, fields):
        if dclass != self.csm.air.dclassesByName['DistributedToonUD']:
            self.demand(
                'Kill',
                "One of the account's avatars is invalid! Its DClass is %s, but it should be DistributedToonUD!"
                % dclass)
            return
        self.avatar = fields
        self.demand('SetAvatar')

    def enterSetAvatar(self):
        channel = self.csm.GetAccountConnectionChannel(self.target)
        dgcleanup = PyDatagram()
        dgcleanup.addServerHeader(self.avId, channel,
                                  STATESERVER_OBJECT_DELETE_RAM)
        dgcleanup.addUint32(self.avId)
        dg = PyDatagram()
        dg.addServerHeader(channel, self.csm.air.ourChannel,
                           CLIENTAGENT_ADD_POST_REMOVE)
        dg.addString(dgcleanup.getMessage())
        self.csm.air.send(dg)
        adminAccess = self.account.get('ADMIN_ACCESS', 0)
        adminAccess = adminAccess - adminAccess % 100
        self.csm.air.sendActivate(
            self.avId, 0, 0, self.csm.air.dclassesByName['DistributedToonUD'],
            {'setAdminAccess': [self.account.get('ADMIN_ACCESS', 0)]})
        dg = PyDatagram()
        dg.addServerHeader(channel, self.csm.air.ourChannel,
                           CLIENTAGENT_OPEN_CHANNEL)
        dg.addChannel(self.csm.GetPuppetConnectionChannel(self.avId))
        self.csm.air.send(dg)
        dg = PyDatagram()
        dg.addServerHeader(channel, self.csm.air.ourChannel,
                           CLIENTAGENT_ADD_SESSION_OBJECT)
        dg.addUint32(self.avId)
        self.csm.air.send(dg)
        dg = PyDatagram()
        dg.addServerHeader(channel, self.csm.air.ourChannel,
                           CLIENTAGENT_SET_CLIENT_ID)
        dg.addChannel(self.target << 32 | self.avId)
        self.csm.air.send(dg)
        dg = PyDatagram()
        dg.addServerHeader(self.avId, self.csm.air.ourChannel,
                           STATESERVER_OBJECT_SET_OWNER)
        dg.addChannel(self.csm.GetAccountConnectionChannel(self.target))
        self.csm.air.send(dg)
        fields = self.avatar
        fields.update(
            {'setAdminAccess': [self.account.get('ADMIN_ACCESS', 0)]})
        self.csm.air.friendsManager.toonOnline(self.avId, fields)
        self.csm.air.globalPartyMgr.avatarJoined(self.avId)
        self.csm.air.writeServerEvent('avatar-chosen',
                                      avId=self.avId,
                                      accId=self.target)
        self.demand('Off')
Beispiel #22
0
class DLPlayground(Playground):
    notify = directNotify.newCategory("DLPlayground")
Beispiel #23
0
import direct
from pandac.PandaModules import HttpRequest
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.task.TaskManagerGlobal import taskMgr
from direct.task import Task
from LandingPage import LandingPage
from direct.showbase import ElementTree as ET

notify = directNotify.newCategory('WebRequestDispatcher')

class WebRequest(object):
    """
    Pointer to a single web request (maps to an open HTTP socket).
    An instance of this class maps to a single client waiting for a response.

    connection is an instance of libdirect.HttpRequest
    """
    def __init__(self,connection):
        self.connection = connection

    def getURI(self):
        return self.connection.GetRequestURL()

    def getRequestType(self):
        return self.connection.GetRequestType()

    def dictFromGET(self):
        result = {}
        for pair in self.connection.GetRequestOptionString().split('&'):
            arg = pair.split('=',1)
            if len(arg) > 1:
class ClientServicesManagerUD(DistributedObjectGlobalUD):
    notify = directNotify.newCategory('ClientServicesManagerUD')

    def announceGenerate(self):
        DistributedObjectGlobalUD.announceGenerate(self)
        self.connection2fsm = {}
        self.account2fsm = {}
        self.nameGenerator = NameGenerator()
        self.wantMiniServer = config.GetBool('want-mini-server', False)
        dbtype = config.GetString('accountdb-type', 'developer')
        if dbtype == 'developer':
            self.accountDB = DeveloperAccountDB(self)
        else:
            if dbtype == 'local':
                self.accountDB = LocalAccountDB(self)
            else:
                self.notify.error('Invalid account DB type configured: %s' %
                                  dbtype)
        self.loginsEnabled = True

    def killConnection(self, connId, code=122, reason=''):
        self.notify.info('Booting client: %d out for reason(%d): %s' %
                         (int(connId), int(code), str(reason)))
        dg = PyDatagram()
        dg.addServerHeader(connId, self.air.ourChannel, CLIENTAGENT_EJECT)
        dg.addUint16(int(code))
        dg.addString(str(reason))
        self.air.send(dg)

    def killConnectionFSM(self, connId):
        fsm = self.connection2fsm.get(connId)
        if not fsm:
            self.notify.warning(
                'Tried to kill connection %d for duplicate FSM, but none exists!'
                % connId)
            return
        self.killConnection(connId,
                            reason='An operation is already underway: ' +
                            fsm.name)

    def killAccount(self, accountId, reason):
        self.killConnection(self.GetAccountConnectionChannel(accountId),
                            reason=reason)

    def killAccountFSM(self, accountId):
        fsm = self.account2fsm.get(accountId)
        if not fsm:
            self.notify.warning(
                'Tried to kill account %d for duplicate FSM, but none exists!'
                % accountId)
            return
        self.killAccount(accountId,
                         'An operation is already underway: ' + fsm.name)

    def runAccountFSM(self, fsmtype, *args):
        sender = self.air.getAccountIdFromSender()
        if not sender:
            self.killAccount(sender, 'Client is not logged in.')
        if sender in self.account2fsm:
            self.killAccountFSM(sender)
            return
        self.account2fsm[sender] = fsmtype(self, sender)
        self.account2fsm[sender].request('Start', *args)

    def setLoginEnabled(self, enable):
        if not enable:
            self.notify.warning(
                'The CSMUD has been told to reject logins! All future logins will now be rejected.'
            )
        self.loginsEnabled = enable

    def login(self, cookie, hwId, sig, serverURL):
        self.notify.debug('Received login cookie %r from %d' %
                          (cookie, self.air.getMsgSender()))
        sender = self.air.getMsgSender()
        self.air.writeServerEvent('login',
                                  hwId=hwId,
                                  serverURL=serverURL,
                                  cookie=cookie)
        if not self.wantMiniServer and serverURL != '127.0.0.1':
            self.killConnection(
                sender, 201,
                'This server is not currently running in mini-server mode. Please try again later.'
            )
            return
        if not self.loginsEnabled:
            self.killConnection(
                sender, 200,
                'Logins are currently disabled. Please try again later.')
            return
        if sender >> 32:
            self.killConnection(sender, reason='Client is already logged in.')
            return
        key = config.GetString('csmud-secret',
                               'broken-code-store') + config.GetString(
                                   'server-version', 'no_version_set') + str(
                                       self.air.hashVal) + FIXED_KEY
        computedSig = hmac.new(key, cookie, hashlib.sha256).digest()
        if sig != computedSig:
            self.killConnection(
                sender, reason='The accounts database rejected your cookie')
            return
        if config.GetString('server-password', ''):
            self.sendUpdateToChannel(sender, 'loginResponse', [True])
            return
        self.sendUpdateToChannel(sender, 'loginResponse', [False])
        self.performLogin(hwId, cookie)

    def authenticateLogin(self, cookie, password, hwId):
        sender = self.air.getMsgSender()
        if password == config.GetString('server-password', ''):
            self.sendUpdateToChannel(sender, 'authenticationResponse', [True])
            self.performLogin(hwId, cookie)
        else:
            self.sendUpdateToChannel(sender, 'authenticationResponse', [False])

    def performLogin(self, hwId, cookie):
        immuneHardwareIds = ['0x5800e36aeac8L']
        sender = self.air.getMsgSender()
        data = simbase.air.banManager.getActiveBans()[0]
        if hwId in data and hwId not in immuneHardwareIds:
            data = data[hwId]
            reason = data['reason']
            simbase.air.writeServerEvent(
                'security',
                issue=
                'Client has attempted to login but their account has been terminated!',
                accId=data['accId'],
                hwId=hwId,
                cookie=cookie,
                reason=reason)
            self.killConnection(connId=sender, code=152, reason=data['reason'])
        if sender in self.connection2fsm:
            self.killConnectionFSM(sender)
            return
        self.connection2fsm[sender] = LoginAccountFSM(self, sender)
        self.connection2fsm[sender].request('Start', cookie)

    def requestAvatars(self):
        self.notify.debug('Received avatar list request from %d' %
                          self.air.getMsgSender())
        self.runAccountFSM(GetAvatarsFSM)

    def createAvatar(self, dna, index, skipTutorial):
        self.runAccountFSM(CreateAvatarFSM, dna, index, skipTutorial)

    def deleteAvatar(self, avId):
        self.runAccountFSM(DeleteAvatarFSM, avId)

    def setNameTyped(self, avId, name):
        self.runAccountFSM(SetNameTypedFSM, avId, name)

    def setNamePattern(self, avId, p1, f1, p2, f2, p3, f3, p4, f4):
        self.runAccountFSM(SetNamePatternFSM, avId, [(p1, f1), (p2, f2),
                                                     (p3, f3), (p4, f4)])

    def acknowledgeAvatarName(self, avId):
        self.runAccountFSM(AcknowledgeNameFSM, avId)

    def chooseAvatar(self, avId):
        currentAvId = self.air.getAvatarIdFromSender()
        accountId = self.air.getAccountIdFromSender()
        if currentAvId and avId:
            self.killAccount(accountId, 'A Toon is already chosen!')
            return
        if not currentAvId and not avId:
            return
        if avId:
            self.runAccountFSM(LoadAvatarFSM, avId)
        else:
            self.runAccountFSM(UnloadAvatarFSM, currentAvId)

    def reportPlayer(self, avId, category):
        reporterId = self.air.getAvatarIdFromSender()
        if len(REPORT_REASONS) <= category:
            self.air.writeServerEvent(
                'suspicious',
                avId=reporterId,
                issue='Invalid report reason index (%d) sent by avatar.' %
                category)
            return
        self.air.writeServerEvent('player-reported',
                                  reporterId=reporterId,
                                  avId=avId,
                                  category=REPORT_REASONS[category])
Beispiel #25
0
class CharSelection(DirectObject):
    notify = directNotify.newCategory('CharSelection')

    STAGE_TOON_POS = (66.4, 74.47, -25)
    STAGE_TOON_HPR = (227.73, 0, 0)

    NO_TOON = "Empty Slot"
    PLAY = "Play"
    CREATE = "Create"
    TITLE = "Pick  A  Toon  To  Play"

    def __init__(self, avChooser):
        self.avChooser = avChooser
        self.choice = None
        self.charList = None
        self.charNameLabel = None
        self.charButtons = []
        self.playOrCreateButton = None
        self.deleteButton = None
        self.quitButton = None
        self.world = None
        self.sky = None
        self.fog = None
        self.title = None
        self.stageToon = None
        self.deleteConf = None
        self.frame = None
        self.selectionFSM = ClassicFSM.ClassicFSM(
            'CharSelection',
            [
                State.State('off', self.enterOff, self.exitOff),
                State.State('character', self.enterCharSelected, self.exitCharSelected),
                State.State('empty', self.enterEmptySelected, self.exitEmptySelected)
            ],
            'off', 'off'
        )
        self.selectionFSM.enterInitialState()

    def __setupStageToon(self):
        self.stageToon = Toon(base.cr)
        self.stageToon.setPos(self.STAGE_TOON_POS)
        self.stageToon.setHpr(self.STAGE_TOON_HPR)

    def cleanupStageToon(self):
        if self.stageToon != None:
            self.stageToon.disable()
            self.stageToon.delete()
            self.stageToon = None

    def enterOff(self):
        pass

    def exitOff(self):
        pass

    def enterCharSelected(self, slot):
        self.choice = self.avChooser.getAvChoiceBySlot(slot)
        dna = self.choice.dna
        name = self.choice.name
        self.stageToon.setName(name)
        self.stageToon.setDNAStrand(dna)
        self.stageToon.nametag.setNametagColor(NametagGlobals.NametagColors[NametagGlobals.CCLocal])
        self.stageToon.nametag.setActive(0)
        self.stageToon.nametag.updateAll()
        self.stageToon.nametag.nametag3d.request('Rollover')
        self.stageToon.animFSM.request('neutral')
        self.stageToon.reparentTo(base.render)
        self.charNameLabel.setText(name)
        self.playOrCreateButton['text'] = self.PLAY
        self.playOrCreateButton['extraArgs'] = ['play']
        self.playOrCreateButton.show()
        self.deleteButton.show()

    def exitCharSelected(self):
        self.stageToon.animFSM.requestFinalState()
        self.stageToon.deleteCurrentToon()
        self.stageToon.reparentTo(base.hidden)
        self.playOrCreateButton.hide()
        self.deleteButton.hide()
        self.choice = None

    def enterEmptySelected(self):
        self.charNameLabel.setText(self.NO_TOON)
        self.playOrCreateButton['text'] = self.CREATE
        self.playOrCreateButton['extraArgs'] = ['create']
        self.playOrCreateButton.show()

    def exitEmptySelected(self):
        self.playOrCreateButton.hide()

    def __action(self, action):
        for btn in self.charButtons:
            if btn['state'] == DGG.DISABLED:
                self.slot = btn.getPythonTag('slot')
                break
        func = None
        arg = None
        doFade = True
        if action == 'delete':
            func = self.deleteToon
            arg = self.choice.avId
            doFade = False
        elif action == 'play':
            func = self.playGame
            arg = self.choice.slot
        elif action == 'create':
            func = self.enterMAT
        elif action == 'quit':
            func = sys.exit
        if doFade:
            base.transitions.fadeOut(0.3)
            if arg != None:
                Sequence(Wait(0.31), Func(func, arg)).start()
            else:
                Sequence(Wait(0.31), Func(func)).start()
        else:
            if arg != None:
                func(arg)
            else:
                func()

    def playGame(self, slot):
        messenger.send("avChooseDone", [self.avChooser.getAvChoiceBySlot(slot)])

    def enterMAT(self):
        messenger.send("enterMakeAToon", [self.slot])

    def deleteToon(self, avId):
        # Show a confirmation message
        self.deleteConf = Dialog.GlobalDialog(
            message = 'This will delete {0} forever. Are you sure?'.format(self.avChooser.getNameFromAvId(avId)),
            style = Dialog.YesNo, doneEvent = 'deleteConfResponse', extraArgs = [avId])
        self.acceptOnce('deleteConfResponse', self.__handleDeleteConfResponse)
        self.deleteConf.show()

    def __handleDeleteConfResponse(self, avId):
        doneStatus = self.deleteConf.getValue()
        if doneStatus:
            # Alright, they pressed yes. No complaining to us.
            self.avChooser.avChooseFSM.request("waitForToonDelResponse", [avId])
        else:
            self.deleteConf.cleanup()
            self.deleteConf = None

    def __handleCharButton(self, slot):
        for btn in self.charButtons:
            if btn.getPythonTag('slot') == slot:
                btn['state'] = DGG.DISABLED
            else:
                btn['state'] = DGG.NORMAL
        if self.avChooser.hasToonInSlot(slot):
            self.selectionFSM.request('character', [slot])
        else:
            self.selectionFSM.request('empty')

    def load(self):
        base.cr.renderFrame()
        base.camLens.setMinFov(CIGlobals.DefaultCameraFov / (4./3.))

        self.__setupStageToon()
        holidayMgr = base.cr.holidayManager

        self.props = []
        self.world = loader.loadModel('phase_9/models/cogHQ/SellbotHQExterior.bam')
        self.world.reparentTo(base.render)
        self.world.setPos(0, 227.09, -25.36)
        self.sky = loader.loadModel('phase_9/models/cogHQ/cog_sky.bam')
        self.sky.setScale(1)
        self.sky.reparentTo(base.render)
        self.sky.find('**/InnerGroup').removeNode()
        self.fog = Fog('charSelectFog')
        self.fog.setColor(0.2, 0.2, 0.2)
        self.fog.setExpDensity(0.003)
        base.render.setFog(self.fog)
        
        # Let's fix the flickering doors.
        doors = self.world.find('**/doors').getChildren()
        
        for door in doors:
            for frameHole in door.findAllMatches('**/doorFrameHole*'): frameHole.removeNode()

        if holidayMgr.getHoliday() == HolidayType.CHRISTMAS:
            piles = {
                'half' : {'pos' : (57.28, 86.47, -25.00), 'hpr' : (46.79, 0, 0)},
                'full' : {'pos' : (71.23, 85.2, -25.00), 'hpr' : (290.82, 0, 0)},
                'half_2' : {'pos' : (-15, 128.69, -25), 'hpr' : (60.26, 0, 0)}
            }

            for pileType, info in piles.items():
                if '_' in pileType:
                    pileType = pileType[:-2]
                pile = loader.loadModel('phase_8/models/props/snow_pile_%s.bam' % (pileType))
                pile.reparentTo(render)
                pile.setPos(info['pos'])
                pile.setHpr(info['hpr'])
                self.props.append(pile)

            self.world.find('**/TopRocks').removeNode()

            snowTxt = loader.loadTexture('winter/maps/sbhq_snow.png')
            self.world.find('**/Ground').setTexture(snowTxt, 1)

            self.particles = ParticleLoader.loadParticleEffect('phase_8/etc/snowdisk.ptf')
            self.particles.setPos(0, 0, 5)
            self.particlesRender = self.world.attachNewNode('snowRender')
            self.particlesRender.setDepthWrite(0)
            self.particlesRender.setBin('fixed', 1)
            self.particles.start(parent = camera, renderParent = self.particlesRender)
            self.fog.setColor(0.486, 0.784, 1)
            self.fog.setExpDensity(0.006)
            base.render.setFog(self.fog)


        self.title = DirectLabel(text=self.TITLE, text_font=CIGlobals.getMickeyFont(), text_fg=(1, 0.9, 0.1, 1),
                                relief=None, text_scale=0.13, pos=(0, 0, 0.82))
        self.charNameLabel = OnscreenText(text = "", font = CIGlobals.getMickeyFont(),
                                        pos = (-0.25, 0.5, 0), fg = (1, 0.9, 0.1, 1.0))
        self.charNameLabel.hide()
        self.frame = DirectFrame()
        self.frame['image'] = DGG.getDefaultDialogGeom()
        self.frame['image_color'] = CIGlobals.DialogColor
        self.frame['image_scale'] = (-0.9, -0.9, 0.8)
        self.frame['image_pos'] = (0.82, 0, -0.125)
        self.playOrCreateButton = DirectButton(text = "", pos = (0.8125, 0, -0.35), command = self.__action,
                                            geom = CIGlobals.getDefaultBtnGeom(), text_scale = 0.06,
                                            relief = None, text_pos = (0, -0.01))
        self.playOrCreateButton.hide()
        self.deleteButton = DirectButton(text = "Delete", pos = (0.8125, 0, -0.45),
                                        command = self.__action, extraArgs = ['delete'],
                                        geom = CIGlobals.getDefaultBtnGeom(), text_scale = 0.06,
                                        relief = None, text_pos = (0, -0.01))
        self.deleteButton.hide()
        self.quitButton = DirectButton(text = "Quit", pos = (-1.10, 0, -0.925), command = self.__action,
                                    extraArgs = ['quit'], text_scale = 0.06, geom = CIGlobals.getDefaultBtnGeom(),
                                    relief = None, text_pos = (0, -0.01))

        textRolloverColor = Vec4(1, 1, 0, 1)
        textDownColor = Vec4(0.5, 0.9, 1, 1)
        textDisabledColor = Vec4(0.4, 0.8, 0.4, 1)

        for slot in range(6):
            if self.avChooser.hasToonInSlot(slot):
                choice = self.avChooser.getAvChoiceBySlot(slot)
                text = choice.name
            else:
                text = self.NO_TOON
            btn = DirectButton(
                relief=None, text = text, text_scale=0.06,
                text_align=TextNode.ALeft, text1_bg=textDownColor, text2_bg=textRolloverColor,
                text3_fg=textDisabledColor, textMayChange=0, command=self.__handleCharButton,
                extraArgs=[slot], text_pos = (0, 0, 0.0)
            )
            btn.setPythonTag('slot', slot)
            self.charButtons.append(btn)
            btn['state'] = DGG.NORMAL

        gui = loader.loadModel('phase_3.5/models/gui/friendslist_gui.bam')
        listXorigin = -0.02
        listFrameSizeX = 0.625
        listZorigin = -0.43
        listFrameSizeZ = 0.51
        arrowButtonScale = 0.0
        itemFrameXorigin = -0.237
        itemFrameZorigin = 0.365
        buttonXstart = itemFrameXorigin + 0.293

        self.charList = DirectScrolledList(
            relief=None,
            pos=(0.75, 0, -0.225),
            incButton_image=None,
            #incButton_relief=None,
            incButton_scale=(arrowButtonScale, arrowButtonScale, -arrowButtonScale),
            #incButton_pos=(buttonXstart, 0, itemFrameZorigin - 0.999),
            #incButton_image3_color=Vec4(1, 1, 1, 0.2),
            decButton_image=None,
            #decButton_relief=None,
            decButton_scale=(arrowButtonScale, arrowButtonScale, arrowButtonScale),
            #decButton_pos=(buttonXstart, 0, itemFrameZorigin + 0.125),
            #decButton_image3_color=Vec4(1, 1, 1, 0.2),
            itemFrame_pos=(itemFrameXorigin, 0, itemFrameZorigin),
            itemFrame_scale=1.0,
            itemFrame_relief=DGG.SUNKEN,
            itemFrame_frameSize=(listXorigin,
                listXorigin + listFrameSizeX,
                listZorigin,
                listZorigin + listFrameSizeZ),
            itemFrame_frameColor=(0.85, 0.95, 1, 1),
            itemFrame_borderWidth=(0.01, 0.01),
            numItemsVisible=15,
            forceHeight=0.075,
            items=self.charButtons,
            parent = self.frame
        )

        base.camera.setPos(75.12, 63.22, -23)
        base.camera.setHpr(26.57, 9.62, 0)

    def unload(self):
        self.selectionFSM.requestFinalState()
        self.cleanupStageToon()
        self.choice = None
        if self.frame:
            self.frame.destroy()
            self.frame = None
        if self.charButtons:
            for btn in self.charButtons:
                btn.destroy()
            self.charButtons = None
        if self.deleteConf:
            self.deleteConf.cleanup()
            self.deleteConf = None
        if self.charList:
            self.charList.destroy()
            self.charList = None
        if self.charNameLabel:
            self.charNameLabel.destroy()
            self.charNameLabel = None
        if self.playOrCreateButton:
            self.playOrCreateButton.destroy()
            self.playOrCreateButton = None
        if self.deleteButton:
            self.deleteButton.destroy()
            self.deleteButton = None
        if self.quitButton:
            self.quitButton.destroy()
            self.quitButton = None
        if self.sky:
            self.sky.removeNode()
            self.sky = None
        if self.world:
            self.world.removeNode()
            self.world = None
        if self.title:
            self.title.destroy()
            self.title = None
        for prop in self.props:
            if not prop.isEmpty():
                prop.removeNode()
        self.props = None
        if hasattr(self, 'particles'):
            self.particles.cleanup()
            self.particlesRender.removeNode()
            self.particles = None
            del self.particlesRender
        base.render.clearFog()
        self.fog = None
        base.camera.setPos(0, 0, 0)
        base.camera.setHpr(0, 0, 0)
        base.transitions.noTransitions()
        del self.selectionFSM
Beispiel #26
0
class Interval(DirectObject):
    """Interval class: Base class for timeline functionality"""

    # create Interval DirectNotify category
    notify = directNotify.newCategory("Interval")

    playbackCounter = 0

    # Class methods
    def __init__(self, name, duration, openEnded=1):
        self.name = name
        self.duration = max(duration, 0.0)
        self.state = CInterval.SInitial
        self.currT = 0.0
        self.doneEvent = None
        self.setTHooks = []
        self.__startT = 0
        self.__startTAtStart = 1
        self.__endT = duration
        self.__endTAtEnd = 1
        self.__playRate = 1.0
        self.__doLoop = 0
        self.__loopCount = 0

        self.pstats = None
        if __debug__ and TaskManager.taskTimerVerbose:
            self.pname = name.split('-', 1)[0]
            self.pstats = PStatCollector("App:Show code:ivalLoop:%s" %
                                         (self.pname))

        # Set true if the interval should be invoked if it was
        # completely skipped over during initialize or finalize, false
        # if it should be ignored in this case.
        self.openEnded = openEnded

    def getName(self):
        return self.name

    def getDuration(self):
        return self.duration

    def getOpenEnded(self):
        return self.openEnded

    def setLoop(self, loop=1):
        self.__doLoop = loop

    def getLoop(self):
        return self.__doLoop

    def getState(self):
        return self.state

    def isPaused(self):
        return self.getState() == CInterval.SPaused

    def isStopped(self):
        # Returns true if the interval has not been started, has already
        # played to its completion, or has been explicitly stopped via
        # finish().
        return (self.getState() == CInterval.SInitial or \
                self.getState() == CInterval.SFinal)

    def setT(self, t):
        # There doesn't seem to be any reason to clamp this, and it
        # breaks looping intervals.  The interval code should properly
        # handle t values outside the proper range.
        #t = min(max(t, 0.0), self.getDuration())

        state = self.getState()
        if state == CInterval.SInitial:
            self.privInitialize(t)
            if self.isPlaying():
                self.setupResume()
            else:
                self.privInterrupt()
        elif state == CInterval.SStarted:
            # Support modifying t while the interval is playing.  We
            # assume is_playing() will be true in this state.
            assert self.isPlaying()
            self.privInterrupt()
            self.privStep(t)
            self.setupResume()
        elif state == CInterval.SPaused:
            # Support modifying t while the interval is paused.  In
            # this case, we simply step to the new value of t; but
            # this will change the state to S_started, so we must then
            # change it back to S_paused by hand (because we're still
            # paused).
            self.privStep(t)
            self.privInterrupt()
        elif state == CInterval.SFinal:
            self.privReverseInitialize(t)
            if self.isPlaying():
                self.setupResume()
            else:
                self.privInterrupt()
        else:
            self.notify.error("Invalid state: %s" % (state))
        self.privPostEvent()

    def getT(self):
        return self.currT

    def start(self, startT=0.0, endT=-1.0, playRate=1.0):
        self.setupPlay(startT, endT, playRate, 0)
        self.__spawnTask()

    def loop(self, startT=0.0, endT=-1.0, playRate=1.0):
        self.setupPlay(startT, endT, playRate, 1)
        self.__spawnTask()

    def pause(self):
        if self.getState() == CInterval.SStarted:
            self.privInterrupt()
        self.privPostEvent()
        self.__removeTask()
        return self.getT()

    def resume(self, startT=None):
        if startT != None:
            self.setT(startT)
        self.setupResume()
        if not self.isPlaying():
            self.__spawnTask()

    def resumeUntil(self, endT):
        duration = self.getDuration()

        if endT < 0 or endT >= duration:
            self.__endT = duration
            self.__endTAtEnd = 1
        else:
            self.__endT = endT
            self.__endTAtEnd = 0

        self.setupResume()
        if not self.isPlaying():
            self.__spawnTask()

    def finish(self):
        state = self.getState()
        if state == CInterval.SInitial:
            self.privInstant()
        elif state != CInterval.SFinal:
            self.privFinalize()
        self.privPostEvent()
        self.__removeTask()

    def clearToInitial(self):
        # This method resets the interval's internal state to the
        # initial state, abandoning any parts of the interval that
        # have not yet been called.  Calling it is like pausing the
        # interval and creating a new one in its place.
        self.pause()
        self.state = CInterval.SInitial
        self.currT = 0.0

    def isPlaying(self):
        return taskMgr.hasTaskNamed(self.getName() + '-play')

    def getPlayRate(self):
        """ Returns the play rate as set by the last call to start(),
        loop(), or setPlayRate(). """
        return self.__playRate

    def setPlayRate(self, playRate):
        """ Changes the play rate of the interval.  If the interval is
        already started, this changes its speed on-the-fly.  Note that
        since playRate is a parameter to start() and loop(), the next
        call to start() or loop() will reset this parameter. """

        if self.isPlaying():
            self.pause()
            self.__playRate = playRate
            self.resume()
        else:
            self.__playRate = playRate

    def setDoneEvent(self, event):
        self.doneEvent = event

    def getDoneEvent(self):
        return self.doneEvent

    def privDoEvent(self, t, event):
        if self.pstats:
            self.pstats.start()
        if event == CInterval.ETStep:
            self.privStep(t)
        elif event == CInterval.ETFinalize:
            self.privFinalize()
        elif event == CInterval.ETInterrupt:
            self.privInterrupt()
        elif event == CInterval.ETInstant:
            self.privInstant()
        elif event == CInterval.ETInitialize:
            self.privInitialize(t)
        elif event == CInterval.ETReverseFinalize:
            self.privReverseFinalize()
        elif event == CInterval.ETReverseInstant:
            self.privReverseInstant()
        elif event == CInterval.ETReverseInitialize:
            self.privReverseInitialize(t)
        else:
            self.notify.error('Invalid event type: %s' % (event))
        if self.pstats:
            self.pstats.stop()

    def privInitialize(self, t):
        # Subclasses may redefine this function
        self.state = CInterval.SStarted
        self.privStep(t)

    def privInstant(self):
        # Subclasses may redefine this function
        self.state = CInterval.SStarted
        self.privStep(self.getDuration())
        self.state = CInterval.SFinal
        self.intervalDone()

    def privStep(self, t):
        # Subclasses may redefine this function
        self.state = CInterval.SStarted
        self.currT = t

    def privFinalize(self):
        # Subclasses may redefine this function
        self.privStep(self.getDuration())
        self.state = CInterval.SFinal
        self.intervalDone()

    def privReverseInitialize(self, t):
        # Subclasses may redefine this function
        self.state = CInterval.SStarted
        self.privStep(t)

    def privReverseInstant(self):
        # Subclasses may redefine this function
        self.state = CInterval.SStarted
        self.privStep(0)
        self.state = CInterval.SInitial

    def privReverseFinalize(self):
        # Subclasses may redefine this function
        self.privStep(0)
        self.state = CInterval.SInitial

    def privInterrupt(self):
        # Subclasses may redefine this function
        self.state = CInterval.SPaused

    def intervalDone(self):
        # Subclasses should call this when the interval transitions to
        # its final state.
        if self.doneEvent:
            messenger.send(self.doneEvent)

    def setupPlay(self, startT, endT, playRate, doLoop):
        duration = self.getDuration()

        if startT <= 0:
            self.__startT = 0
            self.__startTAtStart = 1
        elif startT > duration:
            self.__startT = duration
            self.__startTAtStart = 0
        else:
            self.__startT = startT
            self.__startTAtStart = 0

        if endT < 0 or endT >= duration:
            self.__endT = duration
            self.__endTAtEnd = 1
        else:
            self.__endT = endT
            self.__endTAtEnd = 0

        self.__clockStart = ClockObject.getGlobalClock().getFrameTime()
        self.__playRate = playRate
        self.__doLoop = doLoop
        self.__loopCount = 0

    def setupResume(self):
        now = ClockObject.getGlobalClock().getFrameTime()
        if self.__playRate > 0:
            self.__clockStart = now - (
                (self.getT() - self.__startT) / self.__playRate)
        elif self.__playRate < 0:
            self.__clockStart = now - (
                (self.getT() - self.__endT) / self.__playRate)
        self.__loopCount = 0

    def stepPlay(self):
        now = ClockObject.getGlobalClock().getFrameTime()
        if self.__playRate >= 0:
            t = (now - self.__clockStart) * self.__playRate + self.__startT

            if self.__endTAtEnd:
                self.__endT = self.getDuration()

            if t < self.__endT:
                # In the middle of the interval, not a problem.
                if self.isStopped():
                    self.privInitialize(t)
                else:
                    self.privStep(t)

            else:
                # Past the ending point; time to finalize.
                if self.__endTAtEnd:
                    # Only finalize if the playback cycle includes the
                    # whole interval.
                    if self.isStopped():
                        if self.getOpenEnded() or self.__loopCount != 0:
                            self.privInstant()
                    else:
                        self.privFinalize()
                else:
                    if self.isStopped():
                        self.privInitialize(self.__endT)
                    else:
                        self.privStep(self.__endT)

                # Advance the clock for the next loop cycle.
                if self.__endT == self.__startT:
                    # If the interval has no length, we loop exactly once.
                    self.__loopCount += 1

                else:
                    # Otherwise, figure out how many loops we need to
                    # skip.
                    timePerLoop = (self.__endT -
                                   self.__startT) / self.__playRate
                    numLoops = math.floor(
                        (now - self.__clockStart) / timePerLoop)
                    self.__loopCount += numLoops
                    self.__clockStart += numLoops * timePerLoop

        else:
            # Playing backwards
            t = (now - self.__clockStart) * self.__playRate + self.__endT

            if t >= self.__startT:
                # In the middle of the interval, not a problem.
                if self.isStopped():
                    self.privInitialize(t)
                else:
                    self.privStep(t)
            else:
                # Past the ending point; time to finalize.
                if self.__startTAtStart:
                    # Only finalize if the playback cycle includes the
                    # whole interval.
                    if self.isStopped():
                        if self.getOpenEnded() or self.__loopCount != 0:
                            self.privReverseInstant()
                    else:
                        self.privReverseFinalize()
                else:
                    if self.isStopped():
                        self.privReverseInitialize(self.__startT)
                    else:
                        self.privStep(self.__startT)

                # Advance the clock for the next loop cycle.
                if self.__endT == self.__startT:
                    # If the interval has no length, we loop exactly once.
                    self.__loopCount += 1

                else:
                    # Otherwise, figure out how many loops we need to
                    # skip.
                    timePerLoop = (self.__endT -
                                   self.__startT) / -self.__playRate
                    numLoops = math.floor(
                        (now - self.__clockStart) / timePerLoop)
                    self.__loopCount += numLoops
                    self.__clockStart += numLoops * timePerLoop

        shouldContinue = (self.__loopCount == 0 or self.__doLoop)

        if (not shouldContinue and self.getState() == CInterval.SStarted):
            self.privInterrupt()

        return shouldContinue

    def __repr__(self, indent=0):
        space = ''
        for l in range(indent):
            space = space + ' '
        return (space + self.name + ' dur: %.2f' % self.duration)

    open_ended = property(getOpenEnded)
    stopped = property(isStopped)
    t = property(getT, setT)
    play_rate = property(getPlayRate, setPlayRate)
    done_event = property(getDoneEvent, setDoneEvent)

    # The rest of these methods are duplicates of functions defined
    # for the CInterval class via the file CInterval-extensions.py.

    def privPostEvent(self):
        # Call after calling any of the priv* methods to do any required
        # Python finishing steps.
        if self.pstats:
            self.pstats.start()
        t = self.getT()
        if hasattr(self, "setTHooks"):
            for func in self.setTHooks:
                func(t)
        if self.pstats:
            self.pstats.stop()

    def __spawnTask(self):
        # Spawn task
        self.__removeTask()
        taskName = self.getName() + '-play'
        task = Task(self.__playTask)
        task.interval = self
        taskMgr.add(task, taskName)

    def __removeTask(self):
        # Kill old task(s), including those from a similarly-named but
        # different interval.
        taskName = self.getName() + '-play'
        oldTasks = taskMgr.getTasksNamed(taskName)
        for task in oldTasks:
            if hasattr(task, "interval"):
                task.interval.privInterrupt()
                taskMgr.remove(task)

    def __playTask(self, task):
        again = self.stepPlay()
        self.privPostEvent()
        if again:
            return Task.cont
        else:
            return Task.done

    def popupControls(self, tl=None):
        """
        Popup control panel for interval.
        """
        # Don't use a regular import, to prevent ModuleFinder from picking
        # it up as a dependency when building a .p3d package.
        import importlib, sys
        if sys.version_info >= (3, 0):
            tkinter = importlib.import_module('tkinter')
        else:
            tkinter = importlib.import_module('Tkinter')

        if tl == None:
            tl = tkinter.Toplevel()
            tl.title('Interval Controls')
        outerFrame = tkinter.Frame(tl)

        def entryScaleCommand(t, s=self):
            s.setT(t)
            s.pause()

        self.es = es = EntryScale.EntryScale(
            outerFrame,
            text=self.getName(),
            min=0,
            max=math.floor(self.getDuration() * 100) / 100,
            command=entryScaleCommand)
        es.set(self.getT(), fCommand=0)
        es.pack(expand=1, fill=tkinter.X)
        bf = tkinter.Frame(outerFrame)

        # Jump to start and end
        def toStart(s=self, es=es):
            s.clearToInitial()
            es.set(0, fCommand=0)

        def toEnd(s=self):
            s.pause()
            s.setT(s.getDuration())
            es.set(s.getDuration(), fCommand=0)
            s.pause()

        jumpToStart = tkinter.Button(bf, text='<<', command=toStart)

        # Stop/play buttons
        def doPlay(s=self, es=es):
            s.resume(es.get())

        stop = tkinter.Button(bf,
                              text='Stop',
                              command=lambda s=self: s.pause())
        play = tkinter.Button(bf, text='Play', command=doPlay)
        jumpToEnd = tkinter.Button(bf, text='>>', command=toEnd)
        jumpToStart.pack(side=tkinter.LEFT, expand=1, fill=tkinter.X)
        play.pack(side=tkinter.LEFT, expand=1, fill=tkinter.X)
        stop.pack(side=tkinter.LEFT, expand=1, fill=tkinter.X)
        jumpToEnd.pack(side=tkinter.LEFT, expand=1, fill=tkinter.X)
        bf.pack(expand=1, fill=tkinter.X)
        outerFrame.pack(expand=1, fill=tkinter.X)

        # Add function to update slider during setT calls
        def update(t, es=es):
            es.set(t, fCommand=0)

        if not hasattr(self, "setTHooks"):
            self.setTHooks = []
        self.setTHooks.append(update)

        # Clear out function on destroy
        def onDestroy(e, s=self, u=update):
            if u in s.setTHooks:
                s.setTHooks.remove(u)

        tl.bind('<Destroy>', onDestroy)
Beispiel #27
0
class AssetBrowser(QtWidgets.QDialog):

    FileExtensions = []
    PreloadItems = True

    notify = directNotify.newCategory("AssetBrowser")
    notify.setDebug(True)

    def __init__(self, parent):
        QtWidgets.QDialog.__init__(self, parent)
        self.ui = Ui_AssetBrowser()
        self.ui.setupUi(self)
        self.setModal(True)
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose, False)

        self.callback = None

        self.firstTime = True

        self.recentlyUsed = []

        self.currentFolder = None
        self.selectedAsset = None
        self.modelTrees = []

        self.folderContext = None
        self.recentlyUsedContext = None

        self.ui.folderView.itemSelectionChanged.connect(
            self.__handleFolderSelectionChanged)
        self.ui.fileView.itemDoubleClicked.connect(self.__confirmAsset)
        self.ui.fileView.itemSelectionChanged.connect(self.__selectAsset)
        self.ui.recentView.itemDoubleClicked.connect(self.__confirmAsset)
        self.ui.recentView.itemSelectionChanged.connect(
            self.__selectRecentAsset)
        self.ui.leFileFilter.textChanged.connect(self.__filterList)

    def show(self, parent, callback):
        self.callback = callback
        #self.setParent(parent)
        self.setModal(True)
        QtWidgets.QDialog.show(self)
        if self.firstTime:
            self.firstTime = False
            self.initialize()
        else:
            self.generateRecentlyUsedAssets()
            if self.folderContext:
                self.folderContext.resume()

    def initialize(self):
        assert self.notify.debug("Initializing asset browser")

        # Find all of the models in the tree
        self.generateAssetTree()
        # Then create a widget for each folder that contains models
        self.generateFolderWidgetTree()

        # Generate the recently used items
        self.generateRecentlyUsedAssets()
        self.ui.folderView.setCurrentItem(self.modelTrees[0].rootFolder.item)

    def generateRecentlyUsedAssets(self):
        if self.recentlyUsedContext:
            self.recentlyUsedContext.cleanup()

        self.ui.recentView.clear()

        ctx = AssetCreationContext(self, list(self.recentlyUsed),
                                   self.ui.recentView, False)
        ctx.createAssets()
        self.recentlyUsedContext = ctx

    def __selectAsset(self):
        items = self.ui.fileView.selectedItems()
        if len(items) > 0:
            item = items[0]
            self.selectedAsset = item.filename
            self.ui.recentView.setCurrentItem(None)

    def __selectRecentAsset(self):
        items = self.ui.recentView.selectedItems()
        if len(items) > 0:
            item = items[0]
            self.selectedAsset = item.filename
            self.ui.fileView.setCurrentItem(None)

    def __confirmAsset(self, item):
        # User double clicked a model, confirm selection and close dialog
        self.selectedAsset = item.filename
        self.hide(1)

    def __filterList(self, text):
        text = text.lower()

        for i in range(self.ui.fileView.count()):
            self.ui.fileView.setRowHidden(i, False)

        if len(text) == 0:
            return

        for i in range(self.ui.fileView.count()):
            if text not in self.ui.fileView.item(i).text().lower():
                self.ui.fileView.setRowHidden(i, True)

    def filterFileList(self):
        self.__filterList(self.ui.leFileFilter.text())

    def __handleFolderSelectionChanged(self):
        item = self.ui.folderView.selectedItems()[0]
        self.currentFolder = item.assetFolder
        self.generateAssets()

    def generateFolderWidgetTree(self):
        self.ui.folderView.clear()

        for tree in self.modelTrees:
            self.r_generateFolderWidgetTree(tree.rootFolder, None)

        self.ui.folderView.expandToDepth(0)

    def r_generateFolderWidgetTree(self, folder, parent):
        item = AssetFolderWidgetItem()
        item.assetFolder = folder
        folder.item = item
        if folder.parentRelativeFilename:
            item.setText(0, folder.parentRelativeFilename.getFullpath())
        elif folder.alias:
            item.setText(0, folder.alias)
        else:
            item.setText(0, folder.filename.getFullpath())
        item.setToolTip(0, item.text(0))
        if parent:
            parent.addChild(item)
        else:
            self.ui.folderView.addTopLevelItem(item)

        for child in folder.children:
            self.r_generateFolderWidgetTree(child, item)

    def r_generateAssets(self, tree, dirFilename, parentModelFolder):
        vfs = core.VirtualFileSystem.getGlobalPtr()
        contents = vfs.scanDirectory(dirFilename)
        gotHit = False
        subfolders = []
        assetFiles = []
        for virtualFile in contents.getFiles():
            filename = virtualFile.getFilename()
            if virtualFile.isDirectory():
                subfolders.append(filename)
            elif filename.getExtension() in self.FileExtensions:
                assert self.notify.debug("Found asset " +
                                         filename.getFullpath())
                filename.makeRelativeTo(tree.absRoot)
                assert self.notify.debug("Rel path: " + filename.getFullpath())
                assetFiles.append(filename)
                gotHit = True

        thisFolder = AssetFolder(dirFilename, parentModelFolder)
        thisFolder.assetFiles = assetFiles

        gotChildHits = False
        for sub in subfolders:
            _, ret = self.r_generateAssets(tree, sub, thisFolder)
            if not gotChildHits:
                gotChildHits = ret

        if parentModelFolder and (gotChildHits or gotHit):
            parentModelFolder.children.append(thisFolder)

        return [thisFolder, gotHit or gotChildHits]

    def r_createFilesList(self, folder):
        self.files += folder.assetFiles
        for child in folder.children:
            self.r_createFilesList(child)

    def generateAssetTree(self):
        # Generate an asset tree for each tree we're attached to ending in
        # MODELS.

        self.modelTrees = []

        ctprojs = os.environ.get("CTPROJS")
        if not ctprojs:
            return

        projs = ctprojs.split("+")
        for proj_data in projs:
            name, flavor = proj_data.split(":")
            if not name.endswith("MODELS"):
                # Not a model tree.
                continue

            path = os.environ.get(name.upper())
            rootFilename = core.Filename.fromOsSpecific(path) + "/built"
            assert self.notify.debug("Generating asset tree for " + name +
                                     " (" + rootFilename.getFullpath() + ")")
            tree = ModelTree("$" + name.upper(), rootFilename)
            tree.rootFolder = self.r_generateAssets(tree, rootFilename,
                                                    None)[0]
            tree.rootFolder.alias = tree.name
            self.modelTrees.append(tree)

    def generateAssets(self):
        if self.folderContext:
            self.folderContext.cleanup()

        self.ui.fileView.clear()
        self.files = []
        self.r_createFilesList(self.currentFolder)
        self.files.sort()

        # Generate the assets thumbnails in the selected folder
        ctx = AssetCreationContext(self, self.files, self.ui.fileView, True)
        ctx.createAssets()
        self.folderContext = ctx

    def hide(self, ret):
        self.setParent(None)
        if self.folderContext:
            if not self.folderContext.done:
                self.folderContext.pause()
            else:
                self.folderContext.cleanup()
                self.folderContext = None
        if self.recentlyUsedContext:
            self.recentlyUsedContext.cleanup()
            self.recentlyUsedContext = None
        if ret and self.selectedAsset:
            fullpath = self.selectedAsset.getFullpath()
            if not fullpath in self.recentlyUsed:
                self.recentlyUsed.insert(0, fullpath)
            else:
                # If the asset is already in the recently-used list,
                # bring it to the front.
                self.recentlyUsed.insert(
                    0,
                    self.recentlyUsed.pop(self.recentlyUsed.index(fullpath)))
        if self.callback:
            self.callback(ret, self.selectedAsset)
            self.callback = None

        QtWidgets.QDialog.hide(self)

    def done(self, ret):
        self.hide(ret)
Beispiel #28
0
class DistributedPieTurretManager(DistributedObject):
    notify = directNotify.newCategory('DistributedPieTurretManager')

    def __init__(self, cr):
        DistributedObject.__init__(self, cr)
        self.myTurret = None
        self.guiFrame = None
        self.guiLabel = None
        self.guiBar = None
        self.guiBg = None
        self.turretGag = None

    def announceGenerate(self):
        DistributedObject.announceGenerate(self)
        base.taskMgr.add(self.__pollMyBattle, '__pollMyBattle')

    def disable(self):
        base.taskMgr.remove("DPTM.pollTurret")
        base.taskMgr.remove("__pollMyBattle")
        if hasattr(self, 'makeTurretBtn'):
            self.makeTurretBtn.destroy()
            del self.makeTurretBtn
        self.destroyGui()
        self.myTurret = None
        if base.localAvatar.getBattleZone():
            base.localAvatar.getBattleZone().setTurretManager(None)
        DistributedObject.disable(self)
        
    def clearTurret(self):
        self.turret = None

    def __pollTurret(self, turretId, task):
        turret = self.cr.doId2do.get(turretId)
        if turret != None:
            self.myTurret = turret
            self.myTurret.b_setGag(self.turretGag)
            self.turretGag = None
            self.acceptOnce(turret.getDeathEvent(), self.clearTurret)
            self.makeGui()
            return Task.done
        return Task.cont
    
    def setGag(self, upgradeId):
        self.turretGag = upgradeId

    def d_requestPlace(self, posHpr):
        self.sendUpdate('requestPlace', [posHpr])

    def turretPlaced(self, turretId):
        base.taskMgr.add(self.__pollTurret, 'DPTM.pollTurret', extraArgs = [turretId], appendTask = True)

    def yourTurretIsDead(self):
        base.taskMgr.remove('DPTM.pollTurret')
        self.destroyGui()
        self.myTurret = None
        if base.localAvatar.getPUInventory()[0] > 0:
            self.createTurretButton()

    def makeGui(self):
        self.destroyGui()
        self.guiFrame = DirectFrame(parent = base.a2dBottomRight, pos=(-0.55, 0, 0.15))
        self.guiBg = OnscreenImage(image = "phase_4/maps/turret_gui_bg.png", scale = (0.15, 0, 0.075), parent = self.guiFrame)
        self.guiBg.setTransparency(True)
        self.guiLabel = DirectLabel(text = "Turret", text_fg = (1, 0, 0, 1), relief = None, text_scale = 0.05, text_font = loader.loadFont("phase_3/models/fonts/ImpressBT.ttf"), pos = (0, 0, 0.025), parent = self.guiFrame)
        self.guiBar = DirectWaitBar(range = self.myTurret.getMaxHealth(), value = self.myTurret.getHealth(), scale = 0.125, parent = self.guiFrame, pos = (0, 0, -0.01))

    def createTurretButton(self):
        self.makeTurretBtn = DirectButton(
            relief = None,
            geom = CIGlobals.getDefaultBtnGeom(),
            text = 'Turret',
            text_scale = 0.055,
            command = self.handleMakeTurretBtn,
            pos = (-0.47, 0, 0.1),
            geom_scale = (0.5, 1.0, 1.0),
            text_pos = (0, -0.01),
            parent = base.a2dBottomRight
        )
        
        if base.localAvatar.getPUInventory()[0]:
            self.setGag(base.localAvatar.getPUInventory()[1])

    def handleMakeTurretBtn(self):
        self.makeTurretBtn.destroy()
        del self.makeTurretBtn
        x, y, z = base.localAvatar.getPos()
        h, p, r = base.localAvatar.getHpr()
        self.d_requestPlace([x, y, z, h, p, r])
        base.localAvatar.sendUpdate('usedPU', [0])

    def __pollMyBattle(self, task):
        if base.localAvatar.getBattleZone():
            base.localAvatar.getBattleZone().setTurretManager(self)
            if base.localAvatar.getPUInventory()[0] > 0:
                self.createTurretButton()
            return Task.done
        return Task.cont

    def destroyGui(self):
        if self.guiBar:
            self.guiBar.destroy()
            self.guiBar = None
        if self.guiLabel:
            self.guiLabel.destroy()
            self.guiLabel = None
        if self.guiBg:
            self.guiBg.destroy()
            self.guiBg = None
        if self.guiFrame:
            self.guiFrame.destroy()
            self.guiFrame = None

    def updateTurretGui(self):
        if self.guiBar:
            self.guiBar.update(self.myTurret.getHealth())
            
    def getTurret(self):
        return self.myTurret
class FriendsManagerUD(DistributedObjectGlobalUD):
    notify = directNotify.newCategory("FriendsManagerUD")

    def __init__(self, air):
        DistributedObjectGlobalUD.__init__(self, air)
        self.toonsOnline = []
        self.air.netMessenger.accept('avatarOnline', self, self.toonOnline)
        self.air.netMessenger.accept('avatarOffline', self, self.toonOffline)

    def sendWhisper(self, target, message):
        sender = self.air.getAvatarIdFromSender()

        def senderAvatarResponse(dclass, fields):
            if dclass != self.air.dclassesByName['DistributedPlayerToonUD']:
                return
            name = fields['setName'][0]
            self.sendUpdateToAvatarId(target, 'whisper',
                                      [sender, message, name])

        self.air.dbInterface.queryObject(self.air.dbId, sender,
                                         senderAvatarResponse)

    def requestFriendsList(self, sender=None):
        if sender is None:
            sender = self.air.getAvatarIdFromSender()
        RequestFriendsListProcess(self, self.air, sender)

    def toonOnline(self, avatarId):
        def avatarResponse(dclass, fields):
            if dclass != self.air.dclassesByName['DistributedPlayerToonUD']:
                self.notify.warning(
                    'toonOnline: avatarResponse: Attempted to get name of a newly online Toon and retrieved non-toon.'
                )
                return

            name = fields['setName'][0]
            friendsList = fields['setFriendsList'][0]
            self.d_toonOnline(avatarId, friendsList, name)

        self.air.dbInterface.queryObject(self.air.dbId, avatarId,
                                         avatarResponse)

    def toonOffline(self, avatarId):
        def avatarResponse(dclass, fields):
            if dclass != self.air.dclassesByName['DistributedPlayerToonUD']:
                self.notify.warning(
                    'toonOffline: avatarResponse: Attempted to get name of an offline Toon and retrieved non-toon.'
                )
                return

            name = fields['setName'][0]
            friendsList = fields['setFriendsList'][0]
            self.d_toonOffline(avatarId, friendsList, name)

        self.air.dbInterface.queryObject(self.air.dbId, avatarId,
                                         avatarResponse)

    def d_toonOnline(self, avatarId, friendsList, name):
        if not avatarId in self.toonsOnline:
            self.toonsOnline.append(avatarId)

        for friendId in friendsList:
            if friendId in self.toonsOnline:
                self.sendUpdateToAvatarId(friendId, 'toonOnline',
                                          [avatarId, name])

    def d_toonOffline(self, avatarId, friendsList, name):
        if avatarId in self.toonsOnline:
            self.toonsOnline.remove(avatarId)

        for friendId in friendsList:
            if friendId in self.toonsOnline:
                self.sendUpdateToAvatarId(friendId, 'toonOffline',
                                          [avatarId, name])

    def requestAvatarInfo(self, avId):
        sender = self.air.getAvatarIdFromSender()

        def avatarResponse(dclass, fields):
            if dclass != self.air.dclassesByName["DistributedPlayerToonUD"]:
                self.notify.warning(
                    "requestAvatarInfo: avatarResponse: It's not a toon.")
                return

            name = fields['setName'][0]
            dna = fields['setDNAStrand'][0]
            maxHP = fields['setMaxHealth'][0]
            hp = fields['setHealth'][0]
            zoneId = fields['setLastHood'][0]
            try:
                shardId = fields['setDefaultShard'][0]
            except:
                shardId = 0
            accessLevel = fields['setAccessLevel'][0]
            isOnline = int(avId in self.toonsOnline)

            self.sendUpdateToAvatarId(
                sender, 'avatarInfo',
                [name, dna, maxHP, hp, zoneId, shardId, isOnline, accessLevel])

        self.air.dbInterface.queryObject(self.air.dbId, avId, avatarResponse)

    def askAvatarToBeFriends(self, avId):
        sender = self.air.getAvatarIdFromSender()

        def avatarResponse(dclass, fields):
            if dclass != self.air.dclassesByName["DistributedPlayerToonUD"]:
                self.notify.warning(
                    "requestAvatarInfo: avatarResponse: It's not a toon.")
                return

            name = fields['setName'][0]
            dna = fields['setDNAStrand'][0]

            self.sendUpdateToAvatarId(avId, 'friendRequest',
                                      [sender, name, dna])

        self.air.dbInterface.queryObject(self.air.dbId, sender, avatarResponse)

    def iRemovedFriend(self, friendId):
        sender = self.air.getAvatarIdFromSender()

        def removerAvatarResponse(dclass, fields):
            if dclass != self.air.dclassesByName["DistributedPlayerToonUD"]:
                self.notify.warning(
                    "iRemovedFriend: removerAvatarResponse: It's not a toon.")
                return

            newList = list(fields['setFriendsList'][0])
            newList.remove(friendId)
            dg = dclass.aiFormatUpdate('setFriendsList', sender, sender,
                                       self.air.ourChannel, [newList])
            self.air.send(dg)
            self.air.dbInterface.updateObject(self.air.dbId, sender, dclass,
                                              {'setFriendsList': [newList]})

        def removeeAvatarResponse(dclass, fields):
            if dclass != self.air.dclassesByName["DistributedPlayerToonUD"]:
                self.notify.warning(
                    "iRemovedFriend: removeeAvatarResponse: It's not a toon.")
                return

            newList = list(fields['setFriendsList'][0])
            newList.remove(sender)
            dg = dclass.aiFormatUpdate('setFriendsList', friendId, friendId,
                                       self.air.ourChannel, [newList])
            self.air.send(dg)
            self.air.dbInterface.updateObject(self.air.dbId, friendId, dclass,
                                              {'setFriendsList': [newList]})

        self.air.dbInterface.queryObject(self.air.dbId, sender,
                                         removerAvatarResponse)
        self.air.dbInterface.queryObject(self.air.dbId, friendId,
                                         removeeAvatarResponse)

        self.sendUpdateToAvatarId(friendId, 'friendLeftYourList', [sender])

    def iAcceptedFriendRequest(self, avatarId):
        sender = self.air.getAvatarIdFromSender()

        def accepterAvatarResponse(dclass, fields):
            if dclass != self.air.dclassesByName["DistributedPlayerToonUD"]:
                self.notify.warning(
                    "iAcceptedFriendRequest: accepterAvatarResponse: It's not a toon."
                )
                return

            newList = list(fields['setFriendsList'][0])
            newList.append(avatarId)
            dg = dclass.aiFormatUpdate('setFriendsList', sender, sender,
                                       self.air.ourChannel, [newList])
            self.air.send(dg)
            self.air.dbInterface.updateObject(self.air.dbId, sender, dclass,
                                              {'setFriendsList': [newList]})

        def requesterAvatarResponse(dclass, fields):
            if dclass != self.air.dclassesByName["DistributedPlayerToonUD"]:
                self.notify.warning(
                    "iAcceptedFriendRequest: requesterAvatarResponse: It's not a toon."
                )
                return

            newList = list(fields['setFriendsList'][0])
            newList.append(sender)
            dg = dclass.aiFormatUpdate('setFriendsList', avatarId, avatarId,
                                       self.air.ourChannel, [newList])
            self.air.send(dg)
            self.air.dbInterface.updateObject(self.air.dbId, avatarId, dclass,
                                              {'setFriendsList': [newList]})

        self.air.dbInterface.queryObject(self.air.dbId, sender,
                                         accepterAvatarResponse)
        self.air.dbInterface.queryObject(self.air.dbId, avatarId,
                                         requesterAvatarResponse)

        self.sendUpdateToAvatarId(avatarId, 'acceptedFriendRequest', [])

    def iRejectedFriendRequest(self, avatarId):
        self.sendUpdateToAvatarId(avatarId, 'rejectedFriendRequest', [])

    def iCancelledFriendRequest(self, avatarId):
        sender = self.air.getAvatarIdFromSender()
        self.sendUpdateToAvatarId(avatarId, 'cancelFriendRequest', [sender])

    def requestAvatarStatus(self, avatarId):
        sender = self.air.getAvatarIdFromSender()
        self.sendUpdateToAvatarId(avatarId, 'someoneWantsYourStatus', [sender])

    def myAvatarStatus(self, avatarId, status):
        sender = self.air.getAvatarIdFromSender()
        self.sendUpdateToAvatarId(avatarId, 'avatarStatus', [sender, status])

    def iWantToTeleportToAvatar(self, avatarId):
        sender = self.air.getAvatarIdFromSender()
        self.sendUpdateToAvatarId(avatarId, 'avatarWantsYourLocation',
                                  [sender])

    def myAvatarLocation(self, avatarId, shardId, zoneId):
        sender = self.air.getAvatarIdFromSender()

        def teleportingAvatarResponse(dclass, fields):
            if dclass != self.air.dclassesByName['DistributedPlayerToonUD']:
                return

            name = fields['setName'][0]
            self.sendUpdateToAvatarId(sender, 'teleportNotify', [name])

        self.air.dbInterface.queryObject(self.air.dbId, avatarId,
                                         teleportingAvatarResponse)
        self.sendUpdateToAvatarId(avatarId, 'avatarLocation',
                                  [sender, shardId, zoneId])
Beispiel #30
0
import os, sys, socket, random
#from urllib import quote_plus
from pandac.PandaModules import HTTPClient
from pandac.PandaModules import HTTPCookie
from pandac.PandaModules import URLSpec
from pandac.PandaModules import Ramfile
from pandac.PandaModules import Ostream
from pandac.PandaModules import HTTPDate
from pandac.PandaModules import DocumentSpec
from direct.task.Task import Task
from direct.directnotify.DirectNotifyGlobal import directNotify
notify = directNotify.newCategory('UserFunnel')

class UserFunnel:

    def __init__(self):
        self.hitboxAcct = 'DM53030620EW'
        self.language = 'en-us'
        self.cgRoot = 'ToonTown_Online'
        self.cgBeta = 'Beta'
        self.cgRelease = 'Release'
        self.cgLocation = 'US'
        self.campaignID = ''
        self.cfCookieFile = 'cf.txt'
        self.dynamicVRFunnel = 'http://download.toontown.com/'
        self.hostDict = {0: 'Internal Disney PHP Collector Site',
         1: 'ehg-dig.hitbox.com/HG?',
         2: 'ehg-dig.hitbox.com/HG?',
         3: 'build64.online.disney.com:5020/index.php?'}
        self.CurrentHost = ''
        self.URLtoSend = ''
from extension_native_helpers import *
Dtool_PreloadDLL('libdirect')
from libdirect import *
from extension_native_helpers import *
try:
    Dtool_PreloadDLL('libp3direct')
    from libp3direct import *
except:
    Dtool_PreloadDLL('libdirect')
    from libdirect import *

from direct.directnotify.DirectNotifyGlobal import directNotify
notify = directNotify.newCategory('Interval')
Dtool_ObjectToDict(CInterval, 'notify', notify)
del notify

def setT(self, t):
    self.setT_Old(t)
    self.privPostEvent()


Dtool_ObjectToDict(CInterval, 'setT_Old', CInterval.setT)
Dtool_funcToMethod(setT, CInterval)
del setT

def play(self, t0 = 0.0, duration = None, scale = 1.0):
    self.notify.error('using deprecated CInterval.play() interface')
    if duration:
        self.start(t0, t0 + duration, scale)
    else:
        self.start(t0, -1, scale)
Beispiel #32
0
class StateData(DirectObject):
    """
    A StateData is a base class for a single state within a Finite
    State Machine (ClassicFSM).
    """

    notify = directNotify.newCategory('StateData')

    def __init__(self, doneEvent):
        self.doneEvent = doneEvent
        self.doneStatus = None
        self.isLoaded = 0
        self.isEntered = 0

    def enter(self):
        """
        Enters the StateData.  This makes it active in whatever sense
        this applies.  Returns true if this is a change (i.e. it was
        not previously entered), or false if this is the same (i.e. it
        was already entered).
        """
        if self.isEntered:
            return 0
        if not self.isLoaded:
            self.notify.warning("entered StateData before it was loaded")
            self.load()
        self.isEntered = 1
        StateData.notify.debug('enter()')
        return 1

    def exit(self):
        """
        Exits the StateData.  Returns true if this is a change
        (i.e. it was previously entered), or false if this is the same
        (i.e. it was already exited).
        """
        if not self.isEntered:
            return 0
        self.isEntered = 0
        StateData.notify.debug('exit()')
        return 1

    def load(self):
        """
        Loads the StateData.  This loads whatever assets are needed
        from disk, and otherwise prepares the StateData for being
        entered, without actually entering it.  Returns true if this
        is a change (i.e. it was not already loaded), or false if this
        is the same (i.e. it was previously loaded).
        """
        if self.isLoaded:
            return 0
        self.isLoaded = 1
        StateData.notify.debug('load()')
        return 1

    def unload(self):
        """
        Unloads the StateData.  This frees whatever assets were loaded
        by load(), and generally makes the memory usage for this thing
        be as small as possible.  Some StateData-derived classes can
        load and unload repeatedly; others are useless once they have
        been unloaded.
        """
        if not self.isLoaded:
            return 0
        if self.isEntered:
            self.notify.warning("unloaded StateData before it was exited")
            self.exit()
        self.isLoaded = 0
        StateData.notify.debug('unload()')
        return 1

    def getDoneStatus(self):
        """
        The done status of a state data may be anything.  It is common
        practice to return a Python dictionary or a string; the default
        value is None.
        """
        return self.doneStatus
Beispiel #33
0
from __future__ import division
import itertools
import struct

import panda3d.core as core
from direct.showbase.DirectObject import DirectObject
from direct.task.TaskManagerGlobal import taskMgr
from direct.showbase.MessengerGlobal import messenger
from direct.directnotify.DirectNotifyGlobal import directNotify

import world


notify = directNotify.newCategory('geometry')


class GeomBuilder(object):
    def __init__(self, name, master):
        self.name = name
        self.master = master
        self.primitive = core.GeomTriangles(core.Geom.UHStatic)
        self.primitive.setIndexType(core.Geom.NTUint32)
        self.indices = []

    def add_block(self, x, y, form, hidden):
        if hidden:
            form = world.Block.FORMS['Hidden']
        else:
            form = form
        offset = self.master.index_offset(x, y, form)
        self.indices.extend([i + offset for i in form.indices])
class ToontownRPCConnection:
    notify = directNotify.newCategory('ToontownRPCConnection')

    def __init__(self, socket, handler):
        self.socket = socket

        self.dispatcher = ToontownRPCDispatcher(handler)

        self.socketLock = threading.Lock()
        self.readLock = threading.RLock()
        self.writeLock = threading.RLock()

        self.readBuffer = ''

        self.writeQueue = []
        self.writeSemaphore = threading.Semaphore(0)
        self.writeThread = threading.Thread(target=self.__writeThread)
        self.writeThread.start()

    def __readHeaders(self):
        # Acquire a read lock so that nothing intervenes:
        self.readLock.acquire()

        # Read data until we find the '\r\n\r\n' terminator:
        while '\r\n\r\n' not in self.readBuffer:
            try:
                self.readBuffer += self.socket.recv(2048)
            except:
                self.readLock.release()
                return {}

            if not self.readBuffer:
                # It looks like we have nothing to read.
                self.readLock.release()
                return {}

        # Collect the data before the terminator:
        terminatorIndex = self.readBuffer.find('\r\n\r\n')
        data = self.readBuffer[:terminatorIndex]

        # Truncate the remaining data:
        self.readBuffer = self.readBuffer[terminatorIndex + 4:]

        # We're done working with the read buffer, so:
        self.readLock.release()

        # Return the parsed headers in the form of a dictionary:
        return self.__parseHeaders(data)

    def __parseHeaders(self, data):
        headers = {}

        for i, line in enumerate(data.split('\n')):
            line = line.rstrip('\r')

            if i == 0:
                # This is the HTTP request.
                words = line.split(' ')
                if len(words) != 3:
                    self.writeHTTPError(400)
                    return {}

                command, _, version = words

                if command != 'POST':
                    self.writeHTTPError(501)
                    return {}

                if version not in ('HTTP/1.0', 'HTTP/1.1'):
                    self.writeHTTPError(505)
                    return {}
            else:
                # This is an HTTP header.
                words = line.split(': ', 1)
                if len(words) != 2:
                    self.writeHTTPError(400)
                    return {}

                headers[words[0].lower()] = words[1]

        return headers

    def read(self, timeout=None):
        """
        Read an HTTP POST request from the socket, and return the body.
        """
        self.socketLock.acquire()
        self.socket.settimeout(timeout)

        # Read our HTTP headers:
        headers = self.__readHeaders()

        if not headers:
            # It looks like we have nothing to read.
            self.socketLock.release()
            return ''

        # We need a content-length in order to read POST data:
        contentLength = headers.get('content-length', '')
        if (not contentLength) or (not contentLength.isdigit()):
            self.socketLock.release()
            self.writeHTTPError(400)
            return ''

        # Acquire a read lock so nothing touches the read buffer while we work:
        self.readLock.acquire()

        contentLength = int(contentLength)

        # Ensure we have all of our content:
        while len(self.readBuffer) < contentLength:
            try:
                self.readBuffer += self.socket.recv(2048)
            except:
                self.readLock.release()
                self.socketLock.release()
                return ''

            if not self.readBuffer:
                # It looks like we have nothing to read.
                self.readLock.release()
                self.socketLock.release()
                return ''

        # Collect the content:
        data = self.readBuffer[:contentLength]

        # Truncate the remaining data:
        self.readBuffer = self.readBuffer[contentLength + 1:]

        # Release our thread locks:
        self.readLock.release()
        self.socketLock.release()

        try:
            return data.decode('utf-8')
        except UnicodeDecodeError:
            return ''

    def __writeNow(self, data, timeout=None):
        # Acquire a write lock so nothing intervenes:
        self.writeLock.acquire()

        self.socket.settimeout(timeout)

        # Ensure the data ends with a new line:
        if not data.endswith('\n'):
            data += '\n'

        while data:
            try:
                sent = self.socket.send(data)
            except:
                break
            if sent == 0:
                break
            data = data[sent:]

        # Release our write lock:
        self.writeLock.release()

    def __writeThread(self):
        while True:
            self.writeSemaphore.acquire()

            # Ensure we have a request in the write queue:
            if not self.writeQueue:
                continue

            request = self.writeQueue.pop(0)

            terminate = request.get('terminate')
            if terminate is not None:
                # Clear the write queue, and stop:
                self.writeQueue = []
                terminate.set()
                break

            # Write the data to the socket:
            data = request.get('data')
            if data:
                self.__writeNow(data, timeout=request.get('timeout'))

    def write(self, data, timeout=None):
        """
        Add data to the write queue.
        """
        self.writeQueue.append({'data': data, 'timeout': timeout})
        self.writeSemaphore.release()

    def writeHTTPResponse(self, body, contentType=None, code=200):
        """
        Write an HTTP response to the socket.
        """
        response = 'HTTP/1.1 %d %s\r\n' % (code, httplib.responses.get(code))

        # Add the standard headers:
        response += 'Date: %s\r\n' % time.strftime('%a, %d %b %Y %H:%M:%S GMT',
                                                   time.gmtime())
        response += 'Server: TTC-RPCServer/0.1\r\n'

        # Add the content headers:
        response += 'Content-Length: %d\r\n' % len(body)
        if contentType is not None:
            response += 'Content-Type: %s\r\n' % contentType

        # Add the body:
        response += '\r\n' + body

        # Finally, send it out:
        self.write(response, timeout=5)

    def writeHTTPError(self, code):
        """
        Write an HTTP error response to the socket.
        """
        self.notify.warning('Received a bad HTTP request: ' + str(code))
        body = '%d %s' % (code, httplib.responses.get(code))
        self.writeHTTPResponse(body, contentType='text/plain', code=code)

    def writeJSONResponse(self, response, id=None):
        """
        Write a JSON response object to the socket.
        """
        response.update({'jsonrpc': '2.0', 'id': id})
        try:
            body = json.dumps(response, encoding='latin-1')
        except TypeError:
            self.writeJSONError(-32603, 'Internal error')
            return
        self.writeHTTPResponse(body, contentType='application/json')

    def writeJSONError(self, code, message, id=None):
        """
        Write a JSON error response object to the socket.
        """
        self.notify.warning('Received a bad JSON request: %d %s' %
                            (code, message))
        response = {'error': {'code': code, 'message': message}}
        self.writeJSONResponse(response, id=id)

    def close(self):
        """
        Wait until the write queue is empty, then shutdown and close our
        socket.
        """
        terminate = threading2.Event()
        self.writeQueue.append({'terminate': terminate})
        self.writeSemaphore.release()
        terminate.wait()

        try:
            self.socket.shutdown(socket.SHUT_RDWR)
        except socket.error:
            pass
        self.socket.close()

    def dispatchUntilEmpty(self):
        """
        Read and dispatch until there is nothing left.
        """
        while True:
            data = self.read(timeout=5)

            if not data:
                # We have nothing left to read.
                break

            try:
                request = json.loads(data)
            except ValueError:
                self.writeJSONError(-32700, 'Parse error')
                continue

            request = ToontownRPCRequest(self,
                                         request.get('method'),
                                         params=request.get('params') or (),
                                         id=request.get('id'),
                                         notification=('id' not in request))
            self.dispatcher.dispatch(request)
Beispiel #35
0
import world
import camera
import gui
import geometry
import block_picker
import zmap
import console
import dorf
import tools
import designation

#loadPrcFileData("", "want-directtools #t")
#loadPrcFileData("", "want-tk #t")

notify = directNotify.newCategory('dorfmain')


class Dorfdelf(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)
        wp = core.WindowProperties()
        wp.setTitle("Dorfdelf")
        self.win.requestProperties(wp)

        self.render.setAntialias(core.AntialiasAttrib.MAuto)
        self.setBackgroundColor(0.5, 0.5, 0.5)
        self.disableMouse()
        self.enableParticles()

        font = self.loader.loadFont('media/Carlito-Regular.ttf')
class ToonBase(ShowBase):
    notify = directNotify.newCategory("ToonBase")

    def __init__(self):
        ShowBase.__init__(self)

        self.toons = []
        types = [("boy", "dgl"), ("boy", "dgm"), ("boy", "dgs"),
                 ("girl", "dgl"), ("girl", "dgm"), ("girl", "dgs")]

        x = 0
        for data in types:
            toon = self.makeToon(*data)
            toon.setX(x)
            self.toons.append(toon)
            x += 5

    def makeToon(self, gender, torso):
        if gender == "boy":
            torso += "_shorts"
        elif gender == "girl":
            torso += "_skirt"

        toon = Actor(None, None, None, flattenable=0, setFinal=1)

        # head mdl + anim
        toon.loadModel('phase_3/models/char/tt_a_chr_dgm_skirt_head_1000.bam',
                       'head')
        toon.loadAnims(
            {
                "neutral":
                "phase_3/models/char/tt_a_chr_dgm_skirt_head_neutral.bam"
            }, 'head')
        # torso mdl + anim
        toon.loadModel(
            'phase_3/models/char/tt_a_chr_' + torso + '_torso_1000.bam',
            'torso')
        toon.loadAnims(
            {
                'neutral':
                'phase_3/models/char/tt_a_chr_' + torso + '_torso_neutral.bam'
            }, 'torso')
        # legs mdl + anim
        toon.loadModel('phase_3/models/char/tt_a_chr_dgm_shorts_legs_1000.bam',
                       'legs')
        toon.loadAnims(
            {
                'neutral':
                'phase_3/models/char/tt_a_chr_dgm_shorts_legs_neutral.bam'
            }, 'legs')

        # attach parts
        toon.attach('head', 'torso', 'def_head')
        toon.attach('torso', 'legs', 'joint_hips')

        color = (0.347656, 0.820312, 0.953125, 1.0)
        toon.find('**/arms').setColor(color)
        toon.find('**/legs').setColor(color)
        toon.find('**/feet').setColor(color)
        toon.find('**/neck').setColor(color)
        toon.find('**/head').setColor(color)
        toon.find('**/head-front').setColor(color)
        toon.find('**/hands').setColor((1, 1, 1, 1))
        toon.find('**/shoes').removeNode()
        toon.find('**/boots_long').removeNode()
        toon.find('**/boots_short').removeNode()

        shirt = loader.loadTexture('phase_4/maps/4thJulyShirt2.jpg')
        sleeve = loader.loadTexture('phase_4/maps/4thJulySleeve2.jpg')
        if gender == "boy":
            bottom = loader.loadTexture('phase_4/maps/4thJulyShorts1.jpg')
        elif gender == "girl":
            bottom = loader.loadTexture('phase_4/maps/4thJulySkirt1.jpg')

        toon.find('**/torso-top').setTexture(shirt, 1)
        toon.find('**/sleeves').setTexture(sleeve, 1)
        toon.find('**/torso-bot').setTexture(bottom, 1)

        glasses = loader.loadModel(
            'phase_4/models/accessories/tt_m_chr_avt_acc_msk_dorkGlasses.bam')
        glassesNode = toon.getPart('head').attachNewNode('glassesNode')
        glasses.reparentTo(glassesNode)
        glasses.setScale(0.27, 0.2, 0.35)
        glasses.setH(180)
        glasses.setZ(0.27)
        glasses.setY(0.2)

        shadow = loader.loadModel('phase_3/models/props/drop_shadow.bam')
        shadow.reparentTo(toon.find('**/joint_shadow'))
        shadow.setScale(0.4)
        shadow.flattenMedium()
        shadow.setBillboardAxis(4)
        shadow.setColor(0, 0, 0, 0.5, 1)

        toon.reparentTo(render)
        toon.loop('neutral')

        return toon
from DistributedObjectAI import DistributedObjectAI
from direct.directnotify.DirectNotifyGlobal import directNotify

if __debug__:
    notify = directNotify.newCategory('DistributedObjectGlobalAI')


class DistributedObjectGlobalAI(DistributedObjectAI):
    if __debug__:
        notify = notify

    doNotDeallocateChannel = 1
    isGlobalDistObj = 1

    def __init__(self, air): 
        DistributedObjectAI.__init__(self, air)

    def announceGenerate(self):
        DistributedObjectAI.announceGenerate(self)
        try:
            if not self.doNotListenToChannel:
                self.air.registerForChannel(self.doId)            
        except AttributeError:
                self.air.registerForChannel(self.doId)            
        return False        

    def delete(self):
       DistributedObjectAI.delete(self)
       try:
            if not self.doNotListenToChannel:
Beispiel #38
0
class ObjectReport:
    """report on every Python object in the current process"""
    notify = directNotify.newCategory('ObjectReport')

    def __init__(self, name, log=True):
        gr = GarbageReport.GarbageReport('ObjectReport\'s GarbageReport: %s' %
                                         name,
                                         log=log)
        gr.destroy()
        del gr
        self._name = name
        self._pool = ObjectPool.ObjectPool(self._getObjectList())
        #ExclusiveObjectPool.addExclObjs(self, self._pool, self._name)
        if log:
            self.notify.info('===== ObjectReport: \'%s\' =====\n%s' %
                             (self._name, self.typeFreqStr()))

    def destroy(self):
        #ExclusiveObjectPool.removeExclObjs(self, self._pool, self._name)
        self._pool.destroy()
        del self._pool
        del self._name

    def typeFreqStr(self):
        return self._pool.typeFreqStr()

    def diff(self, other):
        return self._pool.diff(other._pool)

    def getObjectPool(self):
        return self._pool

    def _getObjectList(self):
        if hasattr(sys, 'getobjects'):
            return sys.getobjects(0)
        else:
            gc.collect()
            # grab gc's object list
            gc_objects = gc.get_objects()
            # use get_referents to find everything else
            objects = gc_objects
            objects.append(builtins.__dict__)
            nextObjList = gc_objects
            found = set()
            found.add(id(objects))
            found.add(id(found))
            found.add(id(gc_objects))
            for obj in objects:
                found.add(id(obj))
            # repeatedly call get_referents until we can't find any more objects
            while len(nextObjList):
                curObjList = nextObjList
                nextObjList = []
                for obj in curObjList:
                    refs = gc.get_referents(obj)
                    for ref in refs:
                        if id(ref) not in found:
                            found.add(id(ref))
                            objects.append(ref)
                            nextObjList.append(ref)
            return objects
        """
    # TO DO: THIS IS QUITE DISGUSTING
    # MOVE THIS TO ToontownInternalRepository (this might be interesting for AI)
    _data = {}
    if len(extras.items()) != 0:
        for k, v in extras.items():
            _data[k] = v
    signature = hashlib.sha512(json.dumps(_data) + apiSecret).hexdigest()
    data = urllib.urlencode({'data': json.dumps(_data), 'hmac': signature})
    req = urllib2.Request('http://www.toontowncrystal.com/api/' + url, data)
    req.get_method = lambda: "POST"
    try:
        return urllib2.urlopen(req).read()
    except:
        return None

notify = directNotify.newCategory('ClientServicesManagerUD')

def executeHttpRequestAndLog(url, **extras):
    # SEE ABOVE
    response = executeHttpRequest(url, extras)

    if response is None:
        notify.error('A request to ' + url + ' went wrong.')
        return None

    try:
        data = json.loads(response)
    except:
        notify.error('Malformed response from ' + url + '.')
        return None
Beispiel #40
0
class AppRunner(DirectObject):
    """ This class is intended to be compiled into the Panda3D runtime
    distributable, to execute a packaged p3d application.  It also
    provides some useful runtime services while running in that
    packaged environment.

    It does not usually exist while running Python directly, but you
    can use dummyAppRunner() to create one at startup for testing or
    development purposes.  """

    notify = directNotify.newCategory("AppRunner")

    ConfigBasename = 'config.xml'

    # Default values for parameters that are absent from the config file:
    maxDiskUsage = 2048 * 1048576  # 2 GB

    # Values for verifyContents, from p3d_plugin.h
    P3DVCNone = 0
    P3DVCNormal = 1
    P3DVCForce = 2
    P3DVCNever = 3

    # Also from p3d_plugin.h
    P3D_CONTENTS_DEFAULT_MAX_AGE = 5

    def __init__(self):
        DirectObject.__init__(self)

        # We direct both our stdout and stderr objects onto Panda's
        # Notify stream.  This ensures that unadorned print statements
        # made within Python will get routed into the log properly.
        stream = StreamWriter(Notify.out(), False)
        sys.stdout = stream
        sys.stderr = stream

        # This is set true by dummyAppRunner(), below.
        self.dummy = False

        # These will be set from the application flags when
        # setP3DFilename() is called.
        self.allowPythonDev = False
        self.guiApp = False
        self.interactiveConsole = False
        self.initialAppImport = False
        self.trueFileIO = False
        self.respectPerPlatform = None

        self.verifyContents = self.P3DVCNone

        self.sessionId = 0
        self.packedAppEnvironmentInitialized = False
        self.gotWindow = False
        self.gotP3DFilename = False
        self.p3dFilename = None
        self.p3dUrl = None
        self.started = False
        self.windowOpened = False
        self.windowPrc = None

        self.http = None
        if hasattr(core, 'HTTPClient'):
            self.http = core.HTTPClient.getGlobalPtr()

        self.Undefined = Undefined
        self.ConcreteStruct = ConcreteStruct

        # This is per session.
        self.nextScriptId = 0

        # TODO: we need one of these per instance, not per session.
        self.instanceId = None

        # The root Panda3D install directory.  This is filled in when
        # the instance starts up.
        self.rootDir = None

        # The log directory.  Also filled in when the instance starts.
        self.logDirectory = None

        # self.superMirrorUrl, if nonempty, is the "super mirror" URL
        # that should be contacted first before trying the actual
        # host.  This is primarily used for "downloading" from a
        # locally-stored Panda3D installation.  This is also filled in
        # when the instance starts up.
        self.superMirrorUrl = None

        # A list of the Panda3D packages that have been loaded.
        self.installedPackages = []

        # A list of the Panda3D packages that in the queue to be
        # downloaded.
        self.downloadingPackages = []

        # A dictionary of HostInfo objects for the various download
        # hosts we have imported packages from.
        self.hosts = {}

        # The altHost string that is in effect from the HTML tokens,
        # if any, and the dictionary of URL remapping: orig host url
        # -> alt host url.
        self.altHost = None
        self.altHostMap = {}

        # The URL from which Panda itself should be downloaded.
        self.pandaHostUrl = PandaSystem.getPackageHostUrl()

        # Application code can assign a callable object here; if so,
        # it will be invoked when an uncaught exception propagates to
        # the top of the TaskMgr.run() loop.
        self.exceptionHandler = None

        # Managing packages for runtime download.
        self.downloadingPackages = []
        self.downloadTask = None

        # The mount point for the multifile.  For now, this is always
        # the current working directory, for convenience; but when we
        # move to multiple-instance sessions, it may have to be
        # different for each instance.
        self.multifileRoot = str(ExecutionEnvironment.getCwd())

        # The "main" object will be exposed to the DOM as a property
        # of the plugin object; that is, document.pluginobject.main in
        # JavaScript will be appRunner.main here.  This may be
        # replaced with a direct reference to the JavaScript object
        # later, in setInstanceInfo().
        self.main = ScriptAttributes()

        # By default, we publish a stop() method so the browser can
        # easy stop the plugin.  A particular application can remove
        # this if it chooses.
        self.main.stop = self.stop

        # This will be the browser's toplevel window DOM object;
        # e.g. self.dom.document will be the document.
        self.dom = None

        # This is the list of expressions we will evaluate when
        # self.dom gets assigned.
        self.deferredEvals = []

        # This is the default requestFunc that is installed if we
        # never call setRequestFunc().
        def defaultRequestFunc(*args):
            if args[1] == 'notify':
                # Quietly ignore notifies.
                return
            self.notify.info("Ignoring request: %s" % (args, ))

        self.requestFunc = defaultRequestFunc

        # This will be filled in with the default WindowProperties for
        # this instance, e.g. the WindowProperties necessary to
        # re-embed a window in the browser frame.
        self.windowProperties = None

        # Store our pointer so DirectStart-based apps can find us.
        if AppRunnerGlobal.appRunner is None:
            AppRunnerGlobal.appRunner = self

        # We use this messenger hook to dispatch this __startIfReady()
        # call back to the main thread.
        self.accept('AppRunner_startIfReady', self.__startIfReady)

    def getToken(self, tokenName):
        """ Returns the value of the indicated web token as a string,
        if it was set, or None if it was not. """

        return self.tokenDict.get(tokenName.lower(), None)

    def getTokenInt(self, tokenName):
        """ Returns the value of the indicated web token as an integer
        value, if it was set, or None if it was not, or not an
        integer. """

        value = self.getToken(tokenName)
        if value is not None:
            try:
                value = int(value)
            except ValueError:
                value = None
        return value

    def getTokenFloat(self, tokenName):
        """ Returns the value of the indicated web token as a
        floating-point value value, if it was set, or None if it was
        not, or not a number. """

        value = self.getToken(tokenName)
        if value is not None:
            try:
                value = float(value)
            except ValueError:
                value = None
        return value

    def getTokenBool(self, tokenName):
        """ Returns the value of the indicated web token as a boolean
        value, if it was set, or None if it was not. """

        value = self.getTokenInt(tokenName)
        if value is not None:
            value = bool(value)
        return value

    def installPackage(self, packageName, version=None, hostUrl=None):
        """ Installs the named package, downloading it first if
        necessary.  Returns true on success, false on failure.  This
        method runs synchronously, and will block until it is
        finished; see the PackageInstaller class if you want this to
        happen asynchronously instead. """

        host = self.getHostWithAlt(hostUrl)
        if not host.downloadContentsFile(self.http):
            return False

        # All right, get the package info now.
        package = host.getPackage(packageName, version)
        if not package:
            self.notify.warning("Package %s %s not known on %s" %
                                (packageName, version, hostUrl))
            return False

        return self.__rInstallPackage(package, [])

    def __rInstallPackage(self, package, nested):
        """ The recursive implementation of installPackage().  The new
        parameter, nested, is a list of packages that we are
        recursively calling this from, to avoid recursive loops. """

        package.checkStatus()
        if not package.downloadDescFile(self.http):
            return False

        # Now that we've downloaded and read the desc file, we can
        # install all of the required packages first.
        nested = nested[:] + [self]
        for packageName, version, host in package.requires:
            if host.downloadContentsFile(self.http):
                p2 = host.getPackage(packageName, version)
                if not p2:
                    self.notify.warning("Couldn't find %s %s on %s" %
                                        (packageName, version, host.hostUrl))
                else:
                    if p2 not in nested:
                        self.__rInstallPackage(p2, nested)

        # Now that all of the required packages are installed, carry
        # on to download and install this package.
        if not package.downloadPackage(self.http):
            return False

        if not package.installPackage(self):
            return False

        self.notify.info("Package %s %s installed." %
                         (package.packageName, package.packageVersion))
        return True

    def getHostWithAlt(self, hostUrl):
        """ Returns a suitable HostInfo object for downloading
        contents from the indicated URL.  This is almost always the
        same thing as getHost(), except in the rare case when we have
        an alt_host specified in the HTML tokens; in this case, we may
        actually want to download the contents from a different URL
        than the one given, for instance to download a version in
        testing. """

        if hostUrl is None:
            hostUrl = self.pandaHostUrl

        altUrl = self.altHostMap.get(hostUrl, None)
        if altUrl:
            # We got an alternate host.  Use it.
            return self.getHost(altUrl)

        # We didn't get an aternate host, use the original.
        host = self.getHost(hostUrl)

        # But we might need to consult the host itself to see if *it*
        # recommends an altHost.
        if self.altHost:
            # This means forcing the host to download its contents
            # file on the spot, a blocking operation.  This is a
            # little unfortunate, but since alt_host is so rarely
            # used, probably not really a problem.
            host.downloadContentsFile(self.http)
            altUrl = host.altHosts.get(self.altHost, None)
            if altUrl:
                return self.getHost(altUrl)

        # No shenanigans, just return the requested host.
        return host

    def getHost(self, hostUrl, hostDir=None):
        """ Returns a new HostInfo object corresponding to the
        indicated host URL.  If we have already seen this URL
        previously, returns the same object.

        This returns the literal referenced host.  To return the
        mapped host, which is the one we should actually download
        from, see getHostWithAlt().  """

        if not hostUrl:
            hostUrl = self.pandaHostUrl

        host = self.hosts.get(hostUrl, None)
        if not host:
            host = HostInfo(hostUrl, appRunner=self, hostDir=hostDir)
            self.hosts[hostUrl] = host
        return host

    def getHostWithDir(self, hostDir):
        """ Returns the HostInfo object that corresponds to the
        indicated on-disk host directory.  This would be used when
        reading a host directory from disk, instead of downloading it
        from a server.  Supply the full path to the host directory, as
        a Filename.  Returns None if the contents.xml in the indicated
        host directory cannot be read or doesn't seem consistent. """

        host = HostInfo(None, hostDir=hostDir, appRunner=self)
        if not host.hasContentsFile:
            if not host.readContentsFile():
                # Couldn't read the contents.xml file
                return None

        if not host.hostUrl:
            # The contents.xml file there didn't seem to indicate the
            # same host directory.
            return None

        host2 = self.hosts.get(host.hostUrl)
        if host2 is None:
            # No such host already; store this one.
            self.hosts[host.hostUrl] = host
            return host

        if host2.hostDir != host.hostDir:
            # Hmm, we already have that host somewhere else.
            return None

        # We already have that host, and it's consistent.
        return host2

    def deletePackages(self, packages):
        """ Removes all of the indicated packages from the disk,
        uninstalling them and deleting all of their files.  The
        packages parameter must be a list of one or more PackageInfo
        objects, for instance as returned by getHost().getPackage().
        Returns the list of packages that were NOT found. """

        for hostUrl, host in self.hosts.items():
            packages = host.deletePackages(packages)

            if not host.packages:
                # If that's all of the packages for this host, delete
                # the host directory too.
                del self.hosts[hostUrl]
                self.__deleteHostFiles(host)

        return packages

    def __deleteHostFiles(self, host):
        """ Called by deletePackages(), this removes all the files for
        the indicated host (for which we have presumably already
        removed all of the packages). """

        self.notify.info("Deleting host %s: %s" % (host.hostUrl, host.hostDir))
        self.rmtree(host.hostDir)

        self.sendRequest('forget_package', host.hostUrl, '', '')

    def freshenFile(self, host, fileSpec, localPathname):
        """ Ensures that the localPathname is the most current version
        of the file defined by fileSpec, as offered by host.  If not,
        it downloads a new version on-the-spot.  Returns true on
        success, false on failure. """

        assert self.http
        return host.freshenFile(self.http, fileSpec, localPathname)

    def scanInstalledPackages(self):
        """ Scans the hosts and packages already installed locally on
        the system.  Returns a list of InstalledHostData objects, each
        of which contains a list of InstalledPackageData objects. """

        result = []
        hostsFilename = Filename(self.rootDir, 'hosts')
        hostsDir = ScanDirectoryNode(hostsFilename)
        for dirnode in hostsDir.nested:
            host = self.getHostWithDir(dirnode.pathname)
            hostData = InstalledHostData(host, dirnode)

            if host:
                for package in host.getAllPackages(includeAllPlatforms=True):
                    packageDir = package.getPackageDir()
                    if not packageDir.exists():
                        continue

                    subdir = dirnode.extractSubdir(packageDir)
                    if not subdir:
                        # This package, while defined by the host, isn't installed
                        # locally; ignore it.
                        continue

                    packageData = InstalledPackageData(package, subdir)
                    hostData.packages.append(packageData)

            # Now that we've examined all of the packages for the host,
            # anything left over is junk.
            for subdir in dirnode.nested:
                packageData = InstalledPackageData(None, subdir)
                hostData.packages.append(packageData)

            result.append(hostData)

        return result

    def readConfigXml(self):
        """ Reads the config.xml file that may be present in the root
        directory. """

        if not hasattr(core, 'TiXmlDocument'):
            return

        filename = Filename(self.rootDir, self.ConfigBasename)
        doc = core.TiXmlDocument(filename.toOsSpecific())
        if not doc.LoadFile():
            return

        xconfig = doc.FirstChildElement('config')
        if xconfig:
            maxDiskUsage = xconfig.Attribute('max_disk_usage')
            try:
                self.maxDiskUsage = int(maxDiskUsage or '')
            except ValueError:
                pass

    def writeConfigXml(self):
        """ Rewrites the config.xml to the root directory.  This isn't
        called automatically; an application may call this after
        adjusting some parameters (such as self.maxDiskUsage). """

        from panda3d.core import TiXmlDocument, TiXmlDeclaration, TiXmlElement

        filename = Filename(self.rootDir, self.ConfigBasename)
        doc = TiXmlDocument(filename.toOsSpecific())
        decl = TiXmlDeclaration("1.0", "utf-8", "")
        doc.InsertEndChild(decl)

        xconfig = TiXmlElement('config')
        xconfig.SetAttribute('max_disk_usage', str(self.maxDiskUsage))
        doc.InsertEndChild(xconfig)

        # Write the file to a temporary filename, then atomically move
        # it to its actual filename, to avoid race conditions when
        # updating this file.
        tfile = Filename.temporary(str(self.rootDir), '.xml')
        if doc.SaveFile(tfile.toOsSpecific()):
            tfile.renameTo(filename)

    def checkDiskUsage(self):
        """ Checks the total disk space used by all packages, and
        removes old packages if necessary. """

        totalSize = 0
        hosts = self.scanInstalledPackages()
        for hostData in hosts:
            for packageData in hostData.packages:
                totalSize += packageData.totalSize
        self.notify.info("Total Panda3D disk space used: %s MB" %
                         ((totalSize + 524288) // 1048576))

        if self.verifyContents == self.P3DVCNever:
            # We're not allowed to delete anything anyway.
            return

        self.notify.info("Configured max usage is: %s MB" %
                         ((self.maxDiskUsage + 524288) // 1048576))
        if totalSize <= self.maxDiskUsage:
            # Still within budget; no need to clean up anything.
            return

        # OK, we're over budget.  Now we have to remove old packages.
        usedPackages = []
        for hostData in hosts:
            for packageData in hostData.packages:
                if packageData.package and packageData.package.installed:
                    # Don't uninstall any packages we're currently using.
                    continue

                usedPackages.append((packageData.lastUse, packageData))

        # Sort the packages into oldest-first order.
        usedPackages.sort()

        # Delete packages until we free up enough space.
        packages = []
        for lastUse, packageData in usedPackages:
            if totalSize <= self.maxDiskUsage:
                break
            totalSize -= packageData.totalSize

            if packageData.package:
                packages.append(packageData.package)
            else:
                # If it's an unknown package, just delete it directly.
                print("Deleting unknown package %s" % (packageData.pathname))
                self.rmtree(packageData.pathname)

        packages = self.deletePackages(packages)
        if packages:
            print("Unable to delete %s packages" % (len(packages)))

        return

    def stop(self):
        """ This method can be called by JavaScript to stop the
        application. """

        # We defer the actual exit for a few frames, so we don't raise
        # an exception and invalidate the JavaScript call; and also to
        # help protect against race conditions as the application
        # shuts down.
        taskMgr.doMethodLater(0.5, sys.exit, 'exit')

    def run(self):
        """ This method calls taskMgr.run(), with an optional
        exception handler.  This is generally the program's main loop
        when running in a p3d environment (except on unusual platforms
        like the iPhone, which have to hand the main loop off to the
        OS, and don't use this interface). """

        try:
            taskMgr.run()

        except SystemExit as err:
            # Presumably the window has already been shut down here, but shut
            # it down again for good measure.
            if hasattr(builtins, "base"):
                base.destroy()

            self.notify.info("Normal exit with status %s." % repr(err.code))
            raise

        except:
            # Some unexpected Python exception; pass it to the
            # optional handler, if it is defined.
            if self.exceptionHandler and not self.interactiveConsole:
                self.exceptionHandler()
            else:
                raise

    def rmtree(self, filename):
        """ This is like shutil.rmtree(), but it can remove read-only
        files on Windows.  It receives a Filename, the root directory
        to delete. """
        if filename.isDirectory():
            for child in filename.scanDirectory():
                self.rmtree(Filename(filename, child))
            if not filename.rmdir():
                print("could not remove directory %s" % (filename))
        else:
            if not filename.unlink():
                print("could not delete %s" % (filename))

    def setSessionId(self, sessionId):
        """ This message should come in at startup. """
        self.sessionId = sessionId
        self.nextScriptId = self.sessionId * 1000 + 10000

    def initPackedAppEnvironment(self):
        """ This function sets up the Python environment suitably for
        running a packed app.  It should only run once in any given
        session (and it includes logic to ensure this). """

        if self.packedAppEnvironmentInitialized:
            return

        self.packedAppEnvironmentInitialized = True

        vfs = VirtualFileSystem.getGlobalPtr()

        # Now set up Python to import this stuff.
        VFSImporter.register()
        sys.path.append(self.multifileRoot)

        # Make sure that $MAIN_DIR is set to the p3d root before we
        # start executing the code in this file.
        ExecutionEnvironment.setEnvironmentVariable(
            "MAIN_DIR",
            Filename(self.multifileRoot).toOsSpecific())

        # Put our root directory on the model-path, too.
        getModelPath().appendDirectory(self.multifileRoot)

        if not self.trueFileIO:
            # Replace the builtin open and file symbols so user code will get
            # our versions by default, which can open and read files out of
            # the multifile.
            builtins.open = file.open
            if sys.version_info < (3, 0):
                builtins.file = file.open
                builtins.execfile = file.execfile
            os.listdir = file.listdir
            os.walk = file.walk
            os.path.join = file.join
            os.path.isfile = file.isfile
            os.path.isdir = file.isdir
            os.path.exists = file.exists
            os.path.lexists = file.lexists
            os.path.getmtime = file.getmtime
            os.path.getsize = file.getsize
            sys.modules['glob'] = glob

        self.checkDiskUsage()

    def __startIfReady(self):
        """ Called internally to start the application. """
        if self.started:
            return

        if self.gotWindow and self.gotP3DFilename:
            self.started = True

            # Now we can ignore future calls to startIfReady().
            self.ignore('AppRunner_startIfReady')

            # Hang a hook so we know when the window is actually opened.
            self.acceptOnce('window-event', self.__windowEvent)

            # Look for the startup Python file.  This might be a magic
            # filename (like "__main__", or any filename that contains
            # invalid module characters), so we can't just import it
            # directly; instead, we go through the low-level importer.

            # If there's no p3d_info.xml file, we look for "main".
            moduleName = 'main'
            if self.p3dPackage:
                mainName = self.p3dPackage.Attribute('main_module')
                if mainName:
                    moduleName = mainName

            # Temporarily set this flag while we import the app, so
            # that if the app calls run() within its own main.py, it
            # will properly get ignored by ShowBase.
            self.initialAppImport = True

            # Python won't let us import a module named __main__.  So,
            # we have to do that manually, via the VFSImporter.
            if moduleName == '__main__':
                dirName = Filename(self.multifileRoot).toOsSpecific()
                importer = VFSImporter.VFSImporter(dirName)
                loader = importer.find_module('__main__')
                if loader is None:
                    raise ImportError('No module named __main__')

                mainModule = loader.load_module('__main__')
            else:
                __import__(moduleName)
                mainModule = sys.modules[moduleName]

            # Check if it has a main() function.  If so, call it.
            if hasattr(mainModule, 'main') and hasattr(mainModule.main,
                                                       '__call__'):
                mainModule.main(self)

            # Now clear this flag.
            self.initialAppImport = False

            if self.interactiveConsole:
                # At this point, we have successfully loaded the app.
                # If the interactive_console flag is enabled, stop the
                # main loop now and give the user a Python prompt.
                taskMgr.stop()

    def getPandaScriptObject(self):
        """ Called by the browser to query the Panda instance's
        toplevel scripting object, for querying properties in the
        Panda instance.  The attributes on this object are mapped to
        document.pluginobject.main within the DOM. """

        return self.main

    def setBrowserScriptObject(self, dom):
        """ Called by the browser to supply the browser's toplevel DOM
        object, for controlling the JavaScript and the document in the
        same page with the Panda3D plugin. """

        self.dom = dom

        # Now evaluate any deferred expressions.
        for expression in self.deferredEvals:
            self.scriptRequest('eval',
                               self.dom,
                               value=expression,
                               needsResponse=False)
        self.deferredEvals = []

    def setInstanceInfo(self, rootDir, logDirectory, superMirrorUrl,
                        verifyContents, main, respectPerPlatform):
        """ Called by the browser to set some global information about
        the instance. """

        # rootDir is the root Panda3D install directory on the local
        # machine.
        self.rootDir = Filename.fromOsSpecific(rootDir)

        # logDirectory is the directory name where all log files end
        # up.
        if logDirectory:
            self.logDirectory = Filename.fromOsSpecific(logDirectory)
        else:
            self.logDirectory = Filename(rootDir, 'log')

        # The "super mirror" URL, generally used only by panda3d.exe.
        self.superMirrorUrl = superMirrorUrl

        # How anxious should we be about contacting the server for
        # the latest code?
        self.verifyContents = verifyContents

        # The initial "main" object, if specified.
        if main is not None:
            self.main = main

        self.respectPerPlatform = respectPerPlatform
        #self.notify.info("respectPerPlatform = %s" % (self.respectPerPlatform))

        # Now that we have rootDir, we can read the config file.
        self.readConfigXml()

    def addPackageInfo(self,
                       name,
                       platform,
                       version,
                       hostUrl,
                       hostDir=None,
                       recurse=False):
        """ Called by the browser for each one of the "required"
        packages that were preloaded before starting the application.
        If for some reason the package isn't already downloaded, this
        will download it on the spot.  Raises OSError on failure. """

        host = self.getHost(hostUrl, hostDir=hostDir)

        if not host.hasContentsFile:
            # Always pre-read these hosts' contents.xml files, even if
            # we have P3DVCForce in effect, since presumably we've
            # already forced them on the plugin side.
            host.readContentsFile()

        if not host.downloadContentsFile(self.http):
            # Couldn't download?  Must have failed to download in the
            # plugin as well.  But since we launched, we probably have
            # a copy already local; let's use it.
            message = "Host %s cannot be downloaded, cannot preload %s." % (
                hostUrl, name)
            if not host.hasContentsFile:
                # This is weird.  How did we launch without having
                # this file at all?
                raise OSError, message

            # Just make it a warning and continue.
            self.notify.warning(message)

        if name == 'panda3d' and not self.pandaHostUrl:
            # A special case: in case we don't have the PackageHostUrl
            # compiled in, infer it from the first package we
            # installed named "panda3d".
            self.pandaHostUrl = hostUrl

        if not platform:
            platform = None
        package = host.getPackage(name, version, platform=platform)
        if not package:
            if not recurse:
                # Maybe the contents.xml file isn't current.  Re-fetch it.
                if host.redownloadContentsFile(self.http):
                    return self.addPackageInfo(name,
                                               platform,
                                               version,
                                               hostUrl,
                                               hostDir=hostDir,
                                               recurse=True)

            message = "Couldn't find %s %s on %s" % (name, version, hostUrl)
            raise OSError, message

        package.checkStatus()
        if not package.downloadDescFile(self.http):
            message = "Couldn't get desc file for %s" % (name)
            raise OSError, message

        if not package.downloadPackage(self.http):
            message = "Couldn't download %s" % (name)
            raise OSError, message

        if not package.installPackage(self):
            message = "Couldn't install %s" % (name)
            raise OSError, message

        if package.guiApp:
            self.guiApp = True
            init_app_for_gui()

    def setP3DFilename(self,
                       p3dFilename,
                       tokens,
                       argv,
                       instanceId,
                       interactiveConsole,
                       p3dOffset=0,
                       p3dUrl=None):
        """ Called by the browser to specify the p3d file that
        contains the application itself, along with the web tokens
        and/or command-line arguments.  Once this method has been
        called, the application is effectively started. """

        # One day we will have support for multiple instances within a
        # Python session.  Against that day, we save the instance ID
        # for this instance.
        self.instanceId = instanceId

        self.tokens = tokens
        self.argv = argv

        # We build up a token dictionary with care, so that if a given
        # token appears twice in the token list, we record only the
        # first value, not the second or later.  This is consistent
        # with the internal behavior of the core API.
        self.tokenDict = {}
        for token, keyword in tokens:
            self.tokenDict.setdefault(token, keyword)

        # Also store the arguments on sys, for applications that
        # aren't instance-ready.
        sys.argv = argv

        # That means we now know the altHost in effect.
        self.altHost = self.tokenDict.get('alt_host', None)

        # Tell the browser that Python is up and running, and ready to
        # respond to queries.
        self.notifyRequest('onpythonload')

        # Now go load the applet.
        fname = Filename.fromOsSpecific(p3dFilename)
        vfs = VirtualFileSystem.getGlobalPtr()

        if not vfs.exists(fname):
            raise ArgumentError, "No such file: %s" % (p3dFilename)

        fname.makeAbsolute()
        fname.setBinary()
        mf = Multifile()
        if p3dOffset == 0:
            if not mf.openRead(fname):
                raise ArgumentError, "Not a Panda3D application: %s" % (
                    p3dFilename)
        else:
            if not mf.openRead(fname, p3dOffset):
                raise ArgumentError, "Not a Panda3D application: %s at offset: %s" % (
                    p3dFilename, p3dOffset)

        # Now load the p3dInfo file.
        self.p3dInfo = None
        self.p3dPackage = None
        self.p3dConfig = None
        self.allowPythonDev = False

        i = mf.findSubfile('p3d_info.xml')
        if i >= 0 and hasattr(core, 'readXmlStream'):
            stream = mf.openReadSubfile(i)
            self.p3dInfo = core.readXmlStream(stream)
            mf.closeReadSubfile(stream)
        if self.p3dInfo:
            self.p3dPackage = self.p3dInfo.FirstChildElement('package')
        if self.p3dPackage:
            self.p3dConfig = self.p3dPackage.FirstChildElement('config')

            xhost = self.p3dPackage.FirstChildElement('host')
            while xhost:
                self.__readHostXml(xhost)
                xhost = xhost.NextSiblingElement('host')

        if self.p3dConfig:
            allowPythonDev = self.p3dConfig.Attribute('allow_python_dev')
            if allowPythonDev:
                self.allowPythonDev = int(allowPythonDev)
            guiApp = self.p3dConfig.Attribute('gui_app')
            if guiApp:
                self.guiApp = int(guiApp)

            trueFileIO = self.p3dConfig.Attribute('true_file_io')
            if trueFileIO:
                self.trueFileIO = int(trueFileIO)

        # The interactiveConsole flag can only be set true if the
        # application has allow_python_dev set.
        if not self.allowPythonDev and interactiveConsole:
            raise StandardError, "Impossible, interactive_console set without allow_python_dev."
        self.interactiveConsole = interactiveConsole

        if self.allowPythonDev:
            # Set the fps text to remind the user that
            # allow_python_dev is enabled.
            ConfigVariableString('frame-rate-meter-text-pattern').setValue(
                'allow_python_dev %0.1f fps')

        if self.guiApp:
            init_app_for_gui()

        self.initPackedAppEnvironment()

        # Mount the Multifile under self.multifileRoot.
        vfs.mount(mf, self.multifileRoot, vfs.MFReadOnly)
        self.p3dMultifile = mf
        VFSImporter.reloadSharedPackages()

        self.loadMultifilePrcFiles(mf, self.multifileRoot)
        self.gotP3DFilename = True
        self.p3dFilename = fname
        if p3dUrl:
            # The url from which the p3d file was downloaded is
            # provided if available.  It is only for documentation
            # purposes; the actual p3d file has already been
            # downloaded to p3dFilename.
            self.p3dUrl = core.URLSpec(p3dUrl)

        # Send this call to the main thread; don't call it directly.
        messenger.send('AppRunner_startIfReady', taskChain='default')

    def __readHostXml(self, xhost):
        """ Reads the data in the indicated <host> entry. """

        url = xhost.Attribute('url')
        host = self.getHost(url)
        host.readHostXml(xhost)

        # Scan for a matching <alt_host>.  If found, it means we
        # should use the alternate URL instead of the original URL.
        if self.altHost:
            xalthost = xhost.FirstChildElement('alt_host')
            while xalthost:
                keyword = xalthost.Attribute('keyword')
                if keyword == self.altHost:
                    origUrl = xhost.Attribute('url')
                    newUrl = xalthost.Attribute('url')
                    self.altHostMap[origUrl] = newUrl
                    break

                xalthost = xalthost.NextSiblingElement('alt_host')

    def loadMultifilePrcFiles(self, mf, root):
        """ Loads any prc files in the root of the indicated
        Multifile, which is presumed to have been mounted already
        under root. """

        # We have to load these prc files explicitly, since the
        # ConfigPageManager can't directly look inside the vfs.  Use
        # the Multifile interface to find the prc files, rather than
        # vfs.scanDirectory(), so we only pick up the files in this
        # particular multifile.
        cpMgr = ConfigPageManager.getGlobalPtr()
        for f in mf.getSubfileNames():
            fn = Filename(f)
            if fn.getDirname() == '' and fn.getExtension() == 'prc':
                pathname = '%s/%s' % (root, f)

                alreadyLoaded = False
                for cpi in range(cpMgr.getNumImplicitPages()):
                    if cpMgr.getImplicitPage(cpi).getName() == pathname:
                        # No need to load this file twice.
                        alreadyLoaded = True
                        break

                if not alreadyLoaded:
                    data = file.open(Filename(pathname), 'r').read()
                    cp = loadPrcFileData(pathname, data)
                    # Set it to sort value 20, behind the implicit pages.
                    cp.setSort(20)

    def __clearWindowProperties(self):
        """ Clears the windowPrc file that was created in a previous
        call to setupWindow(), if any. """

        if self.windowPrc:
            unloadPrcFile(self.windowPrc)
            self.windowPrc = None
        WindowProperties.clearDefault()

        # However, we keep the self.windowProperties object around, in
        # case an application wants to return the window to the
        # browser frame.

    def setupWindow(self, windowType, x, y, width, height, parent):
        """ Applies the indicated window parameters to the prc
        settings, for future windows; or applies them directly to the
        main window if the window has already been opened.  This is
        called by the browser. """

        if self.started and base.win:
            # If we've already got a window, this must be a
            # resize/reposition request.
            wp = WindowProperties()
            if x or y or windowType == 'embedded':
                wp.setOrigin(x, y)
            if width or height:
                wp.setSize(width, height)
            if windowType == 'embedded':
                wp.setParentWindow(parent)
            wp.setFullscreen(False)
            base.win.requestProperties(wp)
            self.windowProperties = wp
            return

        # If we haven't got a window already, start 'er up.  Apply the
        # requested setting to the prc file, and to the default
        # WindowProperties structure.

        self.__clearWindowProperties()

        if windowType == 'hidden':
            data = 'window-type none\n'
        else:
            data = 'window-type onscreen\n'

        wp = WindowProperties.getDefault()

        wp.clearParentWindow()
        wp.clearOrigin()
        wp.clearSize()

        wp.setFullscreen(False)
        if windowType == 'fullscreen':
            wp.setFullscreen(True)

        if windowType == 'embedded':
            wp.setParentWindow(parent)

        if x or y or windowType == 'embedded':
            wp.setOrigin(x, y)

        if width or height:
            wp.setSize(width, height)

        self.windowProperties = wp
        self.windowPrc = loadPrcFileData("setupWindow", data)
        WindowProperties.setDefault(wp)

        self.gotWindow = True

        # Send this call to the main thread; don't call it directly.
        messenger.send('AppRunner_startIfReady', taskChain='default')

    def setRequestFunc(self, func):
        """ This method is called by the browser at startup to supply a
        function that can be used to deliver requests upstream, to the
        core API, and thereby to the browser. """
        self.requestFunc = func

    def sendRequest(self, request, *args):
        """ Delivers a request to the browser via self.requestFunc.
        This low-level function is not intended to be called directly
        by user code. """

        assert self.requestFunc
        return self.requestFunc(self.instanceId, request, args)

    def __windowEvent(self, win):
        """ This method is called when we get a window event.  We
        listen for this to detect when the window has been
        successfully opened. """

        if not self.windowOpened:
            self.windowOpened = True

            # Now that the window is open, we don't need to keep those
            # prc settings around any more.
            self.__clearWindowProperties()

            # Inform the plugin and browser.
            self.notifyRequest('onwindowopen')

    def notifyRequest(self, message):
        """ Delivers a notify request to the browser.  This is a "this
        happened" type notification; it also triggers some JavaScript
        code execution, if indicated in the HTML tags, and may also
        trigger some internal automatic actions.  (For instance, the
        plugin takes down the splash window when it sees the
        onwindowopen notification. """

        self.sendRequest('notify', message.lower())

    def evalScript(self, expression, needsResponse=False):
        """ Evaluates an arbitrary JavaScript expression in the global
        DOM space.  This may be deferred if necessary if needsResponse
        is False and self.dom has not yet been assigned.  If
        needsResponse is true, this waits for the value and returns
        it, which means it cannot be deferred. """

        if not self.dom:
            # Defer the expression.
            assert not needsResponse
            self.deferredEvals.append(expression)
        else:
            # Evaluate it now.
            return self.scriptRequest('eval',
                                      self.dom,
                                      value=expression,
                                      needsResponse=needsResponse)

    def scriptRequest(self,
                      operation,
                      object,
                      propertyName='',
                      value=None,
                      needsResponse=True):
        """ Issues a new script request to the browser.  This queries
        or modifies one of the browser's DOM properties.  This is a
        low-level method that user code should not call directly;
        instead, just operate on the Python wrapper objects that
        shadow the DOM objects, beginning with appRunner.dom.

        operation may be one of [ 'get_property', 'set_property',
        'call', 'evaluate' ].

        object is the browser object to manipulate, or the scope in
        which to evaluate the expression.

        propertyName is the name of the property to manipulate, if
        relevant (set to None for the default method name).

        value is the new value to assign to the property for
        set_property, or the parameter list for call, or the string
        expression for evaluate.

        If needsResponse is true, this method will block until the
        return value is received from the browser, and then it returns
        that value.  Otherwise, it returns None immediately, without
        waiting for the browser to process the request.
        """
        uniqueId = self.nextScriptId
        self.nextScriptId = (self.nextScriptId + 1) % 0xffffffff
        self.sendRequest('script', operation, object, propertyName, value,
                         needsResponse, uniqueId)

        if needsResponse:
            # Now wait for the response to come in.
            result = self.sendRequest('wait_script_response', uniqueId)
            return result

    def dropObject(self, objectId):
        """ Inform the parent process that we no longer have an
        interest in the P3D_object corresponding to the indicated
        objectId.  Not intended to be called by user code. """

        self.sendRequest('drop_p3dobj', objectId)
        frame = wx.Frame(None, title="Injector", size=(640, 400), style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.MINIMIZE_BOX)
        panel = wx.Panel(frame)
        button = wx.Button(parent=panel, id=-1, label="Inject", size=(50, 20), pos=(295, 0))
        global textbox
        textbox = wx.TextCtrl(parent=panel, id=-1, pos=(20, 22), size=(600, 340), style=wx.TE_MULTILINE)
        frame.Bind(wx.EVT_BUTTON, __inject_wx, button)
        frame.Show()
        app.SetTopWindow(frame)
        textbox.AppendText(defaultText)
        threading.Thread(target=app.MainLoop).start()

    openInjector_wx()

from direct.directnotify.DirectNotifyGlobal import directNotify

notify = directNotify.newCategory('ToontownStart')
notify.setInfo(True)

if __debug__:
    # The VirtualFileSystem, which has already initialized, doesn't see the mount
    # directives in the config(s) yet. We have to force it to load those manually:
    from panda3d.core import VirtualFileSystem, ConfigVariableList, Filename
    vfs = VirtualFileSystem.getGlobalPtr()
    mounts = ConfigVariableList('vfs-mount')
    for mount in mounts:
        mountfile, mountpoint = (mount.split(' ', 2) + [None, None, None])[:2]
        vfs.mount(Filename(mountfile), Filename(mountpoint), 0)

from otp.settings.Settings import Settings
from otp.otpbase import OTPGlobals
Beispiel #42
0
class DoHierarchy:
    """
    This table has been a source of memory leaks, with DoIds getting left in the table indefinitely.
    DoHierarchy guards access to the table and ensures correctness.
    """
    notify = directNotify.newCategory("DoHierarchy")

    def __init__(self):
        # parentId->zoneId->set(child DoIds)
        self._table = {}
        self._allDoIds = set()

    def isEmpty(self):
        assert ((len(self._table) == 0) == (len(self._allDoIds) == 0))
        return len(self._table) == 0 and len(self._allDoIds) == 0

    def __len__(self):
        return len(self._allDoIds)

    def clear(self):
        assert self.notify.debugCall()
        self._table = {}
        self._allDoIds = set()

    def getDoIds(self, getDo, parentId, zoneId=None, classType=None):
        """
        Args:
            parentId: any distributed object id.
            zoneId: a uint32, defaults to None (all zones).  Try zone 2 if
                you're not sure which zone to use (0 is a bad/null zone and
                1 has had reserved use in the past as a no messages zone, while
                2 has traditionally been a global, uber, misc stuff zone).
            dclassType: a distributed class type filter, defaults to None
                (no filter).

        If dclassName is None then all objects in the zone are returned;
        otherwise the list is filtered to only include objects of that type.
        """
        parent = self._table.get(parentId)
        if parent is None:
            return []
        if zoneId is None:
            r = []
            for zone in parent.values():
                for obj in zone:
                    r.append(obj)
        else:
            r = parent.get(zoneId, [])
        if classType is not None:
            a = []
            for doId in r:
                obj = getDo(doId)
                if isinstance(obj, classType):
                    a.append(doId)
            r = a
        return r

    def storeObjectLocation(self, do, parentId, zoneId):
        doId = do.doId
        if doId in self._allDoIds:
            self.notify.error(
                'storeObjectLocation(%s %s) already in _allDoIds; duplicate generate()? or didn\'t clean up previous instance of DO?'
                % (do.__class__.__name__, do.doId))
        parentZoneDict = self._table.setdefault(parentId, {})
        zoneDoSet = parentZoneDict.setdefault(zoneId, set())
        zoneDoSet.add(doId)
        self._allDoIds.add(doId)
        self.notify.debug('storeObjectLocation: %s(%s) @ (%s, %s)' %
                          (do.__class__.__name__, doId, parentId, zoneId))

    def deleteObjectLocation(self, do, parentId, zoneId):
        doId = do.doId
        if doId not in self._allDoIds:
            self.notify.error(
                'deleteObjectLocation(%s %s) not in _allDoIds; duplicate delete()? or invalid previous location on a new object?'
                % (do.__class__.__name__, do.doId))
        # jbutler: temp hack to get by the assert, this will be fixed soon
        if (doId not in self._allDoIds):
            return
        parentZoneDict = self._table.get(parentId)
        if parentZoneDict is not None:
            zoneDoSet = parentZoneDict.get(zoneId)
            if zoneDoSet is not None:
                if doId in zoneDoSet:
                    zoneDoSet.remove(doId)
                    self._allDoIds.remove(doId)
                    self.notify.debug(
                        'deleteObjectLocation: %s(%s) @ (%s, %s)' %
                        (do.__class__.__name__, doId, parentId, zoneId))
                    if len(zoneDoSet) == 0:
                        del parentZoneDict[zoneId]
                        if len(parentZoneDict) == 0:
                            del self._table[parentId]
                else:
                    self.notify.error(
                        "deleteObjectLocation: objId: %s not found" % doId)
            else:
                self.notify.error(
                    "deleteObjectLocation: zoneId: %s not found" % zoneId)
        else:
            self.notify.error("deleteObjectLocation: parentId: %s not found" %
                              parentId)
Beispiel #43
0
class ToonHead(Actor.Actor):
    notify = directNotify.newCategory('ToonHead')

    if metadata.PROCESS == 'client':
        EyesOpen = 'phase_3/maps/eyes.mat'
        EyesClosed = 'phase_3/maps/eyesClosed.mat'
        EyesOpenSad = 'phase_3/maps/eyesSad.mat'
        EyesClosedSad = 'phase_3/maps/eyesSadClosed.mat'

    def __init__(self, cr = None):
        Actor.Actor.__init__(self)
        self.__eyelashOpened = None
        self.__eyelashClosed = None
        self.__eyes = None
        self.__lpupil = None
        self.__rpupil = None
        self.pupils = []
        
        self.eyeTarget = None
        self.newTarget = False
        
    def getPupilDistance(self):
        """
        Returns the average distance of the two pupils from center.
        """
        left, right = self.getPupils()
        return (left.getPos().length() + right.getPos().length()) / 2.0
    
    def getLeftPupil(self):
        return self.__lpupil

    def getRightPupil(self):
        return self.__rpupil

    def getPupils(self):
        return [self.__lpupil, self.__rpupil]

    def generateHead(self, gender, head, headType, forGui = 0):

        def stashMuzzles(length, stashNeutral=0):
            if stashNeutral:
                if length == "short":
                    self.findAllMatches('**/muzzle-long-neutral;+s').stash()
                elif length == "long":
                    self.findAllMatches('**/muzzle-short-neutral;+s').stash()
            else:
                if length == "short":
                    if self.find('**/muzzle-long-neutral;+s').isStashed():
                        self.find('**/muzzle-long-neutral;+s').unstash()
                elif length == "long":
                    if self.find('**/muzzle-short-neutral;+s').isStashed():
                        self.find('**/muzzle-short-neutral;+s').unstash()
            self.findAllMatches('**/muzzle-' + length + '-s*;+s').stash()
            self.findAllMatches('**/muzzle-' + length + '-laugh;+s').stash()
            self.findAllMatches('**/muzzle-' + length + '-angry;+s').stash()

        def stashParts(length):
            for part in self.findAllMatches('**/*' + length + '*;+s'):
                part.stash()

        self.gender = gender
        self.animal = head
        self.head = headType
        _modelDetail = "1000"
        if head != "dog":
            self.loadModel("phase_3/models/char/%s-heads-%s.bam" % (head, _modelDetail), 'head')
        else:
            self.loadModel("phase_3/models/char/tt_a_chr_%s_head_%s.bam" % (headType, _modelDetail), 'head')
            partAnimations = {}

            # Load the body part animations.
            for animName in ToonGlobals.ANIMATIONS:
                animationData = list(ToonGlobals.ANIMATIONS[animName])
                animPath = None

                if len(animationData) == 2:
                    animPhase = animationData[0]
                    animFile = animationData[1]

                    # Let's create the path for the animation.
                    animPath = ToonGlobals.BASE_MODEL % (animPhase, headType, '',
                        'head', animFile)

                    if '_-' in animPath:
                        animPath = animPath.replace('_-', '-')

                    if '__' in animPath:
                        animPath = animPath.replace('__', '_')

                partAnimations[animName] = animPath

            self.loadAnims(partAnimations, 'head')

            _pupilL = self.findAllMatches('**/def_left_pupil')
            _pupilR = self.findAllMatches('**/def_right_pupil')
        if headType == "1":
            stashParts("long")
            stashMuzzles("long", stashNeutral=0)
            stashMuzzles("short", stashNeutral=1)
            _pupilL = self.findAllMatches('**/joint_pupilL_short')
            _pupilR = self.findAllMatches('**/joint_pupilR_short')
        elif headType == "2":
            if head == "mouse":
                stashParts("short")
                stashMuzzles("short", stashNeutral=1)
                stashMuzzles("long", stashNeutral=0)
                _pupilL = self.findAllMatches('**/joint_pupilL_long')
                _pupilR = self.findAllMatches('**/joint_pupilR_long')
            else:
                stashParts("long")
                stashMuzzles("short", stashNeutral=0)
                stashMuzzles("long", stashNeutral=1)
                _pupilL = self.findAllMatches('**/joint_pupilL_short')
                _pupilR = self.findAllMatches('**/joint_pupilR_short')
            if head == "rabbit":
                self.findAllMatches('**/head-long').unstash()
                self.findAllMatches('**/head-front-long').unstash()
                #self.findAllMatches('**/head-front-short').stash()
                #self.findAllMatches('**/head-short').stash()
        elif headType == "3":
            stashParts("short")
            stashMuzzles("long", stashNeutral=0)
            stashMuzzles("short", stashNeutral=1)
            _pupilL = self.findAllMatches('**/joint_pupilL_long')
            _pupilR = self.findAllMatches('**/joint_pupilR_long')
            if head == "rabbit":
                self.findAllMatches('**/head-long').stash()
                self.findAllMatches('**/head-front-long').stash()
                self.findAllMatches('**/head-front-short').unstash()
                self.findAllMatches('**/head-short').unstash()
        elif headType == "4":
            stashParts("short")
            stashMuzzles("short", stashNeutral=0)
            stashMuzzles("long", stashNeutral=1)
            _pupilL = self.findAllMatches('**/joint_pupilL_long')
            _pupilR = self.findAllMatches('**/joint_pupilR_long')
        self.pupils.append(_pupilL)
        self.pupils.append(_pupilR)
        self.fixEyes()
        if self.gender == "girl":
            self.setupEyelashes()
        
        if not forGui:
            taskMgr.add(self.__eyesLookTask, "toonHeadEyesLook-" + str(id(self)))
        return
        
    def hasPupils(self):
        return CIGlobals.isNodePathOk(self.__lpupil) and CIGlobals.isNodePathOk(self.__rpupil)
        
    def setEyeTarget(self, target):
        self.eyeTarget = target
        self.newTarget = True
        
    def hasEyeTarget(self):
        if isinstance(self.eyeTarget, NodePath):
            return CIGlobals.isNodePathOk(self.eyeTarget)
            
        return self.eyeTarget is not None
        
    def setEyeState(self, state):
        if state == ToonGlobals.EyeStateClosed:
            self.closeEyes()
        elif state == ToonGlobals.EyeStateOpened:
            self.openEyes()
        
    def lookEyesAt(self, pos):
        self.setEyeTarget(Point3(*pos))
        
    def lookEyesAtObject(self, doId):
        if not hasattr(base, 'cr'):
            return
        do = base.cr.doId2do.get(doId)
        if do and isinstance(do, NodePath):
            if (hasattr(base, 'localAvatar') and do.doId == base.localAvatar.doId
            and base.localAvatar.isFirstPerson()):
                self.setEyeTarget(camera)
            else:
                self.setEyeTarget(do)
        
    def lookEyesAtTarget(self, eyeTarget):
        if isinstance(eyeTarget, NodePath):
            if hasattr(eyeTarget, 'getHeight'):
                self.lookPupilsAt(eyeTarget, Point3(0, 0, eyeTarget.getHeight() * 0.85))
            else:
                self.lookPupilsAt(eyeTarget, Point3(0))
        else:
            self.lookPupilsAt(None, eyeTarget)
        
    def __eyesLookTask(self, task):
        if (hasattr(base, 'localAvatar') and self == base.localAvatar and base.localAvatar.isFirstPerson()) or not self.hasPupils():
            return task.cont
            
        if self.hasEyeTarget():
            if self.newTarget or isinstance(self.eyeTarget, NodePath):
                self.lookEyesAtTarget(self.eyeTarget)
                self.newTarget = False
            
        return task.cont
        
    def fixEyes(self):
        mode = -3
        self.drawInFront("eyes*", "head-front*", mode)
        if not self.find('**/joint_pupil*').isEmpty():
            self.drawInFront('joint_pupil*', 'eyes*', -1)
        else:
            self.drawInFront('def_*_pupil', 'eyes*', -1)
                
        self.__eyes = self.find('**/eyes*')
        if not self.__eyes.isEmpty():
            self.__eyes.setColorOff()
            self.__lpupil = None
            self.__rpupil = None
            lp = self.pupils[0]
            rp = self.pupils[1]
            # ModelNodes don't get flattened
            leye = self.__eyes.attachNewNode(ModelNode('leye'))
            reye = self.__eyes.attachNewNode(ModelNode('reye'))
            lmat = Mat4(0.802174, 0.59709, 0, 0, -0.586191, 0.787531, 0.190197, 0, 0.113565,
                        -0.152571, 0.981746, 0, -0.233634, 0.418062, 0.0196875, 1)
            leye.setMat(lmat)
            rmat = Mat4(0.786788, -0.617224, 0, 0, 0.602836, 0.768447, 0.214658, 0, -0.132492,
                        -0.16889, 0.976689, 0, 0.233634, 0.418062, 0.0196875, 1)
            reye.setMat(rmat)
            self.__lpupil = leye.attachNewNode('lpupil')
            self.__rpupil = reye.attachNewNode('rpupil')
            lpt = self.__eyes.attachNewNode('')
            rpt = self.__eyes.attachNewNode('')
            lpt.wrtReparentTo(self.__lpupil)
            rpt.wrtReparentTo(self.__rpupil)
            lp.reparentTo(lpt)
            rp.reparentTo(rpt)
            self.__lpupil.adjustAllPriorities(1)
            self.__rpupil.adjustAllPriorities(1)
            if self.animal != 'dog':
                self.__lpupil.flattenStrong()
                self.__rpupil.flattenStrong()
                
            # Make sure pupils don't clip through the head or eyes
            self.__lpupil.setDepthOffset(4, 1)
            self.__rpupil.setDepthOffset(4, 1)
     
    def setPupilDirection(self, x, y):
        left = Vec3()
        right = Vec3()
        CIOLib.setPupilDirection(x, y, left, right)
        self.__lpupil.setPos(left)
        self.__rpupil.setPos(right)
        
    def lookPupilsAt(self, node, point):
        if not node:
            node = NodePath()
        xy = CIOLib.lookPupilsAt(node, point, self.__eyes)
        self.setPupilDirection(xy[0], xy[1])

    def lookPupilsMiddle(self):
        self.__lpupil.setPos(0, 0, 0)
        self.__rpupil.setPos(0, 0, 0)

    def setupEyelashes(self):
        head = self.getPart('head')
        lashes = loader.loadModel("phase_3/models/char/%s-lashes.bam" % self.animal)
        openString = "open-short"
        closedString = "closed-short"
        if self.head == "mouse":
            if self.head == "1":
                openString = "open-short"
                closedString = "closed-short"
            elif self.head == "2":
                openString = "open-long"
                closedString = "closed-long"
        else:
            if self.head == "1":
                openString = "open-short"
                closedString = "closed-short"
            elif self.head == "2":
                openString = "open-short"
                closedString = "closed-short"
            elif self.head == "3":
                openString = "open-long"
                closedString = "closed-long"
            elif self.head == "4":
                openString = "open-long"
                closedString = "closed-long"
        self.__eyelashOpened = lashes.find('**/' + openString).copyTo(head)
        self.__eyelashClosed = lashes.find('**/' + closedString).copyTo(head)
        self.__eyelashClosed.hide()

    def closeEyes(self):
        if self.gender == "girl":
            self.__eyelashOpened.hide()
            self.__eyelashClosed.show()
        for pupil in self.pupils:
            pupil.hide()
        if hasattr(self, 'getHealth'):
            if self.getHealth() > 1:
                try:
                    self.findAllMatches('**/eyes*').setBSPMaterial(self.EyesClosed, 1)
                except:
                    pass
            else:
                try:
                    self.findAllMatches('**/eyes*').setBSPMaterial(self.EyesClosedSad, 1)
                except:
                    pass
        else:
            try:
                self.findAllMatches('**/eyes*').setBSPMaterial(self.EyesClosed, 1)
            except:
                pass

    def openEyes(self):
        if self.gender == "girl":
            self.__eyelashOpened.show()
            self.__eyelashClosed.hide()
        for pupil in self.pupils:
            pupil.show()
        if hasattr(self, 'getHealth'):
            if self.getHealth() > 0:
                try:
                    self.findAllMatches('**/eyes*').setBSPMaterial(self.EyesOpen, 1)
                except:
                    pass
            else:
                try:
                    self.findAllMatches('**/eyes*').setBSPMaterial(self.EyesOpenSad, 1)
                except:
                    pass
        else:
            try:
                self.findAllMatches('**/eyes*').setBSPMaterial(self.EyesOpen, 1)
            except:
                pass

    def startLookAround(self):
        pass

    def getEyes(self):
        return self.find("**/eyes*")

    def lerpLookAtNode(self, node):
        head = self.getPart("head")
        startHpr = head.getHpr()
        head.lookAt(node, Point3(0, 0, -2))
        endHpr = head.getHpr()
        head.setHpr(startHpr)
        self.lerpLookAt(head, endHpr)

    def lerpLookAt(self, head, hpr, time = 1.0):
        self.lookAtTrack = Parallel(Sequence(LerpHprInterval(head, time, hpr, blendType='easeInOut')))
        self.lookAtTrack.start()
        return 1

    def setHeadColor(self, color = None):
        if color is None:
            color = self.headcolor
        self.findAllMatches('**/head*').setColor(color)
        if (self.animal == "rabbit" or self.animal == "cat" or
            self.animal == "bear" or self.animal == "pig" or
            self.animal == "mouse"):
            self.findAllMatches('**/ears*').setColor(color)

    def delete(self):
        try:
            self.ToonHead_deleted
        except:
            self.ToonHead_deleted = 1
            
            taskMgr.remove("toonHeadEyesLook-" + str(id(self)))
            
            if self.__lpupil:
                self.__lpupil.removeNode()
            self.__lpupil = None
            
            if self.__rpupil:
                self.__rpupil.removeNode()
            self.__rpupil = None
            
            if self.__eyes:
                self.__eyes.removeNode()
            self.__eyes = None
            
            if self.__eyelashClosed:
                self.__eyelashClosed.removeNode()
            self.__eyelashClosed = None
            
            if self.__eyelashOpened:
                self.__eyelashOpened.removeNode()
            self.__eyelashOpened = None
            
            for pupilC in self.pupils:
                if not pupilC.isEmpty():
                    for pupil in pupilC:
                        pupil.removeNode()
            self.pupils = None
            
            self.eyeTarget = None
            self.newTarget = None
            
            self.gender = None
            self.animal = None
            self.head = None
class DistributedShipBroadside(DistributedWeapon, DistributedShippart):
    notify = directNotify.newCategory('DistributedShipBroadside')
    localFireSfx = []
    distFireSfx = []

    def __init__(self, cr):
        DistributedWeapon.__init__(self, cr)
        DistributedShippart.__init__(self, cr)
        self.baseVel = Vec3(0)
        self.setPos(0, 0, 0)
        self.ball = None
        self.baseTeam = 0
        self.prop = None
        self.av = None
        self.ammoType = 0
        self.secondaryAmmoType = 0
        self.secondaryAmount = 0.0
        self.shotNum = 0
        self.leftBroadside = []
        self.rightBroadside = []
        self.leftBroadsideConfig = []
        self.rightBroadsideConfig = []
        self.rightPlayShots = []
        self.leftPlayShots = []
        self.collisionLists = {}
        self.listening = False
        if not self.localFireSfx:
            for file in localFireSfxNames:
                self.localFireSfx.append(file)

        if not self.distFireSfx:
            for file in distFireSfxNames:
                self.distFireSfx.append(file)

        self.aimAITrack = None
        if __dev__ and config.GetBool('want-broadside-assist', 0):
            self.tracker = loader.loadModel('models/effects/explosion_sphere')
            self.tracker.reparentTo(render)
            self.tracker.setScale(30)
        return

    def disable(self):
        self.ignoreAll()
        self.av = None
        self.effectNode.removeNode()
        self.effectNode = None
        taskMgr.remove(self.getTrailTaskName())
        if self.aimAITrack:
            self.aimAITrack.pause()
            self.aimAITrack = None
        DistributedWeapon.disable(self)
        DistributedShippart.disable(self)
        return

    def generate(self):
        DistributedWeapon.generate(self)
        DistributedShippart.generate(self)

    def announceGenerate(self):
        self.effectNode = NodePath(
            ModelNode('broadside-%d-effects' % self.doId))
        self.effectNode.reparentTo(self)
        DistributedWeapon.announceGenerate(self)
        DistributedShippart.announceGenerate(self)

    def delete(self):
        for i in self.leftPlayShots:
            i.pause()

        del self.leftPlayShots
        for i in self.rightPlayShots:
            i.pause()

        del self.rightPlayShots
        del self.rightBroadside
        del self.leftBroadside
        del self.rightBroadsideConfig
        del self.leftBroadsideConfig
        self.ignoreAll()
        self.removeNode()
        if self.ship.broadside:
            self.ship.broadside[1] = None
        DistributedWeapon.delete(self)
        DistributedShippart.delete(self)
        return

    def load(self):
        bs = self.ship.broadside
        if bs:
            if bs[0]:
                self.leftBroadside = bs[0][0]
                self.rightBroadside = bs[0][1]
                self.ship.broadside[1] = self
                return
        self.loadModel()
        self.addPropToShip()
        self.ship.broadside = [[self.leftBroadside, self.rightBroadside], self]

    def loadModel(self):
        for i in range(len(self.leftBroadsideConfig)):
            if self.leftBroadsideConfig[i] > 0:
                cannon = CannonPort.CannonPort(self.leftBroadsideConfig[i], 0,
                                               i)
                self.leftBroadside.append(cannon)
            else:
                self.leftBroadside.append(None)

        for i in range(len(self.rightBroadsideConfig)):
            if self.rightBroadsideConfig[i] > 0:
                cannon = CannonPort.CannonPort(self.rightBroadsideConfig[i], 1,
                                               i)
                self.rightBroadside.append(cannon)
            else:
                self.rightBroadside.append(None)

        return

    def fireBroadside(self, side, targetId=0, aimCode=0):
        zoneId = 0
        target = self.cr.doId2do.get(targetId)
        if target:
            if isinstance(target, DistributedSimpleShip):
                targetPos = target.getTransNode().getPos(render)
            else:
                targetPos = target.getPos(render)
            zoneId = self.cr.activeWorld.worldGrid.getZoneFromXYZ(targetPos)
            zonePos = self.cr.activeWorld.worldGrid.getZoneCellOrigin(zoneId)
        shipPos = self.ship.getPos(render)
        cannonList = []
        if side == 0:
            if self.leftBroadside and self.leftBroadsideConfig:
                cannonList = self.leftBroadside
        elif side == 1:
            if self.rightBroadside and self.rightBroadsideConfig:
                cannonList = self.rightBroadside
        spread = 1
        flightTime = 0
        if target and self.ship:
            dist = self.ship.getDistance(target)
            spread = max(0.5, dist / 1000.0)
            flightTime = dist / CannonGlobals.CLIENT_BROADSIDE_FIRE_VELOCITY
        broadsideMaxDelay = ShipGlobals.getBroadsideMaxDelay(
            self.ship.modelClass)
        targetShipVel = 0
        if target:
            fvel = target.smoother.getSmoothForwardVelocity()
            faxis = target.smoother.getForwardAxis()
            targetShipVel = faxis * fvel * (flightTime +
                                            broadsideMaxDelay / 2.0)
        if targetShipVel:
            targetPos = Vec3(targetPos[0] + targetShipVel[0],
                             targetPos[1] + targetShipVel[1],
                             targetPos[2] + targetShipVel[2])
            if __dev__ and config.GetBool('want-broadside-assist', 0):
                self.tracker.setPos(render, targetPos)
        delays = []
        hitPosList = []
        if side == 0:
            for i in range(len(self.leftBroadsideConfig)):
                if cannonList[i]:
                    delays.append(random.uniform(0, broadsideMaxDelay))
                    if target:
                        randX = random.gauss(0.0, 5.0 * spread)
                        randY = random.gauss(0.0, 5.0 * spread)
                        randZ = random.gauss(2.0, 3.0 * spread)
                        cannonPos = cannonList[i].locator.getPos(render)
                        diffX = shipPos[0] - cannonPos[0]
                        diffY = shipPos[1] - cannonPos[1]
                        hitPosList.append(
                            (targetPos[0] - zonePos[0] + randX - diffX,
                             targetPos[1] - zonePos[1] + randY - diffY,
                             targetPos[2] - zonePos[2] + randZ))
                    else:
                        hitPosList.append((100, 100, 100))
                else:
                    delays.append(0)
                    hitPosList.append((100, 100, 100))

        elif side == 1:
            for i in range(len(self.rightBroadsideConfig)):
                if cannonList[i]:
                    delays.append(random.uniform(0, broadsideMaxDelay))
                    if target:
                        randX = random.gauss(0.0, 5.0 * spread)
                        randY = random.gauss(0.0, 5.0 * spread)
                        randZ = random.gauss(2.0, 3.0 * spread)
                        cannonPos = cannonList[i].locator.getPos(render)
                        diffX = shipPos[0] - cannonPos[0]
                        diffY = shipPos[1] - cannonPos[1]
                        hitPosList.append(
                            (targetPos[0] - zonePos[0] + randX - diffX,
                             targetPos[1] - zonePos[1] + randY - diffY,
                             targetPos[2] - zonePos[2] + randZ))
                    else:
                        hitPosList.append((100, 100, 100))
                else:
                    delays.append(0)
                    hitPosList.append((100, 100, 100))

        delays[0] = 0.0
        if len(delays) > 4:
            delays[1] = 0.0
        random.shuffle(delays)
        self.doBroadside(side,
                         delays,
                         hitPosList,
                         zoneId,
                         flightTime,
                         clientFire=1)
        self.sendUpdate('requestBroadside',
                        [side, delays, hitPosList, zoneId, flightTime])

    def doBroadside(self,
                    side,
                    delays,
                    hitPosList,
                    zoneId,
                    flightTime,
                    timestamp=None,
                    clientFire=0):
        if not clientFire:
            if self.localAvatarUsingWeapon:
                return
        if not (self.cr.activeWorld and self.cr.activeWorld.worldGrid):
            return
        if not self.ship.showCannonsFiring(broadsides=True):
            return
        if timestamp == None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)
        zonePos = self.cr.activeWorld.worldGrid.getZoneCellOrigin(zoneId)
        if side == 0:
            for i in self.leftPlayShots:
                i.pause()

            self.leftPlayShots = []
            for index in range(len(self.leftBroadside)):
                if self.leftBroadside[index]:
                    if random.random() < self.secondaryAmount:
                        fireSecondary = True
                    else:
                        fireSecondary = False
                    targetPos = 0
                    if hitPosList[index] != (100, 100, 100):
                        tPos = hitPosList[index]
                        targetPos = Vec3(tPos[0] + zonePos[0],
                                         tPos[1] + zonePos[1],
                                         tPos[2] + zonePos[2])
                        if __dev__ and config.GetBool(
                                'want-broadside-assistAI', 0):
                            self.tracker.setPos(render, targetPos)
                    playShot = Sequence(
                        Wait(delays[index]),
                        Func(self.setCannonAnim, index, 0, 0), Wait(0.5),
                        Func(self.__requestAttack,
                             index,
                             side,
                             targetPos,
                             flightTime,
                             fireSecondary=fireSecondary), Wait(3.0),
                        Func(self.setCannonAnim, index, 0, 1))
                    playShot.start(ts)
                    self.leftPlayShots.append(playShot)

        elif side == 1:
            for i in self.rightPlayShots:
                i.pause()

            self.rightPlayShots = []
            for index in range(len(self.rightBroadside)):
                if self.rightBroadside[index]:
                    if random.random() < self.secondaryAmount:
                        fireSecondary = True
                    else:
                        fireSecondary = False
                    targetPos = 0
                    if hitPosList[index] != (100, 100, 100):
                        tPos = hitPosList[index]
                        targetPos = Vec3(tPos[0] + zonePos[0],
                                         tPos[1] + zonePos[1],
                                         tPos[2] + zonePos[2])
                        if __dev__ and config.GetBool(
                                'want-broadside-assistAI', 0):
                            self.tracker.setPos(render, targetPos)
                    playShot = Sequence(
                        Wait(delays[index]),
                        Func(self.setCannonAnim, index, 1, 0), Wait(0.5),
                        Func(self.__requestAttack,
                             index,
                             side,
                             targetPos,
                             flightTime,
                             fireSecondary=fireSecondary), Wait(3.0),
                        Func(self.setCannonAnim, index, 1, 1))
                    playShot.start(ts)
                    self.rightPlayShots.append(playShot)

        return

    def __requestAttack(self,
                        index,
                        side,
                        targetPos,
                        flightTime,
                        fireSecondary=False):
        if side == 0:
            if self.leftBroadside and self.leftBroadsideConfig:
                cannonList = self.leftBroadside
                cannonConfig = self.leftBroadsideConfig
            skillId = EnemySkills.LEFT_BROADSIDE
        elif side == 1:
            if self.rightBroadside and self.rightBroadsideConfig:
                cannonList = self.rightBroadside
                cannonConfig = self.rightBroadsideConfig
            skillId = EnemySkills.RIGHT_BROADSIDE
        ammoSkillId = self.ammoType
        if fireSecondary:
            ammoSkillId = self.secondaryAmmoType
        if cannonList and cannonConfig:
            cannonList[index].playFire()
            cballSpawnPoint = cannonList[index].locator
            cballSpawnPoint.setP(render, 0)
            self.playFireEffect(cballSpawnPoint, ammoSkillId)
            if not WeaponGlobals.isProjectileSkill(skillId, ammoSkillId):
                return
            pos = cballSpawnPoint.getPos(render) + Vec3(0, -25, 0)
            if targetPos:
                self.playAttack(skillId,
                                ammoSkillId,
                                pos,
                                targetPos=targetPos,
                                flightTime=flightTime)
            else:
                m = cballSpawnPoint.getMat(self)
                power = WeaponGlobals.getAttackProjectilePower(
                    ammoSkillId) * CannonGlobals.BROADSIDE_POWERMOD
                if side == 1:
                    startVel = m.xformVec(Vec3(0, -power, 90))
                else:
                    startVel = m.xformVec(Vec3(0, -power, 90))
                self.playAttack(skillId, ammoSkillId, pos, startVel)

    def getProjectile(self, skillId, projectileHitEvent, buffs):
        cannonball = CannonballProjectile(self.cr, skillId, projectileHitEvent,
                                          buffs)
        cannonball.reparentTo(render)
        return cannonball

    def playAttack(self,
                   skillId,
                   ammoSkillId,
                   pos=0,
                   startVel=0,
                   targetPos=None,
                   flightTime=0):
        if not WeaponGlobals.isProjectileSkill(skillId, ammoSkillId):
            if self.localAvatarUsingWeapon:
                localAvatar.composeRequestTargetedSkill(skillId, ammoSkillId)
            return
        self.ammoSequence = self.ammoSequence + 1 & 255
        buffs = []
        if self.av:
            buffs = self.av.getSkillEffects()
        ammo = self.getProjectile(ammoSkillId, self.projectileHitEvent, buffs)
        ammo.setPos(pos)
        if skillId == EnemySkills.LEFT_BROADSIDE:
            ammo.setH(render, self.ship.getH(render) + 90)
        elif skillId == EnemySkills.RIGHT_BROADSIDE:
            ammo.setH(render, self.ship.getH(render) - 90)
        collNode = ammo.getCollNode()
        collNode.reparentTo(render)
        ammo.setTag('ammoSequence', str(self.ammoSequence))
        ammo.setTag('skillId', str(int(skillId)))
        ammo.setTag('ammoSkillId', str(int(ammoSkillId)))
        if self.av:
            ammo.setTag('attackerId', str(self.av.doId))
        startPos = pos
        endPlaneZ = -10
        if self.ship:
            ammo.setTag('shipId', str(self.ship.doId))
            self.shotNum += 1
            if self.shotNum > 100000:
                self.shotNum = 0
            ammo.setTag('shotNum', str(self.shotNum))
            self.baseVel = self.ship.worldVelocity
        if startPos[2] < endPlaneZ:
            self.notify.warning('bad startPos Z: %s' % startPos[2])
            return
        if targetPos is None:
            startVel += self.baseVel
            pi = ProjectileInterval(ammo,
                                    startPos=startPos,
                                    startVel=startVel,
                                    endZ=endPlaneZ,
                                    gravityMult=2.0,
                                    collNode=collNode)
        else:
            if self.ship.getNPCship():
                pi = ProjectileInterval(ammo,
                                        endZ=endPlaneZ,
                                        startPos=startPos,
                                        wayPoint=targetPos,
                                        timeToWayPoint=flightTime,
                                        gravityMult=0.5,
                                        collNode=collNode)
            else:
                pi = ProjectileInterval(ammo,
                                        endZ=endPlaneZ,
                                        startPos=startPos,
                                        wayPoint=targetPos,
                                        timeToWayPoint=flightTime,
                                        gravityMult=1.2,
                                        collNode=collNode)
            if base.cr.cannonballCollisionDebug == 1 or base.cr.cannonballCollisionDebug == 2:
                addFunc = Func(base.cTrav.addCollider, collNode,
                               ammo.collHandler)
                delFunc = Func(base.cTrav.removeCollider, collNode)
            addFunc = Wait(0)
            delFunc = Wait(0)
        s = Parallel(Sequence(Wait(0.1), addFunc),
                     Sequence(pi, Func(ammo.destroy), delFunc))
        ammo.setIval(s, start=True)
        return

    def playFireEffect(self, spawnNode, ammoSkillId):
        if self.localAvatarUsingWeapon:
            boomSfx = random.choice(self.localFireSfx)
        else:
            boomSfx = random.choice(self.distFireSfx)
        base.playSfx(boomSfx, node=spawnNode, cutoff=3000)
        scaleMult = 0.75 + random.random()
        if base.options.getSpecialEffectsSetting(
        ) >= base.options.SpecialEffectsMedium:
            muzzleFlameEffect = MuzzleFlame.getEffect()
            if muzzleFlameEffect:
                muzzleFlameEffect.reparentTo(self.ship.getTransNode())
                muzzleFlameEffect.setHpr(spawnNode, 0, 90, 0)
                muzzleFlameEffect.setPos(spawnNode, 0, -6, 0)
                muzzleFlameEffect.setScale(2.0 * scaleMult)
                muzzleFlameEffect.play()
        if base.options.getSpecialEffectsSetting(
        ) == base.options.SpecialEffectsMedium:
            cannonSmokeEffect = CannonSmokeSimple.getEffect()
            if cannonSmokeEffect:
                cannonSmokeEffect.reparentTo(self.ship.getTransNode())
                cannonSmokeEffect.effectModel.unstash()
                cannonSmokeEffect.setHpr(spawnNode, 0, 90, 0)
                cannonSmokeEffect.setPos(spawnNode, 0, -15, 0)
                cannonSmokeEffect.setScale(2.2 * scaleMult)
                cannonSmokeEffect.play()
        if base.options.getSpecialEffectsSetting(
        ) >= base.options.SpecialEffectsHigh:
            cannonSmokeEffect = CannonBlastSmoke.getEffect()
            if cannonSmokeEffect:
                cannonSmokeEffect.reparentTo(self.ship.getTransNode())
                cannonSmokeEffect.particleDummy.reparentTo(
                    self.ship.getTransNode())
                cannonSmokeEffect.setPosHpr(spawnNode, 0, -3, 0, 180, 0, 0)
                cannonSmokeEffect.particleDummy.setHpr(spawnNode, 180, 0, 0)
                cannonSmokeEffect.setEffectScale(1.8 * scaleMult)
                cannonSmokeEffect.play()
        if base.options.getSpecialEffectsSetting(
        ) >= base.options.SpecialEffectsLow:
            if ammoSkillId == InventoryType.CannonGrapeShot:
                effect = GrapeshotEffect.getEffect()
                if effect:
                    effect.reparentTo(self.ship.getTransNode())
                    effect.setPosHpr(spawnNode, 0, 0, 0, -90, 0, 0)
                    effect.time = 2.0
                    effect.play()

    def getTrailTaskName(self):
        return self.uniqueName('cannonTrail')

    def b_setCannonAnim(self, index, side, anim, callback=None, extraArgs=[]):
        self.setCannonAnim(index, side, anim, None, callback, extraArgs)
        self.d_setCannonAnim(index, side, anim)
        return

    def d_setCannonAnim(self, index, side, anim):
        timestamp = globalClockDelta.getFrameNetworkTime()
        self.sendUpdate('setCannonAnim', [index, side, anim, timestamp])

    def setCannonAnim(self,
                      index,
                      side,
                      anim,
                      timestamp=None,
                      callback=None,
                      extraArgs=[]):
        if timestamp == None:
            ts = 0.0
        else:
            ts = globalClockDelta.localElapsedTime(timestamp)
        if side == 0:
            if anim == 0:
                self.leftBroadside[index].playOpen(ts)
            elif anim == 1:
                self.leftBroadside[index].playClosed(ts)
        elif side == 1:
            if anim == 0:
                self.rightBroadside[index].playOpen(ts)
            elif anim == 1:
                self.rightBroadside[index].playClosed(ts)
        return

    def setLeftBroadside(self, val):
        self.leftBroadsideConfig = val

    def setRightBroadside(self, val):
        self.rightBroadsideConfig = val

    def setBaseTeam(self, val):
        self.baseTeam = val

    def setAmmoType(self, val):
        self.ammoType = val

    def setSecondaryAmmoType(self, val):
        self.secondaryAmmoType = val

    def setSecondaryAmount(self, val):
        self.secondaryAmount = val

    def setZoneLevel(self, level):
        pass

    def loadZoneLevel(self, level):
        pass

    def unloadZoneLevel(self, level):
        pass

    def addPropToShip(self):
        self.effectNode.reparentTo(self.ship.getTransNode())

    def completeCannonCheck(self):
        for colList in self.collisionLists.values():
            colList.sort()
            ammo = colList[0][1].getFromNodePath().getPythonTag('ammo')
            if not ammo or ammo.destroyed:
                continue
            for entryData in colList:
                DistributedWeapon.projectileHitObject(self, entryData[1])
                if ammo.destroyed:
                    break

        self.collisionLists = {}
        self.listening = False

    def projectileHitObject(self, entry):
        shot = int(entry.getFromNodePath().getNetTag('shotNum'))
        if not self.collisionLists.get(shot):
            self.collisionLists[shot] = []
        y = entry.getSurfacePoint(entry.getIntoNodePath())[1]
        self.collisionLists[shot].append((y, entry))
        if not self.listening:
            self.listening = True
            self.acceptOnce('event-loop-done', self.completeCannonCheck)
from pandac.PandaModules import getConfigShowbase
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.showbase.PythonUtil import fastRepr
from exceptions import Exception
import sys
import types
import traceback

notify = directNotify.newCategory("ExceptionVarDump")
config = getConfigShowbase()

reentry = 0

def _varDump__init__(self, *args, **kArgs):
    global reentry
    if reentry > 0:
        return
    reentry += 1
    # frame zero is this frame
    f = 1
    self._savedExcString = None
    self._savedStackFrames = []
    while True:
        try:
            frame = sys._getframe(f)
        except ValueError, e:
            break
        else:
            f += 1
            self._savedStackFrames.append(frame)
    self._moved__init__(*args, **kArgs)
Beispiel #46
0
class TTHoodAI(HoodAI):
    notify = directNotify.newCategory('TTHoodAI')

    def __init__(self, air):
        HoodAI.__init__(self, air, ToontownGlobals.ToontownCentral)

        self.fishingSpots = {}
        self.doors = {}

    def createObjects(self):
        HoodAI.createObjects(self)

        if simbase.config.GetBool('want-fishing-spots', False):
            self.createFishingSpots()

        if simbase.config.GetBool('want-doors', False):
            self.createDoors()

    def createClassicChars(self):
        self.classicChar = DistributedMickeyAI(self.air)
        self.classicChar.generateWithRequired(self.zoneId)

    def createFishingSpots(self):
        self.fishingSpots[0] = DistributedFishingSpotAI(self.air)
        self.fishingSpots[0].setPosHpr(-77.5097, 47.3772, -3.2852, 176.818, 0,
                                       0)
        self.fishingSpots[0].generateWithRequired(self.zoneId)

        self.fishingSpots[1] = DistributedFishingSpotAI(self.air)
        self.fishingSpots[1].setPosHpr(-90.7111, 43.1895, -3.30975, -133.237,
                                       0, 0)
        self.fishingSpots[1].generateWithRequired(self.zoneId)

        self.fishingSpots[2] = DistributedFishingSpotAI(self.air)
        self.fishingSpots[2].setPosHpr(-83.6628, -42.4479, -3.95932, -29.2345,
                                       0, 0)
        self.fishingSpots[2].generateWithRequired(self.zoneId)

    def createDoors(self):
        blockNumber = 20
        self.interiorZone = self.zoneId - self.zoneId % 100 + 500 + blockNumber

        self.interior = DistributedHQInteriorAI(self.air, self.interiorZone,
                                                blockNumber)
        self.interior.generateWithRequired(self.interiorZone)

        self.doors[0] = DistributedDoorAI(self.air,
                                          self.interior.blockNumber,
                                          DoorTypes.EXT_HQ,
                                          doorIndex=0)

        self.doors[0].generateWithRequired(self.zoneId)

        self.doors[1] = DistributedDoorAI(self.air,
                                          self.interior.blockNumber,
                                          DoorTypes.EXT_HQ,
                                          doorIndex=1)

        self.doors[1].generateWithRequired(self.zoneId)

        self.doors[2] = DistributedDoorAI(self.air,
                                          self.interior.blockNumber,
                                          DoorTypes.INT_HQ,
                                          doorIndex=0)

        self.doors[2].generateWithRequired(self.interiorZone)

        self.doors[3] = DistributedDoorAI(self.air,
                                          self.interior.blockNumber,
                                          DoorTypes.INT_HQ,
                                          doorIndex=1)

        self.doors[3].generateWithRequired(self.interiorZone)

        self.doors[0].setOtherDoor(self.doors[2])
        self.doors[1].setOtherDoor(self.doors[3])

        self.doors[2].setOtherDoor(self.doors[0])
        self.doors[3].setOtherDoor(self.doors[1])
    """
    CInterval-extensions module: contains methods to extend functionality
    of the CInterval class
    """

    from direct.directnotify.DirectNotifyGlobal import directNotify
    notify = directNotify.newCategory("Interval")

    def setT(self, t):
        # Overridden from the C++ function to call privPostEvent
        # afterward.  We do this by renaming the C++ function in
        # FFIRename.
        self.__cSetT(t)
        self.privPostEvent()

    def play(self, t0 = 0.0, duration = None, scale = 1.0):
        self.notify.error("using deprecated CInterval.play() interface")
        if duration:  # None or 0 implies full length
            self.start(t0, t0 + duration, scale)
        else:
            self.start(t0, -1, scale)

    def stop(self):
        self.notify.error("using deprecated CInterval.stop() interface")
        self.finish()

    def setFinalT(self):
        self.notify.error("using deprecated CInterval.setFinalT() interface")
        self.finish()
class DistributedObjectAI(DistributedObjectBase):
    notify = directNotify.newCategory("DistributedObjectAI")
    QuietZone = 1

    def __init__(self, air):
        try:
            self.DistributedObjectAI_initialized
        except:
            self.DistributedObjectAI_initialized = 1
            DistributedObjectBase.__init__(self, air)

            self.accountName=''
            # Record the repository
            self.air = air

            # Record our distributed class
            className = self.__class__.__name__
            self.dclass = self.air.dclassesByName[className]
            # init doId pre-allocated flag
            self.__preallocDoId = 0

            # used to track zone changes across the quiet zone
            # NOTE: the quiet zone is defined in OTP, but we need it
            # here.
            self.lastNonQuietZone = None

            self._DOAI_requestedDelete = False

            # These are used to implement beginBarrier().
            self.__nextBarrierContext = 0
            self.__barriers = {}

            self.__generated = False
            # reference count for multiple inheritance
            self.__generates = 0

            self._zoneData = None

    # Uncomment if you want to debug DO leaks
    #def __del__(self):
    #    """
    #    For debugging purposes, this just prints out what got deleted
    #    """
    #    print ("Destructing: " + self.__class__.__name__)

    if __debug__:
        def status(self, indent=0):
            """
            print out doId(parentId, zoneId) className
                and conditionally show generated or deleted
            """
            spaces = ' ' * (indent + 2)
            try:
                print("%s%s:" % (' ' * indent, self.__class__.__name__))

                flags = []
                if self.__generated:
                    flags.append("generated")
                if self.air == None:
                    flags.append("deleted")

                flagStr = ""
                if len(flags):
                    flagStr = " (%s)" % (" ".join(flags))

                print("%sfrom DistributedObject doId:%s, parent:%s, zone:%s%s" % (
                    spaces, self.doId, self.parentId, self.zoneId, flagStr))
            except Exception as e:
                print("%serror printing status %s" % (spaces, e))

    def getDeleteEvent(self):
        # this is sent just before we get deleted
        if hasattr(self, 'doId'):
            return 'distObjDelete-%s' % self.doId
        return None

    def sendDeleteEvent(self):
        # this is called just before we get deleted
        delEvent = self.getDeleteEvent()
        if delEvent:
            messenger.send(delEvent)

    def getCacheable(self):
        """ This method exists only to mirror the similar method on
        DistributedObject.  AI objects aren't cacheable. """
        return False

    def deleteOrDelay(self):
        """ This method exists only to mirror the similar method on
        DistributedObject.  AI objects don't have delayDelete, they
        just get deleted immediately. """
        self.delete()

    def getDelayDeleteCount(self):
        return 0

    def delete(self):
        """
        Inheritors should redefine this to take appropriate action on delete
        Note that this may be called multiple times if a class inherits
        from DistributedObjectAI more than once.
        """
        self.__generates -= 1
        if self.__generates < 0:
            self.notify.debug('DistributedObjectAI: delete() called more times than generate()')
        if self.__generates == 0:
            # prevent this code from executing multiple times
            if self.air is not None:
                # self.doId may not exist.  The __dict__ syntax works around that.
                assert self.notify.debug('delete(): %s' % (self.__dict__.get("doId")))

                if not self._DOAI_requestedDelete:
                    # this logs every delete that was not requested by us.
                    # TODO: this currently prints warnings for deletes of objects
                    # that we did not create. We need to add a 'locally created'
                    # flag to every object to filter these out.
                    """
                    DistributedObjectAI.notify.warning(
                        'delete() called but requestDelete never called for %s: %s'
                        % (self.__dict__.get('doId'), self.__class__.__name__))
                        """
                    """
                    # print a stack trace so we can detect whether this is the
                    # result of a network msg.
                    # this is slow.
                    from direct.showbase.PythonUtil import StackTrace
                    DistributedObjectAI.notify.warning(
                        'stack trace: %s' % StackTrace())
                        """
                self._DOAI_requestedDelete = False

                self.releaseZoneData()

                # Clean up all the pending barriers.
                for barrier in self.__barriers.values():
                    barrier.cleanup()
                self.__barriers = {}

                # DCR: I've re-enabled this block of code so that Toontown's
                # AI won't leak channels.
                # Let me know if it causes trouble.
                ### Asad: As per Roger's suggestion, turn off the following
                ### block until a solution is thought out of how to prevent
                ### this delete message or to handle this message better
                # TODO: do we still need this check?
                if not getattr(self, "doNotDeallocateChannel", False):
                    if self.air:
                        self.air.deallocateChannel(self.doId)
                self.air = None

                self.parentId = None
                self.zoneId = None
                self.__generated = False

    def isDeleted(self):
        """
        Returns true if the object has been deleted,
        or if it is brand new and hasnt yet been generated.
        """
        return self.air == None

    def isGenerated(self):
        """
        Returns true if the object has been generated
        """
        return self.__generated

    def getDoId(self):
        """
        Return the distributed object id
        """
        return self.doId

    def preAllocateDoId(self):
        """
        objects that need to have a doId before they are generated
        can call this to pre-allocate a doId for the object
        """
        assert not self.__preallocDoId
        self.doId = self.air.allocateChannel()
        self.__preallocDoId = 1

    def announceGenerate(self):
        """
        Called after the object has been generated and all
        of its required fields filled in. Overwrite when needed.
        """
        pass

    def b_setLocation(self, parentId, zoneId):
        self.d_setLocation(parentId, zoneId)
        self.setLocation(parentId, zoneId)

    def d_setLocation(self, parentId, zoneId):
        self.air.sendSetLocation(self, parentId, zoneId)

    def setLocation(self, parentId, zoneId):
        # Prevent Duplicate SetLocations for being Called
        if (self.parentId == parentId) and (self.zoneId == zoneId):
            return

        oldParentId = self.parentId
        oldZoneId = self.zoneId
        self.air.storeObjectLocation(self, parentId, zoneId)
        if ((oldParentId != parentId) or
            (oldZoneId != zoneId)):
            self.releaseZoneData()
            messenger.send(self.getZoneChangeEvent(), [zoneId, oldZoneId])
            # if we are not going into the quiet zone, send a 'logical' zone
            # change message
            if zoneId != DistributedObjectAI.QuietZone:
                lastLogicalZone = oldZoneId
                if oldZoneId == DistributedObjectAI.QuietZone:
                    lastLogicalZone = self.lastNonQuietZone
                self.handleLogicalZoneChange(zoneId, lastLogicalZone)
                self.lastNonQuietZone = zoneId

    def getLocation(self):
        try:
            if self.parentId <= 0 and self.zoneId <= 0:
                return None
            # This is a -1 stuffed into a uint32
            if self.parentId == 0xffffffff and self.zoneId == 0xffffffff:
                return None
            return (self.parentId, self.zoneId)
        except AttributeError:
            return None

    def postGenerateMessage(self):
        self.__generated = True
        messenger.send(self.uniqueName("generate"), [self])

    def updateRequiredFields(self, dclass, di):
        dclass.receiveUpdateBroadcastRequired(self, di)
        self.announceGenerate()
        self.postGenerateMessage()

    def updateAllRequiredFields(self, dclass, di):
        dclass.receiveUpdateAllRequired(self, di)
        self.announceGenerate()
        self.postGenerateMessage()

    def updateRequiredOtherFields(self, dclass, di):
        dclass.receiveUpdateBroadcastRequired(self, di)
        # Announce generate after updating all the required fields,
        # but before we update the non-required fields.
        self.announceGenerate()
        self.postGenerateMessage()

        dclass.receiveUpdateOther(self, di)

    def updateAllRequiredOtherFields(self, dclass, di):
        dclass.receiveUpdateAllRequired(self, di)
        # Announce generate after updating all the required fields,
        # but before we update the non-required fields.
        self.announceGenerate()
        self.postGenerateMessage()

        dclass.receiveUpdateOther(self, di)

    def startMessageBundle(self, name):
        self.air.startMessageBundle(name)
    def sendMessageBundle(self):
        self.air.sendMessageBundle(self.doId)

    def getZoneChangeEvent(self):
        # this event is generated whenever this object changes zones.
        # arguments are newZoneId, oldZoneId
        # includes the quiet zone.
        return DistributedObjectAI.staticGetZoneChangeEvent(self.doId)
    def getLogicalZoneChangeEvent(self):
        # this event is generated whenever this object changes to a
        # non-quiet-zone zone.
        # arguments are newZoneId, oldZoneId
        # does not include the quiet zone.
        return DistributedObjectAI.staticGetLogicalZoneChangeEvent(self.doId)

    @staticmethod
    def staticGetZoneChangeEvent(doId):
        return 'DOChangeZone-%s' % doId
    @staticmethod
    def staticGetLogicalZoneChangeEvent(doId):
        return 'DOLogicalChangeZone-%s' % doId

    def handleLogicalZoneChange(self, newZoneId, oldZoneId):
        """this function gets called as if we never go through the
        quiet zone. Note that it is called once you reach the newZone,
        and not at the time that you leave the oldZone."""
        messenger.send(self.getLogicalZoneChangeEvent(),
                       [newZoneId, oldZoneId])

    def getZoneData(self):
        # Call this to get an AIZoneData object for the current zone.
        # This class will hold onto it as self._zoneData
        # setLocation destroys self._zoneData if we move away to
        # a different zone
        if self._zoneData is None:
            from otp.ai.AIZoneData import AIZoneData
            self._zoneData = AIZoneData(self.air, self.parentId, self.zoneId)
        return self._zoneData

    def releaseZoneData(self):
        # You can call this to release any AIZoneData object that we might be
        # holding onto. If we're the last one for the current zone, the data
        # will be destroyed (render, collision traverser, etc.)
        # Note that the AIZoneData object that we're holding will be destroyed
        # automatically when we move away or are destroyed.
        if self._zoneData is not None:
            self._zoneData.destroy()
            self._zoneData = None

    def getRender(self):
        # note that this will return a different node if we change zones
        #return self.air.getRender(self.zoneId)
        return self.getZoneData().getRender()

    def getNonCollidableParent(self):
        return self.getZoneData().getNonCollidableParent()

    def getParentMgr(self):
        #return self.air.getParentMgr(self.zoneId)
        return self.getZoneData().getParentMgr()

    def getCollTrav(self, *args, **kArgs):
        return self.getZoneData().getCollTrav(*args, **kArgs)

    def sendUpdate(self, fieldName, args = []):
        assert self.notify.debugStateCall(self)
        if self.air:
            self.air.sendUpdate(self, fieldName, args)

    def GetPuppetConnectionChannel(self, doId):
        return doId + (1001 << 32)

    def GetAccountConnectionChannel(self, doId):
        return doId + (1003 << 32)

    def GetAccountIDFromChannelCode(self, channel):
        return channel >> 32

    def GetAvatarIDFromChannelCode(self, channel):
        return channel & 0xffffffff

    def sendUpdateToAvatarId(self, avId, fieldName, args):
        assert self.notify.debugStateCall(self)
        channelId = self.GetPuppetConnectionChannel(avId)
        self.sendUpdateToChannel(channelId, fieldName, args)

    def sendUpdateToAccountId(self, accountId, fieldName, args):
        assert self.notify.debugStateCall(self)
        channelId = self.GetAccountConnectionChannel(accountId)
        self.sendUpdateToChannel(channelId, fieldName, args)

    def sendUpdateToChannel(self, channelId, fieldName, args):
        assert self.notify.debugStateCall(self)
        if self.air:
            self.air.sendUpdateToChannel(self, channelId, fieldName, args)

    def generateWithRequired(self, zoneId, optionalFields=[]):
        assert self.notify.debugStateCall(self)
        # have we already allocated a doId?
        if self.__preallocDoId:
            self.__preallocDoId = 0
            return self.generateWithRequiredAndId(
                self.doId, zoneId, optionalFields)

        # The repository is the one that really does the work
        parentId = self.air.districtId
        self.air.generateWithRequired(self, parentId, zoneId, optionalFields)
        self.generate()
        self.announceGenerate()
        self.postGenerateMessage()

    # this is a special generate used for estates, or anything else that
    # needs to have a hard coded doId as assigned by the server
    def generateWithRequiredAndId(self, doId, parentId, zoneId, optionalFields=[]):
        assert self.notify.debugStateCall(self)
        # have we already allocated a doId?
        if self.__preallocDoId:
            assert doId == self.doId
            self.__preallocDoId = 0

        # The repository is the one that really does the work
        self.air.generateWithRequiredAndId(self, doId, parentId, zoneId, optionalFields)
        self.generate()
        self.announceGenerate()
        self.postGenerateMessage()

    def generateOtpObject(self, parentId, zoneId, optionalFields=[], doId=None):
        assert self.notify.debugStateCall(self)
        # have we already allocated a doId?
        if self.__preallocDoId:
            assert doId is None or doId == self.doId
            doId=self.doId
            self.__preallocDoId = 0

        # Assign it an id
        if doId is None:
            self.doId = self.air.allocateChannel()
        else:
            self.doId = doId
        # Put the new DO in the dictionaries
        self.air.addDOToTables(self, location=(parentId, zoneId))
        # Send a generate message
        self.sendGenerateWithRequired(self.air, parentId, zoneId, optionalFields)
        self.generate()
        self.announceGenerate()
        self.postGenerateMessage()

    def generate(self):
        """
        Inheritors should put functions that require self.zoneId or
        other networked info in this function.
        """
        assert self.notify.debugStateCall(self)
        self.__generates += 1

    def generateInit(self, repository=None):
        """
        First generate (not from cache).
        """
        assert self.notify.debugStateCall(self)

    def generateTargetChannel(self, repository):
        """
        Who to send this to for generate messages
        """
        if hasattr(self, "dbObject"):
            return self.doId
        return repository.serverId

    def sendGenerateWithRequired(self, repository, parentId, zoneId, optionalFields=[]):
        assert self.notify.debugStateCall(self)
        dg = self.dclass.aiFormatGenerate(
            self, self.doId, parentId, zoneId,
            #repository.serverId,
            self.generateTargetChannel(repository),
            repository.ourChannel,
            optionalFields)
        repository.send(dg)

    def initFromServerResponse(self, valDict):
        assert self.notify.debugStateCall(self)
        # This is a special method used for estates, etc., which get
        # their fields set from the database indirectly by way of the
        # AI.  The input parameter is a dictionary of field names to
        # datagrams that describes the initial field values from the
        # database.

        dclass = self.dclass
        for key, value in valDict.items():
            # Update the field
            dclass.directUpdate(self, key, value)

    def requestDelete(self):
        assert self.notify.debugStateCall(self)
        if not self.air:
            doId = "none"
            if hasattr(self, "doId"):
                doId = self.doId
            self.notify.warning(
                "Tried to delete a %s (doId %s) that is already deleted" %
                (self.__class__, doId))
            return
        self.air.requestDelete(self)
        self._DOAI_requestedDelete = True

    def taskName(self, taskString):
        return ("%s-%s" % (taskString, self.doId))

    def uniqueName(self, idString):
        return ("%s-%s" % (idString, self.doId))

    def validate(self, avId, bool, msg):
        if not bool:
            self.air.writeServerEvent('suspicious', avId, msg)
            self.notify.warning('validate error: avId: %s -- %s' % (avId, msg))
        return bool

    def beginBarrier(self, name, avIds, timeout, callback):
        # Begins waiting for a set of avatars.  When all avatars in
        # the list have reported back in or the callback has expired,
        # calls the indicated callback with the list of avatars that
        # made it through.  There may be multiple barriers waiting
        # simultaneously on different lists of avatars, although they
        # should have different names.

        from otp.ai import Barrier
        context = self.__nextBarrierContext
        # We assume the context number is passed as a uint16.
        self.__nextBarrierContext = (self.__nextBarrierContext + 1) & 0xffff

        assert self.notify.debug('beginBarrier(%s, %s, %s, %s)' % (context, name, avIds, timeout))

        if avIds:
            barrier = Barrier.Barrier(
                name, self.uniqueName(name), avIds, timeout,
                doneFunc = PythonUtil.Functor(
                    self.__barrierCallback, context, callback))
            self.__barriers[context] = barrier

            # Send the context number to each involved client.
            self.sendUpdate("setBarrierData", [self.getBarrierData()])
        else:
            # No avatars; just call the callback immediately.
            callback(avIds)

        return context

    def getBarrierData(self):
        # Returns the barrier data formatted for sending to the
        # clients.  This lists all of the current outstanding barriers
        # and the avIds waiting for them.
        data = []
        for context, barrier in self.__barriers.items():
            avatars = barrier.pendingAvatars
            if avatars:
                data.append((context, barrier.name, avatars))
        return data

    def ignoreBarrier(self, context):
        # Aborts a previously-set barrier.  The context is the return
        # value from the previous call to beginBarrier().
        barrier = self.__barriers.get(context)
        if barrier:
            barrier.cleanup()
            del self.__barriers[context]

    def setBarrierReady(self, context):
        # Generated by the clients to check in after a beginBarrier()
        # call.
        avId = self.air.getAvatarIdFromSender()
        assert self.notify.debug('setBarrierReady(%s, %s)' % (context, avId))
        barrier = self.__barriers.get(context)
        if barrier == None:
            # This may be None if a client was slow and missed an
            # earlier timeout.  Too bad.
            return

        barrier.clear(avId)

    def __barrierCallback(self, context, callback, avIds):
        assert self.notify.debug('barrierCallback(%s, %s)' % (context, avIds))
        # The callback that is generated when a barrier is completed.
        barrier = self.__barriers.get(context)
        if barrier:
            barrier.cleanup()
            del self.__barriers[context]
            callback(avIds)
        else:
            self.notify.warning("Unexpected completion from barrier %s" % (context))

    def isGridParent(self):
        # If this distributed object is a DistributedGrid return 1.  0 by default
        return 0

    def execCommand(self, string, mwMgrId, avId, zoneId):
        pass

    def _retrieveCachedData(self):
        """ This is a no-op on the AI. """
        pass

    def setAI(self, aiChannel):
        self.air.setAI(self.doId, aiChannel)
from direct.extensions_native import VBase4_extensions
from direct.extensions_native import NodePath_extensions


from panda3d.core import loadPrcFile


if __debug__:
    loadPrcFile('config/general.prc')
    loadPrcFile('config/release/dev.prc')


from direct.directnotify.DirectNotifyGlobal import directNotify


notify = directNotify.newCategory('Toontown Planet Client Start')
notify.setInfo(True)


from otp.settings.Settings import Settings


preferencesFilename = ConfigVariableString(
    'preferences-filename', 'preferences.json').getValue()
notify.info('Reading %s...' % preferencesFilename)
__builtin__.settings = Settings(preferencesFilename)
if 'fullscreen' not in settings:
    settings['fullscreen'] = False
if 'music' not in settings:
    settings['music'] = True
if 'sfx' not in settings:
Beispiel #50
0
class ProfileSession:
    # class that encapsulates a profile of a single callable using Python's standard
    # 'profile' module
    #
    # defers formatting of profile results until they are requested
    #
    # implementation sidesteps memory leak in Python profile module,
    # and redirects file output to RAM file for efficiency
    TrueClock = TrueClock.getGlobalPtr()

    notify = directNotify.newCategory("ProfileSession")

    def __init__(self, name, func=None, logAfterProfile=False):
        self._func = func
        self._name = name
        self._logAfterProfile = logAfterProfile
        self._filenameBase = 'profileData-%s-%s' % (self._name, id(self))
        self._refCount = 0
        # if true, accumulate profile results every time we run
        # if false, throw out old results every time we run
        self._aggregate = False
        self._lines = 500
        self._sorts = ['cumulative', 'time', 'calls']
        self._callInfo = True
        self._totalTime = None
        self._reset()
        self.acquire()

    def getReference(self):
        # call this when you want to store a new reference to this session that will
        # manage its acquire/release reference count independently of an existing reference
        self.acquire()
        return self

    def acquire(self):
        self._refCount += 1

    def release(self):
        self._refCount -= 1
        if not self._refCount:
            self._destroy()

    def _destroy(self):
        del self._func
        del self._name
        del self._filenameBase
        del self._filenameCounter
        del self._filenames
        del self._duration
        del self._filename2ramFile
        del self._resultCache
        del self._successfulProfiles

    def _reset(self):
        self._filenameCounter = 0
        self._filenames = []
        # index of next file to be added to stats object
        self._statFileCounter = 0
        self._successfulProfiles = 0
        self._duration = None
        self._filename2ramFile = {}
        self._stats = None
        self._resultCache = {}

    def _getNextFilename(self):
        filename = '%s-%s' % (self._filenameBase, self._filenameCounter)
        self._filenameCounter += 1
        return filename

    def run(self):
        # make sure this instance doesn't get destroyed inside self._func
        self.acquire()

        if not self._aggregate:
            self._reset()

        # if we're already profiling, just run the func and don't profile
        if 'globalProfileSessionFunc' in builtins.__dict__:
            self.notify.warning('could not profile %s' % self._func)
            result = self._func()
            if self._duration is None:
                self._duration = 0.
        else:
            # put the function in the global namespace so that profile can find it
            assert hasattr(self._func, '__call__')
            builtins.globalProfileSessionFunc = self._func
            builtins.globalProfileSessionResult = [None]

            # set up the RAM file
            self._filenames.append(self._getNextFilename())
            filename = self._filenames[-1]
            _installProfileCustomFuncs(filename)

            # do the profiling
            Profile = profile.Profile
            statement = 'globalProfileSessionResult[0]=globalProfileSessionFunc()'
            sort = -1
            retVal = None

            # this is based on profile.run, the code is replicated here to allow us to
            # eliminate a memory leak
            prof = Profile()
            try:
                prof = prof.run(statement)
            except SystemExit:
                pass
            # this has to be run immediately after profiling for the timings to be accurate
            # tell the Profile object to generate output to the RAM file
            prof.dump_stats(filename)

            # eliminate the memory leak
            del prof.dispatcher

            # store the RAM file for later
            profData = _getProfileResultFileInfo(filename)
            self._filename2ramFile[filename] = profData
            # calculate the duration (this is dependent on the internal Python profile data format.
            # see profile.py and pstats.py, this was copied from pstats.Stats.strip_dirs)
            maxTime = 0.
            for cc, nc, tt, ct, callers in profData[1].values():
                if ct > maxTime:
                    maxTime = ct
            self._duration = maxTime
            # clean up the RAM file support
            _removeProfileCustomFuncs(filename)

            # clean up the globals
            result = globalProfileSessionResult[0]
            del builtins.__dict__['globalProfileSessionFunc']
            del builtins.__dict__['globalProfileSessionResult']

            self._successfulProfiles += 1

            if self._logAfterProfile:
                self.notify.info(self.getResults())

        self.release()
        return result

    def getDuration(self):
        return self._duration

    def profileSucceeded(self):
        return self._successfulProfiles > 0

    def _restoreRamFile(self, filename):
        # set up the RAM file
        _installProfileCustomFuncs(filename)
        # install the stored RAM file from self.run()
        _setProfileResultsFileInfo(filename, self._filename2ramFile[filename])

    def _discardRamFile(self, filename):
        # take down the RAM file
        _removeProfileCustomFuncs(filename)
        # and discard it
        del self._filename2ramFile[filename]

    def setName(self, name):
        self._name = name

    def getName(self):
        return self._name

    def setFunc(self, func):
        self._func = func

    def getFunc(self):
        return self._func

    def setAggregate(self, aggregate):
        self._aggregate = aggregate

    def getAggregate(self):
        return self._aggregate

    def setLogAfterProfile(self, logAfterProfile):
        self._logAfterProfile = logAfterProfile

    def getLogAfterProfile(self):
        return self._logAfterProfile

    def setLines(self, lines):
        self._lines = lines

    def getLines(self):
        return self._lines

    def setSorts(self, sorts):
        self._sorts = sorts

    def getSorts(self):
        return self._sorts

    def setShowCallInfo(self, showCallInfo):
        self._showCallInfo = showCallInfo

    def getShowCallInfo(self):
        return self._showCallInfo

    def setTotalTime(self, totalTime=None):
        self._totalTime = totalTime

    def resetTotalTime(self):
        self._totalTime = None

    def getTotalTime(self):
        return self._totalTime

    def aggregate(self, other):
        # pull in stats from another ProfileSession
        other._compileStats()
        self._compileStats()
        self._stats.add(other._stats)

    def _compileStats(self):
        # make sure our stats object exists and is up-to-date
        statsChanged = (self._statFileCounter < len(self._filenames))

        if self._stats is None:
            for filename in self._filenames:
                self._restoreRamFile(filename)
            self._stats = PercentStats(*self._filenames)
            self._statFileCounter = len(self._filenames)
            for filename in self._filenames:
                self._discardRamFile(filename)
        else:
            while self._statFileCounter < len(self._filenames):
                filename = self._filenames[self._statFileCounter]
                self._restoreRamFile(filename)
                self._stats.add(filename)
                self._discardRamFile(filename)

        if statsChanged:
            self._stats.strip_dirs()
            # throw out any cached result strings
            self._resultCache = {}

        return statsChanged

    def getResults(self,
                   lines=Default,
                   sorts=Default,
                   callInfo=Default,
                   totalTime=Default):
        if not self.profileSucceeded():
            output = '%s: profiler already running, could not profile' % self._name
        else:
            if lines is Default:
                lines = self._lines
            if sorts is Default:
                sorts = self._sorts
            if callInfo is Default:
                callInfo = self._callInfo
            if totalTime is Default:
                totalTime = self._totalTime

            self._compileStats()

            if totalTime is None:
                totalTime = self._stats.total_tt

            # make sure the arguments will hash efficiently if callers provide different types
            lines = int(lines)
            sorts = list(sorts)
            callInfo = bool(callInfo)
            totalTime = float(totalTime)
            k = str((lines, sorts, callInfo, totalTime))
            if k in self._resultCache:
                # we've already created this output string, get it from the cache
                output = self._resultCache[k]
            else:
                # now get human-readable output from the profile stats

                # capture print output to a string
                sc = StdoutCapture()

                # print the info to stdout
                s = self._stats
                # make sure our percentages are relative to the correct total time
                s.setTotalTime(totalTime)
                for sort in sorts:
                    s.sort_stats(sort)
                    s.print_stats(lines)
                    if callInfo:
                        s.print_callees(lines)
                        s.print_callers(lines)

                # make a copy of the print output
                output = sc.getString()

                # restore stdout to what it was before
                sc.destroy()

                # cache this result
                self._resultCache[k] = output

        return output