mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-12-05 07:15:34 +00:00
920 lines
28 KiB
Elixir
920 lines
28 KiB
Elixir
defmodule WandererApp.Map.Server.ConnectionsImpl do
|
|
@moduledoc false
|
|
|
|
require Logger
|
|
|
|
alias WandererApp.Map.Server.Impl
|
|
alias WandererApp.Map.Server.SignaturesImpl
|
|
|
|
# @ccp1 -1
|
|
@c1 1
|
|
@c2 2
|
|
@c3 3
|
|
@c4 4
|
|
@c5 5
|
|
@c6 6
|
|
@hs 7
|
|
@ls 8
|
|
@ns 9
|
|
# @ccp2 10
|
|
# @ccp3 11
|
|
@thera 12
|
|
@c13 13
|
|
@sentinel 14
|
|
@barbican 15
|
|
@vidette 16
|
|
@conflux 17
|
|
@redoubt 18
|
|
@a1 19
|
|
@a2 20
|
|
@a3 21
|
|
@a4 22
|
|
@a5 23
|
|
@ccp4 24
|
|
@pochven 25
|
|
# @zarzakh 10100
|
|
|
|
@frigate_ship_size 0
|
|
@large_ship_size 2
|
|
|
|
@jita 30_000_142
|
|
|
|
@wh_space [
|
|
@c1,
|
|
@c2,
|
|
@c3,
|
|
@c4,
|
|
@c5,
|
|
@c6,
|
|
@c13,
|
|
@thera,
|
|
@sentinel,
|
|
@barbican,
|
|
@vidette,
|
|
@conflux,
|
|
@redoubt
|
|
]
|
|
|
|
@known_space [@hs, @ls, @ns, @pochven]
|
|
|
|
@prohibited_systems [@jita]
|
|
@prohibited_system_classes [
|
|
@a1,
|
|
@a2,
|
|
@a3,
|
|
@a4,
|
|
@a5,
|
|
@ccp4
|
|
]
|
|
|
|
# this class of systems will guaranty that no one real class will take that place
|
|
# @unknown 100_100
|
|
|
|
# default (env) setting, not EOL
|
|
@connection_time_status_default 0
|
|
# EOL 1h
|
|
@connection_time_status_eol 1
|
|
# EOL 4h
|
|
@connection_time_status_eol_4 2
|
|
# EOL 4.5h
|
|
@connection_time_status_eol_4_5 3
|
|
# EOL 16h
|
|
@connection_time_status_eol_16 4
|
|
# EOL 24h
|
|
@connection_time_status_eol_24 5
|
|
# EOL 48h
|
|
@connection_time_status_eol_48 6
|
|
|
|
# EOL 1h
|
|
@connection_eol_minutes 60
|
|
# EOL 4h
|
|
@connection_eol_4_minutes 4 * 60
|
|
# EOL 4.5h
|
|
@connection_eol_4_5_minutes 4.5 * 60
|
|
# EOL 16h
|
|
@connection_eol_16_minutes 16 * 60
|
|
# EOL 24h
|
|
@connection_eol_24_minutes 24 * 60
|
|
# EOL 48h
|
|
@connection_eol_48_minutes 48 * 60
|
|
|
|
@connection_type_wormhole 0
|
|
@connection_type_stargate 1
|
|
@connection_type_bridge 2
|
|
@medium_ship_size 1
|
|
|
|
def get_connection_auto_expire_hours(), do: WandererApp.Env.map_connection_auto_expire_hours()
|
|
|
|
def get_connection_auto_eol_hours(), do: WandererApp.Env.map_connection_auto_eol_hours()
|
|
|
|
def get_eol_expire_timeout_mins(), do: WandererApp.Env.map_connection_eol_expire_timeout_mins()
|
|
|
|
def get_eol_expire_timeout(),
|
|
do:
|
|
:timer.hours(get_connection_auto_expire_hours() - get_connection_auto_eol_hours()) +
|
|
:timer.minutes(get_eol_expire_timeout_mins())
|
|
|
|
def get_connection_expire_timeout(),
|
|
do:
|
|
:timer.hours(get_connection_auto_expire_hours()) +
|
|
:timer.minutes(get_eol_expire_timeout_mins())
|
|
|
|
def init_eol_cache(map_id, connections_eol_time) do
|
|
connections_eol_time
|
|
|> Enum.each(fn {connection_id, connection_eol_time} ->
|
|
WandererApp.Cache.put(
|
|
"map_#{map_id}:conn_#{connection_id}:mark_eol_time",
|
|
connection_eol_time
|
|
)
|
|
end)
|
|
end
|
|
|
|
def init_start_cache(map_id, connections_start_time) when not is_nil(connections_start_time) do
|
|
connections_start_time
|
|
|> Enum.each(fn {connection_id, start_time} ->
|
|
set_start_time(map_id, connection_id, start_time)
|
|
end)
|
|
end
|
|
|
|
def init_start_cache(_map_id, _connections_start_time), do: :ok
|
|
|
|
def add_connection(
|
|
map_id,
|
|
%{
|
|
solar_system_source_id: solar_system_source_id,
|
|
solar_system_target_id: solar_system_target_id,
|
|
character_id: character_id
|
|
} = connection_info
|
|
),
|
|
do:
|
|
maybe_add_connection(
|
|
map_id,
|
|
%{solar_system_id: solar_system_target_id},
|
|
%{
|
|
solar_system_id: solar_system_source_id
|
|
},
|
|
character_id,
|
|
true,
|
|
connection_info |> Map.get(:extra_info)
|
|
)
|
|
|
|
def paste_connections(
|
|
map_id,
|
|
connections,
|
|
_user_id,
|
|
character_id
|
|
) do
|
|
connections
|
|
|> Enum.each(fn %{
|
|
"source" => source,
|
|
"target" => target
|
|
} = connection ->
|
|
solar_system_source_id = source |> String.to_integer()
|
|
solar_system_target_id = target |> String.to_integer()
|
|
|
|
add_connection(map_id, %{
|
|
solar_system_source_id: solar_system_source_id,
|
|
solar_system_target_id: solar_system_target_id,
|
|
character_id: character_id,
|
|
extra_info: connection
|
|
})
|
|
end)
|
|
end
|
|
|
|
def delete_connection(
|
|
map_id,
|
|
%{
|
|
solar_system_source_id: solar_system_source_id,
|
|
solar_system_target_id: solar_system_target_id
|
|
} = _connection_info
|
|
),
|
|
do:
|
|
maybe_remove_connection(map_id, %{solar_system_id: solar_system_target_id}, %{
|
|
solar_system_id: solar_system_source_id
|
|
})
|
|
|
|
def get_connection_info(
|
|
map_id,
|
|
%{
|
|
solar_system_source_id: solar_system_source_id,
|
|
solar_system_target_id: solar_system_target_id
|
|
} = _connection_info
|
|
) do
|
|
WandererApp.Map.find_connection(
|
|
map_id,
|
|
solar_system_source_id,
|
|
solar_system_target_id
|
|
)
|
|
|> case do
|
|
{:ok, %{id: connection_id}} ->
|
|
connection_mark_eol_time = get_connection_mark_eol_time(map_id, connection_id, nil)
|
|
{:ok, %{marl_eol_time: connection_mark_eol_time}}
|
|
|
|
_ ->
|
|
{:error, :not_found}
|
|
end
|
|
end
|
|
|
|
def update_connection_time_status(
|
|
map_id,
|
|
connection_update
|
|
),
|
|
do:
|
|
update_connection(map_id, :update_time_status, [:time_status], connection_update, fn
|
|
%{time_status: old_time_status},
|
|
%{id: connection_id, time_status: time_status} = updated_connection ->
|
|
case time_status == @connection_time_status_eol do
|
|
true ->
|
|
if old_time_status != @connection_time_status_eol do
|
|
WandererApp.Cache.put(
|
|
"map_#{map_id}:conn_#{connection_id}:mark_eol_time",
|
|
DateTime.utc_now()
|
|
)
|
|
|
|
set_start_time(map_id, connection_id, DateTime.utc_now())
|
|
end
|
|
|
|
_ ->
|
|
if old_time_status == @connection_time_status_eol do
|
|
WandererApp.Cache.delete("map_#{map_id}:conn_#{connection_id}:mark_eol_time")
|
|
set_start_time(map_id, connection_id, DateTime.utc_now())
|
|
end
|
|
end
|
|
|
|
if time_status != old_time_status do
|
|
maybe_update_linked_signature_time_status(map_id, updated_connection)
|
|
end
|
|
end)
|
|
|
|
def update_connection_type(
|
|
map_id,
|
|
connection_update
|
|
),
|
|
do: update_connection(map_id, :update_type, [:type], connection_update)
|
|
|
|
def update_connection_mass_status(
|
|
map_id,
|
|
connection_update
|
|
),
|
|
do: update_connection(map_id, :update_mass_status, [:mass_status], connection_update)
|
|
|
|
def update_connection_ship_size_type(
|
|
map_id,
|
|
connection_update
|
|
),
|
|
do: update_connection(map_id, :update_ship_size_type, [:ship_size_type], connection_update)
|
|
|
|
def update_connection_locked(
|
|
map_id,
|
|
connection_update
|
|
),
|
|
do: update_connection(map_id, :update_locked, [:locked], connection_update)
|
|
|
|
def update_connection_custom_info(
|
|
map_id,
|
|
connection_update
|
|
),
|
|
do: update_connection(map_id, :update_custom_info, [:custom_info], connection_update)
|
|
|
|
def cleanup_connections(map_id) do
|
|
connection_auto_expire_hours = get_connection_auto_expire_hours()
|
|
connection_auto_eol_hours = get_connection_auto_eol_hours()
|
|
connection_eol_expire_timeout_hours = get_eol_expire_timeout_mins() / 60
|
|
|
|
map_id
|
|
|> WandererApp.Map.list_connections!()
|
|
|> Enum.each(fn connection ->
|
|
maybe_update_connection_time_status(map_id, connection)
|
|
end)
|
|
|
|
map_id
|
|
|> WandererApp.Map.list_connections!()
|
|
|> Enum.filter(fn %{
|
|
id: connection_id,
|
|
solar_system_source: solar_system_source_id,
|
|
solar_system_target: solar_system_target_id,
|
|
time_status: time_status,
|
|
type: type
|
|
} ->
|
|
is_connection_exist =
|
|
is_connection_exist(
|
|
map_id,
|
|
solar_system_source_id,
|
|
solar_system_target_id
|
|
) ||
|
|
not is_nil(
|
|
WandererApp.Map.get_connection(
|
|
map_id,
|
|
solar_system_target_id,
|
|
solar_system_source_id
|
|
)
|
|
)
|
|
|
|
not is_connection_exist ||
|
|
(type == @connection_type_wormhole &&
|
|
time_status == @connection_time_status_eol &&
|
|
is_connection_valid(
|
|
:wormholes,
|
|
solar_system_source_id,
|
|
solar_system_target_id
|
|
) &&
|
|
DateTime.diff(
|
|
DateTime.utc_now(),
|
|
get_connection_mark_eol_time(map_id, connection_id),
|
|
:hour
|
|
) >=
|
|
connection_auto_expire_hours - connection_auto_eol_hours +
|
|
connection_eol_expire_timeout_hours)
|
|
end)
|
|
|> Enum.each(fn %{
|
|
solar_system_source: solar_system_source_id,
|
|
solar_system_target: solar_system_target_id
|
|
} ->
|
|
delete_connection(map_id, %{
|
|
solar_system_source_id: solar_system_source_id,
|
|
solar_system_target_id: solar_system_target_id
|
|
})
|
|
end)
|
|
end
|
|
|
|
defp maybe_update_connection_time_status(map_id, %{
|
|
id: connection_id,
|
|
solar_system_source: solar_system_source_id,
|
|
solar_system_target: solar_system_target_id,
|
|
time_status: time_status,
|
|
type: @connection_type_wormhole
|
|
}) do
|
|
connection_start_time = get_start_time(map_id, connection_id)
|
|
new_time_status = get_new_time_status(connection_start_time, time_status)
|
|
|
|
if new_time_status != time_status &&
|
|
is_connection_valid(
|
|
:wormholes,
|
|
solar_system_source_id,
|
|
solar_system_target_id
|
|
) do
|
|
set_start_time(map_id, connection_id, DateTime.utc_now())
|
|
|
|
update_connection_time_status(map_id, %{
|
|
solar_system_source_id: solar_system_source_id,
|
|
solar_system_target_id: solar_system_target_id,
|
|
time_status: new_time_status
|
|
})
|
|
end
|
|
end
|
|
|
|
defp maybe_update_connection_time_status(_map_id, _connection), do: :ok
|
|
|
|
defp maybe_update_linked_signature_time_status(
|
|
map_id,
|
|
%{
|
|
time_status: time_status,
|
|
solar_system_source: solar_system_source,
|
|
solar_system_target: solar_system_target
|
|
} = updated_connection
|
|
) do
|
|
with source_system when not is_nil(source_system) <-
|
|
WandererApp.Map.find_system_by_location(
|
|
map_id,
|
|
%{solar_system_id: solar_system_source}
|
|
),
|
|
target_system when not is_nil(source_system) <-
|
|
WandererApp.Map.find_system_by_location(
|
|
map_id,
|
|
%{solar_system_id: solar_system_target}
|
|
),
|
|
source_linked_signatures <-
|
|
find_linked_signatures(source_system, target_system),
|
|
target_linked_signatures <- find_linked_signatures(target_system, source_system) do
|
|
update_signatures_time_status(
|
|
map_id,
|
|
source_system.solar_system_id,
|
|
source_linked_signatures,
|
|
time_status
|
|
)
|
|
|
|
update_signatures_time_status(
|
|
map_id,
|
|
target_system.solar_system_id,
|
|
target_linked_signatures,
|
|
time_status
|
|
)
|
|
else
|
|
error ->
|
|
Logger.warning("Failed to update_linked_signature_time_status: #{inspect(error)}")
|
|
end
|
|
end
|
|
|
|
defp find_linked_signatures(
|
|
%{id: source_system_id} = _source_system,
|
|
%{solar_system_id: solar_system_id, linked_sig_eve_id: linked_sig_eve_id} =
|
|
_target_system
|
|
)
|
|
when not is_nil(linked_sig_eve_id) do
|
|
{:ok, signatures} =
|
|
WandererApp.Api.MapSystemSignature.by_linked_system_id(solar_system_id)
|
|
|
|
signatures |> Enum.filter(fn sig -> sig.system_id == source_system_id end)
|
|
end
|
|
|
|
defp find_linked_signatures(_source_system, _target_system), do: []
|
|
|
|
defp update_signatures_time_status(_map_id, _solar_system_id, [], _time_status), do: :ok
|
|
|
|
defp update_signatures_time_status(map_id, solar_system_id, signatures, time_status) do
|
|
signatures
|
|
|> Enum.each(fn %{custom_info: custom_info_json} = sig ->
|
|
update_params =
|
|
if not is_nil(custom_info_json) do
|
|
updated_custom_info =
|
|
custom_info_json
|
|
|> Jason.decode!()
|
|
|> Map.merge(%{"time_status" => time_status})
|
|
|> Jason.encode!()
|
|
|
|
%{custom_info: updated_custom_info}
|
|
else
|
|
updated_custom_info = Jason.encode!(%{"time_status" => time_status})
|
|
%{custom_info: updated_custom_info}
|
|
end
|
|
|
|
SignaturesImpl.apply_update_signature(map_id, sig, update_params)
|
|
end)
|
|
|
|
Impl.broadcast!(map_id, :signatures_updated, solar_system_id)
|
|
end
|
|
|
|
def maybe_add_connection(
|
|
map_id,
|
|
location,
|
|
old_location,
|
|
character_id,
|
|
is_manual,
|
|
extra_info
|
|
)
|
|
when not is_nil(location) and not is_nil(old_location) and
|
|
not is_nil(old_location.solar_system_id) and
|
|
location.solar_system_id != old_location.solar_system_id do
|
|
{:ok, character} = WandererApp.Character.get_character(character_id)
|
|
|
|
if not is_manual do
|
|
:telemetry.execute([:wanderer_app, :map, :character, :jump], %{count: 1}, %{})
|
|
|
|
{:ok, _} =
|
|
WandererApp.Api.MapChainPassages.new(%{
|
|
map_id: map_id,
|
|
character_id: character_id,
|
|
ship_type_id: character.ship,
|
|
ship_name: character.ship_name,
|
|
solar_system_source_id: old_location.solar_system_id,
|
|
solar_system_target_id: location.solar_system_id
|
|
})
|
|
end
|
|
|
|
case WandererApp.Map.check_connection(map_id, location, old_location) do
|
|
:ok ->
|
|
connection_type =
|
|
is_connection_valid(
|
|
:stargates,
|
|
old_location.solar_system_id,
|
|
location.solar_system_id
|
|
)
|
|
|> case do
|
|
true ->
|
|
@connection_type_stargate
|
|
|
|
_ ->
|
|
@connection_type_wormhole
|
|
end
|
|
|
|
# Set ship size type based on system classes and special rules
|
|
ship_size_type =
|
|
get_ship_size_type(
|
|
old_location.solar_system_id,
|
|
location.solar_system_id,
|
|
connection_type
|
|
)
|
|
|
|
time_status =
|
|
if connection_type == @connection_type_wormhole do
|
|
get_time_status(
|
|
old_location.solar_system_id,
|
|
location.solar_system_id,
|
|
ship_size_type
|
|
)
|
|
else
|
|
@connection_time_status_default
|
|
end
|
|
|
|
connection_type = get_extra_info(extra_info, "type", connection_type)
|
|
ship_size_type = get_extra_info(extra_info, "ship_size_type", ship_size_type)
|
|
time_status = get_extra_info(extra_info, "time_status", time_status)
|
|
mass_status = get_extra_info(extra_info, "mass_status", 0)
|
|
locked = get_extra_info(extra_info, "locked", false)
|
|
|
|
{:ok, connection} =
|
|
WandererApp.MapConnectionRepo.create(%{
|
|
map_id: map_id,
|
|
solar_system_source: old_location.solar_system_id,
|
|
solar_system_target: location.solar_system_id,
|
|
type: connection_type,
|
|
ship_size_type: ship_size_type,
|
|
time_status: time_status,
|
|
mass_status: mass_status,
|
|
locked: locked
|
|
})
|
|
|
|
if connection_type == @connection_type_wormhole do
|
|
set_start_time(map_id, connection.id, DateTime.utc_now())
|
|
end
|
|
|
|
WandererApp.Map.add_connection(map_id, connection)
|
|
|
|
Impl.broadcast!(map_id, :maybe_select_system, %{
|
|
character_id: character_id,
|
|
solar_system_id: location.solar_system_id
|
|
})
|
|
|
|
Impl.broadcast!(map_id, :add_connection, connection)
|
|
|
|
Impl.broadcast!(map_id, :maybe_link_signature, %{
|
|
character_id: character_id,
|
|
solar_system_source: old_location.solar_system_id,
|
|
solar_system_target: location.solar_system_id
|
|
})
|
|
|
|
# ADDITIVE: Also broadcast to external event system (webhooks/WebSocket)
|
|
WandererApp.ExternalEvents.broadcast(map_id, :connection_added, %{
|
|
connection_id: connection.id,
|
|
solar_system_source_id: old_location.solar_system_id,
|
|
solar_system_target_id: location.solar_system_id,
|
|
type: connection_type,
|
|
ship_size_type: ship_size_type,
|
|
mass_status: connection.mass_status,
|
|
time_status: connection.time_status
|
|
})
|
|
|
|
WandererApp.User.ActivityTracker.track_map_event(:map_connection_added, %{
|
|
character_id: character_id,
|
|
user_id: character.user_id,
|
|
map_id: map_id,
|
|
solar_system_source_id: old_location.solar_system_id,
|
|
solar_system_target_id: location.solar_system_id
|
|
})
|
|
|
|
:ok
|
|
|
|
{:error, :already_exists} ->
|
|
# Still broadcast location change in case of followed character
|
|
Impl.broadcast!(map_id, :maybe_select_system, %{
|
|
character_id: character_id,
|
|
solar_system_id: location.solar_system_id
|
|
})
|
|
|
|
:ok
|
|
|
|
{:error, error} ->
|
|
Logger.debug(fn -> "Failed to add connection: #{inspect(error, pretty: true)}" end)
|
|
|
|
:ok
|
|
end
|
|
end
|
|
|
|
def maybe_add_connection(
|
|
_map_id,
|
|
_location,
|
|
_old_location,
|
|
_character_id,
|
|
_is_manual,
|
|
_connection_extra_info
|
|
),
|
|
do: :ok
|
|
|
|
defp get_extra_info(nil, _key, default_value), do: default_value
|
|
|
|
defp get_extra_info(extra_info, key, default_value), do: Map.get(extra_info, key, default_value)
|
|
|
|
def get_start_time(map_id, connection_id) do
|
|
case WandererApp.Cache.get("map_#{map_id}:conn_#{connection_id}:start_time") do
|
|
nil ->
|
|
set_start_time(map_id, connection_id, DateTime.utc_now())
|
|
DateTime.utc_now()
|
|
|
|
value ->
|
|
value
|
|
end
|
|
end
|
|
|
|
def set_start_time(map_id, connection_id, start_time),
|
|
do:
|
|
WandererApp.Cache.put(
|
|
"map_#{map_id}:conn_#{connection_id}:start_time",
|
|
start_time
|
|
)
|
|
|
|
def can_add_location(_scope, nil), do: false
|
|
|
|
def can_add_location(:none, _solar_system_id), do: false
|
|
|
|
def can_add_location(scope, solar_system_id) do
|
|
{:ok, system_static_info} = get_system_static_info(solar_system_id)
|
|
|
|
case scope do
|
|
:wormholes ->
|
|
not is_prohibited_system_class?(system_static_info.system_class) and
|
|
not (@prohibited_systems |> Enum.member?(solar_system_id)) and
|
|
@wh_space |> Enum.member?(system_static_info.system_class)
|
|
|
|
:stargates ->
|
|
not is_prohibited_system_class?(system_static_info.system_class) and
|
|
@known_space |> Enum.member?(system_static_info.system_class)
|
|
|
|
:all ->
|
|
not is_prohibited_system_class?(system_static_info.system_class)
|
|
|
|
_ ->
|
|
false
|
|
end
|
|
end
|
|
|
|
def is_prohibited_system_class?(system_class) do
|
|
@prohibited_system_classes |> Enum.member?(system_class)
|
|
end
|
|
|
|
def is_connection_exist(map_id, from_solar_system_id, to_solar_system_id),
|
|
do:
|
|
not is_nil(
|
|
WandererApp.Map.find_system_by_location(
|
|
map_id,
|
|
%{solar_system_id: from_solar_system_id}
|
|
)
|
|
) &&
|
|
not is_nil(
|
|
WandererApp.Map.find_system_by_location(
|
|
map_id,
|
|
%{solar_system_id: to_solar_system_id}
|
|
)
|
|
)
|
|
|
|
def is_connection_valid(:all, from_solar_system_id, to_solar_system_id),
|
|
do: from_solar_system_id != to_solar_system_id
|
|
|
|
def is_connection_valid(:none, _from_solar_system_id, _to_solar_system_id), do: false
|
|
|
|
def is_connection_valid(scope, from_solar_system_id, to_solar_system_id)
|
|
when not is_nil(from_solar_system_id) and not is_nil(to_solar_system_id) and
|
|
from_solar_system_id != to_solar_system_id do
|
|
with {:ok, known_jumps} <- find_solar_system_jump(from_solar_system_id, to_solar_system_id),
|
|
{:ok, from_system_static_info} <- get_system_static_info(from_solar_system_id),
|
|
{:ok, to_system_static_info} <- get_system_static_info(to_solar_system_id) do
|
|
case scope do
|
|
:wormholes ->
|
|
not is_prohibited_system_class?(from_system_static_info.system_class) and
|
|
not is_prohibited_system_class?(to_system_static_info.system_class) and
|
|
not (@prohibited_systems |> Enum.member?(from_solar_system_id)) and
|
|
not (@prohibited_systems |> Enum.member?(to_solar_system_id)) and
|
|
known_jumps |> Enum.empty?()
|
|
|
|
:stargates ->
|
|
# For stargates, we need to check:
|
|
# 1. Both systems are in known space (HS, LS, NS)
|
|
# 2. There is a known jump between them
|
|
# 3. Neither system is prohibited
|
|
from_system_static_info.system_class in @known_space and
|
|
to_system_static_info.system_class in @known_space and
|
|
not is_prohibited_system_class?(from_system_static_info.system_class) and
|
|
not is_prohibited_system_class?(to_system_static_info.system_class) and
|
|
not (known_jumps |> Enum.empty?())
|
|
end
|
|
else
|
|
_ -> false
|
|
end
|
|
end
|
|
|
|
def is_connection_valid(_scope, _from_solar_system_id, _to_solar_system_id), do: false
|
|
|
|
def get_connection_mark_eol_time(map_id, connection_id, default \\ DateTime.utc_now()) do
|
|
WandererApp.Cache.get("map_#{map_id}:conn_#{connection_id}:mark_eol_time")
|
|
|> case do
|
|
nil ->
|
|
default
|
|
|
|
value ->
|
|
value
|
|
end
|
|
end
|
|
|
|
defp find_solar_system_jump(from_solar_system_id, to_solar_system_id) do
|
|
case WandererApp.CachedInfo.get_solar_system_jump(from_solar_system_id, to_solar_system_id) do
|
|
{:ok, jump} when not is_nil(jump) -> {:ok, [jump]}
|
|
_ -> {:ok, []}
|
|
end
|
|
end
|
|
|
|
defp get_system_static_info(solar_system_id) do
|
|
case WandererApp.CachedInfo.get_system_static_info(solar_system_id) do
|
|
{:ok, system_static_info} when not is_nil(system_static_info) ->
|
|
{:ok, system_static_info}
|
|
|
|
_ ->
|
|
{:ok, %{system_class: nil}}
|
|
end
|
|
end
|
|
|
|
defp maybe_remove_connection(map_id, location, old_location)
|
|
when not is_nil(location) and not is_nil(old_location) and
|
|
location.solar_system_id != old_location.solar_system_id do
|
|
case WandererApp.Map.find_connection(
|
|
map_id,
|
|
location.solar_system_id,
|
|
old_location.solar_system_id
|
|
) do
|
|
{:ok, connection} when not is_nil(connection) ->
|
|
:ok = WandererApp.MapConnectionRepo.destroy(map_id, connection)
|
|
|
|
Impl.broadcast!(map_id, :remove_connections, [connection])
|
|
map_id |> WandererApp.Map.remove_connection(connection)
|
|
|
|
# ADDITIVE: Also broadcast to external event system (webhooks/WebSocket)
|
|
WandererApp.ExternalEvents.broadcast(map_id, :connection_removed, %{
|
|
connection_id: connection.id,
|
|
solar_system_source_id: location.solar_system_id,
|
|
solar_system_target_id: old_location.solar_system_id
|
|
})
|
|
|
|
WandererApp.Cache.delete("map_#{map_id}:conn_#{connection.id}:start_time")
|
|
|
|
_error ->
|
|
:ok
|
|
end
|
|
end
|
|
|
|
defp maybe_remove_connection(_map_id, _location, _old_location), do: :ok
|
|
|
|
defp update_connection(
|
|
map_id,
|
|
update_method,
|
|
attributes,
|
|
%{
|
|
solar_system_source_id: solar_system_source_id,
|
|
solar_system_target_id: solar_system_target_id
|
|
} = update,
|
|
callback_fn \\ nil
|
|
) do
|
|
with {:ok, connection} <-
|
|
WandererApp.Map.find_connection(
|
|
map_id,
|
|
solar_system_source_id,
|
|
solar_system_target_id
|
|
),
|
|
{:ok, update_map} <- Impl.get_update_map(update, attributes),
|
|
{:ok, updated_connection} <-
|
|
apply(WandererApp.MapConnectionRepo, update_method, [
|
|
connection,
|
|
update_map
|
|
]),
|
|
:ok <-
|
|
WandererApp.Map.update_connection(
|
|
map_id,
|
|
connection |> Map.merge(update_map)
|
|
) do
|
|
if not is_nil(callback_fn) do
|
|
callback_fn.(connection, updated_connection)
|
|
end
|
|
|
|
Impl.broadcast!(map_id, :update_connection, updated_connection)
|
|
|
|
# ADDITIVE: Also broadcast to external event system (webhooks/WebSocket)
|
|
WandererApp.ExternalEvents.broadcast(map_id, :connection_updated, %{
|
|
connection_id: updated_connection.id,
|
|
solar_system_source_id: solar_system_source_id,
|
|
solar_system_target_id: solar_system_target_id,
|
|
type: updated_connection.type,
|
|
ship_size_type: updated_connection.ship_size_type,
|
|
mass_status: updated_connection.mass_status,
|
|
time_status: updated_connection.time_status,
|
|
locked: updated_connection.locked,
|
|
custom_info: updated_connection.custom_info
|
|
})
|
|
|
|
:ok
|
|
else
|
|
{:error, error} ->
|
|
Logger.error("Failed to update connection: #{inspect(error, pretty: true)}")
|
|
|
|
:ok
|
|
end
|
|
end
|
|
|
|
defp get_ship_size_type(
|
|
source_solar_system_id,
|
|
target_solar_system_id,
|
|
@connection_type_wormhole
|
|
) do
|
|
# Check if either system is C1 before creating the connection
|
|
{:ok, source_system_info} = get_system_static_info(source_solar_system_id)
|
|
{:ok, target_system_info} = get_system_static_info(target_solar_system_id)
|
|
|
|
cond do
|
|
# C1 systems always get medium
|
|
source_system_info.system_class == @c1 or target_system_info.system_class == @c1 ->
|
|
@medium_ship_size
|
|
|
|
# C13 systems always get frigate
|
|
source_system_info.system_class == @c13 or target_system_info.system_class == @c13 ->
|
|
@frigate_ship_size
|
|
|
|
# C4 to null gets frigate (unless C4 is shattered)
|
|
(source_system_info.system_class == @c4 and target_system_info.system_class == @ns and
|
|
not source_system_info.is_shattered) or
|
|
(target_system_info.system_class == @c4 and
|
|
source_system_info.system_class == @ns and
|
|
not target_system_info.is_shattered) ->
|
|
@frigate_ship_size
|
|
|
|
true ->
|
|
# Default to large for other wormhole connections
|
|
@large_ship_size
|
|
end
|
|
end
|
|
|
|
# Default to large for non-wormhole connections
|
|
defp get_ship_size_type(_source_solar_system_id, _target_solar_system_id, _connection_type),
|
|
do: @large_ship_size
|
|
|
|
defp get_time_status(
|
|
_source_solar_system_id,
|
|
_target_solar_system_id,
|
|
@frigate_ship_size
|
|
),
|
|
do: @connection_time_status_eol_4_5
|
|
|
|
defp get_time_status(
|
|
source_solar_system_id,
|
|
target_solar_system_id,
|
|
_ship_size_type
|
|
) do
|
|
# Check if either system is C1 before creating the connection
|
|
{:ok, source_system_info} = get_system_static_info(source_solar_system_id)
|
|
{:ok, target_system_info} = get_system_static_info(target_solar_system_id)
|
|
|
|
cond do
|
|
# C1/2/3/4 systems always get eol_16
|
|
source_system_info.system_class in [@c1, @c2, @c3, @c4] or
|
|
target_system_info.system_class in [@c1, @c2, @c3, @c4] ->
|
|
@connection_time_status_eol_16
|
|
|
|
# C5/6 systems always get eol_24
|
|
source_system_info.system_class in [@c5, @c6] or
|
|
target_system_info.system_class in [@c5, @c6] ->
|
|
@connection_time_status_eol_24
|
|
|
|
true ->
|
|
@connection_time_status_default
|
|
end
|
|
end
|
|
|
|
defp get_time_status(_source_solar_system_id, _target_solar_system_id, _ship_size_type),
|
|
do: @connection_time_status_default
|
|
|
|
defp get_new_time_status(_start_time, @connection_time_status_default),
|
|
do: @connection_time_status_eol_24
|
|
|
|
defp get_new_time_status(start_time, old_time_status) do
|
|
left_minutes =
|
|
get_time_status_minutes(old_time_status) -
|
|
DateTime.diff(DateTime.utc_now(), start_time, :minute)
|
|
|
|
cond do
|
|
left_minutes <= @connection_eol_minutes ->
|
|
@connection_time_status_eol
|
|
|
|
left_minutes <= @connection_eol_4_minutes ->
|
|
@connection_time_status_eol_4
|
|
|
|
left_minutes <= @connection_eol_4_5_minutes ->
|
|
@connection_time_status_eol_4_5
|
|
|
|
left_minutes <= @connection_eol_16_minutes ->
|
|
@connection_time_status_eol_16
|
|
|
|
left_minutes <= @connection_eol_24_minutes ->
|
|
@connection_time_status_eol_24
|
|
|
|
left_minutes <= @connection_eol_48_minutes ->
|
|
@connection_time_status_eol_48
|
|
|
|
true ->
|
|
@connection_time_status_default
|
|
end
|
|
end
|
|
|
|
defp get_time_status_minutes(@connection_time_status_eol), do: @connection_eol_minutes
|
|
defp get_time_status_minutes(@connection_time_status_eol_4), do: @connection_eol_4_minutes
|
|
defp get_time_status_minutes(@connection_time_status_eol_4_5), do: @connection_eol_4_5_minutes
|
|
defp get_time_status_minutes(@connection_time_status_eol_16), do: @connection_eol_16_minutes
|
|
defp get_time_status_minutes(@connection_time_status_eol_24), do: @connection_eol_24_minutes
|
|
defp get_time_status_minutes(@connection_time_status_eol_48), do: @connection_eol_48_minutes
|
|
defp get_time_status_minutes(_), do: @connection_eol_24_minutes
|
|
end
|