PyREUser3 0.6.0__tar.gz → 0.7.1__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 (53) hide show
  1. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/PKG-INFO +24 -1
  2. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/PyREUser3.egg-info/PKG-INFO +24 -1
  3. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/PyREUser3.egg-info/SOURCES.txt +5 -1
  4. pyreuser3-0.7.1/README.md +269 -0
  5. pyreuser3-0.7.1/docs/PYPI.md +63 -0
  6. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/docs/README.zh-CN.md +95 -6
  7. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyproject.toml +1 -1
  8. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/__init__.py +9 -0
  9. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/api.py +138 -19
  10. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/cli.py +62 -6
  11. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/core.py +5 -2
  12. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/export/base.py +34 -11
  13. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/export/fields.py +79 -4
  14. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/export/metadata.py +13 -7
  15. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/export/user3.py +155 -97
  16. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/pack/base.py +78 -21
  17. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/pack/models.py +54 -0
  18. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/pack/plan.py +318 -9
  19. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/pack/writer.py +348 -41
  20. pyreuser3-0.7.1/pyreuser3/usr_container.py +619 -0
  21. pyreuser3-0.7.1/pyreuser3/usr_layouts.py +368 -0
  22. pyreuser3-0.7.1/tests/test_api_cache.py +120 -0
  23. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/tests/test_enum_binary.py +1 -0
  24. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/tests/test_enum_codec.py +11 -3
  25. pyreuser3-0.7.1/tests/test_usr_container.py +780 -0
  26. pyreuser3-0.6.0/README.md +0 -165
  27. pyreuser3-0.6.0/docs/PYPI.md +0 -40
  28. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/LICENSE +0 -0
  29. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/MANIFEST.in +0 -0
  30. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/PyREUser3.egg-info/dependency_links.txt +0 -0
  31. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/PyREUser3.egg-info/entry_points.txt +0 -0
  32. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/PyREUser3.egg-info/requires.txt +0 -0
  33. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/PyREUser3.egg-info/top_level.txt +0 -0
  34. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/__main__.py +0 -0
  35. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/enum_codec.py +0 -0
  36. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/export/__init__.py +0 -0
  37. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/export/enums.py +0 -0
  38. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/export/postprocess.py +0 -0
  39. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/export/tree.py +0 -0
  40. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/pack/__init__.py +0 -0
  41. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/rich_ui.py +0 -0
  42. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/schema.py +0 -0
  43. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/web/__init__.py +0 -0
  44. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/web/__main__.py +0 -0
  45. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/web/handler.py +0 -0
  46. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/web/jobs.py +0 -0
  47. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/web/page.py +0 -0
  48. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/web/picker.py +0 -0
  49. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/web/runners.py +0 -0
  50. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/web/server.py +0 -0
  51. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/pyreuser3/web/settings.py +0 -0
  52. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/setup.cfg +0 -0
  53. {pyreuser3-0.6.0 → pyreuser3-0.7.1}/tests/test_export_enums.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyREUser3
3
- Version: 0.6.0
3
+ Version: 0.7.1
4
4
  Summary: Pure Python tools for converting RE Engine .user.3 files to and from JSON.
5
5
  Author: Egg Targaryen
6
6
  License-Expression: MIT
@@ -47,12 +47,33 @@ pip install pyreuser3
47
47
  - `JSON -> .user.3` packing.
48
48
  - A reusable Python API through `REUser3Converter`.
49
49
  - CLI commands through `pyreuser3`.
50
+ - Schema-free layout probing through `pyreuser3 probe` and the public probe API.
50
51
  - A local `.user.3` export Web UI through `pyreuser3-web`.
52
+ - Automatic separation of the USR outer layout from the embedded RSZ header family;
53
+ modern RSZ v4+ files preserve their original numeric version during repack.
51
54
 
52
55
  The published package intentionally does not include game resources, dumped game data, RE_RSZ templates,
53
56
  `il2cpp_dump.json`, or repository-specific helper scripts. You need to provide data files that match the target game and
54
57
  version.
55
58
 
