Compare commits

..

28 Commits

Author SHA1 Message Date
CI
68b58aa520 chore: release version v1.11.5 2024-10-16 12:46:16 +00:00
Dmitry Popov
dbadd09af3 Merge branch 'main' of github.com:wanderer-industries/wanderer 2024-10-16 16:45:48 +04:00
Dmitry Popov
fcbe2c754f chore: release version v1.11.1 2024-10-16 16:45:44 +04:00
CI
ad4580677b chore: release version v1.11.4 2024-10-16 11:48:48 +00:00
Dmitry Popov
01a6cc7d92 Merge branch 'main' of github.com:wanderer-industries/wanderer 2024-10-16 15:48:20 +04:00
Dmitry Popov
95ce95a187 chore: release version v1.11.1 2024-10-16 15:48:16 +04:00
CI
ce8e6fbfb0 chore: release version v1.11.3 2024-10-16 05:51:27 +00:00
Dmitry Popov
a20eaed76b Merge branch 'main' of github.com:wanderer-industries/wanderer 2024-10-16 09:50:49 +04:00
Dmitry Popov
419af72028 chore: release version v1.11.1 2024-10-16 09:50:45 +04:00
CI
8e499522f6 chore: release version v1.11.2 2024-10-15 22:13:53 +00:00
Dmitry Popov
84321b847e chore: release version v1.11.1 2024-10-16 02:13:18 +04:00
CI
c969a4d465 chore: release version v1.11.1 2024-10-14 14:31:41 +00:00
Dmitry Popov
0e12c850b6 chore: release version v1.11.0 2024-10-14 18:31:12 +04:00
CI
442835dd9b chore: release version v1.11.0 2024-10-14 14:24:17 +00:00
Dmitry Popov
b4ff99cb2e Merge branch 'main' of github.com:wanderer-industries/wanderer 2024-10-14 18:23:43 +04:00
Dmitry Popov
aa0ecbc998 feat(Map): Add map level option to store custom labels 2024-10-14 18:23:39 +04:00
CI
cc412e93c0 chore: release version v1.10.0 2024-10-13 10:18:23 +00:00
Dmitry Popov
1d36fadbfa Merge branch 'main' of github.com:wanderer-industries/wanderer 2024-10-13 14:17:43 +04:00
Dmitry Popov
56182bd87d feat(Map): Link signature on splash 2024-10-13 14:17:40 +04:00
CI
d290ff92b3 chore: release version v1.9.0 2024-10-13 10:10:38 +00:00
Dmitry Popov
298c5fd3b8 Merge branch 'main' of github.com:wanderer-industries/wanderer 2024-10-13 14:09:56 +04:00
Dmitry Popov
e365c43781 feat(Map): Link signature on splash 2024-10-13 14:09:53 +04:00
CI
23a9f22ef4 chore: release version v1.8.0 2024-10-13 10:04:22 +00:00
Dmitry Popov
242f437237 Merge branch 'main' of github.com:wanderer-industries/wanderer 2024-10-13 14:03:53 +04:00
Dmitry Popov
2eae8cffdb feat(Map): Link signature on splash 2024-10-13 14:03:48 +04:00
CI
68ab3d4f72 chore: release version v1.7.0 2024-10-13 09:40:06 +00:00
Dmitry Popov
1ea805aff0 Merge branch 'main' of github.com:wanderer-industries/wanderer 2024-10-13 13:39:39 +04:00
Dmitry Popov
6ce45349dc feat(Map): Link signature on splash 2024-10-13 13:39:35 +04:00
24 changed files with 534 additions and 495 deletions

View File

@@ -2,7 +2,41 @@
<!-- changelog -->
## [v1.6.0](https://github.com/wanderer-industries/wanderer/compare/v1.5.0...v1.6.0) (2024-10-13)
## [v1.11.5](https://github.com/wanderer-industries/wanderer/compare/v1.11.4...v1.11.5) (2024-10-16)
## [v1.11.4](https://github.com/wanderer-industries/wanderer/compare/v1.11.3...v1.11.4) (2024-10-16)
## [v1.11.3](https://github.com/wanderer-industries/wanderer/compare/v1.11.2...v1.11.3) (2024-10-16)
## [v1.11.2](https://github.com/wanderer-industries/wanderer/compare/v1.11.1...v1.11.2) (2024-10-15)
## [v1.11.1](https://github.com/wanderer-industries/wanderer/compare/v1.11.0...v1.11.1) (2024-10-14)
## [v1.11.0](https://github.com/wanderer-industries/wanderer/compare/v1.10.0...v1.11.0) (2024-10-14)
### Features:
* Map: Add map level option to store custom labels
## [v1.10.0](https://github.com/wanderer-industries/wanderer/compare/v1.9.0...v1.10.0) (2024-10-13)
@@ -16,15 +50,6 @@
### Features:
* Map: Follow Character on Map and auto select their current system
## [v1.4.0](https://github.com/wanderer-industries/wanderer/compare/v1.3.6...v1.4.0) (2024-10-11)
### Features:
* Map: Follow Character on Map and auto select their current system
@@ -38,35 +63,6 @@
* Signatures: Signatures update fixes
## [v1.3.5](https://github.com/wanderer-industries/wanderer/compare/v1.3.4...v1.3.5) (2024-10-09)
### Bug Fixes:
* Signatures: Signatures update fixes
## [v1.3.4](https://github.com/wanderer-industries/wanderer/compare/v1.3.3...v1.3.4) (2024-10-09)
## [v1.3.3](https://github.com/wanderer-industries/wanderer/compare/v1.3.2...v1.3.3) (2024-10-08)
## [v1.3.2](https://github.com/wanderer-industries/wanderer/compare/v1.3.1...v1.3.2) (2024-10-07)
## [v1.3.1](https://github.com/wanderer-industries/wanderer/compare/v1.3.0...v1.3.1) (2024-10-07)
## [v1.3.0](https://github.com/wanderer-industries/wanderer/compare/v1.2.10...v1.3.0) (2024-10-07)
@@ -80,26 +76,6 @@
* Map: Revision of sorting from also adding ability to sort all columns
## [v1.2.10](https://github.com/wanderer-industries/wanderer/compare/v1.2.9...v1.2.10) (2024-10-07)
## [v1.2.9](https://github.com/wanderer-industries/wanderer/compare/v1.2.8...v1.2.9) (2024-10-07)
## [v1.2.8](https://github.com/wanderer-industries/wanderer/compare/v1.2.7...v1.2.8) (2024-10-06)
## [v1.2.7](https://github.com/wanderer-industries/wanderer/compare/v1.2.6...v1.2.7) (2024-10-05)
## [v1.2.6](https://github.com/wanderer-industries/wanderer/compare/v1.2.5...v1.2.6) (2024-10-05)
@@ -136,11 +112,6 @@
* Map: Fix map loading after select a different map.
## [v1.2.2](https://github.com/wanderer-industries/wanderer/compare/v1.2.1...v1.2.2) (2024-10-02)
## [v1.2.1](https://github.com/wanderer-industries/wanderer/compare/v1.2.0...v1.2.1) (2024-10-02)
@@ -257,20 +228,10 @@
* docker: Fix DB connection in docker-compose internal network
## [v1.0.7](https://github.com/wanderer-industries/wanderer/compare/v1.0.6...v1.0.7) (2024-09-19)
## [v1.0.6](https://github.com/wanderer-industries/wanderer/compare/v1.0.5...v1.0.6) (2024-09-18)
## [v1.0.5](https://github.com/wanderer-industries/wanderer/compare/v1.0.4...v1.0.5) (2024-09-18)
## [v1.0.4](https://github.com/wanderer-industries/wanderer/compare/v1.0.3...v1.0.4) (2024-09-18)
### Bug Fixes
* core: skip search results for failed character info request
## [v1.0.3](https://github.com/wanderer-industries/wanderer/compare/v1.0.2...v1.0.3) (2024-09-18)
## [v1.0.2](https://github.com/wanderer-industries/wanderer/compare/v1.0.1...v1.0.2) (2024-09-18)
## [v1.0.1](https://github.com/wanderer-industries/wanderer/compare/v1.0.0...v1.0.1) (2024-09-18)

