Compare commits

...

1 Commits

Author SHA1 Message Date
Dmitry Popov
d2f7e4a892 feat(Core): Added unsplashed systems support 2025-10-16 22:11:19 +02:00
8 changed files with 147 additions and 40 deletions

View File

@@ -19,7 +19,13 @@ import {
} from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/constants'; } from '@/hooks/Mapper/components/mapInterface/widgets/SystemSignatures/constants';
import { SignatureSettings } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings'; import { SignatureSettings } from '@/hooks/Mapper/components/mapRootContent/components/SignatureSettings';
import { TooltipPosition, WdTooltip, WdTooltipHandlers, WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit'; import { TooltipPosition, WdTooltip, WdTooltipHandlers, WdTooltipWrapper } from '@/hooks/Mapper/components/ui-kit';
import { ExtendedSystemSignature, SignatureGroup, SignatureKind, SystemSignature } from '@/hooks/Mapper/types'; import {
ExtendedSystemSignature,
OutCommand,
SignatureGroup,
SignatureKind,
SystemSignature,
} from '@/hooks/Mapper/types';
import { import {
renderAddedTimeLeft, renderAddedTimeLeft,
@@ -73,6 +79,7 @@ export const SystemSignaturesContent = ({
const [hoveredSignature, setHoveredSignature] = useState<SystemSignature | null>(null); const [hoveredSignature, setHoveredSignature] = useState<SystemSignature | null>(null);
const { const {
outCommand,
storedSettings: { settingsSignatures, settingsSignaturesUpdate }, storedSettings: { settingsSignatures, settingsSignaturesUpdate },
} = useMapRootState(); } = useMapRootState();
@@ -238,6 +245,16 @@ export const SystemSignaturesContent = ({
}); });
}, []); }, []);
const handleUnsplash = useCallback(
async (row: SystemSignature) => {
await outCommand({
type: OutCommand.unsplashSignature,
data: { system_id: systemId, eve_id: row.eve_id },
});
},
[outCommand],
);
return ( return (
<div ref={tableRef} className="h-full"> <div ref={tableRef} className="h-full">
{filteredSignatures.length === 0 ? ( {filteredSignatures.length === 0 ? (
@@ -354,8 +371,11 @@ export const SystemSignaturesContent = ({
{!selectable && ( {!selectable && (
<Column <Column
header="" header=""
body={() => ( body={(row: SystemSignature) => (
<div className="flex justify-end items-center gap-2 mr-[4px]"> <div className="flex justify-end items-center gap-2 mr-[4px]">
<WdTooltipWrapper content="Unsplash signature">
<span className={PrimeIcons.SHARE_ALT + ' text-[10px]'} onClick={() => handleUnsplash(row)} />
</WdTooltipWrapper>
<WdTooltipWrapper content="Double-click a row to edit signature"> <WdTooltipWrapper content="Double-click a row to edit signature">
<span className={PrimeIcons.PENCIL + ' text-[10px]'} /> <span className={PrimeIcons.PENCIL + ' text-[10px]'} />
</WdTooltipWrapper> </WdTooltipWrapper>

View File

@@ -282,6 +282,7 @@ export enum OutCommand {
unlinkSignature = 'unlink_signature', unlinkSignature = 'unlink_signature',
searchSystems = 'search_systems', searchSystems = 'search_systems',
undoDeleteSignatures = 'undo_delete_signatures', undoDeleteSignatures = 'undo_delete_signatures',
unsplashSignature = 'unsplash_signature',
} }
export type OutCommandHandler = <T = unknown>(event: { type: OutCommand; data: unknown }) => Promise<T>; export type OutCommandHandler = <T = unknown>(event: { type: OutCommand; data: unknown }) => Promise<T>;

View File

@@ -1,5 +1,6 @@
defmodule WandererApp.CachedInfo do defmodule WandererApp.CachedInfo do
require Logger require Logger
use(Nebulex.Caching)
def run(_arg) do def run(_arg) do
:ok = cache_trig_systems() :ok = cache_trig_systems()
@@ -39,7 +40,7 @@ defmodule WandererApp.CachedInfo do
def get_system_static_info(solar_system_id) do def get_system_static_info(solar_system_id) do
case Cachex.get(:system_static_info_cache, solar_system_id) do case Cachex.get(:system_static_info_cache, solar_system_id) do
{:ok, nil} -> {:ok, nil} ->
case WandererApp.Api.MapSolarSystem.read() do case get_solar_systems() do
{:ok, systems} -> {:ok, systems} ->
systems systems
|> Enum.each(fn system -> |> Enum.each(fn system ->
@@ -70,8 +71,24 @@ defmodule WandererApp.CachedInfo do
end) end)
case Cachex.get(:system_static_info_cache, solar_system_id) do case Cachex.get(:system_static_info_cache, solar_system_id) do
{:ok, nil} -> {:error, :not_found} {:ok, nil} ->
result -> result system_static_info = %{
solar_system_id: solar_system_id,
solar_system_name: "Unsplashed",
region_name: "Unknown",
system_class: 5
}
Cachex.put(
:system_static_info_cache,
solar_system_id,
system_static_info
)
{:ok, system_static_info}
result ->
result
end end
{:error, reason} -> {:error, reason} ->
@@ -99,6 +116,24 @@ defmodule WandererApp.CachedInfo do
end end
end end
def get_random_solar_system_id() do
result = -:rand.uniform(1_000_000_000)
case Cachex.exists?(:system_static_info_cache, result) do
{:ok, true} ->
get_random_solar_system_id()
_ ->
result
end
end
@decorate cacheable(
cache: WandererApp.Cache,
key: "solar_systems"
)
def get_solar_systems(), do: WandererApp.Api.MapSolarSystem.read()
def get_wormhole_types() do def get_wormhole_types() do
case WandererApp.Cache.lookup(:wormhole_types) do case WandererApp.Cache.lookup(:wormhole_types) do
{:ok, nil} -> {:ok, nil} ->

View File

@@ -312,7 +312,10 @@ defmodule WandererApp.Kills.Client do
@impl true @impl true
def handle_cast({:subscribe_systems, system_ids}, state) do def handle_cast({:subscribe_systems, system_ids}, state) do
{updated_systems, to_subscribe} = {updated_systems, to_subscribe} =
Manager.subscribe_systems(state.subscribed_systems, system_ids) Manager.subscribe_systems(
state.subscribed_systems,
system_ids |> Enum.filter(fn id -> id > 0 end)
)
# Log subscription details # Log subscription details
if length(to_subscribe) > 0 do if length(to_subscribe) > 0 do
@@ -635,7 +638,7 @@ defmodule WandererApp.Kills.Client do
@impl true @impl true
def handle_connected(transport, state) do def handle_connected(transport, state) do
join_params = %{ join_params = %{
systems: state.subscribed_systems, systems: state.subscribed_systems |> Enum.filter(fn id -> id > 0 end),
client_identifier: "wanderer_app" client_identifier: "wanderer_app"
} }
@@ -710,7 +713,9 @@ defmodule WandererApp.Kills.Client do
@impl true @impl true
def handle_info({:subscribe_systems, system_ids}, transport, state) do def handle_info({:subscribe_systems, system_ids}, transport, state) do
case push_to_channel(transport, "subscribe_systems", %{"systems" => system_ids}) do case push_to_channel(transport, "subscribe_systems", %{
"systems" => system_ids |> Enum.filter(fn id -> id > 0 end)
}) do
:ok -> :ok ->
Logger.debug(fn -> "[Handler] Successfully pushed subscribe_systems event" end) Logger.debug(fn -> "[Handler] Successfully pushed subscribe_systems event" end)
@@ -723,7 +728,9 @@ defmodule WandererApp.Kills.Client do
@impl true @impl true
def handle_info({:unsubscribe_systems, system_ids}, transport, state) do def handle_info({:unsubscribe_systems, system_ids}, transport, state) do
case push_to_channel(transport, "unsubscribe_systems", %{"systems" => system_ids}) do case push_to_channel(transport, "unsubscribe_systems", %{
"systems" => system_ids |> Enum.filter(fn id -> id > 0 end)
}) do
:ok -> :ok ->
Logger.debug(fn -> "[Handler] Successfully pushed unsubscribe_systems event" end) Logger.debug(fn -> "[Handler] Successfully pushed unsubscribe_systems event" end)
@@ -796,7 +803,10 @@ defmodule WandererApp.Kills.Client do
@spec validate_system_ids(list()) :: {:ok, [integer()]} | {:error, :invalid_system_ids} @spec validate_system_ids(list()) :: {:ok, [integer()]} | {:error, :invalid_system_ids}
defp validate_system_ids(system_ids) when is_list(system_ids) do defp validate_system_ids(system_ids) when is_list(system_ids) do
results = Enum.map(system_ids, &validate_system_id/1) results =
system_ids
|> Enum.filter(fn id -> id > 0 end)
|> Enum.map(&validate_system_id/1)
case Enum.all?(results, &match?({:ok, _}, &1)) do case Enum.all?(results, &match?({:ok, _}, &1)) do
true -> true ->

View File

@@ -557,7 +557,11 @@ defmodule WandererApp.Map.Server.SystemsImpl do
_ -> _ ->
%{x: x, y: y} = %{x: x, y: y} =
WandererApp.Map.PositionCalculator.get_new_system_position(nil, rtree_name, map_opts) WandererApp.Map.PositionCalculator.get_new_system_position(
extra_info,
rtree_name,
map_opts
)
%{"x" => x, "y" => y} %{"x" => x, "y" => y}
end end

View File

@@ -18,37 +18,43 @@ defmodule WandererApp.Maps do
] ]
def find_routes(map_id, hubs, origin, routes_settings, false) do def find_routes(map_id, hubs, origin, routes_settings, false) do
WandererApp.Esi.find_routes( origin_int = origin |> String.to_integer()
map_id,
origin,
hubs,
routes_settings
)
|> case do
{:ok, routes} ->
systems_static_data =
routes
|> Enum.map(fn route_info -> route_info.systems end)
|> List.flatten()
|> Enum.uniq()
|> Task.async_stream(
fn system_id ->
case WandererApp.CachedInfo.get_system_static_info(system_id) do
{:ok, nil} ->
nil
{:ok, system} -> if origin_int > 0 do
system |> Map.take(@minimum_route_attrs) WandererApp.Esi.find_routes(
end map_id,
end, origin,
max_concurrency: System.schedulers_online() * 4 hubs,
) routes_settings
|> Enum.map(fn {:ok, val} -> val end) )
|> case do
{:ok, routes} ->
systems_static_data =
routes
|> Enum.map(fn route_info -> route_info.systems end)
|> List.flatten()
|> Enum.uniq()
|> Task.async_stream(
fn system_id ->
case WandererApp.CachedInfo.get_system_static_info(system_id) do
{:ok, nil} ->
nil
{:ok, %{routes: routes, systems_static_data: systems_static_data}} {:ok, system} ->
system |> Map.take(@minimum_route_attrs)
end
end,
max_concurrency: System.schedulers_online() * 4
)
|> Enum.map(fn {:ok, val} -> val end)
error -> {:ok, %{routes: routes, systems_static_data: systems_static_data}}
{:ok, %{routes: [], systems_static_data: []}}
error ->
{:ok, %{routes: [], systems_static_data: []}}
end
else
{:ok, %{routes: [], systems_static_data: []}}
end end
end end

View File

@@ -400,6 +400,36 @@ defmodule WandererAppWeb.MapSignaturesEventHandler do
)} )}
end end
def handle_ui_event(
"unsplash_signature",
%{"system_id" => solar_system_id, "eve_id" => eve_id} = payload,
%{
assigns: %{
map_id: map_id,
current_user: current_user,
main_character_id: main_character_id,
user_permissions: %{update_system: true}
}
} = socket
)
when not is_nil(main_character_id) do
{:ok, system} =
WandererApp.MapSystemRepo.get_by_map_and_solar_system_id(map_id, solar_system_id)
WandererApp.Map.Server.add_system(
map_id,
%{
solar_system_id: WandererApp.CachedInfo.get_random_solar_system_id(),
coordinates: nil,
extra_info: %{position_x: system.position_x, position_y: system.position_y}
},
current_user.id,
main_character_id
)
{:noreply, socket}
end
def handle_ui_event(event, body, socket), def handle_ui_event(event, body, socket),
do: MapCoreEventHandler.handle_ui_event(event, body, socket) do: MapCoreEventHandler.handle_ui_event(event, body, socket)

View File

@@ -127,7 +127,8 @@ defmodule WandererAppWeb.MapEventHandler do
"get_signatures", "get_signatures",
"link_signature_to_system", "link_signature_to_system",
"unlink_signature", "unlink_signature",
"undo_delete_signatures" "undo_delete_signatures",
"unsplash_signature"
] ]
@map_structures_events [ @map_structures_events [