59
+ Verified H30/modern layouts support repacking. Experimental physical H28 and legacy
60
+ RSZ v3 layouts are readable for analysis but intentionally blocked from repacking
61
+ until real fixtures provide byte-for-byte validation.
62
+
63
+ Version 0.7.1 fixes the 0.7.0 modern RSZ alignment regression. Modern userdata and
64
+ data targets use absolute 16-byte file alignment even though their stored offsets
65
+ remain RSZ-relative. Readable parsing accepts alignment-only deviations without
66
+ hiding structural corruption, while the probe API reports them explicitly. Repack
67
+ output blocks layouts carrying unverified diagnostics. The strict schema-free
68
+ probe can validate large local corpora.
69
+
70
+ Repeated operations on one `REUser3Converter` reuse schema and il2cpp metadata,
71
+ with automatic file-signature invalidation and an explicit
72
+ `clear_metadata_cache()` escape hatch. Batch patching reuses one exporter and
73
+ packer. Signed `-1` null object references and very large fixed-width arrays are
74
+ preserved losslessly; large arrays use a compact raw payload instead of millions
75
+ of Python scalar objects.
76
+
56
77
  ## Requirements
57
78
 
58
79
  - Python 3.9 or newer.
@@ -60,6 +81,8 @@ version.
60
81
  - An `il2cpp_dump.json` file when exporting readable enum labels.
61
82
  - One or more unpacked `.user.3` files.
62
83
 
84
+ `pyreuser3 probe` does not require a schema or `il2cpp_dump.json`.
85
+
63
86
  ## Usage
64
87
 
65
88
  Usage details may change as the package evolves. For the latest command-line and Python API examples, read the GitHub README:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyREUser3
3
- Version: 0.6.0
3
+ Version: 0.7.1
4
4
  Summary: Pure Python tools for converting RE Engine .user.3 files to and from JSON.
5
5
  Author: Egg Targaryen
6
6
  License-Expression: MIT
@@ -47,12 +47,33 @@ pip install pyreuser3
47
47
  - `JSON -> .user.3` packing.
48
48
  - A reusable Python API through `REUser3Converter`.
49
49
  - CLI commands through `pyreuser3`.
50
+ - Schema-free layout probing through `pyreuser3 probe` and the public probe API.
50
51
  - A local `.user.3` export Web UI through `pyreuser3-web`.
52
+ - Automatic separation of the USR outer layout from the embedded RSZ header family;
53
+ modern RSZ v4+ files preserve their original numeric version during repack.
51
54
 
52
55
  The published package intentionally does not include game resources, dumped game data, RE_RSZ templates,
53
56
  `il2cpp_dump.json`, or repository-specific helper scripts. You need to provide data files that match the target game and
54
57
  version.
55
58
 
59
+ Verified H30/modern layouts support repacking. Experimental physical H28 and legacy
60
+ RSZ v3 layouts are readable for analysis but intentionally blocked from repacking
61
+ until real fixtures provide byte-for-byte validation.
62
+
63
+ Version 0.7.1 fixes the 0.7.0 modern RSZ alignment regression. Modern userdata and
64
+ data targets use absolute 16-byte file alignment even though their stored offsets
65
+ remain RSZ-relative. Readable parsing accepts alignment-only deviations without
66
+ hiding structural corruption, while the probe API reports them explicitly. Repack
67
+ output blocks layouts carrying unverified diagnostics. The strict schema-free
68
+ probe can validate large local corpora.
69
+
70
+ Repeated operations on one `REUser3Converter` reuse schema and il2cpp metadata,
71
+ with automatic file-signature invalidation and an explicit
72
+ `clear_metadata_cache()` escape hatch. Batch patching reuses one exporter and
73
+ packer. Signed `-1` null object references and very large fixed-width arrays are
74
+ preserved losslessly; large arrays use a compact raw payload instead of millions
75
+ of Python scalar objects.
76
+
56
77
  ## Requirements
57
78
 
58
79
  - Python 3.9 or newer.
@@ -60,6 +81,8 @@ version.
60
81
  - An `il2cpp_dump.json` file when exporting readable enum labels.
61
82
  - One or more unpacked `.user.3` files.
62
83
 
84
+ `pyreuser3 probe` does not require a schema or `il2cpp_dump.json`.
85
+
63
86
  ## Usage
64
87
 
65
88
  Usage details may change as the package evolves. For the latest command-line and Python API examples, read the GitHub README:
@@ -18,6 +18,8 @@ pyreuser3/core.py
18
18
  pyreuser3/enum_codec.py
19
19
  pyreuser3/rich_ui.py
20
20
  pyreuser3/schema.py
21
+ pyreuser3/usr_container.py
22
+ pyreuser3/usr_layouts.py
21
23
  pyreuser3/export/__init__.py
22
24
  pyreuser3/export/base.py
23
25
  pyreuser3/export/enums.py
@@ -40,6 +42,8 @@ pyreuser3/web/picker.py
40
42
  pyreuser3/web/runners.py