View File

@@ -46,7 +46,7 @@ export const useLabelsMenu = (
}
// const labels = getLabels(system.labels);
const hasLabels = labels.list.length > 0;
const hasLabels = labels?.list?.length > 0;
const statusList = hasLabels ? LABELS_ORDER : LABELS_ORDER.slice(1);
return [

View File

@@ -29,7 +29,7 @@ const SpaceToClass: Record<string, string> = {
};
const sortedLabels = (labels: string[]) => {
if (labels === null) {
if (!labels) {
return [];
}

View File

@@ -1,18 +1,18 @@
import { useReactFlow } from 'reactflow';
import { useCallback } from 'react';
import { useCallback, useRef } from 'react';
import { CommandCenterSystem } from '@/hooks/Mapper/types';
export const useCenterSystem = () => {
const rf = useReactFlow();
const ref = useRef({ rf });
ref.current = { rf };
return useCallback((systemId: CommandCenterSystem) => {
if (!rf) {
return;
}
const systemNode = rf.getNodes().find(x => x.data.id === systemId);
const systemNode = ref.current.rf.getNodes().find(x => x.data.id === systemId);
if (!systemNode) {
return;
}
rf.setCenter(systemNode.position.x, systemNode.position.y, { duration: 1000 });
ref.current.rf.setCenter(systemNode.position.x, systemNode.position.y, { duration: 1000 });
}, []);
};

View File

@@ -1,15 +1,15 @@
import { useReactFlow } from 'reactflow';
import { useCallback } from 'react';
import { useCallback, useRef } from 'react';
import { CommandSelectSystem } from '@/hooks/Mapper/types';
export const useSelectSystem = () => {
const rf = useReactFlow();
const ref = useRef({ rf });
ref.current = { rf };
return useCallback((systemId: CommandSelectSystem) => {
if (!rf) {
return;
}
rf.setNodes(nds =>
ref.current.rf.setNodes(nds =>
nds.map(node => {
return {
...node,

View File

@@ -7,7 +7,7 @@ import { Button } from 'primereact/button';
import { OutCommand } from '@/hooks/Mapper/types';
import { IconField } from 'primereact/iconfield';
import { LabelsManager } from '@/hooks/Mapper/utils/labelsManager.ts';
import { WdImageSize, WdImgButton } from '@/hooks/Mapper/components/ui-kit';
import { WdImageSize, WdImgButton, TooltipPosition } from '@/hooks/Mapper/components/ui-kit';
interface SystemCustomLabelDialog {
systemId: string;
@@ -79,14 +79,14 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
// @ts-ignore
const handleInput = useCallback(e => {
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9[\](){}]/g, '');
}, []);
return (
<Dialog
header="Edit label"
visible={visible}
draggable={false}
draggable={true}
style={{ width: '250px' }}
onHide={onHide}
onShow={onShow}
@@ -100,9 +100,13 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
<IconField>
{label !== '' && (
<WdImgButton
className="pi pi-trash p-input-icon"
className="pi pi-trash text-red-400"
textSize={WdImageSize.large}
tooltip={{ content: 'Reset label' }}
tooltip={{
content: 'Remove custom label',
className: 'pi p-input-icon',
position: TooltipPosition.top,
}}
onClick={handleReset}
/>
)}
@@ -111,7 +115,7 @@ export const SystemCustomLabelDialog = ({ systemId, visible, setVisible }: Syste
aria-describedby="username-help"
autoComplete="off"
value={label}
maxLength={3}
maxLength={5}
onChange={e => setLabel(e.target.value)}
// @ts-expect-error
ref={inputRef}

View File

@@ -21,8 +21,6 @@ const signatureSettings: Setting[] = [{ key: COSMIC_SIGNATURE, name: 'Show Cosmi
export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignatureDialogProps) => {
const { outCommand } = useMapRootState();
console.log(data);
const ref = useRef({ outCommand });
ref.current = { outCommand };
@@ -31,8 +29,8 @@ export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignat
}, [setVisible]);
const handleSelect = useCallback(
(signatures: SystemSignature[]) => {
if (!signatures.length) {
(signature: SystemSignature) => {
if (!signature) {
return;
}
@@ -42,12 +40,12 @@ export const SystemLinkSignatureDialog = ({ data, setVisible }: SystemLinkSignat
type: OutCommand.linkSignatureToSystem,
data: {
...data,
signature_eve_id: signatures[0].eve_id,
signature_eve_id: signature.eve_id,
},
});
setVisible(false);
},
[setVisible],
[data, setVisible],
);
return (

View File

@@ -90,7 +90,7 @@ export const SystemSettingsDialog = ({ systemId, visible, setVisible }: SystemSe
}, []);
const handleInput = useCallback((e: any) => {
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, '');
e.target.value = e.target.value.toUpperCase().replace(/[^A-Z0-9[\](){}]/g, '');
}, []);
return (
@@ -160,7 +160,7 @@ export const SystemSettingsDialog = ({ systemId, visible, setVisible }: SystemSe
aria-describedby="label"
autoComplete="off"
value={label}
maxLength={3}
maxLength={5}
onChange={e => setLabel(e.target.value)}
onInput={handleInput}
/>

View File

@@ -43,7 +43,7 @@ interface SystemSignaturesContentProps {
systemId: string;
settings: Setting[];
selectable?: boolean;
onSelect?: (signatures: SystemSignature[]) => void;
onSelect?: (signature: SystemSignature) => void;
}
export const SystemSignaturesContent = ({ systemId, settings, selectable, onSelect }: SystemSignaturesContentProps) => {
const { outCommand } = useMapRootState();
@@ -163,10 +163,16 @@ export const SystemSignaturesContent = ({ systemId, settings, selectable, onSele
setAskUser(false);
}, [parsedSignatures, handleUpdateSignatures]);
const handleSelectSignatures = useCallback(e => {
setSelectedSignatures(e.value);
onSelect?.(e.value);
}, []);
const handleSelectSignatures = useCallback(
e => {
if (selectable) {
onSelect?.(e.value);
} else {
setSelectedSignatures(e.value);
}
},
[onSelect, selectable],
);
useHotkey(true, ['a'], handleSelectAll);
@@ -255,7 +261,7 @@ export const SystemSignaturesContent = ({ systemId, settings, selectable, onSele
className={classes.Table}
value={filteredSignatures}
size="small"
// selectionMode={selectable ? 'multiple' : 'single'}
selectionMode={selectable ? 'single' : 'multiple'}
selection={selectedSignatures}
metaKeySelection
onSelectionChange={handleSelectSignatures}
@@ -312,17 +318,15 @@ export const SystemSignaturesContent = ({ systemId, settings, selectable, onSele
hidden={compact || medium}
sortable
></Column>
{!selectable && (
<Column
field="linked_system"
header="Linked System"
bodyClassName="text-ellipsis overflow-hidden whitespace-nowrap"
body={renderLinkedSystem}
style={{ maxWidth: nameColumnWidth }}
hidden={compact}
sortable
></Column>
)}
<Column
field="linked_system"
header="Linked System"
bodyClassName="text-ellipsis overflow-hidden whitespace-nowrap"
body={renderLinkedSystem}
style={{ maxWidth: nameColumnWidth }}
hidden={compact}
sortable
></Column>
<Column
field="updated_at"

View File

@@ -66,7 +66,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
type="button"
onClick={handleAddCharacter}
>
<i className="pi pi-user-plus text-lg"></i>
<i className="pi pi-user-plus"></i>
</button>
</WdTooltipWrapper>
@@ -76,7 +76,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
type="button"
onClick={handleOpenUserSettings}
>
<i className="pi pi-cog text-lg"></i>
<i className="pi pi-cog"></i>
</button>
</WdTooltipWrapper>
@@ -86,7 +86,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
type="button"
onClick={onShowOnTheMap}
>
<i className="pi pi-hashtag text-lg"></i>
<i className="pi pi-hashtag"></i>
</button>
</WdTooltipWrapper>
</div>
@@ -103,11 +103,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
type="button"
onClick={toggleKSpace}
>
{interfaceSettings.isShowKSpace ? (
<i className="pi pi-heart-fill text-lg"></i>
) : (
<i className="pi pi-heart text-lg"></i>
)}
<i className={interfaceSettings.isShowKSpace ? 'hero-cloud-solid' : 'hero-cloud'}></i>
</button>
</WdTooltipWrapper>
@@ -117,7 +113,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
type="button"
onClick={toggleMinimap}
>
{isShowMinimap ? <i className="pi pi-eye text-lg"></i> : <i className="pi pi-eye-slash text-lg"></i>}
<i className={isShowMinimap ? 'pi pi-eye' : 'pi pi-eye-slash'}></i>
</button>
</WdTooltipWrapper>
@@ -127,7 +123,7 @@ export const RightBar = ({ onShowOnTheMap }: RightBarProps) => {
type="button"
onClick={toggleMenu}
>
<i className="pi pi-window-minimize text-lg"></i>
<i className="pi pi-window-minimize"></i>
</button>
</WdTooltipWrapper>
</div>

View File

@@ -80,7 +80,6 @@ export type CommandCenterSystem = string | undefined;
export type CommandLinkSignatureToSystem = {
solar_system_source: number;
solar_system_target: number;
signatures: any[];
};
export interface CommandData {

View File

@@ -65,7 +65,7 @@ export class LabelsManager {
}
hasLabel(label: string) {
return this.parsedLabels.labels.includes(label);
return this.parsedLabels.labels?.includes(label);
}
toggleLabel(label: string) {

View File

@@ -77,7 +77,7 @@ config :wanderer_app,
web_app_url: web_app_url,
git_sha: System.get_env("GIT_SHA", "111"),
custom_route_base_url: System.get_env("CUSTOM_ROUTE_BASE_URL"),
invites: System.get_env("WANDERER_INVITES", "false") == "true",
invites: System.get_env("WANDERER_INVITES", "false") |> String.to_existing_atom(),
admin_username: System.get_env("WANDERER_ADMIN_USERNAME", "admin"),
admin_password: System.get_env("WANDERER_ADMIN_PASSWORD"),
admins: admins,

View File

@@ -52,15 +52,6 @@ defmodule WandererApp.Map do
end
end
def get_map_options!(map) do
map
|> Map.get(:options)
|> case do
nil -> %{"layout" => "left_to_right"}
options -> Jason.decode!(options)
end
end
def update_map(map_id, map_update) do
Cachex.get_and_update(:map_cache, map_id, fn map ->
case map do

View File

@@ -333,7 +333,7 @@ defmodule WandererApp.Map.Server.Impl do
end
def delete_systems(
%{map_id: map_id, rtree_name: rtree_name} = state,
%{map_id: map_id, rtree_name: rtree_name, map_opts: map_opts} = state,
removed_ids,
user_id,
character_id
@@ -352,7 +352,7 @@ defmodule WandererApp.Map.Server.Impl do
removed_ids
|> Enum.each(fn solar_system_id ->
map_id
|> WandererApp.MapSystemRepo.remove_from_map(solar_system_id)
|> WandererApp.MapSystemRepo.remove_from_map(solar_system_id, map_opts)
|> case do
{:ok, _} ->
:ok
@@ -801,7 +801,13 @@ defmodule WandererApp.Map.Server.Impl do
end
def handle_event({:options_updated, options}, %{map: map, map_id: map_id} = state),
do: %{state | map_opts: [layout: options.layout]}
do: %{
state
| map_opts: [
layout: options |> Map.get("layout"),
store_custom_labels: options |> Map.get("store_custom_labels")
]
}
def handle_event({ref, _result}, %{map_id: _map_id} = state) do
Process.demonitor(ref, [:flush])
@@ -1278,9 +1284,14 @@ defmodule WandererApp.Map.Server.Impl do
|> WandererApp.Map.add_connections!(connections)
|> WandererApp.Map.add_characters!(characters)
map_options = WandererApp.Map.get_map_options!(initial_map)
{:ok, map_options} = WandererApp.MapRepo.options_to_form_data(initial_map)
%{state | map: map, map_opts: [layout: map_options |> Map.get("layout")]}
map_opts = [
layout: map_options |> Map.get("layout"),
store_custom_labels: map_options |> Map.get("store_custom_labels")
]
%{state | map: map, map_opts: map_opts}
end
defp _init_map_systems(state, [] = _systems), do: state
@@ -1630,10 +1641,11 @@ defmodule WandererApp.Map.Server.Impl do
WandererApp.Map.add_connection(map_id, connection)
broadcast!(map_id, :add_connection, connection)
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,
solar_system_target: location.solar_system_id
})
:ok

View File

@@ -1,6 +1,8 @@
defmodule WandererApp.MapRepo do
use WandererApp, :repository
@default_map_options %{"layout" => "left_to_right", "store_custom_labels" => false}
def get(map_id, relationships \\ []) do
map_id
|> WandererApp.Api.Map.by_id()
@@ -13,10 +15,23 @@ defmodule WandererApp.MapRepo do
end
end
def get_by_slug_with_permissions(map_slug, current_user),
do:
map_slug
|> WandererApp.Api.Map.get_map_by_slug()
|> load_user_permissions(current_user)
def load_relationships(map, []), do: {:ok, map}
def load_relationships(map, relationships), do: map |> Ash.load(relationships)
defp load_user_permissions({:ok, map}, current_user),
do:
map
|> Ash.load([:acls, :user_permissions], actor: current_user)
defp load_user_permissions(error, _current_user), do: error
def update_hubs(map_id, hubs) do
map_id
|> WandererApp.Api.Map.by_id()
@@ -28,4 +43,19 @@ defmodule WandererApp.MapRepo do
{:error, :map_not_found}
end
end
def update_options(map, options),
do:
map
|> WandererApp.Api.Map.update_options(%{options: Jason.encode!(options)})
def options_to_form_data(%{options: options} = _map_options) when not is_nil(options),
do: {:ok, Jason.decode!(options)}
def options_to_form_data(_), do: {:ok, @default_map_options}
def options_to_form_data!(options) do
{:ok, data} = options_to_form_data(options)
data
end
end

View File

@@ -22,14 +22,12 @@ defmodule WandererApp.MapSystemRepo do
def get_visible_by_map(map_id),
do: WandererApp.Api.MapSystem.read_visible_by_map(%{map_id: map_id})
def remove_from_map(map_id, solar_system_id) do
def remove_from_map(map_id, solar_system_id, opts) do
WandererApp.Api.MapSystem.read_by_map_and_solar_system!(%{
map_id: map_id,
solar_system_id: solar_system_id
})
|> WandererApp.Api.MapSystem.update_labels!(%{
labels: nil
})
|> cleanup_labels(opts)
|> WandererApp.Api.MapSystem.update_tag!(%{
tag: nil
})
@@ -39,6 +37,33 @@ defmodule WandererApp.MapSystemRepo do
{:error, error}
end
def cleanup_labels(%{labels: labels} = system, opts) do
store_custom_labels? =
Keyword.get(opts, :store_custom_labels, "false") |> String.to_existing_atom()
labels = get_filtered_labels(labels, store_custom_labels?)
system
|> WandererApp.Api.MapSystem.update_labels!(%{
labels: labels
})
end
def get_filtered_labels(labels, true) when is_binary(labels) do
labels
|> Jason.decode!()
|> case do
%{"customLabel" => customLabel} = labels when is_binary(customLabel) ->
%{"customLabel" => customLabel, "labels" => []}
|> Jason.encode!()
_ ->
nil
end
end
def get_filtered_labels(_, _store_custom_labels), do: nil
def update_name(system, update),
do:
system

View File

@@ -62,6 +62,7 @@ defmodule WandererAppWeb do
use Phoenix.LiveView, @opts
unquote(html_helpers())
defguard is_connected?(socket) when socket.transport_pid != nil
end
end

View File

@@ -12,7 +12,7 @@ defmodule WandererAppWeb.AdminLive do
{:ok, socket.assigns.current_user.characters}
)
admin_character =
corp_wallet_character =
socket.assigns.current_user.characters
|> Enum.find(fn character ->
WandererApp.Character.can_track_corp_wallet?(character)
@@ -31,39 +31,35 @@ defmodule WandererAppWeb.AdminLive do
end)
socket =
if not is_nil(admin_character) do
if not is_nil(corp_wallet_character) do
{:ok, total_balance} =
WandererApp.Character.TransactionsTracker.get_total_balance(admin_character.id)
WandererApp.Character.TransactionsTracker.get_total_balance(corp_wallet_character.id)
{:ok, transactions} =
WandererApp.Character.TransactionsTracker.get_transactions(admin_character.id)
{:ok, active_map_subscriptions} =
WandererApp.Api.MapSubscription.all_active()
WandererApp.Character.TransactionsTracker.get_transactions(corp_wallet_character.id)
socket
|> assign(
show_invites?: WandererApp.Env.invites(),
admin_character_id: admin_character.id,
total_balance: total_balance,
transactions: transactions,
user_character_ids: user_character_ids,
active_map_subscriptions: active_map_subscriptions
transactions: transactions
)
else
socket
|> assign(
admin_character_id: nil,
show_invites?: false,
total_balance: 0,
transactions: [],
active_map_subscriptions: []
transactions: []
)
end
{:ok, active_map_subscriptions} =
WandererApp.Api.MapSubscription.all_active()
{:ok,
socket
|> assign(
active_map_subscriptions: active_map_subscriptions,
show_invites?: WandererApp.Env.invites(),
user_character_ids: user_character_ids,
user_id: user_id,
invite_link: nil,
map_subscriptions_enabled?: WandererApp.Env.map_subscriptions_enabled?()
@@ -72,7 +68,7 @@ defmodule WandererAppWeb.AdminLive do
@impl true
def mount(_params, _session, socket) do
{:ok, socket |> assign(user_id: nil, admin_character_id: nil)}
{:ok, socket |> assign(user_id: nil)}
end
@impl true

View File

@@ -4,57 +4,14 @@ defmodule WandererAppWeb.MapLive do
require Logger
@impl true
def mount(params, _session, socket) do
def mount(params, _session, socket) when is_connected?(socket) do
socket =
with %{"slug" => map_slug} <- params do
socket
|> _init_state(map_slug)
else
_ ->
# redirect back to main
socket
|> assign(
map_loaded?: false,
maps_loading: false,
selected_subscription: nil,
maps: [],
map: nil,
map_id: nil,
map_slug: nil,
user_permissions: nil,
form: to_form(%{"map_slug" => nil})
)
end
{:ok, socket |> assign(server_online: false)}
end
defp _init_state(socket, map_slug) do
current_user = socket.assigns.current_user
ErrorTracker.set_context(%{user_id: current_user.id})
Task.async(fn -> _get_available_maps(current_user) end)
map_slug
|> WandererApp.Api.Map.get_map_by_slug()
|> _load_user_permissions(current_user)
|> case do
{:ok,
%{
id: map_id,
deleted: false
} = map} ->
Process.send_after(self(), {:init_map, map}, 10)
Process.send_after(self(), {:load_map, map_slug}, Enum.random(10..200))
socket
|> assign(
map: map,
map_id: map_id,
map_loaded?: false,
maps_loading: true,
maps: [],
user_permissions: nil,
selected_subscription: nil,
map_slug: map_slug,
form: to_form(%{"map_slug" => map_slug})
)
@@ -63,26 +20,42 @@ defmodule WandererAppWeb.MapLive do
attr: "data-loading",
timeout: 2000
})
else
_ ->
# redirect back to main
socket
|> assign(
maps_loading: false,
map_id: nil,
map_slug: nil,
form: to_form(%{"map_slug" => nil})
)
end
{:ok,
%{
deleted: true
} = _map} ->
socket
|> put_flash(
:error,
"Map was deleted by owner or administrator."
)
|> push_navigate(to: ~p"/maps")
{:ok,
socket
|> assign(
map_loaded?: false,
maps: [],
server_online: false,
selected_subscription: nil,
user_permissions: nil
)}
end
{:error, _} ->
socket
|> put_flash(
:error,
"Something went wrong. Please try one more time or submit an issue."
)
|> push_navigate(to: ~p"/maps")
end
@impl true
def mount(_params, _session, socket) do
{:ok,
socket
|> assign(
maps_loading: false,
map_loaded?: false,
maps: [],
server_online: false,
selected_subscription: nil,
user_permissions: nil,
form: to_form(%{"map_slug" => nil})
)}
end
@impl true
@@ -90,33 +63,12 @@ defmodule WandererAppWeb.MapLive do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
defp apply_action(socket, :index, _params) do
socket
|> assign(:active_page, :map)
end
defp apply_action(socket, :add_system, _params) do
socket
|> assign(:active_page, :map)
|> assign(:page_title, "Add System")
|> assign(:add_system_form, to_form(%{"system_id" => nil}))
end
@impl true
def handle_info(
%{event: :map_started},
%{
assigns: %{
current_user: current_user,
map_id: map_id,
user_permissions: user_permissions
}
} = socket
) do
on_map_started(map_id, current_user, user_permissions)
{:noreply, socket}
end
socket
),
do: {:noreply, socket |> on_map_started()}
@impl true
def handle_info(:character_token_invalid, socket),
@@ -218,10 +170,16 @@ defmodule WandererAppWeb.MapLive do
payload: %{
character_id: character_id,
solar_system_source: solar_system_source,
solar_system_target: solar_system_target,
solar_system_target: solar_system_target
}
},
%{assigns: %{current_user: current_user, map_id: map_id, map_user_settings: map_user_settings}} = socket
%{
assigns: %{
current_user: current_user,
map_id: map_id,
map_user_settings: map_user_settings
}
} = socket
) do
is_user_character? =
current_user.characters |> Enum.map(& &1.id) |> Enum.member?(character_id)
@@ -232,37 +190,27 @@ defmodule WandererAppWeb.MapLive do
|> Map.get("link_signature_on_splash", "false")
|> String.to_existing_atom()
{:ok, signatures} =
WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
map_id: map_id,
solar_system_id: solar_system_source
})
{:ok, signatures} =
WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
map_id: map_id,
solar_system_id: solar_system_source
})
|> case do
{:ok, system} ->
{:ok, get_system_signatures(system.id)}
_ ->
{:ok, []}
end
# signatures
# :
# (4) [{…}, {…}, {…}, {…}]
# solar_system_source
# :
# 31000526
# solar_system_target
# :
# 31001819
#
socket =
(is_user_character? && link_signature_on_splash? && not(signatures |> Enum.empty?()))
(is_user_character? && link_signature_on_splash? && not (signatures |> Enum.empty?()))
|> case do
true ->
socket
|> push_map_event("link_signature_to_system", %{
solar_system_source: solar_system_source,
solar_system_target: solar_system_target,
signatures: signatures
solar_system_target: solar_system_target
})
false ->
@@ -439,7 +387,49 @@ defmodule WandererAppWeb.MapLive do
{:noreply, socket}
end
def handle_info({:init_map, map}, %{assigns: %{current_user: current_user}} = socket) do
def handle_info({:load_map, map_slug}, %{assigns: %{current_user: current_user}} = socket) do
ErrorTracker.set_context(%{user_id: current_user.id})
Task.async(fn -> _get_available_maps(current_user) end)
map_slug
|> WandererApp.MapRepo.get_by_slug_with_permissions(current_user)
|> case do
{:ok,
%{
id: map_id,
deleted: false
} = map} ->
Process.send_after(self(), {:init_map, map}, 10)
{:noreply, socket}
{:ok,
%{
deleted: true
} = _map} ->
{:noreply,
socket
|> put_flash(
:error,
"Map was deleted by owner or administrator."
)
|> push_navigate(to: ~p"/maps")}
{:error, _} ->
{:noreply,
socket
|> put_flash(
:error,
"Something went wrong. Please try one more time or submit an issue."
)
|> push_navigate(to: ~p"/maps")}
end
end
def handle_info(
{:init_map, map},
%{assigns: %{current_user: current_user, map_slug: map_slug}} = socket
) do
with %{
id: map_id,
deleted: false,
@@ -477,126 +467,36 @@ defmodule WandererAppWeb.MapLive do
cond do
(only_tracked_characters and can_track? and all_character_tracked?) or
(not only_tracked_characters and can_view?) ->
Process.send_after(
self(),
{:map_init,
%{
map_id: map_id,
page_title: map_name,
user_permissions: user_permissions,
tracked_character_ids: tracked_character_ids
}},
10
)
Phoenix.PubSub.subscribe(WandererApp.PubSub, map_id)
{:ok, ui_loaded} = WandererApp.Cache.get_and_remove("map_#{map_slug}:ui_loaded", false)
if ui_loaded do
maybe_start_map(map_id)
end
{:noreply,
socket
|> assign(
map_id: map_id,
page_title: map_name,
user_permissions: user_permissions,
tracked_character_ids: tracked_character_ids,
only_tracked_characters: only_tracked_characters
)}
only_tracked_characters and can_track? and not all_character_tracked? ->
Process.send_after(self(), :not_all_characters_tracked, 10)
{:noreply, socket}
true ->
Process.send_after(self(), :no_permissions, 10)
{:noreply, socket}
end
else
_ ->
Process.send_after(self(), :no_access, 10)
{:noreply, socket}
end
{:noreply, socket}
end
def handle_info({:map_init, %{map_id: map_id} = initial_data}, socket) do
Phoenix.PubSub.subscribe(WandererApp.PubSub, map_id)
{:noreply,
socket
|> assign(initial_data)}
end
def handle_info(
{:map_start,
%{
map_id: map_id,
map_user_settings: map_user_settings,
user_characters: user_character_eve_ids,
initial_data: initial_data,
events: events
} = _started_data},
socket
) do
socket =
events
|> Enum.reduce(socket, fn event, socket ->
case event do
{:track_characters, map_characters, track_character} ->
:ok = _track_characters(map_characters, map_id, track_character)
:ok = _add_characters(map_characters, map_id, track_character)
socket
:invalid_token_message ->
socket
|> put_flash(
:error,
"One of your characters has expired token. Please refresh it on characters page."
)
:empty_tracked_characters ->
socket
|> put_flash(
:info,
"You should enable tracking for at least one character to work with map."
)
:map_character_limit ->
socket
|> put_flash(
:error,
"Map reached its character limit, your characters won't be tracked. Please contact administrator."
)
_ ->
socket
end
end)
Process.send_after(
self(),
{:map_loaded,
%{
map_id: map_id,
initial_data: initial_data
}},
10
)
{:noreply,
socket
|> assign(
map_user_settings: map_user_settings,
user_characters: user_character_eve_ids,
has_tracked_characters?: _has_tracked_characters?(user_character_eve_ids)
)}
end
def handle_info(
{:map_loaded,
%{
map_id: map_id,
initial_data: initial_data
} = _loaded_data},
socket
) do
map_characters = map_id |> WandererApp.Map.list_characters()
{:noreply,
socket
|> assign(map_loaded?: true)
|> push_map_event(
"init",
initial_data |> Map.put(:characters, map_characters |> Enum.map(&map_ui_character/1))
)
|> push_event("js-exec", %{
to: "#map-loader",
attr: "data-loaded"
})}
end
def handle_info(:no_access, socket),
@@ -640,10 +540,6 @@ defmodule WandererAppWeb.MapLive do
maps: maps
)}
{:map_started_data, started_data} ->
Process.send_after(self(), {:map_start, started_data}, 100)
{:noreply, socket}
{:map_error, map_error} ->
Process.send_after(self(), map_error, 100)
{:noreply, socket}
@@ -675,13 +571,15 @@ defmodule WandererAppWeb.MapLive do
def handle_info(_event, socket), do: {:noreply, socket}
@impl true
def handle_event("ui_loaded", _body, %{assigns: %{map_id: map_id}} = socket) do
{:ok, map_started} = WandererApp.Cache.lookup("map_#{map_id}:started", false)
def handle_event("ui_loaded", _body, %{assigns: %{map_slug: map_slug} = assigns} = socket) do
assigns
|> Map.get(:map_id)
|> case do
map_id when not is_nil(map_id) ->
maybe_start_map(map_id)
if map_started do
Process.send_after(self(), %{event: :map_started}, 10)
else
WandererApp.Map.Manager.start_map(map_id)
_ ->
WandererApp.Cache.insert("map_#{map_slug}:ui_loaded", true)
end
{:noreply, socket}
@@ -1432,14 +1330,24 @@ defmodule WandererAppWeb.MapLive do
end
@impl true
def handle_event("add_character", _, %{assigns: assigns} = socket) do
def handle_event(
"add_character",
_,
%{
assigns: %{
current_user: current_user,
map_id: map_id,
user_permissions: user_permissions
}
} = socket
) do
{:ok, character_settings} =
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: assigns.map_id}) do
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: map_id}) do
{:ok, settings} -> {:ok, settings}
_ -> {:ok, []}
end
case assigns.user_permissions.track_character do
case user_permissions.track_character do
true ->
{:noreply,
socket
@@ -1448,10 +1356,14 @@ defmodule WandererAppWeb.MapLive do
character_settings: character_settings
)
|> assign_async(:characters, fn ->
WandererApp.Maps.load_characters(
assigns.map |> Ash.load!(:acls),
{:ok, map} =
map_id
|> WandererApp.MapRepo.get([:acls])
map
|> WandererApp.Maps.load_characters(
character_settings,
assigns.current_user.id
current_user.id
)
end)}
@@ -1471,24 +1383,33 @@ defmodule WandererAppWeb.MapLive do
end
@impl true
def handle_event("toggle_track", %{"character-id" => character_id}, socket) do
map = socket.assigns.map
character_settings = socket.assigns.character_settings
def handle_event(
"toggle_track",
%{"character-id" => character_id},
%{
assigns: %{
map_id: map_id,
map_slug: map_slug,
character_settings: character_settings,
current_user: current_user,
only_tracked_characters: only_tracked_characters
}
} = socket
) do
socket =
case character_settings |> Enum.find(&(&1.character_id == character_id)) do
nil ->
{:ok, map_character_settings} =
WandererApp.Api.MapCharacterSettings.create(%{
character_id: character_id,
map_id: map.id,
map_id: map_id,
tracked: true
})
character = map_character_settings |> Ash.load!(:character) |> Map.get(:character)
:ok = _track_characters([character], map.id, true)
:ok = _add_characters([character], map.id, true)
:ok = _track_characters([character], map_id, true)
:ok = _add_characters([character], map_id, true)
socket
@@ -1501,16 +1422,16 @@ defmodule WandererAppWeb.MapLive do
character = map_character_settings |> Ash.load!(:character) |> Map.get(:character)
:ok = _untrack_characters([character], map.id)
:ok = _remove_characters([character], map.id)
:ok = _untrack_characters([character], map_id)
:ok = _remove_characters([character], map_id)
if map.only_tracked_characters do
if only_tracked_characters do
socket
|> put_flash(
:error,
"You should enable tracking for all characters that have access to this map first!"
)
|> push_navigate(to: ~p"/tracking/#{map.slug}")
|> push_navigate(to: ~p"/tracking/#{map_slug}")
else
socket
end
@@ -1522,8 +1443,8 @@ defmodule WandererAppWeb.MapLive do
character = map_character_settings |> Ash.load!(:character) |> Map.get(:character)
:ok = _track_characters([character], map.id, true)
:ok = _add_characters([character], map.id, true)
:ok = _track_characters([character], map_id, true)
:ok = _add_characters([character], map_id, true)
socket
end
@@ -1531,12 +1452,12 @@ defmodule WandererAppWeb.MapLive do
%{result: characters} = socket.assigns.characters
{:ok, map_characters} = _get_tracked_map_characters(map.id, socket.assigns.current_user)
{:ok, map_characters} = _get_tracked_map_characters(map_id, current_user)
user_character_eve_ids = map_characters |> Enum.map(& &1.eve_id)
{:ok, character_settings} =
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: map.id}) do
case WandererApp.Api.MapCharacterSettings.read_by_map(%{map_id: map_id}) do
{:ok, settings} -> {:ok, settings}
_ -> {:ok, []}
end
@@ -1585,13 +1506,29 @@ defmodule WandererAppWeb.MapLive do
)}
end
@impl true
def handle_event(
"get_user_settings",
_,
%{assigns: %{map_id: map_id, current_user: current_user}} = socket
) do
{:ok, user_settings} =
WandererApp.MapUserSettingsRepo.get!(map_id, current_user.id)
|> WandererApp.MapUserSettingsRepo.to_form_data()
{:reply, %{user_settings: user_settings}, socket}
end
@impl true
def handle_event(
"update_user_settings",
user_settings_form,
%{assigns: %{map_id: map_id, current_user: current_user}} = socket
) do
settings = user_settings_form |> Map.take(["select_on_spash", "link_signature_on_splash"]) |> Jason.encode!()
settings =
user_settings_form
|> Map.take(["select_on_spash", "link_signature_on_splash"])
|> Jason.encode!()
{:ok, user_settings} =
WandererApp.MapUserSettingsRepo.create_or_update(map_id, current_user.id, settings)
@@ -1610,15 +1547,14 @@ defmodule WandererAppWeb.MapLive do
},
socket
) do
socket
|> _check_user_permissions(:update_system)
|> case do
true ->
case WandererApp.Api.MapSystem.read_by_map_and_solar_system(%{
map_id: socket.assigns.map_id,
solar_system_id: solar_system_source
}) do
map_id: socket.assigns.map_id,
solar_system_id: solar_system_source
}) do
{:ok, system} ->
first_character_eve_id =
Map.get(socket.assigns, :user_characters, []) |> List.first()
@@ -1629,18 +1565,20 @@ defmodule WandererAppWeb.MapLive do
|> Enum.filter(fn s -> s.eve_id == signature_eve_id end)
|> Enum.each(fn s ->
s
|> WandererApp.Api.MapSystemSignature.update_linked_system(%{linked_system_id: solar_system_target})
|> WandererApp.Api.MapSystemSignature.update_linked_system(%{
linked_system_id: solar_system_target
})
end)
{:noreply, socket}
_ ->
{:noreply,
socket
|> put_flash(
:error,
"You should enable tracking for at least one character to work with signatures."
)}
socket
|> put_flash(
:error,
"You should enable tracking for at least one character to work with signatures."
)}
end
_ ->
@@ -1704,10 +1642,101 @@ defmodule WandererAppWeb.MapLive do
{:noreply, socket}
end
defp apply_action(socket, :index, _params) do
socket
|> assign(:active_page, :map)
end
defp apply_action(socket, :add_system, _params) do
socket
|> assign(:active_page, :map)
|> assign(:page_title, "Add System")
|> assign(:add_system_form, to_form(%{"system_id" => nil}))
end
defp maybe_start_map(map_id) do
{:ok, map_started} = WandererApp.Cache.lookup("map_#{map_id}:started", false)
if map_started do
Process.send_after(self(), %{event: :map_started}, 10)
else
WandererApp.Map.Manager.start_map(map_id)
end
end
defp map_start(
socket,
%{
map_id: map_id,
map_user_settings: map_user_settings,
user_characters: user_character_eve_ids,
initial_data: initial_data,
events: events
} = _started_data
) do
socket =
events
|> Enum.reduce(socket, fn event, socket ->
case event do
{:track_characters, map_characters, track_character} ->
:ok = _track_characters(map_characters, map_id, track_character)
:ok = _add_characters(map_characters, map_id, track_character)
socket
:invalid_token_message ->
socket
|> put_flash(
:error,
"One of your characters has expired token. Please refresh it on characters page."
)
:empty_tracked_characters ->
socket
|> put_flash(
:info,
"You should enable tracking for at least one character to work with map."
)
:map_character_limit ->
socket
|> put_flash(
:error,
"Map reached its character limit, your characters won't be tracked. Please contact administrator."
)
_ ->
socket
end
end)
map_characters = map_id |> WandererApp.Map.list_characters()
socket
|> assign(
map_loaded?: true,
map_user_settings: map_user_settings,
user_characters: user_character_eve_ids,
has_tracked_characters?: _has_tracked_characters?(user_character_eve_ids)
)
|> push_map_event(
"init",
initial_data |> Map.put(:characters, map_characters |> Enum.map(&map_ui_character/1))
)
|> push_event("js-exec", %{
to: "#map-loader",
attr: "data-loaded"
})
end
defp on_map_started(
map_id,
current_user,
%{view_system: true, track_character: track_character} = user_permissions
%{
assigns: %{
current_user: current_user,
map_id: map_id,
user_permissions:
%{view_system: true, track_character: track_character} = user_permissions
}
} = socket
) do
with {:ok, _} <- current_user |> WandererApp.Api.User.update_last_map(%{last_map_id: map_id}),
{:ok, map_user_settings} <- WandererApp.MapUserSettingsRepo.get(map_id, current_user.id),
@@ -1786,27 +1815,27 @@ defmodule WandererAppWeb.MapLive do
)
|> Map.put(:reset, true)
Process.send_after(
self(),
{:map_start,
%{
map_id: map_id,
map_user_settings: map_user_settings,
user_characters: user_character_eve_ids,
initial_data: initial_data,
events: events
}},
10
)
socket
|> map_start(%{
map_id: map_id,
map_user_settings: map_user_settings,
user_characters: user_character_eve_ids,
initial_data: initial_data,
events: events
})
else
error ->
Logger.error(fn -> "map_start_error: #{error}" end)
Process.send_after(self(), :no_access, 10)
socket
end
end
defp on_map_started(_map_id, _current_user, _user_permissions),
do: Process.send_after(self(), :no_access, 10)
defp on_map_started(socket) do
Process.send_after(self(), :no_access, 10)
socket
end
defp _set_autopilot_waypoint(
current_user,
@@ -1831,13 +1860,6 @@ defmodule WandererAppWeb.MapLive do
end
end
defp _load_user_permissions({:ok, map}, current_user) do
map
|> Ash.load([:acls, :user_permissions], actor: current_user)
end
defp _load_user_permissions(error, _current_user), do: error
defp _get_map_data(map_id, include_static_data? \\ true) do
{:ok, hubs} = map_id |> WandererApp.Map.list_hubs()
{:ok, connections} = map_id |> WandererApp.Map.list_connections()

View File

@@ -114,12 +114,7 @@ defmodule WandererAppWeb.MapsLive do
"auto_renew?" => true
}
options_form =
map.options
|> case do
nil -> %{"layout" => "left_to_right"}
options -> Jason.decode!(options)
end
{:ok, options_form_data} = WandererApp.MapRepo.options_to_form_data(map)
{:ok, estimated_price, discount} =
WandererApp.Map.SubscriptionManager.estimate_price(subscription_form, false)
@@ -139,7 +134,7 @@ defmodule WandererAppWeb.MapsLive do
active_settings_tab: "general",
is_adding_subscription?: false,
selected_subscription: nil,
options_form: options_form |> to_form(),
options_form: options_form_data |> to_form(),
map_subscriptions: map_subscriptions,
subscription_form: subscription_form |> to_form(),
estimated_price: estimated_price,
@@ -661,16 +656,14 @@ defmodule WandererAppWeb.MapsLive do
def handle_event(
"update_options",
%{
"layout" => layout
} = options_form,
options_form,
%{assigns: %{map_id: map_id, map: map}} = socket
) do
options = %{layout: layout}
options =
options_form
|> Map.take(["layout", "store_custom_labels"])
updated_map =
map
|> WandererApp.Api.Map.update_options!(%{options: Jason.encode!(options)})
{:ok, updated_map} = WandererApp.MapRepo.update_options(map, options)
@pubsub_client.broadcast(
WandererApp.PubSub,

View File

@@ -243,16 +243,23 @@
for={@options_form}
phx-change="update_options"
>
<div class="stat-title">Map systems layout</div>
<div class="stat-value text-white">
<.input
type="select"
field={f[:layout]}
class="p-dropdown p-component p-inputwrapper"
placeholder="Map default layout"
options={@layout_options}
/>
<div>
<div class="stat-title">Map systems layout</div>
<div class="stat-value text-white">
<.input
type="select"
field={f[:layout]}
class="p-dropdown p-component p-inputwrapper"
placeholder="Map default layout"
options={@layout_options}
/>
</div>
</div>
<.input
type="checkbox"
field={f[:store_custom_labels]}
label="Store system custom labels"
/>
</.form>
</:actions>
</.header>

View File

@@ -2,7 +2,7 @@ defmodule WandererApp.MixProject do
use Mix.Project
@source_url "https://github.com/wanderer-industries/wanderer"
@version "1.6.0"
@version "1.11.5"
def project do
[

View File

@@ -100,9 +100,9 @@
"dest": "c5",
"src": ["c6"],
"static": true,
"max_mass_per_jump": 1350000000,
"max_mass_per_jump": 2000000000,
"lifetime": "24",
"total_mass": 3000000000,
"total_mass": 3300000000,
"sibling_groups": [],
"typeID": 30711,
"name": "V911"
@@ -124,9 +124,9 @@
"dest": "c6",
"src": ["c6"],
"static": true,
"max_mass_per_jump": 1350000000,
"max_mass_per_jump": 2000000000,
"lifetime": "24",
"total_mass": 3000000000,
"total_mass": 3300000000,
"sibling_groups": [],
"typeID": 30712,
"name": "W237"
@@ -172,9 +172,9 @@
"dest": "c6",
"src": ["c5"],
"static": true,
"max_mass_per_jump": 1350000000,
"max_mass_per_jump": 2000000000,
"lifetime": "24",
"total_mass": 3000000000,
"total_mass": 3300000000,
"sibling_groups": [],
"typeID": 30703,
"name": "V753"
@@ -208,9 +208,9 @@
"dest": "c6",
"src": ["ls", "ns"],
"static": false,
"max_mass_per_jump": 1350000000,
"max_mass_per_jump": 2000000000,
"lifetime": "48",
"total_mass": 3000000000,
"total_mass": 3300000000,
"sibling_groups": null,
"typeID": 30646,
"name": "U319"
@@ -424,9 +424,9 @@
"dest": "ns",
"src": ["c5", "c6"],
"static": false,
"max_mass_per_jump": 1350000000,
"max_mass_per_jump": 2000000000,
"lifetime": "16",
"total_mass": 3000000000,
"total_mass": 3300000000,
"sibling_groups": null,
"typeID": 30706,
"name": "Z142"
@@ -532,9 +532,9 @@
"dest": "ls",
"src": ["c4"],
"static": false,
"max_mass_per_jump": 1350000000,
"max_mass_per_jump": 2000000000,
"lifetime": "24",
"total_mass": 3000000000,
"total_mass": 3300000000,
"sibling_groups": null,
"typeID": 30696,
"name": "N290"
@@ -616,9 +616,9 @@
"dest": "c5",
"src": ["c5"],
"static": true,
"max_mass_per_jump": 1350000000,
"max_mass_per_jump": 2000000000,
"lifetime": "24",
"total_mass": 3000000000,
"total_mass": 3300000000,
"sibling_groups": [],
"typeID": 30702,
"name": "H296"
@@ -772,7 +772,7 @@
"dest": "c5",
"src": ["c2"],
"static": true,
"max_mass_per_jump": 300000000,
"max_mass_per_jump": 375000000,
"lifetime": "24",
"total_mass": 3000000000,
"sibling_groups": [["E545"]],
@@ -796,9 +796,9 @@
"dest": "ns",
"src": ["ls", "ns"],
"static": false,
"max_mass_per_jump": 1350000000,
"max_mass_per_jump": 2000000000,
"lifetime": "16",
"total_mass": 3000000000,
"total_mass": 3300000000,
"sibling_groups": null,
"typeID": 30649,
"name": "S199"
@@ -844,9 +844,9 @@
"dest": "ls",
"src": ["ls", "ns"],
"static": false,
"max_mass_per_jump": 1350000000,
"max_mass_per_jump": 2000000000,
"lifetime": "24",
"total_mass": 3000000000,
"total_mass": 3300000000,
"sibling_groups": null,
"typeID": 30648,
"name": "N944"
@@ -1024,9 +1024,9 @@
"dest": "c5",
"src": ["ls", "ns"],
"static": false,
"max_mass_per_jump": 1350000000,
"max_mass_per_jump": 2000000000,
"lifetime": "24",
"total_mass": 3000000000,
"total_mass": 3300000000,
"sibling_groups": null,
"typeID": 30643,
"name": "N432"