diff --git a/apps/game_service/lib/game_service.ex b/apps/game_service/lib/game_service.ex index e79c6670..db37d3ac 100644 --- a/apps/game_service/lib/game_service.ex +++ b/apps/game_service/lib/game_service.ex @@ -9,7 +9,12 @@ defmodule GameService do alias GameService.PlayerComponents.EndpointComponent def entity_type(%PlayerBundle{}), do: :character + def entity_type(%Entity{id: {:player, _}}), do: :character + def entity_id(%PlayerBundle{id: id}), do: id + def entity_id(%Entity{id: {_, id}}), do: id + + def entity_type_to_prefix(:character), do: :player def load_bundle(%Entity{id: {:player, _}} = entity, components) do PlayerBundle.load(entity, components) diff --git a/apps/game_service/lib/game_service/events/direction_changed.ex b/apps/game_service/lib/game_service/events/direction_changed.ex index e4f265ff..91b5fc37 100644 --- a/apps/game_service/lib/game_service/events/direction_changed.ex +++ b/apps/game_service/lib/game_service/events/direction_changed.ex @@ -2,7 +2,14 @@ defmodule GameService.Events.DirectionChanged do @moduledoc """ Event triggered when an Entity change his direction. """ - use ElvenGard.ECS.Event, fields: [] - @type t :: %__MODULE__{} + use ElvenGard.ECS.Event, fields: [:entity_type, :entity_id, :value] + + alias ElvenEnums.EntityEnums + + @type t :: %__MODULE__{ + entity_type: EntityEnums.entity_type_keys(), + entity_id: non_neg_integer(), + value: EntityEnums.direction_type_keys() + } end diff --git a/apps/game_service/lib/game_service/partitions/static_map.ex b/apps/game_service/lib/game_service/partitions/static_map.ex index 242d4ae5..118c1511 100644 --- a/apps/game_service/lib/game_service/partitions/static_map.ex +++ b/apps/game_service/lib/game_service/partitions/static_map.ex @@ -26,7 +26,7 @@ defmodule GameService.StaticMapPartition do defp systems() do [ GameService.EntityVisibilitySystem, - GameService.EntityMapActionSystem + GameService.EntityMapActionsSystem ] end end diff --git a/apps/game_service/lib/game_service/systems/entity_map_action.ex b/apps/game_service/lib/game_service/systems/entity_map_action.ex deleted file mode 100644 index 054bba65..00000000 --- a/apps/game_service/lib/game_service/systems/entity_map_action.ex +++ /dev/null @@ -1,34 +0,0 @@ -defmodule GameService.EntityMapActionSystem do - @moduledoc """ - TODO: Documentation for GameService.EntityMapActionSystem - - Note: All Entities must have a PositionComponent or this system will raise - """ - - use ElvenGard.ECS.System, - lock_components: [ - GameService.EntityComponents.PositionComponent, - GameService.EntityComponents.DirectionComponent, - GameService.EntityComponents.LevelComponent, - GameService.PlayerComponents.HeroLevelComponent, - GameService.EntityComponents.CombatComponent, - # GameService.EntityComponents.BuffComponent, - GameService.EntityComponents.SpeedComponent, - GameService.EntityComponents.SittingComponent - ], - event_subscriptions: [ - GameService.Events.DirectionChanged, - GameService.Events.EntityInfoRequest, - GameService.Events.Movement, - GameService.Events.Sitting - ] - - require Logger - - # System behaviour - - @impl true - def run(event, _delta) do - Logger.warn("#{inspect(__MODULE__)} unhandled event #{inspect(event)}") - end -end diff --git a/apps/game_service/lib/game_service/systems/entity_map_actions.ex b/apps/game_service/lib/game_service/systems/entity_map_actions.ex new file mode 100644 index 00000000..a9640192 --- /dev/null +++ b/apps/game_service/lib/game_service/systems/entity_map_actions.ex @@ -0,0 +1,71 @@ +defmodule GameService.EntityMapActionsSystem do + @moduledoc """ + TODO: Documentation for GameService.EntityMapActionsSystem + """ + + use ElvenGard.ECS.System, + lock_components: [ + GameService.EntityComponents.PositionComponent, + GameService.EntityComponents.DirectionComponent, + GameService.EntityComponents.LevelComponent, + GameService.PlayerComponents.HeroLevelComponent, + GameService.EntityComponents.CombatComponent, + # GameService.EntityComponents.BuffComponent, + GameService.EntityComponents.SpeedComponent, + GameService.EntityComponents.SittingComponent + ], + event_subscriptions: [ + GameService.Events.DirectionChanged, + GameService.Events.EntityInfoRequest, + GameService.Events.Movement, + GameService.Events.Sitting + ] + + require Logger + + alias ElvenGard.ECS.{Command, Query} + + alias GameService.EntityComponents, as: E + + alias GameService.Events.{ + DirectionChanged + # EntityInfoRequest, + # Movement, + # Sitting + } + + # System behaviour + + @impl true + def run(%DirectionChanged{} = event, _delta) do + %DirectionChanged{ + entity_type: entity_type, + entity_id: entity_id, + value: value + } = event + + ecs_type = GameService.entity_type_to_prefix(entity_type) + ecs_id = {ecs_type, entity_id} + + # Check if the Entity exists + with {:ok, entity} <- Query.fetch_entity(ecs_id), + # Then update it's DirectionComponent + {:ok, _} <- Command.update_component(entity, E.DirectionComponent, value: value), + # Then get the current map + {:ok, position} <- Query.fetch_component(entity, E.PositionComponent) do + # Finally, notify all players on map + event = {:direction_changed, entity_type, entity_id, value} + GameService.System.map_event(event, position) + else + e -> + Logger.error( + "[#{inspect(__MODULE__)}] Can't set direction, " <> + "got #{inspect(e)} for #{inspect(event)}" + ) + end + end + + def run(event, _delta) do + Logger.warn("#{inspect(__MODULE__)} unhandled event #{inspect(event)}") + end +end diff --git a/apps/game_service/test/game_service/systems/entity_map_actions_system_test.exs b/apps/game_service/test/game_service/systems/entity_map_actions_system_test.exs new file mode 100644 index 00000000..0aebe906 --- /dev/null +++ b/apps/game_service/test/game_service/systems/entity_map_actions_system_test.exs @@ -0,0 +1,43 @@ +defmodule GameService.EntityMapActionsSystemTest do + use GameService.EntityCase, async: true + + alias ElvenGard.ECS.Query + + alias GameService.Events, as: Evt + alias GameService.EntityMapActionsSystem + alias GameService.EntityComponents, as: E + alias GameService.PlayerComponents, as: P + + ## Tests + + test "system notify on Entity change direction" do + # Register our process to receive message + ref = make_ref() + position = %E.PositionComponent{map_ref: ref} + endpoint = %P.EndpointComponent{pid: self()} + _ = spawn_player(components: [endpoint, position]) + + # Create our fake Entity with a DirectionComponent + direction = %E.DirectionComponent{value: :south} + entity = spawn_player(components: [position, direction]) + + # Call our System with a DirectionChanged event + event = %Evt.DirectionChanged{ + entity_type: :character, + entity_id: GameService.entity_id(entity), + value: :north + } + + _ = EntityMapActionsSystem.run(event, 0) + + # Check that the DirectionComponent was updated + {:ok, component} = Query.fetch_component(entity, E.DirectionComponent) + assert %E.DirectionComponent{value: :north} = component + + # # We should receive an event + assert_receive {:direction_changed, entity_type, entity_id, value} + assert entity_type == event.entity_type + assert entity_id == event.entity_id + assert value == event.value + end +end