41
43
  pyreuser3/web/server.py
42
44
  pyreuser3/web/settings.py
45
+ tests/test_api_cache.py
43
46
  tests/test_enum_binary.py
44
47
  tests/test_enum_codec.py
45
- tests/test_export_enums.py
48
+ tests/test_export_enums.py
49
+ tests/test_usr_container.py
@@ -0,0 +1,269 @@
1
+ <h1 align="center">PyREUser3</h1>
2
+
3
+ <p align="center">
4
+ English | <a href="https://github.com/dzxrly/PyREUser3/blob/main/docs/README.zh-CN.md">简体中文</a>
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="https://pypi.org/project/PyREUser3/"><img alt="PyPI Project" src="https://img.shields.io/badge/PyPI-PyREUser3-blue"></a>
9
+ <a href="https://pypi.org/project/PyREUser3/"><img alt="PyPI Version" src="https://img.shields.io/pypi/v/PyREUser3"></a>
10
+ <a href="https://pepy.tech/project/PyREUser3"><img alt="Downloads" src="https://static.pepy.tech/badge/PyREUser3"></a>
11
+ <a href="https://github.com/dzxrly/PyREUser3/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/pypi/l/PyREUser3"></a>
12
+ </p>
13
+
14
+ PyREUser3 is a pure Python package for converting RE Engine `.user.3` database files to JSON and packing compatible JSON back to `.user.3`.
15
+
16
+ Install it with:
17
+
18
+ ```bash
19
+ pip install pyreuser3
20
+ ```
21
+
22
+ Import it with the same normalized package name:
23
+
24
+ ```python
25
+ from pyreuser3 import REUser3Converter
26
+ ```
27
+
28
+ ## What Is Included
29
+
30
+ - `.user.3 -> JSON` export.
31
+ - `JSON -> .user.3` packing.
32
+ - A reusable Python API through `REUser3Converter`.
33
+ - CLI commands through `pyreuser3`.
34
+ - Schema-free layout probing for individual files and whole corpora.
35
+ - A local `.user.3` export Web UI through `pyreuser3-web`.
36
+
37
+ This PyPI package intentionally does not include game resources, dumped game data, RE_RSZ templates, `il2cpp_dump.json`,
38
+ or repository-specific helper scripts.
39
+
40
+ ## Requirements
41
+
42
+ - Python 3.9 or newer.
43
+ - A RE_RSZ schema JSON file for the target game/version.
44
+ - An `il2cpp_dump.json` file when exporting readable enum labels.
45
+ - One or more unpacked `.user.3` files.
46
+
47
+ Layout probing is the exception: `pyreuser3 probe` only inspects the USR/RSZ
48
+ container and does not require a schema or `il2cpp_dump.json`.
49
+
50
+ ## Command Line
51
+
52
+ Export `.user.3` files to JSON:
53
+
54
+ ```bash
55
+ pyreuser3 export \
56
+ -i <input-user3-file-or-directory> \
57
+ -s <RE_RSZ-schema.json> \
58
+ -o <json-output-directory> \
59
+ -p <il2cpp_dump.json>
60
+ ```
61
+
62
+ Export full repack JSON, then pack it back to `.user.3`:
63
+
64
+ ```bash
65
+ pyreuser3 export \
66
+ -i <input-user3-file-or-directory> \
67
+ -s <RE_RSZ-schema.json> \
68
+ -o <repack-json-output-directory> \
69
+ -p <il2cpp_dump.json> \
70
+ --json-format repack
71
+ ```
72
+
73
+ ```bash
74
+ pyreuser3 pack \
75
+ -j <input-repack-json-file-or-directory> \
76
+ -s <RE_RSZ-schema.json> \
77
+ -o <user3-output-directory> \
78
+ -p <il2cpp_dump.json>
79
+ ```
80
+
81
+ The `-p/--il2cpp-dump-path` option is required for export and optional for pack. Passing it during pack is recommended when enum names need to be resolved back to numeric values.
82
+
83
+ Probe a file or directory without loading game metadata:
84
+
85
+ ```bash
86
+ pyreuser3 probe -i <input-user3-file-or-directory>
87
+ pyreuser3 probe -i <input-user3-file-or-directory> --strict -o layout-report.json
88
+ ```
89
+
90
+ The default probe uses the same safety policy as readable export: structural
91
+ corruption remains fatal, while non-canonical alignment is reported as a warning.
92
+ `--strict` rejects every layout deviation and is intended for corpus validation.
93
+ The optional JSON report contains totals grouped by detected layout, RSZ version,
94
+ and diagnostic code.
95
+
96
+ Start the local `.user.3` export Web UI:
97
+
98
+ ```bash
99
+ pyreuser3-web --port 8765
100
+ ```
101
+
102
+ The Web UI only handles `.user.3` export. It does not pack files.
103
+
104
+ ## Python API
105
+
106
+ ```python
107
+ from pyreuser3 import REUser3Converter
108
+
109
+ converter = REUser3Converter(
110
+ schema_path="D:/schema/rsz_game.json",
111
+ il2cpp_dump_path="D:/game/il2cpp_dump.json",
112
+ )
113
+
114
+ converter.export_file(
115
+ "input/OtomonData.user.3",
116
+ "json/OtomonData.user.3.json",
117
+ )
118
+
119
+ # Packing only accepts the full repack document. Readable exports are read-only.
120
+ converter.export_file(
121
+ "input/OtomonData.user.3",
122
+ "json/OtomonData.user.3.pack.json",
123
+ json_format="repack",
124
+ )
125
+ converter.pack_file(
126
+ "json/OtomonData.user.3.pack.json",
127
+ "mod/OtomonData.user.3",
128
+ )
129
+ ```
130
+
131
+ `REUser3Converter` loads schema and il2cpp metadata lazily and caches it for the
132
+ lifetime of that converter. Repeated readable, repack, pack, and patch calls no
133
+ longer rescan large metadata files. Cache entries are invalidated automatically
134
+ when the source path, size, or nanosecond modification time changes; callers that
135
+ replace metadata in an unusual way can force a reload with:
136
+
137
+ ```python
138
+ converter.clear_metadata_cache()
139
+ ```
140
+
141
+ `patch_directory()` also reuses one prepared exporter and packer for the complete
142
+ batch instead of constructing them once per file.
143
+
144
+ Container layout probing is also available without constructing a converter or
145
+ loading a schema:
146
+
147
+ ```python
148
+ from pyreuser3 import probe_usr_file, probe_usr_path
149
+
150
+ one_file = probe_usr_file("input/example.user.3")
151
+ whole_tree = probe_usr_path("input/natives", policy="strict_probe")
152
+ ```
153
+
154
+ Convert a `.user.3` file to an in-memory JSON-compatible Python object without writing a JSON file:
155
+
156
+ ```python
157
+ readable_data = converter.user3_to_json(
158
+ "input/OtomonData.user.3",
159
+ json_format="readable",
160
+ )
161
+
162
+ repack_data = converter.user3_to_json(
163
+ "input/OtomonData.user.3",
164
+ json_format="repack",
165
+ )
166
+ ```
167
+
168
+ Use `json_format="readable"` for the same shape produced by `export_file()`. This
169
+ shape is read-only. Use `json_format="repack"` for the full document accepted by
170
+ `pack()`; the packer rejects readable JSON.
171
+
172
+ Enum fields are rendered as `[numeric] Name` labels using the enum's actual storage
173
+ width. Scalar flag enums are rendered as arrays of labels. ``ace.Bitset`1<T>`` values are
174
+ rendered as enum-index labels together with `_MaxElement` and `_WordCount`, so unknown
175
+ bits and padded word arrays remain reversible. Repack exports use
176
+ `re_user3_pack_v3`, which records the independently detected USR outer layout, RSZ
177
+ header family, and numeric RSZ version while preserving resource and userdata
178
+ dependency tables. Layout candidates and their read/repack capability status are
179
+ declared in `pyreuser3/usr_layouts.py`; RSZ field definitions still come from the
180
+ supplied REFramework-compatible schema. The verified modern header family accepts
181
+ structurally valid RSZ v4+ files and preserves their original version instead of
182
+ forcing MHWS version 16. For this family, offset values remain relative to the RSZ
183
+ section, but the userdata and data targets are aligned to absolute 16-byte file
184
+ positions. Readable export accepts alignment-only deviations, and the probe API
185
+ reports them as structured warnings. Repack export records the same diagnostics in
186
+ `_warnings` and blocks packing through `_unsupported` until the layout is verified.
187
+ Experimental physical H28 and legacy RSZ v3 candidates are read-only until real
188
+ fixtures validate byte-for-byte repacking. V1 and v2 documents are recognized for
189
+ diagnostics but must be re-exported as v3 before packing because they do not record
190
+ the required layout metadata.
191
+
192
+ Modern files may use signed `-1` as an explicit null `Object` reference; repack
193
+ preserves that sentinel while continuing to reject every other missing instance
194
+ ID. Fixed-width arrays above one million elements are kept compactly as
195
+ `_raw_array_count` plus `_raw_array_hex`. This representation is intentionally
196
+ opaque but lossless, avoids expanding millions of Python integers, and validates
197
+ the count/payload length before packing.
198
+
199
+ For stable patch-and-repack workflows, use `patch_file()` or `parse_pack_file()`:
200
+
201
+ ```python
202
+ from pyreuser3 import REUser3Converter
203
+
204
+ converter = REUser3Converter(
205
+ schema_path="D:/schema/rsz_game.json",
206
+ il2cpp_dump_path="D:/game/il2cpp_dump.json",
207
+ )
208
+
209
+ def patch(data, source_path):
210
+ # Modify the full instance-table JSON in place.
211
+ return None
212
+
213
+ converter.patch_file(
214
+ "input/example.user.3",
215
+ "output/example.user.3",
216
+ patch,
217
+ )
218
+ ```
219
+
220
+ ## Compatibility Validation
221
+
222
+ The repository includes a schema-free corpus runner. Game files are not committed;
223
+ point it at a locally unpacked `natives` tree:
224
+
225
+ ```bash
226
+ python tests/corpus_probe.py D:/game/natives \
227
+ --expected-total 62768 \
228
+ --expected-version 16 \
229
+ --report layout-report.json
230
+ ```
231
+
232
+ Version 0.7.1 fixes modern RSZ alignment regression found in 0.7.0 and folds the
233
+ planned compatibility work into the bug-fix release: staged layout detection,
234
+ structured diagnostics, safe readable parsing, verified-only repacking, and the
235
+ schema-free probe command. The modern rule was validated against 62,768 MHWS
236
+ `.user.3` files; four SystemSetting fixtures additionally passed readable export,
237
+ repack export, byte-identical packing, and reparse checks.
238
+
239
+ A second corpus from Monster Hunter Stories 3 was also validated: all 42,945 files
240
+ passed strict layout detection and schema-driven repack export. All 42,945 rebuilt
241
+ without exceptions; 38,548 were byte-identical. The remaining 4,397 are successful
242
+ rebuilds but not byte-identical; observed causes include nonzero padding and
243
+ alternate empty-string encodings, so they are not claimed as byte-identical
244
+ fixtures. Two voxel files use the compact large-array representation; both rebuilt
245
+ byte-identically, including the 6.55 MB `dg100_Root` payload.
246
+
247
+ ## Build From Source
248
+
249
+ ```bash
250
+ python -m pip install -U build twine
251
+ python -m build
252
+ python -m twine check dist/*
253
+ ```
254
+
255
+ Upload to TestPyPI first:
256
+
257
+ ```bash
258
+ python -m twine upload -r testpypi dist/*
259
+ ```
260
+
261
+ Then upload the same checked distribution files to PyPI:
262
+
263
+ ```bash
264
+ python -m twine upload dist/*
265
+ ```
266
+
267
+ ## License
268
+
269
+ MIT License.
@@ -0,0 +1,63 @@
1
+ # PyREUser3
2
+
3
+ PyREUser3 is a pure Python package for converting RE Engine `.user.3` database files to JSON and packing compatible JSON back to `.user.3`.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install pyreuser3
9
+ ```
10
+
11
+ ## What Is Included
12
+
13
+ - `.user.3 -> JSON` export.
14
+ - `JSON -> .user.3` packing.
15
+ - A reusable Python API through `REUser3Converter`.
16
+ - CLI commands through `pyreuser3`.
17
+ - Schema-free layout probing through `pyreuser3 probe` and the public probe API.
18
+ - A local `.user.3` export Web UI through `pyreuser3-web`.
19
+ - Automatic separation of the USR outer layout from the embedded RSZ header family;
20
+ modern RSZ v4+ files preserve their original numeric version during repack.
21
+
22
+ The published package intentionally does not include game resources, dumped game data, RE_RSZ templates,
23
+ `il2cpp_dump.json`, or repository-specific helper scripts. You need to provide data files that match the target game and
24
+ version.
25
+
26
+ Verified H30/modern layouts support repacking. Experimental physical H28 and legacy
27
+ RSZ v3 layouts are readable for analysis but intentionally blocked from repacking
28
+ until real fixtures provide byte-for-byte validation.
29
+
30
+ Version 0.7.1 fixes the 0.7.0 modern RSZ alignment regression. Modern userdata and
31
+ data targets use absolute 16-byte file alignment even though their stored offsets
32
+ remain RSZ-relative. Readable parsing accepts alignment-only deviations without
33
+ hiding structural corruption, while the probe API reports them explicitly. Repack
34
+ output blocks layouts carrying unverified diagnostics. The strict schema-free
35
+ probe can validate large local corpora.
36
+
37
+ Repeated operations on one `REUser3Converter` reuse schema and il2cpp metadata,
38
+ with automatic file-signature invalidation and an explicit
39
+ `clear_metadata_cache()` escape hatch. Batch patching reuses one exporter and
40
+ packer. Signed `-1` null object references and very large fixed-width arrays are
41
+ preserved losslessly; large arrays use a compact raw payload instead of millions
42
+ of Python scalar objects.
43
+
44
+ ## Requirements
45
+
46
+ - Python 3.9 or newer.
47
+ - A RE_RSZ schema JSON file for the target game/version.
48
+ - An `il2cpp_dump.json` file when exporting readable enum labels.
49
+ - One or more unpacked `.user.3` files.
50
+
51
+ `pyreuser3 probe` does not require a schema or `il2cpp_dump.json`.
52
+
53
+ ## Usage
54
+
55
+ Usage details may change as the package evolves. For the latest command-line and Python API examples, read the GitHub README:
56
+
57
+ https://github.com/dzxrly/PyREUser3#readme
58
+
59
+ ## Links
60
+
61
+ - Homepage: https://github.com/dzxrly/PyREUser3
62
+ - Issues: https://github.com/dzxrly/PyREUser3/issues
63
+ - License: MIT License
@@ -33,6 +33,7 @@ PyREUser3 当前提供:
33
33
  - `JSON -> .user.3` 封包;
34
34
  - 面向其他项目调用的 `REUser3Converter` Python API;
35
35
  - `pyreuser3` 命令行工具;
36
+ - 无需 schema 的单文件与整批布局探测;
36
37
  - `pyreuser3-web` 本地 Web 导出界面。
37
38
 
38
39
  PyPI 包不会包含游戏资源、游戏 dump、RE_RSZ 模板、`il2cpp_dump.json`、或特定仓库脚本。调用方需要自己准备与目标游戏版本匹配的数据文件。
@@ -44,6 +45,9 @@ PyPI 包不会包含游戏资源、游戏 dump、RE_RSZ 模板、`il2cpp_dump.js
44
45
  - 导出可读枚举标签时需要 `il2cpp_dump.json`;
45
46
  - 一个或多个已解包的 `.user.3` 文件。
46
47
 
48
+ 布局探测是例外:`pyreuser3 probe` 只检查 USR/RSZ 容器,不需要 schema 或
49
+ `il2cpp_dump.json`。
50
+
47
51
  ## 命令行使用
48
52
 
49
53
  导出 `.user.3` 为 JSON:
@@ -56,11 +60,20 @@ pyreuser3 export \
56
60
  -p <il2cpp_dump.json>
57
61
  ```
58
62
 
59
- JSON 封回 `.user.3`:
63
+ 导出完整 repack JSON,然后封回 `.user.3`:
64
+
65
+ ```bash
66
+ pyreuser3 export \
67
+ -i <输入的-user3-文件或目录> \
68
+ -s <RE_RSZ-schema.json> \
69
+ -o <repack-JSON-输出目录> \
70
+ -p <il2cpp_dump.json> \
71
+ --json-format repack
72
+ ```
60
73
 
61
74
  ```bash
62
75
  pyreuser3 pack \
63
- -j <输入的-JSON-文件或目录> \
76
+ -j <输入的-repack-JSON-文件或目录> \
64
77
  -s <RE_RSZ-schema.json> \
65
78
  -o <user3-输出目录> \
66
79
  -p <il2cpp_dump.json>
@@ -73,6 +86,17 @@ pyreuser3 pack \
73
86
  - `-s/--schema-path` 必须指向具体 schema JSON 文件,不应传目录;
74
87
  - `-i`、`-j` 都可以传单个文件或目录,目录会递归处理。
75
88
 
89
+ 无需加载游戏元数据即可探测单个文件或整个目录:
90
+
91
+ ```bash
92
+ pyreuser3 probe -i <输入的-user3-文件或目录>
93
+ pyreuser3 probe -i <输入的-user3-文件或目录> --strict -o layout-report.json
94
+ ```
95
+
96
+ 默认探测采用与 readable 导出相同的安全策略:结构损坏仍会直接失败,只有非规范对齐会记录为
97
+ 警告。`--strict` 会拒绝任何布局偏差,适合整批语料验证。可选的 JSON 报告会按布局、RSZ
98
+ 版本和诊断代码汇总结果。
99
+
76
100
  可用 `--user-magic` 和 `--rsz-magic` 覆盖默认 magic,例如:
77
101
 
78
102
  ```bash
@@ -118,12 +142,39 @@ converter.export_file(
118
142
  "json/OtomonData.user.3.json",
119
143
  )
120
144
 
145
+ # 封包只接受完整 repack 文档;readable 导出仅供读取。
146
+ converter.export_file(
147
+ "input/OtomonData.user.3",
148
+ "json/OtomonData.user.3.pack.json",
149
+ json_format="repack",
150
+ )
121
151
  converter.pack_file(
122
- "json/OtomonData.user.3.json",
152
+ "json/OtomonData.user.3.pack.json",
123
153
  "mod/OtomonData.user.3",
124
154
  )
125
155
  ```
126
156
 
157
+ `REUser3Converter` 会延迟加载 schema 和 il2cpp metadata,并在该 converter 的生命周期内复用。
158
+ 连续执行 readable、repack、pack 或 patch 时,不再反复扫描大型 metadata 文件。源文件的绝对
159
+ 路径、大小或纳秒修改时间变化后缓存会自动失效;如果调用方以特殊方式原地替换文件,也可以强制
160
+ 清理:
161
+
162
+ ```python
163
+ converter.clear_metadata_cache()
164
+ ```
165
+
166
+ `patch_directory()` 现在也会让整批文件复用同一个已准备好的 exporter 和 packer,不再为每个
167
+ 文件重复构造。
168
+
169
+ 也可以不创建 converter、不加载 schema,直接调用容器布局探测 API:
170
+
171
+ ```python
172
+ from pyreuser3 import probe_usr_file, probe_usr_path
173
+
174
+ one_file = probe_usr_file("input/example.user.3")
175
+ whole_tree = probe_usr_path("input/natives", policy="strict_probe")
176
+ ```
177
+
127
178
  不写入 JSON 文件,直接把 `.user.3` 转成内存中的 JSON 兼容 Python 对象:
128
179
 
129
180
  ```python
@@ -138,12 +189,26 @@ repack_data = converter.user3_to_json(
138
189
  )
139
190
  ```
140
191
 
141
- 使用 `json_format="readable"` 时返回与 `export_file()` 一致的可读导出结构;使用 `json_format="repack"` 时返回可传给 `pack()` 的完整实例表结构。
192
+ 使用 `json_format="readable"` 时返回与 `export_file()` 一致的只读导出结构;使用
193
+ `json_format="repack"` 时返回可传给 `pack()` 的完整实例表结构。封回器会拒绝 readable JSON。
142
194
 
143
195
  枚举字段会按照真实底层存储宽度输出为 `[数值] 名称`。标量位标志枚举输出为标签数组;
144
196
  ``ace.Bitset`1<T>`` 输出为枚举索引标签,并保留 `_MaxElement` 与 `_WordCount`,因此未知位和
145
- 填充词也可以无损封回。新的 repack 文档格式为 `re_user3_pack_v2`,封回器仍兼容使用原始
146
- 数值词数组的 v1 文档。
197
+ 填充词也可以无损封回。新的 repack 文档格式为 `re_user3_pack_v3`,它会分别记录自动探测到的
198
+ USR 外层布局、RSZ 头族和文件中的真实 RSZ 版本,并保留 resource 与 userdata 依赖表。布局
199
+ 候选及其读取/回封能力状态集中声明在 `pyreuser3/usr_layouts.py`,RSZ 字段定义仍来自传入的
200
+ REFramework 兼容模板。已验证的现代头族接受通过完整结构校验的 RSZ v4+ 文件,并原样保留
201
+ 版本号,不再固定为 MHWS 的版本 16。这个头族中的 offset 数值仍以 RSZ 段为基准,但 userdata
202
+ 与 data 的目标位置按整个文件的绝对 16 字节边界对齐。readable 导出会接受仅对齐偏差,probe
203
+ API 则把它们报告为结构化警告;repack 导出会把同一诊断写入 `_warnings`,并通过
204
+ `_unsupported` 阻止未经验证的布局被封回。实验性的物理 H28 与 legacy RSZ v3 候选暂时只读,
205
+ 获得真实样本并完成逐字节回封验证后才能启用 repack。v1 和 v2 文档仍可识别以便诊断,但由于
206
+ 缺少必要的布局元数据,封回前必须从源文件重新导出为 v3。
207
+
208
+ 部分现代文件会用有符号 `-1` 明确表示空 `Object` 引用;repack 会原样保留这个哨兵,同时继续
209
+ 拒绝其他不存在的实例 ID。超过一百万项的定长数组会紧凑保存为 `_raw_array_count` 和
210
+ `_raw_array_hex`。这种表示不提供逐项可读性,但能够无损回封、避免展开数百万个 Python 整数,
211
+ 并会在封包前校验 count 与 payload 长度是否匹配。
147
212
 
148
213
  批量处理目录:
149
214
 
@@ -158,6 +223,7 @@ converter = REUser3Converter(
158
223
  export_result = converter.export_directory(
159
224
  "D:/game/unpacked",
160
225
  "D:/game/json",
226
+ json_format="repack",
161
227
  )
162
228
 
163
229
  pack_result = converter.pack_directory(
@@ -190,6 +256,29 @@ converter.patch_file(
190
256
  )
191
257
  ```
192
258
 
259
+ ## 兼容性验证
260
+
261
+ 仓库内提供无需 schema 的语料测试脚本。游戏文件不会提交到仓库,请让脚本指向本地已解包的
262
+ `natives` 目录:
263
+
264
+ ```bash
265
+ python tests/corpus_probe.py D:/game/natives \
266
+ --expected-total 62768 \
267
+ --expected-version 16 \
268
+ --report layout-report.json
269
+ ```
270
+
271
+ 0.7.1 修复了 0.7.0 引入的现代 RSZ 对齐回归,并把原计划中的兼容性工作合并进本次 bugfix:
272
+ 分阶段布局探测、结构化诊断、安全 readable 解析、仅验证布局可 repack,以及无需 schema 的
273
+ probe 命令。新的现代布局规则已用 62,768 个 MHWS `.user.3` 文件验证;其中四个
274
+ SystemSetting 样本还完成了 readable 导出、repack 导出、逐字节一致回封和二次解析验证。
275
+
276
+ 另外还验证了 Monster Hunter Stories 3 语料:42,945 个文件全部通过严格 layout 探测和
277
+ schema 驱动的 repack 导出;42,945 个文件全部能够无异常地重新构建,其中 38,548 个逐字节
278
+ 一致。其余 4,397 个可以成功重建但并非逐字节一致;已观察到的原因包括非零 padding、空字符串
279
+ 的另一种物理编码,因此不把它们宣称为逐字节 fixture。两个使用紧凑超大数组表示的 voxel 文件
280
+ 都能逐字节一致回封,其中包括 6.55 MB 的 `dg100_Root` payload。
281
+
193
282
  ## 常见注意事项
194
283
 
195
284
  - schema JSON、`il2cpp_dump.json` 和 `.user.3` 文件应来自同一个游戏版本;
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "PyREUser3"
7
- version = "0.6.0"
7
+ version = "0.7.1"
8
8
  description = "Pure Python tools for converting RE Engine .user.3 files to and from JSON."
9
9
  readme = "docs/PYPI.md"
10
10
  requires-python = ">=3.9"
@@ -9,15 +9,21 @@ from __future__ import annotations
9
9
  from importlib import import_module
10
10
  from typing import Any
11
11
 
12
+ __version__ = "0.7.1"
13
+
12
14
  __all__ = [
15
+ "__version__",
13
16
  "BinaryReader",
14
17
  "ClassDef",
15
18
  "FieldDef",
16
19
  "PackError",
17
20
  "ParseError",
21
+ "LayoutValidationIssue",
18
22
  "TypeDB",
19
23
  "REUser3Converter",
20
24
  "RSZ_MAGIC",
25
+ "probe_usr_file",
26
+ "probe_usr_path",
21
27
  "User3Exporter",
22
28
  "User3Packer",
23
29
  "USR_MAGIC",
@@ -28,6 +34,9 @@ _EXPORT_MODULES = {
28
34
  "ParseError": ".core",
29
35
  "RSZ_MAGIC": ".core",
30
36
  "USR_MAGIC": ".core",
37
+ "LayoutValidationIssue": ".usr_container",
38
+ "probe_usr_file": ".usr_container",
39
+ "probe_usr_path": ".usr_container",
31
40
  "ClassDef": ".schema",
32
41
  "FieldDef": ".schema",
33
42
  "TypeDB": ".schema",