Beispiel #1
0
class DistributedObjectGlobalAI(DistributedObjectAI):
    notify = directNotify.newCategory('DistributedObjectGlobalAI')

    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:
                self.air.unregisterForChannel(self.doId)
        except AttributeError:
            self.air.unregisterForChannel(self.doId)
Beispiel #2
0
class Factory:
    """This class manages a list of object types and their corresponding constructors.
    Objects may be created on-demand from their type. Object types may be any hashable
    piece of unique data (such as a string).
    
    This class is intended to be derived from. Subclasses should call self._registerTypes
    to set up type constructors."""
    notify = directNotify.newCategory('Factory')
    
    def __init__(self):
        self._type2ctor = {}

    def create(self, type, *args, **kwArgs):
        return self._type2ctor[type](*args, **kwArgs)

    def _registerType(self, type, ctor):
        if self._type2ctor.has_key(type):
            self.notify.debug('replacing %s ctor %s with %s' %
                              (type, self._type2ctor[type], ctor))
        self._type2ctor[type] = ctor
    def _registerTypes(self, type2ctor):
        for type, ctor in type2ctor.items():
            self._registerType(type, ctor)
        
    def nullCtor(self, *args, **kwArgs):
        return None
class DistributedObjectGlobal(DistributedObject):
    """
    The Distributed Object Global class is the base class for global
    network based (i.e. distributed) objects.
    """
    notify = directNotify.newCategory("DistributedObjectGlobal")

    # A few objects will set neverDisable to 1... Examples are
    # localToon, and anything that lives in the UberZone. This
    # keeps them from being disabled when you change zones,
    # even to the quiet zone.
    neverDisable = 1

    def __init__(self, cr):
        assert self.notify.debugStateCall(self)
        DistributedObject.__init__(self, cr)
        self.parentId = 0
        self.zoneId = 0
Beispiel #4
0
def checkForGarbageLeaks():
    gc.collect()
    numGarbage = len(gc.garbage)
    if (numGarbage > 0 and (not config.GetBool('disable-garbage-logging', 1))):
        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 #5
0
class DistributedObjectOV(DistributedObjectBase):
    """
    Implementation of the 'owner view' (OV) of a distributed object;
    """
    notify = directNotify.newCategory("DistributedObjectOV")

    def __init__(self, cr):
        assert self.notify.debugStateCall(self)
        try:
            self.DistributedObjectOV_initialized
        except:
            self.DistributedObjectOV_initialized = 1
            DistributedObjectBase.__init__(self, cr)

            # Keep track of our state as a distributed object.  This
            # is only trustworthy if the inheriting class properly
            # calls up the chain for disable() and generate().
            self.activeState = ESNew

    if __debug__:

        def status(self, indent=0):
            """
            print out "doId(parentId, zoneId) className"
                and conditionally show generated, disabled
            """
            spaces = ' ' * (indent + 2)
            try:
                print "%s%s:" % (' ' * indent, self.__class__.__name__)
                print "%sfrom DistributedObjectOV doId:%s, parent:%s, zone:%s" % (
                    spaces, self.doId, self.parentId, self.zoneId),
                flags = []
                if self.activeState == ESGenerated:
                    flags.append("generated")
                if self.activeState < ESGenerating:
                    flags.append("disabled")
                if len(flags):
                    print "(%s)" % (" ".join(flags), ),
                print
            except Exception, e:
                print "%serror printing status" % (spaces, ), e
Beispiel #6
0
def checkForGarbageLeaks():
    gc.collect()
    numGarbage = len(gc.garbage)
    if (numGarbage > 0 and (not config.GetBool('disable-garbage-logging', 1))):
        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 #7
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))
Beispiel #8
0
import direct
from panda3d.pandac import HttpRequest
from panda3d.direct.directnotify.DirectNotifyGlobal import directNotify
from panda3d.direct.task.TaskManagerGlobal import taskMgr
from panda3d.direct.task import Task
from LandingPage import LandingPage

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:
Beispiel #9
0
class GravityWalker(DirectObject.DirectObject):
    notify = directNotify.newCategory("GravityWalker")
    wantDebugIndicator = base.config.GetBool('want-avatar-physics-indicator',
                                             0)
    wantFloorSphere = base.config.GetBool('want-floor-sphere', 0)
    earlyEventSphere = base.config.GetBool('early-event-sphere', 0)

    DiagonalFactor = math.sqrt(2.) / 2.

    # special methods
    def __init__(self,
                 gravity=64.348,
                 standableGround=0.707,
                 hardLandingForce=16.0):
        assert self.notify.debugStateCall(self)
        DirectObject.DirectObject.__init__(self)
        self.__gravity = gravity
        self.__standableGround = standableGround
        self.__hardLandingForce = hardLandingForce

        self.mayJump = 1
        self.jumpDelayTask = None

        self.controlsTask = None
        self.indicatorTask = None

        self.falling = 0
        self.needToDeltaPos = 0
        self.physVelocityIndicator = None
        self.avatarControlForwardSpeed = 0
        self.avatarControlJumpForce = 0
        self.avatarControlReverseSpeed = 0
        self.avatarControlRotateSpeed = 0
        self.getAirborneHeight = None

        self.priorParent = Vec3(0)
        self.__oldPosDelta = Vec3(0)
        self.__oldDt = 0

        self.moving = 0
        self.speed = 0.0
        self.rotationSpeed = 0.0
        self.slideSpeed = 0.0
        self.vel = Vec3(0.0)
        self.collisionsActive = 0

        self.isAirborne = 0
        self.highMark = 0

    """
    def spawnTest(self):
        assert self.notify.debugStateCall(self)
        if not self.wantDebugIndicator:
            return
        from panda3d.pandac import *
        from panda3d.direct.interval.IntervalGlobal import *
        from toontown.coghq import MovingPlatform

        if hasattr(self, "platform"):
            # Remove the prior instantiation:
            self.moveIval.pause()
            del self.moveIval
            self.platform.destroy()
            del self.platform
            self.platform2.destroy()
            del self.platform2

        model = loader.loadModel('phase_9/models/cogHQ/platform1')
        fakeId = id(self)
        self.platform = MovingPlatform.MovingPlatform()
        self.platform.setupCopyModel(fakeId, model, 'platformcollision')
        self.platformRoot = render.attachNewNode("GravityWalker-spawnTest-%s"%fakeId)
        self.platformRoot.setPos(base.localAvatar, Vec3(0.0, 0.0, 1.0))
        self.platformRoot.setHpr(base.localAvatar, Vec3.zero())
        self.platform.reparentTo(self.platformRoot)

        self.platform2 = MovingPlatform.MovingPlatform()
        self.platform2.setupCopyModel(1+fakeId, model, 'platformcollision')
        self.platform2Root = render.attachNewNode("GravityWalker-spawnTest2-%s"%fakeId)
        self.platform2Root.setPos(base.localAvatar, Vec3(-16.0, 30.0, 1.0))
        self.platform2Root.setHpr(base.localAvatar, Vec3.zero())
        self.platform2.reparentTo(self.platform2Root)

        duration = 5
        self.moveIval = Parallel(
                Sequence(
                    WaitInterval(0.3),
                    LerpPosInterval(self.platform, duration,
                                    Vec3(0.0, 30.0, 0.0),
                                    name='platformOut%s' % fakeId,
                                    fluid = 1),
                    WaitInterval(0.3),
                    LerpPosInterval(self.platform, duration,
                                    Vec3(0.0, 0.0, 0.0),
                                    name='platformBack%s' % fakeId,
                                    fluid = 1),
                    WaitInterval(0.3),
                    LerpPosInterval(self.platform, duration,
                                    Vec3(0.0, 0.0, 30.0),
                                    name='platformUp%s' % fakeId,
                                    fluid = 1),
                    WaitInterval(0.3),
                    LerpPosInterval(self.platform, duration,
                                    Vec3(0.0, 0.0, 0.0),
                                    name='platformDown%s' % fakeId,
                                    fluid = 1),
                ),
                Sequence(
                    WaitInterval(0.3),
                    LerpPosInterval(self.platform2, duration,
                                    Vec3(0.0, -30.0, 0.0),
                                    name='platform2Out%s' % fakeId,
                                    fluid = 1),
                    WaitInterval(0.3),
                    LerpPosInterval(self.platform2, duration,
                                    Vec3(0.0, 30.0, 30.0),
                                    name='platform2Back%s' % fakeId,
                                    fluid = 1),
                    WaitInterval(0.3),
                    LerpPosInterval(self.platform2, duration,
                                    Vec3(0.0, -30.0, 0.0),
                                    name='platform2Up%s' % fakeId,
                                    fluid = 1),
                    WaitInterval(0.3),
                    LerpPosInterval(self.platform2, duration,
                                    Vec3(0.0, 0.0, 0.0),
                                    name='platformDown%s' % fakeId,
                                    fluid = 1),
                ),
            name='platformIval%s' % fakeId,
            )
        self.moveIval.loop()
    """

    def setWalkSpeed(self, forward, jump, reverse, rotate):
        assert self.notify.debugStateCall(self)
        self.avatarControlForwardSpeed = forward
        self.avatarControlJumpForce = jump
        self.avatarControlReverseSpeed = reverse
        self.avatarControlRotateSpeed = rotate

    def getSpeeds(self):
        #assert self.debugPrint("getSpeeds()")
        return (self.speed, self.rotationSpeed, self.slideSpeed)

    def getIsAirborne(self):
        return self.isAirborne

    def setAvatar(self, avatar):
        self.avatar = avatar
        if avatar is not None:
            pass  # setup the avatar

    def setupRay(self, bitmask, floorOffset, reach):
        assert self.notify.debugStateCall(self)
        # This is a ray cast from your head down to detect floor polygons.
        # This ray start is arbitrarily high in the air.  Feel free to use
        # a higher or lower value depending on whether you want an avatar
        # that is outside of the world to step up to the floor when they
        # get under valid floor:
        cRay = CollisionRay(0.0, 0.0, CollisionHandlerRayStart, 0.0, 0.0, -1.0)
        cRayNode = CollisionNode('GW.cRayNode')
        cRayNode.addSolid(cRay)
        self.cRayNodePath = self.avatarNodePath.attachNewNode(cRayNode)
        cRayNode.setFromCollideMask(bitmask)
        cRayNode.setIntoCollideMask(BitMask32.allOff())

        # set up floor collision mechanism
        self.lifter = CollisionHandlerGravity()
        self.lifter.setGravity(self.__gravity)
        self.lifter.addInPattern("enter%in")
        self.lifter.addOutPattern("exit%in")
        self.lifter.setOffset(floorOffset)
        self.lifter.setReach(reach)

        # Limit our rate-of-fall with the lifter.
        # If this is too low, we actually "fall" off steep stairs
        # and float above them as we go down. I increased this
        # from 8.0 to 16.0 to prevent this
        #self.lifter.setMaxVelocity(16.0)

        self.lifter.addCollider(self.cRayNodePath, self.avatarNodePath)

    def setupWallSphere(self, bitmask, avatarRadius):
        """
        Set up the collision sphere
        """
        assert self.notify.debugStateCall(self)
        # This is a sphere on the ground to detect collisions with
        # walls, but not the floor.
        self.avatarRadius = avatarRadius
        cSphere = CollisionSphere(0.0, 0.0, avatarRadius, avatarRadius)
        cSphereNode = CollisionNode('GW.cWallSphereNode')
        cSphereNode.addSolid(cSphere)
        cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)

        cSphereNode.setFromCollideMask(bitmask)
        cSphereNode.setIntoCollideMask(BitMask32.allOff())

        # set up collision mechanism
        if config.GetBool('want-fluid-pusher', 0):
            self.pusher = CollisionHandlerFluidPusher()
        else:
            self.pusher = CollisionHandlerPusher()
        self.pusher.addCollider(cSphereNodePath, self.avatarNodePath)
        self.cWallSphereNodePath = cSphereNodePath

    def setupEventSphere(self, bitmask, avatarRadius):
        """
        Set up the collision sphere
        """
        assert self.notify.debugStateCall(self)
        # This is a sphere a little larger than the wall sphere to
        # trigger events.
        self.avatarRadius = avatarRadius
        cSphere = CollisionSphere(0.0, 0.0, avatarRadius - 0.1,
                                  avatarRadius * 1.04)
        # Mark it intangible just to emphasize its non-physical purpose.
        cSphere.setTangible(0)
        cSphereNode = CollisionNode('GW.cEventSphereNode')
        cSphereNode.addSolid(cSphere)
        cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)

        cSphereNode.setFromCollideMask(bitmask)
        cSphereNode.setIntoCollideMask(BitMask32.allOff())

        # set up collision mechanism
        self.event = CollisionHandlerEvent()
        self.event.addInPattern("enter%in")
        self.event.addOutPattern("exit%in")
        self.cEventSphereNodePath = cSphereNodePath

    def setupFloorSphere(self, bitmask, avatarRadius):
        """
        Set up the collision sphere
        """
        assert self.notify.debugStateCall(self)
        # This is a tiny sphere concentric with the wallSphere to keep
        # us from slipping through floors.
        self.avatarRadius = avatarRadius
        cSphere = CollisionSphere(0.0, 0.0, avatarRadius, 0.01)
        cSphereNode = CollisionNode('GW.cFloorSphereNode')
        cSphereNode.addSolid(cSphere)
        cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)

        cSphereNode.setFromCollideMask(bitmask)
        cSphereNode.setIntoCollideMask(BitMask32.allOff())

        # set up collision mechanism
        self.pusherFloorhandler = CollisionHandlerPusher()
        self.pusherFloor.addCollider(cSphereNodePath, self.avatarNodePath)
        self.cFloorSphereNodePath = cSphereNodePath

    def setWallBitMask(self, bitMask):
        self.wallBitmask = bitMask

    def setFloorBitMask(self, bitMask):
        self.floorBitmask = bitMask

    def swapFloorBitMask(self, oldMask, newMask):
        self.floorBitmask = self.floorBitmask & ~oldMask
        self.floorBitmask |= newMask

        if self.cRayNodePath and not self.cRayNodePath.isEmpty():
            self.cRayNodePath.node().setFromCollideMask(self.floorBitmask)

    def setGravity(self, gravity):
        self.__gravity = gravity
        self.lifter.setGravity(self.__gravity)

    def getGravity(self, gravity):
        return self.__gravity

    def initializeCollisions(self,
                             collisionTraverser,
                             avatarNodePath,
                             avatarRadius=1.4,
                             floorOffset=1.0,
                             reach=1.0):
        """
        floorOffset is how high the avatar can reach.  I.e. if the avatar
            walks under a ledge that is <= floorOffset above the ground (a
            double floor situation), the avatar will step up on to the
            ledge (instantly).

        Set up the avatar collisions
        """
        assert self.notify.debugStateCall(self)

        assert not avatarNodePath.isEmpty()
        self.avatarNodePath = avatarNodePath

        self.cTrav = collisionTraverser

        self.setupRay(self.floorBitmask, floorOffset, reach)
        self.setupWallSphere(self.wallBitmask, avatarRadius)
        self.setupEventSphere(self.wallBitmask, avatarRadius)
        if self.wantFloorSphere:
            self.setupFloorSphere(self.floorBitmask, avatarRadius)

        self.setCollisionsActive(1)

    def setTag(self, key, value):
        self.cEventSphereNodePath.setTag(key, value)

    def setAirborneHeightFunc(self, unused_parameter):
        assert self.notify.debugStateCall(self)
        self.getAirborneHeight = self.lifter.getAirborneHeight

    def getAirborneHeight(self):
        assert self.notify.debugStateCall(self)
        self.lifter.getAirborneHeight()

    def setAvatarPhysicsIndicator(self, indicator):
        """
        indicator is a NodePath
        """
        assert self.notify.debugStateCall(self)
        self.cWallSphereNodePath.show()

    def deleteCollisions(self):
        assert self.notify.debugStateCall(self)
        del self.cTrav

        self.cWallSphereNodePath.removeNode()
        del self.cWallSphereNodePath
        if self.wantFloorSphere:
            self.cFloorSphereNodePath.removeNode()
            del self.cFloorSphereNodePath

        del self.pusher
        # del self.pusherFloor
        del self.event
        del self.lifter

        del self.getAirborneHeight

    def setCollisionsActive(self, active=1):
        assert self.notify.debugStateCall(self)
        if self.collisionsActive != active:
            self.collisionsActive = active
            # Each time we change the collision geometry, make one
            # more pass to ensure we aren't standing in a wall.
            self.oneTimeCollide()
            # make sure we have a shadow traverser
            base.initShadowTrav()
            if active:
                if 1:
                    # Please let skyler or drose know if this is causing a problem
                    # This is a bit of a hack fix:
                    self.avatarNodePath.setP(0.0)
                    self.avatarNodePath.setR(0.0)
                self.cTrav.addCollider(self.cWallSphereNodePath, self.pusher)
                if self.wantFloorSphere:
                    self.cTrav.addCollider(self.cFloorSphereNodePath,
                                           self.pusherFloor)
                # Add the lifter to the shadow traverser, which runs after
                # our traverser. This prevents the "fall through wall and
                # off ledge" bug. The problem was that we couldn't control
                # which collided first, the wall pusher or the lifter, if
                # they're in the same collision traverser. If the lifter
                # collided first, we'd start falling before getting pushed
                # back behind the wall.
                base.shadowTrav.addCollider(self.cRayNodePath, self.lifter)

                if self.earlyEventSphere:
                    # If we want to trigger the events at the same
                    # time as we intersect walls (e.g. Toontown, for
                    # backward compatibility issues), add the event
                    # sphere to the main traverser.  This allows us to
                    # hit door triggers that are just slightly behind
                    # the door itself.
                    self.cTrav.addCollider(self.cEventSphereNodePath,
                                           self.event)
                else:
                    # Normally, we'd rather trigger the events after
                    # the pusher has had a chance to fix up our
                    # position, so we never trigger things that are
                    # behind other polygons.
                    base.shadowTrav.addCollider(self.cEventSphereNodePath,
                                                self.event)

            else:
                if hasattr(self, 'cTrav'):
                    self.cTrav.removeCollider(self.cWallSphereNodePath)
                    if self.wantFloorSphere:
                        self.cTrav.removeCollider(self.cFloorSphereNodePath)
                    self.cTrav.removeCollider(self.cEventSphereNodePath)
                base.shadowTrav.removeCollider(self.cEventSphereNodePath)
                base.shadowTrav.removeCollider(self.cRayNodePath)

    def getCollisionsActive(self):
        assert self.debugPrint("getCollisionsActive() returning=%s" %
                               (self.collisionsActive, ))
        return self.collisionsActive

    def placeOnFloor(self):
        """
        Make a reasonable effor to place the avatar on the ground.
        For example, this is useful when switching away from the
        current walker.
        """
        assert self.notify.debugStateCall(self)
        self.oneTimeCollide()
        self.avatarNodePath.setZ(self.avatarNodePath.getZ() -
                                 self.lifter.getAirborneHeight())

    def oneTimeCollide(self):
        """
        Makes one quick collision pass for the avatar, for instance as
        a one-time straighten-things-up operation after collisions
        have been disabled.
        """
        assert self.notify.debugStateCall(self)
        if not hasattr(self, 'cWallSphereNodePath'):
            return
        self.isAirborne = 0
        self.mayJump = 1
        tempCTrav = CollisionTraverser("oneTimeCollide")
        tempCTrav.addCollider(self.cWallSphereNodePath, self.pusher)
        if self.wantFloorSphere:
            tempCTrav.addCollider(self.cFloorSphereNodePath, self.event)
        tempCTrav.addCollider(self.cRayNodePath, self.lifter)
        tempCTrav.traverse(render)

    def setMayJump(self, task):
        """
        This function's use is internal to this class (maybe I'll add
        the __ someday).  Anyway, if you want to enable or disable
        jumping in a general way see the ControlManager (don't use this).
        """
        assert self.notify.debugStateCall(self)
        self.mayJump = 1
        return Task.done

    def startJumpDelay(self, delay):
        assert self.notify.debugStateCall(self)
        if self.jumpDelayTask:
            self.jumpDelayTask.remove()
        self.mayJump = 0
        self.jumpDelayTask = taskMgr.doMethodLater(delay, self.setMayJump,
                                                   "jumpDelay-%s" % id(self))

    def addBlastForce(self, vector):
        self.lifter.addVelocity(vector.length())

    def displayDebugInfo(self):
        """
        For debug use.
        """
        onScreenDebug.add("w controls", "GravityWalker")

        onScreenDebug.add("w airborneHeight", self.lifter.getAirborneHeight())
        onScreenDebug.add("w falling", self.falling)
        onScreenDebug.add("w isOnGround", self.lifter.isOnGround())
        #onScreenDebug.add("w gravity", self.lifter.getGravity())
        #onScreenDebug.add("w jumpForce", self.avatarControlJumpForce)
        onScreenDebug.add("w contact normal",
                          self.lifter.getContactNormal().pPrintValues())
        onScreenDebug.add("w mayJump", self.mayJump)
        onScreenDebug.add("w impact", self.lifter.getImpactVelocity())
        onScreenDebug.add("w velocity", self.lifter.getVelocity())
        onScreenDebug.add("w isAirborne", self.isAirborne)
        onScreenDebug.add("w hasContact", self.lifter.hasContact())

    def handleAvatarControls(self, task):
        """
        Check on the arrow keys and update the avatar.
        """
        # get the button states:
        run = inputState.isSet("run")
        forward = inputState.isSet("forward")
        reverse = inputState.isSet("reverse")
        turnLeft = inputState.isSet("turnLeft")
        turnRight = inputState.isSet("turnRight")
        slideLeft = inputState.isSet("slideLeft")
        slideRight = inputState.isSet("slideRight")
        jump = inputState.isSet("jump")

        # Check for Auto-Run
        if 'localAvatar' in __builtins__:
            if base.localAvatar and base.localAvatar.getAutoRun():
                forward = 1
                reverse = 0

        # Determine what the speeds are based on the buttons:
        self.speed = (forward and self.avatarControlForwardSpeed
                      or reverse and -self.avatarControlReverseSpeed)
        # Slide speed is a scaled down version of forward speed
        # Note: you can multiply a factor in here if you want slide to
        # be slower than normal walk/run. Let's try full speed.
        #self.slideSpeed=(slideLeft and -self.avatarControlForwardSpeed*0.75 or
        #                 slideRight and self.avatarControlForwardSpeed*0.75)
        self.slideSpeed = (
            reverse and slideLeft and -self.avatarControlReverseSpeed * 0.75
            or reverse and slideRight and self.avatarControlReverseSpeed * 0.75
            or slideLeft and -self.avatarControlForwardSpeed * 0.75
            or slideRight and self.avatarControlForwardSpeed * 0.75)
        self.rotationSpeed = not (slideLeft or slideRight) and (
            (turnLeft and self.avatarControlRotateSpeed) or
            (turnRight and -self.avatarControlRotateSpeed))

        if self.speed and self.slideSpeed:
            self.speed *= GravityWalker.DiagonalFactor
            self.slideSpeed *= GravityWalker.DiagonalFactor

        debugRunning = inputState.isSet("debugRunning")
        if (debugRunning):
            self.speed *= base.debugRunningMultiplier
            self.slideSpeed *= base.debugRunningMultiplier
            self.rotationSpeed *= 1.25

        if self.needToDeltaPos:
            self.setPriorParentVector()
            self.needToDeltaPos = 0
        if self.wantDebugIndicator:
            self.displayDebugInfo()
        if self.lifter.isOnGround():
            if self.isAirborne:
                self.isAirborne = 0
                assert self.debugPrint("isAirborne 0 due to isOnGround() true")
                impact = self.lifter.getImpactVelocity()
                if impact < -30.0:
                    messenger.send("jumpHardLand")
                    self.startJumpDelay(0.3)
                else:
                    messenger.send("jumpLand")
                    if impact < -5.0:
                        self.startJumpDelay(0.2)
                    # else, ignore the little potholes.
            assert self.isAirborne == 0
            self.priorParent = Vec3.zero()
            if jump and self.mayJump:
                # The jump button is down and we're close
                # enough to the ground to jump.
                self.lifter.addVelocity(self.avatarControlJumpForce)
                messenger.send("jumpStart")
                self.isAirborne = 1
                assert self.debugPrint("isAirborne 1 due to jump")
        else:
            if self.isAirborne == 0:
                assert self.debugPrint(
                    "isAirborne 1 due to isOnGround() false")
            self.isAirborne = 1

        self.__oldPosDelta = self.avatarNodePath.getPosDelta(render)
        # How far did we move based on the amount of time elapsed?
        self.__oldDt = ClockObject.getGlobalClock().getDt()
        dt = self.__oldDt

        # Check to see if we're moving at all:
        self.moving = self.speed or self.slideSpeed or self.rotationSpeed or (
            self.priorParent != Vec3.zero())
        if self.moving:
            distance = dt * self.speed
            slideDistance = dt * self.slideSpeed
            rotation = dt * self.rotationSpeed

            # Take a step in the direction of our previous heading.
            if distance or slideDistance or self.priorParent != Vec3.zero():
                # rotMat is the rotation matrix corresponding to
                # our previous heading.
                rotMat = Mat3.rotateMatNormaxis(self.avatarNodePath.getH(),
                                                Vec3.up())
                if self.isAirborne:
                    forward = Vec3.forward()
                else:
                    contact = self.lifter.getContactNormal()
                    forward = contact.cross(Vec3.right())
                    # Consider commenting out this normalize.  If you do so
                    # then going up and down slops is a touch slower and
                    # steeper terrain can cut the movement in half.  Without
                    # the normalize the movement is slowed by the cosine of
                    # the slope (i.e. it is multiplied by the sign as a
                    # side effect of the cross product above).
                    forward.normalize()
                self.vel = Vec3(forward * distance)
                if slideDistance:
                    if self.isAirborne:
                        right = Vec3.right()
                    else:
                        right = forward.cross(contact)
                        # See note above for forward.normalize()
                        right.normalize()
                    self.vel = Vec3(self.vel + (right * slideDistance))
                self.vel = Vec3(rotMat.xform(self.vel))
                step = self.vel + (self.priorParent * dt)
                self.avatarNodePath.setFluidPos(
                    Point3(self.avatarNodePath.getPos() + step))
            self.avatarNodePath.setH(self.avatarNodePath.getH() + rotation)
        else:
            self.vel.set(0.0, 0.0, 0.0)
        if self.moving or jump:
            messenger.send("avatarMoving")
        return Task.cont

    def doDeltaPos(self):
        assert self.notify.debugStateCall(self)
        self.needToDeltaPos = 1

    def setPriorParentVector(self):
        assert self.notify.debugStateCall(self)
        if __debug__:
            onScreenDebug.add("__oldDt", "% 10.4f" % self.__oldDt)
            onScreenDebug.add("self.__oldPosDelta",
                              self.__oldPosDelta.pPrintValues())
        # avoid divide by zero crash - grw
        if self.__oldDt == 0:
            velocity = 0
        else:
            velocity = self.__oldPosDelta * (1.0 / self.__oldDt)
        self.priorParent = Vec3(velocity)
        if __debug__:
            if self.wantDebugIndicator:
                onScreenDebug.add("priorParent",
                                  self.priorParent.pPrintValues())

    def reset(self):
        assert self.notify.debugStateCall(self)
        self.lifter.setVelocity(0.0)
        self.priorParent = Vec3.zero()

    def getVelocity(self):
        return self.vel

    def enableAvatarControls(self):
        """
        Activate the arrow keys, etc.
        """
        assert self.notify.debugStateCall(self)
        assert self.collisionsActive

        #*#if __debug__:
        #*#    self.accept("control-f3", self.spawnTest) #*#

        # remove any old
        if self.controlsTask:
            self.controlsTask.remove()
        # spawn the new task
        taskName = "AvatarControls-%s" % (id(self), )
        self.controlsTask = taskMgr.add(self.handleAvatarControls, taskName,
                                        25)

        self.isAirborne = 0
        self.mayJump = 1

        if self.physVelocityIndicator:
            if self.indicatorTask:
                self.indicatorTask.remove()
            self.indicatorTask = taskMgr.add(
                self.avatarPhysicsIndicator,
                "AvatarControlsIndicator-%s" % (id(self), ), 35)

    def disableAvatarControls(self):
        """
        Ignore the arrow keys, etc.
        """
        assert self.notify.debugStateCall(self)
        if self.controlsTask:
            self.controlsTask.remove()
            self.controlsTask = None
        if self.indicatorTask:
            self.indicatorTask.remove()
            self.indicatorTask = None
        if self.jumpDelayTask:
            self.jumpDelayTask.remove()
            self.jumpDelayTask = None

        if __debug__:
            self.ignore("control-f3")  #*#

    def flushEventHandlers(self):
        if hasattr(self, 'cTrav'):
            self.pusher.flush()
            if self.wantFloorSphere:
                self.floorPusher.flush()
            self.event.flush()
        self.lifter.flush()  # not currently defined or needed

    if __debug__:

        def debugPrint(self, message):
            """for debugging"""
            return self.notify.debug(str(id(self)) + ' ' + message)
