feat: added starred spawns to session data

This commit is contained in:
Davide Passoni 2024-12-20 15:43:54 +01:00
parent 71e47bce0b
commit 5797b9d209
10 changed files with 82 additions and 44 deletions

View File

@ -51,7 +51,8 @@ export interface SessionData {
| { type: 'circle', label: string; latlng: { lat: number; lng: number }; radius: number; coalition: Coalition }
| { type: 'polygon', label: string; latlngs: { lat: number; lng: number }[]; coalition: Coalition }
)[];
hotgroups?: {[key: string]: number[]}
hotgroups?: {[key: string]: number[]},
starredSpawns?: { [key: number]: SpawnRequestTable }
}
export interface ProfileOptions {

View File

@ -2,7 +2,7 @@ import { LatLng, LeafletMouseEvent } from "leaflet";
import { DrawSubState, OlympusState } from "../../constants/constants";
import { AppStateChangedEvent, CoalitionAreaChangedEvent, CoalitionAreasChangedEvent, CoalitionAreaSelectedEvent, SessionDataLoadedEvent } from "../../events";
import { getApp } from "../../olympusapp";
import { areaContains } from "../../other/utils";
import { areaContains, deepCopyTable } from "../../other/utils";
import { CoalitionCircle } from "./coalitioncircle";
import { CoalitionPolygon } from "./coalitionpolygon";
import { SessionData } from "../../interfaces";
@ -45,7 +45,7 @@ export class CoalitionAreasManager {
SessionDataLoadedEvent.on((sessionData: SessionData) => {
/* Make a local copy */
const localSessionData = JSON.parse(JSON.stringify(sessionData)) as SessionData;
const localSessionData = deepCopyTable(sessionData) as SessionData;
this.#areas.forEach((area) => this.deleteCoalitionArea(area));
localSessionData.coalitionAreas?.forEach((options) => {
if (options.type === "circle") {

View File

@ -3,7 +3,7 @@ import { getApp } from "../olympusapp";
import { BoxSelect } from "./boxselect";
import { Airbase } from "../mission/airbase";
import { Unit } from "../unit/unit";
import { areaContains, deg2rad, getGroundElevation } from "../other/utils";
import { areaContains, deepCopyTable, deg2rad, getGroundElevation } from "../other/utils";
import { TemporaryUnitMarker } from "./markers/temporaryunitmarker";
import { ClickableMiniMap } from "./clickableminimap";
import {
@ -53,6 +53,7 @@ import {
PasteEnabledChangedEvent,
SelectionClearedEvent,
SelectionEnabledChangedEvent,
SessionDataLoadedEvent,
SpawnContextMenuRequestEvent,
StarredSpawnsChangedEvent,
UnitDeselectedEvent,
@ -291,6 +292,14 @@ export class Map extends L.Map {
ContextActionChangedEvent.on((contextAction) => this.#updateDestinationPreviewMarkers());
MapOptionsChangedEvent.on((mapOptions) => this.#moveDestinationPreviewMarkers());
SessionDataLoadedEvent.on((sessionData) => {
const localSessionData = deepCopyTable(sessionData);
if (localSessionData.starredSpawns) {
this.#starredSpawnRequestTables = localSessionData.starredSpawns;
StarredSpawnsChangedEvent.dispatch(this.#starredSpawnRequestTables);
}
});
window.addEventListener("blur", () => {
this.setSelectionEnabled(false);
this.setPasteEnabled(false);

View File

@ -258,9 +258,9 @@
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
width: 80px;
width: 100px;
height: 45px;
translate: 60px 2px;
translate: 80px 2px;
}
[todo-data-awacs-mode] [data-object|="unit"] .unit-summary.cluster-north {

View File

@ -436,3 +436,12 @@ export function mode(array) {
}
return maxEl;
}
export function deepCopyTable(table) {
try {
return JSON.parse(JSON.stringify(table));
} catch (error) {
console.error(error);
return {};
}
}

View File

@ -12,6 +12,7 @@ import {
SessionDataChangedEvent,
SessionDataLoadedEvent,
SessionDataSavedEvent,
StarredSpawnsChangedEvent,
} from "./events";
import { SessionData } from "./interfaces";
import { CoalitionCircle } from "./map/coalitionarea/coalitioncircle";
@ -125,6 +126,11 @@ export class SessionDataManager {
});
this.#saveSessionData();
});
StarredSpawnsChangedEvent.on((starredSpawns) => {
this.#sessionData.starredSpawns = starredSpawns;
this.#saveSessionData();
})
}, 200);
});
}

View File

@ -15,6 +15,7 @@ import { CoalitionCircle } from "../../map/coalitionarea/coalitioncircle";
import { DrawSubState, ERAS_ORDER, IADSTypes, NO_SUBSTATE, OlympusState, OlympusSubState } from "../../constants/constants";
import { AppStateChangedEvent, CoalitionAreasChangedEvent, CoalitionAreaSelectedEvent } from "../../events";
import { FaXmark } from "react-icons/fa6";
import { deepCopyTable } from "../../other/utils";
export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED);
@ -205,7 +206,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
{types.map((type, idx) => {
if (!(type in typesSelection)) {
typesSelection[type] = true;
setTypesSelection(JSON.parse(JSON.stringify(typesSelection)));
setTypesSelection(deepCopyTable(typesSelection));
}
return (
@ -214,7 +215,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
checked={typesSelection[type]}
onChange={(ev) => {
typesSelection[type] = ev.currentTarget.checked;
setTypesSelection(JSON.parse(JSON.stringify(typesSelection)));
setTypesSelection(deepCopyTable(typesSelection));
}}
/>
<div>{type}</div>
@ -226,7 +227,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
{eras.map((era) => {
if (!(era in erasSelection)) {
erasSelection[era] = true;
setErasSelection(JSON.parse(JSON.stringify(erasSelection)));
setErasSelection(deepCopyTable(erasSelection));
}
return (
@ -235,7 +236,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
checked={erasSelection[era]}
onChange={(ev) => {
erasSelection[era] = ev.currentTarget.checked;
setErasSelection(JSON.parse(JSON.stringify(erasSelection)));
setErasSelection(deepCopyTable(erasSelection));
}}
/>
<div>{era}</div>
@ -247,7 +248,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
{["Short range", "Medium range", "Long range"].map((range) => {
if (!(range in rangesSelection)) {
rangesSelection[range] = true;
setRangesSelection(JSON.parse(JSON.stringify(rangesSelection)));
setRangesSelection(deepCopyTable(rangesSelection));
}
return (
@ -256,7 +257,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
checked={rangesSelection[range]}
onChange={(ev) => {
rangesSelection[range] = ev.currentTarget.checked;
setErasSelection(JSON.parse(JSON.stringify(rangesSelection)));
setErasSelection(deepCopyTable(rangesSelection));
}}
/>
<div>{range}</div>

View File

@ -46,7 +46,7 @@ import {
olButtonsVisibilityOlympus,
} from "../components/olicons";
import { Coalition } from "../../types/types";
import { convertROE, ftToM, knotsToMs, mToFt, msToKnots } from "../../other/utils";
import { convertROE, deepCopyTable, ftToM, knotsToMs, mToFt, msToKnots } from "../../other/utils";
import { FaCog, FaGasPump, FaSignal, FaTag } from "react-icons/fa";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { OlSearchBar } from "../components/olsearchbar";
@ -270,7 +270,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
key={entry[0]}
onClick={() => {
selectionFilter["control"][entry[0]] = !selectionFilter["control"][entry[0]];
setSelectionFilter(JSON.parse(JSON.stringify(selectionFilter)));
setSelectionFilter(deepCopyTable(selectionFilter));
}}
toggled={selectionFilter["control"][entry[0]]}
/>
@ -319,7 +319,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
disabled={selectionID !== null}
onChange={() => {
selectionFilter[coalition][entry[0]] = !selectionFilter[coalition][entry[0]];
setSelectionFilter(JSON.parse(JSON.stringify(selectionFilter)));
setSelectionFilter(deepCopyTable(selectionFilter));
}}
/>
</td>
@ -339,7 +339,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
Object.keys(selectionFilter["blue"]).forEach((key) => {
selectionFilter["blue"][key] = newValue;
});
setSelectionFilter(JSON.parse(JSON.stringify(selectionFilter)));
setSelectionFilter(deepCopyTable(selectionFilter));
}}
/>
</td>
@ -351,7 +351,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
Object.keys(selectionFilter["neutral"]).forEach((key) => {
selectionFilter["neutral"][key] = newValue;
});
setSelectionFilter(JSON.parse(JSON.stringify(selectionFilter)));
setSelectionFilter(deepCopyTable(selectionFilter));
}}
/>
</td>
@ -363,7 +363,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
Object.keys(selectionFilter["red"]).forEach((key) => {
selectionFilter["red"][key] = newValue;
});
setSelectionFilter(JSON.parse(JSON.stringify(selectionFilter)));
setSelectionFilter(deepCopyTable(selectionFilter));
}}
/>
</td>
@ -812,8 +812,8 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
`}
onClick={() => {
setActiveAdvancedSettings({
radio: JSON.parse(JSON.stringify(selectedUnits[0].getRadio())),
TACAN: JSON.parse(JSON.stringify(selectedUnits[0].getTACAN())),
radio: deepCopyTable(selectedUnits[0].getRadio()),
TACAN: deepCopyTable(selectedUnits[0].getTACAN()),
});
setShowAdvancedSettings(true);
}}
@ -1104,7 +1104,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
key={idx}
onClick={() => {
if (activeAdvancedSettings) activeAdvancedSettings.radio.callsign = idx + 1;
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
>
{name}
@ -1123,7 +1123,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
key={idx}
onClick={() => {
if (activeAdvancedSettings) activeAdvancedSettings.radio.callsign = idx + 1;
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
>
{name}
@ -1141,17 +1141,17 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
max={9}
onChange={(e) => {
if (activeAdvancedSettings) activeAdvancedSettings.radio.callsignNumber = Math.max(Math.min(Number(e.target.value), 9), 1);
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
onDecrease={() => {
if (activeAdvancedSettings)
activeAdvancedSettings.radio.callsignNumber = Math.max(Math.min(Number(activeAdvancedSettings.radio.callsignNumber - 1), 9), 1);
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
onIncrease={() => {
if (activeAdvancedSettings)
activeAdvancedSettings.radio.callsignNumber = Math.max(Math.min(Number(activeAdvancedSettings.radio.callsignNumber + 1), 9), 1);
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
value={activeAdvancedSettings ? activeAdvancedSettings.radio.callsignNumber : 1}
></OlNumberInput>
@ -1163,17 +1163,17 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
max={126}
onChange={(e) => {
if (activeAdvancedSettings) activeAdvancedSettings.TACAN.channel = Math.max(Math.min(Number(e.target.value), 126), 1);
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
onDecrease={() => {
if (activeAdvancedSettings)
activeAdvancedSettings.TACAN.channel = Math.max(Math.min(Number(activeAdvancedSettings.TACAN.channel - 1), 126), 1);
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
onIncrease={() => {
if (activeAdvancedSettings)
activeAdvancedSettings.TACAN.channel = Math.max(Math.min(Number(activeAdvancedSettings.TACAN.channel + 1), 126), 1);
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
value={activeAdvancedSettings ? activeAdvancedSettings.TACAN.channel : 1}
></OlNumberInput>
@ -1186,7 +1186,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
key={"X"}
onClick={() => {
if (activeAdvancedSettings) activeAdvancedSettings.TACAN.XY = "X";
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
>
X
@ -1195,7 +1195,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
key={"Y"}
onClick={() => {
if (activeAdvancedSettings) activeAdvancedSettings.TACAN.XY = "Y";
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
>
Y
@ -1210,7 +1210,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
if (activeAdvancedSettings.TACAN.callsign.length > 3)
activeAdvancedSettings.TACAN.callsign = activeAdvancedSettings.TACAN.callsign.slice(0, 3);
}
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
/>
</div>
@ -1220,7 +1220,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
toggled={activeAdvancedSettings ? activeAdvancedSettings.TACAN.isOn : false}
onClick={() => {
if (activeAdvancedSettings) activeAdvancedSettings.TACAN.isOn = !activeAdvancedSettings.TACAN.isOn;
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}}
/>
</div>
@ -1232,7 +1232,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
onChange={(value) => {
if (activeAdvancedSettings) {
activeAdvancedSettings.radio.frequency = value;
setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings)));
setActiveAdvancedSettings(deepCopyTable(activeAdvancedSettings));
}
}}
/>

View File

@ -9,7 +9,7 @@ import { LoadoutBlueprint, SpawnRequestTable, UnitBlueprint } from "../../interf
import { OlStateButton } from "../components/olstatebutton";
import { Coalition } from "../../types/types";
import { getApp } from "../../olympusapp";
import { ftToM, hash, mode } from "../../other/utils";
import { deepCopyTable, ftToM, hash, mode } from "../../other/utils";
import { LatLng } from "leaflet";
import { Airbase } from "../../mission/airbase";
import { altitudeIncrements, groupUnitCount, maxAltitudeValues, minAltitudeValues, OlympusState, SpawnSubState } from "../../constants/constants";
@ -50,7 +50,7 @@ export function UnitSpawnMenu(props: {
const [showLoadout, setShowLoadout] = useState(false);
const [showAdvancedOptions, setShowAdvancedOptions] = useState(false);
const [showUnitSummary, setShowUnitSummary] = useState(false);
const [quickAccessName, setQuickAccessName] = useState("No name");
const [quickAccessName, setQuickAccessName] = useState("Preset 1");
const [key, setKey] = useState("");
const [spawnRequestTable, setSpawnRequestTable] = useState(null as null | SpawnRequestTable);
@ -69,7 +69,7 @@ export function UnitSpawnMenu(props: {
const setSpawnRequestTableCallback = useCallback(() => {
if (spawnRequestTable) {
/* Refresh the unique key identified */
const tempTable = JSON.parse(JSON.stringify(spawnRequestTable));
const tempTable = deepCopyTable(spawnRequestTable);
delete tempTable.quickAccessName;
delete tempTable.unit.location;
delete tempTable.unit.altitude;
@ -93,7 +93,7 @@ export function UnitSpawnMenu(props: {
if (!props.airbase) {
/* If the spawn is starred, set the quick access name */
if (key in props.starredSpawns && props.starredSpawns[key].quickAccessName) setQuickAccessName(props.starredSpawns[key].quickAccessName);
else setQuickAccessName("No name");
else setQuickAccessName(`Preset ${Object.keys(props.starredSpawns).length + 1}`);
}
}, [props.starredSpawns, key]);
useEffect(updateQuickAccessName, [key]);

View File

@ -1,7 +1,17 @@
import { LatLng, LatLngBounds } from "leaflet";
import { getApp } from "../olympusapp";
import { AirUnit, Unit } from "./unit";
import { areaContains, bearingAndDistanceToLatLng, deg2rad, getGroundElevation, latLngToMercator, mToFt, mercatorToLatLng, msToKnots } from "../other/utils";
import {
areaContains,
bearingAndDistanceToLatLng,
deepCopyTable,
deg2rad,
getGroundElevation,
latLngToMercator,
mToFt,
mercatorToLatLng,
msToKnots,
} from "../other/utils";
import { CoalitionPolygon } from "../map/coalitionarea/coalitionpolygon";
import { DELETE_CYCLE_TIME, DELETE_SLOW_THRESHOLD, DataIndexes, GAME_MASTER, IADSDensities, OlympusState, UnitControlSubState } from "../constants/constants";
import { DataExtractor } from "../server/dataextractor";
@ -66,13 +76,15 @@ export class UnitsManager {
SessionDataLoadedEvent.on((sessionData) => {
UnitsRefreshed.on(() => {
const localSessionData = JSON.parse(JSON.stringify(sessionData));
Object.keys(localSessionData.hotgroups).forEach((hotgroup) => {
localSessionData.hotgroups[hotgroup].forEach((ID) => {
let unit = this.getUnitByID(ID);
if (unit) this.addToHotgroup(Number(hotgroup), [unit]);
const localSessionData = deepCopyTable(sessionData);
if (localSessionData.hotgroups) {
Object.keys(localSessionData.hotgroups).forEach((hotgroup) => {
localSessionData.hotgroups[hotgroup].forEach((ID) => {
let unit = this.getUnitByID(ID);
if (unit) this.addToHotgroup(Number(hotgroup), [unit]);
});
});
});
}
}, true);
});