Browse Source

generalize interruptible to autoPause and autoFinish

David Rose 23 years ago
parent
commit
a71af97bf4

+ 32 - 1
direct/src/interval/IntervalManager.py

@@ -1,5 +1,6 @@
 from PandaModules import *
 from DirectNotifyGlobal import *
+import EventManager
 import Interval
 import types
 
@@ -24,6 +25,12 @@ class IntervalManager(CIntervalManager):
         else:
             CIntervalManager.__init__(self)
 
+        # Set up a custom event queue for handling C++ events from
+        # intervals.
+        self.eventQueue = EventQueue()
+        self.eventManager = EventManager.EventManager(self.eventQueue)
+        self.setEventQueue(self.eventQueue)
+        
         self.ivals = []
         self.removedIvals = {}
 
@@ -46,9 +53,26 @@ class IntervalManager(CIntervalManager):
         return None
 
     def step(self):
-        # Call C++ step, then do all the required Python post-processing.
+        # This method should be called once per frame to perform all
+        # of the per-frame processing on the active intervals.
+        
+        # Call C++ step, then do the Python stuff.
         CIntervalManager.step(self)
+        self.__doPythonCallbacks()
+
+    def interrupt(self):
+        # This method should be called during an emergency cleanup
+        # operation, to automatically pause or finish all active
+        # intervals tagged with autoPause or autoFinish set true.
+        
+        # Call C++ interrupt, then do the Python stuff.
+        CIntervalManager.interrupt(self)
+        self.__doPythonCallbacks()
 
+    def __doPythonCallbacks(self):
+        # This method does all of the required Python post-processing
+        # after performing some C++-level action.
+        
         # It is important to call all of the python callbacks on the
         # just-removed intervals before we call any of the callbacks
         # on the still-running intervals.
@@ -67,6 +91,13 @@ class IntervalManager(CIntervalManager):
             self.ivals[index].privPostEvent()
             index = self.getNextEvent()
 
+        # Finally, throw all the events on the custom event queue.
+        # These are the done events that may have been generated in
+        # C++.  We use a custom event queue so we can service all of
+        # these immediately, rather than waiting for the global event
+        # queue to be serviced (which might not be till next frame).
+        self.eventManager.doEvents()
+        
         
     def __storeInterval(self, interval, index):
         while index >= len(self.ivals):

+ 18 - 5
direct/src/interval/MetaInterval.py

@@ -32,10 +32,22 @@ class MetaInterval(CMetaInterval):
                 name = kw['name']
                 del kw['name']
 
-        interruptible = 0
-        if kw.has_key('interruptible'):
-            interruptible = kw['interruptible']
-            del kw['interruptible']
+        # If the keyword "autoPause" or "autoFinish" is defined to
+        # non-zero, it means the interval may be automatically paused
+        # or finished when CIntervalManager::interrupt() is called.
+        # This is generally called only on a catastrophic situation
+        # (for instance, the connection to the server being lost) when
+        # we have to exit right away; these keywords indicate
+        # intervals that might not be cleaned up by their owners.
+        
+        autoPause = 0
+        autoFinish = 0
+        if kw.has_key('autoPause'):
+            autoPause = kw['autoPause']
+            del kw['autoPause']
+        if kw.has_key('autoFinish'):
+            autoFinish = kw['autoFinish']
+            del kw['autoFinish']
 
         # A duration keyword specifies the duration the interval will
         # appear to have for the purposes of computing the start time
@@ -71,7 +83,8 @@ class MetaInterval(CMetaInterval):
 
         CMetaInterval.__init__(self, name)
         self.__manager = ivalMgr
-        self.setInterruptible(interruptible)
+        self.setAutoPause(autoPause)
+        self.setAutoFinish(autoFinish)
 
         self.pythonIvals = []
 

+ 37 - 10
direct/src/interval/cInterval.I

@@ -117,30 +117,57 @@ get_t() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CInterval::set_interruptible
+//     Function: CInterval::set_auto_pause
 //       Access: Published
-//  Description: Changes the state of the 'interruptible' flag.  If
+//  Description: Changes the state of the 'auto_pause' flag.  If
 //               this is true, the interval may be arbitrarily
 //               interrupted when the system needs to reset due to
 //               some external event by calling