Beispiel #10
0
class MessengerLeakDetector(Job):
    # check for objects that are only referenced by the messenger
    # and would otherwise be garbage collected
    notify = directNotify.newCategory("MessengerLeakDetector")

    def __init__(self, name):
        Job.__init__(self, name)
        self.setPriority(Job.Priorities.Normal * 2)
        jobMgr.add(self)

    def run(self):
        # set of ids of objects that we know are always attached to builtin;
        # if an object is attached to one of these, it's attached to builtin
        # this cuts down on the amount of searching that needs to be done
        builtinIds = set()
        builtinIds.add(id(__builtin__.__dict__))
        try:
            builtinIds.add(id(base))
            builtinIds.add(id(base.cr))
            builtinIds.add(id(base.cr.doId2do))
        except:
            pass
        try:
            builtinIds.add(id(simbase))
            builtinIds.add(id(simbase.air))
            builtinIds.add(id(simbase.air.doId2do))
        except:
            pass
        try:
            builtinIds.add(id(uber))
            builtinIds.add(id(uber.air))
            builtinIds.add(id(uber.air.doId2do))
        except:
            pass

        while True:
            yield None
            objects = messenger._Messenger__objectEvents.keys()
            assert self.notify.debug('%s objects in the messenger' %
                                     len(objects))
            for object in objects:
                yield None
                assert self.notify.debug('---> new object: %s' % itype(object))
                # try to find a path to builtin that doesn't involve the messenger
                # lists of objects for breadth-first search
                # iterate through one list while populating other list
                objList1 = []
                objList2 = []
                curObjList = objList1
                nextObjList = objList2
                visitedObjIds = set()

                # add the id of the object, and the messenger containers so that
                # the search for builtin will stop at the messenger; we're looking
                # for any path to builtin that don't involve the messenger
                visitedObjIds.add(id(object))
                visitedObjIds.add(id(messenger._Messenger__objectEvents))
                visitedObjIds.add(id(messenger._Messenger__callbacks))

                nextObjList.append(object)
                foundBuiltin = False

                # breadth-first search, go until you run out of new objects or you find __builtin__
                while len(nextObjList):
                    if foundBuiltin:
                        break
                    # swap the lists, prepare for the next pass
                    curObjList = nextObjList
                    nextObjList = []
                    assert self.notify.debug(
                        'next search iteration, num objects: %s' %
                        len(curObjList))
                    for curObj in curObjList:
                        if foundBuiltin:
                            break
                        yield None
                        referrers = gc.get_referrers(curObj)
                        assert self.notify.debug(
                            'curObj: %s @ %s, %s referrers, repr=%s' %
                            (itype(curObj), hex(id(curObj)), len(referrers),
                             fastRepr(curObj, maxLen=2)))
                        for referrer in referrers:
                            #assert self.notify.debug('referrer: %s' % itype(curObj))
                            yield None
                            refId = id(referrer)
                            # don't go in a loop
                            if refId in visitedObjIds:
                                #assert self.notify.debug('already visited')
                                continue
                            # don't self-reference
                            if referrer is curObjList or referrer is nextObjList:
                                continue
                            if refId in builtinIds:
                                # not a leak, there is a path to builtin that does not involve the messenger
                                #assert self.notify.debug('object has another path to __builtin__, it\'s not a messenger leak')
                                foundBuiltin = True
                                break
                            else:
                                visitedObjIds.add(refId)
                                nextObjList.append(referrer)

                if not foundBuiltin:
                    self.notify.warning(
                        '%s is referenced only by the messenger' %
                        (itype(object)))
