Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BMSCC Refactor #251

Merged
merged 16 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 52 additions & 20 deletions src/mercury_engine_data_structures/formats/bmscc.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from __future__ import annotations

from typing import TYPE_CHECKING

import construct
from construct import (
from construct.core import (
Const,
Construct,
GreedyBytes,
IfThenElse,
Container,
Int8ul,
Int16ul,
Struct,
Expand All @@ -14,47 +15,78 @@

from mercury_engine_data_structures import game_check
from mercury_engine_data_structures.base_resource import BaseResource
from mercury_engine_data_structures.common_types import StrId, VersionAdapter, make_vector
from mercury_engine_data_structures.common_types import (
StrId,
VersionAdapter,
make_vector,
)
from mercury_engine_data_structures.construct_extensions.function_complex import ComplexIf
from mercury_engine_data_structures.construct_extensions.misc import ErrorWithMessage
from mercury_engine_data_structures.formats.collision import collision_formats
from mercury_engine_data_structures.game_check import Game

if TYPE_CHECKING:
from mercury_engine_data_structures.game_check import Game

Check warning on line 28 in src/mercury_engine_data_structures/formats/bmscc.py

View check run for this annotation

Codecov / codecov/patch

src/mercury_engine_data_structures/formats/bmscc.py#L28

Added line #L28 was not covered by tests

CollisionEntry = Struct(
name=StrId,
prop1=StrId,
prop2=StrId,
prop3=StrId,
flag=IfThenElse(
game_check.current_game_at_most(Game.SAMUS_RETURNS),
"name" / StrId,
"prop1" / StrId,
"prop2" / StrId,
"prop3" / StrId,
"flag"
/ game_check.is_sr_or_else(
Int8ul,
Int16ul,
),
type=StrId,
data=Switch(
"type" / StrId,
"data"
/ Switch(
construct.this.type,
collision_formats,
ErrorWithMessage(lambda ctx: f"Type {ctx.type} not known, valid types are {list(collision_formats.keys())}."),
),
)

CollisionLayer = Struct(
name=StrId,
entries=make_vector(CollisionEntry),
"name" / StrId,
"entries" / make_vector(CollisionEntry),
)

PartsComponent = Struct(
"group" / StrId,
"components" / make_vector(Struct("name" / StrId)),
)

BMSCC = Struct(
_magic=Const(b"MSCD"),
_version=IfThenElse(
game_check.current_game_at_most(Game.SAMUS_RETURNS),
"_magic" / Const(b"MSCD"),
"_version"
/ game_check.is_sr_or_else(
VersionAdapter("1.13.0"),
VersionAdapter("1.16.0"),
),
layers=make_vector(CollisionLayer),
eof=GreedyBytes,
"layers" / make_vector(CollisionLayer),
"_remaining" / construct.Peek(construct.GreedyBytes),
"parts"
/ ComplexIf(
lambda this: ((this._parsing and this._remaining) or (this._building and (this.parts is not None))),
make_vector(PartsComponent),
),
dyceron marked this conversation as resolved.
Show resolved Hide resolved
construct.Terminated,
dyceron marked this conversation as resolved.
Show resolved Hide resolved
)


class Bmscc(BaseResource):
@classmethod
def construct_class(cls, target_game: Game) -> Construct:
return BMSCC

def get_data(self) -> Container:
return self.raw.layers[0].entries[0].data
dyceron marked this conversation as resolved.
Show resolved Hide resolved

def get_poly(self, poly_idx: int) -> Container:
dyceron marked this conversation as resolved.
Show resolved Hide resolved
return self.get_data().polys[poly_idx]

def get_point(self, poly_idx: int, point_idx: int) -> Container:
return self.get_poly(poly_idx).points[point_idx]

def get_total_boundings(self) -> Container:
return self.get_data().total_boundings

Check warning on line 92 in src/mercury_engine_data_structures/formats/bmscc.py

View check run for this annotation

Codecov / codecov/patch

src/mercury_engine_data_structures/formats/bmscc.py#L92

Added line #L92 was not covered by tests
16 changes: 16 additions & 0 deletions tests/formats/test_collision.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,19 @@ def test_compare_dread_210(dread_tree_210, file_path):
)
def test_compare_collision_msr(samus_returns_tree, file_path):
parse_build_compare_editor_parsed(Bmscc, samus_returns_tree, file_path)


@pytest.fixture()
def surface_bmscc(samus_returns_tree) -> Bmscc:
return samus_returns_tree.get_parsed_asset("maps/levels/c10_samus/s000_surface/s000_surface.bmscd", type_hint=Bmscc)


def test_get_data(surface_bmscc: Bmscc):
data = surface_bmscc.get_data()
assert len(data) == 5


def test_modifying_collision(surface_bmscc: Bmscc):
point = surface_bmscc.get_point(2, 9)
assert point["x"] == -800.0
assert point["y"] == -7000.0
Loading