Skip to content

Commit

Permalink
BMSSD
Browse files Browse the repository at this point in the history
- refactored get_item to allow getting any item by crc (or index for
  objects)
- updated test
  • Loading branch information
steven11sjf committed Oct 4, 2024
1 parent 69714de commit 1664f84
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 26 deletions.
26 changes: 20 additions & 6 deletions src/mercury_engine_data_structures/formats/bmssd.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,11 @@ def _decode(self, obj, context, path):
)
else:
res.scene_groups[sg.sg_name][group_type] = construct.ListContainer(
[res[f"_{group_type}"][block] for block in items]
[
# use raw hash value instead of block value if it doesn't exist above
res[f"_{group_type}"][block] if res[f"_{group_type}"].get(block, None) else block
for block in items
]
)

return res
Expand Down Expand Up @@ -181,7 +185,11 @@ def obj_to_tuple(o):
if group_type_int == 1:
sg_cont.item_groups[group_type_int] = [object_order[obj_to_tuple(o)] for o in items]
else:
sg_cont.item_groups[group_type_int] = [crc(o["model_name"]) for o in items]
sg_cont.item_groups[group_type_int] = [
# handle integers (unmatched crc's in decode)
o if isinstance(o, int) else crc(o["model_name"])
for o in items
]

res.scene_groups.append(sg_cont)

Expand All @@ -205,19 +213,25 @@ class Bmssd(BaseResource):
def construct_class(cls, target_game: Game) -> Construct:
return BmssdAdapter(BMSSD)

def get_item_by_name(self, item_name: str, item_type: ItemType) -> construct.Container:
def get_item(self, item_name_or_id: str | int, item_type: ItemType) -> construct.Container:
if isinstance(item_name_or_id, int):
if item_type == ItemType.OBJECT:
return self.raw._objects[item_name_or_id]
else:
return self.raw[f"_{item_type.group_name}"].get(item_name_or_id, None)

Check warning on line 221 in src/mercury_engine_data_structures/formats/bmssd.py

View check run for this annotation

Codecov / codecov/patch

src/mercury_engine_data_structures/formats/bmssd.py#L221

Added line #L221 was not covered by tests

if item_type == ItemType.OBJECT:
raise ValueError("Cannot get objects by name!")
raise ValueError("If accessing an Object type item, must use the index!")

crc = crc_func(self.raw)
return self.raw[f"_{item_type.group_name}"].get(crc(item_name), None)
return self.raw[f"_{item_type.group_name}"].get(crc(item_name_or_id), None)

def get_scene_group(self, scene_group: str) -> construct.Container:
return self.raw.scene_groups.get(scene_group, None)

def scene_groups_for_item(self, item: str | construct.Container, item_type: str) -> list[str]:
if isinstance(item, str):
item = self.get_item_by_name(item, item_type)
item = self.get_item(item, item_type)

return [sg_name for sg_name, sg_val in self.raw.scene_groups.items() if item in sg_val[item_type.group_name]]

Expand Down
30 changes: 10 additions & 20 deletions tests/formats/test_bmssd.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import contextlib

import pytest
from tests.test_lib import parse_build_compare_editor_parsed

Expand Down Expand Up @@ -38,13 +36,6 @@
"maps/levels/c10_samus/s920_traininggallery/s920_traininggallery.bmssd",
]

sr_xfail = [
"maps/levels/c10_samus/s000_surface/s000_surface.bmssd",
"maps/levels/c10_samus/s020_area2/s020_area2.bmssd",
"maps/levels/c10_samus/s050_area5/s050_area5.bmssd",
"maps/levels/c10_samus/s110_surfaceb/s110_surfaceb.bmssd",
]


@pytest.mark.parametrize("bmssd_path", dread_data.all_files_ending_with(".bmssd", bossrush_assets))
def test_compare_bmssd_dread_100(dread_tree_100, bmssd_path):
Expand All @@ -58,22 +49,17 @@ def test_compare_dread_210(dread_tree_210, bmssd_path):

@pytest.mark.parametrize("bmssd_path", samus_returns_data.all_files_ending_with(".bmssd", sr_missing))
def test_compare_bmssd_msr(samus_returns_tree, bmssd_path):
if bmssd_path in sr_xfail:
expectation = pytest.raises(KeyError)
else:
expectation = contextlib.nullcontext()
with expectation:
parse_build_compare_editor_parsed(Bmssd, samus_returns_tree, bmssd_path)
parse_build_compare_editor_parsed(Bmssd, samus_returns_tree, bmssd_path)


def test_bmssd_dread_functions(dread_tree_100):
bmssd = dread_tree_100.get_parsed_asset("maps/levels/c10_samus/s090_skybase/s090_skybase.bmssd", type_hint=Bmssd)

# PART 1: Ensure getting an item and accessing scene group for item works

lshaft03 = bmssd.get_item_by_name("part001_jp6_lshaft03", ItemType.SCENE_BLOCK)
lshaft03 = bmssd.get_item("part001_jp6_lshaft03", ItemType.SCENE_BLOCK)

# check get_item_by_name returned the correct data
# check get_item returned the correct data
assert lshaft03.transform.position[0] == 640.7750244140625
# check the scene groups are correct
assert bmssd.scene_groups_for_item(lshaft03, ItemType.SCENE_BLOCK) == [
Expand Down Expand Up @@ -106,7 +92,7 @@ def test_bmssd_dread_functions(dread_tree_100):
}
new_sb_groups = [f"sg_casca100{x}" for x in [0, 1, 2]]
bmssd.add_item(new_sb, ItemType.SCENE_BLOCK, new_sb_groups)
assert bmssd.get_item_by_name("part420_rdv_newblock", ItemType.SCENE_BLOCK) == new_sb
assert bmssd.get_item("part420_rdv_newblock", ItemType.SCENE_BLOCK) == new_sb
assert bmssd.scene_groups_for_item("part420_rdv_newblock", ItemType.SCENE_BLOCK) == new_sb_groups

# objects
Expand All @@ -123,10 +109,14 @@ def test_bmssd_dread_functions(dread_tree_100):

# can't get object by name
with pytest.raises(ValueError):
bmssd.get_item_by_name("theoreticalplandoobj", ItemType.OBJECT)
bmssd.get_item("theoreticalplandoobj", ItemType.OBJECT)

# can get object by index
obj = bmssd.get_item(69, ItemType.OBJECT)
assert obj.model_name == "chozoskypathroofx1" and obj.transform.position[1] == -2650.0

# non-existant object
assert bmssd.get_item_by_name("isweariaddedthis", ItemType.SCENE_BLOCK) is None
assert bmssd.get_item("isweariaddedthis", ItemType.SCENE_BLOCK) is None

# actually we changed our mind on where the newblock goes
bmssd.remove_item_from_group(new_sb, ItemType.SCENE_BLOCK, "sg_casca1002")
Expand Down

0 comments on commit 1664f84

Please sign in to comment.