mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-11-02 23:47:04 +00:00
294 lines
8.5 KiB
Elixir
294 lines
8.5 KiB
Elixir
defmodule WandererApp.Character.TrackingUtils do
|
|
@moduledoc """
|
|
Utility functions for handling character tracking and following operations.
|
|
|
|
"""
|
|
|
|
require Logger
|
|
|
|
@doc """
|
|
Toggles the tracking state for a character on a map.
|
|
Returns the updated tracking data for all characters with access to the map.
|
|
"""
|
|
def update_tracking(
|
|
map_id,
|
|
character_eve_id,
|
|
current_user_id,
|
|
track,
|
|
caller_pid,
|
|
only_tracked_characters
|
|
)
|
|
when not is_nil(caller_pid) do
|
|
with {:ok, character} <-
|
|
WandererApp.Character.get_by_eve_id("#{character_eve_id}"),
|
|
{:ok, %{tracked: is_tracked}} <-
|
|
do_update_character_tracking(character, map_id, track, caller_pid) do
|
|
# Determine which event to send based on tracking mode and previous state
|
|
if only_tracked_characters && not is_tracked do
|
|
{:ok, nil, :not_all_characters_tracked}
|
|
else
|
|
# Get updated tracking data
|
|
{:ok, tracking_data} = build_tracking_data(map_id, current_user_id)
|
|
|
|
{:ok, tracking_data, %{event: :refresh_user_characters}}
|
|
end
|
|
else
|
|
error ->
|
|
Logger.error("Failed to toggle tracking: #{inspect(error)}")
|
|
{:error, "Failed to toggle tracking"}
|
|
end
|
|
end
|
|
|
|
def update_tracking(
|
|
_map_id,
|
|
_character_id,
|
|
_current_user_id,
|
|
_track,
|
|
_caller_pid,
|
|
_only_tracked_characters
|
|
) do
|
|
Logger.error("Failed to update tracking")
|
|
{:error, "Failed to update tracking"}
|
|
end
|
|
|
|
@doc """
|
|
Builds tracking data for all characters with access to a map.
|
|
"""
|
|
def build_tracking_data(map_id, current_user_id) do
|
|
with {:ok, map} <-
|
|
WandererApp.MapRepo.get(map_id,
|
|
acls: [
|
|
:owner_id,
|
|
members: [:role, :eve_character_id, :eve_corporation_id, :eve_alliance_id]
|
|
]
|
|
),
|
|
{:ok, user_settings} <- WandererApp.MapUserSettingsRepo.get(map_id, current_user_id),
|
|
{:ok, %{characters: characters_with_access}} <-
|
|
WandererApp.Maps.load_characters(map, current_user_id) do
|
|
# Map characters to tracking data
|
|
{:ok, characters_data} =
|
|
build_character_tracking_data(characters_with_access)
|
|
|
|
{:ok, main_character} =
|
|
get_main_character(user_settings, characters_with_access, characters_with_access)
|
|
|
|
following_character_eve_id =
|
|
case user_settings do
|
|
nil -> nil
|
|
%{following_character_eve_id: following_character_eve_id} -> following_character_eve_id
|
|
end
|
|
|
|
main_character_eve_id =
|
|
case main_character do
|
|
nil -> nil
|
|
%{eve_id: eve_id} -> eve_id
|
|
end
|
|
|
|
{:ok,
|
|
%{
|
|
characters: characters_data,
|
|
main: main_character_eve_id,
|
|
following: following_character_eve_id
|
|
}}
|
|
else
|
|
nil ->
|
|
Logger.warning("User not found when building tracking data", %{user_id: current_user_id})
|
|
{:error, "User not found"}
|
|
|
|
error ->
|
|
Logger.error("Error building tracking data: #{inspect(error)}")
|
|
{:error, "Failed to build tracking data"}
|
|
end
|
|
end
|
|
|
|
# Helper to build tracking data for each character
|
|
defp build_character_tracking_data(characters) do
|
|
{:ok,
|
|
Enum.map(characters, fn char ->
|
|
%{
|
|
character: char |> WandererAppWeb.MapEventHandler.map_ui_character_stat(),
|
|
tracked: char.tracked
|
|
}
|
|
end)}
|
|
end
|
|
|
|
# Private implementation of update character tracking
|
|
defp do_update_character_tracking(character, map_id, track, caller_pid) do
|
|
WandererApp.MapCharacterSettingsRepo.get(map_id, character.id)
|
|
|> case do
|
|
# Untracking flow
|
|
{:ok, %{tracked: true} = existing_settings} ->
|
|
if not track do
|
|
{:ok, updated_settings} =
|
|
WandererApp.MapCharacterSettingsRepo.untrack(existing_settings)
|
|
|
|
:ok = untrack([character], map_id, caller_pid)
|
|
{:ok, updated_settings}
|
|
else
|
|
{:ok, existing_settings}
|
|
end
|
|
|
|
# Tracking flow
|
|
{:ok, %{tracked: false} = existing_settings} ->
|
|
if track do
|
|
{:ok, updated_settings} = WandererApp.MapCharacterSettingsRepo.track(existing_settings)
|
|
:ok = track([character], map_id, true, caller_pid)
|
|
{:ok, updated_settings}
|
|
else
|
|
{:ok, existing_settings}
|
|
end
|
|
|
|
{:error, :not_found} ->
|
|
if track do
|
|
# Create new settings with tracking enabled
|
|
{:ok, settings} =
|
|
WandererApp.MapCharacterSettingsRepo.create(%{
|
|
character_id: character.id,
|
|
map_id: map_id,
|
|
tracked: true
|
|
})
|
|
|
|
:ok = track([character], map_id, true, caller_pid)
|
|
{:ok, settings}
|
|
else
|
|
{:error, "Character settings not found"}
|
|
end
|
|
|
|
error ->
|
|
error
|
|
end
|
|
end
|
|
|
|
# Helper functions for character tracking
|
|
|
|
def track([], _map_id, _is_track_character?, _), do: :ok
|
|
|
|
def track([character | characters], map_id, is_track_allowed, caller_pid) do
|
|
with :ok <- track_character(character, map_id, is_track_allowed, caller_pid) do
|
|
track(characters, map_id, is_track_allowed, caller_pid)
|
|
end
|
|
end
|
|
|
|
defp track_character(
|
|
%{
|
|
id: character_id,
|
|
eve_id: eve_id
|
|
},
|
|
map_id,
|
|
is_track_allowed,
|
|
caller_pid
|
|
)
|
|
when not is_nil(caller_pid) do
|
|
WandererAppWeb.Presence.update(caller_pid, map_id, character_id, %{
|
|
tracked: is_track_allowed,
|
|
from: DateTime.utc_now()
|
|
})
|
|
|> case do
|
|
{:ok, _} ->
|
|
:ok
|
|
|
|
{:error, :nopresence} ->
|
|
WandererAppWeb.Presence.track(caller_pid, map_id, character_id, %{
|
|
tracked: is_track_allowed,
|
|
from: DateTime.utc_now()
|
|
})
|
|
|
|
error ->
|
|
Logger.error("Failed to update presence: #{inspect(error)}")
|
|
{:error, "Failed to update presence"}
|
|
end
|
|
|
|
cache_key = "#{inspect(caller_pid)}_map_#{map_id}:character_#{character_id}:tracked"
|
|
|
|
case WandererApp.Cache.lookup!(cache_key, false) do
|
|
true ->
|
|
:ok
|
|
|
|
_ ->
|
|
:ok = Phoenix.PubSub.subscribe(WandererApp.PubSub, "character:#{eve_id}")
|
|
:ok = WandererApp.Cache.put(cache_key, true)
|
|
end
|
|
|
|
if is_track_allowed do
|
|
:ok = WandererApp.Character.TrackerManager.start_tracking(character_id)
|
|
end
|
|
|
|
:ok
|
|
end
|
|
|
|
defp track_character(
|
|
_character,
|
|
_map_id,
|
|
_is_track_allowed,
|
|
_caller_pid
|
|
) do
|
|
Logger.error("caller_pid is required for tracking characters")
|
|
{:error, "caller_pid is required"}
|
|
end
|
|
|
|
def untrack(characters, map_id, caller_pid) do
|
|
with false <- is_nil(caller_pid) do
|
|
character_ids = characters |> Enum.map(& &1.id)
|
|
|
|
character_ids
|
|
|> Enum.each(fn character_id ->
|
|
WandererAppWeb.Presence.update(caller_pid, map_id, character_id, %{
|
|
tracked: false,
|
|
from: DateTime.utc_now()
|
|
})
|
|
end)
|
|
|
|
# WandererApp.Map.Server.untrack_characters(map_id, character_ids)
|
|
|
|
:ok
|
|
else
|
|
true ->
|
|
Logger.error("caller_pid is required for untracking characters")
|
|
{:error, "caller_pid is required"}
|
|
end
|
|
end
|
|
|
|
# def add_characters([], _map_id, _track_character), do: :ok
|
|
|
|
# def add_characters([character | characters], map_id, track_character) do
|
|
# :ok = WandererApp.Map.Server.add_character(map_id, character, track_character)
|
|
# add_characters(characters, map_id, track_character)
|
|
# end
|
|
|
|
# def remove_characters([], _map_id), do: :ok
|
|
|
|
# def remove_characters([character | characters], map_id) do
|
|
# :ok = WandererApp.Map.Server.remove_character(map_id, character.id)
|
|
# remove_characters(characters, map_id)
|
|
# end
|
|
|
|
def get_main_character(
|
|
nil,
|
|
current_user_characters,
|
|
available_map_characters
|
|
),
|
|
do:
|
|
get_main_character(
|
|
%{main_character_eve_id: nil},
|
|
current_user_characters,
|
|
available_map_characters
|
|
)
|
|
|
|
def get_main_character(
|
|
%{main_character_eve_id: nil} = _map_user_settings,
|
|
_current_user_characters,
|
|
available_map_characters
|
|
),
|
|
do: {:ok, available_map_characters |> Enum.sort_by(& &1.inserted_at) |> List.first()}
|
|
|
|
def get_main_character(
|
|
%{main_character_eve_id: main_character_eve_id} = _map_user_settings,
|
|
current_user_characters,
|
|
_available_map_characters
|
|
),
|
|
do:
|
|
{:ok,
|
|
current_user_characters
|
|
|> Enum.find(fn c -> c.eve_id === main_character_eve_id end)}
|
|
end
|