trainerbase 4.8.0__tar.gz → 4.8.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.8.0 → trainerbase-4.8.2}/PKG-INFO +1 -1
- {trainerbase-4.8.0 → trainerbase-4.8.2}/pyproject.toml +22 -17
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/codeinjection.py +8 -8
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/common/helpers.py +4 -3
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/common/rainbow.py +1 -2
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/config.py +1 -1
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gameobject.py +2 -2
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gui/objects.py +6 -4
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/logger.py +1 -1
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/main.py +1 -2
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/memory.py +19 -12
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/process.py +2 -2
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/scriptengine.py +3 -3
- {trainerbase-4.8.0 → trainerbase-4.8.2}/README.md +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/__init__.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/abc.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/common/__init__.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/common/abc.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/common/keyboard.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/common/tapper.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/common/teleport.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gui/__init__.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gui/helpers.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gui/injections.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gui/misc.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gui/rainbow.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gui/scripts.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gui/speedhack.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gui/tapper.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gui/teleport.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/gui/types.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/py.typed +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/speedhack.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/tts.py +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/vendor/FASM.EXE +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/vendor/big_logo.png +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/vendor/speedhack32.dll +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/vendor/speedhack64.dll +0 -0
- {trainerbase-4.8.0 → trainerbase-4.8.2}/trainerbase/vendor/trainerbase.ico +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "trainerbase"
|
|
3
|
-
version = "4.8.
|
|
3
|
+
version = "4.8.2"
|
|
4
4
|
description = "Framework for creating game trainers/mods"
|
|
5
5
|
license = "MIT"
|
|
6
6
|
authors = [
|
|
@@ -34,20 +34,25 @@ src = ["trainerbase"]
|
|
|
34
34
|
line-length = 120
|
|
35
35
|
|
|
36
36
|
[tool.ruff.lint]
|
|
37
|
-
select = [
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
37
|
+
select = ["ALL"]
|
|
38
|
+
ignore = [
|
|
39
|
+
"D",
|
|
40
|
+
"ANN",
|
|
41
|
+
"TC",
|
|
42
|
+
"EM",
|
|
43
|
+
"A005",
|
|
44
|
+
"FIX002",
|
|
45
|
+
"COM812",
|
|
46
|
+
"TC002",
|
|
47
|
+
"S607",
|
|
48
|
+
"BLE001",
|
|
49
|
+
"TRY003",
|
|
50
|
+
"RET504",
|
|
51
|
+
"PLR2004",
|
|
52
|
+
"PLR0913",
|
|
53
|
+
"PLW2901",
|
|
54
|
+
"TD002",
|
|
55
|
+
"TD003",
|
|
51
56
|
]
|
|
52
57
|
|
|
53
58
|
[tool.ruff.lint.isort]
|
|
@@ -70,12 +75,12 @@ module-name = "trainerbase"
|
|
|
70
75
|
module-root = ""
|
|
71
76
|
|
|
72
77
|
[build-system]
|
|
73
|
-
requires = ["uv_build>=0.
|
|
78
|
+
requires = ["uv_build>=0.11.3,<1.0.0"]
|
|
74
79
|
build-backend = "uv_build"
|
|
75
80
|
|
|
76
81
|
[dependency-groups]
|
|
77
82
|
dev = [
|
|
78
83
|
"invoke>=2.2.1",
|
|
79
84
|
"pyright>=1.1.407",
|
|
80
|
-
"ruff>=0.15.
|
|
85
|
+
"ruff>=0.15.9",
|
|
81
86
|
]
|
|
@@ -59,7 +59,7 @@ class CodeInjection(AbstractCodeInjection):
|
|
|
59
59
|
self.injection_point = self.address.resolve()
|
|
60
60
|
self.original_code = pm.read_bytes(self.injection_point, len(self.code_to_inject))
|
|
61
61
|
|
|
62
|
-
logger.debug(
|
|
62
|
+
logger.debug("Injecting %d byte(s) at 0x%X", len(self.code_to_inject), self.injection_point)
|
|
63
63
|
|
|
64
64
|
pm.write_bytes(self.injection_point, self.code_to_inject, len(self.code_to_inject))
|
|
65
65
|
self._injected = True
|
|
@@ -67,7 +67,7 @@ class CodeInjection(AbstractCodeInjection):
|
|
|
67
67
|
@override
|
|
68
68
|
def eject(self):
|
|
69
69
|
if self._injected:
|
|
70
|
-
logger.debug(
|
|
70
|
+
logger.debug("Ejecting %d byte(s) from 0x%X", len(self.code_to_inject), self.injection_point)
|
|
71
71
|
|
|
72
72
|
pm.write_bytes(self.injection_point, self.original_code, len(self.original_code))
|
|
73
73
|
self._injected = False
|
|
@@ -140,19 +140,19 @@ class AllocatingCodeInjection(AbstractCodeInjection):
|
|
|
140
140
|
|
|
141
141
|
code_to_inject = code_to_inject + jump_back
|
|
142
142
|
|
|
143
|
-
logger.debug(
|
|
143
|
+
logger.debug("Injecting %d byte(s) (INJECTION) at 0x%X", len(code_to_inject), self.new_memory_address)
|
|
144
144
|
pm.write_bytes(self.new_memory_address, code_to_inject, len(code_to_inject))
|
|
145
145
|
|
|
146
|
-
logger.debug(
|
|
146
|
+
logger.debug("Injecting %d byte(s) (JUMPER) at 0x%X", len(jump_to_new_mem), self.injection_point)
|
|
147
147
|
pm.write_bytes(self.injection_point, jump_to_new_mem, len(jump_to_new_mem))
|
|
148
148
|
|
|
149
149
|
@override
|
|
150
150
|
def eject(self):
|
|
151
151
|
if self.new_memory_address and self.injection_point:
|
|
152
|
-
logger.debug(
|
|
152
|
+
logger.debug("Ejecting %d byte(s) (JUMPER) from 0x%X", self.original_code_length, self.injection_point)
|
|
153
153
|
pm.write_bytes(self.injection_point, self.original_code, self.original_code_length)
|
|
154
154
|
|
|
155
|
-
logger.debug(
|
|
155
|
+
logger.debug("Freeing memory at 0x%X", self.new_memory_address)
|
|
156
156
|
pm.free(self.new_memory_address)
|
|
157
157
|
self.new_memory_address = 0
|
|
158
158
|
self.injection_point = 0
|
|
@@ -200,7 +200,7 @@ def preprocess_asm(code: str, *, original_code: bytes | None, base_address: int
|
|
|
200
200
|
@lru_cache
|
|
201
201
|
def compile_asm(code: Code) -> bytes:
|
|
202
202
|
if isinstance(code, str):
|
|
203
|
-
logger.debug(
|
|
203
|
+
logger.debug("Assembling for x%d:\n%s", ARCH, code)
|
|
204
204
|
|
|
205
205
|
fasm_mode = f"use{ARCH}"
|
|
206
206
|
with TemporaryDirectory() as tmp_dir:
|
|
@@ -208,7 +208,7 @@ def compile_asm(code: Code) -> bytes:
|
|
|
208
208
|
|
|
209
209
|
asm_file.write_text(f"{fasm_mode}\n{code}", encoding="utf-8")
|
|
210
210
|
|
|
211
|
-
run_executable([FASM_EXECUTABLE_PATH, asm_file], stdout=DEVNULL, check=True)
|
|
211
|
+
run_executable([FASM_EXECUTABLE_PATH, asm_file], stdout=DEVNULL, check=True) # noqa: S603
|
|
212
212
|
code = asm_file.with_suffix(".bin").read_bytes()
|
|
213
213
|
|
|
214
214
|
if not isinstance(code, bytes):
|
|
@@ -22,8 +22,8 @@ class ASMArrayManager(Sequence):
|
|
|
22
22
|
offsets: None | list[int] = None,
|
|
23
23
|
add: int = 0,
|
|
24
24
|
) -> None:
|
|
25
|
-
if offsets:
|
|
26
|
-
|
|
25
|
+
if offsets and element_size != POINTER_SIZE:
|
|
26
|
+
raise ValueError("If `offsets` is not None, `element_size` must be `POINTER_SIZE`")
|
|
27
27
|
|
|
28
28
|
self.array_length = array_length
|
|
29
29
|
self.element_size = element_size
|
|
@@ -72,7 +72,8 @@ class ASMArrayManager(Sequence):
|
|
|
72
72
|
if from_register == array_index_register:
|
|
73
73
|
array_index_register = reserve_register
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
if len({from_register, array_address_register, array_index_register}) != 3:
|
|
76
|
+
raise RuntimeError("Registers must be unique")
|
|
76
77
|
|
|
77
78
|
label_continue = f"__label_continue_{uuid4().hex}"
|
|
78
79
|
|
|
@@ -61,8 +61,7 @@ class GradientUpdater(AbstractBaseScript):
|
|
|
61
61
|
colors = []
|
|
62
62
|
|
|
63
63
|
for _ in range(length // 2):
|
|
64
|
-
for _ in range(self.color_length)
|
|
65
|
-
colors.append((red, green, blue))
|
|
64
|
+
colors.extend((red, green, blue) for _ in range(self.color_length))
|
|
66
65
|
|
|
67
66
|
red, delta_red = self.next_color_channel_value(red, delta_red)
|
|
68
67
|
green, delta_green = self.next_color_channel_value(green, delta_green)
|
|
@@ -186,11 +186,11 @@ class GameBool(GameObject[bool, bool], Switchable):
|
|
|
186
186
|
|
|
187
187
|
@override
|
|
188
188
|
def enable(self):
|
|
189
|
-
self.value = True
|
|
189
|
+
self.value = True
|
|
190
190
|
|
|
191
191
|
@override
|
|
192
192
|
def disable(self):
|
|
193
|
-
self.value = False
|
|
193
|
+
self.value = False
|
|
194
194
|
|
|
195
195
|
|
|
196
196
|
class ReadonlyGameObjectSumGetter(AbstractReadableObject[int | float]):
|
|
@@ -123,15 +123,17 @@ class GameObjectUI(AbstractUIComponent):
|
|
|
123
123
|
| GameUnsignedLongLong()
|
|
124
124
|
):
|
|
125
125
|
# There is no input for integers that are not simple `signed long int`.
|
|
126
|
-
# TODO: Use better input component if it's already added to dpg. Remove this crutch.
|
|
126
|
+
# TODO: Use better input component if it's already added to dpg. Remove this crutch.
|
|
127
|
+
|
|
128
|
+
if GameInt.value_range is None:
|
|
129
|
+
raise RuntimeError("GameInt must have value_range")
|
|
127
130
|
|
|
128
|
-
assert GameInt.value_range is not None, "GameInt must have value_range"
|
|
129
131
|
min_value = default_kwargs.pop("min_value", GameInt.value_range[0])
|
|
130
132
|
max_value = default_kwargs.pop("max_value", GameInt.value_range[1])
|
|
131
133
|
|
|
132
134
|
if self.gameobject.value_range is not None:
|
|
133
|
-
min_value = max(min_value, GameInt.value_range[0])
|
|
134
|
-
max_value = min(max_value, GameInt.value_range[1])
|
|
135
|
+
min_value = max(min_value, GameInt.value_range[0])
|
|
136
|
+
max_value = min(max_value, GameInt.value_range[1])
|
|
135
137
|
|
|
136
138
|
dpg.add_input_int(min_value=min_value, max_value=max_value, **default_kwargs)
|
|
137
139
|
case GameBool():
|
|
@@ -38,7 +38,7 @@ getLogger("comtypes").setLevel(ERROR)
|
|
|
38
38
|
|
|
39
39
|
logger = getLogger("TrainerBase")
|
|
40
40
|
if using_default_config:
|
|
41
|
-
logger.debug(
|
|
41
|
+
logger.debug("No logging config in %s! Using default one.", CONFIG_FILE)
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
def _exception_hook(*args):
|
|
@@ -22,7 +22,7 @@ from trainerbase.tts import tts_manager
|
|
|
22
22
|
type Callback = Callable[[], None]
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def run(
|
|
25
|
+
def run(
|
|
26
26
|
run_gui: Callable[[Callback, Callback], None],
|
|
27
27
|
on_gui_initialized_hook: Callback | None = None,
|
|
28
28
|
on_shutdown_hook: Callback | None = None,
|
|
@@ -80,6 +80,5 @@ def run( # pylint: disable=too-complex
|
|
|
80
80
|
print_exc()
|
|
81
81
|
except KeyboardInterrupt:
|
|
82
82
|
logger.info("KeyboardInterrupt (Ctrl+C)")
|
|
83
|
-
pass
|
|
84
83
|
|
|
85
84
|
on_shutdown()
|
|
@@ -15,7 +15,8 @@ from trainerbase.process import pm
|
|
|
15
15
|
|
|
16
16
|
ARCH: Final[int] = 64 if pm.is_64_bit else 32
|
|
17
17
|
POINTER_SIZE: Final[int] = 8 if pm.is_64_bit else 4
|
|
18
|
-
DEFAULT_HARDCODED_ADDRESS_OFFSET_READER: Callable[[int], int] = cast(Callable[[int], int], pm.read_uint)
|
|
18
|
+
DEFAULT_HARDCODED_ADDRESS_OFFSET_READER: Final[Callable[[int], int]] = cast(Callable[[int], int], pm.read_uint)
|
|
19
|
+
ANY_BYTE_MARKER_HEX: Final[str] = "2E" # 2E is hex(46), 46 is ord(".")
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
type ConvertibleToAddress = AbstractAddress | int | bytes | str
|
|
@@ -24,7 +25,7 @@ type ConvertibleToAddress = AbstractAddress | int | bytes | str
|
|
|
24
25
|
read_pointer = cast(Callable[[int], int], pm.read_ulonglong if pm.is_64_bit else pm.read_uint)
|
|
25
26
|
|
|
26
27
|
|
|
27
|
-
logger.debug(
|
|
28
|
+
logger.debug("Process arch is %d", ARCH)
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
class AbstractAddress(ABC):
|
|
@@ -51,9 +52,10 @@ class AOBScan(AbstractAddress):
|
|
|
51
52
|
):
|
|
52
53
|
self._should_cache = should_cache
|
|
53
54
|
self._saved_scan_result: int | None = None
|
|
55
|
+
self._any_byte_marker = any_byte_marker
|
|
54
56
|
|
|
55
57
|
if isinstance(aob, str):
|
|
56
|
-
aob = bytes.fromhex(aob.replace(any_byte_marker,
|
|
58
|
+
aob = bytes.fromhex(aob.replace(any_byte_marker, ANY_BYTE_MARKER_HEX)) # 2E is hex(46), 46 is ord(".")
|
|
57
59
|
|
|
58
60
|
if should_escape:
|
|
59
61
|
aob = self._escape_aob(aob)
|
|
@@ -88,7 +90,8 @@ class AOBScan(AbstractAddress):
|
|
|
88
90
|
scan_result: list[int] | int | None = find_aob(self.aob, check_memory_protection=self.check_memory_protection)
|
|
89
91
|
|
|
90
92
|
if not scan_result:
|
|
91
|
-
|
|
93
|
+
aob_repr = self.aob.hex(" ").upper().replace(ANY_BYTE_MARKER_HEX, self._any_byte_marker)
|
|
94
|
+
raise ValueError(f"AOB not found: {aob_repr}")
|
|
92
95
|
|
|
93
96
|
if isinstance(scan_result, list):
|
|
94
97
|
result_address = scan_result[cast(int, self.multiple_result_index)]
|
|
@@ -109,6 +112,8 @@ class AOBScan(AbstractAddress):
|
|
|
109
112
|
module_name=self.module_name,
|
|
110
113
|
multiple_result_index=self.multiple_result_index,
|
|
111
114
|
should_cache=self._should_cache,
|
|
115
|
+
check_memory_protection=self.check_memory_protection,
|
|
116
|
+
should_escape=False,
|
|
112
117
|
)
|
|
113
118
|
|
|
114
119
|
if new_add is not None:
|
|
@@ -172,12 +177,12 @@ def ensure_address(obj: ConvertibleToAddress) -> AbstractAddress:
|
|
|
172
177
|
case bytes() | str():
|
|
173
178
|
return AOBScan(obj)
|
|
174
179
|
case _:
|
|
175
|
-
|
|
180
|
+
assert_never(obj)
|
|
176
181
|
|
|
177
182
|
|
|
178
183
|
def allocate(size: int = POINTER_SIZE, count: int = 1) -> int:
|
|
179
184
|
total = size * count
|
|
180
|
-
logger.debug(
|
|
185
|
+
logger.debug("Allocating %d bytes.", total)
|
|
181
186
|
|
|
182
187
|
return pm.allocate(total)
|
|
183
188
|
|
|
@@ -237,19 +242,19 @@ def get_module_address(module_name: str, *, delay: float = 2, retry_limit: int |
|
|
|
237
242
|
Set retry_limit to 0 if you want to disable retries.
|
|
238
243
|
"""
|
|
239
244
|
|
|
240
|
-
logger.info(
|
|
245
|
+
logger.info("Looking for %s...", module_name)
|
|
241
246
|
|
|
242
247
|
for try_counter in count():
|
|
243
248
|
module_info = module_from_name(pm.process_handle, module_name)
|
|
244
249
|
|
|
245
250
|
if module_info is not None:
|
|
246
|
-
logger.info(
|
|
251
|
+
logger.info("Successfully found %s at 0x%X", module_name, module_info.lpBaseOfDll)
|
|
247
252
|
return module_info.lpBaseOfDll
|
|
248
253
|
|
|
249
254
|
if try_counter == retry_limit:
|
|
250
255
|
raise RuntimeError(f"Failed to find module: {module_name}, tried {try_counter + 1} time(s).")
|
|
251
256
|
|
|
252
|
-
logger.info(
|
|
257
|
+
logger.info("Failed to find %s. I will retry in %f s. Retry limit is %s", module_name, delay, retry_limit)
|
|
253
258
|
|
|
254
259
|
sleep(delay)
|
|
255
260
|
|
|
@@ -271,7 +276,7 @@ def ensure_resolved(
|
|
|
271
276
|
Set retry_limit to 0 if you want to disable retries.
|
|
272
277
|
"""
|
|
273
278
|
|
|
274
|
-
logger.info(
|
|
279
|
+
logger.info("Looking for %s...", verbose_name)
|
|
275
280
|
|
|
276
281
|
for try_counter in count():
|
|
277
282
|
try:
|
|
@@ -280,12 +285,14 @@ def ensure_resolved(
|
|
|
280
285
|
if try_counter == retry_limit:
|
|
281
286
|
raise RuntimeError(f"Failed to resolve {verbose_name}, tried {try_counter + 1} time(s).") from e
|
|
282
287
|
|
|
283
|
-
logger.info(
|
|
288
|
+
logger.info(
|
|
289
|
+
"Failed to resolve %s. I will retry in %f s. Retry limit is %s", verbose_name, delay, retry_limit
|
|
290
|
+
)
|
|
284
291
|
|
|
285
292
|
sleep(delay)
|
|
286
293
|
continue
|
|
287
294
|
|
|
288
|
-
logger.info(
|
|
295
|
+
logger.info("Successfully found %s at 0x%X", verbose_name, resolved)
|
|
289
296
|
return resolved
|
|
290
297
|
|
|
291
298
|
raise RuntimeError("This code must be unreachable!")
|
|
@@ -46,14 +46,14 @@ def select_one_process(processes: Iterable[Process]) -> Process:
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
def get_target_pid(process_names: Iterable[str], *, exact_match: bool, ignore_case: bool) -> int:
|
|
49
|
-
logger.info(
|
|
49
|
+
logger.info("Waiting for process in: %s", process_names)
|
|
50
50
|
|
|
51
51
|
for process_name in cycle(process_names):
|
|
52
52
|
found_processes = find_processes(process_name, exact_match=exact_match, ignore_case=ignore_case)
|
|
53
53
|
|
|
54
54
|
if found_processes:
|
|
55
55
|
pid = select_one_process(found_processes).pid
|
|
56
|
-
logger.info(
|
|
56
|
+
logger.info("Found %s, pid: %d", process_name, pid)
|
|
57
57
|
|
|
58
58
|
return pid
|
|
59
59
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from collections.abc import Callable
|
|
3
3
|
from contextlib import suppress
|
|
4
|
-
from sys import stderr
|
|
5
4
|
from threading import Thread
|
|
6
5
|
from time import sleep
|
|
7
6
|
from typing import Any, override
|
|
@@ -9,6 +8,7 @@ from typing import Any, override
|
|
|
9
8
|
from pymem.exception import MemoryReadError, MemoryWriteError
|
|
10
9
|
|
|
11
10
|
from trainerbase.abc import Switchable
|
|
11
|
+
from trainerbase.logger import logger
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class AbstractBaseScript(Switchable, ABC):
|
|
@@ -73,8 +73,8 @@ class ScriptEngine:
|
|
|
73
73
|
script()
|
|
74
74
|
except MemoryReadError, MemoryWriteError:
|
|
75
75
|
continue
|
|
76
|
-
except Exception
|
|
77
|
-
|
|
76
|
+
except Exception:
|
|
77
|
+
logger.exception("Error in script %r. Stopping Script Engine.", script)
|
|
78
78
|
self.stop()
|
|
79
79
|
|
|
80
80
|
sleep(self.delay)
|
|
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
|