PyLibMS 4.3.2__tar.gz → 4.3.3__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 (83) hide show
  1. {pylibms-4.3.2 → pylibms-4.3.3}/PKG-INFO +1 -1
  2. {pylibms-4.3.2 → pylibms-4.3.3}/PyLibMS.egg-info/PKG-INFO +1 -1
  3. {pylibms-4.3.2 → pylibms-4.3.3}/lms/common/lms_constants.py +2 -0
  4. {pylibms-4.3.2 → pylibms-4.3.3}/lms/common/stream/fileinfo.py +2 -2
  5. {pylibms-4.3.2 → pylibms-4.3.3}/lms/flowchart/definitions/node.py +17 -10
  6. {pylibms-4.3.2 → pylibms-4.3.3}/lms/flowchart/msbf.py +11 -4
  7. {pylibms-4.3.2 → pylibms-4.3.3}/lms/flowchart/msbfio.py +3 -9
  8. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/config.py +17 -10
  9. {pylibms-4.3.2 → pylibms-4.3.3}/pyproject.toml +1 -1
  10. {pylibms-4.3.2 → pylibms-4.3.3}/LICENSE +0 -0
  11. {pylibms-4.3.2 → pylibms-4.3.3}/MANIFEST.in +0 -0
  12. {pylibms-4.3.2 → pylibms-4.3.3}/PyLibMS.egg-info/SOURCES.txt +0 -0
  13. {pylibms-4.3.2 → pylibms-4.3.3}/PyLibMS.egg-info/dependency_links.txt +0 -0
  14. {pylibms-4.3.2 → pylibms-4.3.3}/PyLibMS.egg-info/requires.txt +0 -0
  15. {pylibms-4.3.2 → pylibms-4.3.3}/PyLibMS.egg-info/top_level.txt +0 -0
  16. {pylibms-4.3.2 → pylibms-4.3.3}/README.md +0 -0
  17. {pylibms-4.3.2 → pylibms-4.3.3}/lms/__init__.py +0 -0
  18. {pylibms-4.3.2 → pylibms-4.3.3}/lms/common/__init__.py +0 -0
  19. {pylibms-4.3.2 → pylibms-4.3.3}/lms/common/field/__init__.py +0 -0
  20. {pylibms-4.3.2 → pylibms-4.3.3}/lms/common/field/io.py +0 -0
  21. {pylibms-4.3.2 → pylibms-4.3.3}/lms/common/field/lms_datatype.py +0 -0
  22. {pylibms-4.3.2 → pylibms-4.3.3}/lms/common/field/lms_field.py +0 -0
  23. {pylibms-4.3.2 → pylibms-4.3.3}/lms/common/lms_exceptions.py +0 -0
  24. {pylibms-4.3.2 → pylibms-4.3.3}/lms/common/lms_fileinfo.py +0 -0
  25. {pylibms-4.3.2 → pylibms-4.3.3}/lms/common/stream/hashtable.py +0 -0
  26. {pylibms-4.3.2 → pylibms-4.3.3}/lms/common/stream/section.py +0 -0
  27. {pylibms-4.3.2 → pylibms-4.3.3}/lms/fileio/encoding.py +0 -0
  28. {pylibms-4.3.2 → pylibms-4.3.3}/lms/fileio/io.py +0 -0
  29. {pylibms-4.3.2 → pylibms-4.3.3}/lms/flowchart/__init__.py +0 -0
  30. {pylibms-4.3.2 → pylibms-4.3.3}/lms/flowchart/definitions/__init__.py +0 -0
  31. {pylibms-4.3.2 → pylibms-4.3.3}/lms/flowchart/definitions/flowchart.py +0 -0
  32. {pylibms-4.3.2 → pylibms-4.3.3}/lms/flowchart/definitions/lms_nodeexceptions.py +0 -0
  33. {pylibms-4.3.2 → pylibms-4.3.3}/lms/flowchart/definitions/node_type.py +0 -0
  34. {pylibms-4.3.2 → pylibms-4.3.3}/lms/flowchart/flw3.py +0 -0
  35. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/__init__.py +0 -0
  36. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/definitions/__init__.py +0 -0
  37. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/definitions/field/__init__.py +0 -0
  38. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/lms_messagetext.py +0 -0
  39. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/msbt.py +0 -0
  40. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/msbtentry.py +0 -0
  41. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/msbtio.py +0 -0
  42. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/section/__init__.py +0 -0
  43. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/section/atr1.py +0 -0
  44. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/section/nli1.py +0 -0
  45. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/section/tsy1.py +0 -0
  46. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/section/txt2.py +0 -0
  47. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/tag/__init__.py +0 -0
  48. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/tag/io/param_io.py +0 -0
  49. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/tag/io/tag_io.py +0 -0
  50. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/tag/lms_tag.py +0 -0
  51. {pylibms-4.3.2 → pylibms-4.3.3}/lms/message/tag/lms_tagexceptions.py +0 -0
  52. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/__init__.py +0 -0
  53. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/definitions/__init__.py +0 -0
  54. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/definitions/attribute.py +0 -0
  55. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/definitions/color.py +0 -0
  56. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/definitions/style.py +0 -0
  57. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/definitions/tag.py +0 -0
  58. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/msbp.py +0 -0
  59. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/msbpread.py +0 -0
  60. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/section/ali2.py +0 -0
  61. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/section/ati2.py +0 -0
  62. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/section/clr1.py +0 -0
  63. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/section/string.py +0 -0
  64. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/section/syl3.py +0 -0
  65. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/section/tag2.py +0 -0
  66. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/section/tgg2.py +0 -0
  67. {pylibms-4.3.2 → pylibms-4.3.3}/lms/project/section/tgp2.py +0 -0
  68. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/__init__.py +0 -0
  69. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/definitions/__init__.py +0 -0
  70. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/definitions/attribute.py +0 -0
  71. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/definitions/nodes.py +0 -0
  72. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/definitions/tags.py +0 -0
  73. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/definitions/value.py +0 -0
  74. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/presets/Badge Arcade.yaml +0 -0
  75. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/presets/Brain Age Concentration Training.yaml +0 -0
  76. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/presets/Kirby Planet Robobot.yaml +0 -0
  77. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/presets/Super Mario 3D Land.yaml +0 -0
  78. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/presets/Super Mario 3D World + Bowsers Fury.yaml +0 -0
  79. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/presets/Super Mario Odyssey.yaml +0 -0
  80. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/presets/The Legend of Zelda Echos of Wisdom.yaml +0 -0
  81. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/presets/The Legend of Zelda a Link Between Worlds.yaml +0 -0
  82. {pylibms-4.3.2 → pylibms-4.3.3}/lms/titleconfig/presets/Tomodachi Life Living The Dream.yaml +0 -0
  83. {pylibms-4.3.2 → pylibms-4.3.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyLibMS
3
- Version: 4.3.2
3
+ Version: 4.3.3
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyLibMS
3
- Version: 4.3.2
3
+ Version: 4.3.3
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
@@ -1,4 +1,6 @@
1
1
  # Common constant definitions between files
2
+ LMS_MINIMUM_VERSION = 3
3
+
2
4
  PADDING_BYTE = b"\x00"
3
5
 
4
6
  SIZE_OFFSET = 0x12
@@ -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 < 3:
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, and must be set with `set_msbt` or by providing a MSBT file on reading."""
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
- if self.definition.case_options:
316
+ definition: NodeDefinition = self.definition
317
+
318
+ if definition.case_options:
317
319
  for case, branch in self._branches.items():
318
- case_message = self.definition.case_options.get(
319
- case, f"Case {case}"
320
+ case_format = definition.case_options.get(
321
+ case, None,
320
322
  )
321
323
 
322
- result.append(((case,), case_message, branch))
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 self.definition.case_format is not None:
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(self._definition.case_format)
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
- self._shared_references: dict[int, LMS_BaseNode] = {}
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
- """References of nodes between flowcharts."""
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: optional argument that registers the node to that 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(
@@ -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, _ = read_labels(reader)
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
- MSBF.DEFAULT_SLOT_COUNT,
128
+ file.slot_count,
135
129
  index_map,
136
130
  )
137
131
  write_file_size(writer)
@@ -218,7 +218,7 @@ class TitleConfig:
218
218
  game = parsed_content.get("game")
219
219
 
220
220
  attribute_configs = {}
221
- for config in parsed_content[cls.ATTR_KEY]:
221
+ for config in parsed_content.get(cls.ATTR_KEY, []):
222
222
  definitions = [
223
223
  ValueDefinition.from_dict(value_def)
224
224
  for value_def in config["definitions"]
@@ -227,21 +227,28 @@ class TitleConfig:
227
227
  config["name"], config.get("description", ""), definitions
228
228
  )
229
229
 
230
+ tag_config = None
230
231
  tag_definitions: dict[int, list[TagDefinition]] = {}
231
- group_map = parsed_content[cls.TAG_KEY]["groups"]
232
+ tag_content = parsed_content.get(cls.TAG_KEY, None)
232
233
 
233
- for tag_def in parsed_content[cls.TAG_KEY]["tags"]:
234
- definition = TagDefinition.from_dict(tag_def, group_map)
235
- if definition.group_id not in tag_definitions:
236
- tag_definitions[definition.group_id] = []
237
- tag_definitions[definition.group_id].append(definition)
234
+ if tag_content is not None:
235
+ group_map = tag_content["groups"]
238
236
 
239
- tag_config = TagConfig(group_map, tag_definitions)
237
+ for tag_def in tag_content["tags"]:
238
+ definition = TagDefinition.from_dict(tag_def, group_map)
239
+ if definition.group_id not in tag_definitions:
240
+ tag_definitions[definition.group_id] = []
241
+ tag_definitions[definition.group_id].append(definition)
242
+
243
+ tag_config = TagConfig(group_map, tag_definitions)
240
244
 
241
245
  branch_nodes: dict[int, NodeDefinition | tuple[NodeDefinition, ...]] = {}
242
246
  event_nodes: dict[int, tuple[NodeDefinition, ...]] = {}
243
247
 
244
- for definition in parsed_content[cls.NODE_KEY]["branch"]:
248
+ node_data = parsed_content.get(cls.NODE_KEY, [])
249
+ branch_data, event_data = node_data.get("branch", []), node_data.get("event", [])
250
+
251
+ for definition in branch_data:
245
252
  node_id = definition["id"]
246
253
 
247
254
  node_definition = NodeDefinition.from_dict(
@@ -259,7 +266,7 @@ class TitleConfig:
259
266
  else:
260
267
  branch_nodes[node_id] = (existing, node_definition)
261
268
 
262
- for definition in parsed_content[cls.NODE_KEY]["event"]:
269
+ for definition in event_data:
263
270
  node_id = definition["id"]
264
271
 
265
272
  node_definition = NodeDefinition.from_dict(
@@ -7,7 +7,7 @@ include = ["lms*"]
7
7
 
8
8
  [project]
9
9
  name = "PyLibMS"
10
- version = "4.3.2"
10
+ version = "4.3.3"
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