Beispiel #11
0
class ShipPilot2(PhysicsWalker):
    notify = directNotify.newCategory("PhysicsWalker")
    wantDebugIndicator = base.config.GetBool('want-avatar-physics-indicator',
                                             0)

    useBowSternSpheres = 1
    useOneSphere = 0
    useDSSolid = 0
    useLifter = 0
    useHeightRay = 0

    MAX_STRAIGHT_SAIL_BONUS = 4.0
    STRAIGHT_SAIL_BONUS_TIME = 10.0

    # special methods
    def __init__(self,
                 gravity=-32.1740,
                 standableGround=0.707,
                 hardLandingForce=16.0):
        assert self.debugPrint(
            "PhysicsWalker(gravity=%s, standableGround=%s)" %
            (gravity, standableGround))
        PhysicsWalker.__init__(self, gravity, standableGround,
                               hardLandingForce)
        self.__gravity = gravity
        self.__standableGround = standableGround
        self.__hardLandingForce = hardLandingForce

        self.needToDeltaPos = 0
        self.physVelocityIndicator = None
        self.avatarControlForwardSpeed = 0
        self.avatarControlJumpForce = 0
        self.avatarControlReverseSpeed = 0
        self.avatarControlRotateSpeed = 0
        self.__oldAirborneHeight = None
        self.getAirborneHeight = None
        self.__oldContact = None
        self.__oldPosDelta = Vec3(0)
        self.__oldDt = 0
        self.__speed = 0.0
        self.__rotationSpeed = 0.0
        self.__slideSpeed = 0.0
        self.__vel = Vec3(0.0)
        self.collisionsActive = 0
        self.currentTurning = 0.0

        self.isAirborne = 0
        self.highMark = 0
        self.ship = None

        # Keeps track of the ship sailing in a straight heading
        # for long periods of time.  We slowly up the ship's max
        # acceleration as this increases.
        self.straightHeading = 0

    def setWalkSpeed(self, forward, jump, reverse, rotate):
        assert self.debugPrint("setWalkSpeed()")
        self.avatarControlForwardSpeed = forward
        self.avatarControlJumpForce = 0.0
        self.avatarControlReverseSpeed = reverse
        self.avatarControlRotateSpeed = rotate

    def getSpeeds(self):
        #assert self.debugPrint("getSpeeds()")
        return (self.__speed, self.__rotationSpeed)

    def setAvatar(self, ship):
        if ship is None:
            base.controlForce.clearPhysicsObject()
            self.takedownPhysics()
            self.ship = None
        else:
            base.controlForce.setPhysicsObject(ship.node().getPhysicsObject())
            #self.setupShip()
            self.setupPhysics(ship)
            self.ship = ship
            """
            #*# Debug:
            if not hasattr(ship, "acceleration"):
                self.ship.acceleration = 60
                self.ship.maxSpeed = 14
                self.ship.reverseAcceleration = 30
                self.ship.maxReverseSpeed = 2
                self.ship.turnRate = 3
                self.ship.maxTurn = 30
                self.ship.anchorDrag = .9
                self.ship.hullDrag = .9
            """

    def setupRay(self, floorBitmask, floorOffset):
        # This is a ray cast from your head down to detect floor polygons
        # A toon is about 4.0 feet high, so start it there
        self.cRay = CollisionRay(0.0, 0.0, CollisionHandlerRayStart, 0.0, 0.0,
                                 -1.0)
        cRayNode = CollisionNode('PW.cRayNode')
        cRayNode.addSolid(self.cRay)
        self.cRayNodePath = self.avatarNodePath.attachNewNode(cRayNode)
        self.cRayBitMask = floorBitmask
        cRayNode.setFromCollideMask(self.cRayBitMask)
        cRayNode.setIntoCollideMask(BitMask32.allOff())

        if 0 or self.useLifter:
            # set up floor collision mechanism
            self.lifter = CollisionHandlerFloor()
            self.lifter.setInPattern("enter%in")
            self.lifter.setOutPattern("exit%in")
            self.lifter.setOffset(floorOffset)

            # Limit our rate-of-fall with the lifter.
            # If this is too low, we actually "fall" off steep stairs
            # and float above them as we go down. I increased this
            # from 8.0 to 16.0 to prevent this
            #self.lifter.setMaxVelocity(16.0)

            #self.bobNodePath = self.avatarNodePath.attachNewNode("bob")
            #self.lifter.addCollider(self.cRayNodePath, self.cRayNodePath)
            self.lifter.addCollider(self.cRayNodePath, self.avatarNodePath)
        else:  # useCollisionHandlerQueue
            self.cRayQueue = CollisionHandlerQueue()
            self.cTrav.addCollider(self.cRayNodePath, self.cRayQueue)

    def determineHeight(self):
        """
        returns the height of the avatar above the ground.
        If there is no floor below the avatar, 0.0 is returned.
        aka get airborne height.
        """
        if self.useLifter:
            height = self.avatarNodePath.getPos(self.cRayNodePath)
            # If the shadow where not pointed strait down, we would need to
            # get magnitude of the vector.  Since it is strait down, we'll
            # just get the z:
            #spammy --> assert self.debugPrint(
            #spammy -->     "getAirborneHeight() returning %s"%(height.getZ(),))
            assert onScreenDebug.add("height", height.getZ())
            return height.getZ() - self.floorOffset
        else:  # useCollisionHandlerQueue
            """
            returns the height of the avatar above the ground.
            If there is no floor below the avatar, 0.0 is returned.
            aka get airborne height.
            """
            height = 0.0
            #*#self.cRayTrav.traverse(render)
            if self.cRayQueue.getNumEntries() != 0:
                # ...we have a floor.
                # Choose the highest of the possibly several floors we're over:
                self.cRayQueue.sortEntries()
                floorPoint = self.cRayQueue.getEntry(
                    0).getFromIntersectionPoint()
                height = -floorPoint.getZ()
            self.cRayQueue.clearEntries()
            if __debug__:
                onScreenDebug.add("height", height)
            return height

    def setupSphere(self, bitmask, avatarRadius):
        """
        Set up the collision sphere
        """
        # This is a sphere on the ground to detect barrier collisions
        if 0:
            self.avatarRadius = avatarRadius
            self.cSphere = CollisionTube(Point3(0.0, 0.0, 0.0),
                                         Point3(0.0, 40.0, 0.0), avatarRadius)
            cSphereNode = CollisionNode('SP.cSphereNode')
            cSphereNode.addSolid(self.cSphere)
            self.cSphereNodePath = self.avatarNodePath.attachNewNode(
                cSphereNode)
            self.cSphereBitMask = bitmask
        else:
            # Middle sphere:
            self.avatarRadius = avatarRadius
            #self.cSphere = CollisionSphere(0.0, -5.0, 0.0, avatarRadius)
            #cSphereNode = CollisionNode('SP.cSphereNode')
            #cSphereNode.addSolid(self.cSphere)
            #self.cSphereNodePath = self.avatarNodePath.attachNewNode(cSphereNode)
            self.cSphereBitMask = bitmask

        #cSphereNode.setFromCollideMask(self.cSphereBitMask)
        #cSphereNode.setIntoCollideMask(BitMask32.allOff())

        # set up collision mechanism
        self.pusher = PhysicsCollisionHandler()
        self.pusher.setInPattern("enter%in")
        self.pusher.setOutPattern("exit%in")

        #self.pusher.addCollider(self.cSphereNodePath, self.avatarNodePath)

        if self.useBowSternSpheres:
            # Front sphere:
            self.cBowSphere = CollisionSphere(0.0, self.frontSphereOffset,
                                              -5.0, avatarRadius)
            cBowSphereNode = CollisionNode('SP.cBowSphereNode')
            cBowSphereNode.addSolid(self.cBowSphere)
            self.cBowSphereNodePath = self.avatarNodePath.attachNewNode(
                cBowSphereNode)
            #self.cBowSphereNodePath.show()

            cBowSphereNode.setFromCollideMask(self.cSphereBitMask)
            cBowSphereNode.setIntoCollideMask(BitMask32.allOff())

            self.cBowSphereNode = cBowSphereNode

            self.pusher.addCollider(self.cBowSphereNodePath,
                                    self.avatarNodePath)

            # Back sphere:
            self.cSternSphere = CollisionSphere(0.0, self.backSphereOffset,
                                                -5.0, avatarRadius)
            cSternSphereNode = CollisionNode('SP.cSternSphereNode')
            cSternSphereNode.addSolid(self.cSternSphere)
            self.cSternSphereNodePath = self.avatarNodePath.attachNewNode(
                cSternSphereNode)
            #self.cSternSphereNodePath.show()
            self.cSternSphereBitMask = bitmask

            cSternSphereNode.setFromCollideMask(self.cSphereBitMask)
            cSternSphereNode.setIntoCollideMask(BitMask32.allOff())

            self.pusher.addCollider(self.cSternSphereNodePath,
                                    self.avatarNodePath)

            # hide other things on my ship that these spheres might collide
            # with and which I dont need anyways...
            shipCollWall = self.avatarNodePath.transNode.find(
                "**/collision_hull")
            if not shipCollWall.isEmpty():
                shipCollWall.stash()
        elif self.useOneSphere:
            # Front sphere:
            self.cSphere = CollisionSphere(0.0, 0.0, -5.0, avatarRadius)
            cSphereNode = CollisionNode('SP.cSphereNode')
            cSphereNode.addSolid(self.cSphere)
            self.cSphereNodePath = self.avatarNodePath.attachNewNode(
                cSphereNode)
            if 1:
                self.cSphereNodePath.show()
                self.cSphereNodePath.showBounds()

            cSphereNode.setFromCollideMask(self.cSphereBitMask)
            cSphereNode.setIntoCollideMask(BitMask32.allOff())

            self.cSphereNode = cSphereNode

            self.pusher.addCollider(self.cSphereNodePath, self.avatarNodePath)

            # hide other things on my ship that these spheres might collide
            # with and which I dont need anyways...
            shipCollWall = self.avatarNodePath.transNode.find(
                "**/collision_hull")
            if not shipCollWall.isEmpty():
                shipCollWall.stash()
        elif self.useDSSolid:
            # DSSolid:
            self.cHull = CollisionDSSolid(
                Point3(-160, 0, 0), 200, Point3(160, 0, 0), 200,
                Plane(Vec3(0, 0, 1), Point3(0, 0, 50)),
                Plane(Vec3(0, -1, 0), Point3(0, -90, 0)))
            cHullNode = CollisionNode('SP.cHullNode')
            cHullNode.addSolid(self.cHull)
            self.cHullNodePath = self.avatarNodePath.attachNewNode(cHullNode)
            self.cHullNodePath.show()

            cHullNode.setFromCollideMask(bitmask)
            cHullNode.setIntoCollideMask(BitMask32.allOff())

            self.cHullNode = cHullNode

            self.pusher.addCollider(self.cHullNodePath, self.avatarNodePath)

            # hide other things on my ship that these spheres might collide
            # with and which I dont need anyways...
            shipCollWall = self.avatarNodePath.transNode.find(
                "**/collision_hull")
            if not shipCollWall.isEmpty():
                shipCollWall.stash()

    def takedownPhysics(self):
        assert self.debugPrint("takedownPhysics()")
        if 0:
            if hasattr(self, "phys"):
                for i in self.nodes:
                    i.removeNode()
                del self.phys
            if self.ship != None:
                self.ship.worldVelocity = Vec3.zero()

    def setupPhysics(self, avatarNodePath):
        assert self.debugPrint("setupPhysics()")
        if avatarNodePath is None:
            return
        assert not avatarNodePath.isEmpty()

        self.takedownPhysics()
        self.nodes = []
        self.actorNode = avatarNodePath.node()

        if 0:
            fn = ForceNode("ship priorParent")
            fnp = NodePath(fn)
            fnp.reparentTo(render)
            self.nodes.append(fnp)
            priorParent = LinearVectorForce(0.0, 0.0, 0.0)
            fn.addForce(priorParent)
            self.phys.addLinearForce(priorParent)
            self.priorParentNp = fnp
            self.priorParent = priorParent

        self.avatarNodePath = avatarNodePath
        #self.actorNode.getPhysicsObject().resetPosition(self.avatarNodePath.getPos())
        #self.actorNode.updateTransform()
        self.setupSphere(self.wallBitmask | self.floorBitmask,
                         self.avatarRadius)

        assert not avatarNodePath.isEmpty()

        self.setCollisionsActive(1)

    def setWallBitMask(self, bitMask):
        self.wallBitmask = bitMask

    def setFloorBitMask(self, bitMask):
        self.floorBitmask = bitMask

    def initializeCollisions(self,
                             collisionTraverser,
                             avatarRadius=1.4,
                             floorOffset=1.0,
                             reach=1.0,
                             width=30.0,
                             length=105.0,
                             height=45.0):
        """
        width is feet from port to starboard.
        length is feet from aft to bow.
        height is feet from bildge to deck (i.e. not including mast height).

        Set up the avatar collisions
        """
        assert self.debugPrint("initializeCollisions()")
        self.cTrav = collisionTraverser
        self.avatarRadius = avatarRadius
        self.floorOffset = floorOffset
        self.reach = reach
        if self.useBowSternSpheres:
            self.frontSphereOffset = length * 0.3
            self.backSphereOffset = -length * 0.7
        self.width = width
        self.length = length
        self.height = height

    def deleteCollisions(self):
        assert self.debugPrint("deleteCollisions()")
        del self.cTrav

        if self.useHeightRay:
            del self.cRayQueue
            self.cRayNodePath.removeNode()
            del self.cRayNodePath

        if hasattr(self, "cSphere"):
            del self.cSphere
            self.cSphereNodePath.removeNode()
            del self.cSphereNodePath

            del self.pusher

        self.getAirborneHeight = None

    def setTag(self, key, value):
        if not hasattr(self, "collisionTags"):
            self.collisionTags = {}
        self.collisionTags[key] = value

    def setAirborneHeightFunc(self, getAirborneHeight):
        self.getAirborneHeight = getAirborneHeight

    def setAvatarPhysicsIndicator(self, indicator):
        """
        indicator is a NodePath
        """
        assert self.debugPrint("setAvatarPhysicsIndicator()")
        self.cSphereNodePath.show()
        if indicator:
            # Indicator Node:
            change = render.attachNewNode("change")
            #change.setPos(Vec3(1.0, 1.0, 1.0))
            #change.setHpr(0.0, 0.0, 0.0)
            change.setScale(0.1)
            #change.setColor(Vec4(1.0, 1.0, 1.0, 1.0))
            indicator.reparentTo(change)

            indicatorNode = render.attachNewNode("physVelocityIndicator")
            #indicatorNode.setScale(0.1)
            #indicatorNode.setP(90.0)
            indicatorNode.setPos(self.avatarNodePath, 0.0, 0.0, 6.0)
            indicatorNode.setColor(0.0, 0.0, 1.0, 1.0)
            change.reparentTo(indicatorNode)

            self.physVelocityIndicator = indicatorNode
            # Contact Node:
            contactIndicatorNode = render.attachNewNode("physContactIndicator")
            contactIndicatorNode.setScale(0.25)
            contactIndicatorNode.setP(90.0)
            contactIndicatorNode.setPos(self.avatarNodePath, 0.0, 0.0, 5.0)
            contactIndicatorNode.setColor(1.0, 0.0, 0.0, 1.0)
            indicator.instanceTo(contactIndicatorNode)
            self.physContactIndicator = contactIndicatorNode
        else:
            print "failed load of physics indicator"

    def avatarPhysicsIndicator(self, task):
        #assert self.debugPrint("avatarPhysicsIndicator()")
        # Velocity:
        self.physVelocityIndicator.setPos(self.avatarNodePath, 0.0, 0.0, 6.0)
        physObject = self.actorNode.getPhysicsObject()
        a = physObject.getVelocity()
        self.physVelocityIndicator.setScale(math.sqrt(a.length()))
        a += self.physVelocityIndicator.getPos()
        self.physVelocityIndicator.lookAt(Point3(a))
        # Contact:
        contact = self.actorNode.getContactVector()
        if contact == Vec3.zero():
            self.physContactIndicator.hide()
        else:
            self.physContactIndicator.show()
            self.physContactIndicator.setPos(self.avatarNodePath, 0.0, 0.0,
                                             5.0)
            #contact=self.actorNode.getContactVector()
            point = Point3(contact + self.physContactIndicator.getPos())
            self.physContactIndicator.lookAt(point)
        return Task.cont

    def setCollisionsActive(self, active=1):
        assert self.debugPrint("collisionsActive(active=%s)" % (active, ))
        if self.collisionsActive != active:
            self.collisionsActive = active
            if active:
                if self.useBowSternSpheres:
                    self.cTrav.addCollider(self.cBowSphereNodePath,
                                           self.pusher)
                    self.cTrav.addCollider(self.cSternSphereNodePath,
                                           self.pusher)
                elif self.useOneSphere:
                    self.cTrav.addCollider(self.cSphereNodePath, self.pusher)
                elif self.useDSSolid:
                    self.cTrav.addCollider(self.cHullNodePath, self.pusher)
                if self.useHeightRay:
                    if self.useLifter:
                        self.cTrav.addCollider(self.cRayNodePath, self.lifter)
                    else:
                        self.cTrav.addCollider(self.cRayNodePath,
                                               self.cRayQueue)
            else:
                if self.useBowSternSpheres:
                    self.cTrav.removeCollider(self.cBowSphereNodePath)
                    self.cTrav.removeCollider(self.cSternSphereNodePath)
                elif self.useOneSphere:
                    self.cTrav.removeCollider(self.cSphereNodePath)
                elif self.useDSSolid:
                    self.cTrav.removeCollider(self.cHullNodePath)
                if self.useHeightRay:
                    self.cTrav.removeCollider(self.cRayNodePath)
                # Now that we have disabled collisions, make one more pass
                # right now to ensure we aren't standing in a wall.
                self.oneTimeCollide()

    def getCollisionsActive(self):
        assert self.debugPrint("getCollisionsActive() returning=%s" %
                               (self.collisionsActive, ))
        return self.collisionsActive

    def placeOnFloor(self):
        """
        Make a reasonable effort to place the avatar on the ground.
        For example, this is useful when switching away from the
        current walker.
        """
        self.oneTimeCollide()
        self.avatarNodePath.setZ(self.avatarNodePath.getZ() -
                                 self.getAirborneHeight())

    def oneTimeCollide(self):
        """
        Makes one quick collision pass for the avatar, for instance as
        a one-time straighten-things-up operation after collisions
        have been disabled.
        """
        assert self.debugPrint("oneTimeCollide()")
        tempCTrav = CollisionTraverser("oneTimeCollide")
        if self.useHeightRay:
            if self.useLifter:
                tempCTrav.addCollider(self.cRayNodePath, self.lifter)
            else:
                tempCTrav.addCollider(self.cRayNodePath, self.cRayQueue)
        tempCTrav.traverse(render)

    def addBlastForce(self, vector):
        pass

    def displayDebugInfo(self):
        """
        For debug use.
        """
        onScreenDebug.add("w controls", "ShipPilot")

        onScreenDebug.add("w ship", self.ship)
        onScreenDebug.add("w isAirborne", self.isAirborne)
        onScreenDebug.add(
            "posDelta1",
            self.avatarNodePath.getPosDelta(render).pPrintValues())

        physObject = self.actorNode.getPhysicsObject()
        if 0:
            onScreenDebug.add(
                "w posDelta3",
                render.getRelativeVector(
                    self.avatarNodePath,
                    self.avatarNodePath.getPosDelta(render)).pPrintValues())
        if 0:
            onScreenDebug.add("w priorParent",
                              self.priorParent.getLocalVector().pPrintValues())

            onScreenDebug.add("w physObject pos",
                              physObject.getPosition().pPrintValues())
            onScreenDebug.add(
                "w physObject hpr",
                physObject.getOrientation().getHpr().pPrintValues())
            onScreenDebug.add("w physObject orien",
                              physObject.getOrientation().pPrintValues())
        if 1:
            physObject = physObject.getVelocity()
            onScreenDebug.add("w physObject vec", physObject.pPrintValues())
            onScreenDebug.add("w physObject len",
                              "% 10.4f" % physObject.length())

            onScreenDebug.add(
                "orientation",
                self.actorNode.getPhysicsObject().getOrientation().
                pPrintValues())

        if 0:
            momentumForce = self.momentumForce.getLocalVector()
            onScreenDebug.add("w momentumForce vec",
                              momentumForce.pPrintValues())
            onScreenDebug.add("w momentumForce len",
                              "% 10.4f" % momentumForce.length())

        ## if 1:
        ## keel = self.keel.getLocalVector()
        ## onScreenDebug.add("w keel vec",
        ##    keel.pPrintValues())
        if 0:
            onScreenDebug.add(
                "posDelta4",
                self.priorParentNp.getRelativeVector(
                    render,
                    self.avatarNodePath.getPosDelta(render)).pPrintValues())
        if 0:
            onScreenDebug.add("w priorParent",
                              self.priorParent.getLocalVector().pPrintValues())
        if 0:
            onScreenDebug.add(
                "w priorParent po",
                self.priorParent.getVector(physObject).pPrintValues())

        if 1:
            onScreenDebug.add("w contact",
                              self.actorNode.getContactVector().pPrintValues())
            #onScreenDebug.add("airborneHeight", "% 10.4f"%(
            #    self.getAirborneHeight(),))

    def handleAvatarControls(self, task):
        """
        Check on the arrow keys and update the avatar.
        """
        if __debug__:
            if self.wantDebugIndicator:
                onScreenDebug.append(
                    "localAvatar pos = %s\n" %
                    (base.localAvatar.getPos().pPrintValues(), ))
                onScreenDebug.append(
                    "localAvatar hpr = %s\n" %
                    (base.localAvatar.getHpr().pPrintValues(), ))
        #assert self.debugPrint("handleAvatarControls(task=%s)"%(task,))
        physObject = self.actorNode.getPhysicsObject()
        contact = self.actorNode.getContactVector()

        # get the button states:
        forward = inputState.isSet("forward")
        reverse = inputState.isSet("reverse")
        turnLeft = inputState.isSet("slideLeft") or inputState.isSet(
            "turnLeft")
        turnRight = inputState.isSet("slideRight") or inputState.isSet(
            "turnRight")
        slide = inputState.isSet("slide")
        slideLeft = 0
        slideRight = 0
        jump = inputState.isSet("jump")
        # Determine what the speeds are based on the buttons:

        # Check for Auto-Sailing
        if self.ship.getIsAutoSailing():
            forward = 1
            reverse = 0

        # How far did we move based on the amount of time elapsed?
        dt = ClockObject.getGlobalClock().getDt()

        if reverse or turnLeft or turnRight:
            # Reset Straight Sailing Bonus
            self.straightHeading = 0

        # Straight Sailing Acceleration Bonus
        straightSailDt += dt
        straightSailBonus = 0.0
        if straightSailDt > self.STRAIGHT_SAIL_BONUS_TIME / 2.0:
            straightSailBonus = (straightSailDt -
                                 (self.STRAIGHT_SAIL_BONUS_TIME /
                                  2.0)) / self.STRAIGHT_SAIL_BONUS_TIME / 2.0
        straightSailBonus *= self.MAX_STRAIGHT_SAIL_BONUS
        straightSailBonus += 1.0

        print "##################"
        print straightSailBonus

        # this was causing the boat to get stuck moving forward or back
        if 0:
            if not hasattr(self, "sailsDeployed"):
                self.sailsDeployed = 0.0
            if forward and reverse:
                # Way anchor:
                self.__speed = 0.0
                physObject.setVelocity(Vec3.zero())
            elif forward:
                self.sailsDeployed += 0.25
                if self.sailsDeployed > 1.0:
                    self.sailsDeployed = 1.0
            elif reverse:
                self.sailsDeployed -= 0.25
                if self.sailsDeployed < -1.0:
                    self.sailsDeployed = -1.0
            self.__speed = self.ship.acceleration * self.sailsDeployed
        else:
            self.__speed=(forward and self.ship.acceleration) or \
                (reverse and -self.ship.reverseAcceleration)
            #self.__speed=(forward and min(dt*(self.__speed + self.ship.acceleration), self.ship.maxSpeed) or
            #        reverse and min(dt*(self.__speed - self.ship.reverseAcceleration), self.ship.maxReverseSpeed))

        avatarSlideSpeed = self.ship.acceleration * 0.5
        #self.__slideSpeed=slide and (
        #        (turnLeft and -avatarSlideSpeed) or
        #        (turnRight and avatarSlideSpeed))
        self.__slideSpeed = (forward or reverse) and (
            (slideLeft and -avatarSlideSpeed) or
            (slideRight and avatarSlideSpeed))
        self.__rotationSpeed = not slide and (
            (turnLeft and self.ship.turnRate) or
            (turnRight and -self.ship.turnRate))

        # Add in Straight Sailing Multiplier
        self.__speed *= straightSailBonus

        # Enable debug turbo mode
        maxSpeed = self.ship.maxSpeed * straightSailBonus
        debugRunning = inputState.isSet("debugRunning")
        if debugRunning or base.localAvatar.getTurbo():
            self.__speed *= 4.0
            self.__slideSpeed *= 4.0
            self.__rotationSpeed *= 1.25
            maxSpeed = self.ship.maxSpeed * 4.0

        #self.__speed*=4.0
        #self.__slideSpeed*=4.0
        #self.__rotationSpeed*=1.25
        #maxSpeed = self.ship.maxSpeed * 4.0

        #*#
        self.currentTurning += self.__rotationSpeed
        if self.currentTurning > self.ship.maxTurn:
            self.currentTurning = self.ship.maxTurn
        elif self.currentTurning < -self.ship.maxTurn:
            self.currentTurning = -self.ship.maxTurn
        if turnLeft or turnRight:
            mult = .9
        elif forward or reverse:
            mult = .82
        else:
            mult = .8
        self.currentTurning *= mult
        if self.currentTurning < 0.001 and self.currentTurning > -0.001:
            self.currentTurning = 0.0
        self.__rotationSpeed = self.currentTurning

        if self.wantDebugIndicator:
            self.displayDebugInfo()

        if self.needToDeltaPos:
            self.setPriorParentVector()
            self.needToDeltaPos = 0

        airborneHeight = self.getAirborneHeight()
        if airborneHeight > self.highMark:
            self.highMark = airborneHeight
            if __debug__:
                onScreenDebug.add("highMark", "% 10.4f" % (self.highMark, ))
        #if airborneHeight < 0.1: #contact!=Vec3.zero():
        if 1:
            if (airborneHeight > self.avatarRadius * 0.5
                    or physObject.getVelocity().getZ() >
                    0.0):  # Check stair angles before changing this.
                # The avatar is airborne (maybe a lot or a tiny amount).
                self.isAirborne = 1
            else:
                # The avatar is very close to the ground (close
                # enough to be considered on the ground).
                if self.isAirborne and physObject.getVelocity().getZ() <= 0.0:
                    # the avatar has landed.
                    contactLength = contact.length()
                    if contactLength > self.__hardLandingForce:
                        messenger.send("shipJumpHardLand")
                    else:
                        messenger.send("shipJumpLand")
                    #self.priorParent.setVector(Vec3.zero())
                    self.isAirborne = 0
                elif jump:
                    #self.__jumpButton=0
                    messenger.send("shipJumpStart")
                    if 0:
                        # Jump away from walls and with with the slope normal.
                        jumpVec = Vec3(contact + Vec3.up())
                        #jumpVec=Vec3(rotAvatarToPhys.xform(jumpVec))
                        jumpVec.normalize()
                    else:
                        # Jump straight up, even if next to a wall.
                        jumpVec = Vec3.up()
                    jumpVec *= self.avatarControlJumpForce
                    physObject.addImpulse(Vec3(jumpVec))
                    self.isAirborne = 1  # Avoid double impulse before fully airborne.
                else:
                    self.isAirborne = 0
            if __debug__:
                onScreenDebug.add("isAirborne", "%d" % (self.isAirborne, ))
        else:
            if contact != Vec3.zero():
                # The avatar has touched something (but might
                # not be on the ground).
                contactLength = contact.length()
                contact.normalize()
                angle = contact.dot(Vec3.up())
                if angle > self.__standableGround:
                    # ...avatar is on standable ground.
                    if self.__oldContact == Vec3.zero():
                        #if self.__oldAirborneHeight > 0.1: #self.__oldContact==Vec3.zero():
                        # ...avatar was airborne.
                        self.jumpCount -= 1
                        if contactLength > self.__hardLandingForce:
                            messenger.send("jumpHardLand")
                        else:
                            messenger.send("jumpLand")
                    elif jump:
                        self.jumpCount += 1
                        #self.__jumpButton=0
                        messenger.send("jumpStart")
                        jump = Vec3(contact + Vec3.up())
                        #jump=Vec3(rotAvatarToPhys.xform(jump))
                        jump.normalize()
                        jump *= self.avatarControlJumpForce
                        physObject.addImpulse(Vec3(jump))

        if contact != self.__oldContact:
            # We must copy the vector to preserve it:
            self.__oldContact = Vec3(contact)
        self.__oldAirborneHeight = airborneHeight

        #------------------------------
        #debugTempH=self.avatarNodePath.getH()
        if __debug__:
            q1 = self.avatarNodePath.getQuat()
            q2 = physObject.getOrientation()
            q1.normalize()
            q2.normalize()
            assert q1.isSameDirection(q2) or (q1.getHpr() == q2.getHpr())
        assert self.avatarNodePath.getPos().almostEqual(
            physObject.getPosition(), 0.0001)
        #------------------------------

        # Check to see if we're moving at all:
        physVel = physObject.getVelocity()
        physVelLen = physVel.length()
        if (physVelLen != 0. or self.__speed or self.__slideSpeed
                or self.__rotationSpeed):
            distance = dt * self.__speed
            goForward = True
            if (distance < 0):
                goForward = False
            slideDistance = dt * self.__slideSpeed
            rotation = dt * self.__rotationSpeed

            # update pos:
            # Take a step in the direction of our previous heading.
            self.__vel = Vec3(Vec3.forward() * distance +
                              Vec3.right() * slideDistance)

            # rotMat is the rotation matrix corresponding to
            # our previous heading.
            rotMat = Mat3.rotateMatNormaxis(self.avatarNodePath.getH(),
                                            Vec3.up())
            step = rotMat.xform(self.__vel)

            #newVector = self.acForce.getLocalVector()+Vec3(step)
            newVector = Vec3(step)
            #newVector=Vec3(rotMat.xform(newVector))
            #maxLen = maxSpeed
            if (goForward):
                maxLen = self.ship.acceleration
            else:
                maxLen = self.ship.reverseAcceleration
            if newVector.length() > maxLen:
                newVector.normalize()
                newVector *= maxLen

            if __debug__:
                onScreenDebug.add("newVector", newVector)
                onScreenDebug.add("newVector length", newVector.length())
            base.controlForce.setVector(newVector)
            assert base.controlForce.getLocalVector() == newVector
            assert base.controlForce.getPhysicsObject()
            assert base.controlForce.getPhysicsObject() == physObject

            #momentum = self.momentumForce.getLocalVector()
            #momentum *= 0.9
            #self.momentumForce.setVector(momentum)

            # update hpr:
            o = physObject.getOrientation()
            r = LRotationf()
            r.setHpr(Vec3(rotation, 0.0, 0.0))
            physObject.setOrientation(o * r)

            # sync the change:
            self.actorNode.updateTransform()
            #assert self.avatarNodePath.getH()==debugTempH-rotation
            messenger.send("avatarMoving")
        else:
            # even if there are no active inputs, we still might be moving
            assert physObject.getVelocity().length() == 0.
            #base.controlForce.setVector(Vec3.zero())
            goForward = True

        #*#
        speed = physVel
        if (goForward):
            if physVelLen > maxSpeed:
                speed.normalize()
                speed *= maxSpeed
        else:
            if physVelLen > self.ship.maxReverseSpeed:
                speed.normalize()
                speed *= self.ship.maxReverseSpeed

        #speed *= 1.0 - dt * 0.05

        # modify based on sail damage
        speed *= self.ship.Sp
        speed /= self.ship.maxSp
        ## physObject.setVelocity(speed)

        #rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up())
        #speed=rotMat.xform(speed)
        # The momentumForce makes it feel like we are sliding on ice -- Joe
        # f = Vec3(self.__vel)
        # f.normalize()
        # self.momentumForce.setVector(Vec3(f*(speed.length()*0.9)))

        if __debug__:
            q1 = self.avatarNodePath.getQuat()
            q2 = physObject.getOrientation()
            q1.normalize()
            q2.normalize()
            assert q1.isSameDirection(q2) or q1.getHpr() == q2.getHpr()
        assert self.avatarNodePath.getPos().almostEqual(
            physObject.getPosition(), 0.0001)

        # Clear the contact vector so we can
        # tell if we contact something next frame
        self.actorNode.setContactVector(Vec3.zero())

        self.__oldPosDelta = self.avatarNodePath.getPosDelta(render)
        self.__oldDt = dt
        assert hasattr(self.ship, 'worldVelocity')
        self.ship.worldVelocity = self.__oldPosDelta * (1 / self.__oldDt)
        if self.wantDebugIndicator:
            onScreenDebug.add("w __oldPosDelta vec",
                              self.__oldPosDelta.pPrintValues())
            onScreenDebug.add("w __oldPosDelta len",
                              "% 10.4f" % self.__oldPosDelta.length())
            onScreenDebug.add("w __oldDt", "% 10.4f" % self.__oldDt)
            onScreenDebug.add("w worldVelocity vec",
                              self.ship.worldVelocity.pPrintValues())
            onScreenDebug.add("w worldVelocity len",
                              "% 10.4f" % self.ship.worldVelocity.length())

        # if hasattr(self.ship, 'sailBillow'):
        #     self.ship.sailBillow = self.sailsDeployed

        if hasattr(self.ship, 'currentTurning'):
            self.ship.currentTurning = self.currentTurning

        return Task.cont

    def doDeltaPos(self):
        assert self.debugPrint("doDeltaPos()")
        self.needToDeltaPos = 1

    def setPriorParentVector(self):
        assert self.debugPrint("doDeltaPos()")

        #print "self.__oldDt", self.__oldDt, "self.__oldPosDelta", self.__oldPosDelta
        if __debug__:
            onScreenDebug.add("__oldDt", "% 10.4f" % self.__oldDt)
            onScreenDebug.add("self.__oldPosDelta",
                              self.__oldPosDelta.pPrintValues())

        velocity = self.__oldPosDelta * (1 / self.__oldDt
                                         )  #*4.0 # *4.0 is a hack
        assert self.debugPrint("  __oldPosDelta=%s" % (self.__oldPosDelta, ))
        assert self.debugPrint("  velocity=%s" % (velocity, ))
        self.priorParent.setVector(Vec3(velocity))
        if __debug__:
            if self.wantDebugIndicator:
                onScreenDebug.add("velocity", velocity.pPrintValues())

    def reset(self):
        assert self.debugPrint("reset()")
        self.actorNode.getPhysicsObject().resetPosition(
            self.avatarNodePath.getPos())
        self.priorParent.setVector(Vec3.zero())
        self.highMark = 0
        self.actorNode.setContactVector(Vec3.zero())
        if __debug__:
            contact = self.actorNode.getContactVector()
            onScreenDebug.add(
                "priorParent po",
                self.priorParent.getVector(
                    self.actorNode.getPhysicsObject()).pPrintValues())
            onScreenDebug.add("highMark", "% 10.4f" % (self.highMark, ))
            onScreenDebug.add("contact", contact.pPrintValues())

    def getVelocity(self):
        return self.__vel

    def enableAvatarControls(self):
        """
        Activate the arrow keys, etc.
        """
        assert self.debugPrint("enableAvatarControls()")
        assert self.collisionsActive

        if __debug__:
            #self.accept("control-f3", self.spawnTest) #*#
            self.accept("f3", self.reset)  # for debugging only.

        taskName = "AvatarControls-%s" % (id(self), )
        # remove any old
        taskMgr.remove(taskName)
        # spawn the new task
        taskMgr.add(self.handleAvatarControls, taskName, 25)
        if self.physVelocityIndicator:
            taskMgr.add(self.avatarPhysicsIndicator,
                        "AvatarControlsIndicator%s" % (id(self), ), 35)

    def disableAvatarControls(self):
        """
        Ignore the arrow keys, etc.
        """
        assert self.debugPrint("disableAvatarControls()")
        taskName = "AvatarControls-%s" % (id(self), )
        taskMgr.remove(taskName)

        taskName = "AvatarControlsIndicator%s" % (id(self), )
        taskMgr.remove(taskName)

        if __debug__:
            self.ignore("control-f3")  #*#
            self.ignore("f3")

    if __debug__:

        def setupAvatarPhysicsIndicator(self):
            if self.wantDebugIndicator:
                indicator = loader.loadModel('phase_5/models/props/dagger')
                #self.walkControls.setAvatarPhysicsIndicator(indicator)

        def debugPrint(self, message):
            """for debugging"""
            return self.notify.debug(str(id(self)) + ' ' + message)
