PyLibMS 4.3.2__tar.gz → 4.3.4__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.3.2 → pylibms-4.3.4}/PKG-INFO +1 -1
- {pylibms-4.3.2 → pylibms-4.3.4}/PyLibMS.egg-info/PKG-INFO +1 -1
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/common/lms_constants.py +2 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/common/stream/fileinfo.py +2 -2
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/flowchart/definitions/node.py +17 -10
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/flowchart/msbf.py +16 -8
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/flowchart/msbfio.py +3 -9
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/section/tag2.py +3 -1
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/section/tgg2.py +3 -1
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/section/tgp2.py +3 -1
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/config.py +24 -32
- {pylibms-4.3.2 → pylibms-4.3.4}/pyproject.toml +1 -1
- {pylibms-4.3.2 → pylibms-4.3.4}/LICENSE +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/MANIFEST.in +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/PyLibMS.egg-info/SOURCES.txt +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/PyLibMS.egg-info/dependency_links.txt +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/PyLibMS.egg-info/requires.txt +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/PyLibMS.egg-info/top_level.txt +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/README.md +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/common/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/common/field/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/common/field/io.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/common/field/lms_datatype.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/common/field/lms_field.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/common/lms_exceptions.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/common/lms_fileinfo.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/common/stream/hashtable.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/common/stream/section.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/fileio/encoding.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/fileio/io.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/flowchart/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/flowchart/definitions/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/flowchart/definitions/flowchart.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/flowchart/definitions/lms_nodeexceptions.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/flowchart/definitions/node_type.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/flowchart/flw3.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/definitions/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/definitions/field/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/lms_messagetext.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/msbt.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/msbtentry.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/msbtio.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/section/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/section/atr1.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/section/nli1.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/section/tsy1.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/section/txt2.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/tag/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/tag/io/param_io.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/tag/io/tag_io.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/tag/lms_tag.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/message/tag/lms_tagexceptions.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/definitions/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/definitions/attribute.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/definitions/color.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/definitions/style.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/definitions/tag.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/msbp.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/msbpread.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/section/ali2.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/section/ati2.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/section/clr1.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/section/string.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/project/section/syl3.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/definitions/__init__.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/definitions/attribute.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/definitions/nodes.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/definitions/tags.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/definitions/value.py +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/Badge Arcade.yaml +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/Brain Age Concentration Training.yaml +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/Kirby Planet Robobot.yaml +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/Super Mario 3D Land.yaml +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/Super Mario 3D World + Bowsers Fury.yaml +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/Super Mario Odyssey.yaml +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/The Legend of Zelda Echos of Wisdom.yaml +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/The Legend of Zelda a Link Between Worlds.yaml +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/Tomodachi Life Living The Dream.yaml +0 -0
- {pylibms-4.3.2 → pylibms-4.3.4}/setup.cfg +0 -0
|
@@ -3,7 +3,7 @@ from lms.common.lms_constants import (
|
|
|
3
3
|
BIG_ENDIAN_BOM,
|
|
4
4
|
SECTION_DATA_START,
|
|
5
5
|
LITTLE_ENDIAN_BOM,
|
|
6
|
-
SIZE_OFFSET,
|
|
6
|
+
SIZE_OFFSET, LMS_MINIMUM_VERSION,
|
|
7
7
|
)
|
|
8
8
|
from lms.common.lms_fileinfo import LMS_FileInfo
|
|
9
9
|
from lms.fileio.encoding import FileEncoding
|
|
@@ -29,7 +29,7 @@ def read_file_info(reader: FileReader, expected_magic: str) -> LMS_FileInfo:
|
|
|
29
29
|
|
|
30
30
|
version = reader.read_uint8()
|
|
31
31
|
|
|
32
|
-
if version <
|
|
32
|
+
if version < LMS_MINIMUM_VERSION:
|
|
33
33
|
raise lms_exceptions.LMS_UnsupportedFileVersionError(
|
|
34
34
|
"Only version 3+ files are supported!"
|
|
35
35
|
)
|
|
@@ -185,7 +185,7 @@ class LMS_MessageNode(LMS_BaseNode):
|
|
|
185
185
|
|
|
186
186
|
@property
|
|
187
187
|
def msbt(self) -> MSBT | None:
|
|
188
|
-
"""MSBT instance the node references. Optional,
|
|
188
|
+
"""MSBT instance the node references. Optional, is set by providing a MSBT file on reading."""
|
|
189
189
|
return self._msbt
|
|
190
190
|
|
|
191
191
|
@property
|
|
@@ -313,26 +313,33 @@ class LMS_BranchNode(LMS_BaseNode):
|
|
|
313
313
|
case_map.setdefault(branch, []).append(case)
|
|
314
314
|
|
|
315
315
|
if self.definition is not None:
|
|
316
|
-
|
|
316
|
+
definition: NodeDefinition = self.definition
|
|
317
|
+
|
|
318
|
+
if definition.case_options:
|
|
317
319
|
for case, branch in self._branches.items():
|
|
318
|
-
|
|
319
|
-
case,
|
|
320
|
+
case_format = definition.case_options.get(
|
|
321
|
+
case, None,
|
|
320
322
|
)
|
|
321
323
|
|
|
322
|
-
|
|
324
|
+
if case_format is None:
|
|
325
|
+
formatted_message = f"Case {case}"
|
|
326
|
+
else:
|
|
327
|
+
formatted_message = self._format_case_message(case, case_format)
|
|
328
|
+
|
|
329
|
+
result.append(((case,), formatted_message, branch))
|
|
323
330
|
|
|
324
331
|
return result
|
|
325
332
|
|
|
326
|
-
if
|
|
333
|
+
if definition.case_format is not None:
|
|
327
334
|
if compress_shared_references:
|
|
328
335
|
for branch, cases in case_map.items():
|
|
329
336
|
case_message = self._format_case_message(
|
|
330
|
-
merge_shared_cases(cases)
|
|
337
|
+
merge_shared_cases(cases), definition.case_format
|
|
331
338
|
)
|
|
332
339
|
result.append((tuple(cases), case_message, branch))
|
|
333
340
|
else:
|
|
334
341
|
for case, branch in self._branches.items():
|
|
335
|
-
case_message = self._format_case_message(case)
|
|
342
|
+
case_message = self._format_case_message(case, definition.case_format)
|
|
336
343
|
result.append(((case,), case_message, branch))
|
|
337
344
|
|
|
338
345
|
return result
|
|
@@ -352,8 +359,8 @@ class LMS_BranchNode(LMS_BaseNode):
|
|
|
352
359
|
|
|
353
360
|
return result
|
|
354
361
|
|
|
355
|
-
def _format_case_message(self, case_prefix: str):
|
|
356
|
-
prefix = string.Template(
|
|
362
|
+
def _format_case_message(self, case_prefix: str, case_format: str):
|
|
363
|
+
prefix = string.Template(case_format)
|
|
357
364
|
|
|
358
365
|
# Unpack dict for formatting $case and $param formats
|
|
359
366
|
# Allows inserting parameter values dynamically into the case message
|
|
@@ -22,14 +22,17 @@ class MSBF:
|
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
24
|
MAGIC = "MsgFlwBn"
|
|
25
|
-
|
|
26
25
|
DEFAULT_SLOT_COUNT = 59
|
|
27
26
|
|
|
28
27
|
def __init__(
|
|
29
28
|
self, info: LMS_FileInfo | None = None, flowcharts: list[LMS_Flowchart] = None
|
|
30
29
|
):
|
|
31
30
|
self._info = info if info is not None else LMS_FileInfo()
|
|
32
|
-
|
|
31
|
+
|
|
32
|
+
# While unlikely to vary, and have yet to find a file that changes the slot count (unlike MSBT)
|
|
33
|
+
# it is wiser to store an editable attribute just in case a game decides to vary the amount.
|
|
34
|
+
self.slot_count = MSBF.DEFAULT_SLOT_COUNT
|
|
35
|
+
|
|
33
36
|
self._flowcharts = flowcharts or []
|
|
34
37
|
self._nodes: dict[int, LMS_BaseNode] = {}
|
|
35
38
|
self._global_node_id = 0
|
|
@@ -77,7 +80,11 @@ class MSBF:
|
|
|
77
80
|
)
|
|
78
81
|
|
|
79
82
|
def get_flowchart_references(self, node_id: int) -> set[LMS_Flowchart]:
|
|
80
|
-
"""
|
|
83
|
+
"""
|
|
84
|
+
Determines which flowcharts contain this node.
|
|
85
|
+
|
|
86
|
+
:param node_id: The node to find references for.
|
|
87
|
+
"""
|
|
81
88
|
return {flowchart for flowchart in self._flowcharts if node_id in flowchart.nodes}
|
|
82
89
|
|
|
83
90
|
def register_node(self, node: LMS_BaseNode, flowchart: LMS_Flowchart = None) -> None:
|
|
@@ -85,7 +92,7 @@ class MSBF:
|
|
|
85
92
|
Registers a node to the MSBF instance.
|
|
86
93
|
|
|
87
94
|
:param node: The node to register.
|
|
88
|
-
:param flowchart:
|
|
95
|
+
:param flowchart: Optional argument that registers the node to that flowchart.
|
|
89
96
|
"""
|
|
90
97
|
if not isinstance(node, LMS_BaseNode):
|
|
91
98
|
raise TypeError(
|
|
@@ -135,10 +142,6 @@ class MSBF:
|
|
|
135
142
|
if flowchart_name in self.flowcharts:
|
|
136
143
|
raise KeyError(f"Flowchart with name '{flowchart_name}' already exists!")
|
|
137
144
|
|
|
138
|
-
# Node IDs may not be sequential after user additions/deletions, so we track the absolute max value of
|
|
139
|
-
# all nodes and store it so that _generate_next_id can set any IDs added via the flowchart correctly.
|
|
140
|
-
self._global_node_id = max((node.id for flowchart in self for node in flowchart), default=1) + 1
|
|
141
|
-
|
|
142
145
|
if entry_point is None:
|
|
143
146
|
entry_point = LMS_EntryNode(self._generate_next_id(), flowchart_name)
|
|
144
147
|
|
|
@@ -150,6 +153,11 @@ class MSBF:
|
|
|
150
153
|
self._nodes[node_id] = node
|
|
151
154
|
|
|
152
155
|
self._nodes = dict(sorted(self._nodes.items()))
|
|
156
|
+
|
|
157
|
+
# Node IDs may not be sequential after user additions/deletions, so we track the absolute max value of
|
|
158
|
+
# all nodes and store it so that _generate_next_id can set any IDs added via the flowchart correctly.
|
|
159
|
+
self._global_node_id = max(self._nodes, default=-1) + 1
|
|
160
|
+
|
|
153
161
|
return flowchart
|
|
154
162
|
|
|
155
163
|
def delete_flowchart(self, name: str):
|
|
@@ -59,13 +59,12 @@ def read_msbf(
|
|
|
59
59
|
file_info = read_file_info(reader, MSBF.MAGIC)
|
|
60
60
|
|
|
61
61
|
msbf = MSBF(file_info)
|
|
62
|
-
|
|
63
62
|
for magic, size in read_section_data(reader, file_info.section_count):
|
|
64
63
|
match magic:
|
|
65
64
|
case "FLW3":
|
|
66
65
|
entry_nodes = read_flw3(reader, config, msbt)
|
|
67
66
|
case "FEN1":
|
|
68
|
-
labels,
|
|
67
|
+
labels, slot_count = read_labels(reader)
|
|
69
68
|
case "REF1":
|
|
70
69
|
raise LMS_UnsupportedSectionError("""REF1 was found in the MSBF file! Please report this file as an issue
|
|
71
70
|
in the PyLibMS repository https://github.com/AbdyyEee/PylibMS""")
|
|
@@ -74,6 +73,7 @@ def read_msbf(
|
|
|
74
73
|
entry_nodes[i].flowchart_name = label
|
|
75
74
|
msbf.add_flowchart(label, entry_nodes[i])
|
|
76
75
|
|
|
76
|
+
msbf.slot_count = slot_count
|
|
77
77
|
return msbf
|
|
78
78
|
|
|
79
79
|
|
|
@@ -115,12 +115,6 @@ def write_msbf(file: MSBF) -> bytes:
|
|
|
115
115
|
# Saved here so ids aren't mutated in the current state
|
|
116
116
|
stream_ids = {node: stream_id for stream_id, node in enumerate(file.nodes.values())}
|
|
117
117
|
|
|
118
|
-
for chart in file:
|
|
119
|
-
if amount := len(chart.get_dangling_nodes()):
|
|
120
|
-
raise LMS_Error(
|
|
121
|
-
f"Unable to write the flowchart '{chart.name}'! There are {amount} dangling nodes."
|
|
122
|
-
)
|
|
123
|
-
|
|
124
118
|
index_map = {
|
|
125
119
|
flowchart.name: stream_ids[flowchart.entry_point] for flowchart in file
|
|
126
120
|
}
|
|
@@ -131,7 +125,7 @@ def write_msbf(file: MSBF) -> bytes:
|
|
|
131
125
|
"FEN1",
|
|
132
126
|
write_labels,
|
|
133
127
|
list(file.flowcharts.keys()),
|
|
134
|
-
|
|
128
|
+
file.slot_count,
|
|
135
129
|
index_map,
|
|
136
130
|
)
|
|
137
131
|
write_file_size(writer)
|
|
@@ -5,7 +5,8 @@ from lms.project.definitions.tag import LMS_TagDefinition
|
|
|
5
5
|
def read_tag2(reader: FileReader) -> list[LMS_TagDefinition]:
|
|
6
6
|
info_list = []
|
|
7
7
|
|
|
8
|
-
count = reader.
|
|
8
|
+
count = reader.read_uint16()
|
|
9
|
+
reader.skip(2)
|
|
9
10
|
for offset in reader.read_offset_array(count):
|
|
10
11
|
reader.seek(offset)
|
|
11
12
|
|
|
@@ -14,5 +15,6 @@ def read_tag2(reader: FileReader) -> list[LMS_TagDefinition]:
|
|
|
14
15
|
name = reader.read_encoded_string()
|
|
15
16
|
|
|
16
17
|
info_list.append(LMS_TagDefinition(name, parameter_indices))
|
|
18
|
+
reader.align(4)
|
|
17
19
|
|
|
18
20
|
return info_list
|
|
@@ -5,7 +5,8 @@ from lms.project.definitions.tag import LMS_TagGroup
|
|
|
5
5
|
def read_tgg2(reader: FileReader, version: int) -> list[LMS_TagGroup]:
|
|
6
6
|
group_list = []
|
|
7
7
|
|
|
8
|
-
count = reader.
|
|
8
|
+
count = reader.read_uint16()
|
|
9
|
+
reader.skip(2)
|
|
9
10
|
for i, offset in enumerate(reader.read_offset_array(count)):
|
|
10
11
|
reader.seek(offset)
|
|
11
12
|
|
|
@@ -18,5 +19,6 @@ def read_tgg2(reader: FileReader, version: int) -> list[LMS_TagGroup]:
|
|
|
18
19
|
|
|
19
20
|
name = reader.read_encoded_string()
|
|
20
21
|
group_list.append(LMS_TagGroup(name, group_id, tag_indexes))
|
|
22
|
+
reader.align(4)
|
|
21
23
|
|
|
22
24
|
return group_list
|
|
@@ -6,7 +6,8 @@ from lms.project.definitions.tag import LMS_TagParamDefinition
|
|
|
6
6
|
def read_tgp2(reader: FileReader) -> list[LMS_TagParamDefinition]:
|
|
7
7
|
parameter_info = []
|
|
8
8
|
|
|
9
|
-
count = reader.
|
|
9
|
+
count = reader.read_uint16()
|
|
10
|
+
reader.skip(2)
|
|
10
11
|
for offset in reader.read_offset_array(count):
|
|
11
12
|
reader.seek(offset)
|
|
12
13
|
|
|
@@ -24,5 +25,6 @@ def read_tgp2(reader: FileReader) -> list[LMS_TagParamDefinition]:
|
|
|
24
25
|
parameter_info.append(
|
|
25
26
|
LMS_TagParamDefinition(name, LMS_DataType.LIST, list_indexes)
|
|
26
27
|
)
|
|
28
|
+
reader.align(4)
|
|
27
29
|
|
|
28
30
|
return parameter_info
|
|
@@ -29,31 +29,16 @@ class TitleConfig:
|
|
|
29
29
|
NODE_KEY = "node_definitions"
|
|
30
30
|
|
|
31
31
|
GAME_PRESET = Literal[
|
|
32
|
-
"
|
|
33
|
-
"Animal Crossing: New Horizons",
|
|
34
|
-
"Animal Crossing: New Leaf",
|
|
35
|
-
"The Legend of Zelda: Echoes of Wisdom"
|
|
36
|
-
"Metroid Prime 4: Beyond"
|
|
37
|
-
"Mario vs. Donkey Kong"
|
|
38
|
-
"Paper Mario: Color Splash"
|
|
39
|
-
"Paper Mario: Sticker Star"
|
|
40
|
-
"Paper Mario: The Origami King"
|
|
41
|
-
"Paper Mario: The Thousand-Year Door (Nintendo Switch)"
|
|
42
|
-
"Super Mario 3D Land"
|
|
43
|
-
"Super Mario 3D World + Bowser's Fury"
|
|
44
|
-
"Super Mario Odyssey"
|
|
45
|
-
"Splatoon 3"
|
|
46
|
-
"The Legend of Zelda: Link's Awakening (Nintendo Switch)"
|
|
47
|
-
"The Legend of Zelda a Link Between Worlds",
|
|
48
|
-
"The Legend of Zelda: Tri Force Heroes"
|
|
49
|
-
"Tomodachi Life (NA-EU)",
|
|
50
|
-
"Tomodachi Life (JP)",
|
|
51
|
-
"Tomodachi Life: Living the Dream",
|
|
52
|
-
"The Legend of Zelda: Tears of the Kingdom"
|
|
53
|
-
"Wii Sports Club"
|
|
32
|
+
"Badge Arcade",
|
|
54
33
|
"Brain Age Concentration Training",
|
|
55
34
|
"Kirby Planet Robobot",
|
|
56
35
|
"Super Mario Odyssey",
|
|
36
|
+
"Super Mario 3D Land",
|
|
37
|
+
"Super Mario 3D World + Bowsers Fury",
|
|
38
|
+
"The Legend of Zelda a Link Between Worlds",
|
|
39
|
+
"The Legend of Zelda Echos of Wisdom",
|
|
40
|
+
"Tomodachi Life Living The Dream",
|
|
41
|
+
"Tomodachi Life NA-EU",
|
|
57
42
|
]
|
|
58
43
|
|
|
59
44
|
def __init__(
|
|
@@ -218,7 +203,7 @@ class TitleConfig:
|
|
|
218
203
|
game = parsed_content.get("game")
|
|
219
204
|
|
|
220
205
|
attribute_configs = {}
|
|
221
|
-
for config in parsed_content
|
|
206
|
+
for config in parsed_content.get(cls.ATTR_KEY, []):
|
|
222
207
|
definitions = [
|
|
223
208
|
ValueDefinition.from_dict(value_def)
|
|
224
209
|
for value_def in config["definitions"]
|
|
@@ -227,21 +212,28 @@ class TitleConfig:
|
|
|
227
212
|
config["name"], config.get("description", ""), definitions
|
|
228
213
|
)
|
|
229
214
|
|
|
215
|
+
tag_config = None
|
|
230
216
|
tag_definitions: dict[int, list[TagDefinition]] = {}
|
|
231
|
-
|
|
217
|
+
tag_content = parsed_content.get(cls.TAG_KEY, None)
|
|
232
218
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if definition.group_id not in tag_definitions:
|
|
236
|
-
tag_definitions[definition.group_id] = []
|
|
237
|
-
tag_definitions[definition.group_id].append(definition)
|
|
219
|
+
if tag_content is not None:
|
|
220
|
+
group_map = tag_content["groups"]
|
|
238
221
|
|
|
239
|
-
|
|
222
|
+
for tag_def in tag_content["tags"]:
|
|
223
|
+
definition = TagDefinition.from_dict(tag_def, group_map)
|
|
224
|
+
if definition.group_id not in tag_definitions:
|
|
225
|
+
tag_definitions[definition.group_id] = []
|
|
226
|
+
tag_definitions[definition.group_id].append(definition)
|
|
227
|
+
|
|
228
|
+
tag_config = TagConfig(group_map, tag_definitions)
|
|
240
229
|
|
|
241
230
|
branch_nodes: dict[int, NodeDefinition | tuple[NodeDefinition, ...]] = {}
|
|
242
231
|
event_nodes: dict[int, tuple[NodeDefinition, ...]] = {}
|
|
243
232
|
|
|
244
|
-
|
|
233
|
+
node_data = parsed_content.get(cls.NODE_KEY, [])
|
|
234
|
+
branch_data, event_data = node_data.get("branch", []), node_data.get("event", [])
|
|
235
|
+
|
|
236
|
+
for definition in branch_data:
|
|
245
237
|
node_id = definition["id"]
|
|
246
238
|
|
|
247
239
|
node_definition = NodeDefinition.from_dict(
|
|
@@ -259,7 +251,7 @@ class TitleConfig:
|
|
|
259
251
|
else:
|
|
260
252
|
branch_nodes[node_id] = (existing, node_definition)
|
|
261
253
|
|
|
262
|
-
for definition in
|
|
254
|
+
for definition in event_data:
|
|
263
255
|
node_id = definition["id"]
|
|
264
256
|
|
|
265
257
|
node_definition = NodeDefinition.from_dict(
|
|
@@ -7,7 +7,7 @@ include = ["lms*"]
|
|
|
7
7
|
|
|
8
8
|
[project]
|
|
9
9
|
name = "PyLibMS"
|
|
10
|
-
version = "4.3.
|
|
10
|
+
version = "4.3.4"
|
|
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"
|
|
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.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/Brain Age Concentration Training.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/Super Mario 3D World + Bowsers Fury.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/The Legend of Zelda Echos of Wisdom.yaml
RENAMED
|
File without changes
|
|
File without changes
|
{pylibms-4.3.2 → pylibms-4.3.4}/lms/titleconfig/presets/Tomodachi Life Living The Dream.yaml
RENAMED
|
File without changes
|
|
File without changes
|