state_machine.py (4382B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\dynamicresources\client\ess\bracket\state_machine.py 2 import logging 3 import eveui 4 import gametime 5 import threadutils 6 import uthread2 7 log = logging.getLogger(__name__) 8 9 class StateMachine(object): 10 11 def __init__(self): 12 self._is_closed = False 13 self._active_state = None 14 self._next_state = None 15 self._is_transitioning = False 16 self._active_transition = None 17 18 @property 19 def is_closed(self): 20 return self._is_closed 21 22 def close(self): 23 if self._active_transition is not None: 24 self._active_transition.stop() 25 if self._active_state is not None: 26 self._active_state.close() 27 self._active_state = None 28 self._is_closed = True 29 30 @threadutils.threaded 31 def move_to(self, state): 32 self._next_state = state 33 if self._is_transitioning: 34 if self._active_transition is not None: 35 self._active_transition.stop() 36 return 37 while self._next_state is not None: 38 state = self._next_state 39 self._next_state = None 40 self._move_to(state) 41 42 def _move_to(self, state): 43 self._is_transitioning = True 44 try: 45 if self._active_state is not None: 46 if type(self._active_state) == type(state): 47 return 48 transition = self._active_state.exit() 49 self._active_state.close() 50 if transition is not None: 51 self._run_transition(transition) 52 if self.is_closed: 53 return 54 if self._next_state is not None: 55 state = self._next_state 56 self._next_state = None 57 self._active_state = state 58 transition = self._active_state.enter() 59 if transition is not None: 60 self._run_transition(transition) 61 finally: 62 self._is_transitioning = False 63 64 def _run_transition(self, transition): 65 self._active_transition = transition 66 try: 67 transition.start() 68 transition.wait() 69 finally: 70 self._active_transition = None 71 72 73 class State(object): 74 75 def enter(self): 76 return None 77 78 def exit(self): 79 return None 80 81 def close(self): 82 pass 83 84 85 class Transition(object): 86 87 def __init__(self): 88 self._is_started = False 89 self._is_stopped = False 90 self._is_closed = False 91 self._wait_channel = uthread2.queue_channel() 92 self._waiting_count = 0 93 94 @property 95 def is_stopped(self): 96 return self._is_stopped 97 98 def animation(self): 99 pass 100 101 def on_close(self): 102 pass 103 104 def sleep(self, duration, interruptable = True): 105 start = gametime.now() 106 while (gametime.now() - start).total_seconds() < duration: 107 if interruptable and self._is_stopped: 108 raise TransitionStopped() 109 eveui.wait_for_next_frame() 110 111 def start(self): 112 if self._is_closed: 113 raise RuntimeError('Transition has been closed') 114 if self._is_started: 115 raise RuntimeError('Already started') 116 self._is_started = True 117 self._perform_transition() 118 119 def wait(self): 120 if self._is_closed: 121 return 122 self._waiting_count += 1 123 try: 124 self._wait_channel.receive() 125 finally: 126 self._waiting_count -= 1 127 128 def stop(self): 129 self._is_stopped = True 130 131 def close(self): 132 if self._is_closed: 133 return 134 self.stop() 135 self._is_closed = True 136 if self._waiting_count > 0: 137 self._notify_waiting() 138 self.on_close() 139 140 @threadutils.threaded 141 def _perform_transition(self): 142 try: 143 self.animation() 144 except TransitionStopped: 145 pass 146 except Exception: 147 log.exception('Exception raised during transition') 148 149 try: 150 self.close() 151 except Exception: 152 log.exception('Exception when closing a transition') 153 154 self._notify_waiting() 155 156 def _notify_waiting(self): 157 for _ in range(self._waiting_count): 158 self._wait_channel.send(None) 159 160 161 class TransitionStopped(Exception): 162 pass