PyREUser3 0.6.0__tar.gz → 0.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.
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/PKG-INFO +7 -1
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/PyREUser3.egg-info/PKG-INFO +7 -1
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/PyREUser3.egg-info/SOURCES.txt +4 -1
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/README.md +31 -6
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/docs/PYPI.md +6 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/docs/README.zh-CN.md +28 -6
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyproject.toml +1 -1
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/__init__.py +3 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/api.py +18 -5
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/cli.py +10 -6
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/core.py +5 -2
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/export/base.py +16 -5
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/export/user3.py +113 -97
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/pack/base.py +63 -19
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/pack/models.py +46 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/pack/plan.py +286 -9
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/pack/writer.py +262 -40
- pyreuser3-0.7.0/pyreuser3/usr_container.py +339 -0
- pyreuser3-0.7.0/pyreuser3/usr_layouts.py +321 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/tests/test_enum_binary.py +1 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/tests/test_enum_codec.py +11 -3
- pyreuser3-0.7.0/tests/test_usr_container.py +377 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/LICENSE +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/MANIFEST.in +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/PyREUser3.egg-info/dependency_links.txt +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/PyREUser3.egg-info/entry_points.txt +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/PyREUser3.egg-info/requires.txt +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/PyREUser3.egg-info/top_level.txt +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/__main__.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/enum_codec.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/export/__init__.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/export/enums.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/export/fields.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/export/metadata.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/export/postprocess.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/export/tree.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/pack/__init__.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/rich_ui.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/schema.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/web/__init__.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/web/__main__.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/web/handler.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/web/jobs.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/web/page.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/web/picker.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/web/runners.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/web/server.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/pyreuser3/web/settings.py +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/setup.cfg +0 -0
- {pyreuser3-0.6.0 → pyreuser3-0.7.0}/tests/test_export_enums.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyREUser3
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
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
|
|
@@ -48,11 +48,17 @@ pip install pyreuser3
|
|
|
48
48
|
- A reusable Python API through `REUser3Converter`.
|
|
49
49
|
- CLI commands through `pyreuser3`.
|
|
50
50
|
- A local `.user.3` export Web UI through `pyreuser3-web`.
|
|
51
|
+
- Automatic separation of the USR outer layout from the embedded RSZ header family;
|
|
52
|
+
modern RSZ v4+ files preserve their original numeric version during repack.
|
|
51
53
|
|
|
52
54
|
The published package intentionally does not include game resources, dumped game data, RE_RSZ templates,
|
|
53
55
|
`il2cpp_dump.json`, or repository-specific helper scripts. You need to provide data files that match the target game and
|
|
54
56
|
version.
|
|
55
57
|
|
|
58
|
+
Verified H30/modern layouts support repacking. Experimental physical H28 and legacy
|
|
59
|
+
RSZ v3 layouts are readable for analysis but intentionally blocked from repacking
|
|
60
|
+
until real fixtures provide byte-for-byte validation.
|
|
61
|
+
|
|
56
62
|
## Requirements
|
|
57
63
|
|
|
58
64
|
- Python 3.9 or newer.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyREUser3
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
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
|
|
@@ -48,11 +48,17 @@ pip install pyreuser3
|
|
|
48
48
|
- A reusable Python API through `REUser3Converter`.
|
|
49
49
|
- CLI commands through `pyreuser3`.
|
|
50
50
|
- A local `.user.3` export Web UI through `pyreuser3-web`.
|
|
51
|
+
- Automatic separation of the USR outer layout from the embedded RSZ header family;
|
|
52
|
+
modern RSZ v4+ files preserve their original numeric version during repack.
|
|
51
53
|
|
|
52
54
|
The published package intentionally does not include game resources, dumped game data, RE_RSZ templates,
|
|
53
55
|
`il2cpp_dump.json`, or repository-specific helper scripts. You need to provide data files that match the target game and
|
|
54
56
|
version.
|
|
55
57
|
|
|
58
|
+
Verified H30/modern layouts support repacking. Experimental physical H28 and legacy
|
|
59
|
+
RSZ v3 layouts are readable for analysis but intentionally blocked from repacking
|
|
60
|
+
until real fixtures provide byte-for-byte validation.
|
|
61
|
+
|
|
56
62
|
## Requirements
|
|
57
63
|
|
|
58
64
|
- Python 3.9 or newer.
|
|
@@ -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
|
|
@@ -42,4 +44,5 @@ pyreuser3/web/server.py
|
|
|
42
44
|
pyreuser3/web/settings.py
|
|
43
45
|
tests/test_enum_binary.py
|
|
44
46
|
tests/test_enum_codec.py
|
|
45
|
-
tests/test_export_enums.py
|
|
47
|
+
tests/test_export_enums.py
|
|
48
|
+
tests/test_usr_container.py
|
|
@@ -55,11 +55,20 @@ pyreuser3 export \
|
|
|
55
55
|
-p <il2cpp_dump.json>
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
Export full repack JSON, then pack it back to `.user.3`:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pyreuser3 export \
|
|
62
|
+
-i <input-user3-file-or-directory> \
|
|
63
|
+
-s <RE_RSZ-schema.json> \
|
|
64
|
+
-o <repack-json-output-directory> \
|
|
65
|
+
-p <il2cpp_dump.json> \
|
|
66
|
+
--json-format repack
|
|
67
|
+
```
|
|
59
68
|
|
|
60
69
|
```bash
|
|
61
70
|
pyreuser3 pack \
|
|
62
|
-
-j <input-json-file-or-directory> \
|
|
71
|
+
-j <input-repack-json-file-or-directory> \
|
|
63
72
|
-s <RE_RSZ-schema.json> \
|
|
64
73
|
-o <user3-output-directory> \
|
|
65
74
|
-p <il2cpp_dump.json>
|
|
@@ -90,8 +99,14 @@ converter.export_file(
|
|
|
90
99
|
"json/OtomonData.user.3.json",
|
|
91
100
|
)
|
|
92
101
|
|
|
102
|
+
# Packing only accepts the full repack document. Readable exports are read-only.
|
|
103
|
+
converter.export_file(
|
|
104
|
+
"input/OtomonData.user.3",
|
|
105
|
+
"json/OtomonData.user.3.pack.json",
|
|
106
|
+
json_format="repack",
|
|
107
|
+
)
|
|
93
108
|
converter.pack_file(
|
|
94
|
-
"json/OtomonData.user.3.json",
|
|
109
|
+
"json/OtomonData.user.3.pack.json",
|
|
95
110
|
"mod/OtomonData.user.3",
|
|
96
111
|
)
|
|
97
112
|
```
|
|
@@ -110,14 +125,24 @@ repack_data = converter.user3_to_json(
|
|
|
110
125
|
)
|
|
111
126
|
```
|
|
112
127
|
|
|
113
|
-
Use `json_format="readable"` for the same shape produced by `export_file()
|
|
128
|
+
Use `json_format="readable"` for the same shape produced by `export_file()`. This
|
|
129
|
+
shape is read-only. Use `json_format="repack"` for the full document accepted by
|
|
130
|
+
`pack()`; the packer rejects readable JSON.
|
|
114
131
|
|
|
115
132
|
Enum fields are rendered as `[numeric] Name` labels using the enum's actual storage
|
|
116
133
|
width. Scalar flag enums are rendered as arrays of labels. ``ace.Bitset`1<T>`` values are
|
|
117
134
|
rendered as enum-index labels together with `_MaxElement` and `_WordCount`, so unknown
|
|
118
135
|
bits and padded word arrays remain reversible. Repack exports use
|
|
119
|
-
`
|
|
120
|
-
|
|
136
|
+
`re_user3_pack_v3`, which records the independently detected USR outer layout, RSZ
|
|
137
|
+
header family, and numeric RSZ version while preserving resource and userdata
|
|
138
|
+
dependency tables. Layout candidates and their read/repack capability status are
|
|
139
|
+
declared in `pyreuser3/usr_layouts.py`; RSZ field definitions still come from the
|
|
140
|
+
supplied REFramework-compatible schema. The verified modern header family accepts
|
|
141
|
+
structurally valid RSZ v4+ files and preserves their original version instead of
|
|
142
|
+
forcing MHWS version 16. Experimental physical H28 and legacy RSZ v3 candidates are
|
|
143
|
+
read-only until real fixtures validate byte-for-byte repacking. V1 and v2 documents
|
|
144
|
+
are recognized for diagnostics but must be re-exported as v3 before packing because
|
|
145
|
+
they do not record the required layout metadata.
|
|
121
146
|
|
|
122
147
|
For stable patch-and-repack workflows, use `patch_file()` or `parse_pack_file()`:
|
|
123
148
|
|
|
@@ -15,11 +15,17 @@ pip install pyreuser3
|
|
|
15
15
|
- A reusable Python API through `REUser3Converter`.
|
|
16
16
|
- CLI commands through `pyreuser3`.
|
|
17
17
|
- A local `.user.3` export Web UI through `pyreuser3-web`.
|
|
18
|
+
- Automatic separation of the USR outer layout from the embedded RSZ header family;
|
|
19
|
+
modern RSZ v4+ files preserve their original numeric version during repack.
|
|
18
20
|
|
|
19
21
|
The published package intentionally does not include game resources, dumped game data, RE_RSZ templates,
|
|
20
22
|
`il2cpp_dump.json`, or repository-specific helper scripts. You need to provide data files that match the target game and
|
|
21
23
|
version.
|
|
22
24
|
|
|
25
|
+
Verified H30/modern layouts support repacking. Experimental physical H28 and legacy
|
|
26
|
+
RSZ v3 layouts are readable for analysis but intentionally blocked from repacking
|
|
27
|
+
until real fixtures provide byte-for-byte validation.
|
|
28
|
+
|
|
23
29
|
## Requirements
|
|
24
30
|
|
|
25
31
|
- Python 3.9 or newer.
|
|
@@ -56,11 +56,20 @@ pyreuser3 export \
|
|
|
56
56
|
-p <il2cpp_dump.json>
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
导出完整 repack JSON,然后封回 `.user.3`:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pyreuser3 export \
|
|
63
|
+
-i <输入的-user3-文件或目录> \
|
|
64
|
+
-s <RE_RSZ-schema.json> \
|
|
65
|
+
-o <repack-JSON-输出目录> \
|
|
66
|
+
-p <il2cpp_dump.json> \
|
|
67
|
+
--json-format repack
|
|
68
|
+
```
|
|
60
69
|
|
|
61
70
|
```bash
|
|
62
71
|
pyreuser3 pack \
|
|
63
|
-
-j <输入的-JSON-文件或目录> \
|
|
72
|
+
-j <输入的-repack-JSON-文件或目录> \
|
|
64
73
|
-s <RE_RSZ-schema.json> \
|
|
65
74
|
-o <user3-输出目录> \
|
|
66
75
|
-p <il2cpp_dump.json>
|
|
@@ -118,8 +127,14 @@ converter.export_file(
|
|
|
118
127
|
"json/OtomonData.user.3.json",
|
|
119
128
|
)
|
|
120
129
|
|
|
130
|
+
# 封包只接受完整 repack 文档;readable 导出仅供读取。
|
|
131
|
+
converter.export_file(
|
|
132
|
+
"input/OtomonData.user.3",
|
|
133
|
+
"json/OtomonData.user.3.pack.json",
|
|
134
|
+
json_format="repack",
|
|
135
|
+
)
|
|
121
136
|
converter.pack_file(
|
|
122
|
-
"json/OtomonData.user.3.json",
|
|
137
|
+
"json/OtomonData.user.3.pack.json",
|
|
123
138
|
"mod/OtomonData.user.3",
|
|
124
139
|
)
|
|
125
140
|
```
|
|
@@ -138,12 +153,18 @@ repack_data = converter.user3_to_json(
|
|
|
138
153
|
)
|
|
139
154
|
```
|
|
140
155
|
|
|
141
|
-
使用 `json_format="readable"` 时返回与 `export_file()`
|
|
156
|
+
使用 `json_format="readable"` 时返回与 `export_file()` 一致的只读导出结构;使用
|
|
157
|
+
`json_format="repack"` 时返回可传给 `pack()` 的完整实例表结构。封回器会拒绝 readable JSON。
|
|
142
158
|
|
|
143
159
|
枚举字段会按照真实底层存储宽度输出为 `[数值] 名称`。标量位标志枚举输出为标签数组;
|
|
144
160
|
``ace.Bitset`1<T>`` 输出为枚举索引标签,并保留 `_MaxElement` 与 `_WordCount`,因此未知位和
|
|
145
|
-
填充词也可以无损封回。新的 repack 文档格式为 `
|
|
146
|
-
|
|
161
|
+
填充词也可以无损封回。新的 repack 文档格式为 `re_user3_pack_v3`,它会分别记录自动探测到的
|
|
162
|
+
USR 外层布局、RSZ 头族和文件中的真实 RSZ 版本,并保留 resource 与 userdata 依赖表。布局
|
|
163
|
+
候选及其读取/回封能力状态集中声明在 `pyreuser3/usr_layouts.py`,RSZ 字段定义仍来自传入的
|
|
164
|
+
REFramework 兼容模板。已验证的现代头族接受通过完整结构校验的 RSZ v4+ 文件,并原样保留
|
|
165
|
+
版本号,不再固定为 MHWS 的版本 16。实验性的物理 H28 与 legacy RSZ v3 候选暂时只读,获得
|
|
166
|
+
真实样本并完成逐字节回封验证后才能启用 repack。v1 和 v2 文档仍可识别以便诊断,但由于缺少
|
|
167
|
+
必要的布局元数据,封回前必须从源文件重新导出为 v3。
|
|
147
168
|
|
|
148
169
|
批量处理目录:
|
|
149
170
|
|
|
@@ -158,6 +179,7 @@ converter = REUser3Converter(
|
|
|
158
179
|
export_result = converter.export_directory(
|
|
159
180
|
"D:/game/unpacked",
|
|
160
181
|
"D:/game/json",
|
|
182
|
+
json_format="repack",
|
|
161
183
|
)
|
|
162
184
|
|
|
163
185
|
pack_result = converter.pack_directory(
|
|
@@ -73,6 +73,7 @@ class REUser3Converter:
|
|
|
73
73
|
user3_root: str | Path,
|
|
74
74
|
output_root: str | Path,
|
|
75
75
|
exclude_regexes: list[str] | None = None,
|
|
76
|
+
json_format: JsonFormat = "readable",
|
|
76
77
|
) -> dict[str, int]:
|
|
77
78
|
"""Export every selected .user.3 file under a directory or single-file root.
|
|
78
79
|
|
|
@@ -81,33 +82,42 @@ class REUser3Converter:
|
|
|
81
82
|
output_root (str | Path): Directory where generated output is written.
|
|
82
83
|
exclude_regexes (list[str] | None): Regular expressions used to skip matching
|
|
83
84
|
relative paths.
|
|
85
|
+
json_format (JsonFormat): "readable" for read-only exports or "repack"
|
|
86
|
+
for documents accepted by pack().
|
|
84
87
|
|
|
85
88
|
Returns:
|
|
86
89
|
dict[str, int]: Counters describing total, successful, and failed items.
|
|
87
90
|
"""
|
|
88
|
-
exporter = self._new_exporter(
|
|
91
|
+
exporter = self._new_exporter(
|
|
92
|
+
user3_root,
|
|
93
|
+
output_root,
|
|
94
|
+
exclude_regexes,
|
|
95
|
+
json_format=self._normalize_json_format(json_format),
|
|
96
|
+
)
|
|
89
97
|
return exporter.run()
|
|
90
98
|
|
|
91
99
|
def export_file(
|
|
92
100
|
self,
|
|
93
101
|
user3_path: str | Path,
|
|
94
102
|
json_path: str | Path,
|
|
103
|
+
json_format: JsonFormat = "readable",
|
|
95
104
|
) -> Path:
|
|
96
105
|
"""Export one .user.3 file to the requested JSON path.
|
|
97
106
|
|
|
98
107
|
Args:
|
|
99
108
|
user3_path (str | Path): Path to the .user.3 file being parsed, exported, patched, or packed.
|
|
100
109
|
json_path (str | Path): Path to the JSON document read from or written by this workflow.
|
|
110
|
+
json_format (JsonFormat): "readable" for a read-only tree or "repack"
|
|
111
|
+
for a document accepted by pack().
|
|
101
112
|
|
|
102
113
|
Returns:
|
|
103
114
|
Path: Concrete filesystem path returned after the read, write, or resolution step finishes.
|
|
104
115
|
"""
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
# remain compatible across workflows.
|
|
116
|
+
# Use the same in-memory format selector as parse_file/parse_pack_file so
|
|
117
|
+
# single-file and batch exports keep identical document shapes.
|
|
108
118
|
tree = self.user3_to_json(
|
|
109
119
|
user3_path,
|
|
110
|
-
json_format=
|
|
120
|
+
json_format=json_format,
|
|
111
121
|
round_floats=True,
|
|
112
122
|
)
|
|
113
123
|
target = Path(json_path)
|
|
@@ -343,6 +353,7 @@ class REUser3Converter:
|
|
|
343
353
|
user3_root: str | Path,
|
|
344
354
|
output_root: str | Path,
|
|
345
355
|
exclude_regexes: list[str] | None,
|
|
356
|
+
json_format: str = "readable",
|
|
346
357
|
) -> User3Exporter:
|
|
347
358
|
"""Create an exporter with this facade's schema, enum metadata, and magic values.
|
|
348
359
|
|
|
@@ -351,6 +362,7 @@ class REUser3Converter:
|
|
|
351
362
|
output_root (str | Path): Directory where generated output is written.
|
|
352
363
|
exclude_regexes (list[str] | None): Regular expressions used to skip matching
|
|
353
364
|
relative paths.
|
|
365
|
+
json_format (str): Export document shape requested by the caller.
|
|
354
366
|
|
|
355
367
|
Returns:
|
|
356
368
|
User3Exporter: Configured object or normalized value returned for the caller to use directly.
|
|
@@ -369,6 +381,7 @@ class REUser3Converter:
|
|
|
369
381
|
il2cpp_dump_path=self.il2cpp_dump_path,
|
|
370
382
|
user_magic=self.user_magic,
|
|
371
383
|
rsz_magic=self.rsz_magic,
|
|
384
|
+
json_format=json_format,
|
|
372
385
|
)
|
|
373
386
|
|
|
374
387
|
def _new_packer(self, output_root: str | Path | None) -> User3Packer:
|
|
@@ -8,9 +8,9 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
import argparse
|
|
10
10
|
import json
|
|
11
|
-
from importlib.metadata import PackageNotFoundError, version
|
|
12
11
|
from typing import Sequence
|
|
13
12
|
|
|
13
|
+
from . import __version__
|
|
14
14
|
from .core import RSZ_MAGIC, USR_MAGIC
|
|
15
15
|
|
|
16
16
|
|
|
@@ -33,10 +33,7 @@ def package_version() -> str:
|
|
|
33
33
|
Returns:
|
|
34
34
|
str: Normalized or formatted text.
|
|
35
35
|
"""
|
|
36
|
-
|
|
37
|
-
return version("PyREUser3")
|
|
38
|
-
except PackageNotFoundError:
|
|
39
|
-
return "0.1.0"
|
|
36
|
+
return __version__
|
|
40
37
|
|
|
41
38
|
|
|
42
39
|
def normalize_tree_depth(value: str) -> int | str:
|
|
@@ -143,6 +140,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
143
140
|
required=True,
|
|
144
141
|
help="Path to il2cpp_dump.json, used to generate enum labels.",
|
|
145
142
|
)
|
|
143
|
+
export_parser.add_argument(
|
|
144
|
+
"--json-format",
|
|
145
|
+
choices=("readable", "repack"),
|
|
146
|
+
default="readable",
|
|
147
|
+
help="Export read-only readable JSON or packable repack JSON (default: readable).",
|
|
148
|
+
)
|
|
146
149
|
add_magic_args(export_parser)
|
|
147
150
|
export_parser.set_defaults(func=run_export)
|
|
148
151
|
|
|
@@ -154,7 +157,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
154
157
|
"--input-json",
|
|
155
158
|
"-j",
|
|
156
159
|
required=True,
|
|
157
|
-
help="JSON file or root directory that contains
|
|
160
|
+
help="Repack JSON file or root directory that contains repack documents.",
|
|
158
161
|
)
|
|
159
162
|
pack_parser.add_argument(
|
|
160
163
|
"--schema-path",
|
|
@@ -212,6 +215,7 @@ def run_export(args: argparse.Namespace) -> int:
|
|
|
212
215
|
il2cpp_dump_path=args.il2cpp_dump_path,
|
|
213
216
|
user_magic=args.user_magic,
|
|
214
217
|
rsz_magic=args.rsz_magic,
|
|
218
|
+
json_format=args.json_format,
|
|
215
219
|
)
|
|
216
220
|
result = exporter.run()
|
|
217
221
|
console.log("Export complete:", json.dumps(result, ensure_ascii=False))
|
|
@@ -21,8 +21,11 @@ RSZ_MAGIC = 5919570
|
|
|
21
21
|
# Preserve instance numbering and reference identity; RSZ object links depend on these
|
|
22
22
|
# indexes remaining stable.
|
|
23
23
|
PACK_JSON_FORMAT_V1 = "re_user3_pack_v1"
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
PACK_JSON_FORMAT_V2 = "re_user3_pack_v2"
|
|
25
|
+
PACK_JSON_FORMAT = "re_user3_pack_v3"
|
|
26
|
+
PACK_JSON_FORMATS = frozenset(
|
|
27
|
+
{PACK_JSON_FORMAT_V1, PACK_JSON_FORMAT_V2, PACK_JSON_FORMAT}
|
|
28
|
+
)
|
|
26
29
|
# Decode strings and GUID-like values conservatively so invalid data does not corrupt
|
|
27
30
|
# subsequent parsing.
|
|
28
31
|
HEX32_RE = re.compile(r"^[0-9a-fA-F]{32}$")
|
|
@@ -43,6 +43,7 @@ class User3Exporter(
|
|
|
43
43
|
il2cpp_dump_path: str | Path = "",
|
|
44
44
|
user_magic: int = USR_MAGIC,
|
|
45
45
|
rsz_magic: int = RSZ_MAGIC,
|
|
46
|
+
json_format: str = "readable",
|
|
46
47
|
):
|
|
47
48
|
"""Initialize User3Exporter with validated configuration and state.
|
|
48
49
|
|
|
@@ -57,6 +58,8 @@ class User3Exporter(
|
|
|
57
58
|
il2cpp_dump_path (str | Path): Path to il2cpp_dump.json for enum metadata.
|
|
58
59
|
user_magic (int): Expected magic value for the outer .user.3 container header.
|
|
59
60
|
rsz_magic (int): Expected magic value for embedded RSZ blocks.
|
|
61
|
+
json_format (str): "readable" for display-only trees or "repack" for
|
|
62
|
+
full pack documents.
|
|
60
63
|
|
|
61
64
|
Returns:
|
|
62
65
|
None. The method performs its documented side effect in place and raises on invalid input.
|
|
@@ -77,6 +80,10 @@ class User3Exporter(
|
|
|
77
80
|
self.tree_depth = self._normalize_tree_depth(tree_depth)
|
|
78
81
|
self.user_magic = int(user_magic)
|
|
79
82
|
self.rsz_magic = int(rsz_magic)
|
|
83
|
+
normalized_format = str(json_format).strip().lower().replace("-", "_")
|
|
84
|
+
if normalized_format not in {"readable", "repack"}:
|
|
85
|
+
raise ValueError("json_format must be 'readable' or 'repack'")
|
|
86
|
+
self.json_format = normalized_format
|
|
80
87
|
self.exclude_regexes = exclude_regexes or []
|
|
81
88
|
self._exclude_patterns = [re.compile(p) for p in self.exclude_regexes]
|
|
82
89
|
self.schema_path = self._resolve_schema_path(self.schema_dir)
|
|
@@ -155,10 +162,13 @@ class User3Exporter(
|
|
|
155
162
|
# and numeric packing stay reversible.
|
|
156
163
|
# Preserve the exported JSON structure so external scripts and hand-edited
|
|
157
164
|
# files remain compatible across workflows.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
165
|
+
if self.json_format == "repack":
|
|
166
|
+
tree = self._parse_user3_pack(user3_file)
|
|
167
|
+
else:
|
|
168
|
+
tree = self._parse_user3(user3_file)
|
|
169
|
+
tree = self._postprocess_enum_nodes(tree)
|
|
170
|
+
tree = self._finalize_export_tree(tree)
|
|
171
|
+
tree = self._round_export_floats(tree)
|
|
162
172
|
output_path = self._output_path_for(user3_file)
|
|
163
173
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
164
174
|
with output_path.open("w", encoding="utf-8") as f:
|
|
@@ -254,5 +264,6 @@ class User3Exporter(
|
|
|
254
264
|
relative_parent = Path()
|
|
255
265
|
else:
|
|
256
266
|
relative_parent = user3_file.relative_to(self.user3_root).parent
|
|
257
|
-
|
|
267
|
+
suffix = ".pack.json" if self.json_format == "repack" else ".json"
|
|
268
|
+
output_name = f"{user3_file.name}{suffix}"
|
|
258
269
|
return self.output_root / relative_parent / output_name
|