class ShadowBurner(Task): game = attr.ib(type=Game) food_key = attr.ib(type=pynput.keyboard.Key, kw_only=True) mana_burn_key = attr.ib(type=pynput.keyboard.Key, kw_only=True) delay = attr.ib(init=False, kw_only=True, type=float, default=1.0) hwnd = attr.ib(init=False, kw_only=False) def _run(self): if not self._connect(): return self.thread = StoppableThread(target=self._burn, args=(), daemon=True) self.thread.start() WindowsInhibitor.inhibit() def _connect(self) -> bool: try: self.hwnd = win32gui.FindWindow(None, self.game.name) print(f'ShadowBurner connected with {self.game.name} {self.hwnd}') return True except RuntimeError as e: print(f'Unable to connect ShadowBurner to {self.game.name}. Reason: {e}') return False def _burn(self): while not self.thread.stopped(): self._press_and_release(self.food_key) self._press_and_release(self.mana_burn_key) time.sleep(self.delay) def _press_and_release(self, key: pynput.keyboard.Key): k = FUNCTION_KEYS.get(key.name) if isinstance(key, pynput.keyboard.Key) else ord(key) win32api.PostMessage(self.hwnd, win32con.WM_KEYDOWN, k, 0)
class StateManagerTask(Task, StateManager[T], Generic[T]): game = attr.ib() delay = attr.ib(type=float, default=0.1, kw_only=True) def _run(self): self.thread = StoppableThread(target=self.executor, args=(), daemon=True) self.thread.start() def executor(self): while not self.thread.stopped(): start = int(time.time_ns()) if self.game.is_active(): self.update(self.new_value()) # if self.delay: # time.sleep(self.delay) end_ = int((time.time_ns()) - start) / 1_000_000 print( f"Total state execution time of {self.__class__.__name__}: {end_ if end_ > 0 else 0} ms" ) else: time.sleep(0.5) def new_value(self) -> T: raise NotImplementedError()
class Caster(Task): game = attr.ib(type=Game) psm = attr.ib(type=PlayerStateManager) cast_list = attr.ib(type=List[Cast]) priority = attr.ib(type=int, default=-100, kw_only=True) delay = attr.ib(type=float, default=0.4, kw_only=True) def __attrs_post_init__(self): self.cast_list = sorted(self.cast_list, key=lambda c: (c.priority, c.min_health, c.min_mana)) def _run(self): self.thread = StoppableThread(target=self._cast, args=(), daemon=True) self.thread.start() def _cast(self): while not self.thread.stopped(): player: Player = self.psm.get().value if not self.game.is_active() or not player: time.sleep(self.delay) continue for cast in self.cast_list: if not cast.should_cast(player): continue self.keyboard.press(cast.key) self.keyboard.release(cast.key) if cast.cooldown: time.sleep(cast.cooldown) break
class ExchangeTask(Task): game = attr.ib(type=Game) psm = attr.ib(type=PlayerStateManager) wsm = attr.ib(type=WindowStateManagerTask) app = attr.ib(kw_only=True, type=Application, factory=Application) exchange_img = attr.ib(kw_only=True, type=str, default=GP_IMAGE) exchange_img_center = attr.ib(init=False, type=Position) delay = attr.ib(kw_only=True, type=float, default=0.5) _is_connected = attr.ib(init=False, type=bool, default=False) def __attrs_post_init__(self): self.exchange_img_center = image_center(self.exchange_img) def _run(self): self.thread = StoppableThread(target=self._exchange, args=(), daemon=True) self.thread.start() def _connect(self) -> bool: if self._is_connected or not self.game.is_active(): return False self.app.connect(title=self.game.name) self._is_connected = True print('exchange application connected') return True def _exchange(self): while not self.thread.stopped(): state = self.wsm.get() if not self.game.is_active() or state.is_empty(): time.sleep(1) continue if not self._is_connected: self._connect() time.sleep(1) continue player_state = self.psm.get() if player_state.is_empty() or not player_state.value.is_healthy(): time.sleep(1) continue cash = locate_image(state, self.exchange_img, precision=0.9) if cash is not Position.empty(): pos_to_click = cash.add(self.exchange_img_center).minus(MARGIN) self.app.window().click(button='right', coords=pos_to_click.tuple()) time.sleep(self.delay) print("Cash exchanged!")
class FoodEaterTask(Task): game = attr.ib(type=Game) key = attr.ib(type=pynput.keyboard.Key, kw_only=True) delay = attr.ib(init=False, kw_only=True, type=float, default=30) def _run(self): self.thread = StoppableThread(target=self._eat_food, args=(), daemon=True) self.thread.start() def _eat_food(self): while not self.thread.stopped(): if self.game.is_active(): self.keyboard.press(self.key) self.keyboard.release(self.key) time.sleep(self.delay) time.sleep(0.5)
class MagicTrainingTask(Task): game = attr.ib(type=Game) psm = attr.ib(type=PlayerStateManager) key = attr.ib(type=pynput.keyboard.Key, kw_only=True) min_mana = attr.ib(kw_only=True, type=int) min_health = attr.ib(kw_only=True, type=int, default=100) delay = attr.ib(init=False, kw_only=True, type=float, default=1) def _run(self): self.thread = StoppableThread(target=self._train, args=(), daemon=True) self.thread.start() def _train(self): while not self.thread.stopped(): player = self.psm.get().value if self.game.is_active( ) and player and player.mana >= self.min_mana and player.health >= self.min_health: self.keyboard.press(self.key) self.keyboard.release(self.key) if self.delay: time.sleep(self.delay) else: time.sleep(0.5)