Beispiel #12
0
class JobManager:
    """
    Similar to the taskMgr but designed for tasks that are CPU-intensive and/or
    not time-critical. Jobs run in a fixed timeslice that the JobManager is
    allotted each frame.
    """
    notify = directNotify.newCategory("JobManager")

    # there's one task for the JobManager, all jobs run in this task
    TaskName = 'jobManager'

    def __init__(self, timeslice=None):
        # how long do we run per frame
        self._timeslice = timeslice
        # store the jobs in these structures to allow fast lookup by various keys
        # priority -> jobId -> job
        self._pri2jobId2job = {}
        # priority -> chronological list of jobIds
        self._pri2jobIds = {}
        # jobId -> priority
        self._jobId2pri = {}
        # how many timeslices to give each job; this is used to efficiently implement
        # the relative job priorities
        self._jobId2timeslices = {}
        # how much time did the job use beyond the allotted timeslice, used to balance
        # out CPU usage
        self._jobId2overflowTime = {}
        self._useOverflowTime = None
        # this is a generator that we use to give high-priority jobs more timeslices,
        # it yields jobIds in a sequence that includes high-priority jobIds more often
        # than low-priority
        self._jobIdGenerator = None
        self._highestPriority = Job.Priorities.Normal

    def destroy(self):
        taskMgr.remove(JobManager.TaskName)
        del self._pri2jobId2job

    def add(self, job):
        pri = job.getPriority()
        jobId = job._getJobId()
        # store the job in the main table
        self._pri2jobId2job.setdefault(pri, {})
        self._pri2jobId2job[pri][jobId] = job
        # and also store a direct mapping from the job's ID to its priority
        self._jobId2pri[jobId] = pri
        # add the jobId onto the end of the list of jobIds for this priority
        self._pri2jobIds.setdefault(pri, [])
        self._pri2jobIds[pri].append(jobId)
        # record the job's relative timeslice count
        self._jobId2timeslices[jobId] = pri
        # init the overflow time tracking
        self._jobId2overflowTime[jobId] = 0.
        # reset the jobId round-robin
        self._jobIdGenerator = None
        if len(self._jobId2pri) == 1:
            taskMgr.add(self._process, JobManager.TaskName)
            self._highestPriority = pri
        elif pri > self._highestPriority:
            self._highestPriority = pri
        self.notify.debug('added job: %s' % job.getJobName())
        
    def remove(self, job):
        jobId = job._getJobId()
        # look up the job's priority
        pri = self._jobId2pri.pop(jobId)
        # TODO: this removal is a linear search
        self._pri2jobIds[pri].remove(jobId)
        # remove the job from the main table
        del self._pri2jobId2job[pri][jobId]
        # clean up the job's generator, if any
        job._cleanupGenerator()
        # remove the job's timeslice count
        self._jobId2timeslices.pop(jobId)
        # remove the overflow time
        self._jobId2overflowTime.pop(jobId)
        if len(self._pri2jobId2job[pri]) == 0:
            del self._pri2jobId2job[pri]
            if pri == self._highestPriority:
                if len(self._jobId2pri) > 0:
                    # calculate a new highest priority
                    # TODO: this is not very fast
                    priorities = self._getSortedPriorities()
                    self._highestPriority = priorities[-1]
                else:
                    taskMgr.remove(JobManager.TaskName)
                    self._highestPriority = 0
        self.notify.debug('removed job: %s' % job.getJobName())

    def finish(self, job):
        # run this job, right now, until it finishes
        assert self.notify.debugCall()
        jobId = job._getJobId()
        # look up the job's priority
        pri = self._jobId2pri[jobId]
        # grab the job
        job = self._pri2jobId2job[pri][jobId]
        gen = job._getGenerator()
        if __debug__:
            job._pstats.start()
        job.resume()
        while True:
            try:
                result = gen.next()
            except StopIteration:
                # Job didn't yield Job.Done, it ran off the end and returned
                # treat it as if it returned Job.Done
                self.notify.warning('job %s never yielded Job.Done' % job)
                result = Job.Done
            if result is Job.Done:
                job.suspend()
                self.remove(job)
                job._setFinished()
                messenger.send(job.getFinishedEvent())
                # job is done.
                break
        if __debug__:
            job._pstats.stop()

    # how long should we run per frame?
    @staticmethod
    def getDefaultTimeslice():
        # run for 1/2 millisecond per frame by default
        # config is in milliseconds, this func returns value in seconds
        return getBase().config.GetFloat('job-manager-timeslice-ms', .5) / 1000.
    def getTimeslice(self):
        if self._timeslice:
            return self._timeslice
        return self.getDefaultTimeslice()
    def setTimeslice(self, timeslice):
        self._timeslice = timeslice

    def _getSortedPriorities(self):
        # returns all job priorities in ascending order
        priorities = self._pri2jobId2job.keys()
        priorities.sort()
        return priorities

    def _process(self, task=None):
        if self._useOverflowTime is None:
            self._useOverflowTime = config.GetBool('job-use-overflow-time', 1)
        if len(self._pri2jobId2job):
            #assert self.notify.debugCall()
            # figure out how long we can run
            endT = globalClock.getRealTime() + (self.getTimeslice() * .9)
            while True:
                if self._jobIdGenerator is None:
                    # round-robin the jobs, giving high-priority jobs more timeslices
                    self._jobIdGenerator = flywheel(
                        self._jobId2timeslices.keys(),
                        countFunc = lambda jobId: self._jobId2timeslices[jobId])
                try:
                    # grab the next jobId in the sequence
                    jobId = self._jobIdGenerator.next()
                except StopIteration:
                    self._jobIdGenerator = None
                    continue
                # OK, we've selected a job to run
                pri = self._jobId2pri.get(jobId)
                if pri is None:
                    # this job is no longer present
                    continue
                # check if there's overflow time that we need to make up for
                if self._useOverflowTime:
                    overflowTime = self._jobId2overflowTime[jobId]
                    timeLeft = endT - globalClock.getRealTime()
                    if overflowTime >= timeLeft:
                        self._jobId2overflowTime[jobId] = max(0., overflowTime-timeLeft)
                        # don't run any more jobs this frame, this makes up
                        # for the extra overflow time that was used before
                        break
                job = self._pri2jobId2job[pri][jobId]
                gen = job._getGenerator()
                if __debug__:
                    job._pstats.start()
                job.resume()
                while globalClock.getRealTime() < endT:
                    try:
                        result = gen.next()
                    except StopIteration:
                        # Job didn't yield Job.Done, it ran off the end and returned
                        # treat it as if it returned Job.Done
                        self.notify.warning('job %s never yielded Job.Done' % job)
                        result = Job.Done

                    if result is Job.Sleep:
                        job.suspend()
                        if __debug__:
                            job._pstats.stop()
                        # grab the next job if there's time left
                        break
                    elif result is Job.Done:
                        job.suspend()
                        self.remove(job)
                        job._setFinished()
                        if __debug__:
                            job._pstats.stop()
                        messenger.send(job.getFinishedEvent())
                        # grab the next job if there's time left
                        break
                else:
                    # we've run out of time
                    #assert self.notify.debug('timeslice end: %s, %s' % (endT, globalClock.getRealTime()))
                    job.suspend()
                    overflowTime = globalClock.getRealTime() - endT
                    if overflowTime > self.getTimeslice():
                        self._jobId2overflowTime[jobId] += overflowTime
                    if __debug__:
                        job._pstats.stop()
                    break
                
                if len(self._pri2jobId2job) == 0:
                    # there's nothing left to do, all the jobs are done!
                    break
        return task.cont

    def __repr__(self):
        s  =   '======================================================='
        s += '\nJobManager: active jobs in descending order of priority'
        s += '\n======================================================='
        pris = self._getSortedPriorities()
        if len(pris) == 0:
            s += '\n    no jobs running'
        else:
            pris.reverse()
            for pri in pris:
                jobId2job = self._pri2jobId2job[pri]
                # run through the jobs at this priority in the order that they will run
                for jobId in self._pri2jobIds[pri]:
                    job = jobId2job[jobId]
                    s += '\n%5d: %s (jobId %s)' % (pri, job.getJobName(), jobId)
        s += '\n'
        return s
