From 7fa39561e31cbe6d6f3530cf16aab6b2ca98bb95 Mon Sep 17 00:00:00 2001 From: Pax1601 Date: Sat, 19 Oct 2024 10:53:43 +0200 Subject: [PATCH] Multiple small improvements and bugfixes --- frontend/react/src/audio/unitsink.ts | 1 + frontend/react/src/dom.d.ts | 1 + frontend/react/src/map/boxselect.ts | 5 +- frontend/react/src/map/map.ts | 13 +++- .../src/ui/contextmenus/mapcontextmenu.tsx | 26 +++++-- frontend/react/src/ui/modals/login.tsx | 11 ++- frontend/react/src/ui/panels/airbasemenu.tsx | 6 +- .../src/ui/panels/components/sourcepanel.tsx | 2 +- frontend/react/src/ui/panels/drawingmenu.tsx | 5 -- .../react/src/ui/panels/formationmenu.tsx | 7 +- frontend/react/src/ui/panels/sidebar.tsx | 4 +- .../react/src/ui/panels/unitcontrolmenu.tsx | 4 ++ .../src/ui/panels/unitmousecontrolbar.tsx | 19 ++++- frontend/react/src/ui/ui.tsx | 20 +++--- frontend/react/src/unit/contextaction.ts | 1 + frontend/react/src/unit/unit.ts | 70 ++++++++++++------- frontend/react/src/unit/unitsmanager.ts | 8 +-- 17 files changed, 133 insertions(+), 70 deletions(-) diff --git a/frontend/react/src/audio/unitsink.ts b/frontend/react/src/audio/unitsink.ts index 3c4f120e..73861c70 100644 --- a/frontend/react/src/audio/unitsink.ts +++ b/frontend/react/src/audio/unitsink.ts @@ -37,6 +37,7 @@ export class UnitSink extends AudioSink { this.#unitPipelines[unitID] = new AudioUnitPipeline(this.#unit, unitID, this.getInputNode()); this.#unitPipelines[unitID].setPtt(false); this.#unitPipelines[unitID].setMaxDistance(this.#maxDistance); + console.log(`Added unit pipeline for unitID ${unitID} ` ) } }); diff --git a/frontend/react/src/dom.d.ts b/frontend/react/src/dom.d.ts index d918388a..bc4b769f 100644 --- a/frontend/react/src/dom.d.ts +++ b/frontend/react/src/dom.d.ts @@ -3,6 +3,7 @@ import { CoalitionPolygon } from "./map/coalitionarea/coalitionpolygon"; import { Unit } from "./unit/unit"; interface CustomEventMap { + // TODO add missing events and remove unused unitSelection: CustomEvent; unitDeselection: CustomEvent; unitsSelection: CustomEvent; diff --git a/frontend/react/src/map/boxselect.ts b/frontend/react/src/map/boxselect.ts index c201eea3..1e970988 100644 --- a/frontend/react/src/map/boxselect.ts +++ b/frontend/react/src/map/boxselect.ts @@ -89,11 +89,8 @@ export var BoxSelect = Handler.extend({ _onMouseMove: function (e: any) { if (!this._moved) { this._moved = true; - this._box = DomUtil.create("div", "leaflet-zoom-box", this._container); DomUtil.addClass(this._container, "leaflet-crosshair"); - - this._map.fire("boxzoomstart"); } if (e.type === "touchmove") this._point = this._map.mouseEventToContainerPoint(e.touches[0]); @@ -117,6 +114,7 @@ export var BoxSelect = Handler.extend({ DomUtil.enableTextSelection(); DomUtil.enableImageDrag(); this._map.dragging.enable(); + this._forceBoxSelect = false; DomEvent.off( //@ts-ignore @@ -149,7 +147,6 @@ export var BoxSelect = Handler.extend({ window.setTimeout(Util.bind(this._resetState, this), 0); var bounds = new LatLngBounds(this._map.containerPointToLatLng(this._startPoint), this._map.containerPointToLatLng(this._point)); - this._forceBoxSelect = false; this._map.fire("selectionend", { selectionBounds: bounds }); }, diff --git a/frontend/react/src/map/map.ts b/frontend/react/src/map/map.ts index 7541a28c..2537b4f6 100644 --- a/frontend/react/src/map/map.ts +++ b/frontend/react/src/map/map.ts @@ -67,8 +67,10 @@ export class Map extends L.Map { #mouseCooldownTimer: number = 0; #shortPressTimer: number = 0; #longPressTimer: number = 0; + #selecting: boolean = false; /* Camera keyboard panning control */ + // TODO add back defaultPanDelta: number = 100; #panInterval: number | null = null; #panLeft: boolean = false; @@ -80,6 +82,7 @@ export class Map extends L.Map { #isShiftKeyDown: boolean = false; /* Center on unit target */ + // TODO add back #centeredUnit: Unit | null = null; /* Minimap */ @@ -721,6 +724,10 @@ export class Map extends L.Map { return this.#centeredUnit; } + isSelecting() { + return this.#selecting; + } + setTheatre(theatre: string) { this.#theatre = theatre; @@ -921,11 +928,14 @@ export class Map extends L.Map { this.#isDragging = false; } - #onSelectionStart(e: any) {} + #onSelectionStart(e: any) { + this.#selecting = true; + } #onSelectionEnd(e: any) { getApp().getUnitsManager().selectFromBounds(e.selectionBounds); document.dispatchEvent(new CustomEvent("mapSelectionEnd")); + this.#selecting = false; } #onMouseUp(e: any) { @@ -966,7 +976,6 @@ export class Map extends L.Map { this.setState(COALITIONAREA_EDIT); } else { this.setState(IDLE); - document.dispatchEvent(new CustomEvent("hideAllMenus")); } } diff --git a/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx b/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx index e95db72d..055cc8a9 100644 --- a/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx +++ b/frontend/react/src/ui/contextmenus/mapcontextmenu.tsx @@ -16,7 +16,7 @@ export function MapContextMenu(props: {}) { const [xPosition, setXPosition] = useState(0); const [yPosition, setYPosition] = useState(0); const [latLng, setLatLng] = useState(null as null | LatLng); - const [unit, setUnit] = useState(null as null | Unit) + const [unit, setUnit] = useState(null as null | Unit); var contentRef = useRef(null); @@ -84,7 +84,7 @@ export function MapContextMenu(props: {}) { getApp() .getUnitsManager() .getSelectedUnits() - .filter(unit => !unit.getHuman()) + .filter((unit) => !unit.getHuman()) .forEach((unit: Unit) => { unit.appendContextActions(newContextActionSet); }); @@ -93,6 +93,15 @@ export function MapContextMenu(props: {}) { return newContextActionSet; } + let colors = [null, "white", "green", "purple", "blue", "red"]; + let reorderedActions: ContextAction[] = []; + colors.forEach((color) => { + Object.values(contextActionsSet.getContextActions()).forEach((contextAction: ContextAction) => { + if (color === null && contextAction.getOptions().buttonColor === undefined) reorderedActions.push(contextAction); + else if (color === contextAction.getOptions().buttonColor) reorderedActions.push(contextAction); + }); + }); + return ( <> {open && ( @@ -108,10 +117,19 @@ export function MapContextMenu(props: {}) { flex w-full flex-col gap-2 overflow-x-auto no-scrollbar p-2 `} > - {Object.values(contextActionsSet.getContextActions(latLng? "position": "unit")).map((contextAction) => { + {Object.values(contextActionsSet.getContextActions(latLng ? "position" : "unit")).map((contextAction) => { + const colorString = contextAction.getOptions().buttonColor + ? ` + border-2 + border-${contextAction.getOptions().buttonColor}-500 + ` + : ""; return ( { if (contextAction.getOptions().executeImmediately) { contextAction.executeCallback(null, null); diff --git a/frontend/react/src/ui/modals/login.tsx b/frontend/react/src/ui/modals/login.tsx index 59af7767..ab390794 100644 --- a/frontend/react/src/ui/modals/login.tsx +++ b/frontend/react/src/ui/modals/login.tsx @@ -15,7 +15,7 @@ export function LoginModal(props: { onBack: () => void; }) { const [password, setPassword] = useState(""); - const [displayName, setDisplayName] = useState(""); + const [displayName, setDisplayName] = useState("Game Master"); return (
@@ -204,6 +200,7 @@ export function LoginModal(props: { focus:border-blue-500 focus:ring-blue-500 `} placeholder="Enter display name" + value={displayName} required />
diff --git a/frontend/react/src/ui/panels/airbasemenu.tsx b/frontend/react/src/ui/panels/airbasemenu.tsx index a7c46f18..ff868314 100644 --- a/frontend/react/src/ui/panels/airbasemenu.tsx +++ b/frontend/react/src/ui/panels/airbasemenu.tsx @@ -50,12 +50,14 @@ export function AirbaseMenu(props: { open: boolean; onClose: () => void; airbase
- {props.airbase?.getChartData().runways.map((runway) => { + {props.airbase?.getChartData().runways.map((runway, idx) => { return ( <> {Object.keys(runway.headings[0]).map((runwayName) => { return ( -
+
{" "} RWY {runwayName} diff --git a/frontend/react/src/ui/panels/components/sourcepanel.tsx b/frontend/react/src/ui/panels/components/sourcepanel.tsx index 6d9a98d0..245bcb56 100644 --- a/frontend/react/src/ui/panels/components/sourcepanel.tsx +++ b/frontend/react/src/ui/panels/components/sourcepanel.tsx @@ -116,7 +116,7 @@ export const AudioSourcePanel = forwardRef((props: { source: AudioSource; onExpa { props.source.setVolume(parseFloat(ev.currentTarget.value) / 100); }} diff --git a/frontend/react/src/ui/panels/drawingmenu.tsx b/frontend/react/src/ui/panels/drawingmenu.tsx index d5989230..7e3987d0 100644 --- a/frontend/react/src/ui/panels/drawingmenu.tsx +++ b/frontend/react/src/ui/panels/drawingmenu.tsx @@ -43,11 +43,6 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) { /* Align the state of the coalition toggle to the coalition of the area */ if (activeCoalitionArea && activeCoalitionArea?.getCoalition() !== areaCoalition) setAreaCoalition(activeCoalitionArea?.getCoalition()); - - if (!props.open) { - if ([COALITIONAREA_EDIT, COALITIONAREA_DRAW_CIRCLE, COALITIONAREA_DRAW_POLYGON].includes(getApp().getMap().getState())) - getApp().getMap().setState(IDLE); - } } }); diff --git a/frontend/react/src/ui/panels/formationmenu.tsx b/frontend/react/src/ui/panels/formationmenu.tsx index 4bd3dc4c..5e87501f 100644 --- a/frontend/react/src/ui/panels/formationmenu.tsx +++ b/frontend/react/src/ui/panels/formationmenu.tsx @@ -103,6 +103,7 @@ export function FormationMenu(props: { .map((optionFormationType) => { return ( { setCount(count + 1); setFormationType(optionFormationType); @@ -231,7 +232,7 @@ export function FormationMenu(props: { .forEach((unit, idx) => { if (units.length > 0 && units[0] !== null && idx != 0) { const ID = units[0].ID; - + const [dx, dz] = [ -(silhouetteHandles[idx].position.y - silhouetteHandles[0].position.y), silhouetteHandles[idx].position.x - silhouetteHandles[0].position.x, @@ -265,7 +266,9 @@ export function FormationMenu(props: { style={{ width: `${referenceWidth}px`, }} - >
{referenceDistance}ft
+ > +
{referenceDistance}ft
+
diff --git a/frontend/react/src/ui/panels/unitcontrolmenu.tsx b/frontend/react/src/ui/panels/unitcontrolmenu.tsx index be37c687..5d5a2f68 100644 --- a/frontend/react/src/ui/panels/unitcontrolmenu.tsx +++ b/frontend/react/src/ui/panels/unitcontrolmenu.tsx @@ -137,6 +137,10 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) { }); }, []); + useEffect(() => { + setShowAdvancedSettings(false); + }, [selectedUnits]) + /* Update the current values of the shown data */ function updateData() { const getters = { diff --git a/frontend/react/src/ui/panels/unitmousecontrolbar.tsx b/frontend/react/src/ui/panels/unitmousecontrolbar.tsx index b11fb1a2..8dd1a0f7 100644 --- a/frontend/react/src/ui/panels/unitmousecontrolbar.tsx +++ b/frontend/react/src/ui/panels/unitmousecontrolbar.tsx @@ -72,6 +72,15 @@ export function UnitMouseControlBar(props: {}) { sr > 1 && scrolledRight && setScrolledRight(false); } + let colors = [null, "white", "green", "purple", "blue", "red"]; + let reorderedActions: ContextAction[] = []; + colors.forEach((color) => { + Object.values(contextActionsSet.getContextActions()).forEach((contextAction: ContextAction) => { + if (color === null && contextAction.getOptions().buttonColor === undefined) reorderedActions.push(contextAction); + else if (color === contextAction.getOptions().buttonColor) reorderedActions.push(contextAction); + }); + }); + return ( <> {open && Object.keys(contextActionsSet.getContextActions()).length > 0 && ( @@ -93,13 +102,21 @@ export function UnitMouseControlBar(props: {}) { /> )}
onScroll(ev.target)} ref={scrollRef}> - {Object.values(contextActionsSet.getContextActions()).map((contextAction: ContextAction) => { + {reorderedActions.map((contextAction: ContextAction) => { return ( { if (contextAction.getOptions().executeImmediately) { setActiveContextAction(null); diff --git a/frontend/react/src/ui/ui.tsx b/frontend/react/src/ui/ui.tsx index fc4381ba..53fb1180 100644 --- a/frontend/react/src/ui/ui.tsx +++ b/frontend/react/src/ui/ui.tsx @@ -79,14 +79,13 @@ export function UI() { setMapOptions({ ...getApp().getMap().getOptions() }); }); - document.addEventListener("mapStateChanged", (ev) => { - //if ((ev as CustomEvent).detail === IDLE) hideAllMenus(); - /*else*/ if ((ev as CustomEvent).detail === CONTEXT_ACTION && window.innerWidth > 1000) setUnitControlMenuVisible(true); - setMapState(String((ev as CustomEvent).detail)); - }); + document.addEventListener("mapStateChanged", (ev: CustomEventInit) => { + if (ev.detail === IDLE || ev.detail === CONTEXT_ACTION || mapState !== IDLE) { + hideAllMenus(); + } - document.addEventListener("hideAllMenus", (ev) => { - hideAllMenus(); + if (ev.detail === CONTEXT_ACTION && window.innerWidth > 1000) setUnitControlMenuVisible(true); + setMapState(ev.detail); }); document.addEventListener("mapSourceChanged", (ev) => { @@ -116,14 +115,16 @@ export function UI() { document.addEventListener("showProtectionPrompt", (ev: CustomEventInit) => { setProtectionPromptVisible(true); - setProtectionCallback(() => {return ev.detail.callback}); + setProtectionCallback(() => { + return ev.detail.callback; + }); setProtectionUnits(ev.detail.units); }); document.addEventListener("showUnitExplosionMenu", (ev) => { setUnitExplosionMenuVisible(true); setUnitExplosionUnits((ev as CustomEvent).detail.units); - }) + }); }, []); function hideAllMenus() { @@ -137,6 +138,7 @@ export function UI() { setAudioMenuVisible(false); setFormationMenuVisible(false); setUnitExplosionMenuVisible(false); + setJTACMenuVisible(false); } function checkPassword(password: string) { diff --git a/frontend/react/src/unit/contextaction.ts b/frontend/react/src/unit/contextaction.ts index 7848de78..e7e47297 100644 --- a/frontend/react/src/unit/contextaction.ts +++ b/frontend/react/src/unit/contextaction.ts @@ -4,6 +4,7 @@ import { LatLng } from "leaflet"; export interface ContextActionOptions { executeImmediately?: boolean; + buttonColor?: string; } export type ContextActionCallback = (units: Unit[], targetUnit: Unit | null, targetPosition: LatLng | null) => void; diff --git a/frontend/react/src/unit/unit.ts b/frontend/react/src/unit/unit.ts index b536213e..952527bc 100644 --- a/frontend/react/src/unit/unit.ts +++ b/frontend/react/src/unit/unit.ts @@ -827,7 +827,8 @@ export abstract class Unit extends CustomMarker { (units: Unit[], _, targetPosition) => { getApp().getUnitsManager().clearDestinations(units); if (targetPosition) getApp().getUnitsManager().addDestination(targetPosition, false, 0, units); - } + }, + { buttonColor: "white" } ); contextActionSet.addContextAction( @@ -839,7 +840,8 @@ export abstract class Unit extends CustomMarker { "position", (units: Unit[], _, targetPosition) => { if (targetPosition) getApp().getUnitsManager().addDestination(targetPosition, false, 0, units); - } + }, + { buttonColor: "white" } ); contextActionSet.addContextAction( @@ -854,6 +856,7 @@ export abstract class Unit extends CustomMarker { }, { executeImmediately: true, + buttonColor: "red", } ); @@ -869,6 +872,7 @@ export abstract class Unit extends CustomMarker { }, { executeImmediately: true, + buttonColor: "red", } ); @@ -1244,10 +1248,10 @@ export abstract class Unit extends CustomMarker { // .getServerManager() // .isCommandExecuted((res: any) => { // if (res.commandExecuted) { - getApp().getMap().addExplosionMarker(this.getPosition()); - window.clearInterval(timer); - // } - // }, commandHash); + getApp().getMap().addExplosionMarker(this.getPosition()); + window.clearInterval(timer); + // } + // }, commandHash); }, 500); } }); @@ -1337,6 +1341,8 @@ export abstract class Unit extends CustomMarker { #onMouseUp(e: any) { this.#isMouseDown = false; + if (getApp().getMap().isSelecting()) return; + DomEvent.stop(e); DomEvent.preventDefault(e); e.originalEvent.stopImmediatePropagation(); @@ -1386,8 +1392,8 @@ export abstract class Unit extends CustomMarker { this.setSelected(!this.getSelected()); } } else if (getApp().getMap().getState() === SELECT_JTAC_TARGET) { - document.dispatchEvent(new CustomEvent("selectJTACTarget", {detail: {unit: this}})) - getApp().getMap().setState(IDLE) + document.dispatchEvent(new CustomEvent("selectJTACTarget", { detail: { unit: this } })); + getApp().getMap().setState(IDLE); } } @@ -1820,7 +1826,7 @@ export abstract class AirUnit extends Unit { (units: Unit[]) => { getApp().getUnitsManager().refuel(units); }, - { executeImmediately: true } + { executeImmediately: true, buttonColor: "purple" } ); contextActionSet.addContextAction( this, @@ -1832,7 +1838,7 @@ export abstract class AirUnit extends Unit { (units: Unit[]) => { getApp().getMap().centerOnUnit(units[0]); }, - { executeImmediately: true } + { executeImmediately: true, buttonColor: "green" } ); /* Context actions that require a target unit */ @@ -1845,7 +1851,8 @@ export abstract class AirUnit extends Unit { "unit", (units: Unit[], targetUnit: Unit | null, _) => { if (targetUnit) getApp().getUnitsManager().attackUnit(targetUnit.ID, units); - } + }, + { buttonColor: "blue" } ); contextActionSet.addContextAction( this, @@ -1865,7 +1872,8 @@ export abstract class AirUnit extends Unit { }) ); } - } + }, + { buttonColor: "purple" } ); /* Context actions that require a target position */ @@ -1878,7 +1886,8 @@ export abstract class AirUnit extends Unit { "position", (units: Unit[], _, targetPosition: LatLng | null) => { if (targetPosition) getApp().getUnitsManager().bombPoint(targetPosition, units); - } + }, + { buttonColor: "blue" } ); contextActionSet.addContextAction( this, @@ -1889,7 +1898,8 @@ export abstract class AirUnit extends Unit { "position", (units: Unit[], _, targetPosition: LatLng | null) => { if (targetPosition) getApp().getUnitsManager().carpetBomb(targetPosition, units); - } + }, + { buttonColor: "blue" } ); contextActionSet.addContextAction( @@ -1901,7 +1911,8 @@ export abstract class AirUnit extends Unit { "position", (units: Unit[], _, targetPosition: LatLng | null) => { if (targetPosition) getApp().getUnitsManager().landAt(targetPosition, units); - } + }, + { buttonColor: "purple" } ); } } @@ -1948,7 +1959,8 @@ export class Helicopter extends AirUnit { "position", (units: Unit[], _, targetPosition: LatLng | null) => { if (targetPosition) getApp().getUnitsManager().landAtPoint(targetPosition, units); - } + }, + { buttonColor: "purple" } ); } @@ -1997,7 +2009,7 @@ export class GroundUnit extends Unit { (units: Unit[], _1, _2) => { getApp().getUnitsManager().createGroup(units); }, - { executeImmediately: true } + { executeImmediately: true, buttonColor: "green" } ); contextActionSet.addContextAction( this, @@ -2009,7 +2021,7 @@ export class GroundUnit extends Unit { (units: Unit[]) => { getApp().getMap().centerOnUnit(units[0]); }, - { executeImmediately: true } + { executeImmediately: true, buttonColor: "green" } ); /* Context actions that require a target unit */ @@ -2022,7 +2034,8 @@ export class GroundUnit extends Unit { "unit", (units: Unit[], targetUnit: Unit | null, _) => { if (targetUnit) getApp().getUnitsManager().attackUnit(targetUnit.ID, units); - } + }, + { buttonColor: "blue" } ); /* Context actions that require a target position */ @@ -2036,7 +2049,8 @@ export class GroundUnit extends Unit { "position", (units: Unit[], _, targetPosition: LatLng | null) => { if (targetPosition) getApp().getUnitsManager().fireAtArea(targetPosition, units); - } + }, + { buttonColor: "blue" } ); contextActionSet.addContextAction( this, @@ -2047,7 +2061,8 @@ export class GroundUnit extends Unit { "position", (units: Unit[], _, targetPosition: LatLng | null) => { if (targetPosition) getApp().getUnitsManager().simulateFireFight(targetPosition, units); - } + }, + { buttonColor: "purple" } ); } } @@ -2139,7 +2154,7 @@ export class NavyUnit extends Unit { (units: Unit[], _1, _2) => { getApp().getUnitsManager().createGroup(units); }, - { executeImmediately: true } + { executeImmediately: true, buttonColor: "green" } ); contextActionSet.addContextAction( this, @@ -2151,7 +2166,7 @@ export class NavyUnit extends Unit { (units: Unit[]) => { getApp().getMap().centerOnUnit(units[0]); }, - { executeImmediately: true } + { executeImmediately: true, buttonColor: "green" } ); /* Context actions that require a target unit */ @@ -2160,11 +2175,12 @@ export class NavyUnit extends Unit { "attack", "Attack unit", "Click on a unit to attack it", - faQuestionCircle, + olButtonsContextAttack, "unit", (units: Unit[], targetUnit: Unit | null, _) => { if (targetUnit) getApp().getUnitsManager().attackUnit(targetUnit.ID, units); - } + }, + { buttonColor: "blue" } ); /* Context actions that require a target position */ @@ -2173,11 +2189,11 @@ export class NavyUnit extends Unit { "fire-at-area", "Fire at area", "Click on a point to precisely fire at it (if possible)", - faQuestionCircle, + faLocationCrosshairs, "position", (units: Unit[], _, targetPosition: LatLng | null) => { if (targetPosition) getApp().getUnitsManager().fireAtArea(targetPosition, units); - } + }, { buttonColor: "blue" } ); } diff --git a/frontend/react/src/unit/unitsmanager.ts b/frontend/react/src/unit/unitsmanager.ts index 98ef83f5..3cb965b8 100644 --- a/frontend/react/src/unit/unitsmanager.ts +++ b/frontend/react/src/unit/unitsmanager.ts @@ -381,11 +381,11 @@ export class UnitsManager { else unit.clearDestinations(); } else unit.clearDestinations(); } - - if (getApp().getMap().getOptions().protectDCSUnits && !units.every((unit) => unit.isControlledByOlympus())) - document.dispatchEvent(new CustomEvent("showProtectionPrompt", { detail: { callback: callback, units: units } })); - else callback(units); }; + + if (getApp().getMap().getOptions().protectDCSUnits && !units.every((unit) => unit.isControlledByOlympus())) + document.dispatchEvent(new CustomEvent("showProtectionPrompt", { detail: { callback: callback, units: units } })); + else callback(units); } /** Instruct all the selected units to land at a specific location