PyREUser3 0.2.0__tar.gz → 0.4.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.
Files changed (50) hide show
  1. pyreuser3-0.4.0/PKG-INFO +73 -0
  2. pyreuser3-0.4.0/PyREUser3.egg-info/PKG-INFO +73 -0
  3. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/PyREUser3.egg-info/SOURCES.txt +4 -1
  4. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/README.md +30 -4
  5. pyreuser3-0.4.0/docs/PYPI.md +40 -0
  6. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/docs/README.zh-CN.md +29 -4
  7. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyproject.toml +2 -2
  8. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/api.py +58 -6
  9. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/core.py +67 -0
  10. pyreuser3-0.4.0/pyreuser3/export/__init__.py +27 -0
  11. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/export/base.py +2 -0
  12. pyreuser3-0.4.0/pyreuser3/export/enums.py +486 -0
  13. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/export/fields.py +32 -2
  14. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/export/metadata.py +76 -9
  15. pyreuser3-0.4.0/pyreuser3/pack/__init__.py +27 -0
  16. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/pack/base.py +10 -2
  17. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/pack/writer.py +56 -10
  18. pyreuser3-0.4.0/tests/test_enum_binary.py +92 -0
  19. pyreuser3-0.4.0/tests/test_export_enums.py +195 -0
  20. pyreuser3-0.2.0/PKG-INFO +0 -165
  21. pyreuser3-0.2.0/PyREUser3.egg-info/PKG-INFO +0 -165
  22. pyreuser3-0.2.0/pyreuser3/export/__init__.py +0 -9
  23. pyreuser3-0.2.0/pyreuser3/export/enums.py +0 -184
  24. pyreuser3-0.2.0/pyreuser3/pack/__init__.py +0 -9
  25. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/LICENSE +0 -0
  26. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/MANIFEST.in +0 -0
  27. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/PyREUser3.egg-info/dependency_links.txt +0 -0
  28. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/PyREUser3.egg-info/entry_points.txt +0 -0
  29. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/PyREUser3.egg-info/requires.txt +0 -0
  30. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/PyREUser3.egg-info/top_level.txt +0 -0
  31. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/__init__.py +0 -0
  32. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/__main__.py +0 -0
  33. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/cli.py +0 -0
  34. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/export/postprocess.py +0 -0
  35. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/export/tree.py +0 -0
  36. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/export/user3.py +0 -0
  37. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/pack/models.py +0 -0
  38. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/pack/plan.py +0 -0
  39. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/rich_ui.py +0 -0
  40. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/schema.py +0 -0
  41. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/web/__init__.py +0 -0
  42. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/web/__main__.py +0 -0
  43. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/web/handler.py +0 -0
  44. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/web/jobs.py +0 -0
  45. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/web/page.py +0 -0
  46. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/web/picker.py +0 -0
  47. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/web/runners.py +0 -0
  48. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/web/server.py +0 -0
  49. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/pyreuser3/web/settings.py +0 -0
  50. {pyreuser3-0.2.0 → pyreuser3-0.4.0}/setup.cfg +0 -0
