window.py (25885B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\dynamicresources\client\ess\bracket\debug\window.py 2 import contextlib 3 import datetime 4 import uuid 5 from collections import OrderedDict 6 import datetimeutils 7 import eveformat 8 import evelink.client 9 import eveui 10 import gametime 11 import localization 12 import signals 13 import uthread2 14 from carbonui import uiconst 15 from carbonui.control.combo import Combo 16 from carbonui.primitives.container import Container 17 from carbonui.primitives.containerAutoSize import ContainerAutoSize 18 from carbonui.primitives.fill import Fill 19 from carbonui.primitives.flowcontainer import FlowContainer 20 from carbonui.primitives.layoutGrid import LayoutGrid 21 from eve.client.script.ui import eveColor 22 from eve.client.script.ui.control import eveLabel 23 from carbonui.control.button import Button 24 from carbonui.control.checkbox import Checkbox 25 from carbonui.control.window import Window 26 from dynamicresources.client.ess.state import EssStateProvider, EssStatus, MainBankLink, MainBankLinkResult 27 from dynamicresources.client.service import get_dynamic_resource_service 28 29 class DebugEssStateProvider(EssStateProvider): 30 31 def __init__(self, provider): 32 if isinstance(provider, DebugEssStateProvider): 33 raise RuntimeError('Double wrapping!') 34 self._suppress_state_update = False 35 super(DebugEssStateProvider, self).__init__(provider.state) 36 self._real_provider = provider 37 self._next_token_id = provider._next_token_id 38 self._subscribers = provider._subscribers 39 provider._subscribers = OrderedDict() 40 self._need_fetch = provider._need_fetch 41 self.on_fetch_request = provider.on_fetch_request 42 provider.on_fetch_request = signals.Signal() 43 self._overrides = {} 44 self.history = [self._state] 45 self.on_override_changed = signals.Signal() 46 47 @EssStateProvider.state.setter 48 def state(self, state): 49 if self._real_provider is None: 50 raise RuntimeError('Provider has been released') 51 if state != self._real_provider.state: 52 self.history.append(state) 53 self._real_provider.state = state 54 old_state = self._state 55 self._state = self._override_state(state) 56 self.notify_subscribers(old_state, self._state) 57 58 def evolve(self, *args, **kwargs): 59 self.state = self._real_provider.state.evolve(*args, **kwargs) 60 61 def _override_state(self, state): 62 if '__state__' in self._overrides: 63 state = self._overrides['__state__'] 64 return state.evolve(status=self._overrides.get('status', state.status), in_range=self._overrides.get('in_range', state.in_range), main_bank=state.main_bank.evolve(balance=self._overrides.get('main_bank.balance', state.main_bank.balance), link=self._overrides.get('main_bank.link', state.main_bank.link), link_result=self._overrides.get('main_bank.link_result', state.main_bank.link_result)), reserve_bank=state.reserve_bank.evolve(balance=self._overrides.get('reserve_bank.balance', state.reserve_bank.balance), pulses_total=self._overrides.get('reserve_bank.pulses_total', state.reserve_bank.pulses_total), pulses_remaining=self._overrides.get('reserve_bank.pulses_remaining', state.reserve_bank.pulses_remaining), last_pulse_start=self._overrides.get('reserve_bank.last_pulse_start', state.reserve_bank.last_pulse_start), link_count=self._overrides.get('reserve_bank.link_count', state.reserve_bank.link_count), linked=self._overrides.get('reserve_bank.linked', state.reserve_bank.linked))) 65 66 def release_provider(self): 67 provider = self._real_provider 68 self._real_provider = None 69 provider._next_token_id = self._next_token_id 70 provider._subscribers = self._subscribers 71 self._subscribers = OrderedDict() 72 provider._need_fetch = self._need_fetch 73 provider.on_fetch_request = self.on_fetch_request 74 self.on_fetch_request = signals.Signal() 75 if self.state != provider.state: 76 provider.notify_subscribers(self.state, provider.state) 77 return provider 78 79 @contextlib.contextmanager 80 def atomic_override(self): 81 old_suppress = self._suppress_state_update 82 self._suppress_state_update = True 83 old_overrides = self._overrides.copy() 84 try: 85 yield 86 finally: 87 self._suppress_state_update = old_suppress 88 89 self._update_state(old_overrides) 90 91 def set_override(self, path, value): 92 old_overrides = self._overrides.copy() 93 self._overrides[path] = value 94 self._update_state(old_overrides) 95 96 def has_override(self, path): 97 return path in self._overrides 98 99 def clear_override(self, path): 100 old_overrides = self._overrides.copy() 101 del self._overrides[path] 102 self._update_state(old_overrides) 103 104 def _update_state(self, old_overrides): 105 if self._real_provider is None: 106 raise RuntimeError('Provider has been released') 107 if self._suppress_state_update: 108 return 109 old_state = self._state 110 self._state = self._override_state(self._real_provider.state) 111 self.notify_subscribers(old_state, self._state) 112 if old_overrides != self._overrides: 113 self.on_override_changed() 114 115 116 class EssStateProviderOverride(object): 117 118 def __init__(self, service): 119 self._service = service 120 self._wrapper = DebugEssStateProvider(service.ess_state_provider) 121 service._ess_state_provider = self._wrapper 122 123 def __del__(self): 124 self._service._ess_state_provider = self._wrapper.release_provider() 125 126 127 class EssDebugWindow(Window): 128 default_name = 'EssDebugWindow' 129 default_windowID = 'ess_debug_window' 130 default_caption = 'ESS Debug Window' 131 default_width = 300 132 default_height = 400 133 default_minSize = (default_width, default_height) 134 default_left = '__center__' 135 default_top = '__center__' 136 137 def __init__(self, **kwargs): 138 super(EssDebugWindow, self).__init__(**kwargs) 139 self._state_update_token = None 140 self._paused = False 141 self._state_index = 0 142 self._service = get_dynamic_resource_service() 143 self._ess_state_provider_override = EssStateProviderOverride(self._service) 144 self._is_reserve_bank_lock_overridden = False 145 self._on_state_update() 146 self.state_provider.on_override_changed.connect(self._redraw) 147 148 @property 149 def ess_state(self): 150 return self.state_provider.state 151 152 @property 153 def state_provider(self): 154 provider = self._service.ess_state_provider 155 if not isinstance(provider, DebugEssStateProvider): 156 raise RuntimeError('EssStateProvider not wrapped') 157 return provider 158 159 def Close(self, setClosed = False, *args, **kwargs): 160 self._state_update_token = None 161 if hasattr(self, '_ess_state_provider_override'): 162 del self._ess_state_provider_override 163 super(EssDebugWindow, self).Close(setClosed, *args, **kwargs) 164 165 def _on_state_update(self, state = None): 166 _, self._state_update_token = self.state_provider.watch(self._on_state_update) 167 self._redraw() 168 169 def _pause(self): 170 self._paused = True 171 self._state_index = len(self.state_provider.history) - 1 172 self.state_provider.set_override('__state__', self.state_provider.history[self._state_index]) 173 174 def _resume(self): 175 self._paused = False 176 self.state_provider.clear_override('__state__') 177 178 def _next_history(self): 179 if self._state_index < len(self.state_provider.history) - 1: 180 self._state_index += 1 181 self.state_provider.set_override('__state__', self.state_provider.history[self._state_index]) 182 183 def _previous_history(self): 184 if self._state_index > 0: 185 self._state_index -= 1 186 self.state_provider.set_override('__state__', self.state_provider.history[self._state_index]) 187 188 def _redraw(self): 189 if self.destroyed: 190 return 191 self.GetMainArea().Flush() 192 main = Container(parent=self.GetMainArea(), align=uiconst.TOALL, padding=12) 193 change_color = eveColor.CRYO_BLUE 194 history_cont = Container(parent=Container(parent=self.GetMainArea(), align=uiconst.TOBOTTOM, height=52, padding=(2, 0, 2, 2), bgColor=(0.0, 0.0, 0.0, 0.3)), align=uiconst.TOALL, padding=(16, 8, 16, 8)) 195 if not self._paused: 196 Button(parent=history_cont, align=uiconst.CENTERLEFT, minHeight=32, sidePadding=16, label='PAUSE', func=self._pause, args=()) 197 eveLabel.EveLabelMedium(parent=history_cont, align=uiconst.CENTERRIGHT, text='{} updates'.format(len(self.state_provider.history))) 198 else: 199 Fill(parent=history_cont.parent, align=uiconst.TOLEFT_NOPUSH, width=3, color=change_color) 200 Button(parent=history_cont, align=uiconst.CENTERLEFT, minHeight=32, sidePadding=16, label='RESUME', func=self._resume, args=()) 201 grid = LayoutGrid(parent=history_cont, align=uiconst.CENTERRIGHT, columns=3, cellSpacing=8) 202 prev_button = Button(parent=grid, align=uiconst.CENTER, label='PREVIOUS', func=self._previous_history, args=()) 203 if self._state_index == 0: 204 prev_button.Disable() 205 eveLabel.EveLabelMedium(parent=grid, align=uiconst.CENTER, text='{} / {}'.format(self._state_index + 1, len(self.state_provider.history))) 206 next_button = Button(parent=grid, align=uiconst.CENTER, label='NEXT', func=self._next_history, args=()) 207 if self._state_index >= len(self.state_provider.history) - 1: 208 next_button.Disable() 209 left_pad = 21 210 value_color = eveColor.BLACK 211 state_cont = ContainerAutoSize(parent=main, align=uiconst.TOTOP) 212 213 def field(parent, checked, callback): 214 wrap = ContainerAutoSize(parent=parent, align=uiconst.TOTOP, alignMode=uiconst.TOTOP, padBottom=8) 215 Fill(parent=wrap, align=uiconst.TOLEFT_NOPUSH, left=-10, width=3, color=change_color if checked else (0.2, 0.2, 0.2)) 216 Checkbox(parent=ContainerAutoSize(parent=wrap, align=uiconst.TOLEFT, minHeight=16), align=uiconst.CENTERTOP, top=1, checked=checked, callback=callback, hint='clear override' if checked else 'override') 217 return wrap 218 219 is_status_overridden = self.state_provider.has_override('status') 220 status_field = field(parent=state_cont, checked=is_status_overridden, callback=self._on_status_override) 221 if is_status_overridden: 222 status_cont = LayoutGrid(parent=status_field, align=uiconst.TOTOP, columns=2) 223 eveLabel.EveLabelMedium(parent=status_cont, align=uiconst.CENTER, text='The ESS is') 224 Combo(parent=status_cont, align=uiconst.CENTER, left=4, options=map(lambda s: (s.name, s), iter(EssStatus)), callback=self._on_status, select=self.ess_state.status) 225 else: 226 eveLabel.EveLabelMedium(parent=status_field, align=uiconst.TOTOP, text='The ESS is {}'.format(eveformat.bold(eveformat.color(self.ess_state.status.name, value_color)))) 227 is_range_overridden = self.state_provider.has_override('in_range') 228 range_field = field(parent=state_cont, checked=is_range_overridden, callback=self._on_range_override) 229 if not is_range_overridden: 230 eveLabel.EveLabelMedium(parent=range_field, align=uiconst.TOTOP, text='You are {}'.format(eveformat.bold(eveformat.color('in range' if self.ess_state.in_range else 'out of range', value_color)))) 231 else: 232 range_cont = LayoutGrid(parent=range_field, align=uiconst.TOTOP, columns=2) 233 eveLabel.EveLabelMedium(parent=range_cont, align=uiconst.CENTER, text='You are') 234 Combo(parent=range_cont, align=uiconst.CENTER, left=4, options=[('in range', True), ('out of range', False)], callback=self._on_range, select=self.ess_state.in_range) 235 eveLabel.EveCaptionSmall(parent=state_cont, align=uiconst.TOTOP, text='MAIN BANK', padding=(left_pad, 236 16, 237 0, 238 0)) 239 eveLabel.EveLabelMedium(parent=state_cont, align=uiconst.TOTOP, text='The balance is {}'.format(eveformat.color(eveformat.isk(self.ess_state.main_bank.balance), value_color)), padding=(left_pad, 240 4, 241 0, 242 16)) 243 is_link_overridden = self.state_provider.has_override('main_bank.link') 244 link_field = field(parent=state_cont, checked=is_link_overridden, callback=self._on_link_override) 245 if not self.ess_state.main_bank.link: 246 eveLabel.EveLabelMedium(parent=link_field, align=uiconst.TOTOP, text='No one is currently hacking') 247 else: 248 eveLabel.EveLabelMedium(parent=ContainerAutoSize(parent=link_field, align=uiconst.TOTOP), align=uiconst.TOPLEFT, state=uiconst.UI_NORMAL, text='{} is hacking'.format(eveformat.color(evelink.character_link(self.ess_state.main_bank.link.character_id), value_color))) 249 timer_label = eveLabel.EveLabelMedium(parent=ContainerAutoSize(parent=link_field, align=uiconst.TOTOP, padding=(0, 4, 0, 4)), align=uiconst.TOTOP) 250 251 def update_time(label, state): 252 link = state.main_bank.link 253 while not label.destroyed: 254 remaining = link.end - gametime.now_sim() 255 if remaining.total_seconds() > 0: 256 text = '{} remaining'.format(eveformat.color(format_delta_time(remaining), value_color)) 257 else: 258 text = 'Completion pending ...' 259 label.SetText(text) 260 eveui.wait_for_next_frame() 261 262 uthread2.start_tasklet(update_time, timer_label, self.ess_state) 263 if is_link_overridden: 264 button_cont = FlowContainer(parent=ContainerAutoSize(parent=link_field, align=uiconst.TOTOP, padTop=4), align=uiconst.TOTOP, contentSpacing=(4, 4)) 265 Button(parent=button_cont, align=uiconst.NOALIGN, label='UNLINK', minHeight=32, sidePadding=16, func=self._fail_hack, args=()) 266 Button(parent=button_cont, align=uiconst.NOALIGN, label='COMPLETE', minHeight=32, sidePadding=16, func=self._succeed_hack, args=()) 267 Button(parent=button_cont, align=uiconst.NOALIGN, label='+1m', minHeight=32, sidePadding=16, func=self._advance_hack, args=(datetime.timedelta(minutes=1),)) 268 Button(parent=button_cont, align=uiconst.NOALIGN, label='-1m', minHeight=32, sidePadding=16, func=self._advance_hack, args=(datetime.timedelta(minutes=-1),)) 269 if not self.ess_state.main_bank.link and self.ess_state.main_bank.link_result: 270 link_result = self.ess_state.main_bank.link_result 271 character = evelink.character_link(link_result.character_id) 272 if link_result.successful: 273 text = '{} completed a hack'.format(character) 274 else: 275 text = '{} disconnected'.format(character) 276 eveLabel.EveLabelMedium(parent=link_field, align=uiconst.TOTOP, state=uiconst.UI_NORMAL, padding=(0, 4, 0, 4), text=text) 277 if is_link_overridden and not self.ess_state.main_bank.link: 278 button_cont = FlowContainer(parent=ContainerAutoSize(parent=link_field, align=uiconst.TOTOP, padTop=4), align=uiconst.TOTOP, contentSpacing=(4, 4)) 279 Button(parent=button_cont, align=uiconst.NOALIGN, label='LINK', func=self._fake_hack, args=()) 280 Button(parent=button_cont, align=uiconst.NOALIGN, label='LINK (10s)', func=self._fake_hack, args=datetime.timedelta(seconds=10)) 281 eveLabel.EveCaptionSmall(parent=state_cont, align=uiconst.TOTOP, text='Reserve bank', padding=(left_pad, 282 16, 283 0, 284 0)) 285 eveLabel.EveLabelMedium(parent=state_cont, align=uiconst.TOTOP, text='The balance is {}'.format(eveformat.color(eveformat.isk(self.ess_state.reserve_bank.balance), value_color)), padding=(left_pad, 286 4, 287 0, 288 4)) 289 lock_field = field(parent=state_cont, checked=self._is_reserve_bank_lock_overridden, callback=self._on_reserve_bank_lock_override) 290 if self.ess_state.reserve_bank.locked: 291 eveLabel.EveLabelMedium(parent=lock_field, align=uiconst.TOTOP, text='The bank is {}'.format(eveformat.color('LOCKED', value_color))) 292 if self._is_reserve_bank_lock_overridden: 293 button_cont = FlowContainer(parent=ContainerAutoSize(parent=lock_field, align=uiconst.TOTOP, padTop=4), align=uiconst.TOTOP, contentSpacing=(4, 4)) 294 Button(parent=button_cont, align=uiconst.NOALIGN, label='UNLOCK (15m)', func=self._unlock_reserve_bank, args=(15,)) 295 Button(parent=button_cont, align=uiconst.NOALIGN, label='UNLOCK (45m)', func=self._unlock_reserve_bank, args=(45,)) 296 else: 297 eveLabel.EveLabelMedium(parent=lock_field, align=uiconst.TOTOP, text='{} of {} pulses remaining'.format(eveformat.color(self.ess_state.reserve_bank.pulses_remaining, value_color), eveformat.color(self.ess_state.reserve_bank.pulses_total, value_color))) 298 last_pulse_start_label = eveLabel.EveLabelMedium(parent=lock_field, align=uiconst.TOTOP) 299 300 def update_last_pulse_start_label(): 301 while not last_pulse_start_label.destroyed: 302 last_pulse_start_label.text = 'Pulse started {} ago'.format(eveformat.color(format_delta_time(gametime.now_sim() - self.ess_state.reserve_bank.last_pulse_start), value_color)) 303 eveui.wait_for_next_frame() 304 305 uthread2.start_tasklet(update_last_pulse_start_label) 306 if self._is_reserve_bank_lock_overridden: 307 grid = LayoutGrid(parent=lock_field, align=uiconst.TOTOP, top=4, columns=4, cellSpacing=4) 308 decrease_button = Button(parent=grid, fixedwidth=18, label='-', func=self._remove_reserve_bank_link, args=()) 309 link_count = self.ess_state.reserve_bank.link_count 310 linked = self.ess_state.reserve_bank.linked 311 if link_count == 0 or link_count == 1 and linked: 312 decrease_button.Disable() 313 eveLabel.EveLabelMedium(parent=grid, text=eveformat.color(self.ess_state.reserve_bank.link_count, value_color)) 314 Button(parent=grid, fixedwidth=18, label='+', func=self._add_reserve_bank_link, args=()) 315 eveLabel.EveLabelMedium(parent=grid, text='active links') 316 else: 317 eveLabel.EveLabelMedium(parent=lock_field, align=uiconst.TOTOP, text='{} active links'.format(eveformat.color(self.ess_state.reserve_bank.link_count, value_color))) 318 eveLabel.EveLabelMedium(parent=lock_field, align=uiconst.TOTOP, top=4, text='You are {}'.format(eveformat.color('linked' if self.ess_state.reserve_bank.linked else 'not linked', value_color))) 319 if self._is_reserve_bank_lock_overridden: 320 button_cont = FlowContainer(parent=ContainerAutoSize(parent=lock_field, align=uiconst.TOTOP, padTop=8), align=uiconst.TOTOP, contentSpacing=(4, 4)) 321 if self.ess_state.reserve_bank.linked: 322 Button(parent=button_cont, align=uiconst.NOALIGN, label='UNLINK', func=self._unlink_from_reserve_bank, args=()) 323 else: 324 Button(parent=button_cont, align=uiconst.NOALIGN, label='LINK', func=self._link_to_reserve_bank, args=()) 325 if self.ess_state.reserve_bank.pulses_remaining > 0: 326 Button(parent=button_cont, align=uiconst.NOALIGN, label='PULSE', func=self._pulse_reserve_bank, args=()) 327 Button(parent=button_cont, align=uiconst.NOALIGN, label='FINISH', func=self._lock_reserve_bank, args=()) 328 329 def _on_status_override(self, checkbox): 330 override = bool(checkbox.GetValue()) 331 if override: 332 self.state_provider.set_override('status', self.ess_state.status) 333 else: 334 self.state_provider.clear_override('status') 335 336 def _on_status(self, combo, key, value): 337 self.state_provider.set_override('status', value) 338 339 def _on_range_override(self, checkbox): 340 override = bool(checkbox.GetValue()) 341 if override: 342 self.state_provider.set_override('in_range', self.ess_state.in_range) 343 else: 344 self.state_provider.clear_override('in_range') 345 346 def _on_range(self, combo, key, value): 347 self.state_provider.set_override('in_range', value) 348 349 def _on_link_override(self, checkbox): 350 override = bool(checkbox.GetValue()) 351 if override: 352 with self.state_provider.atomic_override(): 353 self.state_provider.set_override('main_bank.link', self.ess_state.main_bank.link) 354 self.state_provider.set_override('main_bank.link_result', self.ess_state.main_bank.link_result) 355 else: 356 with self.state_provider.atomic_override(): 357 self.state_provider.clear_override('main_bank.link') 358 self.state_provider.clear_override('main_bank.link_result') 359 360 def _fake_hack(self, duration = None): 361 if duration is None: 362 duration = datetime.timedelta(minutes=6) 363 start = gametime.now_sim() 364 end = start + duration 365 self.state_provider.set_override('main_bank.link', MainBankLink(uuid.uuid4(), session.charid, start, end)) 366 367 def _fail_hack(self): 368 self._finish_hack(successful=False) 369 370 def _succeed_hack(self): 371 self._finish_hack(successful=True) 372 373 def _finish_hack(self, successful): 374 if self.ess_state.main_bank.link is None: 375 return 376 link = self.ess_state.main_bank.link 377 with self.state_provider.atomic_override(): 378 self.state_provider.set_override('main_bank.link', None) 379 self.state_provider.set_override('main_bank.link_result', MainBankLinkResult(link_id=self.ess_state.main_bank.link.link_id, character_id=link.character_id, successful=successful)) 380 381 def _advance_hack(self, delta): 382 if self.ess_state.main_bank.link is None: 383 return 384 link = self.ess_state.main_bank.link 385 self.state_provider.set_override('main_bank.link', link.evolve(start=link.start - delta, end=link.end - delta)) 386 387 def _on_reserve_bank_lock_override(self, checkbox): 388 override = bool(checkbox.GetValue()) 389 if override: 390 self._is_reserve_bank_lock_overridden = True 391 with self.state_provider.atomic_override(): 392 self.state_provider.set_override('reserve_bank.pulses_total', self.state_provider.state.reserve_bank.pulses_total) 393 self.state_provider.set_override('reserve_bank.pulses_remaining', self.state_provider.state.reserve_bank.pulses_remaining) 394 self.state_provider.set_override('reserve_bank.link_count', self.state_provider.state.reserve_bank.link_count) 395 self.state_provider.set_override('reserve_bank.last_pulse_start', self.state_provider.state.reserve_bank.last_pulse_start) 396 self.state_provider.set_override('reserve_bank.linked', False) 397 else: 398 self._is_reserve_bank_lock_overridden = False 399 with self.state_provider.atomic_override(): 400 self.state_provider.clear_override('reserve_bank.pulses_total') 401 self.state_provider.clear_override('reserve_bank.pulses_remaining') 402 self.state_provider.clear_override('reserve_bank.link_count') 403 self.state_provider.clear_override('reserve_bank.last_pulse_start') 404 self.state_provider.clear_override('reserve_bank.linked') 405 406 def _unlock_reserve_bank(self, pulses): 407 with self.state_provider.atomic_override(): 408 self.state_provider.set_override('reserve_bank.pulses_total', pulses) 409 self.state_provider.set_override('reserve_bank.pulses_remaining', pulses) 410 self.state_provider.set_override('reserve_bank.link_count', 0) 411 self.state_provider.set_override('reserve_bank.last_pulse_start', gametime.now_sim()) 412 413 def _lock_reserve_bank(self): 414 with self.state_provider.atomic_override(): 415 self.state_provider.set_override('reserve_bank.pulses_total', 0) 416 self.state_provider.set_override('reserve_bank.pulses_remaining', 0) 417 self.state_provider.set_override('reserve_bank.link_count', 0) 418 self.state_provider.set_override('reserve_bank.last_pulse_start', None) 419 self.state_provider.set_override('reserve_bank.linked', False) 420 421 def _pulse_reserve_bank(self): 422 with self.state_provider.atomic_override(): 423 self.state_provider.set_override('reserve_bank.pulses_remaining', self.state_provider.state.reserve_bank.pulses_remaining - 1) 424 self.state_provider.set_override('reserve_bank.last_pulse_start', gametime.now_sim()) 425 426 def _add_reserve_bank_link(self): 427 self.state_provider.set_override('reserve_bank.link_count', self.state_provider.state.reserve_bank.link_count + 1) 428 429 def _remove_reserve_bank_link(self): 430 self.state_provider.set_override('reserve_bank.link_count', self.state_provider.state.reserve_bank.link_count - 1) 431 432 def _link_to_reserve_bank(self): 433 with self.state_provider.atomic_override(): 434 self._add_reserve_bank_link() 435 self.state_provider.set_override('reserve_bank.linked', True) 436 437 def _unlink_from_reserve_bank(self): 438 with self.state_provider.atomic_override(): 439 self._remove_reserve_bank_link() 440 self.state_provider.set_override('reserve_bank.linked', False) 441 442 443 def format_delta_time(delta_time): 444 return localization.formatters.FormatTimeIntervalShortWritten(datetimeutils.timedelta_to_filetime_delta(delta_time), showFrom='hour', showTo='second') 445 446 447 def __reload_update__(old_namespace): 448 window = EssDebugWindow.GetIfOpen() 449 if window: 450 window.Close() 451 EssDebugWindow.Open()