trainerbase 4.0.0__tar.gz → 4.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {trainerbase-4.0.0 → trainerbase-4.0.2}/PKG-INFO +1 -1
  2. {trainerbase-4.0.0 → trainerbase-4.0.2}/pyproject.toml +1 -1
  3. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/tapper.py +2 -0
  4. trainerbase-4.0.2/trainerbase/config.py +15 -0
  5. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/tapper.py +5 -2
  6. trainerbase-4.0.2/trainerbase/logger.py +40 -0
  7. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/main.py +20 -1
  8. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/memory.py +13 -1
  9. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/process.py +5 -2
  10. trainerbase-4.0.2/trainerbase/tts.py +45 -0
  11. trainerbase-4.0.0/trainerbase/config.py +0 -10
  12. trainerbase-4.0.0/trainerbase/tts.py +0 -30
  13. {trainerbase-4.0.0 → trainerbase-4.0.2}/LICENSE +0 -0
  14. {trainerbase-4.0.0 → trainerbase-4.0.2}/README.md +0 -0
  15. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/__init__.py +0 -0
  16. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/abc.py +0 -0
  17. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/codeinjection.py +0 -0
  18. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/__init__.py +0 -0
  19. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/abc.py +0 -0
  20. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/helpers.py +0 -0
  21. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/keyboard.py +0 -0
  22. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/rainbow.py +0 -0
  23. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/teleport.py +0 -0
  24. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gameobject.py +0 -0
  25. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/__init__.py +0 -0
  26. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/helpers.py +0 -0
  27. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/injections.py +0 -0
  28. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/misc.py +0 -0
  29. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/objects.py +0 -0
  30. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/rainbow.py +0 -0
  31. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/scripts.py +0 -0
  32. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/speedhack.py +0 -0
  33. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/teleport.py +0 -0
  34. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/types.py +0 -0
  35. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/scriptengine.py +0 -0
  36. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/speedhack.py +0 -0
  37. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase_vendor/FASM.EXE +0 -0
  38. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase_vendor/speedhack32.dll +0 -0
  39. {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase_vendor/speedhack64.dll +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: trainerbase
3
- Version: 4.0.0
3
+ Version: 4.0.2
4
4
  Summary: Framework for creating game trainers/mods
5
5
  Home-page: https://gitlab.com/python-trainers/trainer-base
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "trainerbase"
3
- version = "4.0.0"
3
+ version = "4.0.2"
4
4
  description = "Framework for creating game trainers/mods"
5
5
  authors = ["v01d <v01d@v01d.ru>", "doomayka <zd@doomayka.ru>"]
6
6
  license = "MIT"
@@ -28,6 +28,8 @@ class TappingDevice(StrEnum):
28
28
  class Tapper(Switchable):
29
29
  def __init__(self, default_delay: float, tap_button: str = "left", device: TappingDevice = TappingDevice.MOUSE):
30
30
  self._delay = default_delay
31
+ self.button = tap_button
32
+ self.device = device
31
33
  self.tapper_script_engine: ScriptEngine | None = None
32
34
  self.tapper_function = partial(device.function, tap_button)
33
35
 
@@ -0,0 +1,15 @@
1
+ from pathlib import Path
2
+ from typing import Final
3
+
4
+ from tomllib import load as load_toml
5
+
6
+
7
+ CONFIG_FILE: Final[Path] = Path("./trainerbase.toml")
8
+
9
+
10
+ with CONFIG_FILE.resolve().open("rb") as trainerbase_toml:
11
+ trainerbase_config = load_toml(trainerbase_toml)
12
+
13
+
14
+ pymem_config = trainerbase_config["pymem"]
15
+ logging_config = trainerbase_config.get("logging")
@@ -5,7 +5,7 @@ from dearpygui import dearpygui as dpg
5
5
  from trainerbase.common.keyboard import ReleaseHotkeySwitch
6
6
  from trainerbase.common.tapper import Tapper
7
7
  from trainerbase.gui.helpers import add_components
8
- from trainerbase.gui.misc import HotkeyHandlerUI
8
+ from trainerbase.gui.misc import HotkeyHandlerUI, TextUI
9
9
  from trainerbase.gui.types import AbstractUIComponent
10
10
 
11
11
 
@@ -32,7 +32,10 @@ class TapperUI(AbstractUIComponent):
32
32
 
33
33
  @override
34
34
  def add_to_ui(self) -> None:
35
- add_components(HotkeyHandlerUI(ReleaseHotkeySwitch(self.tapper, self.key), "Tapper"))
35
+ add_components(
36
+ TextUI(f"Tapper for {self.tapper.device} {self.tapper.button}"),
37
+ HotkeyHandlerUI(ReleaseHotkeySwitch(self.tapper, self.key), "Tapper"),
38
+ )
36
39
 
37
40
  dpg.add_input_double(
38
41
  tag=self.DPG_TAG_TAPPER_DELAY_INPUT,
@@ -0,0 +1,40 @@
1
+ from logging import ERROR, getLogger
2
+ from logging.config import dictConfig
3
+
4
+ from trainerbase.config import CONFIG_FILE, logging_config
5
+
6
+
7
+ if logging_config is None:
8
+ logging_config = {
9
+ "version": 1,
10
+ "disable_existing_loggers": True,
11
+ "formatters": {
12
+ "default": {
13
+ "format": "[%(asctime)s] <%(levelname)s> %(funcName)s: %(message)s",
14
+ "datefmt": "%Y-%m-%d %H:%M:%S",
15
+ }
16
+ },
17
+ "handlers": {
18
+ "console": {
19
+ "formatter": "default",
20
+ "class": "logging.StreamHandler",
21
+ "stream": "ext://sys.stdout",
22
+ }
23
+ },
24
+ "root": {
25
+ "level": "INFO",
26
+ "handlers": ["console"],
27
+ },
28
+ }
29
+ display_no_logger_config_warning = True
30
+ else:
31
+ display_no_logger_config_warning = False
32
+
33
+
34
+ dictConfig(logging_config)
35
+ getLogger("comtypes").setLevel(ERROR)
36
+
37
+ logger = getLogger("TrainerBase")
38
+
39
+ if display_no_logger_config_warning:
40
+ logger.warning(f"No logging config in {CONFIG_FILE}! Use updated trainer template.")
@@ -7,6 +7,7 @@ from trainerbase.codeinjection import safely_eject_all_code_injections
7
7
  from trainerbase.common.rainbow import gradient_updater
8
8
  from trainerbase.gameobject import update_frozen_objects
9
9
  from trainerbase.gui.objects import update_displayed_objects
10
+ from trainerbase.logger import logger
10
11
  from trainerbase.process import shutdown_if_process_exited
11
12
  from trainerbase.scriptengine import (
12
13
  enabled_by_default,
@@ -15,6 +16,7 @@ from trainerbase.scriptengine import (
15
16
  system_script_engine,
16
17
  )
17
18
  from trainerbase.speedhack import SpeedHack
19
+ from trainerbase.tts import tts_manager
18
20
 
19
21
 
20
22
  type Callback = Callable[[], None]
@@ -26,34 +28,51 @@ def run( # pylint: disable=too-complex
26
28
  on_shutdown_hook: Callback | None = None,
27
29
  ) -> NoReturn:
28
30
  def on_shutdown() -> NoReturn:
31
+ logger.debug("Shutting down. Stopping Script Engines.")
32
+
29
33
  rainbow_script_engine.stop()
30
34
  system_script_engine.stop()
31
35
  process_healthcheck_script_engine.stop()
32
36
 
37
+ logger.debug("Ejecting Code Injections.")
38
+
33
39
  safely_eject_all_code_injections()
40
+
41
+ logger.debug("Disabling SpeedHack")
42
+
34
43
  SpeedHack.disable()
35
44
 
36
45
  if on_shutdown_hook is not None:
46
+ logger.debug("on_shutdown_hook provided. Calling.")
37
47
  on_shutdown_hook()
38
48
 
39
49
  force_exit(0)
40
50
 
41
51
  def on_gui_initialized() -> None:
52
+ logger.debug("GUI has been initialized. Starting Script Engines.")
53
+
42
54
  system_script_engine.start()
43
55
  process_healthcheck_script_engine.start()
44
56
  rainbow_script_engine.start()
45
57
 
46
58
  if on_gui_initialized_hook is not None:
59
+ logger.debug("on_gui_initialized_hook provided. Calling.")
60
+
47
61
  try:
48
62
  on_gui_initialized_hook()
49
63
  except Exception:
64
+ logger.error("Exception occurred while calling on_gui_initialized_hook. See stderr.")
50
65
  print_exc()
51
66
  on_shutdown()
52
67
 
68
+ logger.debug("Registering core scripts")
53
69
  system_script_engine.simple_script(update_frozen_objects, enabled=True)
54
70
  system_script_engine.simple_script(update_displayed_objects, enabled=True)
55
- process_healthcheck_script_engine.simple_script(shutdown_if_process_exited, enabled=True)
71
+ system_script_engine.register_script(enabled_by_default(tts_manager))
56
72
  rainbow_script_engine.register_script(enabled_by_default(gradient_updater))
73
+ process_healthcheck_script_engine.simple_script(shutdown_if_process_exited, enabled=True)
74
+
75
+ logger.debug("Running GUI")
57
76
 
58
77
  try:
59
78
  run_gui(on_gui_initialized, on_shutdown)
@@ -9,6 +9,7 @@ from typing import Final, Self, assert_never, cast, override
9
9
  from pymem.pattern import pattern_scan_all, pattern_scan_module
10
10
  from pymem.process import module_from_name
11
11
 
12
+ from trainerbase.logger import logger
12
13
  from trainerbase.process import _pm as pm
13
14
 
14
15
 
@@ -22,6 +23,9 @@ type ConvertibleToAddress = AbstractAddress | int | bytes | str
22
23
  read_pointer = cast(Callable[[int], int], pm.read_ulonglong if pm.is_64_bit else pm.read_uint)
23
24
 
24
25
 
26
+ logger.debug(f"Process arch is {ARCH}")
27
+
28
+
25
29
  class AbstractAddress(ABC):
26
30
  @abstractmethod
27
31
  def resolve(self) -> int:
@@ -169,7 +173,10 @@ def ensure_address(obj: ConvertibleToAddress) -> AbstractAddress:
169
173
 
170
174
 
171
175
  def allocate(size: int = POINTER_SIZE, count: int = 1) -> int:
172
- return pm.allocate(size * count)
176
+ total = size * count
177
+ logger.debug(f"Allocating {total} bytes.")
178
+
179
+ return pm.allocate(total)
173
180
 
174
181
 
175
182
  def get_module_address(module_name: str, *, delay: float = 2, retry_limit: int | None = 4) -> int:
@@ -181,15 +188,20 @@ def get_module_address(module_name: str, *, delay: float = 2, retry_limit: int |
181
188
  Set retry_limit to 0 if you want to disable retries.
182
189
  """
183
190
 
191
+ logger.info(f"Looking for {module_name}...")
192
+
184
193
  for try_counter in count():
185
194
  module_info = module_from_name(pm.process_handle, module_name)
186
195
 
187
196
  if module_info is not None:
197
+ logger.info(f"Successfully found {module_name} at {module_info.lpBaseOfDll:x}")
188
198
  return module_info.lpBaseOfDll
189
199
 
190
200
  if try_counter == retry_limit:
191
201
  raise RuntimeError(f"Failed to find module: {module_name}, tried {try_counter + 1} time(s).")
192
202
 
203
+ logger.info(f"Failed to find {module_name}. I will retry in {delay} s. Retry limit is {retry_limit}")
204
+
193
205
  sleep(delay)
194
206
 
195
207
  raise RuntimeError("This code must be unreachable!")
@@ -8,6 +8,7 @@ from pymem import Pymem
8
8
  from pymem.exception import ProcessNotFound
9
9
 
10
10
  from trainerbase.config import pymem_config
11
+ from trainerbase.logger import logger
11
12
 
12
13
 
13
14
  def attach_to_process() -> Pymem:
@@ -16,7 +17,7 @@ def attach_to_process() -> Pymem:
16
17
  if not process_names:
17
18
  raise ValueError("Empty process name list")
18
19
 
19
- print("Waiting for process in:", process_names)
20
+ logger.info(f"Waiting for process in: {process_names}")
20
21
 
21
22
  with suppress(KeyboardInterrupt):
22
23
  for process_name in cycle(process_names):
@@ -29,7 +30,7 @@ def attach_to_process() -> Pymem:
29
30
  except ProcessNotFound:
30
31
  continue
31
32
 
32
- print(f"Found {process_name}, pid: {pm.process_id}")
33
+ logger.info(f"Found {process_name}, pid: {pm.process_id}")
33
34
 
34
35
  return pm
35
36
 
@@ -38,10 +39,12 @@ def attach_to_process() -> Pymem:
38
39
 
39
40
  def shutdown_if_process_exited():
40
41
  if not pid_exists(cast(int, _pm.process_id)):
42
+ logger.info("Game process exited. Shutting down.")
41
43
  force_exit(0)
42
44
 
43
45
 
44
46
  def kill_game_process():
47
+ logger.info("Killing game process.")
45
48
  Process(_pm.process_id).kill()
46
49
 
47
50
 
@@ -0,0 +1,45 @@
1
+ from collections import deque
2
+ from typing import override
3
+
4
+ from pyttsx3 import init as init_tts_engine
5
+
6
+ from trainerbase.scriptengine import AbstractBaseScript
7
+
8
+
9
+ class TTSManager(AbstractBaseScript):
10
+ def __init__(self, queue_length_limit: int = 5):
11
+ self.__engine = init_tts_engine()
12
+ self.__queue = deque(maxlen=queue_length_limit)
13
+
14
+ @override
15
+ def __call__(self):
16
+ if not self.__queue:
17
+ return
18
+
19
+ try:
20
+ self.__say_sync(*self.__queue[0])
21
+ except RuntimeError:
22
+ return
23
+
24
+ self.__queue.popleft()
25
+
26
+ def __say_sync(self, text: str, rate: int = 210, volume: float = 1.0):
27
+ self.__engine.setProperty("rate", rate)
28
+ self.__engine.setProperty("volume", volume)
29
+ self.__engine.say(text)
30
+ self.__engine.runAndWait()
31
+
32
+ @property
33
+ def queue_length_limit(self):
34
+ return self.__queue.maxlen
35
+
36
+ @queue_length_limit.setter
37
+ def queue_length_limit(self, limit: int):
38
+ self.__queue = deque(self.__queue, maxlen=limit)
39
+
40
+ def schedule(self, text: str, rate: int = 210, volume: float = 1.0):
41
+ self.__queue.append((text, rate, volume))
42
+
43
+
44
+ tts_manager = TTSManager()
45
+ say = say_sync = tts_manager.schedule
@@ -1,10 +0,0 @@
1
- from pathlib import Path
2
-
3
- from tomllib import load as load_toml
4
-
5
-
6
- with Path("./trainerbase.toml").resolve().open("rb") as trainerbase_toml:
7
- trainerbase_config = load_toml(trainerbase_toml)
8
-
9
-
10
- pymem_config = trainerbase_config["pymem"]
@@ -1,30 +0,0 @@
1
- from contextlib import suppress
2
- from threading import Thread
3
-
4
- from pyttsx3 import init as init_tts_engine
5
-
6
-
7
- engine = init_tts_engine()
8
-
9
-
10
- def say(text: str, rate: int = 210, volume: float = 1.0, *, sync=False):
11
- args = (text, rate, volume)
12
-
13
- if sync:
14
- say_sync(*args)
15
- else:
16
- Thread(target=say_sync, args=args).start()
17
-
18
-
19
- def say_sync(text: str, rate: int, volume: float):
20
- engine.stop()
21
-
22
- with suppress(RuntimeError):
23
- engine.endLoop()
24
-
25
- engine.setProperty("rate", rate)
26
- engine.setProperty("volume", volume)
27
- engine.say(text)
28
-
29
- with suppress(RuntimeError):
30
- engine.runAndWait()
File without changes
File without changes