Current section
Files
Jump to
Current section
Files
lib/sesopenko/ecs/component/state.ex
defmodule Sesopenko.ECS.Component.State do
defstruct state: %{}, subs: [], component: nil
alias Sesopenko.ECS.Component.State
use GenServer
@impl true
def init(%State{} = initial_state \\ %State{}) do
for sub_pid <- initial_state.subs do
send(sub_pid, {:state_changed, initial_state.component, initial_state.state})
end
{:ok, initial_state}
end
@impl true
def handle_call({:get_state}, _from, current_state) do
{:reply, current_state, current_state}
end
@impl true
def handle_call({:update_state, new_state}, _from, current_component) do
updated = Map.put(current_component, :state, new_state)
subs = current_component.subs
for sub_pid <- subs do
send(sub_pid, {:state_changed, current_component.component, new_state})
end
{:reply, nil, updated}
end
def handle_call({:sub, sub_pid}, _from, current_component) do
{
:reply,
:ok,
Map.update!(current_component, :subs, fn current_subs ->
[sub_pid | current_subs]
end)
}
end
@doc """
Spawns a component state with the given map as initial state
"""
@spec spawn_link(type :: map(), type :: atom(), type :: list()) :: type :: pid()
def spawn_link(initial_component_state, component, subs \\ []) do
new_state = initial_component_state
{:ok, component_pid} =
GenServer.start_link(State, %State{
state: new_state,
component: component,
subs: subs
})
component_pid
end
@doc """
Gets the state of a given component state process.
"""
@spec get(type :: pid()) :: type :: map()
def get(pid) do
GenServer.call(pid, {:get_state})
end
@doc """
sets the state of a given component state process with the given map.
"""
@spec update(type :: pid, type :: map()) :: nil
def update(pid, new_state) do
GenServer.call(pid, {:update_state, new_state})
end
def sub(state_pid, sub_pid) do
GenServer.call(state_pid, {:sub, sub_pid})
end
end