DistributedObject.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. """DistributedObject module: contains the DistributedObject class"""
  2. from PandaObject import *
  3. from DirectNotifyGlobal import *
  4. class DistributedObject(PandaObject):
  5. """Distributed Object class:"""
  6. notify = directNotify.newCategory("DistributedObject")
  7. # A few objects will set neverDisable to 1... Examples are
  8. # localToon, and anything that lives in the UberZone. This
  9. # keeps them from being disabled when you change zones,
  10. # even to the quiet zone.
  11. neverDisable = 0
  12. def __init__(self, cr):
  13. try:
  14. self.DistributedObject_initialized
  15. except:
  16. self.DistributedObject_initialized = 1
  17. self.cr = cr
  18. # Most DistributedObjects are simple and require no real
  19. # effort to load. Some, particularly actors, may take
  20. # some significant time to load; these we can optimize by
  21. # caching them when they go away instead of necessarily
  22. # deleting them. The object should set cacheable to 1 if
  23. # it needs to be optimized in this way.
  24. self.setCacheable(0)
  25. # This count tells whether the object can be deleted right away,
  26. # or not.
  27. self.delayDeleteCount = 0
  28. # This flag tells whether a delete has been requested on this
  29. # object.
  30. self.deleteImminent = 0
  31. # It's useful to have a "disabled" flag. This is only
  32. # trustworthy if the inheriting class properly calls up
  33. # the chain for disable() and generate().
  34. self.disabled = 1
  35. return None
  36. #def __del__(self):
  37. # """
  38. # For debugging purposes, this just prints out what got deleted
  39. # """
  40. # DistributedObject.notify.debug("Destructing: " + self.__class__.__name__ +
  41. # " id: " + str(self.doId))
  42. # PandaObject.__del__(self)
  43. def setNeverDisable(self, bool):
  44. assert((bool == 1) or (bool == 0))
  45. self.neverDisable = bool
  46. return None
  47. def getNeverDisable(self):
  48. return self.neverDisable
  49. def setCacheable(self, bool):
  50. assert((bool == 1) or (bool == 0))
  51. self.cacheable = bool
  52. return None
  53. def getCacheable(self):
  54. return self.cacheable
  55. def deleteOrDelay(self):
  56. if self.delayDeleteCount > 0:
  57. self.deleteImminent = 1
  58. else:
  59. self.disableAnnounceAndDelete()
  60. return None
  61. def delayDelete(self, flag):
  62. # Flag should be 0 or 1, meaning increment or decrement count
  63. # Also see DelayDelete.py
  64. if (flag == 1):
  65. self.delayDeleteCount += 1
  66. elif (flag == 0):
  67. self.delayDeleteCount -= 1
  68. else:
  69. self.notify.error("Invalid flag passed to delayDelete: " + str(flag))
  70. if (self.delayDeleteCount < 0):
  71. self.notify.error("Somebody decremented delayDelete for doId %s without incrementing"
  72. % (self.doId))
  73. elif (self.delayDeleteCount == 0):
  74. self.notify.debug("delayDeleteCount for doId %s now 0" % (self.doId))
  75. if self.deleteImminent:
  76. self.notify.debug("delayDeleteCount for doId %s -- deleteImminent"
  77. % (self.doId))
  78. self.disableAnnounceAndDelete()
  79. else:
  80. self.notify.debug("delayDeleteCount for doId %s now %s"
  81. % (self.doId, self.delayDeleteCount))
  82. # Return the count just for kicks
  83. return self.delayDeleteCount
  84. def disableAnnounceAndDelete(self):
  85. self.disableAndAnnounce()
  86. self.delete()
  87. return None
  88. def disableAndAnnounce(self):
  89. """disableAndAnnounce(self)
  90. Inheritors should *not* redefine this function.
  91. """
  92. # We must send the disable announce message *before* we
  93. # actually disable the object. That way, the various cleanup
  94. # tasks can run first and take care of restoring the object to
  95. # a normal, nondisabled state; and *then* the disable function
  96. # can properly disable it (for instance, by parenting it to
  97. # hidden).
  98. messenger.send(self.uniqueName("disable"))
  99. self.disable()
  100. return None
  101. def announceGenerate(self):
  102. """announceGenerate(self)
  103. Sends a message to the world after the object has been
  104. generated and all of its required fields filled in.
  105. """
  106. messenger.send(self.uniqueName("generate"), [self])
  107. def disable(self):
  108. """disable(self)
  109. Inheritors should redefine this to take appropriate action on disable
  110. """
  111. self.disabled = 1
  112. def delete(self):
  113. """delete(self)
  114. Inheritors should redefine this to take appropriate action on delete
  115. """
  116. try:
  117. self.DistributedObject_deleted
  118. except:
  119. self.DistributedObject_deleted = 1
  120. del self.cr
  121. return
  122. def generate(self):
  123. """generate(self)
  124. Inheritors should redefine this to take appropriate action on generate
  125. """
  126. self.disabled = 0
  127. def generateInit(self):
  128. """generateInit(self)
  129. This method is called when the DistributedObject is first introduced
  130. to the world... Not when it is pulled from the cache.
  131. """
  132. def getDoId(self):
  133. """getDoId(self)
  134. Return the distributed object id
  135. """
  136. return self.doId
  137. def updateRequiredFields(self, cdc, di):
  138. for i in cdc.broadcastRequiredCDU:
  139. i.updateField(cdc, self, di)
  140. def updateAllRequiredFields(self, cdc, di):
  141. for i in cdc.allRequiredCDU:
  142. i.updateField(cdc, self, di)
  143. def updateRequiredOtherFields(self, cdc, di):
  144. # First, update the required fields
  145. for i in cdc.broadcastRequiredCDU:
  146. i.updateField(cdc, self, di)
  147. # Determine how many other fields there are
  148. numberOfOtherFields = di.getArg(STUint16)
  149. # Update each of the other fields
  150. for i in range(numberOfOtherFields):
  151. cdc.updateField(self, di)
  152. return None
  153. def sendUpdate(self, fieldName, args = [], sendToId = None):
  154. self.cr.sendUpdate(self, fieldName, args, sendToId)
  155. def taskName(self, taskString):
  156. return (taskString + "-" + str(self.getDoId()))
  157. def uniqueName(self, idString):
  158. return (idString + "-" + str(self.getDoId()))
  159. def isLocal(self):
  160. # This returns true if the distributed object is "local,"
  161. # which means the client created it instead of the AI, and it
  162. # gets some other special handling. Normally, only the local
  163. # avatar class overrides this to return true.
  164. return 0