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

Refactor BRFLD #217

Merged
merged 34 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
976c4c1
Refactor BRFLD
MayberryZoom Aug 31, 2024
ab062d4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 31, 2024
cfef4c3
Rename layer to actor_layer and use enum for it
MayberryZoom Oct 7, 2024
a84a10f
Merge branch 'main' into brfld-layers
MayberryZoom Oct 7, 2024
2c49930
Get actor group by actor layer in add/remove actor from group functions
MayberryZoom Oct 11, 2024
64d002c
Use strings in ActorLayer enum
MayberryZoom Oct 11, 2024
96da27b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 11, 2024
c37ecb2
Add method to add actor to actor groups in other actor layers
MayberryZoom Oct 12, 2024
0ac279c
Add test for adding actor to actor groups
MayberryZoom Oct 12, 2024
428922d
Remove add_actor_to_entity_groups method
MayberryZoom Oct 12, 2024
beeee14
Rename actor_layer_name to actor_layer
MayberryZoom Oct 12, 2024
f340a7d
Get actor groups with correct method in add_actor_to_actor_groups
MayberryZoom Oct 12, 2024
a427581
Missing argument when getting actor group in is_actor_in_group
MayberryZoom Oct 12, 2024
b7fb6e4
Use enum value to access actor layers
MayberryZoom Oct 12, 2024
8954d9b
Fix collision camera names in tests
MayberryZoom Oct 12, 2024
aec9a37
Add missing type hints
MayberryZoom Oct 12, 2024
eb364ce
Add and update docstrings
MayberryZoom Oct 12, 2024
8bbc2eb
Fix ruff errors
MayberryZoom Oct 12, 2024
4e063d1
Add additional tests
MayberryZoom Oct 12, 2024
b7d9c1d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 12, 2024
c51f244
Merge branch 'main' into brfld-layers
MayberryZoom Oct 14, 2024
1ef9c69
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 14, 2024
1bced76
Re-add missing import
MayberryZoom Oct 14, 2024
9bc3a5d
Make ActorLayer enum extend str
MayberryZoom Oct 16, 2024
5fe16d4
Parametrize add/remove actor from group tests
MayberryZoom Oct 16, 2024
d3907cc
Raise and test exception when adding/removing actor from group
MayberryZoom Oct 16, 2024
8b20e2f
Use ActorLink alias when a method returns an actor link str
MayberryZoom Oct 16, 2024
ffef029
Fix ruff errors
MayberryZoom Oct 16, 2024
1272f96
Update all_actors_in_actor_layer returns docstring
MayberryZoom Oct 16, 2024
823a9cc
Merge branch 'main' into brfld-layers
MayberryZoom Oct 16, 2024
717c24b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 16, 2024
6ee9314
Add name and level properties to BRFLD
MayberryZoom Oct 16, 2024
4e90100
Use optional regex for exceptions in BRFLD test
MayberryZoom Oct 17, 2024
7f3b6f7
Rename ActorLink to BrfldLink and hint it in follow_link argument
MayberryZoom Oct 17, 2024
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
97 changes: 66 additions & 31 deletions src/mercury_engine_data_structures/formats/brfld.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import functools
import logging
from enum import Enum
from typing import Iterator, List, Tuple

import construct
Expand All @@ -11,22 +12,30 @@
logger = logging.getLogger(__name__)


class ActorLayer(Enum):
MayberryZoom marked this conversation as resolved.
Show resolved Hide resolved
ENTITIES = "rEntitiesLayer"
SOUNDS = "rSoundsLayer"
LIGHTS = "rLightsLayer"


class Brfld(BaseResource):
@classmethod
@functools.lru_cache
def construct_class(cls, target_game: Game) -> construct.Construct:
return standard_format.game_model("CScenario", "49.0.2")

def actors_for_layer(self, name: str) -> dict:
return self.raw.Root.pScenario.rEntitiesLayer.dctSublayers[name].dctActors
def actors_for_sublayer(self, sublayer_name: str, actor_layer_name: ActorLayer = ActorLayer.ENTITIES) -> dict:
return self.raw.Root.pScenario[actor_layer_name].dctSublayers[sublayer_name].dctActors

def all_layers(self) -> Iterator[str]:
yield from self.raw.Root.pScenario.rEntitiesLayer.dctSublayers.keys()
def sublayers_for_actor_layer(self, actor_layer_name: ActorLayer = ActorLayer.ENTITIES) -> Iterator[str]:
yield from self.raw.Root.pScenario[actor_layer_name].dctSublayers.keys()

def all_actors(self) -> Iterator[Tuple[str, str, construct.Container]]:
for layer_name, sublayer in self.raw.Root.pScenario.rEntitiesLayer.dctSublayers.items():
def all_actors_in_actor_layer(
self, actor_layer_name: ActorLayer = ActorLayer.ENTITIES
) -> Iterator[Tuple[str, str, construct.Container]]:
for sublayer_name, sublayer in self.raw.Root.pScenario[actor_layer_name].dctSublayers.items():
for actor_name, actor in sublayer.dctActors.items():
yield layer_name, actor_name, actor
yield sublayer_name, actor_name, actor

def follow_link(self, link: str):
if link != "{EMPTY}":
Expand All @@ -35,42 +44,68 @@ def follow_link(self, link: str):
result = result[part]
return result

MayberryZoom marked this conversation as resolved.
Show resolved Hide resolved
def link_for_actor(self, actor_name: str, layer_name: str = "default") -> str:
return ":".join(["Root", "pScenario", "rEntitiesLayer", "dctSublayers", layer_name, "dctActors", actor_name])

def all_actor_groups(self) -> Iterator[str]:
yield from self.raw.Root.pScenario.rEntitiesLayer.dctActorGroups.keys()

