state.py (10583B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\dynamicresources\client\ess\state.py 2 import datetime 3 from collections import OrderedDict 4 import codereload 5 import enum 6 import gametime 7 import immutable 8 import signals 9 import weakness 10 UNCHANGED = object() 11 12 class EssStateProvider(object): 13 14 def __init__(self, state, on_fetch_request = None): 15 self._next_token_id = 1 16 self._state = state 17 self._subscribers = OrderedDict() 18 self._need_fetch = False 19 self.on_fetch_request = signals.Signal() 20 if on_fetch_request is not None: 21 self.on_fetch_request.connect(on_fetch_request) 22 23 @property 24 def state(self): 25 self._signal_fetch_if_needed() 26 return self._state 27 28 @state.setter 29 def state(self, state): 30 if state != self.state: 31 old_state = self.state 32 self._state = state 33 self.notify_subscribers(old_state, state) 34 35 @property 36 def has_subscribers(self): 37 return len(self._subscribers) > 0 38 39 def mark_need_fetch(self): 40 self._need_fetch = True 41 42 def notify_subscribers(self, old_state, new_state): 43 subscribers = self._subscribers 44 self._subscribers = OrderedDict() 45 for token, (callback, lens) in subscribers.items(): 46 new_lens_state = lens(new_state) 47 if lens(old_state) != new_lens_state: 48 try: 49 callback(new_lens_state) 50 except ReferenceError: 51 pass 52 53 else: 54 self._subscribers[token] = (callback, lens) 55 56 def evolve(self, **kwargs): 57 self.state = self.state.evolve(**kwargs) 58 59 def read(self): 60 return self.state 61 62 def watch(self, callback): 63 return (self.state, self.subscribe(callback)) 64 65 def select(self, callback, lens): 66 return (lens(self.state), self.subscribe(callback, lens)) 67 68 def subscribe(self, callback, lens = None): 69 if lens is None: 70 lens = lambda s: s 71 token_id = self._get_next_token_id() 72 self._subscribers[token_id] = (weakness.callable_proxy(callback), lens) 73 self._signal_fetch_if_needed() 74 return SubscriptionToken(self, token_id) 75 76 def unsubscribe(self, token): 77 if isinstance(token, SubscriptionToken): 78 token = token.id 79 try: 80 del self._subscribers[token] 81 except (IndexError, KeyError): 82 pass 83 84 def _signal_fetch_if_needed(self): 85 if self._need_fetch: 86 self._need_fetch = False 87 self.on_fetch_request() 88 89 def _get_next_token_id(self): 90 token_id = self._next_token_id 91 self._next_token_id += 1 92 return token_id 93 94 95 class SubscriptionToken(object): 96 97 def __init__(self, provider, token_id): 98 self.provider = provider 99 self.id = token_id 100 101 def __del__(self): 102 self.unsubscribe() 103 104 def unsubscribe(self): 105 self.provider.unsubscribe(self.id) 106 107 108 @codereload.reloadable_enum 109 110 class EssStatus(enum.Enum): 111 offline = 1 112 loading = 2 113 online = 3 114 115 116 class EssState(object): 117 __metaclass__ = immutable.Immutable 118 119 def __init__(self, status, ess_item_id, in_range, main_bank, reserve_bank): 120 self.status = status 121 self.ess_item_id = ess_item_id 122 self.in_range = in_range 123 self.main_bank = main_bank 124 self.reserve_bank = reserve_bank 125 126 @property 127 def online(self): 128 return self.status == EssStatus.online 129 130 @property 131 def offline(self): 132 return self.status == EssStatus.offline 133 134 @property 135 def loading(self): 136 return self.status == EssStatus.loading 137 138 @property 139 def out_of_range(self): 140 return not self.in_range 141 142 def evolve(self, status = UNCHANGED, ess_item_id = UNCHANGED, in_range = UNCHANGED, main_bank = UNCHANGED, reserve_bank = UNCHANGED): 143 return EssState(status=changed(status, self.status), ess_item_id=changed(ess_item_id, self.ess_item_id), in_range=changed(in_range, self.in_range), main_bank=changed(main_bank, self.main_bank), reserve_bank=changed(reserve_bank, self.reserve_bank)) 144 145 def __eq__(self, other): 146 return self is other or isinstance(other, EssState) and self.status == other.status and self.ess_item_id == other.ess_item_id and self.in_range == other.in_range and self.main_bank == other.main_bank and self.reserve_bank == other.reserve_bank 147 148 def __ne__(self, other): 149 return not self.__eq__(other) 150 151 def __hash__(self): 152 return hash((self.status, 153 self.ess_item_id, 154 self.in_range, 155 self.main_bank, 156 self.reserve_bank)) 157 158 def __repr__(self): 159 return u'EssState(status={!r}, ess_item_id={!r}, in_range={!r}, main_bank={!r}, reserve_bank={!r})'.format(self.status, self.ess_item_id, self.in_range, self.main_bank, self.reserve_bank) 160 161 162 class MainBankState(object): 163 __metaclass__ = immutable.Immutable 164 165 def __init__(self, balance, link, link_result): 166 self.balance = balance 167 self.link = link 168 self.link_result = link_result 169 170 def is_hacking(self, character_id): 171 return self.link is not None and self.link.character_id == character_id 172 173 def evolve(self, balance = UNCHANGED, link = UNCHANGED, link_result = UNCHANGED): 174 return MainBankState(balance=changed(balance, self.balance), link=changed(link, self.link), link_result=changed(link_result, self.link_result)) 175 176 def __eq__(self, other): 177 return self is other or isinstance(other, MainBankState) and self.balance == other.balance and self.link == other.link and self.link_result == other.link_result 178 179 def __ne__(self, other): 180 return not self.__eq__(other) 181 182 def __hash__(self): 183 return hash((self.balance, self.link, self.link_result)) 184 185 def __repr__(self): 186 return u'MainBankState(balance={!r}, link={!r}, link_result={!r})'.format(self.balance, self.link, self.link_result) 187 188 189 class MainBankLink(object): 190 __metaclass__ = immutable.Immutable 191 192 def __init__(self, link_id, character_id, start, end): 193 self.link_id = link_id 194 self.character_id = character_id 195 self.start = start 196 self.end = end 197 198 @property 199 def remaining(self): 200 remaining = self.end - gametime.now_sim() 201 if remaining.total_seconds() < 0.0: 202 return datetime.timedelta() 203 return remaining 204 205 @property 206 def duration(self): 207 return self.end - self.start 208 209 def evolve(self, link_id = UNCHANGED, character_id = UNCHANGED, start = UNCHANGED, end = UNCHANGED): 210 return MainBankLink(link_id=changed(link_id, self.link_id), character_id=changed(character_id, self.character_id), start=changed(start, self.start), end=changed(end, self.end)) 211 212 def __eq__(self, other): 213 return self is other or isinstance(other, MainBankLink) and self.link_id == other.link_id and self.character_id == other.character_id and self.start == other.start and self.end == other.end 214 215 def __ne__(self, other): 216 return not self.__eq__(other) 217 218 def __hash__(self): 219 return hash((self.link_id, 220 self.character_id, 221 self.start, 222 self.end)) 223 224 def __repr__(self): 225 return u'MainBankLink(link_id={!r}, character_id={!r}, start={!r}, end={!r})'.format(self.link_id, self.character_id, self.start, self.end) 226 227 228 class MainBankLinkResult(object): 229 __metaclass__ = immutable.Immutable 230 231 def __init__(self, link_id, character_id, successful): 232 self.link_id = link_id 233 self.character_id = character_id 234 self.successful = successful 235 236 def evolve(self, link_id = UNCHANGED, character_id = UNCHANGED, successful = UNCHANGED): 237 return MainBankLinkResult(link_id=changed(link_id, self.link_id), character_id=changed(character_id, self.character_id), successful=changed(successful, self.successful)) 238 239 def __eq__(self, other): 240 return self is other or isinstance(other, MainBankLinkResult) and self.link_id == other.link_id and self.character_id == other.character_id and self.successful == other.successful 241 242 def __ne__(self, other): 243 return not self.__eq__(other) 244 245 def __hash__(self): 246 return hash((self.link_id, self.character_id, self.successful)) 247 248 def __repr__(self): 249 return u'MainBankLinkResult(link_id={!r}, character_id={!r}, successful={!r})'.format(self.link_id, self.character_id, self.successful) 250 251 252 class ReserveBankState(object): 253 __metaclass__ = immutable.Immutable 254 255 def __init__(self, balance, pulses_total, pulses_remaining, last_pulse_start, link_count, linked): 256 self.balance = balance 257 self.pulses_total = pulses_total 258 self.pulses_remaining = pulses_remaining 259 self.last_pulse_start = last_pulse_start 260 self.link_count = link_count 261 self.linked = linked 262 263 @property 264 def locked(self): 265 return self.pulses_remaining == 0 266 267 @property 268 def unlocked(self): 269 return self.pulses_remaining > 0 270 271 def evolve(self, balance = UNCHANGED, pulses_total = UNCHANGED, pulses_remaining = UNCHANGED, last_pulse_start = UNCHANGED, link_count = UNCHANGED, linked = UNCHANGED): 272 return ReserveBankState(balance=changed(balance, self.balance), pulses_total=changed(pulses_total, self.pulses_total), pulses_remaining=changed(pulses_remaining, self.pulses_remaining), last_pulse_start=changed(last_pulse_start, self.last_pulse_start), link_count=changed(link_count, self.link_count), linked=changed(linked, self.linked)) 273 274 def __eq__(self, other): 275 return self is other or isinstance(other, ReserveBankState) and self.balance == other.balance and self.pulses_total == other.pulses_total and self.pulses_remaining == other.pulses_remaining and self.last_pulse_start == other.last_pulse_start and self.link_count == other.link_count and self.linked == other.linked 276 277 def __ne__(self, other): 278 return not self.__eq__(other) 279 280 def __hash__(self): 281 return hash((self.balance, 282 self.pulses_total, 283 self.pulses_remaining, 284 self.last_pulse_start, 285 self.link_count, 286 self.linked)) 287 288 def __repr__(self): 289 return u'ReserveBankState(balance={!r}, pulses_total={!r}, pulses_remaining={!r}, last_pulse_start={!r}, link_count={!r}, linked={!r})'.format(self.balance, self.pulses_total, self.pulses_remaining, self.last_pulse_start, self.link_count, self.linked) 290 291 292 def changed(value, default): 293 if value is not UNCHANGED: 294 return value 295 return default