-//               CIntervalManager::pause_all_interruptible().  If this
+//               CIntervalManager::interrupt().  If this
 //               is false (the default), the interval must always be
 //               explicitly finished or paused.
 ////////////////////////////////////////////////////////////////////
 INLINE void CInterval::
-set_interruptible(bool interruptible) {
-  _interruptible = interruptible;
+set_auto_pause(bool auto_pause) {
+  _auto_pause = auto_pause;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CInterval::get_interruptible
+//     Function: CInterval::get_auto_pause
 //       Access: Published
-//  Description: Returns the state of the 'interruptible' flag.  See
-//               set_interruptible().
+//  Description: Returns the state of the 'auto_pause' flag.  See
+//               set_auto_pause().
 ////////////////////////////////////////////////////////////////////
 INLINE bool CInterval::
-get_interruptible() const {
-  return _interruptible;
+get_auto_pause() const {
+  return _auto_pause;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CInterval::set_auto_finish
+//       Access: Published
+//  Description: Changes the state of the 'auto_finish' flag.  If
+//               this is true, the interval may be arbitrarily
+//               finished when the system needs to reset due to
+//               some external event by calling
+//               CIntervalManager::interrupt().  If this
+//               is false (the default), the interval must always be
+//               explicitly finished or paused.
+////////////////////////////////////////////////////////////////////
+INLINE void CInterval::
+set_auto_finish(bool auto_finish) {
+  _auto_finish = auto_finish;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CInterval::get_auto_finish
+//       Access: Published
+//  Description: Returns the state of the 'auto_finish' flag.  See
+//               set_auto_finish().
+////////////////////////////////////////////////////////////////////
+INLINE bool CInterval::
+get_auto_finish() const {
+  return _auto_finish;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 5 - 3
direct/src/interval/cInterval.cxx

@@ -20,7 +20,8 @@
 #include "cIntervalManager.h"
 #include "indent.h"
 #include "clockObject.h"
-#include "throw_event.h"
+#include "event.h"
+#include "eventQueue.h"
 #include <math.h>
 
 TypeHandle CInterval::_type_handle;
@@ -39,7 +40,8 @@ CInterval(const string &name, double duration, bool open_ended) :
   _open_ended(open_ended),
   _dirty(false)
 {
-  _interruptible = false;
+  _auto_pause = false;
+  _auto_finish = false;
   _wants_t_callback = false;
   _last_t_callback = -1.0;
   _manager = CIntervalManager::get_global_ptr();
@@ -610,7 +612,7 @@ mark_dirty() {
 void CInterval::
 interval_done() {
   if (!_done_event.empty()) {
-    throw_event(_done_event);
+    _manager->get_event_queue()->queue_event(new Event(_done_event));
   }
 }
 

+ 6 - 3
direct/src/interval/cInterval.h

@@ -75,8 +75,10 @@ PUBLISHED:
   void set_t(double t);
   INLINE double get_t() const;
 
-  INLINE void set_interruptible(bool interruptible);
-  INLINE bool get_interruptible() const;
+  INLINE void set_auto_pause(bool auto_pause);
+  INLINE bool get_auto_pause() const;
+  INLINE void set_auto_finish(bool auto_finish);
+  INLINE bool get_auto_finish() const;
 
   INLINE void set_wants_t_callback(bool wants_t_callback);
   INLINE bool get_wants_t_callback() const;
@@ -136,7 +138,8 @@ protected:
   string _done_event;
   double _duration;
 
-  bool _interruptible;
+  bool _auto_pause;
+  bool _auto_finish;
   bool _wants_t_callback;
   double _last_t_callback;
   CIntervalManager *_manager;

+ 29 - 0
direct/src/interval/cIntervalManager.I

@@ -17,6 +17,35 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CIntervalManager::set_event_queue
+//       Access: Published
+//  Description: Specifies a custom event queue to be used for
+//               throwing done events from intervals as they finish.
+//               If this is not specified, the global event queue is
+//               used.
+//
+//               The caller maintains ownership of the EventQueue
+//               object; it is the caller's responsibility to ensure
+//               that the supplied EventQueue does not destruct during
+//               the lifetime of the CIntervalManager.
+////////////////////////////////////////////////////////////////////
+INLINE void CIntervalManager::
+set_event_queue(EventQueue *event_queue) {
+  _event_queue = event_queue;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CIntervalManager::get_event_queue
+//       Access: Published
+//  Description: Returns the custom event queue to be used for
+//               throwing done events from intervals as they finish.
+////////////////////////////////////////////////////////////////////
+INLINE EventQueue *CIntervalManager::
+get_event_queue() const {
+  return _event_queue;
+}
+
 INLINE ostream &
 operator << (ostream &out, const CIntervalManager &ival_mgr) {
   ival_mgr.output(out);

+ 39 - 10
direct/src/interval/cIntervalManager.cxx

@@ -19,6 +19,7 @@
 #include "cIntervalManager.h"
 #include "cMetaInterval.h"
 #include "dcast.h"
+#include "eventQueue.h"
 
 CIntervalManager *CIntervalManager::_global_ptr;
 
@@ -31,6 +32,7 @@ CIntervalManager::
 CIntervalManager() {
   _first_slot = 0;
   _next_event_index = 0;
+  _event_queue = EventQueue::get_global_event_queue();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -164,18 +166,18 @@ remove_c_interval(int index) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CIntervalManager::pause_all_interruptible
+//     Function: CIntervalManager::interrupt
 //       Access: Published
-//  Description: Pauses (removes from the active queue) all intervals
-//               tagged as "interruptible".  These are intervals that
-//               someone fired up but won't necessarily expect to
-//               clean up; they can be interrupted at will when
-//               necessary.
+//  Description: Pauses or finishes (removes from the active queue)
+//               all intervals tagged with auto_pause or auto_finish
+//               set to true.  These are intervals that someone fired
+//               up but won't necessarily expect to clean up; they can
+//               be interrupted at will when necessary.
 //
 //               Returns the number of intervals affected.
 ////////////////////////////////////////////////////////////////////
 int CIntervalManager::
-pause_all_interruptible() {
+interrupt() {
   int num_paused = 0;
 
   NameIndex::iterator ni;
@@ -184,11 +186,38 @@ pause_all_interruptible() {
     int index = (*ni).second;
     const IntervalDef &def = _intervals[index];
     nassertr(def._interval != (CInterval *)NULL, num_paused);
-    if (def._interval->get_interruptible()) {
+    if (def._interval->get_auto_pause() || def._interval->get_auto_finish()) {
       // This interval may be interrupted.
-      if (def._interval->get_state() == CInterval::S_started) {
-        def._interval->priv_interrupt();
+      if (def._interval->get_auto_pause()) {
+        // It may be interrupted simply by pausing it.
+        if (interval_cat.is_debug()) {
+          interval_cat.debug()
+            << "Auto-pausing " << def._interval->get_name() << "\n";
+        }
+        if (def._interval->get_state() == CInterval::S_started) {
+          def._interval->priv_interrupt();
+        }
+
+      } else {
+        // It should be interrupted by finishing it.
+        if (interval_cat.is_debug()) {
+          interval_cat.debug()
+            << "Auto-finishing " << def._interval->get_name() << "\n";
+        }
+        switch (def._interval->get_state()) {
+        case CInterval::S_initial:
+          def._interval->priv_instant();
+          break;
+          
+        case CInterval::S_final:
+          break;
+          
+        default:
+          def._interval->priv_finalize();
+        }
       }
+
+      // Now carefully remove it from the active list.
       NameIndex::iterator prev;
       prev = ni;
       ++ni;

+ 7 - 1
direct/src/interval/cIntervalManager.h

@@ -26,6 +26,8 @@
 #include "pmap.h"
 #include "vector_int.h"
 
+class EventQueue;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : CIntervalManager
 // Description : This object holds a number of currently-playing
@@ -46,13 +48,16 @@ PUBLISHED:
   CIntervalManager();
   ~CIntervalManager();
 
+  INLINE void set_event_queue(EventQueue *event_queue);
+  INLINE EventQueue *get_event_queue() const;
+
   int add_c_interval(CInterval *interval, bool external);
   int find_c_interval(const string &name) const;
 
   CInterval *get_c_interval(int index) const;
   void remove_c_interval(int index);
 
-  int pause_all_interruptible();
+  int interrupt();
   int get_num_intervals() const;
 
   void step();
@@ -84,6 +89,7 @@ private:
   NameIndex _name_index;
   typedef vector_int Removed;
   Removed _removed;
+  EventQueue *_event_queue;
 
   int _first_slot;
   int _next_event_index;