def get_actor_group(self, group_name: str) -> List[str]:
return self.raw.Root.pScenario.rEntitiesLayer.dctActorGroups[group_name]

def is_actor_in_group(self, group_name: str, actor_name: str, layer_name: str = "default") -> bool:
return self.link_for_actor(actor_name, layer_name) in self.get_actor_group(group_name)

def add_actor_to_group(self, group_name: str, actor_name: str, layer_name: str = "default"):
group = self.get_actor_group(group_name)
actor_link = self.link_for_actor(actor_name, layer_name)
def link_for_actor(
self, actor_name: str, sublayer_name: str = "default", actor_layer_name: ActorLayer = ActorLayer.ENTITIES
) -> str:
return ":".join(["Root", "pScenario", actor_layer_name, "dctSublayers", sublayer_name, "dctActors", actor_name])

def actor_groups_for_actor_layer(self, actor_layer_name: ActorLayer = ActorLayer.ENTITIES) -> Iterator[str]:
yield from self.raw.Root.pScenario[actor_layer_name].dctActorGroups.keys()

def get_actor_group(self, group_name: str, actor_layer_name: ActorLayer = ActorLayer.ENTITIES) -> List[str]:
return self.raw.Root.pScenario[actor_layer_name].dctActorGroups[group_name]

def is_actor_in_group(
self,
group_name: str,
actor_name: str,
sublayer_name: str = "default",
actor_layer_name: ActorLayer = ActorLayer.ENTITIES,
) -> bool:
return self.link_for_actor(actor_name, sublayer_name, actor_layer_name) in self.get_actor_group(group_name)

def add_actor_to_group(
self,
group_name: str,
actor_name: str,
sublayer_name: str = "default",
actor_layer_name: ActorLayer = ActorLayer.ENTITIES,
):
group = self.get_actor_group(group_name, actor_layer_name)
actor_link = self.link_for_actor(actor_name, sublayer_name, actor_layer_name)
if actor_link not in group:
group.append(actor_link)

def remove_actor_from_group(self, group_name: str, actor_name: str, layer_name: str = "default"):
group = self.get_actor_group(group_name)
actor_link = self.link_for_actor(actor_name, layer_name)
def remove_actor_from_group(
self,
group_name: str,
actor_name: str,
sublayer_name: str = "default",
actor_layer_name: ActorLayer = ActorLayer.ENTITIES,
):
group = self.get_actor_group(group_name, actor_layer_name)
actor_link = self.link_for_actor(actor_name, sublayer_name, actor_layer_name)
if actor_link in group:
group.remove(actor_link)

def add_actor_to_entity_groups(self, collision_camera_name: str, actor_name: str, layer_name: str = "default"):
def add_actor_to_actor_groups(
self,
collision_camera_name: str,
actor_name: str,
sublayer_name: str = "default",
actor_layer_name: ActorLayer = ActorLayer.ENTITIES,
):
"""
adds an actor to all entity groups starting with "eg_" + collision_camera_name
adds an actor to all actor groups starting with collision_camera_name

param collision_camera_name: name of the collision camera group
(prefix "eg_" is added to find the entity groups)
param actor_name: name of the actor to add to the group
param layer_name: name of the layer the actor belongs to
param sublayer_name: name of the sublayer the actor belongs to
param actor_layer_name: the actor layer the sublayer belongs to
"""
collision_camera_groups = [
group for group in self.all_actor_groups() if group.startswith(f"eg_{collision_camera_name}")
group for group in self.all_actor_groups() if group.startswith(collision_camera_name)
]
for group in collision_camera_groups:
logger.debug("Add actor %s to group %s", actor_name, group)
self.add_actor_to_group(group, actor_name, layer_name)
self.add_actor_to_group(group, actor_name, sublayer_name, actor_layer_name)
23 changes: 22 additions & 1 deletion tests/formats/test_brfld.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from tests.test_lib import parse_build_compare_editor

from mercury_engine_data_structures import dread_data
from mercury_engine_data_structures.formats.brfld import Brfld
from mercury_engine_data_structures.formats.brfld import ActorLayer, Brfld

bossrush_assets = [
"maps/levels/c10_samus/s201_bossrush_scorpius/s201_bossrush_scorpius.brfld",
Expand All @@ -28,3 +28,24 @@ def test_dread_brfld_100(dread_tree_100, brfld_path):
@pytest.mark.parametrize("brfld_path", bossrush_assets)
def test_dread_brfld_210(dread_tree_210, brfld_path):
parse_build_compare_editor(Brfld, dread_tree_210, brfld_path)


def test_add_actor_to_actor_groups(dread_tree_100):
scenario = dread_tree_100.get_file("maps/levels/c10_samus/s010_cave/s010_cave.brfld", Brfld)

scenario.add_actor_to_actor_groups("collision_camera_000", "breakabletilegroup_000", "breakables")
assert scenario.is_actor_in_group("eg_collision_camera_000", "breakabletilegroup_000", "breakables")

scenario.add_actor_to_actor_groups(
"ssg_collision_camera_000_Default", "Pos_C_LavaWindow_06", actor_layer_name=ActorLayer.SOUNDS
)
assert scenario.is_actor_in_group(
"ssg_collision_camera_000_Default", "Pos_C_LavaWindow_06", actor_layer_name=ActorLayer.SOUNDS
)

scenario.add_actor_to_actor_groups(
"lg_collision_camera_000", "cubemap_006_1_bake", "emmy_006_light", ActorLayer.LIGHTS
)
assert scenario.is_actor_in_group(
"lg_collision_camera_000", "cubemap_006_1_bake", "emmy_006_light", ActorLayer.LIGHTS
)
Loading