PyLibMS 4.1.6__tar.gz → 4.2.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.
- {pylibms-4.1.6 → pylibms-4.2.0}/PKG-INFO +30 -9
- {pylibms-4.1.6 → pylibms-4.2.0}/PyLibMS.egg-info/PKG-INFO +30 -9
- {pylibms-4.1.6 → pylibms-4.2.0}/README.md +28 -7
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/common/field/io.py +20 -6
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/flowchart/definitions/flowchart.py +5 -2
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/flowchart/definitions/node.py +2 -1
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/flowchart/definitions/node_type.py +22 -2
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/flowchart/flw3.py +14 -4
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/flowchart/msbf.py +4 -8
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/definitions/nodes.py +9 -2
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/Tomodachi Life NA-EU.yaml +1 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/pyproject.toml +12 -2
- {pylibms-4.1.6 → pylibms-4.2.0}/LICENSE +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/MANIFEST.in +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/PyLibMS.egg-info/SOURCES.txt +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/PyLibMS.egg-info/dependency_links.txt +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/PyLibMS.egg-info/requires.txt +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/PyLibMS.egg-info/top_level.txt +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/common/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/common/field/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/common/field/lms_datatype.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/common/field/lms_field.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/common/lms_constants.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/common/lms_exceptions.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/common/lms_fileinfo.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/common/stream/fileinfo.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/common/stream/hashtable.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/common/stream/section.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/fileio/encoding.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/fileio/io.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/flowchart/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/flowchart/definitions/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/flowchart/definitions/lms_nodeexceptions.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/flowchart/msbfio.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/definitions/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/definitions/field/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/lms_messagetext.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/msbt.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/msbtentry.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/msbtio.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/section/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/section/atr1.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/section/nli1.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/section/tsy1.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/section/txt2.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/tag/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/tag/io/param_io.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/tag/io/tag_io.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/tag/lms_tag.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/message/tag/lms_tagexceptions.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/definitions/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/definitions/attribute.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/definitions/color.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/definitions/style.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/definitions/tag.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/msbp.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/msbpread.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/section/ali2.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/section/ati2.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/section/clr1.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/section/string.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/section/syl3.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/section/tag2.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/section/tgg2.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/project/section/tgp2.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/config.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/definitions/__init__.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/definitions/attribute.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/definitions/tags.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/definitions/value.py +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/Badge Arcade.yaml +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/Brain Age Concentration Training.yaml +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/Kirby Planet Robobot.yaml +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/Super Mario 3D Land.yaml +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/Super Mario 3D World + Bowsers Fury.yaml +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/Super Mario Odyssey.yaml +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/The Legend of Zelda Echos of Wisdom.yaml +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/The Legend of Zelda a Link Between Worlds.yaml +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/Tomodachi Life Living The Dream.yaml +0 -0
- {pylibms-4.1.6 → pylibms-4.2.0}/setup.cfg +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyLibMS
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.0
|
|
4
4
|
Summary: Python library built for the libMessageStudio (LMS) proprietary file formats from Nintendo. Supports MSBT, MSBP, and MSBF.
|
|
5
5
|
Author: AbdyyEee
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Documentation, https://github.com/AbdyyEee/PylibMS/wiki
|
|
8
8
|
Project-URL: Repository, https://github.com/AbdyyEee/PylibMS
|
|
9
|
-
Keywords: nintendo,
|
|
9
|
+
Keywords: nintendo,msbt,message text,msbp,message project,msbf,message flowchart,flw3,modding,libmessagestudio
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.10
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -23,14 +23,14 @@ Dynamic: license-file
|
|
|
23
23
|
[](https://pypi.org/project/PyLibMS/)
|
|
24
24
|
[](https://badge.fury.io/py/PyLibMS)
|
|
25
25
|
|
|
26
|
-
PyLibMS is a library built
|
|
26
|
+
PyLibMS is a library built in Python 3.10 and above for reading and writing of libMessageStudio (LMS) proprietary file formats from Nintendo.
|
|
27
27
|
|
|
28
28
|
The following is supported
|
|
29
29
|
| Format | Read | Write | Configuration Support |
|
|
30
30
|
|-------------|------|-------|-------------------------------------------------------------------------------------------|
|
|
31
31
|
| `MSBT` | ✅ | ✅ | Support for full attribute (`ATR1`) decoding. Tag decoding 1:1 with the official Nintendo `.mstxt` file format. |
|
|
32
32
|
| `MSBF` | ✅ | ✅ | Support for custom node definitions, attaching names and descriptions to nodes. Altering parameter datatypes for flexibility between games. |
|
|
33
|
-
| `MSBP` | ✅ | ❌ |
|
|
33
|
+
| `MSBP` | ✅ | ❌ | Generating configuration files for use with `MSBT` files. |
|
|
34
34
|
|
|
35
35
|
This library is designed to support LMS revision >=3.0. These include files generated for late **Wii** titles, **Nintendo 3DS**, **Wii U**, **Mobile**, **Nintendo Switch** and **Nintendo Switch 2** games.
|
|
36
36
|
|
|
@@ -41,24 +41,45 @@ and examples.
|
|
|
41
41
|
|
|
42
42
|
## Reading
|
|
43
43
|
|
|
44
|
-
MSBT
|
|
44
|
+
### MSBT
|
|
45
45
|
|
|
46
46
|
```py
|
|
47
47
|
from lms.message.msbtio import read_msbt_path
|
|
48
|
+
|
|
49
|
+
msbt = read_msbt_path("Text.msbt")
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### MSBP
|
|
53
|
+
```py
|
|
54
|
+
from lms.project.msbpread import read_msbp_path
|
|
55
|
+
|
|
56
|
+
msbp = read_msbp_path("Project.msbp")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### MSBF
|
|
61
|
+
```py
|
|
48
62
|
from lms.flowchart.msbfio import read_msbf_path
|
|
49
63
|
|
|
50
|
-
|
|
51
|
-
msbf = read_msbf_path("Game_Flowchart.msbf")
|
|
64
|
+
msbf = read_msbf_path("Flowchart.msbf")
|
|
52
65
|
```
|
|
53
66
|
|
|
67
|
+
|
|
54
68
|
## Writing
|
|
69
|
+
There is no writing for `MSBP` files as most of the time it acts as leftover metadata and not actually loaded by games.
|
|
55
70
|
|
|
71
|
+
### MSBT
|
|
56
72
|
```py
|
|
57
73
|
from lms.message.msbtio import write_msbt_path
|
|
74
|
+
|
|
75
|
+
write_msbt_path("Out_text.msbt")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### MSBF
|
|
79
|
+
```py
|
|
58
80
|
from lms.flowchart.msbfio import write_msbf_path
|
|
59
81
|
|
|
60
|
-
|
|
61
|
-
write_msbf_path("Out_Game_Flowchart.msbt")
|
|
82
|
+
write_msbf_path("Out_Flowchart.msbf")
|
|
62
83
|
```
|
|
63
84
|
|
|
64
85
|
# Adding/Editing Presets
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyLibMS
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.0
|
|
4
4
|
Summary: Python library built for the libMessageStudio (LMS) proprietary file formats from Nintendo. Supports MSBT, MSBP, and MSBF.
|
|
5
5
|
Author: AbdyyEee
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Documentation, https://github.com/AbdyyEee/PylibMS/wiki
|
|
8
8
|
Project-URL: Repository, https://github.com/AbdyyEee/PylibMS
|
|
9
|
-
Keywords: nintendo,
|
|
9
|
+
Keywords: nintendo,msbt,message text,msbp,message project,msbf,message flowchart,flw3,modding,libmessagestudio
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.10
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -23,14 +23,14 @@ Dynamic: license-file
|
|
|
23
23
|
[](https://pypi.org/project/PyLibMS/)
|
|
24
24
|
[](https://badge.fury.io/py/PyLibMS)
|
|
25
25
|
|
|
26
|
-
PyLibMS is a library built
|
|
26
|
+
PyLibMS is a library built in Python 3.10 and above for reading and writing of libMessageStudio (LMS) proprietary file formats from Nintendo.
|
|
27
27
|
|
|
28
28
|
The following is supported
|
|
29
29
|
| Format | Read | Write | Configuration Support |
|
|
30
30
|
|-------------|------|-------|-------------------------------------------------------------------------------------------|
|
|
31
31
|
| `MSBT` | ✅ | ✅ | Support for full attribute (`ATR1`) decoding. Tag decoding 1:1 with the official Nintendo `.mstxt` file format. |
|
|
32
32
|
| `MSBF` | ✅ | ✅ | Support for custom node definitions, attaching names and descriptions to nodes. Altering parameter datatypes for flexibility between games. |
|
|
33
|
-
| `MSBP` | ✅ | ❌ |
|
|
33
|
+
| `MSBP` | ✅ | ❌ | Generating configuration files for use with `MSBT` files. |
|
|
34
34
|
|
|
35
35
|
This library is designed to support LMS revision >=3.0. These include files generated for late **Wii** titles, **Nintendo 3DS**, **Wii U**, **Mobile**, **Nintendo Switch** and **Nintendo Switch 2** games.
|
|
36
36
|
|
|
@@ -41,24 +41,45 @@ and examples.
|
|
|
41
41
|
|
|
42
42
|
## Reading
|
|
43
43
|
|
|
44
|
-
MSBT
|
|
44
|
+
### MSBT
|
|
45
45
|
|
|
46
46
|
```py
|
|
47
47
|
from lms.message.msbtio import read_msbt_path
|
|
48
|
+
|
|
49
|
+
msbt = read_msbt_path("Text.msbt")
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### MSBP
|
|
53
|
+
```py
|
|
54
|
+
from lms.project.msbpread import read_msbp_path
|
|
55
|
+
|
|
56
|
+
msbp = read_msbp_path("Project.msbp")
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
### MSBF
|
|
61
|
+
```py
|
|
48
62
|
from lms.flowchart.msbfio import read_msbf_path
|
|
49
63
|
|
|
50
|
-
|
|
51
|
-
msbf = read_msbf_path("Game_Flowchart.msbf")
|
|
64
|
+
msbf = read_msbf_path("Flowchart.msbf")
|
|
52
65
|
```
|
|
53
66
|
|
|
67
|
+
|
|
54
68
|
## Writing
|
|
69
|
+
There is no writing for `MSBP` files as most of the time it acts as leftover metadata and not actually loaded by games.
|
|
55
70
|
|
|
71
|
+
### MSBT
|
|
56
72
|
```py
|
|
57
73
|
from lms.message.msbtio import write_msbt_path
|
|
74
|
+
|
|
75
|
+
write_msbt_path("Out_text.msbt")
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### MSBF
|
|
79
|
+
```py
|
|
58
80
|
from lms.flowchart.msbfio import write_msbf_path
|
|
59
81
|
|
|
60
|
-
|
|
61
|
-
write_msbf_path("Out_Game_Flowchart.msbt")
|
|
82
|
+
write_msbf_path("Out_Flowchart.msbf")
|
|
62
83
|
```
|
|
63
84
|
|
|
64
85
|
# Adding/Editing Presets
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
[](https://pypi.org/project/PyLibMS/)
|
|
3
3
|
[](https://badge.fury.io/py/PyLibMS)
|
|
4
4
|
|
|
5
|
-
PyLibMS is a library built
|
|
5
|
+
PyLibMS is a library built in Python 3.10 and above for reading and writing of libMessageStudio (LMS) proprietary file formats from Nintendo.
|
|
6
6
|
|
|
7
7
|
The following is supported
|
|
8
8
|
| Format | Read | Write | Configuration Support |
|
|
9
9
|
|-------------|------|-------|-------------------------------------------------------------------------------------------|
|
|
10
10
|
| `MSBT` | ✅ | ✅ | Support for full attribute (`ATR1`) decoding. Tag decoding 1:1 with the official Nintendo `.mstxt` file format. |
|
|
11
11
|
| `MSBF` | ✅ | ✅ | Support for custom node definitions, attaching names and descriptions to nodes. Altering parameter datatypes for flexibility between games. |
|
|
12
|
-
| `MSBP` | ✅ | ❌ |
|
|
12
|
+
| `MSBP` | ✅ | ❌ | Generating configuration files for use with `MSBT` files. |
|
|
13
13
|
|
|
14
14
|
This library is designed to support LMS revision >=3.0. These include files generated for late **Wii** titles, **Nintendo 3DS**, **Wii U**, **Mobile**, **Nintendo Switch** and **Nintendo Switch 2** games.
|
|
15
15
|
|
|
@@ -20,24 +20,45 @@ and examples.
|
|
|
20
20
|
|
|
21
21
|
## Reading
|
|
22
22
|
|
|
23
|
-
MSBT
|
|
23
|
+
### MSBT
|
|
24
24
|
|
|
25
25
|
```py
|
|
26
26
|
from lms.message.msbtio import read_msbt_path
|
|
27
|
+
|
|
28
|
+
msbt = read_msbt_path("Text.msbt")
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### MSBP
|
|
32
|
+
```py
|
|
33
|
+
from lms.project.msbpread import read_msbp_path
|
|
34
|
+
|
|
35
|
+
msbp = read_msbp_path("Project.msbp")
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### MSBF
|
|
40
|
+
```py
|
|
27
41
|
from lms.flowchart.msbfio import read_msbf_path
|
|
28
42
|
|
|
29
|
-
|
|
30
|
-
msbf = read_msbf_path("Game_Flowchart.msbf")
|
|
43
|
+
msbf = read_msbf_path("Flowchart.msbf")
|
|
31
44
|
```
|
|
32
45
|
|
|
46
|
+
|
|
33
47
|
## Writing
|
|
48
|
+
There is no writing for `MSBP` files as most of the time it acts as leftover metadata and not actually loaded by games.
|
|
34
49
|
|
|
50
|
+
### MSBT
|
|
35
51
|
```py
|
|
36
52
|
from lms.message.msbtio import write_msbt_path
|
|
53
|
+
|
|
54
|
+
write_msbt_path("Out_text.msbt")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### MSBF
|
|
58
|
+
```py
|
|
37
59
|
from lms.flowchart.msbfio import write_msbf_path
|
|
38
60
|
|
|
39
|
-
|
|
40
|
-
write_msbf_path("Out_Game_Flowchart.msbt")
|
|
61
|
+
write_msbf_path("Out_Flowchart.msbf")
|
|
41
62
|
```
|
|
42
63
|
|
|
43
64
|
# Adding/Editing Presets
|
|
@@ -8,7 +8,8 @@ from lms.fileio.io import FileReader, FileWriter
|
|
|
8
8
|
from lms.titleconfig.definitions.value import ValueDefinition
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def read_field(reader: FileReader, definition: ValueDefinition
|
|
11
|
+
def read_field(reader: FileReader, definition: ValueDefinition,
|
|
12
|
+
read_variable_width_value: Callable | None = None) -> LMS_Field:
|
|
12
13
|
# String is excluded as their reading varies between MSBT/MSBF
|
|
13
14
|
match definition.datatype:
|
|
14
15
|
case LMS_DataType.UINT8:
|
|
@@ -26,17 +27,23 @@ def read_field(reader: FileReader, definition: ValueDefinition) -> LMS_Field:
|
|
|
26
27
|
case LMS_DataType.FLOAT32:
|
|
27
28
|
value = reader.read_float32()
|
|
28
29
|
case LMS_DataType.LIST:
|
|
29
|
-
|
|
30
|
+
if read_variable_width_value is not None:
|
|
31
|
+
index = read_variable_width_value()
|
|
32
|
+
else:
|
|
33
|
+
index = reader.read_uint8()
|
|
30
34
|
value = definition.list_items[index]
|
|
31
35
|
case LMS_DataType.BOOL:
|
|
32
|
-
|
|
36
|
+
if read_variable_width_value is not None:
|
|
37
|
+
value = bool(read_variable_width_value())
|
|
38
|
+
else:
|
|
39
|
+
value = bool(reader.read_uint8())
|
|
33
40
|
case LMS_DataType.BYTES:
|
|
34
41
|
value = reader.read_bytes(1)
|
|
35
42
|
|
|
36
43
|
return LMS_Field(value, definition) # type: ignore
|
|
37
44
|
|
|
38
45
|
|
|
39
|
-
def write_field(writer: FileWriter, field: LMS_Field) -> None:
|
|
46
|
+
def write_field(writer: FileWriter, field: LMS_Field, write_variable_width_value: Callable | None = None) -> None:
|
|
40
47
|
if is_number_datatype(field.value, field.datatype):
|
|
41
48
|
write_functions: dict[LMS_DataType, Callable] = {
|
|
42
49
|
LMS_DataType.UINT8: writer.write_uint8,
|
|
@@ -51,10 +58,17 @@ def write_field(writer: FileWriter, field: LMS_Field) -> None:
|
|
|
51
58
|
return
|
|
52
59
|
|
|
53
60
|
if is_list_datatype(field.value, field.datatype):
|
|
54
|
-
|
|
61
|
+
value = field.list_items.index(field.value)
|
|
62
|
+
if write_variable_width_value is not None:
|
|
63
|
+
write_variable_width_value(value)
|
|
64
|
+
else:
|
|
65
|
+
writer.write_uint8(value)
|
|
55
66
|
elif is_bytes_datatype(field.value, field.datatype):
|
|
56
67
|
writer.write_bytes(field.value)
|
|
57
68
|
elif is_bool_datatype(field.value, field.datatype):
|
|
58
|
-
|
|
69
|
+
if write_variable_width_value is not None:
|
|
70
|
+
write_variable_width_value(bool(field.value))
|
|
71
|
+
else:
|
|
72
|
+
writer.write_uint8(bool(field.value))
|
|
59
73
|
else:
|
|
60
74
|
raise ValueError(f"Unsupported datatype: {field.datatype}")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from types import MappingProxyType
|
|
2
|
-
from typing import Callable
|
|
2
|
+
from typing import Callable, Iterator
|
|
3
3
|
|
|
4
4
|
from lms.flowchart.definitions.node import LMS_EntryNode, LMS_BranchNode, LMS_BaseNode
|
|
5
5
|
|
|
@@ -16,6 +16,9 @@ class LMS_Flowchart:
|
|
|
16
16
|
for node in entry_point.get_descendents():
|
|
17
17
|
self._nodes[node.id] = node
|
|
18
18
|
|
|
19
|
+
def __iter__(self) -> Iterator[LMS_BaseNode]:
|
|
20
|
+
return iter(self._nodes.values())
|
|
21
|
+
|
|
19
22
|
def __len__(self) -> int:
|
|
20
23
|
return len(self._nodes)
|
|
21
24
|
|
|
@@ -89,7 +92,7 @@ class LMS_Flowchart:
|
|
|
89
92
|
|
|
90
93
|
del self._nodes[node_id]
|
|
91
94
|
|
|
92
|
-
def get_dangling_nodes(self):
|
|
95
|
+
def get_dangling_nodes(self) -> list[LMS_BaseNode]:
|
|
93
96
|
"""
|
|
94
97
|
Retrieves all the nodes that do not have a parent in the flowchart.
|
|
95
98
|
"""
|
|
@@ -365,6 +365,7 @@ class LMS_EventNode(LMS_BaseNode):
|
|
|
365
365
|
|
|
366
366
|
:param parameter_type: the parameter type.
|
|
367
367
|
:param parameter_value: the parameter value.
|
|
368
|
+
:param action_id: the action_id of the node.
|
|
368
369
|
|
|
369
370
|
"""
|
|
370
371
|
verify_parameter_structure(parameter_value, parameter_type)
|
|
@@ -435,7 +436,7 @@ class LMS_JumpNode(LMS_BaseNode):
|
|
|
435
436
|
self.next_flowchart: LMS_EntryNode | None = None
|
|
436
437
|
|
|
437
438
|
# TODO: Document this unknown value at 0xA in the node
|
|
438
|
-
# This value is usually -1 in TL but is a set value in other games
|
|
439
|
+
# This value is usually -1 in TL 3DS but is a set value in other games
|
|
439
440
|
self.unknown_short0a = unknown_short0a
|
|
440
441
|
|
|
441
442
|
@classmethod
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
from typing import Type
|
|
2
1
|
from enum import IntEnum
|
|
2
|
+
from typing import Type
|
|
3
3
|
|
|
4
|
-
from lms.common.
|
|
4
|
+
from lms.common.field.lms_datatype import LMS_DataType
|
|
5
5
|
|
|
6
6
|
PARAMETER_ALIASES = {
|
|
7
7
|
"p32_0": "PARAM_32_0",
|
|
@@ -53,8 +53,27 @@ class LMS_NodeParameterType(IntEnum):
|
|
|
53
53
|
PARAM_32_1 = 6
|
|
54
54
|
NONE = -1
|
|
55
55
|
|
|
56
|
+
@property
|
|
57
|
+
def sliced_datatype(self):
|
|
58
|
+
"""The parameter type split into the raw datatypes. Not valid for PARAM_32_0, PARAM_32_1, and STRING."""
|
|
59
|
+
if self in [
|
|
60
|
+
LMS_NodeParameterType.NONE,
|
|
61
|
+
LMS_NodeParameterType.PARAM_32_0,
|
|
62
|
+
LMS_NodeParameterType.PARAM_32_1,
|
|
63
|
+
LMS_NodeParameterType.STRING]:
|
|
64
|
+
raise TypeError(f"There is no sliced datatypes for {self} parameter types!")
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
LMS_NodeParameterType.PARAM_16_16: (LMS_DataType.UINT16, LMS_DataType.UINT16),
|
|
68
|
+
LMS_NodeParameterType.PARAM_16_8_8: (LMS_DataType.UINT16, LMS_DataType.UINT8, LMS_DataType.UINT8),
|
|
69
|
+
LMS_NodeParameterType.PARAM_8_8_16: (LMS_DataType.UINT8, LMS_DataType.UINT8, LMS_DataType.UINT16),
|
|
70
|
+
LMS_NodeParameterType.PARAM_8_8_8_8: (LMS_DataType.UINT8, LMS_DataType.UINT8, LMS_DataType.UINT8,
|
|
71
|
+
LMS_DataType.UINT8)
|
|
72
|
+
}[self]
|
|
73
|
+
|
|
56
74
|
@property
|
|
57
75
|
def value_count(self) -> int:
|
|
76
|
+
"""Amount of values the parameter holds."""
|
|
58
77
|
if self is LMS_NodeParameterType.NONE:
|
|
59
78
|
raise TypeError("There is no value count for NONE parameter types!")
|
|
60
79
|
|
|
@@ -70,6 +89,7 @@ class LMS_NodeParameterType(IntEnum):
|
|
|
70
89
|
|
|
71
90
|
@property
|
|
72
91
|
def builtin_type(self) -> Type[int] | Type[tuple[int, ...]] | Type[str]:
|
|
92
|
+
"""The builtin type of the parameter type."""
|
|
73
93
|
if self is LMS_NodeParameterType.NONE:
|
|
74
94
|
raise TypeError("There is no builtin type for NONE parameter types!")
|
|
75
95
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from lms.common.field.io import read_field, write_field
|
|
2
|
+
from lms.common.field.lms_datatype import LMS_DataType
|
|
2
3
|
from lms.common.field.lms_field import LMS_FieldMap, LMS_Field
|
|
3
4
|
from lms.common.lms_exceptions import LMS_Error
|
|
4
5
|
from lms.fileio.io import FileReader, FileWriter
|
|
@@ -13,6 +14,8 @@ NO_NEXT_NODE = 0xFFFF
|
|
|
13
14
|
FLW3_HEADER_SIZE = 16
|
|
14
15
|
NODE_SIZE = 16
|
|
15
16
|
|
|
17
|
+
VARIABLE_WIDTH_DATATYPES = (LMS_DataType.BOOL, LMS_DataType.LIST)
|
|
18
|
+
|
|
16
19
|
|
|
17
20
|
def read_flw3(reader: FileReader, config: NodeConfig | None, msbt: MSBT | None, ) -> tuple[
|
|
18
21
|
int, dict[int, LMS_EntryNode]]:
|
|
@@ -155,8 +158,10 @@ def evaluate_node_parameter(reader: FileReader,
|
|
|
155
158
|
param_definition.name: LMS_Field(value, param_definition)
|
|
156
159
|
})
|
|
157
160
|
|
|
158
|
-
for param_definition in definition.parameter_definitions:
|
|
159
|
-
|
|
161
|
+
for i, param_definition in enumerate(definition.parameter_definitions):
|
|
162
|
+
stream_map = {1: reader.read_uint8, 2: reader.read_uint16, 3: reader.read_uint32}
|
|
163
|
+
result[param_definition.name] = read_field(reader, param_definition,
|
|
164
|
+
stream_map[parameter_type.sliced_datatype[i].stream_size])
|
|
160
165
|
|
|
161
166
|
return LMS_FieldMap(result)
|
|
162
167
|
else:
|
|
@@ -297,8 +302,13 @@ def write_node_parameter(writer: FileWriter,
|
|
|
297
302
|
value: LMS_NodeParameter,
|
|
298
303
|
parameter_type: LMS_NodeParameterType) -> None:
|
|
299
304
|
if isinstance(value, LMS_FieldMap):
|
|
300
|
-
for field in value:
|
|
301
|
-
|
|
305
|
+
for i, field in enumerate(value):
|
|
306
|
+
# In MSBF files there could be a case where naturally one bit datatypes take up 2/4 bits.
|
|
307
|
+
if field.datatype in VARIABLE_WIDTH_DATATYPES:
|
|
308
|
+
stream_map = {1: writer.write_uint8, 2: writer.write_uint16, 3: writer.write_uint32}
|
|
309
|
+
write_field(writer, field, stream_map[parameter_type.sliced_datatype[i].stream_size])
|
|
310
|
+
else:
|
|
311
|
+
write_field(writer, field)
|
|
302
312
|
return
|
|
303
313
|
|
|
304
314
|
match parameter_type:
|
|
@@ -63,17 +63,13 @@ class MSBF:
|
|
|
63
63
|
"""The flowcharts of the MSBF instance."""
|
|
64
64
|
return MappingProxyType({flowchart.name: flowchart for flowchart in self._flowcharts})
|
|
65
65
|
|
|
66
|
-
@property
|
|
67
|
-
def global_node_id(self) -> int:
|
|
68
|
-
"""Current node ID count."""
|
|
69
|
-
return self._global_node_id
|
|
70
|
-
|
|
71
66
|
def set_global_id_count(self, value: int) -> None:
|
|
72
|
-
if value < self._global_node_id:
|
|
73
|
-
raise ValueError("Cannot decrease global node ID below existing count.")
|
|
74
67
|
self._global_node_id = value
|
|
75
68
|
|
|
76
69
|
def generate_next_id(self) -> int:
|
|
70
|
+
"""
|
|
71
|
+
Lazy generation for the next ID of a node. IDs are normalized properly when the msbf file is being written.
|
|
72
|
+
"""
|
|
77
73
|
next_id = self._global_node_id
|
|
78
74
|
self._global_node_id += 1
|
|
79
75
|
return next_id
|
|
@@ -97,7 +93,7 @@ class MSBF:
|
|
|
97
93
|
def delete_flowchart(self, name: str):
|
|
98
94
|
"""Delete a flowchart from the MSBF instance."""
|
|
99
95
|
|
|
100
|
-
if name not in self.
|
|
96
|
+
if name not in self.flowcharts:
|
|
101
97
|
raise KeyError(f"Flowchart with name {name} does not exist!")
|
|
102
98
|
|
|
103
99
|
del self._flowcharts[name]
|
|
@@ -55,11 +55,13 @@ class NodeDefinition:
|
|
|
55
55
|
type: LMS_NodeType.BRANCH | LMS_NodeType.EVENT
|
|
56
56
|
parameter_type: LMS_NodeParameterType
|
|
57
57
|
parameter_definitions: tuple[ValueDefinition, ...]
|
|
58
|
+
case_format: str | None
|
|
58
59
|
next_node_dependency: bool = False
|
|
59
60
|
|
|
60
61
|
@classmethod
|
|
61
62
|
def from_dict(cls, id: int, node_type: LMS_NodeType, data: dict) -> NodeDefinition:
|
|
62
63
|
|
|
64
|
+
description = data.get("description", "")
|
|
63
65
|
converted_parameters: list[ValueDefinition] = []
|
|
64
66
|
parameter_type = LMS_NodeParameterType.from_string(data["parameter_type"])
|
|
65
67
|
|
|
@@ -83,15 +85,19 @@ class NodeDefinition:
|
|
|
83
85
|
(LMS_DataType.UINT8, LMS_DataType.UINT8, LMS_DataType.UINT8, LMS_DataType.UINT8)[i]
|
|
84
86
|
case LMS_NodeParameterType.STRING:
|
|
85
87
|
datatype_from_dict = LMS_DataType.STRING
|
|
86
|
-
definition = ValueDefinition(parameter["name"],
|
|
88
|
+
definition = ValueDefinition(parameter["name"], description, datatype_from_dict,
|
|
87
89
|
list_items)
|
|
88
90
|
else:
|
|
89
|
-
definition = ValueDefinition(parameter["name"],
|
|
91
|
+
definition = ValueDefinition(parameter["name"], description,
|
|
90
92
|
LMS_DataType.from_string(datatype_from_dict),
|
|
91
93
|
list_items)
|
|
92
94
|
|
|
93
95
|
converted_parameters.append(definition)
|
|
94
96
|
|
|
97
|
+
# case_format is only for branch nodesa
|
|
98
|
+
if (case_format := data.get("case_format", None)) is not None and type == LMS_NodeType.EVENT:
|
|
99
|
+
raise ValueError("There may only be case_format for branch nodes!")
|
|
100
|
+
|
|
95
101
|
return NodeDefinition(
|
|
96
102
|
name=data["name"],
|
|
97
103
|
id=id,
|
|
@@ -99,5 +105,6 @@ class NodeDefinition:
|
|
|
99
105
|
type=node_type,
|
|
100
106
|
parameter_type=parameter_type,
|
|
101
107
|
parameter_definitions=converted_parameters,
|
|
108
|
+
case_format=case_format,
|
|
102
109
|
next_node_dependency=data.get("next_node_dependency", False)
|
|
103
110
|
)
|
|
@@ -7,12 +7,22 @@ include = ["lms*"]
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "PyLibMS"
|
|
10
|
-
version = "4.
|
|
10
|
+
version = "4.2.0"
|
|
11
11
|
requires-python = ">=3.10"
|
|
12
12
|
description = "Python library built for the libMessageStudio (LMS) proprietary file formats from Nintendo. Supports MSBT, MSBP, and MSBF."
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
authors = [{ name = "AbdyyEee" }]
|
|
15
|
-
keywords = [
|
|
15
|
+
keywords = [
|
|
16
|
+
"nintendo",
|
|
17
|
+
"msbt",
|
|
18
|
+
"message text",
|
|
19
|
+
"msbp",
|
|
20
|
+
"message project",
|
|
21
|
+
"msbf",
|
|
22
|
+
"message flowchart",
|
|
23
|
+
"flw3",
|
|
24
|
+
"modding",
|
|
25
|
+
"libmessagestudio"]
|
|
16
26
|
license = "MIT"
|
|
17
27
|
license-files = ["LICENSE*"]
|
|
18
28
|
classifiers = [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/Brain Age Concentration Training.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/Super Mario 3D World + Bowsers Fury.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/The Legend of Zelda Echos of Wisdom.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{pylibms-4.1.6 → pylibms-4.2.0}/lms/titleconfig/presets/Tomodachi Life Living The Dream.yaml
RENAMED
|
File without changes
|
|
File without changes
|