@@ -0,0 +1,73 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyREUser3
3
+ Version: 0.4.0
4
+ Summary: Pure Python tools for converting RE Engine .user.3 files to and from JSON.
5
+ Author: Egg Targaryen
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/dzxrly/PyREUser3
8
+ Project-URL: Repository, https://github.com/dzxrly/PyREUser3
9
+ Project-URL: Issues, https://github.com/dzxrly/PyREUser3/issues
10
+ Keywords: RE Engine,user.3,JSON,modding,RSZ
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: File Formats
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: rich>=13.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: build>=1.2; extra == "dev"
31
+ Requires-Dist: twine>=5.0; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # PyREUser3
35
+
36
+ PyREUser3 is a pure Python package for converting RE Engine `.user.3` database files to JSON and packing compatible JSON back to `.user.3`.
37
+
38
+ ## Installation
39
+
40
+ ```bash
41
+ pip install pyreuser3
42
+ ```
43
+
44
+ ## What Is Included
45
+
46
+ - `.user.3 -> JSON` export.
47
+ - `JSON -> .user.3` packing.
48
+ - A reusable Python API through `REUser3Converter`.
49
+ - CLI commands through `pyreuser3`.
50
+ - A local `.user.3` export Web UI through `pyreuser3-web`.
51
+
52
+ The published package intentionally does not include game resources, dumped game data, RE_RSZ templates,
53
+ `il2cpp_dump.json`, or repository-specific helper scripts. You need to provide data files that match the target game and
54
+ version.
55
+
56
+ ## Requirements
57
+
58
+ - Python 3.9 or newer.
59
+ - A RE_RSZ schema JSON file for the target game/version.
60
+ - An `il2cpp_dump.json` file when exporting readable enum labels.
61
+ - One or more unpacked `.user.3` files.
62
+
63
+ ## Usage
64
+
65
+ Usage details may change as the package evolves. For the latest command-line and Python API examples, read the GitHub README:
66
+
67
+ https://github.com/dzxrly/PyREUser3#readme
68
+
69
+ ## Links
70
+
71
+ - Homepage: https://github.com/dzxrly/PyREUser3
72
+ - Issues: https://github.com/dzxrly/PyREUser3/issues
73
+ - License: MIT License
@@ -0,0 +1,73 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyREUser3
3
+ Version: 0.4.0
4
+ Summary: Pure Python tools for converting RE Engine .user.3 files to and from JSON.
5
+ Author: Egg Targaryen
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/dzxrly/PyREUser3
8
+ Project-URL: Repository, https://github.com/dzxrly/PyREUser3
9
+ Project-URL: Issues, https://github.com/dzxrly/PyREUser3/issues
10
+ Keywords: RE Engine,user.3,JSON,modding,RSZ
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: File Formats
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.9
26
+ Description-Content-Type: text/markdown
27
+ License-File: LICENSE
28
+ Requires-Dist: rich>=13.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: build>=1.2; extra == "dev"
31
+ Requires-Dist: twine>=5.0; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # PyREUser3
35
+
36
+ PyREUser3 is a pure Python package for converting RE Engine `.user.3` database files to JSON and packing compatible JSON back to `.user.3`.
37
+
38
+ ## Installation
39
+
40
+ ```bash
41
+ pip install pyreuser3
42
+ ```
43
+
44
+ ## What Is Included
45
+
46
+ - `.user.3 -> JSON` export.
47
+ - `JSON -> .user.3` packing.
48
+ - A reusable Python API through `REUser3Converter`.
49
+ - CLI commands through `pyreuser3`.
50
+ - A local `.user.3` export Web UI through `pyreuser3-web`.
51
+
52
+ The published package intentionally does not include game resources, dumped game data, RE_RSZ templates,
53
+ `il2cpp_dump.json`, or repository-specific helper scripts. You need to provide data files that match the target game and
54
+ version.
55
+
56
+ ## Requirements
57
+
58
+ - Python 3.9 or newer.
59
+ - A RE_RSZ schema JSON file for the target game/version.
60
+ - An `il2cpp_dump.json` file when exporting readable enum labels.
61
+ - One or more unpacked `.user.3` files.
62
+
63
+ ## Usage
64
+
65
+ Usage details may change as the package evolves. For the latest command-line and Python API examples, read the GitHub README:
66
+
67
+ https://github.com/dzxrly/PyREUser3#readme
68
+
69
+ ## Links
70
+
71
+ - Homepage: https://github.com/dzxrly/PyREUser3
72
+ - Issues: https://github.com/dzxrly/PyREUser3/issues
73
+ - License: MIT License
@@ -8,6 +8,7 @@ PyREUser3.egg-info/dependency_links.txt
8
8
  PyREUser3.egg-info/entry_points.txt
9
9
  PyREUser3.egg-info/requires.txt
10
10
  PyREUser3.egg-info/top_level.txt
11
+ docs/PYPI.md
11
12
  docs/README.zh-CN.md
12
13
  pyreuser3/__init__.py
13
14
  pyreuser3/__main__.py
@@ -37,4 +38,6 @@ pyreuser3/web/page.py
37
38
  pyreuser3/web/picker.py
38
39
  pyreuser3/web/runners.py
39
40
  pyreuser3/web/server.py
