bethkit 1.0.0__py3-none-win_amd64.whl
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.
- bethkit/__init__.py +102 -0
- bethkit/_error.py +85 -0
- bethkit/_ffi/__init__.py +44 -0
- bethkit/_ffi/_loader.py +568 -0
- bethkit/_ffi/_types.py +97 -0
- bethkit/archive/__init__.py +16 -0
- bethkit/archive/archive.py +694 -0
- bethkit/enums.py +139 -0
- bethkit/load_order.py +198 -0
- bethkit/plugin/__init__.py +22 -0
- bethkit/plugin/cache.py +251 -0
- bethkit/plugin/plugin.py +823 -0
- bethkit/plugin/writer.py +510 -0
- bethkit/py.typed +0 -0
- bethkit/schema/__init__.py +26 -0
- bethkit/schema/schema.py +472 -0
- bethkit/strings/__init__.py +13 -0
- bethkit/strings/strings.py +522 -0
- bethkit-1.0.0.dist-info/METADATA +155 -0
- bethkit-1.0.0.dist-info/RECORD +22 -0
- bethkit-1.0.0.dist-info/WHEEL +4 -0
- bethkit-1.0.0.dist-info/licenses/LICENSE +203 -0
bethkit/plugin/writer.py
ADDED
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright (c) Modding Forge
|
|
3
|
+
"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import ctypes
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from .. import _ffi
|
|
10
|
+
from .._error import BethkitClosedError, BethkitOwnershipError
|
|
11
|
+
from ..enums import Game
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _sig_buf(sig: bytes | str) -> ctypes.Array[ctypes.c_uint8]:
|
|
15
|
+
"""
|
|
16
|
+
Convert a 4-byte signature to a ctypes ``c_uint8`` array.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
sig (bytes | str): Four-byte ASCII signature.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
ctypes.Array: A ``c_uint8[4]`` array containing the signature.
|
|
23
|
+
|
|
24
|
+
Raises:
|
|
25
|
+
ValueError: If *sig* is not exactly 4 bytes.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
if isinstance(sig, str):
|
|
29
|
+
sig = sig.encode("ascii")
|
|
30
|
+
if len(sig) != 4:
|
|
31
|
+
raise ValueError("signature must be exactly 4 bytes")
|
|
32
|
+
return (ctypes.c_uint8 * 4)(*sig)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class WritableRecord:
|
|
36
|
+
"""
|
|
37
|
+
A plugin record under construction.
|
|
38
|
+
|
|
39
|
+
Create via :meth:`new`, add sub-records with :meth:`add_subrecord`,
|
|
40
|
+
then hand the record off to a :class:`WritableGroup` with
|
|
41
|
+
:meth:`WritableGroup.add_record`. Ownership transfers on that call
|
|
42
|
+
and this wrapper becomes invalid.
|
|
43
|
+
|
|
44
|
+
Use as a context manager to free the handle if the record is never
|
|
45
|
+
added to a group::
|
|
46
|
+
|
|
47
|
+
with WritableRecord.new(b"NPC_") as rec:
|
|
48
|
+
rec.add_subrecord(b"EDID", b"MyNPC\x00")
|
|
49
|
+
group.add_record(rec)
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
__ptr: int
|
|
53
|
+
|
|
54
|
+
def __init__(self, ptr: int) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Args:
|
|
57
|
+
ptr (int): Native handle returned by the FFI new call.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
self.__ptr = ptr
|
|
61
|
+
|
|
62
|
+
def __check_open(self) -> int:
|
|
63
|
+
"""
|
|
64
|
+
Return the native pointer, raising if the handle has been closed.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
int: Valid native pointer.
|
|
68
|
+
|
|
69
|
+
Raises:
|
|
70
|
+
BethkitClosedError: If the record has been closed or transferred.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
if not self.__ptr:
|
|
74
|
+
raise BethkitClosedError("WritableRecord is closed or transferred")
|
|
75
|
+
return self.__ptr
|
|
76
|
+
|
|
77
|
+
def _transfer_ptr(self) -> int:
|
|
78
|
+
"""
|
|
79
|
+
Transfer ownership to the caller.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
int: The raw native pointer.
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
BethkitOwnershipError: If the record has already been transferred
|
|
86
|
+
or closed.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
if not self.__ptr:
|
|
90
|
+
raise BethkitOwnershipError(
|
|
91
|
+
"WritableRecord has already been transferred or closed"
|
|
92
|
+
)
|
|
93
|
+
ptr = self.__ptr
|
|
94
|
+
self.__ptr = 0
|
|
95
|
+
return ptr
|
|
96
|
+
|
|
97
|
+
@classmethod
|
|
98
|
+
def new(
|
|
99
|
+
cls,
|
|
100
|
+
signature: bytes | str,
|
|
101
|
+
flags: int = 0,
|
|
102
|
+
form_id: int = 0,
|
|
103
|
+
form_version: int = 44,
|
|
104
|
+
) -> WritableRecord:
|
|
105
|
+
"""
|
|
106
|
+
Create a new writable record with the given header fields.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
signature (bytes | str): Four-byte record type signature.
|
|
110
|
+
flags (int): Record header flags bitmask. Defaults to ``0``.
|
|
111
|
+
form_id (int): Raw FormID. Defaults to ``0``.
|
|
112
|
+
form_version (int): Form version. Defaults to ``44``.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
WritableRecord: A new, empty record.
|
|
116
|
+
|
|
117
|
+
Raises:
|
|
118
|
+
BethkitNativeError: If the native record cannot be created.
|
|
119
|
+
ValueError: If *signature* is not exactly 4 bytes.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
buf = _sig_buf(signature)
|
|
123
|
+
lib = _ffi.load_lib()
|
|
124
|
+
ptr = lib.bethkit_writable_record_new(
|
|
125
|
+
buf, flags, form_id, form_version
|
|
126
|
+
)
|
|
127
|
+
if not ptr:
|
|
128
|
+
_ffi.raise_last_error(lib)
|
|
129
|
+
return cls(ptr)
|
|
130
|
+
|
|
131
|
+
def close(self) -> None:
|
|
132
|
+
"""
|
|
133
|
+
Release the native record handle.
|
|
134
|
+
|
|
135
|
+
Safe to call multiple times; subsequent calls are no-ops.
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
if self.__ptr:
|
|
139
|
+
_ffi.load_lib().bethkit_writable_record_free(self.__ptr)
|
|
140
|
+
self.__ptr = 0
|
|
141
|
+
|
|
142
|
+
def __enter__(self) -> WritableRecord:
|
|
143
|
+
"""Return *self* for use as a context manager."""
|
|
144
|
+
|
|
145
|
+
return self
|
|
146
|
+
|
|
147
|
+
def __exit__(self, *_: object) -> None:
|
|
148
|
+
"""Free the record when exiting the context."""
|
|
149
|
+
|
|
150
|
+
self.close()
|
|
151
|
+
|
|
152
|
+
def __del__(self) -> None:
|
|
153
|
+
"""Free the native handle on garbage collection."""
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
self.close()
|
|
157
|
+
except Exception:
|
|
158
|
+
pass
|
|
159
|
+
|
|
160
|
+
def add_subrecord(
|
|
161
|
+
self, signature: bytes | str, data: bytes
|
|
162
|
+
) -> None:
|
|
163
|
+
"""
|
|
164
|
+
Append a sub-record to this record.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
signature (bytes | str): Four-byte sub-record type signature.
|
|
168
|
+
data (bytes): Raw sub-record payload.
|
|
169
|
+
|
|
170
|
+
Raises:
|
|
171
|
+
BethkitClosedError: If the record has been closed or transferred.
|
|
172
|
+
BethkitNativeError: If the native call fails.
|
|
173
|
+
ValueError: If *signature* is not exactly 4 bytes.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
lib = _ffi.load_lib()
|
|
177
|
+
sig_buf = _sig_buf(signature)
|
|
178
|
+
data_buf = (ctypes.c_uint8 * len(data)).from_buffer_copy(data)
|
|
179
|
+
if (
|
|
180
|
+
lib.bethkit_writable_record_add_subrecord(
|
|
181
|
+
self.__check_open(), sig_buf, data_buf, len(data)
|
|
182
|
+
)
|
|
183
|
+
!= 0
|
|
184
|
+
):
|
|
185
|
+
_ffi.raise_last_error(lib)
|
|
186
|
+
|
|
187
|
+
def __repr__(self) -> str:
|
|
188
|
+
"""
|
|
189
|
+
Returns:
|
|
190
|
+
str: Developer-friendly representation with native pointer.
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
if not self.__ptr:
|
|
194
|
+
return "<WritableRecord transferred>"
|
|
195
|
+
return f"<WritableRecord ptr=0x{self.__ptr:016X}>"
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class WritableGroup:
|
|
199
|
+
"""
|
|
200
|
+
A plugin group under construction.
|
|
201
|
+
|
|
202
|
+
Add records with :meth:`add_record` and sub-groups with
|
|
203
|
+
:meth:`add_group`, then hand the group off to a
|
|
204
|
+
:class:`PluginWriter` with :meth:`PluginWriter.add_group`.
|
|
205
|
+
Ownership transfers on that call.
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
__ptr: int
|
|
209
|
+
|
|
210
|
+
def __init__(self, ptr: int) -> None:
|
|
211
|
+
"""
|
|
212
|
+
Args:
|
|
213
|
+
ptr (int): Native handle returned by the FFI new call.
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
self.__ptr = ptr
|
|
217
|
+
|
|
218
|
+
def __check_open(self) -> int:
|
|
219
|
+
"""
|
|
220
|
+
Return the native pointer, raising if the handle has been closed.
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
int: Valid native pointer.
|
|
224
|
+
|
|
225
|
+
Raises:
|
|
226
|
+
BethkitClosedError: If the group has been closed or transferred.
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
if not self.__ptr:
|
|
230
|
+
raise BethkitClosedError("WritableGroup is closed or transferred")
|
|
231
|
+
return self.__ptr
|
|
232
|
+
|
|
233
|
+
def _transfer_ptr(self) -> int:
|
|
234
|
+
"""
|
|
235
|
+
Transfer ownership to the caller.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
int: The raw native pointer.
|
|
239
|
+
|
|
240
|
+
Raises:
|
|
241
|
+
BethkitOwnershipError: If the group has already been transferred
|
|
242
|
+
or closed.
|
|
243
|
+
"""
|
|
244
|
+
|
|
245
|
+
if not self.__ptr:
|
|
246
|
+
raise BethkitOwnershipError(
|
|
247
|
+
"WritableGroup has already been transferred or closed"
|
|
248
|
+
)
|
|
249
|
+
ptr = self.__ptr
|
|
250
|
+
self.__ptr = 0
|
|
251
|
+
return ptr
|
|
252
|
+
|
|
253
|
+
@classmethod
|
|
254
|
+
def new(
|
|
255
|
+
cls, label: bytes | str, group_type: int = 0
|
|
256
|
+
) -> WritableGroup:
|
|
257
|
+
"""
|
|
258
|
+
Create a new writable group.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
label (bytes | str): Four-byte group label (top-level
|
|
262
|
+
groups use a record-type signature).
|
|
263
|
+
group_type (int): Numeric group type. Defaults to ``0``
|
|
264
|
+
(top-level).
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
WritableGroup: A new, empty group.
|
|
268
|
+
|
|
269
|
+
Raises:
|
|
270
|
+
BethkitNativeError: If the native group cannot be created.
|
|
271
|
+
ValueError: If *label* is not exactly 4 bytes.
|
|
272
|
+
"""
|
|
273
|
+
|
|
274
|
+
lib = _ffi.load_lib()
|
|
275
|
+
buf = _sig_buf(label)
|
|
276
|
+
ptr = lib.bethkit_writable_group_new(buf, group_type)
|
|
277
|
+
if not ptr:
|
|
278
|
+
_ffi.raise_last_error(lib)
|
|
279
|
+
return cls(ptr)
|
|
280
|
+
|
|
281
|
+
def close(self) -> None:
|
|
282
|
+
"""
|
|
283
|
+
Release the native group handle.
|
|
284
|
+
|
|
285
|
+
Safe to call multiple times; subsequent calls are no-ops.
|
|
286
|
+
"""
|
|
287
|
+
|
|
288
|
+
if self.__ptr:
|
|
289
|
+
_ffi.load_lib().bethkit_writable_group_free(self.__ptr)
|
|
290
|
+
self.__ptr = 0
|
|
291
|
+
|
|
292
|
+
def __enter__(self) -> WritableGroup:
|
|
293
|
+
"""Return *self* for use as a context manager."""
|
|
294
|
+
|
|
295
|
+
return self
|
|
296
|
+
|
|
297
|
+
def __exit__(self, *_: object) -> None:
|
|
298
|
+
"""Free the group when exiting the context."""
|
|
299
|
+
|
|
300
|
+
self.close()
|
|
301
|
+
|
|
302
|
+
def __del__(self) -> None:
|
|
303
|
+
"""Free the native handle on garbage collection."""
|
|
304
|
+
|
|
305
|
+
try:
|
|
306
|
+
self.close()
|
|
307
|
+
except Exception:
|
|
308
|
+
pass
|
|
309
|
+
|
|
310
|
+
def add_record(self, record: WritableRecord) -> None:
|
|
311
|
+
"""
|
|
312
|
+
Append a record to this group, transferring ownership.
|
|
313
|
+
|
|
314
|
+
After this call *record* is invalid.
|
|
315
|
+
|
|
316
|
+
Args:
|
|
317
|
+
record (WritableRecord): The record to add.
|
|
318
|
+
|
|
319
|
+
Raises:
|
|
320
|
+
BethkitClosedError: If this group has been closed or transferred.
|
|
321
|
+
BethkitOwnershipError: If *record* has already been transferred
|
|
322
|
+
or closed.
|
|
323
|
+
BethkitNativeError: If the native call fails.
|
|
324
|
+
"""
|
|
325
|
+
|
|
326
|
+
lib = _ffi.load_lib()
|
|
327
|
+
rec_ptr = record._transfer_ptr()
|
|
328
|
+
if lib.bethkit_writable_group_add_record(
|
|
329
|
+
self.__check_open(), rec_ptr
|
|
330
|
+
) != 0:
|
|
331
|
+
_ffi.raise_last_error(lib)
|
|
332
|
+
|
|
333
|
+
def add_group(self, child: WritableGroup) -> None:
|
|
334
|
+
"""
|
|
335
|
+
Append a sub-group to this group, transferring ownership.
|
|
336
|
+
|
|
337
|
+
After this call *child* is invalid.
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
child (WritableGroup): The sub-group to add.
|
|
341
|
+
|
|
342
|
+
Raises:
|
|
343
|
+
BethkitClosedError: If this group has been closed or transferred.
|
|
344
|
+
BethkitOwnershipError: If *child* has already been transferred
|
|
345
|
+
or closed.
|
|
346
|
+
BethkitNativeError: If the native call fails.
|
|
347
|
+
"""
|
|
348
|
+
|
|
349
|
+
lib = _ffi.load_lib()
|
|
350
|
+
child_ptr = child._transfer_ptr()
|
|
351
|
+
if lib.bethkit_writable_group_add_group(
|
|
352
|
+
self.__check_open(), child_ptr
|
|
353
|
+
) != 0:
|
|
354
|
+
_ffi.raise_last_error(lib)
|
|
355
|
+
|
|
356
|
+
def __repr__(self) -> str:
|
|
357
|
+
"""
|
|
358
|
+
Returns:
|
|
359
|
+
str: Developer-friendly representation with native pointer.
|
|
360
|
+
"""
|
|
361
|
+
|
|
362
|
+
if not self.__ptr:
|
|
363
|
+
return "<WritableGroup transferred>"
|
|
364
|
+
return f"<WritableGroup ptr=0x{self.__ptr:016X}>"
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
class PluginWriter:
|
|
368
|
+
"""
|
|
369
|
+
Assembles and serialises a complete plugin file.
|
|
370
|
+
|
|
371
|
+
Add top-level groups with :meth:`add_group`, then call
|
|
372
|
+
:meth:`write_to_file` or :meth:`write_to_bytes` to produce the
|
|
373
|
+
finished plugin.
|
|
374
|
+
"""
|
|
375
|
+
|
|
376
|
+
__ptr: int
|
|
377
|
+
|
|
378
|
+
def __init__(self, game: Game, form_version: int = 44) -> None:
|
|
379
|
+
"""
|
|
380
|
+
Args:
|
|
381
|
+
game (Game): Target game; determines the correct format.
|
|
382
|
+
form_version (int): Default form version written to record
|
|
383
|
+
headers. Defaults to ``44`` (Skyrim SE).
|
|
384
|
+
|
|
385
|
+
Raises:
|
|
386
|
+
BethkitNativeError: If the native writer cannot be created.
|
|
387
|
+
"""
|
|
388
|
+
|
|
389
|
+
lib = _ffi.load_lib()
|
|
390
|
+
ptr = lib.bethkit_plugin_writer_new(int(game), form_version)
|
|
391
|
+
if not ptr:
|
|
392
|
+
_ffi.raise_last_error(lib)
|
|
393
|
+
self.__ptr = ptr
|
|
394
|
+
|
|
395
|
+
def __check_open(self) -> int:
|
|
396
|
+
"""
|
|
397
|
+
Return the native pointer, raising if the handle has been closed.
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
int: Valid native pointer.
|
|
401
|
+
|
|
402
|
+
Raises:
|
|
403
|
+
BethkitClosedError: If the writer has been closed.
|
|
404
|
+
"""
|
|
405
|
+
|
|
406
|
+
if not self.__ptr:
|
|
407
|
+
raise BethkitClosedError("PluginWriter is closed")
|
|
408
|
+
return self.__ptr
|
|
409
|
+
|
|
410
|
+
def close(self) -> None:
|
|
411
|
+
"""
|
|
412
|
+
Release the native writer handle.
|
|
413
|
+
|
|
414
|
+
Safe to call multiple times; subsequent calls are no-ops.
|
|
415
|
+
"""
|
|
416
|
+
|
|
417
|
+
if self.__ptr:
|
|
418
|
+
_ffi.load_lib().bethkit_plugin_writer_free(self.__ptr)
|
|
419
|
+
self.__ptr = 0
|
|
420
|
+
|
|
421
|
+
def __enter__(self) -> PluginWriter:
|
|
422
|
+
"""Return *self* for use as a context manager."""
|
|
423
|
+
|
|
424
|
+
return self
|
|
425
|
+
|
|
426
|
+
def __exit__(self, *_: object) -> None:
|
|
427
|
+
"""Free the writer when exiting the context."""
|
|
428
|
+
|
|
429
|
+
self.close()
|
|
430
|
+
|
|
431
|
+
def __del__(self) -> None:
|
|
432
|
+
"""Free the native handle on garbage collection."""
|
|
433
|
+
|
|
434
|
+
try:
|
|
435
|
+
self.close()
|
|
436
|
+
except Exception:
|
|
437
|
+
pass
|
|
438
|
+
|
|
439
|
+
def add_group(self, group: WritableGroup) -> None:
|
|
440
|
+
"""
|
|
441
|
+
Append a top-level group to the plugin, transferring ownership.
|
|
442
|
+
|
|
443
|
+
After this call *group* is invalid.
|
|
444
|
+
|
|
445
|
+
Args:
|
|
446
|
+
group (WritableGroup): The group to add.
|
|
447
|
+
|
|
448
|
+
Raises:
|
|
449
|
+
BethkitClosedError: If the writer has been closed.
|
|
450
|
+
BethkitOwnershipError: If *group* has already been transferred
|
|
451
|
+
or closed.
|
|
452
|
+
BethkitNativeError: If the native call fails.
|
|
453
|
+
"""
|
|
454
|
+
|
|
455
|
+
lib = _ffi.load_lib()
|
|
456
|
+
grp_ptr = group._transfer_ptr()
|
|
457
|
+
if lib.bethkit_plugin_writer_add_group(
|
|
458
|
+
self.__check_open(), grp_ptr
|
|
459
|
+
) != 0:
|
|
460
|
+
_ffi.raise_last_error(lib)
|
|
461
|
+
|
|
462
|
+
def write_to_file(self, path: Path) -> None:
|
|
463
|
+
"""
|
|
464
|
+
Serialise and write the plugin to *path* on disk.
|
|
465
|
+
|
|
466
|
+
Args:
|
|
467
|
+
path (Path): Destination file path.
|
|
468
|
+
|
|
469
|
+
Raises:
|
|
470
|
+
BethkitClosedError: If the writer has been closed.
|
|
471
|
+
BethkitNativeError: If serialisation or the write fails.
|
|
472
|
+
"""
|
|
473
|
+
|
|
474
|
+
lib = _ffi.load_lib()
|
|
475
|
+
if lib.bethkit_plugin_writer_write_to_file(
|
|
476
|
+
self.__check_open(), _ffi.enc(path)
|
|
477
|
+
) != 0:
|
|
478
|
+
_ffi.raise_last_error(lib)
|
|
479
|
+
|
|
480
|
+
def write_to_bytes(self) -> bytes:
|
|
481
|
+
"""
|
|
482
|
+
Serialise the plugin and return it as a byte buffer.
|
|
483
|
+
|
|
484
|
+
Returns:
|
|
485
|
+
bytes: Complete serialised plugin data.
|
|
486
|
+
|
|
487
|
+
Raises:
|
|
488
|
+
BethkitClosedError: If the writer has been closed.
|
|
489
|
+
BethkitNativeError: If serialisation fails.
|
|
490
|
+
"""
|
|
491
|
+
|
|
492
|
+
lib = _ffi.load_lib()
|
|
493
|
+
out_len = ctypes.c_size_t(0)
|
|
494
|
+
ptr = lib.bethkit_plugin_writer_write_to_bytes(
|
|
495
|
+
self.__check_open(), ctypes.byref(out_len)
|
|
496
|
+
)
|
|
497
|
+
if not ptr:
|
|
498
|
+
_ffi.raise_last_error(lib)
|
|
499
|
+
try:
|
|
500
|
+
return bytes(ctypes.string_at(ptr, out_len.value))
|
|
501
|
+
finally:
|
|
502
|
+
lib.bethkit_bytes_free(ptr, out_len.value)
|
|
503
|
+
|
|
504
|
+
def __repr__(self) -> str:
|
|
505
|
+
"""
|
|
506
|
+
Returns:
|
|
507
|
+
str: Developer-friendly representation of the writer.
|
|
508
|
+
"""
|
|
509
|
+
|
|
510
|
+
return "<PluginWriter>"
|
bethkit/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Copyright (c) Modding Forge
|
|
3
|
+
|
|
4
|
+
Schema subpackage — schema-driven record field decoding and type information.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from .schema import (
|
|
9
|
+
EnumVal,
|
|
10
|
+
FieldValue,
|
|
11
|
+
FlagsVal,
|
|
12
|
+
NamedField,
|
|
13
|
+
RecordView,
|
|
14
|
+
SchemaRegistry,
|
|
15
|
+
TypedFormId,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"EnumVal",
|
|
20
|
+
"FieldValue",
|
|
21
|
+
"FlagsVal",
|
|
22
|
+
"NamedField",
|
|
23
|
+
"RecordView",
|
|
24
|
+
"SchemaRegistry",
|
|
25
|
+
"TypedFormId",
|
|
26
|
+
]
|