DistributedObjectOV.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. from direct.directnotify.DirectNotifyGlobal import directNotify
  2. from direct.distributed.DistributedObjectBase import DistributedObjectBase
  3. #from PyDatagram import PyDatagram
  4. #from PyDatagramIterator import PyDatagramIterator
  5. # Values for DistributedObjectOV.activeState
  6. # these should match DistributedObject.ES*
  7. ESNew = 1
  8. ESDeleted = 2
  9. ESDisabling = 3
  10. ESDisabled = 4 # values here and lower are considered "disabled"
  11. ESGenerating = 5 # values here and greater are considered "generated"
  12. ESGenerated = 6
  13. class DistributedObjectOV(DistributedObjectBase):
  14. """
  15. Implementation of the 'owner view' (OV) of a distributed object;
  16. """
  17. notify = directNotify.newCategory("DistributedObjectOV")
  18. def __init__(self, cr):
  19. assert self.notify.debugStateCall(self)
  20. try:
  21. self.DistributedObjectOV_initialized
  22. except:
  23. self.DistributedObjectOV_initialized = 1
  24. DistributedObjectBase.__init__(self, cr)
  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. # Keep track of our state as a distributed object. This
  32. # is only trustworthy if the inheriting class properly
  33. # calls up the chain for disable() and generate().
  34. self.activeState = ESNew
  35. if __debug__:
  36. def status(self, indent=0):
  37. """
  38. print out "doId(parentId, zoneId) className"
  39. and conditionally show generated, disabled
  40. """
  41. spaces=' '*(indent+2)
  42. try:
  43. print "%s%s:"%(
  44. ' '*indent, self.__class__.__name__)
  45. print "%sfrom DistributedObjectOV doId:%s, parent:%s, zone:%s"%(
  46. spaces,
  47. self.doId, self.parentId, self.zoneId),
  48. flags=[]
  49. if self.activeState == ESGenerated:
  50. flags.append("generated")
  51. if self.activeState < ESGenerating:
  52. flags.append("disabled")
  53. if len(flags):
  54. print "(%s)"%(" ".join(flags),),
  55. print
  56. except Exception, e: print "%serror printing status"%(spaces,), e
  57. def deleteOrDelay(self):
  58. if self.delayDeleteCount > 0:
  59. self.deleteImminent = 1
  60. else:
  61. self.disableAnnounceAndDelete()
  62. def delayDelete(self, flag):
  63. # Flag should be 0 or 1, meaning increment or decrement count
  64. # Also see DelayDelete.py
  65. if (flag == 1):
  66. self.delayDeleteCount += 1
  67. elif (flag == 0):
  68. self.delayDeleteCount -= 1
  69. else:
  70. self.notify.error("Invalid flag passed to delayDelete: " + str(flag))
  71. if (self.delayDeleteCount < 0):
  72. self.notify.error("Somebody decremented delayDelete for doId %s without incrementing"
  73. % (self.doId))
  74. elif (self.delayDeleteCount == 0):
  75. assert(self.notify.debug("delayDeleteCount for doId %s now 0"
  76. % (self.doId)))
  77. if self.deleteImminent:
  78. assert(self.notify.debug("delayDeleteCount for doId %s -- deleteImminent"
  79. % (self.doId)))
  80. self.disableAnnounceAndDelete()
  81. else:
  82. self.notify.debug("delayDeleteCount for doId %s now %s"
  83. % (self.doId, self.delayDeleteCount))
  84. # Return the count just for kicks
  85. return self.delayDeleteCount
  86. def disableAnnounceAndDelete(self):
  87. self.disableAndAnnounce()
  88. self.delete()
  89. def disableAndAnnounce(self):
  90. """
  91. Inheritors should *not* redefine this function.
  92. """
  93. # We must send the disable announce message *before* we
  94. # actually disable the object. That way, the various cleanup
  95. # tasks can run first and take care of restoring the object to
  96. # a normal, nondisabled state; and *then* the disable function
  97. # can properly disable it (for instance, by parenting it to
  98. # hidden).
  99. if self.activeState != ESDisabled:
  100. self.activeState = ESDisabling
  101. messenger.send(self.uniqueName("disable"))
  102. self.disable()
  103. def announceGenerate(self):
  104. """
  105. Sends a message to the world after the object has been
  106. generated and all of its required fields filled in.
  107. """
  108. assert self.notify.debug('announceGenerate(): %s' % (self.doId))
  109. if self.activeState != ESGenerated:
  110. self.activeState = ESGenerated
  111. messenger.send(self.uniqueName("generate"), [self])
  112. def disable(self):
  113. """
  114. Inheritors should redefine this to take appropriate action on disable
  115. """
  116. assert self.notify.debug('disable(): %s' % (self.doId))
  117. if self.activeState != ESDisabled:
  118. self.activeState = ESDisabled
  119. def isDisabled(self):
  120. """
  121. Returns true if the object has been disabled and/or deleted,
  122. or if it is brand new and hasn't yet been generated.
  123. """
  124. return (self.activeState < ESGenerating)
  125. def isGenerated(self):
  126. """
  127. Returns true if the object has been fully generated by now,
  128. and not yet disabled.
  129. """
  130. assert self.notify.debugStateCall(self)
  131. return (self.activeState == ESGenerated)
  132. def delete(self):
  133. """
  134. Inheritors should redefine this to take appropriate action on delete
  135. """
  136. assert self.notify.debug('delete(): %s' % (self.doId))
  137. try:
  138. self.DistributedObjectOV_deleted
  139. except:
  140. self.DistributedObjectOV_deleted = 1
  141. self.cr = None
  142. self.dclass = None
  143. def generate(self):
  144. """
  145. Inheritors should redefine this to take appropriate action on generate
  146. """
  147. assert self.notify.debugStateCall(self)
  148. self.activeState = ESGenerating
  149. # this has already been set at this point
  150. #self.cr.storeObjectLocation(self.doId, self.parentId, self.zoneId)
  151. def generateInit(self):
  152. """
  153. This method is called when the DistributedObjectOV is first introduced
  154. to the world... Not when it is pulled from the cache.
  155. """
  156. self.activeState = ESGenerating
  157. def getDoId(self):
  158. """
  159. Return the distributed object id
  160. """
  161. return self.doId
  162. def updateRequiredFields(self, dclass, di):
  163. dclass.receiveUpdateBroadcastRequired(self, di)
  164. self.announceGenerate()
  165. def updateAllRequiredFields(self, dclass, di):
  166. dclass.receiveUpdateAllRequired(self, di)
  167. self.announceGenerate()
  168. def updateRequiredOtherFields(self, dclass, di):
  169. # First, update the required fields
  170. dclass.receiveUpdateBroadcastRequiredOwner(self, di)
  171. # Announce generate after updating all the required fields,
  172. # but before we update the non-required fields.
  173. self.announceGenerate()
  174. dclass.receiveUpdateOther(self, di)
  175. def getCacheable(self):
  176. return False
  177. def sendUpdate(self, fieldName, args = [], sendToId = None):
  178. if self.cr:
  179. dg = self.dclass.clientFormatUpdate(
  180. fieldName, sendToId or self.doId, args)
  181. self.cr.send(dg)
  182. else:
  183. self.notify.warning("sendUpdate failed, because self.cr is not set")
  184. def taskName(self, taskString):
  185. return ('%s-%s-OV' % (taskString, self.getDoId()))
  186. def uniqueName(self, idString):
  187. return ('%s-%s-OV' % (idString, self.getDoId()))