diff --git a/src/mercury_engine_data_structures/formats/__init__.py b/src/mercury_engine_data_structures/formats/__init__.py index 07c4d582..be39e0ea 100644 --- a/src/mercury_engine_data_structures/formats/__init__.py +++ b/src/mercury_engine_data_structures/formats/__init__.py @@ -16,6 +16,7 @@ from mercury_engine_data_structures.formats.bmsnav import Bmsnav from mercury_engine_data_structures.formats.bmssd import Bmssd from mercury_engine_data_structures.formats.bmtre import Bmtre +from mercury_engine_data_structures.formats.bmtun import Bmtun from mercury_engine_data_structures.formats.brem import Brem from mercury_engine_data_structures.formats.bres import Bres from mercury_engine_data_structures.formats.brev import Brev @@ -41,6 +42,7 @@ "BMSSS": Bmsss, "BMSAD": Bmsad, "BMSAS": Bmsas, + "BMTUN": Bmtun, "BRFLD": Brfld, "BMSCC": Bmscc, "BMSCD": Bmscc, diff --git a/src/mercury_engine_data_structures/formats/bmtun.py b/src/mercury_engine_data_structures/formats/bmtun.py new file mode 100644 index 00000000..905ee0dc --- /dev/null +++ b/src/mercury_engine_data_structures/formats/bmtun.py @@ -0,0 +1,55 @@ +import functools + +import construct +from construct.core import ( + Array, + Const, + Construct, + Flag, + Float32l, + Hex, + Int32sl, + Int32ul, + Struct, + Switch, +) + +from mercury_engine_data_structures.common_types import Char, Float, StrId, make_dict +from mercury_engine_data_structures.construct_extensions.misc import ErrorWithMessage +from mercury_engine_data_structures.formats import BaseResource +from mercury_engine_data_structures.game_check import Game + +# Functions +TunableParam = Struct( + type=Char, + value=Switch( + construct.this.type, + { + 's': StrId, + 'f': Float, + 'b': Flag, + 'i': Int32sl, + 'v': Array(3, Float32l) + }, + ErrorWithMessage(lambda ctx: f"Unknown argument type: {ctx.type}", construct.SwitchError) + ) +) + +TunableClass = Struct( + "tunables" / make_dict(TunableParam), +) + +# BMTUN +BMTUN = Struct( + "_magic" / Const(b"MTUN"), + "version" / Const(0x00050001, Hex(Int32ul)), + "classes" / make_dict(TunableClass), + construct.Terminated, +) + + +class Bmtun(BaseResource): + @classmethod + @functools.lru_cache + def construct_class(cls, target_game: Game) -> Construct: + return BMTUN diff --git a/tests/formats/test_bmtun.py b/tests/formats/test_bmtun.py new file mode 100644 index 00000000..1491796e --- /dev/null +++ b/tests/formats/test_bmtun.py @@ -0,0 +1,13 @@ +import pytest +from tests.test_lib import parse_build_compare_editor + +from mercury_engine_data_structures import samus_returns_data +from mercury_engine_data_structures.formats.bmtun import Bmtun + +all_sr_bmtun = [name for name in samus_returns_data.all_name_to_asset_id().keys() + if name.endswith(".bmtun")] + + +@pytest.mark.parametrize("bmtun_path", all_sr_bmtun) +def test_bmtun(samus_returns_tree, bmtun_path): + parse_build_compare_editor(Bmtun, samus_returns_tree, bmtun_path)