40
- pyreuser3/web/settings.py
41
+ pyreuser3/web/settings.py
42
+ tests/test_enum_binary.py
43
+ tests/test_export_enums.py
@@ -1,6 +1,15 @@
1
- # PyREUser3
1
+ <h1 align="center">PyREUser3</h1>
2
2
 
3
- English | [简体中文](./docs/README.zh-CN.md)
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>
4
13
 
5
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`.
6
15
 
@@ -24,7 +33,8 @@ from pyreuser3 import REUser3Converter
24
33
  - CLI commands through `pyreuser3`.
25
34
  - A local `.user.3` export Web UI through `pyreuser3-web`.
26
35
 
27
- This PyPI package intentionally does not include game resources, dumped game data, RE_RSZ templates, `il2cpp_dump.json`, `.msg.23` conversion tools, or repository-specific helper scripts.
36
+ This PyPI package intentionally does not include game resources, dumped game data, RE_RSZ templates, `il2cpp_dump.json`,
37
+ or repository-specific helper scripts.
28
38
 
29
39
  ## Requirements
30
40
 
@@ -63,7 +73,7 @@ Start the local `.user.3` export Web UI:
63
73
  pyreuser3-web --port 8765
64
74
  ```
65
75
 
66
- The Web UI only handles `.user.3` export. It does not pack files and does not provide `.msg.23` conversion.
76
+ The Web UI only handles `.user.3` export. It does not pack files.
67
77
 
68
78
  ## Python API
69
79
 
@@ -86,6 +96,22 @@ converter.pack_file(
86
96
  )
87
97
  ```
88
98
 
99
+ Convert a `.user.3` file to an in-memory JSON-compatible Python object without writing a JSON file:
100
+
101
+ ```python
102
+ readable_data = converter.user3_to_json(
103
+ "input/OtomonData.user.3",
104
+ json_format="readable",
105
+ )
106
+
107
+ repack_data = converter.user3_to_json(
108
+ "input/OtomonData.user.3",
109
+ json_format="repack",
110
+ )
111
+ ```
112
+
113
+ Use `json_format="readable"` for the same shape produced by `export_file()`, or `json_format="repack"` for the full instance-table document accepted by `pack()`.
114
+
89
115
  For stable patch-and-repack workflows, use `patch_file()` or `parse_pack_file()`:
90
116
 
91
117
  ```python
@@ -0,0 +1,40 @@
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
+ - A local `.user.3` export Web UI through `pyreuser3-web`.
18
+
19
+ The published package intentionally does not include game resources, dumped game data, RE_RSZ templates,
20
+ `il2cpp_dump.json`, or repository-specific helper scripts. You need to provide data files that match the target game and
21
+ version.
22
+
23
+ ## Requirements
24
+
25
+ - Python 3.9 or newer.
26
+ - A RE_RSZ schema JSON file for the target game/version.
27
+ - An `il2cpp_dump.json` file when exporting readable enum labels.
28
+ - One or more unpacked `.user.3` files.
29
+
30
+ ## Usage
31
+
32
+ Usage details may change as the package evolves. For the latest command-line and Python API examples, read the GitHub README:
33
+
34
+ https://github.com/dzxrly/PyREUser3#readme
35
+
36
+ ## Links
37
+
38
+ - Homepage: https://github.com/dzxrly/PyREUser3
39
+ - Issues: https://github.com/dzxrly/PyREUser3/issues
40
+ - License: MIT License
@@ -1,6 +1,15 @@
1
- # PyREUser3
1
+ <h1 align="center">PyREUser3</h1>
2
2
 
3
- [English](../README.md) | 简体中文
3
+ <p align="center">
4
+ <a href="https://github.com/dzxrly/PyREUser3/blob/main/README.md">English</a> | 简体中文
5
+ </p>
6
+
7
+ <p align="center">
8
+ <a href="https://pypi.org/project/PyREUser3/"><img alt="PyPI 项目" src="https://img.shields.io/badge/PyPI-PyREUser3-blue"></a>
9
+ <a href="https://pypi.org/project/PyREUser3/"><img alt="PyPI 版本" src="https://img.shields.io/pypi/v/PyREUser3"></a>
10
+ <a href="https://pepy.tech/project/PyREUser3"><img alt="下载量" src="https://static.pepy.tech/badge/PyREUser3"></a>
11
+ <a href="https://github.com/dzxrly/PyREUser3/blob/main/LICENSE"><img alt="许可证" src="https://img.shields.io/pypi/l/PyREUser3"></a>
12
+ </p>
4
13
 
