trainerbase 3.6.3__tar.gz → 3.7.0__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-3.6.3 → trainerbase-3.7.0}/PKG-INFO +1 -1
- {trainerbase-3.6.3 → trainerbase-3.7.0}/pyproject.toml +1 -1
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase/codeinjection.py +2 -2
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase/gameobject.py +37 -0
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase/gui.py +43 -14
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase/memory.py +3 -3
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase/speedhack.py +6 -4
- {trainerbase-3.6.3 → trainerbase-3.7.0}/LICENSE +0 -0
- {trainerbase-3.6.3 → trainerbase-3.7.0}/README.rst +0 -0
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase/__init__.py +0 -0
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase/common.py +0 -0
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase/config.py +0 -0
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase/main.py +0 -0
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase/scriptengine.py +0 -0
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase/tts.py +0 -0
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase_vendor/FASM.EXE +0 -0
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase_vendor/speedhack32.dll +0 -0
- {trainerbase-3.6.3 → trainerbase-3.7.0}/trainerbase_vendor/speedhack64.dll +0 -0
|
@@ -3,14 +3,14 @@ from pathlib import Path
|
|
|
3
3
|
from subprocess import DEVNULL
|
|
4
4
|
from subprocess import run as run_executable
|
|
5
5
|
from tempfile import TemporaryDirectory
|
|
6
|
-
from typing import Never, Self, override
|
|
6
|
+
from typing import Final, Never, Self, override
|
|
7
7
|
|
|
8
8
|
from pymem.exception import MemoryWriteError
|
|
9
9
|
|
|
10
10
|
from trainerbase.memory import ARCH, ConvertibleToAddress, ensure_address, pm
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
FASM_EXECUTABLE_PATH = Path(__file__).resolve().parent.parent / "trainerbase_vendor" / "FASM.EXE"
|
|
13
|
+
FASM_EXECUTABLE_PATH: Final[Path] = Path(__file__).resolve().parent.parent / "trainerbase_vendor" / "FASM.EXE"
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
type Code = bytes | str
|
|
@@ -15,6 +15,7 @@ class AbstractReadableObject[T](ABC):
|
|
|
15
15
|
|
|
16
16
|
class GameObject[PymemType, TrainerBaseType](AbstractReadableObject[TrainerBaseType]):
|
|
17
17
|
tracked_objects: list[Self] = []
|
|
18
|
+
value_range: None | tuple[int | float, int | float] = None
|
|
18
19
|
|
|
19
20
|
@staticmethod
|
|
20
21
|
@abstractmethod
|
|
@@ -31,6 +32,7 @@ class GameObject[PymemType, TrainerBaseType](AbstractReadableObject[TrainerBaseT
|
|
|
31
32
|
address: ConvertibleToAddress,
|
|
32
33
|
frozen: TrainerBaseType | None = None,
|
|
33
34
|
is_tracked: bool = True,
|
|
35
|
+
value_range: None | tuple[int | float, int | float] = None,
|
|
34
36
|
):
|
|
35
37
|
if is_tracked:
|
|
36
38
|
GameObject.tracked_objects.append(self)
|
|
@@ -39,6 +41,9 @@ class GameObject[PymemType, TrainerBaseType](AbstractReadableObject[TrainerBaseT
|
|
|
39
41
|
self.frozen = frozen
|
|
40
42
|
self.is_tracked = is_tracked
|
|
41
43
|
|
|
44
|
+
if value_range is not None:
|
|
45
|
+
self.value_range = value_range
|
|
46
|
+
|
|
42
47
|
def __repr__(self):
|
|
43
48
|
return (
|
|
44
49
|
f"<{self.__class__.__name__}"
|
|
@@ -54,6 +59,17 @@ class GameObject[PymemType, TrainerBaseType](AbstractReadableObject[TrainerBaseT
|
|
|
54
59
|
def before_write(self, value: TrainerBaseType) -> PymemType:
|
|
55
60
|
return value # type: ignore
|
|
56
61
|
|
|
62
|
+
def validate_range(self, value: TrainerBaseType) -> bool:
|
|
63
|
+
if self.value_range is None:
|
|
64
|
+
return True
|
|
65
|
+
|
|
66
|
+
if not isinstance(value, (int, float)):
|
|
67
|
+
raise TypeError(f"Unable to validate range for non-numeric value: {value} (type: {type(value)})")
|
|
68
|
+
|
|
69
|
+
min_value, max_value = self.value_range
|
|
70
|
+
|
|
71
|
+
return min_value <= value <= max_value
|
|
72
|
+
|
|
57
73
|
@property
|
|
58
74
|
@override
|
|
59
75
|
def value(self) -> TrainerBaseType:
|
|
@@ -61,10 +77,14 @@ class GameObject[PymemType, TrainerBaseType](AbstractReadableObject[TrainerBaseT
|
|
|
61
77
|
|
|
62
78
|
@value.setter
|
|
63
79
|
def value(self, new_value: TrainerBaseType):
|
|
80
|
+
if not self.validate_range(new_value):
|
|
81
|
+
raise ValueError(f"Wrong value for type {type(self)}: {new_value} not in range {self.value_range}")
|
|
82
|
+
|
|
64
83
|
self.pm_write(self.address.resolve(), self.before_write(new_value))
|
|
65
84
|
|
|
66
85
|
|
|
67
86
|
class GameFloat(GameObject[float, float]):
|
|
87
|
+
value_range = (-3.4e38, 3.4e38)
|
|
68
88
|
pm_read = pm.read_float # type: ignore
|
|
69
89
|
pm_write = pm.write_float
|
|
70
90
|
|
|
@@ -74,6 +94,7 @@ class GameFloat(GameObject[float, float]):
|
|
|
74
94
|
|
|
75
95
|
|
|
76
96
|
class GameDouble(GameObject[float, float]):
|
|
97
|
+
value_range = (-1.7e308, 1.7e308)
|
|
77
98
|
pm_read = pm.read_double # type: ignore
|
|
78
99
|
pm_write = pm.write_double
|
|
79
100
|
|
|
@@ -83,6 +104,8 @@ class GameDouble(GameObject[float, float]):
|
|
|
83
104
|
|
|
84
105
|
|
|
85
106
|
class GameByte(GameObject[bytes, int]):
|
|
107
|
+
value_range = (0, 255)
|
|
108
|
+
|
|
86
109
|
@staticmethod
|
|
87
110
|
@override
|
|
88
111
|
def pm_read(address: int) -> bytes:
|
|
@@ -103,36 +126,50 @@ class GameByte(GameObject[bytes, int]):
|
|
|
103
126
|
|
|
104
127
|
|
|
105
128
|
class GameInt(GameObject[int, int]):
|
|
129
|
+
value_range = (-2_147_483_648, 2_147_483_647)
|
|
130
|
+
|
|
106
131
|
pm_read = pm.read_int # type: ignore
|
|
107
132
|
pm_write = pm.write_int
|
|
108
133
|
|
|
109
134
|
|
|
110
135
|
class GameShort(GameObject[int, int]):
|
|
136
|
+
value_range = (-32_768, 32_767)
|
|
137
|
+
|
|
111
138
|
pm_read = pm.read_short # type: ignore
|
|
112
139
|
pm_write = pm.write_short
|
|
113
140
|
|
|
114
141
|
|
|
115
142
|
class GameLongLong(GameObject[int, int]):
|
|
143
|
+
value_range = (-(2**63), (2**63) - 1)
|
|
144
|
+
|
|
116
145
|
pm_read = pm.read_longlong # type: ignore
|
|
117
146
|
pm_write = pm.write_longlong
|
|
118
147
|
|
|
119
148
|
|
|
120
149
|
class GameUnsignedInt(GameObject[int, int]):
|
|
150
|
+
value_range = (0, 4_294_967_295)
|
|
151
|
+
|
|
121
152
|
pm_read = pm.read_uint # type: ignore
|
|
122
153
|
pm_write = pm.write_uint
|
|
123
154
|
|
|
124
155
|
|
|
125
156
|
class GameUnsignedShort(GameObject[int, int]):
|
|
157
|
+
value_range = (0, 65_535)
|
|
158
|
+
|
|
126
159
|
pm_read = pm.read_ushort # type: ignore
|
|
127
160
|
pm_write = pm.write_ushort
|
|
128
161
|
|
|
129
162
|
|
|
130
163
|
class GameUnsignedLongLong(GameObject[int, int]):
|
|
164
|
+
value_range = (0, 18_446_744_073_709_551_615)
|
|
165
|
+
|
|
131
166
|
pm_read = pm.read_ulonglong # type: ignore
|
|
132
167
|
pm_write = pm.write_ulonglong
|
|
133
168
|
|
|
134
169
|
|
|
135
170
|
class GameBool(GameObject[bool, bool]):
|
|
171
|
+
value_range = (False, True)
|
|
172
|
+
|
|
136
173
|
pm_read = pm.read_bool # type: ignore
|
|
137
174
|
pm_write = pm.write_bool
|
|
138
175
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from collections.abc import Callable
|
|
3
|
-
from functools import
|
|
3
|
+
from functools import wraps
|
|
4
4
|
from typing import Any, Self, override
|
|
5
5
|
from uuid import uuid4
|
|
6
6
|
|
|
@@ -153,6 +153,7 @@ class GameObjectUI(AbstractUIComponent):
|
|
|
153
153
|
default_setter_input_value: Any = 0,
|
|
154
154
|
before_set: Callable | None = None,
|
|
155
155
|
tts_on_hotkey: bool = True,
|
|
156
|
+
setter_input_width: int = 220,
|
|
156
157
|
):
|
|
157
158
|
if not gameobject.is_tracked:
|
|
158
159
|
hotkey = None
|
|
@@ -164,6 +165,7 @@ class GameObjectUI(AbstractUIComponent):
|
|
|
164
165
|
self.default_setter_input_value = default_setter_input_value
|
|
165
166
|
self.before_set = before_set
|
|
166
167
|
self.tts_on_hotkey = tts_on_hotkey
|
|
168
|
+
self.setter_input_width = setter_input_width
|
|
167
169
|
|
|
168
170
|
dpg_tag = f"{self.DPG_TAG_PREFIX}{uuid4()}"
|
|
169
171
|
self.dpg_tag_frozen = f"{dpg_tag}{self.DPG_TAG_POSTFIX_IS_FROZEN}"
|
|
@@ -175,29 +177,56 @@ class GameObjectUI(AbstractUIComponent):
|
|
|
175
177
|
if self.hotkey is not None:
|
|
176
178
|
add_hotkey(self.hotkey, self.on_hotkey_press)
|
|
177
179
|
|
|
178
|
-
match self.gameobject:
|
|
179
|
-
case GameFloat():
|
|
180
|
-
add_setter_input = dpg.add_input_float
|
|
181
|
-
case GameDouble():
|
|
182
|
-
add_setter_input = dpg.add_input_double
|
|
183
|
-
case GameByte() | GameShort() | GameInt() | GameLongLong() | GameBool():
|
|
184
|
-
add_setter_input = dpg.add_input_int
|
|
185
|
-
case GameUnsignedShort() | GameUnsignedInt() | GameUnsignedLongLong():
|
|
186
|
-
add_setter_input = partial(dpg.add_input_int, min_clamped=True, min_value=0)
|
|
187
|
-
case _:
|
|
188
|
-
add_setter_input = dpg.add_input_text
|
|
189
|
-
|
|
190
180
|
with dpg.group(horizontal=True):
|
|
191
181
|
if self.gameobject.is_tracked:
|
|
192
182
|
dpg.add_checkbox(tag=self.dpg_tag_frozen, callback=self.on_frozen_state_change)
|
|
193
183
|
|
|
194
184
|
dpg.add_text(self.label_with_hotkey)
|
|
195
185
|
dpg.add_input_text(width=220, tag=self.dpg_tag_getter, readonly=True)
|
|
196
|
-
|
|
186
|
+
|
|
187
|
+
self.add_setter_input()
|
|
188
|
+
|
|
197
189
|
dpg.add_button(label="Set", callback=self.on_value_set)
|
|
198
190
|
|
|
199
191
|
GameObjectUI.displayed_objects.append(self)
|
|
200
192
|
|
|
193
|
+
def add_setter_input(self):
|
|
194
|
+
default_kwargs = {
|
|
195
|
+
"tag": self.dpg_tag_setter,
|
|
196
|
+
"width": self.setter_input_width,
|
|
197
|
+
"default_value": self.default_setter_input_value,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if self.gameobject.value_range is not None:
|
|
201
|
+
min_value, max_value = self.gameobject.value_range
|
|
202
|
+
default_kwargs["min_clamped"] = True
|
|
203
|
+
default_kwargs["max_clamped"] = True
|
|
204
|
+
default_kwargs["min_value"] = min_value
|
|
205
|
+
default_kwargs["max_value"] = max_value
|
|
206
|
+
|
|
207
|
+
match self.gameobject:
|
|
208
|
+
case GameFloat():
|
|
209
|
+
dpg.add_input_float(**default_kwargs)
|
|
210
|
+
case GameDouble():
|
|
211
|
+
dpg.add_input_double(**default_kwargs)
|
|
212
|
+
case (
|
|
213
|
+
GameByte()
|
|
214
|
+
| GameShort()
|
|
215
|
+
| GameInt()
|
|
216
|
+
| GameLongLong()
|
|
217
|
+
| GameUnsignedShort()
|
|
218
|
+
| GameUnsignedInt()
|
|
219
|
+
| GameUnsignedLongLong()
|
|
220
|
+
):
|
|
221
|
+
dpg.add_input_int(**default_kwargs)
|
|
222
|
+
case GameBool():
|
|
223
|
+
dpg.add_checkbox(
|
|
224
|
+
tag=self.dpg_tag_setter,
|
|
225
|
+
default_value=bool(self.default_setter_input_value),
|
|
226
|
+
)
|
|
227
|
+
case _:
|
|
228
|
+
dpg.add_input_text(**default_kwargs)
|
|
229
|
+
|
|
201
230
|
def on_frozen_state_change(self):
|
|
202
231
|
try:
|
|
203
232
|
self.gameobject.frozen = self.gameobject.value if dpg.get_value(self.dpg_tag_frozen) else None
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from collections.abc import Callable
|
|
3
3
|
from functools import partial
|
|
4
|
-
from typing import Self, assert_never, override
|
|
4
|
+
from typing import Final, Self, assert_never, override
|
|
5
5
|
|
|
6
6
|
from pymem import Pymem
|
|
7
7
|
from pymem.exception import ProcessNotFound
|
|
@@ -21,8 +21,8 @@ else:
|
|
|
21
21
|
raise ProcessNotFound(f"not any: {pymem_config['process_names']}")
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
ARCH = 64 if pm.is_64_bit else 32
|
|
25
|
-
POINTER_SIZE = 8 if pm.is_64_bit else 4
|
|
24
|
+
ARCH: Final[int] = 64 if pm.is_64_bit else 32
|
|
25
|
+
POINTER_SIZE: Final[int] = 8 if pm.is_64_bit else 4
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
type ConvertibleToAddress = AbstractAddress | int | bytes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from typing import Self
|
|
2
|
+
from typing import Final, Self
|
|
3
3
|
|
|
4
4
|
from pyinjector import inject
|
|
5
5
|
from pymem.exception import MemoryWriteError
|
|
@@ -9,9 +9,11 @@ from trainerbase.gameobject import GameDouble
|
|
|
9
9
|
from trainerbase.memory import ARCH, pm
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
SPEEDHACK_DLL_MODULE_NAME = f"speedhack{ARCH}.dll"
|
|
13
|
-
SPEEDHACK_DLL_PATH =
|
|
14
|
-
|
|
12
|
+
SPEEDHACK_DLL_MODULE_NAME: Final[str] = f"speedhack{ARCH}.dll"
|
|
13
|
+
SPEEDHACK_DLL_PATH: Final[Path] = (
|
|
14
|
+
Path(__file__).resolve().parent.parent / "trainerbase_vendor" / SPEEDHACK_DLL_MODULE_NAME
|
|
15
|
+
)
|
|
16
|
+
SPEED_MODIFIER_OFFSET: Final[int] = 0x40058 if ARCH == 32 else 0x47098
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
class SpeedHack:
|
|
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
|