From e54a5899c092949eba4725738eca0e26ccc9360d Mon Sep 17 00:00:00 2001 From: dyceron Date: Sun, 22 Dec 2024 00:18:09 -0500 Subject: [PATCH 1/4] Minor cleanup and add functions --- .../formats/bmsbk.py | 24 +++++++++++++++---- tests/formats/test_bmsbk.py | 20 ++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/mercury_engine_data_structures/formats/bmsbk.py b/src/mercury_engine_data_structures/formats/bmsbk.py index 03fc003..602bbac 100644 --- a/src/mercury_engine_data_structures/formats/bmsbk.py +++ b/src/mercury_engine_data_structures/formats/bmsbk.py @@ -3,7 +3,8 @@ import functools from typing import TYPE_CHECKING -from construct import ( +import construct +from construct.core import ( Array, Const, Construct, @@ -13,7 +14,6 @@ Int32ul, Rebuild, Struct, - Terminated, ) from mercury_engine_data_structures.base_resource import BaseResource @@ -43,7 +43,7 @@ def _rebuild_types(ctx: Container) -> int: BlockGroup = Struct( "_num_blocks" / Rebuild(Int32ul, _rebuild_blocks), "_num_types" / Rebuild(Int32ul, _rebuild_types), - "unk_bool" / Flag, # always true? + "is_enabled" / Flag, # always true? "types" / Array(lambda this: this._num_types, Struct( "block_type" / StrId, "blocks" / make_vector(Block), @@ -52,13 +52,13 @@ def _rebuild_types(ctx: Container) -> int: BMSBK = Struct( "magic" / Const(b"MSBK"), - "version" / VersionAdapter(), + "version" / VersionAdapter("1.10.0"), "block_groups" / make_vector(BlockGroup), "collision_cameras" / make_vector(Struct( "name" / StrId, "entries" / make_vector(Int32ul), )), - Terminated, + construct.Terminated, ) # fmt: skip @@ -67,3 +67,17 @@ class Bmsbk(BaseResource): @functools.lru_cache def construct_class(cls, target_game: Game) -> Construct: return BMSBK + + def get_block_group(self, block_group: int) -> Container: + return self.raw.block_groups[block_group] + + def set_block_type(self, block_group: int, block_type: str) -> Container: + weakness = self.get_block_group(block_group).types[0] + weakness.block_type = block_type + + def get_block(self, block_group: int, block_idx: int = 0) -> Container: + return self.get_block_group(block_group).types[0].blocks[block_idx] + + def set_respawn_time(self, block_group: int, block_idx: int = 0, respawn_time: float = 0.0) -> Container: + block = self.get_block(block_group) + block.respawn_time = respawn_time diff --git a/tests/formats/test_bmsbk.py b/tests/formats/test_bmsbk.py index 980e60c..b85ee9d 100644 --- a/tests/formats/test_bmsbk.py +++ b/tests/formats/test_bmsbk.py @@ -17,3 +17,23 @@ @pytest.mark.parametrize("bmsbk_path", samus_returns_data.all_files_ending_with(".bmsbk", sr_missing)) def test_bmsbk(samus_returns_tree, bmsbk_path): parse_build_compare_editor(Bmsbk, samus_returns_tree, bmsbk_path) + + +@pytest.fixture() +def surface_bmsbk(samus_returns_tree) -> Bmsbk: + return samus_returns_tree.get_parsed_asset("maps/levels/c10_samus/s000_surface/s000_surface.bmsbk", type_hint=Bmsbk) + + +def test_get_block(surface_bmsbk: Bmsbk): + block = surface_bmsbk.get_block(0, 1) + assert block.respawn_time == 0.0 + + +def test_changing_weakness(surface_bmsbk: Bmsbk): + surface_bmsbk.set_block_type(1, "bomb") + assert surface_bmsbk.get_block_group(1).type == "bomb" + + +def test_respawn_time(surface_bmsbk: Bmsbk): + surface_bmsbk.set_respawn_time(0, 0, 5.0) + assert surface_bmsbk.get_block(0).respawn_time == 5.0 From 183cabda1f17b1e9970506a8e1105c7f63dbd616 Mon Sep 17 00:00:00 2001 From: dyceron Date: Sun, 22 Dec 2024 08:24:58 -0500 Subject: [PATCH 2/4] Fix test --- tests/formats/test_bmsbk.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/formats/test_bmsbk.py b/tests/formats/test_bmsbk.py index b85ee9d..679eb89 100644 --- a/tests/formats/test_bmsbk.py +++ b/tests/formats/test_bmsbk.py @@ -30,8 +30,9 @@ def test_get_block(surface_bmsbk: Bmsbk): def test_changing_weakness(surface_bmsbk: Bmsbk): - surface_bmsbk.set_block_type(1, "bomb") - assert surface_bmsbk.get_block_group(1).type == "bomb" + original_type = surface_bmsbk.get_block_group(1).types[0].block_type + new_type = surface_bmsbk.set_block_type(1, "bomb") + assert original_type != new_type def test_respawn_time(surface_bmsbk: Bmsbk): From 37bea773fb8fef959e8b260850c6f00d85aa432c Mon Sep 17 00:00:00 2001 From: dyceron Date: Tue, 24 Dec 2024 17:19:24 -0500 Subject: [PATCH 3/4] Address reviews --- .../formats/bmsbk.py | 31 +++++++++++++++---- tests/formats/test_bmsbk.py | 9 +++--- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/mercury_engine_data_structures/formats/bmsbk.py b/src/mercury_engine_data_structures/formats/bmsbk.py index 602bbac..510062a 100644 --- a/src/mercury_engine_data_structures/formats/bmsbk.py +++ b/src/mercury_engine_data_structures/formats/bmsbk.py @@ -1,6 +1,7 @@ from __future__ import annotations import functools +from enum import Enum from typing import TYPE_CHECKING import construct @@ -62,6 +63,17 @@ def _rebuild_types(ctx: Container) -> int: ) # fmt: skip +class BlockType(Enum): + POWER_BEAM = "power_beam" + BOMB = "bomb" + MISSILE = "missile" + SUPER_MISSILE = "super_missile" + POWER_BOMB = "power_bomb" + BABY = "baby" + SCREW_ATTACK = "screw_attack" + WEIGHT = "weight" + + class Bmsbk(BaseResource): @classmethod @functools.lru_cache @@ -69,15 +81,22 @@ def construct_class(cls, target_game: Game) -> Construct: return BMSBK def get_block_group(self, block_group: int) -> Container: + """Returns a block group by index""" return self.raw.block_groups[block_group] - def set_block_type(self, block_group: int, block_type: str) -> Container: - weakness = self.get_block_group(block_group).types[0] - weakness.block_type = block_type + def set_block_type(self, block_group: int, block_type: BlockType) -> None: + """Change a given block's block_type into another""" + if block_type not in BlockType: + raise KeyError(f"{block_type} is not a valid block type!") + assert len(self.get_block_group(block_group).types) == 1 + self.get_block_group(block_group).types[0].block_type = block_type - def get_block(self, block_group: int, block_idx: int = 0) -> Container: + def get_block(self, block_group: int, block_idx: int) -> Container: + """Returns a block from a block group by index""" + assert len(self.get_block_group(block_group).types) == 1 return self.get_block_group(block_group).types[0].blocks[block_idx] - def set_respawn_time(self, block_group: int, block_idx: int = 0, respawn_time: float = 0.0) -> Container: - block = self.get_block(block_group) + def set_respawn_time(self, block_group: int, block_idx: int, respawn_time: float) -> None: + """Change the respawn time of a given block""" + block = self.get_block(block_group, block_idx) block.respawn_time = respawn_time diff --git a/tests/formats/test_bmsbk.py b/tests/formats/test_bmsbk.py index 679eb89..8c90d14 100644 --- a/tests/formats/test_bmsbk.py +++ b/tests/formats/test_bmsbk.py @@ -4,7 +4,7 @@ from tests.test_lib import parse_build_compare_editor from mercury_engine_data_structures import samus_returns_data -from mercury_engine_data_structures.formats.bmsbk import Bmsbk +from mercury_engine_data_structures.formats.bmsbk import BlockType, Bmsbk sr_missing = [ "maps/levels/c10_samus/s908_manicminerbotrun/s908_manicminerbotrun.bmsbk", @@ -30,11 +30,10 @@ def test_get_block(surface_bmsbk: Bmsbk): def test_changing_weakness(surface_bmsbk: Bmsbk): - original_type = surface_bmsbk.get_block_group(1).types[0].block_type - new_type = surface_bmsbk.set_block_type(1, "bomb") - assert original_type != new_type + surface_bmsbk.set_block_type(1, BlockType.BOMB) + assert surface_bmsbk.get_block_group(1).types[0].block_type == BlockType.BOMB def test_respawn_time(surface_bmsbk: Bmsbk): surface_bmsbk.set_respawn_time(0, 0, 5.0) - assert surface_bmsbk.get_block(0).respawn_time == 5.0 + assert surface_bmsbk.get_block(0, 0).respawn_time == 5.0 From 3900c8f10f5ec662fae67b0d375b5c4b8d64148c Mon Sep 17 00:00:00 2001 From: dyceron Date: Tue, 24 Dec 2024 18:10:49 -0500 Subject: [PATCH 4/4] Remove `raise` --- src/mercury_engine_data_structures/formats/bmsbk.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mercury_engine_data_structures/formats/bmsbk.py b/src/mercury_engine_data_structures/formats/bmsbk.py index 510062a..057fb56 100644 --- a/src/mercury_engine_data_structures/formats/bmsbk.py +++ b/src/mercury_engine_data_structures/formats/bmsbk.py @@ -86,8 +86,6 @@ def get_block_group(self, block_group: int) -> Container: def set_block_type(self, block_group: int, block_type: BlockType) -> None: """Change a given block's block_type into another""" - if block_type not in BlockType: - raise KeyError(f"{block_type} is not a valid block type!") assert len(self.get_block_group(block_group).types) == 1 self.get_block_group(block_group).types[0].block_type = block_type