NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

_ticker.py (9370B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\destiny\net\client\_ticker.py
      2 import logging
      3 import sys
      4 from destiny.net.client._baseticker import BaseTicker
      5 from destiny.net.client._util import merge_state_into_history
      6 import blue
      7 logger = logging.getLogger(__name__)
      8 LOCAL_ACTIONS = {'AddBallsToPark', 'RemoveBall', 'RemoveBalls'}
      9 
     10 class Ticker(BaseTicker):
     11 
     12     def __init__(self, error_handler, client_ticker_interface):
     13         super(Ticker, self).__init__(error_handler)
     14         self._should_rebase = False
     15         self._last_stamp = -1
     16         self._states = []
     17         self._state_is_valid = False
     18         self._client_ticker_interface = client_ticker_interface
     19 
     20     def set_ballpark(self, ballpark):
     21         super(Ticker, self).set_ballpark(ballpark)
     22         self._client_ticker_interface.set_ballpark(ballpark)
     23 
     24     def _flush_state(self, state, wait_for_bubble):
     25         logger.info('Server Update with %s event(s) added to history', len(state))
     26         if len(state) == 0:
     27             logger.warn('Empty state received from remote ballpark')
     28             return
     29         if state[0][1][0] == 'SetState':
     30             self._latest_set_state_time = state[0][0]
     31             logger.info('Michelle received a SetState at time %s. Clearing out-of-date entries...', self._latest_set_state_time)
     32             self._history = [ history_entry for history_entry in self._history if history_entry[0][0][0] >= self._latest_set_state_time ]
     33             self._dump_history()
     34         else:
     35             entry_time = state[0][0]
     36             if entry_time < self._latest_set_state_time:
     37                 logger.warn('Michelle discarded a state that was too old %s < %s', entry_time, self._latest_set_state_time)
     38                 self._dump_history()
     39                 return
     40         merge_state_into_history(state, self._history, wait_for_bubble)
     41         self._dump_history()
     42 
     43     def do_pre_tick(self):
     44         while len(self._history) > 0:
     45             state, wait_for_bubble = self._history[0]
     46             if wait_for_bubble:
     47                 return
     48             event_stamp = state[0][0]
     49             if event_stamp > self._current_time and event_stamp - self._current_time < 3:
     50                 break
     51             self._real_flush_state(state)
     52             del self._history[0]
     53             if self._state_is_valid and self._should_rebase:
     54                 self.store_state(mid_tick=True)
     55             if len(self._history) > 1:
     56                 if self._history[0][1]:
     57                     return
     58                 self._ballpark._parent_Evolve()
     59 
     60     def _set_state(self, state, ego_ball_id):
     61         self._client_ticker_interface.on_set_state()
     62         self._ballpark.ClearAll()
     63         ms = blue.MemStream()
     64         ms.Write(state)
     65         self._ballpark.ReadFullStateFromStream(ms)
     66         self._ballpark.ego = long(ego_ball_id)
     67         self._ballpark.Start()
     68         self._state_is_valid = True
     69         self.flush_simulation_history()
     70 
     71     def _real_flush_state(self, state):
     72         logger.info('Handling Server Update with %s event(s)', len(state))
     73         if len(state) == 0:
     74             logger.warn('Empty state received from remote ballpark')
     75             return
     76         event_stamp, event = state[0]
     77         func_name, args = event
     78         if func_name == 'SetState':
     79             if self._client_ticker_interface.should_log_actions():
     80                 logger.info('Action: %12.12s %s - current: %s %s', func_name, event_stamp, self._current_time, args)
     81             self._set_state(*args)
     82         if self._state_is_valid:
     83             self._should_rebase = False
     84             synchronised = False
     85             for action in state:
     86                 event_stamp, event = action
     87                 func_name, args = event
     88                 if func_name == 'SetState':
     89                     continue
     90                 if self._client_ticker_interface.should_log_actions():
     91                     logger.info('Action: %12.12s %s - current: %s %s', func_name, event_stamp, self._current_time, args)
     92                 try:
     93                     if not synchronised:
     94                         synchronised = self.synchronize_to_simulation_time(event_stamp)
     95                     if not synchronised:
     96                         logger.warn('Failed to synchronize to %s', event_stamp)
     97                         self._error_handler.on_recoverable_desync()
     98                         return
     99                     self._should_rebase = True
    100                     if func_name in LOCAL_ACTIONS:
    101                         apply(getattr(self, func_name), args)
    102                     else:
    103                         apply(getattr(self._ballpark, '_parent_' + func_name), args)
    104                         self._client_ticker_interface.on_ballpark_local_action(func_name, args)
    105                         if func_name == 'CloakBall':
    106                             event_ball_id = args[0]
    107                             if self._ballpark.ego and self._ballpark.ego != event_ball_id:
    108                                 self.RemoveBall(event_ball_id)
    109                 except Exception:
    110                     message = '{} failed.'.format(func_name)
    111                     logger.error(message, exc_info=1)
    112                     sys.exc_clear()
    113                     continue
    114 
    115         else:
    116             logger.info('Events ignored')
    117 
    118     def do_post_tick(self, stamp):
    119         if self._should_rebase:
    120             self.flush_simulation_history()
    121             self._should_rebase = False
    122         elif stamp > self._last_stamp + 10:
    123             self.store_state()
    124 
    125     def clear_states(self):
    126         self._states = []
    127 
    128     def store_state(self, mid_tick = False):
    129         if not self._ballpark.isRunning:
    130             return
    131         ms = blue.MemStream()
    132         self._ballpark.WriteFullStateToStream(ms)
    133         self._states.append([ms, self._current_time, mid_tick])
    134         logger.info('store_state: %s mid_tick: %s', self._current_time, mid_tick)
    135         if len(self._states) > 10:
    136             self._states = self._states[:1] + self._states[3:3] + self._states[-5:]
    137         self._last_stamp = self._current_time
    138 
    139     def synchronize_to_simulation_time(self, stamp):
    140         logger.info('SynchroniseToSimulationTime looking for: %s - current: %s', stamp, self._current_time)
    141         if stamp < self._current_time:
    142             last_stamp = 0
    143             last_state = None
    144             for item in self._states:
    145                 if item[1] <= stamp:
    146                     last_stamp = item[1]
    147                     last_state = item[0]
    148                 else:
    149                     continue
    150 
    151             if not last_state:
    152                 logger.warn('SynchroniseToSimulationTime: Did not find any state')
    153                 return 0
    154             self._ballpark._parent_ReadFullStateFromStream(last_state, 1)
    155         else:
    156             last_stamp = self._current_time
    157         for i in range(stamp - last_stamp):
    158             self._ballpark._parent_Evolve()
    159 
    160         logger.info('SynchroniseToSimulationTime found: %s', self._current_time)
    161         return 1
    162 
    163     def flush_simulation_history(self, new_base_snapshot = True):
    164         logger.info('State history rebased at %s newBaseSnapshot %s', self._current_time, new_base_snapshot)
    165         last_mid_state = None
    166         if new_base_snapshot and len(self._states):
    167             last_mid_state = self._states[-1]
    168             if not last_mid_state[2] or last_mid_state[1] != self._current_time - 1:
    169                 last_mid_state = None
    170         self.clear_states()
    171         if new_base_snapshot:
    172             if last_mid_state:
    173                 self._states.append(last_mid_state)
    174             self.store_state()
    175             for state in self._states:
    176                 logger.info('State entry %s', state)
    177 
    178     def AddBallsToPark(self, state):
    179         ms = blue.MemStream()
    180         ms.Write(state)
    181         self._ballpark.ReadFullStateFromStream(ms, 2)
    182 
    183     def RemoveBall(self, ball_id, terminal = False):
    184         blue.statistics.EnterZone('RemoveBall')
    185         try:
    186             if terminal:
    187                 logger.info('Removing ball %s (terminal)')
    188             else:
    189                 logger.info('Removing ball %s')
    190             ball = self._ballpark.balls.get(ball_id, None)
    191             delay = self._client_ticker_interface.get_ball_destruction_delay(ball, is_terminal=terminal)
    192             self._ballpark._parent_RemoveBall(ball_id, delay)
    193             self._client_ticker_interface.clean_up_after_ball_removal(ball_id, ball, is_terminal=terminal)
    194         finally:
    195             blue.statistics.LeaveZone()
    196 
    197     def RemoveBalls(self, ball_ids, is_release = False):
    198         blue.statistics.EnterZone('RemoveBalls')
    199         try:
    200             self._client_ticker_interface.clean_up_after_multiple_ball_removal(ball_ids, is_release=is_release)
    201             removal_delays = self._client_ticker_interface.get_ball_destruction_delays(ball_ids, is_release=is_release)
    202             for ball_id, delay in removal_delays.iteritems():
    203                 self._ballpark._parent_RemoveBall(ball_id, delay)
    204 
    205         finally:
    206             blue.statistics.LeaveZone()
    207 
    208     def invalidate_state(self):
    209         self._state_is_valid = False
    210 
    211     def release(self):
    212         self.RemoveBalls(self._ballpark.balls.iterkeys(), is_release=True)
    213         self._ballpark.ClearAll()
    214         self.flush_simulation_history(new_base_snapshot=False)
    215         self._history = []
    216         self._latest_set_state_time = 0
    217         self._state_is_valid = False