5
14
  PyREUser3 是一个纯 Python 包,用于在 RE Engine 的 `.user.3` 数据库文件和 JSON 之间进行双向转换。
6
15
 
@@ -26,7 +35,7 @@ PyREUser3 当前提供:
26
35
  - `pyreuser3` 命令行工具;
27
36
  - `pyreuser3-web` 本地 Web 导出界面。
28
37
 
29
- PyPI 包不会包含游戏资源、游戏 dump、RE_RSZ 模板、`il2cpp_dump.json`、`.msg.23` 转换工具或特定仓库脚本。调用方需要自己准备与目标游戏版本匹配的数据文件。
38
+ PyPI 包不会包含游戏资源、游戏 dump、RE_RSZ 模板、`il2cpp_dump.json`、或特定仓库脚本。调用方需要自己准备与目标游戏版本匹配的数据文件。
30
39
 
31
40
  ## 环境要求
32
41
 
@@ -90,7 +99,7 @@ pyreuser3-web --port 8765
90
99
  http://127.0.0.1:8765/
91
100
  ```
92
101
 
93
- Web UI 只提供 `.user.3` 导出,不提供 JSON 封包,也不提供 `.msg.23` 转换。
102
+ Web UI 只提供 `.user.3` 导出,不提供 JSON 封包。
94
103
 
95
104
  ## Python API
96
105
 
@@ -115,6 +124,22 @@ converter.pack_file(
115
124
  )
116
125
  ```
117
126
 
127
+ 不写入 JSON 文件,直接把 `.user.3` 转成内存中的 JSON 兼容 Python 对象:
128
+
129
+ ```python
130
+ readable_data = converter.user3_to_json(
131
+ "input/OtomonData.user.3",
132
+ json_format="readable",
133
+ )
134
+
135
+ repack_data = converter.user3_to_json(
136
+ "input/OtomonData.user.3",
137
+ json_format="repack",
138
+ )
139
+ ```
140
+
141
+ 使用 `json_format="readable"` 时返回与 `export_file()` 一致的可读导出结构;使用 `json_format="repack"` 时返回可传给 `pack()` 的完整实例表结构。
142
+
118
143
  批量处理目录:
119
144
 