Beispiel #13
0
class State(DirectObject):
    notify = directNotify.newCategory("State")

    # this 'constant' can be used to specify that the state
    # can transition to any other state
    Any = 'ANY'

    # Keep a list of State objects currently in memory for
    # Control-C-Control-V redefining. These are just weakrefs so they
    # should not cause any leaks.
    if __debug__:
        import weakref
        States = weakref.WeakKeyDictionary()

        @classmethod
        def replaceMethod(self, oldFunction, newFunction):
            import new
            import types
            count = 0
            for state in self.States:
                # Note: you can only replace methods currently
                enterFunc = state.getEnterFunc()
                exitFunc = state.getExitFunc()
                # print 'testing: ', state, enterFunc, exitFunc, oldFunction
                if type(enterFunc) == types.MethodType:
                    if (enterFunc.im_func == oldFunction):
                        # print 'found: ', enterFunc, oldFunction
                        state.setEnterFunc(
                            new.instancemethod(newFunction, enterFunc.im_self,
                                               enterFunc.im_class))
                        count += 1
                if type(exitFunc) == types.MethodType:
                    if (exitFunc.im_func == oldFunction):
                        # print 'found: ', exitFunc, oldFunction
                        state.setExitFunc(
                            new.instancemethod(newFunction, exitFunc.im_self,
                                               exitFunc.im_class))
                        count += 1
            return count

    def __init__(self,
                 name,
                 enterFunc=None,
                 exitFunc=None,
                 transitions=Any,
                 inspectorPos=[]):
        """__init__(self, string, func, func, string[], inspectorPos = [])
        State constructor: takes name, enter func, exit func, and
        a list of states it can transition to (or State.Any)."""
        self.__name = name
        self.__enterFunc = enterFunc
        self.__exitFunc = exitFunc
        self.__transitions = transitions
        self.__FSMList = []
        if __debug__:
            self.setInspectorPos(inspectorPos)
            # For redefining
            self.States[self] = 1

    # setters and getters

    def getName(self):
        return (self.__name)

    def setName(self, stateName):
        self.__name = stateName

    def getEnterFunc(self):
        return (self.__enterFunc)

    def setEnterFunc(self, stateEnterFunc):
        self.__enterFunc = stateEnterFunc

    def getExitFunc(self):
        return (self.__exitFunc)

    def setExitFunc(self, stateExitFunc):
        self.__exitFunc = stateExitFunc

    def transitionsToAny(self):
        """ returns true if State defines transitions to any other state """
        return self.__transitions is State.Any

    def getTransitions(self):
        """
        warning -- if the state transitions to any other state,
        returns an empty list (falsely implying that the state
        has no transitions)
        see State.transitionsToAny()
        """
        if self.transitionsToAny():
            return []
        return self.__transitions

    def isTransitionDefined(self, otherState):
        if self.transitionsToAny():
            return 1

        # if we're given a state object, get its name instead
        if type(otherState) != type(''):
            otherState = otherState.getName()
        return (otherState in self.__transitions)

    def setTransitions(self, stateTransitions):
        """setTransitions(self, string[])"""
        self.__transitions = stateTransitions

    def addTransition(self, transition):
        """addTransitions(self, string)"""
        if not self.transitionsToAny():
            self.__transitions.append(transition)
        else:
            State.notify.warning(
                'attempted to add transition %s to state that '
                'transitions to any state')

    if __debug__:

        def getInspectorPos(self):
            """getInspectorPos(self)"""
            return (self.__inspectorPos)

        def setInspectorPos(self, inspectorPos):
            """setInspectorPos(self, [x, y])"""
            self.__inspectorPos = inspectorPos

    # support for HFSMs

    def getChildren(self):
        """
        Return the list of child FSMs
        """
        return (self.__FSMList)

    def setChildren(self, FSMList):
        """setChildren(self, ClassicFSM[])
        Set the children to given list of FSMs
        """
        self.__FSMList = FSMList

    def addChild(self, ClassicFSM):
        """
        Add the given ClassicFSM to list of child FSMs
        """
        self.__FSMList.append(ClassicFSM)

    def removeChild(self, ClassicFSM):
        """
        Remove the given ClassicFSM from list of child FSMs
        """
        if ClassicFSM in self.__FSMList:
            self.__FSMList.remove(ClassicFSM)

    def hasChildren(self):
        """
        Return true if state has child FSMs
        """
        return len(self.__FSMList) > 0

    def __enterChildren(self, argList):
        """
        Enter all child FSMs
        """
        for fsm in self.__FSMList:
            # Check to see if the child fsm is already in a state
            # if it is, politely request the initial state

            if fsm.getCurrentState():
                # made this 'conditional_request()' instead of 'request()' to avoid warning when
                # loading minigames where rules->frameworkInit transition doesnt exist and you
                # dont want to add it since it results in hanging the game
                fsm.conditional_request((fsm.getInitialState()).getName())

            # If it has no current state, I assume this means it
            # has never entered the initial state, so enter it
            # explicitly
            else:
                fsm.enterInitialState()

    def __exitChildren(self, argList):
        """
        Exit all child FSMs
        """
        for fsm in self.__FSMList:
            fsm.request((fsm.getFinalState()).getName())

    # basic State functionality

    def enter(self, argList=[]):
        """
        Call the enter function for this state
        """
        # enter child FSMs first. It is assumed these have a start
        # state that is safe to enter
        self.__enterChildren(argList)

        if (self.__enterFunc != None):
            apply(self.__enterFunc, argList)

    def exit(self, argList=[]):
        """
        Call the exit function for this state
        """
        # first exit child FSMs
        self.__exitChildren(argList)

        # call exit function if it exists
        if (self.__exitFunc != None):
            apply(self.__exitFunc, argList)

    def __str__(self):
        return "State: name = %s, enter = %s, exit = %s, trans = %s, children = %s" %\
               (self.__name, self.__enterFunc, self.__exitFunc, self.__transitions, self.__FSMList)
Beispiel #14
0
class LandingPage:
    notify  = directNotify.newCategory("LandingPage")
    def __init__(self):
        self.headerTemplate = LandingPageHTML.header
        self.footerTemplate = LandingPageHTML.footer
        
        self.menu = {}

        self.uriToTitle = {}

        self.quickStats = [[],{}]

        self.addQuickStat("Pages Served", 0, 0)

        self.favicon = self.readFavIcon()
        

    def readFavIcon(self):
        vfs = VirtualFileSystem.getGlobalPtr()
        filename = Filename('favicon.ico')

        searchPath = DSearchPath()
        searchPath.appendDirectory(Filename('.'))
        searchPath.appendDirectory(Filename('etc'))
        searchPath.appendDirectory(Filename.fromOsSpecific(os.path.expandvars('$DIRECT/src/http')))
        searchPath.appendDirectory(Filename.fromOsSpecific(os.path.expandvars('direct/src/http')))
        searchPath.appendDirectory(Filename.fromOsSpecific(os.path.expandvars('direct/http')))
        found = vfs.resolveFilename(filename,searchPath)
        if not found:
            raise "Couldn't find direct/http/favicon.ico"

        return vfs.readFile(filename, 1)


    def addTab(self, title, uri):
        self.menu[title] = uri
        self.uriToTitle[uri] = title

    def getMenu(self, activeTab):
        return LandingPageHTML.getTabs(self.menu,activeTab)

    def getHeader(self, activeTab = "Main"):
        s = self.headerTemplate % {'titlestring' : LandingPageHTML.title,
                                   'menustring' : self.getMenu(activeTab)}
        return s
        

    def getFooter(self):
        return self.footerTemplate % {'contact' : LandingPageHTML.contactInfo}

    def getServicesPage(self, uriToHandler):
        output = ""
        
        uriList = uriToHandler.keys()

        uriList.sort()

        autoList = []

        if "/" in uriList:
            uriList.remove("/")
            autoList.append("/")
        if "/services" in uriList:
            uriList.remove("/services")
            autoList.append("/services")
        if "/default.css" in uriList:
            uriList.remove("/default.css")
            autoList.append("/default.css")
        if "/favicon.ico" in uriList:
            uriList.remove("/favicon.ico")
            autoList.append("/favicon.ico")

        output += LandingPageHTML.getURITable(title="Application",uriList=uriList,uriToHandler=uriToHandler)

        output += LandingPageHTML.getURITable(title="Admin",uriList=autoList,uriToHandler=uriToHandler)
        
        return output

    def populateMainPage(self, body):
        LandingPageHTML.mainPageBody = body

    def setTitle(self, title):
        if LandingPageHTML.title == LandingPageHTML.defaultTitle:
            LandingPageHTML.title = title
        else:
            LandingPageHTML.title = LandingPageHTML.title + " + " + title

    def setDescription(self,desc):
        if LandingPageHTML.description == LandingPageHTML.defaultDesc:
            LandingPageHTML.description = desc
        else:
            LandingPageHTML.description = LandingPageHTML.description + "</P>\n<P>" + desc

    def setContactInfo(self,info):
        LandingPageHTML.contactInfo = info

    def getDescription(self):
        return LandingPageHTML.description

    def getQuickStatsTable(self):
        return LandingPageHTML.getQuickStatsTable(self.quickStats)

    def getMainPage(self):
        return LandingPageHTML.mainPageBody % {"description" : self.getDescription(),
                                               "quickstats" : self.getQuickStatsTable()}

    def getStyleSheet(self):
        return LandingPageHTML.stylesheet

    def getFavIcon(self):
        return self.favicon
    
    def skin(self, body, uri):
        title = self.uriToTitle.get(uri,"Services")
        return self.getHeader(title) + body + self.getFooter()

    def addQuickStat(self,item,value,position):
        if item in self.quickStats[1]:
            assert self.notify.warning("Ignoring duplicate addition of quickstat %s." % item)
            return
                                
        self.quickStats[0].insert(position,item)
        self.quickStats[1][item] = value
        
    def updateQuickStat(self,item,value):
        assert item in self.quickStats[1]

        self.quickStats[1][item] = value

    def incrementQuickStat(self,item):
        assert item in self.quickStats[1]

        self.quickStats[1][item] += 1
Beispiel #15
0
class GarbageReport(Job):
    """Detects leaked Python objects (via gc.collect()) and reports on garbage
    items, garbage-to-garbage references, and garbage cycles.
    If you just want to dump the report to the log, use GarbageLogger."""
    notify = directNotify.newCategory("GarbageReport")

    NotGarbage = 'NG'

    def __init__(self,
                 name,
                 log=True,
                 verbose=False,
                 fullReport=False,
                 findCycles=True,
                 threaded=False,
                 doneCallback=None,
                 autoDestroy=False,
                 priority=None,
                 safeMode=False,
                 delOnly=False,
                 collect=True):
        # if autoDestroy is True, GarbageReport will self-destroy after logging
        # if false, caller is responsible for calling destroy()
        # if threaded is True, processing will be performed over multiple frames
        # if collect is False, we assume that the caller just did a collect and the results
        # are still in gc.garbage
        Job.__init__(self, name)
        # stick the arguments onto a ScratchPad so we can delete them all at once
        self._args = ScratchPad(name=name,
                                log=log,
                                verbose=verbose,
                                fullReport=fullReport,
                                findCycles=findCycles,
                                doneCallback=doneCallback,
                                autoDestroy=autoDestroy,
                                safeMode=safeMode,
                                delOnly=delOnly,
                                collect=collect)
        if priority is not None:
            self.setPriority(priority)
        jobMgr.add(self)
        if not threaded:
            jobMgr.finish(self)

    def run(self):
        # do the garbage collection
        oldFlags = gc.get_debug()

        if self._args.delOnly:
            # do a collect without SAVEALL, to identify the instances that are involved in
            # cycles with instances that define __del__
            # cycles that do not involve any instances that define __del__ are cleaned up
            # automatically by Python, but they also appear in gc.garbage when SAVEALL is set
            gc.set_debug(0)
            if self._args.collect:
                gc.collect()
            garbageInstances = gc.garbage[:]
            del gc.garbage[:]
            # only yield if there's more time-consuming work to do,
            # if there's no garbage, give instant feedback
            if len(garbageInstances) > 0:
                yield None
            # don't repr the garbage list if we don't have to
            if self.notify.getDebug():
                self.notify.debug('garbageInstances == %s' %
                                  fastRepr(garbageInstances))

            self.numGarbageInstances = len(garbageInstances)
            # grab the ids of the garbage instances (objects with __del__)
            self.garbageInstanceIds = set()
            for i in xrange(len(garbageInstances)):
                self.garbageInstanceIds.add(id(garbageInstances[i]))
                if not (i % 20):
                    yield None
            # then release the list of instances so that it doesn't interfere with the gc.collect() below
            del garbageInstances
        else:
            self.garbageInstanceIds = set()

        # do a SAVEALL pass so that we have all of the objects involved in legitimate garbage cycles
        # without SAVEALL, gc.garbage only contains objects with __del__ methods
        gc.set_debug(gc.DEBUG_SAVEALL)
        if self._args.collect:
            gc.collect()
        self.garbage = gc.garbage[:]
        del gc.garbage[:]
        # only yield if there's more time-consuming work to do,
        # if there's no garbage, give instant feedback
        if len(self.garbage) > 0:
            yield None
        # don't repr the garbage list if we don't have to
        if self.notify.getDebug():
            self.notify.debug('self.garbage == %s' % fastRepr(self.garbage))
        gc.set_debug(oldFlags)

        self.numGarbage = len(self.garbage)
        # only yield if there's more time-consuming work to do,
        # if there's no garbage, give instant feedback
        if self.numGarbage > 0:
            yield None

        if self._args.verbose:
            self.notify.info('found %s garbage items' % self.numGarbage)
        """ spammy
        # print the types of the garbage first, in case the repr of an object
        # causes a crash
        if self.numGarbage > 0:
            self.notify.info('TYPES ONLY (this is only needed if a crash occurs before GarbageReport finishes):')
            for result in printNumberedTypesGen(self.garbage):
                yield None
                """

        # Py obj id -> garbage list index
        self._id2index = {}

        self.referrersByReference = {}
        self.referrersByNumber = {}

        self.referentsByReference = {}
        self.referentsByNumber = {}

        self.cycles = []
        self.cyclesBySyntax = []
        self.uniqueCycleSets = set()
        self.cycleIds = set()

        # make the id->index table to speed up the next steps
        for i in xrange(self.numGarbage):
            self._id2index[id(self.garbage[i])] = i
            if not (i % 20):
                yield None

        # grab the referrers (pointing to garbage)
        if self._args.fullReport and (self.numGarbage != 0):
            if self._args.verbose:
                self.notify.info('getting referrers...')
            for i in xrange(self.numGarbage):
                yield None
                for result in self._getReferrers(self.garbage[i]):
                    yield None
                byNum, byRef = result
                self.referrersByNumber[i] = byNum
                self.referrersByReference[i] = byRef

        # grab the referents (pointed to by garbage)
        if self.numGarbage > 0:
            if self._args.verbose:
                self.notify.info('getting referents...')
            for i in xrange(self.numGarbage):
                yield None
                for result in self._getReferents(self.garbage[i]):
                    yield None
                byNum, byRef = result
                self.referentsByNumber[i] = byNum
                self.referentsByReference[i] = byRef

        # find the cycles
        if self._args.findCycles and self.numGarbage > 0:
            if self._args.verbose:
                self.notify.info('calculating cycles...')
            for i in xrange(self.numGarbage):
                yield None
                for newCycles in self._getCycles(i, self.uniqueCycleSets):
                    yield None
                self.cycles.extend(newCycles)
                # create a representation of the cycle in human-readable form
                newCyclesBySyntax = []
                for cycle in newCycles:
                    cycleBySyntax = ''
                    objs = []
                    # leave off the last index, it's a repeat of the first index
                    for index in cycle[:-1]:
                        objs.append(self.garbage[index])
                        yield None
                    # make the list repeat so we can safely iterate off the end
                    numObjs = len(objs) - 1
                    objs.extend(objs)

                    # state variables for our loop below
                    numToSkip = 0
                    objAlreadyRepresented = False

                    # if cycle starts off with an instance dict, start with the instance instead
                    startIndex = 0
                    # + 1 to include a reference back to the first object
                    endIndex = numObjs + 1
                    if type(objs[-1]) is types.InstanceType and type(
                            objs[0]) is types.DictType:
                        startIndex -= 1
                        endIndex -= 1

                    for index in xrange(startIndex, endIndex):
                        if numToSkip:
                            numToSkip -= 1
                            continue
                        obj = objs[index]
                        if type(obj) is types.InstanceType:
                            if not objAlreadyRepresented:
                                cycleBySyntax += '%s' % obj.__class__.__name__
                            cycleBySyntax += '.'
                            # skip past the instance dict and get the member obj
                            numToSkip += 1
                            member = objs[index + 2]
                            for key, value in obj.__dict__.iteritems():
                                if value is member:
                                    break
                                yield None
                            else:
                                key = '<unknown member name>'
                            cycleBySyntax += '%s' % key
                            objAlreadyRepresented = True
                        elif type(obj) is types.DictType:
                            cycleBySyntax += '{'
                            # get object referred to by dict
                            val = objs[index + 1]
                            for key, value in obj.iteritems():
                                if value is val:
                                    break
                                yield None
                            else:
                                key = '<unknown key>'
                            cycleBySyntax += '%s}' % fastRepr(key)
                            objAlreadyRepresented = True
                        elif type(obj) in (types.TupleType, types.ListType):
                            brackets = {
                                types.TupleType: '()',
                                types.ListType: '[]',
                            }[type(obj)]
                            # get object being referenced by container
                            nextObj = objs[index + 1]
                            cycleBySyntax += brackets[0]
                            for index in xrange(len(obj)):
                                if obj[index] is nextObj:
                                    index = str(index)
                                    break
                                yield None
                            else:
                                index = '<unknown index>'
                            cycleBySyntax += '%s%s' % (index, brackets[1])
                            objAlreadyRepresented = True
                        else:
                            cycleBySyntax += '%s --> ' % itype(obj)
                            objAlreadyRepresented = False
                    newCyclesBySyntax.append(cycleBySyntax)
                    yield None
                self.cyclesBySyntax.extend(newCyclesBySyntax)
                # if we're not doing a full report, add this cycle's IDs to the master set
                if not self._args.fullReport:
                    for cycle in newCycles:
                        yield None
                        self.cycleIds.update(set(cycle))

        self.numCycles = len(self.cycles)

        if self._args.findCycles:
            s = [
                '===== GarbageReport: \'%s\' (%s %s) =====' %
                (self._args.name, self.numCycles,
                 choice(self.numCycles == 1, 'cycle', 'cycles'))
            ]
        else:
            s = ['===== GarbageReport: \'%s\' =====' % (self._args.name)]
        if self.numGarbage > 0:
            # make a list of the ids we will actually be printing
            if self._args.fullReport:
                garbageIndices = range(self.numGarbage)
            else:
                garbageIndices = list(self.cycleIds)
                garbageIndices.sort()
            numGarbage = len(garbageIndices)

            # log each individual item with a number in front of it
            if not self._args.fullReport:
                abbrev = '(abbreviated) '
            else:
                abbrev = ''
            s.append('===== Garbage Items %s=====' % abbrev)
            digits = 0
            n = numGarbage
            while n > 0:
                yield None
                digits += 1
                n /= 10
            digits = digits
            format = '%0' + '%s' % digits + 'i:%s \t%s'

            for i in xrange(numGarbage):
                yield None
                idx = garbageIndices[i]
                if self._args.safeMode:
                    # in safe mode, don't try to repr any of the objects
                    objStr = repr(itype(self.garbage[idx]))
                else:
                    objStr = fastRepr(self.garbage[idx])
                maxLen = 5000
                if len(objStr) > maxLen:
                    snip = '<SNIP>'
                    objStr = '%s%s' % (objStr[:(maxLen - len(snip))], snip)
                s.append(format % (idx, itype(self.garbage[idx]), objStr))

            # also log the types of the objects
            s.append('===== Garbage Item Types %s=====' % abbrev)
            for i in xrange(numGarbage):
                yield None
                idx = garbageIndices[i]
                objStr = str(deeptype(self.garbage[idx]))
                maxLen = 5000
                if len(objStr) > maxLen:
                    snip = '<SNIP>'
                    objStr = '%s%s' % (objStr[:(maxLen - len(snip))], snip)
                s.append(format % (idx, itype(self.garbage[idx]), objStr))

            if self._args.findCycles:
                s.append('===== Garbage Cycles (Garbage Item Numbers) =====')
                ac = AlphabetCounter()
                for i in xrange(self.numCycles):
                    yield None
                    s.append('%s:%s' % (ac.next(), self.cycles[i]))

            if self._args.findCycles:
                s.append('===== Garbage Cycles (Python Syntax) =====')
                ac = AlphabetCounter()
                for i in xrange(len(self.cyclesBySyntax)):
                    yield None
                    s.append('%s:%s' % (ac.next(), self.cyclesBySyntax[i]))

            if self._args.fullReport:
                format = '%0' + '%s' % digits + 'i:%s'
                s.append(
                    '===== Referrers By Number (what is referring to garbage item?) ====='
                )
                for i in xrange(numGarbage):
                    yield None
                    s.append(format % (i, self.referrersByNumber[i]))
                s.append(
                    '===== Referents By Number (what is garbage item referring to?) ====='
                )
                for i in xrange(numGarbage):
                    yield None
                    s.append(format % (i, self.referentsByNumber[i]))
                s.append(
                    '===== Referrers (what is referring to garbage item?) ====='
                )
                for i in xrange(numGarbage):
                    yield None
                    s.append(format % (i, self.referrersByReference[i]))
                s.append(
                    '===== Referents (what is garbage item referring to?) ====='
                )
                for i in xrange(numGarbage):
                    yield None
                    s.append(format % (i, self.referentsByReference[i]))

        self._report = s

        if self._args.log:
            self.printingBegin()
            for i in xrange(len(self._report)):
                if self.numGarbage > 0:
                    yield None
                self.notify.info(self._report[i])
            self.printingEnd()

        yield Job.Done

    def finished(self):
        if self._args.doneCallback:
            self._args.doneCallback(self)
        if self._args.autoDestroy:
            self.destroy()

    def destroy(self):
        #print 'GarbageReport.destroy'
        del self._args
        del self.garbage
        # don't get rid of these, we might need them
        #del self.numGarbage
        #del self.numCycles
        del self.referrersByReference
        del self.referrersByNumber
        del self.referentsByReference
        del self.referentsByNumber
        if hasattr(self, 'cycles'):
            del self.cycles
        del self._report
        if hasattr(self, '_reportStr'):
            del self._reportStr
        Job.destroy(self)

    def getNumCycles(self):
        # if the job hasn't run yet, we don't have a numCycles yet
        return self.numCycles

    def getDesc2numDict(self):
        # dict of python-syntax leak -> number of that type of leak
        desc2num = {}
        for cycleBySyntax in self.cyclesBySyntax:
            desc2num.setdefault(cycleBySyntax, 0)
            desc2num[cycleBySyntax] += 1
        return desc2num

    def getGarbage(self):
        return self.garbage

    def getReport(self):
        if not hasattr(self, '_reportStr'):
            self._reportStr = ''
            for str in self._report:
                self._reportStr += '\n' + str
        return self._reportStr

    def _getReferrers(self, obj):
        # referrers (pointing to garbage)
        # returns two lists, first by index into gc.garbage, second by
        # direct reference
        yield None
        byRef = gc.get_referrers(obj)
        yield None
        # look to see if each referrer is another garbage item
        byNum = []
        for i in xrange(len(byRef)):
            if not (i % 20):
                yield None
            referrer = byRef[i]
            num = self._id2index.get(id(referrer), None)
            byNum.append(num)
        yield byNum, byRef

    def _getReferents(self, obj):
        # referents (pointed to by garbage)
        # returns two lists, first by index into gc.garbage, second by
        # direct reference
        yield None
        byRef = gc.get_referents(obj)
        yield None
        # look to see if each referent is another garbage item
        byNum = []
        for i in xrange(len(byRef)):
            if not (i % 20):
                yield None
            referent = byRef[i]
            num = self._id2index.get(id(referent), None)
            byNum.append(num)
        yield byNum, byRef

    def _getNormalizedCycle(self, cycle):
        # returns a representation of a cycle (list of indices) that will be
        # reliably derived from a unique cycle regardless of ordering
        # this lets us detect duplicate cycles that appear different because of
        # which element appears first
        if len(cycle) == 0:
            return cycle
        min = 1 << 30
        minIndex = None
        for i in xrange(len(cycle)):
            elem = cycle[i]
            if elem < min:
                min = elem
                minIndex = i
        return cycle[minIndex:] + cycle[:minIndex]

    def _getCycles(self, index, uniqueCycleSets=None):
        # detect garbage cycles for a particular item of garbage
        assert self.notify.debugCall()
        # returns list of lists, sublists are garbage reference cycles
        cycles = []
        # this lets us eliminate duplicate cycles
        if uniqueCycleSets is None:
            uniqueCycleSets = set()
        stateStack = Stack()
        rootId = index
        # check if the root object is one of the garbage instances (has __del__)
        objId = id(self.garbage[rootId])
        numDelInstances = choice(objId in self.garbageInstanceIds, 1, 0)
        stateStack.push(([rootId], rootId, numDelInstances, 0))
        while True:
            yield None
            if len(stateStack) == 0:
                break
            candidateCycle, curId, numDelInstances, resumeIndex = stateStack.pop(
            )
            if self.notify.getDebug():
                if self._args.delOnly:
                    print 'restart: %s root=%s cur=%s numDelInstances=%s resume=%s' % (
                        candidateCycle, rootId, curId, numDelInstances,
                        resumeIndex)
                else:
                    print 'restart: %s root=%s cur=%s resume=%s' % (
                        candidateCycle, rootId, curId, resumeIndex)
            for index in xrange(resumeIndex,
                                len(self.referentsByNumber[curId])):
                yield None
                refId = self.referentsByNumber[curId][index]
                if self.notify.getDebug():
                    print '       : %s -> %s' % (curId, refId)
                if refId == rootId:
                    # we found a cycle! mark it down and move on to the next refId
                    normCandidateCycle = self._getNormalizedCycle(
                        candidateCycle)
                    normCandidateCycleTuple = tuple(normCandidateCycle)
                    if not normCandidateCycleTuple in uniqueCycleSets:
                        # cycles with no instances that define __del__ will be
                        # cleaned up by Python
                        if (not self._args.delOnly) or numDelInstances >= 1:
                            if self.notify.getDebug():
                                print '  FOUND: ', normCandidateCycle + [
                                    normCandidateCycle[0],
                                ]
                            cycles.append(normCandidateCycle + [
                                normCandidateCycle[0],
                            ])
                            uniqueCycleSets.add(normCandidateCycleTuple)
                elif refId in candidateCycle:
                    pass
                elif refId is not None:
                    # check if this object is one of the garbage instances (has __del__)
                    objId = id(self.garbage[refId])
                    numDelInstances += choice(objId in self.garbageInstanceIds,
                                              1, 0)
                    # this refId does not complete a cycle. Mark down
                    # where we are in this list of referents, then
                    # start looking through the referents of the new refId
                    stateStack.push((list(candidateCycle), curId,
                                     numDelInstances, index + 1))
                    stateStack.push((list(candidateCycle) + [refId], refId,
                                     numDelInstances, 0))
                    break
        yield cycles
