From 23013a67ad8d8b3f927df5a98834928f88445f6c Mon Sep 17 00:00:00 2001 From: Steven Franklin Date: Sat, 19 Aug 2023 03:09:00 -0500 Subject: [PATCH] BMSNAV parse/build for Samus Returns - mostly just a simpler format of Dread's navmesh - geo_connections have 3 bytes added to the start of each entry - there's an unknown struct that seems to be there for metroids, probably similar to how emmy actions are in dread --- .../formats/bmsnav.py | 43 +++++++++++++------ tests/formats/test_bmsnav.py | 30 +++++++++++-- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/mercury_engine_data_structures/formats/bmsnav.py b/src/mercury_engine_data_structures/formats/bmsnav.py index 0fae8dee..c7c09843 100644 --- a/src/mercury_engine_data_structures/formats/bmsnav.py +++ b/src/mercury_engine_data_structures/formats/bmsnav.py @@ -1,14 +1,4 @@ -from construct.core import ( - Array, - Byte, - Const, - Construct, - Flag, - Hex, - Int32ul, - PrefixedArray, - Struct, -) +from construct.core import Array, Byte, Const, Construct, Flag, Hex, Int32ul, PrefixedArray, Struct, Terminated from mercury_engine_data_structures.common_types import CVector2D, CVector3D, Float, StrId, make_dict from mercury_engine_data_structures.formats import BaseResource @@ -29,6 +19,13 @@ connections=PrefixedArray(Int32ul, geo_connection), ) +geo_connections_sr = Struct( + unk0=Byte, + unk1=Byte, + unk2=Byte, # 0? + gcs = geo_connections +) + # idk Struct1 = Struct( unk0=Int32ul, @@ -144,6 +141,25 @@ unk1=PrefixedArray(Int32ul, Struct3), ) +sr_unk_struct = Struct( + bound_start = CVector2D, + bound_end = CVector2D, + unk1 = Int32ul, + const0 = Int32ul, + unk2 = Int32ul, + unk3 = Int32ul +) + +BMSNAV_SR = Struct( + _magic=Const(b'MNAV'), + version=Const(0x000C0001, Hex(Int32ul)), + aNavmeshGeos = PrefixedArray(Int32ul, CVector2D), + geo_connections = PrefixedArray(Int32ul, geo_connections_sr), + unk1=PrefixedArray(Int32ul, Struct1), + navigable_paths=make_dict(NavigablePath), # contains additional paths for certain enemies (ie chozo soldiers) + unk2 = make_dict(PrefixedArray(Int32ul, sr_unk_struct)), + _eof = Terminated +) BMSNAV = Struct( _magic=Const(b'MNAV'), version=Const(0x00030002, Hex(Int32ul)), @@ -166,4 +182,7 @@ class Bmsnav(BaseResource): @classmethod def construct_class(cls, target_game: Game) -> Construct: - return BMSNAV + return { + Game.SAMUS_RETURNS: BMSNAV_SR, + Game.DREAD: BMSNAV, + }[target_game] diff --git a/tests/formats/test_bmsnav.py b/tests/formats/test_bmsnav.py index aedd4bf1..1f79f29d 100644 --- a/tests/formats/test_bmsnav.py +++ b/tests/formats/test_bmsnav.py @@ -3,7 +3,7 @@ from mercury_engine_data_structures.formats.bmsnav import Bmsnav -all_bmsnav = [ +dread_bmsnav = [ "maps/levels/c10_samus/s010_cave/s010_cave.bmsnav", "maps/levels/c10_samus/s020_magma/s020_magma.bmsnav", "maps/levels/c10_samus/s030_baselab/s030_baselab.bmsnav", @@ -15,7 +15,31 @@ "maps/levels/c10_samus/s090_skybase/s090_skybase.bmsnav", ] +sr_bmsnav = [ + "maps/levels/c10_samus/s000_surface/s000_surface.bmsnav", + "maps/levels/c10_samus/s010_area1/s010_area1.bmsnav", + "maps/levels/c10_samus/s020_area2/s020_area2.bmsnav", + "maps/levels/c10_samus/s025_area2b/s025_area2b.bmsnav", + "maps/levels/c10_samus/s028_area2c/s028_area2c.bmsnav", + "maps/levels/c10_samus/s030_area3/s030_area3.bmsnav", + "maps/levels/c10_samus/s033_area3b/s033_area3b.bmsnav", + "maps/levels/c10_samus/s036_area3c/s036_area3c.bmsnav", + "maps/levels/c10_samus/s040_area4/s040_area4.bmsnav", + "maps/levels/c10_samus/s050_area5/s050_area5.bmsnav", + "maps/levels/c10_samus/s060_area6/s060_area6.bmsnav", + "maps/levels/c10_samus/s065_area6b/s065_area6b.bmsnav", + "maps/levels/c10_samus/s067_area6c/s067_area6c.bmsnav", + "maps/levels/c10_samus/s070_area7/s070_area7.bmsnav", + "maps/levels/c10_samus/s090_area9/s090_area9.bmsnav", + "maps/levels/c10_samus/s100_area10/s100_area10.bmsnav", + "maps/levels/c10_samus/s110_surfaceb/s110_surfaceb.bmsnav", +] + -@pytest.mark.parametrize("bmsnav_path", all_bmsnav) -def test_bmsnav(dread_file_tree, bmsnav_path): +@pytest.mark.parametrize("bmsnav_path", dread_bmsnav) +def test_dread_bmsnav(dread_file_tree, bmsnav_path): parse_build_compare_editor(Bmsnav, dread_file_tree, bmsnav_path) + +@pytest.mark.parametrize("bmsnav_path", sr_bmsnav) +def test_sr_bmsnav(samus_returns_tree, bmsnav_path): + parse_build_compare_editor(Bmsnav, samus_returns_tree, bmsnav_path)