120
145
  ```python
@@ -4,9 +4,9 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "PyREUser3"
7
- version = "0.2.0"
7
+ version = "0.4.0"
8
8
  description = "Pure Python tools for converting RE Engine .user.3 files to and from JSON."
9
- readme = "README.md"
9
+ readme = "docs/PYPI.md"
10
10
  requires-python = ">=3.9"
11
11
  license = "MIT"
12
12
  license-files = ["LICENSE"]
@@ -11,7 +11,7 @@ import inspect
11
11
  import json
12
12
  import re
13
13
  from pathlib import Path
14
- from typing import Any, Callable, Optional
14
+ from typing import Any, Callable, Literal, Optional
15
15
 
16
16
  from .core import RSZ_MAGIC, USR_MAGIC
17
17
  from .export import User3Exporter
@@ -20,6 +20,7 @@ from .pack import User3Packer
20
20
  # Preserve the exported JSON structure so external scripts and hand-edited files remain
21
21
  # compatible across workflows.
22
22
  JsonTree = Any
23
+ JsonFormat = Literal["readable", "repack"]
23
24
  # Patch callbacks may accept only the parsed data or both the data and source
24
25
  # path; returning None means the callback mutated in place.
25
26
  PatchCallback = Callable[..., Optional[JsonTree]]
@@ -104,7 +105,11 @@ class REUser3Converter:
104
105
  # Reuse parse_file so single-file and batch exports keep the same parsed JSON shape and metadata handling.
105
106
  # Preserve the exported JSON structure so external scripts and hand-edited files
106
107
  # remain compatible across workflows.
107
- tree = self.parse_file(user3_path, round_floats=True)
108
+ tree = self.user3_to_json(
109
+ user3_path,
110
+ json_format="readable",
111
+ round_floats=True,
112
+ )
108
113
  target = Path(json_path)
109
114
  target.parent.mkdir(parents=True, exist_ok=True)
110
115
 
@@ -112,6 +117,37 @@ class REUser3Converter:
112
117
  json.dump(tree, f, ensure_ascii=False, indent=2)
113
118
  return target
114
119
 
120
+ def user3_to_json(
121
+ self,
122
+ user3_path: str | Path,
123
+ json_format: JsonFormat = "readable",
124
+ round_floats: bool = True,
125
+ ) -> JsonTree:
126
+ """Convert one .user.3 file to an in-memory JSON-compatible tree.
127
+
128
+ Args:
129
+ user3_path (str | Path): Path to the .user.3 file being parsed.
130
+ json_format (JsonFormat): Return "readable" for the same shape written by
131
+ export_file(), or "repack" for the full instance-table document accepted by
132
+ pack().
133
+ round_floats (bool): Whether readable-format floats should be rounded to four
134
+ decimal places.
135
+
136
+ Returns:
137
+ JsonTree: JSON-compatible Python data. The readable format preserves the
138
+ existing export shape; the repack format returns a dictionary with pack
139
+ metadata and instance tables.
140
+
141
+ Raises:
142
+ ValueError: json_format was not "readable" or "repack".
143
+ """
144
+ normalized_format = self._normalize_json_format(json_format)
145
+ if normalized_format == "readable":
146
+ return self.parse_file(user3_path, round_floats=round_floats)
147
+ if normalized_format == "repack":
148
+ return self.parse_pack_file(user3_path)
149
+ raise ValueError("json_format must be 'readable' or 'repack'")
150
+
115
151
  def parse_file(self, user3_path: str | Path, round_floats: bool = True) -> JsonTree:
116
152
  """Parse one .user.3 file into the compact exported JSON tree.
117
153
 
@@ -147,6 +183,23 @@ class REUser3Converter:
147
183
  self._prepare_exporter_metadata(exporter)
148
184
  return exporter._parse_user3_pack(Path(user3_path))
149
185
 
186
+ @staticmethod
187
+ def _normalize_json_format(json_format: str) -> str:
188
+ """Normalize the public in-memory JSON format selector.
189
+
190
+ Args:
191
+ json_format (str): Requested JSON output shape.
192
+
193
+ Returns:
194
+ str: Normalized format name.
195
+
196
+ Raises:
197
+ TypeError: The caller supplied a non-string format selector.
198
+ """
199
+ if not isinstance(json_format, str):
200
+ raise TypeError("json_format must be a string")
201
+ return json_format.strip().lower().replace("-", "_")
202
+
150
203
  def pack_directory(
151
204
  self,
152
205
  json_root: str | Path,
@@ -349,17 +402,16 @@ class REUser3Converter:
349
402
  """
350
403
  if self.il2cpp_dump_path is None or not self.il2cpp_dump_path.is_file():
351
404
  raise FileNotFoundError("il2cpp_dump_path is required for parsing JSON")
352
- with self.il2cpp_dump_path.open("r", encoding="utf-8") as f:
353
- il2cpp_dump = json.load(f)
354
405
  # Batch export writes Enums_Internal.json for downstream tools; direct
355
406
  # parsing keeps the same lookup only in memory.
356
407
  # Keep the generated metadata attached to the exporter so field parsing can
357
408
  # format enum names consistently.
358
- enums_internal = exporter.export_enums_internal(il2cpp_dump)
409
+ enums_internal, enum_context = exporter.export_il2cpp_metadata_from_path(
410
+ self.il2cpp_dump_path
411
+ )
359
412
  exporter.enum_lookup = exporter._build_enum_lookup_from_enums_internal(
360
413
  enums_internal
361
414
  )
362
- enum_context = exporter.export_enum_context_internal(il2cpp_dump)
363
415
  exporter._apply_enum_context(enum_context)
364
416
  exporter._ensure_enum_lookup()
365
417
 
@@ -28,6 +28,41 @@ HEX32_RE = re.compile(r"^[0-9a-fA-F]{32}$")
28
28
  # packing stay reversible.
29
29
  ENUM_UNUSED_KEY = "value__"
30
30
 
31
+ ENUM_UNDERLYING_TYPE_MAP = {
32
+ "byte": "U8",
33
+ "system.byte": "U8",
34
+ "u8": "U8",
35
+ "uint8": "U8",
36
+ "sbyte": "S8",
37
+ "system.sbyte": "S8",
38
+ "s8": "S8",
39
+ "int8": "S8",
40
+ "short": "S16",
41
+ "system.int16": "S16",
42
+ "int16": "S16",
43
+ "s16": "S16",
44
+ "ushort": "U16",
45
+ "system.uint16": "U16",
46
+ "uint16": "U16",
47
+ "u16": "U16",
48
+ "int": "S32",
49
+ "system.int32": "S32",
50
+ "int32": "S32",
51
+ "s32": "S32",
52
+ "uint": "U32",
53
+ "system.uint32": "U32",
54
+ "uint32": "U32",
55
+ "u32": "U32",
56
+ "long": "S64",
57
+ "system.int64": "S64",
58
+ "int64": "S64",
59
+ "s64": "S64",
60
+ "ulong": "U64",
61
+ "system.uint64": "U64",
62
+ "uint64": "U64",
63
+ "u64": "U64",
64
+ }
65
+
31
66
 
32
67
  class ParseError(RuntimeError):
33
68
  """Signal expected binary-format problems separately from programming errors.
@@ -52,6 +87,38 @@ def align(value: int, alignment: int) -> int:
52
87
  return (value + (alignment - 1)) & ~(alignment - 1)
53
88
 
54
89
 
90
+ def normalize_enum_storage_type(type_name: Any) -> str | None:
91
+ """Normalize an il2cpp enum underlying type name to an RSZ scalar storage code."""
92
+ if not isinstance(type_name, str):
93
+ return None
94
+ text = type_name.strip()
95
+ if not text:
96
+ return None
97
+ return ENUM_UNDERLYING_TYPE_MAP.get(text.lower())
98
+
99
+
100
+ def enum_storage_type_from_size(size: int) -> str:
101
+ """Choose a conservative enum storage type from a schema-declared byte size."""
102
+ if size == 1:
103
+ return "U8"
104
+ if size == 2:
105
+ return "U16"
106
+ if size == 8:
107
+ return "S64"
108
+ return "S32"
109
+
110
+
111
+ def enum_storage_size(storage_type: str) -> int:
112
+ """Return the byte width for a normalized enum storage type."""
113
+ if storage_type in {"S8", "U8"}:
114
+ return 1
115
+ if storage_type in {"S16", "U16"}:
116
+ return 2
117
+ if storage_type in {"S64", "U64"}:
118
+ return 8
119
+ return 4
120
+
121
+
55
122
  def format_guid_text_from_hex32(hex32: str) -> str:
56
123
  """Format compact hexadecimal GUID text with canonical separators.
57
124
 
@@ -0,0 +1,27 @@
1
+ """Expose the public exporter type for the export subpackage.
2
+
3
+ Implementation details are split across mixins, but callers can import User3Exporter
4
+ from this package directly.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from importlib import import_module
10
+ from typing import Any
11
+
12
+ __all__ = ["User3Exporter"]
13
+
14
+ _EXPORT_MODULES = {
15
+ "User3Exporter": ".base",
16
+ }
17
+
18
+
19
+ def __getattr__(name: str) -> Any:
20
+ """Resolve lazily exported subpackage attributes on first access."""
21
+ module_name = _EXPORT_MODULES.get(name)
22
+ if module_name is None:
23
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
24
+ module = import_module(module_name, __name__)
25
+ value = getattr(module, name)
26
+ globals()[name] = value
27
+ return value
@@ -88,7 +88,9 @@ class User3Exporter(
88
88
  self.serializable_to_fixed: dict[str, str] = {}
89
89
  self.generic_container_rules: dict[str, tuple[str, str]] = {}
90
90
  self.param_type_default_enum: dict[str, str] = {}
91
+ self.enum_underlying_types: dict[str, str] = {}
91
92
  self.enum_member_to_types: dict[str, list[str]] = {}
93
+ self._pending_enum_context: dict | None = None
92
94
 
93
95
  def run(self) -> dict[str, int]:
94
96
  """Run the batch exporter and return conversion counters.