Beispiel #16
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(__builtin__.__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
        """
Beispiel #17
0
from panda3d.pandac import ConfigConfigureGetConfigConfigShowbase as config
from panda3d.direct.directnotify.DirectNotifyGlobal import directNotify
from panda3d.direct.showbase.PythonUtil import fastRepr
from exceptions import Exception
import sys
import types
import traceback

notify = directNotify.newCategory("ExceptionVarDump")

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 #18
0
class ClassicFSM(DirectObject):
    """
    Finite State Machine class.

    This module and class exist only for backward compatibility with
    existing code.  New code should use the FSM class instead.
    """

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

    # special methods

    # these are flags that tell the ClassicFSM what to do when an
    # undefined transition is requested:
    ALLOW = 0  # print a warning, and do the transition
    DISALLOW = 1  # silently ignore the request (don't do the transition)
    DISALLOW_VERBOSE = 2  # print a warning, and don't do the transition
    ERROR = 3  # print an error message and raise an exception

    def __init__(self,
                 name,
                 states=[],
                 initialStateName=None,
                 finalStateName=None,
                 onUndefTransition=DISALLOW_VERBOSE):
        """__init__(self, string, State[], string, string, int)

        ClassicFSM constructor: takes name, list of states, initial state and
        final state as:

        fsm = ClassicFSM.ClassicFSM('stopLight',
          [State.State('red', enterRed, exitRed, ['green']),
            State.State('yellow', enterYellow, exitYellow, ['red']),
            State.State('green', enterGreen, exitGreen, ['yellow'])],
          'red',
          'red')

        each state's last argument, a list of allowed state transitions,
        is optional; if left out (or explicitly specified to be
        State.State.Any) then any transition from the state is 'defined'
        and allowed

        'onUndefTransition' flag determines behavior when undefined
        transition is requested; see flag definitions above
        """
        self.setName(name)
        self.setStates(states)
        self.setInitialState(initialStateName)
        self.setFinalState(finalStateName)

        self.onUndefTransition = onUndefTransition

        # Flag to see if we are inspecting
        self.inspecting = 0

        # We do not enter the initial state to separate
        # construction from activation
        self.__currentState = None

        # We set this while we are modifying the state.  No one else
        # should recursively attempt to modify the state while we are
        # doing this.
        self.__internalStateInFlux = 0
        if __debug__:
            global _debugFsms
            _debugFsms[name] = weakref.ref(self)

    # I know this isn't how __repr__ is supposed to be used, but it
    # is nice and convenient.
    def __repr__(self):
        return self.__str__()

    def __str__(self):
        """
        Print out something useful about the fsm
        """
        currentState = self.getCurrentState()
        if currentState:
            str = ("ClassicFSM " + self.getName() + ' in state "' +
                   currentState.getName() + '"')
        else:
            str = ("ClassicFSM " + self.getName() + ' not in any state')
        return str

    def enterInitialState(self, argList=[]):
        assert not self.__internalStateInFlux
        if self.__currentState == self.__initialState:
            return

        assert self.__currentState == None
        self.__internalStateInFlux = 1
        self.__enter(self.__initialState, argList)
        assert not self.__internalStateInFlux

    # setters and getters

    def getName(self):
        return (self.__name)

    def setName(self, name):
        self.__name = name

    def getStates(self):
        return self.__states.values()

    def setStates(self, states):
        """setStates(self, State[])"""
        # Make a dictionary from stateName -> state
        self.__states = {}
        for state in states:
            self.__states[state.getName()] = state

    def addState(self, state):
        self.__states[state.getName()] = state

    def getInitialState(self):
        return (self.__initialState)

    def setInitialState(self, initialStateName):
        self.__initialState = self.getStateNamed(initialStateName)

    def getFinalState(self):
        return (self.__finalState)

    def setFinalState(self, finalStateName):
        self.__finalState = self.getStateNamed(finalStateName)

    def requestFinalState(self):
        self.request(self.__finalState.getName())

    def getCurrentState(self):
        return (self.__currentState)

    # lookup funcs

    def getStateNamed(self, stateName):
        """
        Return the state with given name if found, issue warning otherwise
        """
        state = self.__states.get(stateName)
        if state:
            return state
        else:
            ClassicFSM.notify.warning(
                "[%s]: getStateNamed: %s, no such state" %
                (self.__name, stateName))

    def hasStateNamed(self, stateName):
        """
        Return True if stateName is a valid state, False otherwise.
        """
        result = False
        state = self.__states.get(stateName)
        if state:
            result = True
        return result

    # basic ClassicFSM functionality

    def __exitCurrent(self, argList):
        """
        Exit the current state
        """
        assert self.__internalStateInFlux
        assert ClassicFSM.notify.debug(
            "[%s]: exiting %s" % (self.__name, self.__currentState.getName()))
        self.__currentState.exit(argList)
        # Only send the state change event if we are inspecting it
        # If this event turns out to be generally useful, we can
        # turn it on all the time, but for now nobody else is using it
        if self.inspecting:
            messenger.send(self.getName() + '_' +
                           self.__currentState.getName() + '_exited')
        self.__currentState = None

    def __enter(self, aState, argList=[]):
        """
        Enter a given state, if it exists
        """
        assert self.__internalStateInFlux
        stateName = aState.getName()
        if (stateName in self.__states):
            assert ClassicFSM.notify.debug("[%s]: entering %s" %
                                           (self.__name, stateName))
            self.__currentState = aState
            # Only send the state change event if we are inspecting it
            # If this event turns out to be generally useful, we can
            # turn it on all the time, but for now nobody else is using it
            if self.inspecting:
                messenger.send(self.getName() + '_' + stateName + '_entered')

            # Once we begin entering the new state, we're allow to
            # recursively request a transition to another state.
            # Indicate this by marking our internal state no longer in
            # flux.
            self.__internalStateInFlux = 0
            aState.enter(argList)
        else:
            # notify.error is going to raise an exception; reset the
            # flux flag first
            self.__internalStateInFlux = 0
            ClassicFSM.notify.error("[%s]: enter: no such state" %
                                    (self.__name))

    def __transition(self, aState, enterArgList=[], exitArgList=[]):
        """
        Exit currentState and enter given one
        """
        assert not self.__internalStateInFlux
        self.__internalStateInFlux = 1
        self.__exitCurrent(exitArgList)
        self.__enter(aState, enterArgList)
        assert not self.__internalStateInFlux

    def request(self, aStateName, enterArgList=[], exitArgList=[], force=0):
        """
        Attempt transition from currentState to given one.
        Return true is transition exists to given state,
        false otherwise.
        """
        # If you trigger this assertion failure, you must have
        # recursively requested a state transition from within the
        # exitState() function for the previous state.  This is not
        # supported because we're not fully transitioned into the new
        # state yet.
        assert not self.__internalStateInFlux

        if not self.__currentState:
            # Make this a warning for now
            ClassicFSM.notify.warning(
                "[%s]: request: never entered initial state" % (self.__name))
            self.__currentState = self.__initialState

        if isinstance(aStateName, types.StringType):
            aState = self.getStateNamed(aStateName)
        else:
            # Allow the caller to pass in a state in itself, not just
            # the name of a state.
            aState = aStateName
            aStateName = aState.getName()

        if aState == None:
            ClassicFSM.notify.error("[%s]: request: %s, no such state" %
                                    (self.__name, aStateName))

        # is the transition defined? if it isn't, should we allow it?
        transitionDefined = self.__currentState.isTransitionDefined(aStateName)
        transitionAllowed = transitionDefined

        if self.onUndefTransition == ClassicFSM.ALLOW:
            transitionAllowed = 1
            if not transitionDefined:
                # the transition is not defined, but we're going to do it
                # anyway. print a warning.
                ClassicFSM.notify.warning(
                    "[%s]: performing undefined transition from %s to %s" %
                    (self.__name, self.__currentState.getName(), aStateName))

        if transitionAllowed or force:
            self.__transition(aState, enterArgList, exitArgList)
            return 1
        # We can implicitly always transition to our final state.
        elif (aStateName == self.__finalState.getName()):
            if (self.__currentState == self.__finalState):
                # Do not do the transition if we are already in the
                # final state
                assert ClassicFSM.notify.debug(
                    "[%s]: already in final state: %s" %
                    (self.__name, aStateName))
                return 1
            else:
                # Force a transition to allow for cleanup
                assert ClassicFSM.notify.debug(
                    "[%s]: implicit transition to final state: %s" %
                    (self.__name, aStateName))
                self.__transition(aState, enterArgList, exitArgList)
                return 1
        # are we already in this state?
        elif (aStateName == self.__currentState.getName()):
            assert ClassicFSM.notify.debug(
                "[%s]: already in state %s and no self transition" %
                (self.__name, aStateName))
            return 0
        else:
            msg = ("[%s]: no transition exists from %s to %s" %
                   (self.__name, self.__currentState.getName(), aStateName))
            if self.onUndefTransition == ClassicFSM.ERROR:
                ClassicFSM.notify.error(msg)
            elif self.onUndefTransition == ClassicFSM.DISALLOW_VERBOSE:
                ClassicFSM.notify.warning(msg)
            return 0

    def forceTransition(self, aStateName, enterArgList=[], exitArgList=[]):
        """
        force a transition -- for debugging ONLY
        """
        self.request(aStateName, enterArgList, exitArgList, force=1)

    def conditional_request(self, aStateName, enterArgList=[], exitArgList=[]):
        """
        'if this transition is defined, do it'
        Attempt transition from currentState to given one, if it exists.
        Return true if transition exists to given state, false otherwise.
        It is NOT an error/warning to attempt a cond_request if the
        transition doesn't exist.  This lets people be sloppy about
        ClassicFSM transitions, letting the same fn be used for different
        states that may not have the same out transitions.
        """
        assert not self.__internalStateInFlux
        if not self.__currentState:
            # Make this a warning for now
            ClassicFSM.notify.warning(
                "[%s]: request: never entered initial state" % (self.__name))
            self.__currentState = self.__initialState

        if isinstance(aStateName, types.StringType):
            aState = self.getStateNamed(aStateName)
        else:
            # Allow the caller to pass in a state in itself, not just
            # the name of a state.
            aState = aStateName
            aStateName = aState.getName()

        if aState == None:
            ClassicFSM.notify.error("[%s]: request: %s, no such state" %
                                    (self.__name, aStateName))

        transitionDefined = (
            self.__currentState.isTransitionDefined(aStateName) or aStateName
            in [self.__currentState.getName(),
                self.__finalState.getName()])

        if transitionDefined:
            return self.request(aStateName, enterArgList, exitArgList)
        else:
            assert ClassicFSM.notify.debug(
                "[%s]: condition_request: %s, transition doesnt exist" %
                (self.__name, aStateName))
            return 0

    def view(self):
        from panda3d.direct.tkpanels import FSMInspector
        FSMInspector.FSMInspector(self)

    def isInternalStateInFlux(self):
        return self.__internalStateInFlux
Beispiel #19
0
class ObjectPool:
    """manipulate a pool of Python objects"""
    notify = directNotify.newCategory('ObjectPool')

    def __init__(self, objects):
        self._objs = list(objects)
        self._type2objs = {}
        self._count2types = {}
        self._len2obj = {}
        type2count = {}
        for obj in self._objs:
            typ = itype(obj)
            type2count.setdefault(typ, 0)
            type2count[typ] += 1
            self._type2objs.setdefault(typ, [])
            self._type2objs[typ].append(obj)
            try:
                self._len2obj[len(obj)] = obj
            except:
                pass
        self._count2types = invertDictLossless(type2count)

    def _getInternalObjs(self):
        return (self._objs, self._type2objs, self._count2types)

    def destroy(self):
        del self._objs
        del self._type2objs
        del self._count2types

    def getTypes(self):
        return self._type2objs.keys()

    def getObjsOfType(self, type):
        return self._type2objs.get(type, [])

    def printObjsOfType(self, type):
        for obj in self._type2objs.get(type, []):
            print repr(obj)

    def diff(self, other):
        """print difference between this pool and 'other' pool"""
        thisId2obj = {}
        otherId2obj = {}
        for obj in self._objs:
            thisId2obj[id(obj)] = obj
        for obj in other._objs:
            otherId2obj[id(obj)] = obj
        thisIds = set(thisId2obj.keys())
        otherIds = set(otherId2obj.keys())
        lostIds = thisIds.difference(otherIds)
        gainedIds = otherIds.difference(thisIds)
        del thisIds
        del otherIds
        lostObjs = []
        for i in lostIds:
            lostObjs.append(thisId2obj[i])
        gainedObjs = []
        for i in gainedIds:
            gainedObjs.append(otherId2obj[i])
        return Diff(self.__class__(lostObjs), self.__class__(gainedObjs))

    def typeFreqStr(self):
        s = 'Object Pool: Type Frequencies'
        s += '\n============================='
        counts = list(set(self._count2types.keys()))
        counts.sort()
        counts.reverse()
        for count in counts:
            types = makeList(self._count2types[count])
            for typ in types:
                s += '\n%s\t%s' % (count, typ)
        return s

    def printObjsByType(self, printReferrers=False):
        print 'Object Pool: Objects By Type'
        print '\n============================'
        counts = list(set(self._count2types.keys()))
        counts.sort()
        # print types with the smallest number of instances first, in case
        # there's a large group that waits a long time before printing
        #counts.reverse()
        for count in counts:
            types = makeList(self._count2types[count])
            for typ in types:
                print 'TYPE: %s, %s objects' % (repr(typ),
                                                len(self._type2objs[typ]))
                if printReferrers:
                    for line in getNumberedTypedSortedStringWithReferrersGen(
                            self._type2objs[typ]):
                        print line
                else:
                    print getNumberedTypedSortedString(self._type2objs[typ])

    def containerLenStr(self):
        s = 'Object Pool: Container Lengths'
        s += '\n=============================='
        lengths = list(self._len2obj.keys())
        lengths.sort()
        lengths.reverse()
        for count in counts:
            pass

    def printReferrers(self, numEach=3):
        """referrers of the first few of each type of object"""
        counts = list(set(self._count2types.keys()))
        counts.sort()
        counts.reverse()
        for count in counts:
            types = makeList(self._count2types[count])
            for typ in types:
                print '\n\nTYPE: %s' % repr(typ)
                for i in xrange(min(numEach, len(self._type2objs[typ]))):
                    obj = self._type2objs[typ][i]
                    print '\nOBJ: %s\n' % safeRepr(obj)
                    referrers = gc.get_referrers(obj)
                    print '%s REFERRERS:\n' % len(referrers)
                    if len(referrers):
                        print getNumberedTypedString(referrers,
                                                     maxLen=80,
                                                     numPrefix='REF')
                    else:
                        print '<No Referrers>'

    def __len__(self):
        return len(self._objs)
Beispiel #20
0
class DistributedObjectGlobalUD(DistributedObjectUD):
    notify = directNotify.newCategory('DistributedObjectGlobalUD')

    doNotDeallocateChannel = 1
    isGlobalDistObj = 1

    def __init__(self, air):
        DistributedObjectUD.__init__(self, air)
        self.ExecNamespace = {"self": self}

    def announceGenerate(self):
        self.air.registerForChannel(self.doId)
        DistributedObjectUD.announceGenerate(self)

    def delete(self):
        self.air.unregisterForChannel(self.doId)
        ## self.air.removeDOFromTables(self)
        DistributedObjectUD.delete(self)

    def execCommand(self, command, mwMgrId, avId, zoneId):
        text = self.__execMessage(command)
        print text
        dclass = uber.air.dclassesByName.get("PiratesMagicWordManagerAI")
        dg = dclass.aiFormatUpdate("setMagicWordResponse", mwMgrId,
                                   (1 << 32) + avId, uber.air.ourChannel,
                                   [text])
        uber.air.send(dg)

    def __execMessage(self, message):
        if not self.ExecNamespace:
            # Import some useful variables into the ExecNamespace initially.
            exec 'from panda3d.pandac import *' in globals(
            ), self.ExecNamespace
            #self.importExecNamespace()

        # Now try to evaluate the expression using ChatInputNormal.ExecNamespace as
        # the local namespace.
        try:
            return str(eval(message, globals(), self.ExecNamespace))

        except SyntaxError:
            # Maybe it's only a statement, like "x = 1", or
            # "import math".  These aren't expressions, so eval()
            # fails, but they can be exec'ed.
            try:
                exec message in globals(), self.ExecNamespace
                return 'ok'
            except:
                exception = sys.exc_info()[0]
                extraInfo = sys.exc_info()[1]
                if extraInfo:
                    return str(extraInfo)
                else:
                    return str(exception)
        except:
            exception = sys.exc_info()[0]
            extraInfo = sys.exc_info()[1]
            if extraInfo:
                return str(extraInfo)
            else:
                return str(exception)
Beispiel #21
0
class DistributedObjectUD(DistributedObjectBase):
    notify = directNotify.newCategory("DistributedObjectUD")
    QuietZone = 1

    def __init__(self, air):
        try:
            self.DistributedObjectUD_initialized
        except:
            self.DistributedObjectUD_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._DOUD_requestedDelete = False

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

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

    # 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, disabled, neverDisable,
                or cachable
            """
            spaces = ' ' * (indent + 2)
            try:
                print "%s%s:" % (' ' * indent, self.__class__.__name__)
                print(
                    "%sfrom "
                    "DistributedObject doId:%s, parent:%s, zone:%s" %
                    (spaces, self.doId, self.parentId, self.zoneId)),
                flags = []
                if self.__generated:
                    flags.append("generated")
                if self.air == None:
                    flags.append("deleted")
                if len(flags):
                    print "(%s)" % (" ".join(flags), ),
                print
            except Exception, e:
                print "%serror printing status" % (spaces, ), e
Beispiel #22
0
class FunctionInterval(Interval.Interval):
    # Name counter
    functionIntervalNum = 1

    # Keep a list of function intervals currently in memory for
    # Control-C-Control-V redefining. These are just weakrefs so they
    # should not cause any leaks.
    if __debug__:
        import weakref
        FunctionIntervals = weakref.WeakKeyDictionary()

        @classmethod
        def replaceMethod(self, oldFunction, newFunction):
            import new
            import types
            count = 0
            for ival in self.FunctionIntervals:
                # print 'testing: ', ival.function, oldFunction
                # Note: you can only replace methods currently
                if type(ival.function) == types.MethodType:
                    if (ival.function.im_func == oldFunction):
                        # print 'found: ', ival.function, oldFunction
                        ival.function = new.instancemethod(
                            newFunction, ival.function.im_self,
                            ival.function.im_class)
                        count += 1
            return count

    # create FunctionInterval DirectNotify category
    notify = directNotify.newCategory('FunctionInterval')

    # Class methods
    def __init__(self, function, **kw):
        """__init__(function, name = None, openEnded = 1, extraArgs = [])
        """
        name = kw.pop('name', None)
        openEnded = kw.pop('openEnded', 1)
        extraArgs = kw.pop('extraArgs', [])

        # Record instance variables
        self.function = function

        # Create a unique name for the interval if necessary
        if (name == None):
            name = self.makeUniqueName(function)
        assert isinstance(name, types.StringType)
        # Record any arguments
        self.extraArgs = extraArgs
        self.kw = kw
        # Initialize superclass
        # Set openEnded true if privInitialize after end time cause interval
        # function to be called.  If false, privInitialize calls have no effect
        # Event, Accept, Ignore intervals default to openEnded = 0
        # Parent, Pos, Hpr, etc intervals default to openEnded = 1
        Interval.Interval.__init__(self,
                                   name,
                                   duration=0.0,
                                   openEnded=openEnded)

        # For rebinding, let's remember this function interval on the class
        if __debug__:
            self.FunctionIntervals[self] = 1

    @staticmethod
    def makeUniqueName(func, suffix=''):
        name = 'Func-%s-%d' % (func.__name__,
                               FunctionInterval.functionIntervalNum)
        FunctionInterval.functionIntervalNum += 1
        if suffix:
            name = '%s-%s' % (name, str(suffix))
        return name

    def privInstant(self):
        # Evaluate the function
        self.function(*self.extraArgs, **self.kw)
        # Print debug information
        self.notify.debug('updateFunc() - %s: executing Function' % self.name)
Beispiel #23
0
from panda3d.pandac import ConfigConfigureGetConfigConfigShowbase as config
from panda3d.direct.directnotify.DirectNotifyGlobal import directNotify
from panda3d.direct.showbase.PythonUtil import fastRepr
from exceptions import Exception
import sys
import types
import traceback

notify = directNotify.newCategory("ExceptionVarDump")

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)
    reentry -= 1
