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.
- {trainerbase-4.0.0 → trainerbase-4.0.2}/PKG-INFO +1 -1
- {trainerbase-4.0.0 → trainerbase-4.0.2}/pyproject.toml +1 -1
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/tapper.py +2 -0
- trainerbase-4.0.2/trainerbase/config.py +15 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/tapper.py +5 -2
- trainerbase-4.0.2/trainerbase/logger.py +40 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/main.py +20 -1
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/memory.py +13 -1
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/process.py +5 -2
- trainerbase-4.0.2/trainerbase/tts.py +45 -0
- trainerbase-4.0.0/trainerbase/config.py +0 -10
- trainerbase-4.0.0/trainerbase/tts.py +0 -30
- {trainerbase-4.0.0 → trainerbase-4.0.2}/LICENSE +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/README.md +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/__init__.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/abc.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/codeinjection.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/__init__.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/abc.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/helpers.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/keyboard.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/rainbow.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/common/teleport.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gameobject.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/__init__.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/helpers.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/injections.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/misc.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/objects.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/rainbow.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/scripts.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/speedhack.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/teleport.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/gui/types.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/scriptengine.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase/speedhack.py +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase_vendor/FASM.EXE +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase_vendor/speedhack32.dll +0 -0
- {trainerbase-4.0.0 → trainerbase-4.0.2}/trainerbase_vendor/speedhack64.dll +0 -0
|
@@ -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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|