Beispiel #24
0
class InterestWatcher(DirectObject):
    """Object that observes all interests adds/removes over a period of time,
    and sends out an event when all of those interests have closed"""
    notify = directNotify.newCategory('InterestWatcher')
    
    def __init__(self, interestMgr, name, doneEvent=None,
                 recurse=True, start=True, mustCollect=False, doCollectionMgr=None):
        DirectObject.__init__(self)
        self._interestMgr = interestMgr
        if doCollectionMgr is None:
            doCollectionMgr = interestMgr
        self._doCollectionMgr = doCollectionMgr
        self._eGroup = EventGroup(name, doneEvent=doneEvent)
        self._doneEvent = self._eGroup.getDoneEvent()
        self._gotEvent = False
        self._recurse = recurse
        if self._recurse:
            # this will hold a dict of parentId to set(zoneIds) that are closing
            self.closingParent2zones = {}
        if start:
            self.startCollect(mustCollect)

    def startCollect(self, mustCollect=False):
        self._mustCollect = mustCollect

        self.accept(self._interestMgr._getAddInterestEvent(), self._handleInterestOpenEvent)
        self.accept(self._interestMgr._getRemoveInterestEvent(), self._handleInterestCloseEvent)
        
    def stopCollect(self):
        self.ignore(self._interestMgr._getAddInterestEvent())
        self.ignore(self._interestMgr._getRemoveInterestEvent())

        mustCollect = self._mustCollect
        del self._mustCollect
        if not self._gotEvent:
            if mustCollect:
                logFunc = self.notify.error
            else:
                logFunc = self.notify.warning
            logFunc('%s: empty interest-complete set' % self.getName())
            self.destroy()
        else:
            self.accept(self.getDoneEvent(), self.destroy)

    def destroy(self):
        if hasattr(self, '_eGroup'):
            self._eGroup.destroy()
            del self._eGroup
            del self._gotEvent
            del self._interestMgr
            self.ignoreAll()

    def getName(self):
        return self._eGroup.getName()
    def getDoneEvent(self):
        return self._doneEvent

    def _handleInterestOpenEvent(self, event):
        self._gotEvent = True
        self._eGroup.addEvent(event)
    def _handleInterestCloseEvent(self, event, parentId, zoneIdList):
        self._gotEvent = True
        self._eGroup.addEvent(event)
        """
Beispiel #25
0
class DoInterestManager(DirectObject.DirectObject):
    """
    Top level Interest Manager
    """
    notify = directNotify.newCategory("DoInterestManager")
    try:
        tempbase = base
    except:
        tempbase = simbase
    InterestDebug = tempbase.config.GetBool('interest-debug', False)
    del tempbase

    # 'handle' is a number that represents a single interest set that the
    # client has requested; the interest set may be modified
    _HandleSerialNum = 0
    # high bit is reserved for server interests
    _HandleMask = 0x7FFF

    # 'context' refers to a single request to change an interest set
    _ContextIdSerialNum = 100
    _ContextIdMask = 0x3FFFFFFF  # avoid making Python create a long

    _interests = {}
    if __debug__:
        _debug_interestHistory = []
        _debug_maxDescriptionLen = 40

    _SerialGen = SerialNumGen()
    _SerialNum = serialNum()

    def __init__(self):
        assert DoInterestManager.notify.debugCall()
        DirectObject.DirectObject.__init__(self)
        self._addInterestEvent = uniqueName('DoInterestManager-Add')
        self._removeInterestEvent = uniqueName('DoInterestManager-Remove')
        self._noNewInterests = False
        self._completeDelayedCallback = None
        # keep track of request contexts that have not completed
        self._completeEventCount = ScratchPad(num=0)
        self._allInterestsCompleteCallbacks = []

    def __verbose(self):
        return self.InterestDebug or self.getVerbose()

    def _getAnonymousEvent(self, desc):
        return 'anonymous-%s-%s' % (desc, DoInterestManager._SerialGen.next())

    def setNoNewInterests(self, flag):
        self._noNewInterests = flag

    def noNewInterests(self):
        return self._noNewInterests

    def setAllInterestsCompleteCallback(self, callback):
        if ((self._completeEventCount.num == 0)
                and (self._completeDelayedCallback is None)):
            callback()
        else:
            self._allInterestsCompleteCallbacks.append(callback)

    def getAllInterestsCompleteEvent(self):
        return 'allInterestsComplete-%s' % DoInterestManager._SerialNum

    def resetInterestStateForConnectionLoss(self):
        DoInterestManager._interests.clear()
        self._completeEventCount = ScratchPad(num=0)
        if __debug__:
            self._addDebugInterestHistory("RESET", "", 0, 0, 0, [])

    def isValidInterestHandle(self, handle):
        # pass in a handle (or anything else) and this will return true if it is
        # still a valid interest handle
        if not isinstance(handle, InterestHandle):
            return False
        return DoInterestManager._interests.has_key(handle.asInt())

    def updateInterestDescription(self, handle, desc):
        iState = DoInterestManager._interests.get(handle.asInt())
        if iState:
            iState.setDesc(desc)

    def addInterest(self, parentId, zoneIdList, description, event=None):
        """
        Look into a (set of) zone(s).
        """
        assert DoInterestManager.notify.debugCall()
        handle = self._getNextHandle()
        # print 'base.cr.addInterest(',description,',',handle,'):',globalClock.getFrameCount()
        if self._noNewInterests:
            DoInterestManager.notify.warning(
                "addInterest: addingInterests on delete: %s" % (handle))
            return

        # make sure we've got parenting rules set in the DC
        if parentId not in (self.getGameDoId(), ):
            parent = self.getDo(parentId)
            if not parent:
                DoInterestManager.notify.error(
                    'addInterest: attempting to add interest under unknown object %s'
                    % parentId)
            else:
                if not parent.hasParentingRules():
                    DoInterestManager.notify.error(
                        'addInterest: no setParentingRules defined in the DC for object %s (%s)'
                        '' % (parentId, parent.__class__.__name__))

        if event:
            contextId = self._getNextContextId()
        else:
            contextId = 0
            # event = self._getAnonymousEvent('addInterest')

        DoInterestManager._interests[handle] = InterestState(
            description, InterestState.StateActive, contextId, event, parentId,
            zoneIdList, self._completeEventCount)
        if self.__verbose():
            print 'CR::INTEREST.addInterest(handle=%s, parentId=%s, zoneIdList=%s, description=%s, event=%s)' % (
                handle, parentId, zoneIdList, description, event)
        self._sendAddInterest(handle, contextId, parentId, zoneIdList,
                              description)
        if event:
            messenger.send(self._getAddInterestEvent(), [event])
        assert self.printInterestsIfDebug()
        return InterestHandle(handle)

    def addAutoInterest(self, parentId, zoneIdList, description):
        """
        Look into a (set of) zone(s).
        """
        assert DoInterestManager.notify.debugCall()
        handle = self._getNextHandle()
        if self._noNewInterests:
            DoInterestManager.notify.warning(
                "addInterest: addingInterests on delete: %s" % (handle))
            return

        # make sure we've got parenting rules set in the DC
        if parentId not in (self.getGameDoId(), ):
            parent = self.getDo(parentId)
            if not parent:
                DoInterestManager.notify.error(
                    'addInterest: attempting to add interest under unknown object %s'
                    % parentId)
            else:
                if not parent.hasParentingRules():
                    DoInterestManager.notify.error(
                        'addInterest: no setParentingRules defined in the DC for object %s (%s)'
                        '' % (parentId, parent.__class__.__name__))

        DoInterestManager._interests[handle] = InterestState(
            description, InterestState.StateActive, 0, None, parentId,
            zoneIdList, self._completeEventCount, True)
        if self.__verbose():
            print 'CR::INTEREST.addInterest(handle=%s, parentId=%s, zoneIdList=%s, description=%s)' % (
                handle, parentId, zoneIdList, description)
        assert self.printInterestsIfDebug()
        return InterestHandle(handle)

    def removeInterest(self, handle, event=None):
        """
        Stop looking in a (set of) zone(s)
        """
        # print 'base.cr.removeInterest(',handle,'):',globalClock.getFrameCount()

        assert DoInterestManager.notify.debugCall()
        assert isinstance(handle, InterestHandle)
        existed = False
        if not event:
            event = self._getAnonymousEvent('removeInterest')
        handle = handle.asInt()
        if DoInterestManager._interests.has_key(handle):
            existed = True
            intState = DoInterestManager._interests[handle]
            if event:
                messenger.send(self._getRemoveInterestEvent(),
                               [event, intState.parentId, intState.zoneIdList])
            if intState.isPendingDelete():
                self.notify.warning(
                    'removeInterest: interest %s already pending removal' %
                    handle)
                # this interest is already pending delete, so let's just tack this
                # callback onto the list
                if event is not None:
                    intState.addEvent(event)
            else:
                if len(intState.events) > 0:
                    # we're not pending a removal, but we have outstanding events?
                    # probably we are waiting for an add/alter complete.
                    # should we send those events now?
                    assert self.notify.warning(
                        'removeInterest: abandoning events: %s' %
                        intState.events)
                    intState.clearEvents()
                intState.state = InterestState.StatePendingDel
                contextId = self._getNextContextId()
                intState.context = contextId
                if event:
                    intState.addEvent(event)
                self._sendRemoveInterest(handle, contextId)
                if not event:
                    self._considerRemoveInterest(handle)
                if self.__verbose():
                    print 'CR::INTEREST.removeInterest(handle=%s, event=%s)' % (
                        handle, event)
        else:
            DoInterestManager.notify.warning(
                "removeInterest: handle not found: %s" % (handle))
        assert self.printInterestsIfDebug()
        return existed

    def removeAutoInterest(self, handle):
        """
        Stop looking in a (set of) zone(s)
        """
        assert DoInterestManager.notify.debugCall()
        assert isinstance(handle, InterestHandle)
        existed = False
        handle = handle.asInt()
        if DoInterestManager._interests.has_key(handle):
            existed = True
            intState = DoInterestManager._interests[handle]
            if intState.isPendingDelete():
                self.notify.warning(
                    'removeInterest: interest %s already pending removal' %
                    handle)
                # this interest is already pending delete, so let's just tack this
                # callback onto the list
            else:
                if len(intState.events) > 0:
                    # we're not pending a removal, but we have outstanding events?
                    # probably we are waiting for an add/alter complete.
                    # should we send those events now?
                    self.notify.warning(
                        'removeInterest: abandoning events: %s' %
                        intState.events)
                    intState.clearEvents()
                intState.state = InterestState.StatePendingDel
                self._considerRemoveInterest(handle)
                if self.__verbose():
                    print 'CR::INTEREST.removeAutoInterest(handle=%s)' % (
                        handle)
        else:
            DoInterestManager.notify.warning(
                "removeInterest: handle not found: %s" % (handle))
        assert self.printInterestsIfDebug()
        return existed

    @report(types=['args'], dConfigParam='want-guildmgr-report')
    def removeAIInterest(self, handle):
        """
        handle is NOT an InterestHandle.  It's just a bare integer representing an
        AI opened interest. We're making the client close down this interest since
        the AI has trouble removing interests(that its opened) when the avatar goes
        offline.  See GuildManager(UD) for how it's being used.
        """
        self._sendRemoveAIInterest(handle)

    def alterInterest(self,
                      handle,
                      parentId,
                      zoneIdList,
                      description=None,
                      event=None):
        """
        Removes old interests and adds new interests.

        Note that when an interest is changed, only the most recent
        change's event will be triggered. Previous events are abandoned.
        If this is a problem, consider opening multiple interests.
        """
        assert DoInterestManager.notify.debugCall()
        assert isinstance(handle, InterestHandle)
        #assert not self._noNewInterests
        handle = handle.asInt()
        if self._noNewInterests:
            DoInterestManager.notify.warning(
                "alterInterest: addingInterests on delete: %s" % (handle))
            return

        exists = False
        if event is None:
            event = self._getAnonymousEvent('alterInterest')
        if DoInterestManager._interests.has_key(handle):
            if description is not None:
                DoInterestManager._interests[handle].desc = description
            else:
                description = DoInterestManager._interests[handle].desc

            # are we overriding an existing change?
            if DoInterestManager._interests[handle].context != NO_CONTEXT:
                DoInterestManager._interests[handle].clearEvents()

            contextId = self._getNextContextId()
            DoInterestManager._interests[handle].context = contextId
            DoInterestManager._interests[handle].parentId = parentId
            DoInterestManager._interests[handle].zoneIdList = zoneIdList
            DoInterestManager._interests[handle].addEvent(event)

            if self.__verbose():
                print 'CR::INTEREST.alterInterest(handle=%s, parentId=%s, zoneIdList=%s, description=%s, event=%s)' % (
                    handle, parentId, zoneIdList, description, event)
            self._sendAddInterest(handle,
                                  contextId,
                                  parentId,
                                  zoneIdList,
                                  description,
                                  action='modify')
            exists = True
            assert self.printInterestsIfDebug()
        else:
            DoInterestManager.notify.warning(
                "alterInterest: handle not found: %s" % (handle))
        return exists

    def openAutoInterests(self, obj):
        if hasattr(obj, '_autoInterestHandle'):
            # must be multiple inheritance
            self.notify.debug('openAutoInterests(%s): interests already open' %
                              obj.__class__.__name__)
            return
        autoInterests = obj.getAutoInterests()
        obj._autoInterestHandle = None
        if not len(autoInterests):
            return
        obj._autoInterestHandle = self.addAutoInterest(
            obj.doId, autoInterests,
            '%s-autoInterest' % obj.__class__.__name__)

    def closeAutoInterests(self, obj):
        if not hasattr(obj, '_autoInterestHandle'):
            # must be multiple inheritance
            self.notify.debug(
                'closeAutoInterests(%s): interests already closed' % obj)
            return
        if obj._autoInterestHandle is not None:
            self.removeAutoInterest(obj._autoInterestHandle)
        del obj._autoInterestHandle

    # events for InterestWatcher
    def _getAddInterestEvent(self):
        return self._addInterestEvent

    def _getRemoveInterestEvent(self):
        return self._removeInterestEvent

    def _getInterestState(self, handle):
        return DoInterestManager._interests[handle]

    def _getNextHandle(self):
        handle = DoInterestManager._HandleSerialNum
        while True:
            handle = (handle + 1) & DoInterestManager._HandleMask
            # skip handles that are already in use
            if handle not in DoInterestManager._interests:
                break
            DoInterestManager.notify.warning('interest %s already in use' %
                                             handle)
        DoInterestManager._HandleSerialNum = handle
        return DoInterestManager._HandleSerialNum

    def _getNextContextId(self):
        contextId = DoInterestManager._ContextIdSerialNum
        while True:
            contextId = (contextId + 1) & DoInterestManager._ContextIdMask
            # skip over the 'no context' id
            if contextId != NO_CONTEXT:
                break
        DoInterestManager._ContextIdSerialNum = contextId
        return DoInterestManager._ContextIdSerialNum

    def _considerRemoveInterest(self, handle):
        """
        Consider whether we should cull the interest set.
        """
        assert DoInterestManager.notify.debugCall()

        if DoInterestManager._interests.has_key(handle):
            if DoInterestManager._interests[handle].isPendingDelete():
                # make sure there is no pending event for this interest
                if DoInterestManager._interests[handle].context == NO_CONTEXT:
                    assert len(
                        DoInterestManager._interests[handle].events) == 0
                    del DoInterestManager._interests[handle]

    if __debug__:

        def printInterestsIfDebug(self):
            if DoInterestManager.notify.getDebug():
                self.printInterests()
            return 1  # for assert

        def _addDebugInterestHistory(self, action, description, handle,
                                     contextId, parentId, zoneIdList):
            if description is None:
                description = ''
            DoInterestManager._debug_interestHistory.append(
                (action, description, handle, contextId, parentId, zoneIdList))
            DoInterestManager._debug_maxDescriptionLen = max(
                DoInterestManager._debug_maxDescriptionLen, len(description))

        def printInterestHistory(self):
            print "***************** Interest History *************"
            format = '%9s %' + str(DoInterestManager._debug_maxDescriptionLen
                                   ) + 's %6s %6s %9s %s'
            print format % ("Action", "Description", "Handle", "Context",
                            "ParentId", "ZoneIdList")
            for i in DoInterestManager._debug_interestHistory:
                print format % tuple(i)
            print "Note: interests with a Context of 0 do not get" \
                " done/finished notices."

        def printInterestSets(self):
            print "******************* Interest Sets **************"
            format = '%6s %' + str(DoInterestManager._debug_maxDescriptionLen
                                   ) + 's %11s %11s %8s %8s %8s'
            print format % ("Handle", "Description", "ParentId", "ZoneIdList",
                            "State", "Context", "Event")
            for id, state in DoInterestManager._interests.items():
                if len(state.events) == 0:
                    event = ''
                elif len(state.events) == 1:
                    event = state.events[0]
                else:
                    event = state.events
                print format % (id, state.desc, state.parentId,
                                state.zoneIdList, state.state, state.context,
                                event)
            print "************************************************"

        def printInterests(self):
            self.printInterestHistory()
            self.printInterestSets()

    def _sendAddInterest(self,
                         handle,
                         contextId,
                         parentId,
                         zoneIdList,
                         description,
                         action=None):
        """
        Part of the new otp-server code.

        handle is a client-side created number that refers to
                a set of interests.  The same handle number doesn't
                necessarily have any relationship to the same handle
                on another client.
        """
        assert DoInterestManager.notify.debugCall()
        if __debug__:
            if isinstance(zoneIdList, types.ListType):
                zoneIdList.sort()
            if action is None:
                action = 'add'
            self._addDebugInterestHistory(action, description, handle,
                                          contextId, parentId, zoneIdList)
        if parentId == 0:
            DoInterestManager.notify.error(
                'trying to set interest to invalid parent: %s' % parentId)
        datagram = PyDatagram()
        # Add message type
        datagram.addUint16(CLIENT_ADD_INTEREST)
        datagram.addUint16(handle)
        datagram.addUint32(contextId)
        datagram.addUint32(parentId)
        if isinstance(zoneIdList, types.ListType):
            vzl = list(zoneIdList)
            vzl.sort()
            uniqueElements(vzl)
            for zone in vzl:
                datagram.addUint32(zone)
        else:
            datagram.addUint32(zoneIdList)
        self.send(datagram)

    def _sendRemoveInterest(self, handle, contextId):
        """
        handle is a client-side created number that refers to
                a set of interests.  The same handle number doesn't
                necessarily have any relationship to the same handle
                on another client.
        """
        assert DoInterestManager.notify.debugCall()
        assert handle in DoInterestManager._interests
        datagram = PyDatagram()
        # Add message type
        datagram.addUint16(CLIENT_REMOVE_INTEREST)
        datagram.addUint16(handle)
        if contextId != 0:
            datagram.addUint32(contextId)
        self.send(datagram)
        if __debug__:
            state = DoInterestManager._interests[handle]
            self._addDebugInterestHistory("remove", state.desc, handle,
                                          contextId, state.parentId,
                                          state.zoneIdList)

    def _sendRemoveAIInterest(self, handle):
        """
        handle is a bare int, NOT an InterestHandle.  Use this to
        close an AI opened interest.
        """
        datagram = PyDatagram()
        # Add message type
        datagram.addUint16(CLIENT_REMOVE_INTEREST)
        datagram.addUint16((1 << 15) + handle)
        self.send(datagram)

    def cleanupWaitAllInterestsComplete(self):
        if self._completeDelayedCallback is not None:
            self._completeDelayedCallback.destroy()
            self._completeDelayedCallback = None

    def queueAllInterestsCompleteEvent(self, frames=5):
        # wait for N frames, if no new interests, send out all-done event
        # calling this is OK even if there are no pending interest completes
        def checkMoreInterests():
            # if there are new interests, cancel this delayed callback, another
            # will automatically be scheduled when all interests complete
            # print 'checkMoreInterests(',self._completeEventCount.num,'):',globalClock.getFrameCount()
            return self._completeEventCount.num > 0

        def sendEvent():
            messenger.send(self.getAllInterestsCompleteEvent())
            for callback in self._allInterestsCompleteCallbacks:
                callback()
            self._allInterestsCompleteCallbacks = []

        self.cleanupWaitAllInterestsComplete()
        self._completeDelayedCallback = FrameDelayedCall(
            'waitForAllInterestCompletes',
            callback=sendEvent,
            frames=frames,
            cancelFunc=checkMoreInterests)
        checkMoreInterests = None
        sendEvent = None

    def handleInterestDoneMessage(self, di):
        """
        This handles the interest done messages and may dispatch an event
        """
        assert DoInterestManager.notify.debugCall()
        handle = di.getUint16()
        contextId = di.getUint32()
        if self.__verbose():
            print 'CR::INTEREST.interestDone(handle=%s)' % handle
        DoInterestManager.notify.debug(
            "handleInterestDoneMessage--> Received handle %s, context %s" %
            (handle, contextId))
        if DoInterestManager._interests.has_key(handle):
            eventsToSend = []
            # if the context matches, send out the event
            if contextId == DoInterestManager._interests[handle].context:
                DoInterestManager._interests[handle].context = NO_CONTEXT
                # the event handlers may call back into the interest manager. Send out
                # the events after we're once again in a stable state.
                #DoInterestManager._interests[handle].sendEvents()
                eventsToSend = list(
                    DoInterestManager._interests[handle].getEvents())
                DoInterestManager._interests[handle].clearEvents()
            else:
                DoInterestManager.notify.debug(
                    "handleInterestDoneMessage--> handle: %s: Expecting context %s, got %s"
                    % (handle, DoInterestManager._interests[handle].context,
                       contextId))
            if __debug__:
                state = DoInterestManager._interests[handle]
                self._addDebugInterestHistory("finished", state.desc, handle,
                                              contextId, state.parentId,
                                              state.zoneIdList)
            self._considerRemoveInterest(handle)
            for event in eventsToSend:
                messenger.send(event)
        else:
            DoInterestManager.notify.warning(
                "handleInterestDoneMessage: handle not found: %s" % (handle))
        # if there are no more outstanding interest-completes, send out global all-done event
        if self._completeEventCount.num == 0:
            self.queueAllInterestsCompleteEvent()
        assert self.printInterestsIfDebug()
Beispiel #26
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):
        """
        Moved from DoCollectionManager
        ==============================
        parentId is any distributed object id.
        zoneId is 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 is 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 #27
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(self.getDuration())
        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 = globalClock.getFrameTime()
        self.__playRate = playRate
        self.__doLoop = doLoop
        self.__loopCount = 0

    def setupResume(self):
        now = globalClock.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 = globalClock.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.  Not supported at the moment for
            # Python-style intervals.  To add support, copy the code
            # from C++-style intervals in cInterval.cxx, and modify it
            # for Python (as the above).
            pass

        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)


    # 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.
        """
        from panda3d.direct.showbase import TkGlobal
        import math
        # I moved this here because Toontown does not ship Tk
        from Tkinter import Toplevel, Frame, Button, LEFT, X
        import Pmw
        from panda3d.direct.tkwidgets import EntryScale
        if tl == None:
            tl = Toplevel()
            tl.title('Interval Controls')
        outerFrame = 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 = X)
        bf = 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 = Button(bf, text = '<<', command = toStart)
        # Stop/play buttons
        def doPlay(s=self, es=es):
            s.resume(es.get())

        stop = Button(bf, text = 'Stop',
                      command = lambda s=self: s.pause())
        play = Button(
            bf, text = 'Play',
            command = doPlay)
        jumpToEnd = Button(bf, text = '>>', command = toEnd)
        jumpToStart.pack(side = LEFT, expand = 1, fill = X)
        play.pack(side = LEFT, expand = 1, fill = X)
        stop.pack(side = LEFT, expand = 1, fill = X)
        jumpToEnd.pack(side = LEFT, expand = 1, fill = X)
        bf.pack(expand = 1, fill = X)
        outerFrame.pack(expand = 1, fill = 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 #28
0
from panda3d.direct.extensions_native.Helpers import *

Dtool_PreloadDLL("direct")
from direct import *

#####################################################################

from panda3d.direct.directnotify.DirectNotifyGlobal import directNotify
notify = directNotify.newCategory("Interval")
Dtool_ObjectToDict(CInterval,"notify", notify)
del notify
#####################################################################
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()

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:  # None or 0 implies full length
            self.start(t0, t0 + duration, scale)
        else:
            self.start(t0, -1, scale)
Beispiel #29
0
class ContainerReport(Job):
    notify = directNotify.newCategory("ContainerReport")
    # set of containers that should not be included in the report
    PrivateIds = set()

    def __init__(self, name, log=False, limit=None, threaded=False):
        Job.__init__(self, name)
        self._log = log
        self._limit = limit
        # set up our data structures
        self._visitedIds = set()
        self._id2pathStr = {}
        self._id2container = {}
        self._type2id2len = {}
        self._instanceDictIds = set()
        # for breadth-first searching
        self._queue = Queue()
        jobMgr.add(self)
        if threaded == False:
            jobMgr.finish(self)

    def destroy(self):
        del self._queue
        del self._instanceDictIds
        del self._type2id2len
        del self._id2container
        del self._id2pathStr
        del self._visitedIds
        del self._limit
        del self._log

    def finished(self):
        if self._log:
            self.destroy()

    def run(self):
        ContainerReport.PrivateIds.update(set([
            id(ContainerReport.PrivateIds),
            id(self._visitedIds),
            id(self._id2pathStr),
            id(self._id2container),
            id(self._type2id2len),
            id(self._queue),
            id(self._instanceDictIds),
            ]))
        # push on a few things that we want to give priority
        # for the sake of the variable-name printouts
        try:
            base
        except:
            pass
        else:
            self._enqueueContainer( base.__dict__,
                                   'base')
        try:
            simbase
        except:
            pass
        else:
            self._enqueueContainer( simbase.__dict__,
                                   'simbase')
        self._queue.push(__builtins__)
        self._id2pathStr[id(__builtins__)] = ''

        while len(self._queue) > 0:
            # yield up here instead of at the end, since we skip back to the
            # top of the while loop from various points
            yield None
            parentObj = self._queue.pop()
            #print '%s: %s, %s' % (id(parentObj), type(parentObj), self._id2pathStr[id(parentObj)])
            isInstanceDict = False
            if id(parentObj) in self._instanceDictIds:
                isInstanceDict = True

            try:
                if parentObj.__class__.__name__ == 'method-wrapper':
                    continue
            except:
                pass

            if type(parentObj) in (types.StringType, types.UnicodeType):
                continue
            
            if type(parentObj) in (types.ModuleType, types.InstanceType):
                child = parentObj.__dict__
                if self._examine(child):
                    assert (self._queue.back() is child)
                    self._instanceDictIds.add(id(child))
                    self._id2pathStr[id(child)] = str(self._id2pathStr[id(parentObj)])
                continue

            if type(parentObj) is types.DictType:
                key = None
                attr = None
                keys = parentObj.keys()
                try:
                    keys.sort()
                except TypeError, e:
                    self.notify.warning('non-sortable dict keys: %s: %s' % (self._id2pathStr[id(parentObj)], repr(e)))
                for key in keys:
                    try:
                        attr = parentObj[key]
                    except KeyError, e:
                        self.notify.warning('could not index into %s with key %s' % (self._id2pathStr[id(parentObj)],
                                                                                     key))
                    if id(attr) not in self._visitedIds:
                        self._visitedIds.add(id(attr))
                        if self._examine(attr):
                            assert (self._queue.back() is attr)
                            if parentObj is __builtins__:
                                self._id2pathStr[id(attr)] = key
                            else:
                                if isInstanceDict:
                                    self._id2pathStr[id(attr)] = self._id2pathStr[id(parentObj)] + '.%s' % key
                                else:
                                    self._id2pathStr[id(attr)] = self._id2pathStr[id(parentObj)] + '[%s]' % safeRepr(key)
                del key
                del attr
                continue

            if type(parentObj) is not types.FileType:
                try:
                    itr = iter(parentObj)
                except:
                    pass
                else:
                    try:
                        index = 0
                        while 1:
                            try:
                                attr = itr.next()
                            except:
                                # some custom classes don't do well when iterated
                                attr = None
                                break
                            if id(attr) not in self._visitedIds:
                                self._visitedIds.add(id(attr))
                                if self._examine(attr):
                                    assert (self._queue.back() is attr)
                                    self._id2pathStr[id(attr)] = self._id2pathStr[id(parentObj)] + '[%s]' % index
                            index += 1
                        del attr
                    except StopIteration, e:
                        pass
                    del itr
                    continue
Beispiel #30
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 __builtin__.__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 callable(self._func)
            __builtin__.globalProfileSessionFunc = self._func
            __builtin__.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].itervalues():
                if ct > maxTime:
                    maxTime = ct
            self._duration = maxTime
            # clean up the RAM file support
            _removeProfileCustomFuncs(filename)

            # clean up the globals
            result = globalProfileSessionResult[0]
            del __builtin__.__dict__['globalProfileSessionFunc']
            del __builtin__.__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
Beispiel #31
0
import direct
from panda3d.pandac import HttpRequest
from panda3d.direct.directnotify.DirectNotifyGlobal import directNotify
from panda3d.direct.task.TaskManagerGlobal import taskMgr
from panda3d.direct.task import Task
from LandingPage import LandingPage

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:
                result[arg[0]] = arg[1]
Beispiel #32
0
class TestInterval(Interval):
    # Name counter
    particleNum = 1
    # create ParticleInterval DirectNotify category
    notify = directNotify.newCategory('TestInterval')
    # Class methods
    def __init__(self,
                 particleEffect,
                 duration=0.0,
                 parent = None,
                 renderParent = None,
                 name=None):
        """
        particleEffect is ??
        parent is ??
        worldRelative is a boolean
        loop is a boolean
        duration is a float for the time
        name is ??
        """
        # Generate unique name
        id = 'Particle-%d' % TestInterval.particleNum
        TestInterval.particleNum += 1
        if name == None:
            name = id
        # Record instance variables
        self.particleEffect = particleEffect
        self.parent = parent
        self.renderParent = renderParent
                
        Interval.__init__(self, name, duration)

    def __del__(self):
        pass

    def __step(self,dt):
        self.particleEffect.accelerate(dt,1,0.05)

    def start(self,*args,**kwargs):
        self.particleEffect.clearToInitial()
        self.currT = 0
        Interval.start(self,*args,**kwargs)
        
    def privInitialize(self, t):
        if self.parent != None:
            self.particleEffect.reparentTo(self.parent)
        if self.renderParent != None:
            self.setRenderParent(self.renderParent.node())

        self.state = CInterval.SStarted
        #self.particleEffect.enable()
        """
        if (self.particleEffect.renderParent != None):
            for p in self.particleEffect.particlesDict.values():
                p.setRenderParent(self.particleEffect.renderParent.node())
        """
        for f in self.particleEffect.forceGroupDict.values():
            f.enable()
        """
        for p in self.particleEffect.particlesDict.values():
            p.enable()
        self.particleEffect.fEnabled = 1
        """
        self.__step(t-self.currT)
        self.currT = t

    def privStep(self, t):
        if self.state == CInterval.SPaused:
            # Restarting from a pause.
            self.privInitialize(t)
        else:
            self.state = CInterval.SStarted
            self.__step(t-self.currT)
            self.currT = t

    def privFinalize(self):
        self.__step(self.getDuration()-self.currT)
        self.currT = self.getDuration()

        self.state = CInterval.SFinal
        
    def privInstant(self):
        """
        Full jump from Initial state to Final State
        """
        self.__step(self.getDuration()-self.currT)
        self.currT = self.getDuration()

        self.state = CInterval.SFinal

    def privInterrupt(self):
        if not self.isStopped():
            self.state = CInterval.SPaused
Beispiel #33
0
class ParticleInterval(Interval):
    """
    Use this interval when you want to have greater control over a
    ParticleEffect.  The interval does not register the effect with
    the global particle and physics managers, but it does call upon
    them to perform its stepping.  You should NOT call
    particleEffect.start() with an effect that is being controlled
    by a ParticleInterval.
    """
    # Name counter
    particleNum = 1
    # create ParticleInterval DirectNotify category
    notify = directNotify.newCategory('ParticleInterval')

    # Class methods
    def __init__(self,
                 particleEffect,
                 parent,
                 worldRelative=1,
                 renderParent=None,
                 duration=0.0,
                 softStopT=0.0,
                 cleanup=False,
                 name=None):
        """
        particleEffect is a ParticleEffect
        parent is a NodePath: this is where the effect will be
                              parented in the scenegraph
        worldRelative is a boolean: this will override 'renderParent'
                                    with render
        renderParent is a NodePath: this is where the particles will
                                    be rendered in the scenegraph
        duration is a float: for the time
        softStopT is a float: no effect if 0.0,
                              a positive value will count from the
                              start of the interval,
                              a negative value will count from the
                              end of the interval
        cleanup is a boolean: if True the effect will be destroyed
                              and removed from the scenegraph upon
                              interval completion
                              set to False if planning on reusing
                              the interval
        name is a string: use this for unique intervals so that
                          they can be easily found in the taskMgr
        """

        # Generate unique name
        id = 'Particle-%d' % ParticleInterval.particleNum
        ParticleInterval.particleNum += 1
        if name == None:
            name = id
        # Record instance variables
        self.particleEffect = particleEffect
        self.cleanup = cleanup

        if parent != None:
            self.particleEffect.reparentTo(parent)
        if worldRelative:
            renderParent = render
        if renderParent:
            for particles in self.particleEffect.getParticlesList():
                particles.setRenderParent(renderParent.node())

        self.__softStopped = False

        if softStopT == 0.0:
            self.softStopT = duration
        elif softStopT < 0.0:
            self.softStopT = duration + softStopT
        else:
            self.softStopT = softStopT

        # Initialize superclass
        Interval.__init__(self, name, duration)

    def __step(self, dt):
        if self.particleEffect:
            self.particleEffect.accelerate(dt, 1, 0.05)

    def __softStart(self):
        if self.particleEffect:
            self.particleEffect.softStart()
        self.__softStopped = False

    def __softStop(self):
        if self.particleEffect:
            self.particleEffect.softStop()
        self.__softStopped = True

    def privInitialize(self, t):
        if self.state != CInterval.SPaused:
            # Restarting from a hard stop or just interrupting the
            # current play
            self.__softStart()
            if self.particleEffect:
                self.particleEffect.clearToInitial()
            self.currT = 0

        if self.particleEffect:
            for forceGroup in self.particleEffect.getForceGroupList():
                forceGroup.enable()

        Interval.privInitialize(self, t)

    def privInstant(self):
        self.privInitialize(self.getDuration())
        self.privFinalize()

    def privStep(self, t):
        if self.state == CInterval.SPaused or t < self.currT:
            # Restarting from a pause.
            self.privInitialize(t)
        else:
            if not self.__softStopped and t > self.softStopT:
                self.__step(self.softStopT - self.currT)
                self.__softStop()
                self.__step(t - self.softStopT)
            else:
                self.__step(t - self.currT)
            Interval.privStep(self, t)

    def privFinalize(self):
        Interval.privFinalize(self)
        if self.cleanup and self.particleEffect:
            self.particleEffect.disable()
            self.particleEffect = None