mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Added minimap summary panel
This commit is contained in:
parent
9c53e0605b
commit
a9a6b18943
@ -154,15 +154,9 @@ export const mapBounds = {
|
||||
"SinaiMap": { bounds: new LatLngBounds([34.312222, 28.523333], [25.946944, 36.897778]), zoom: 4 },
|
||||
}
|
||||
|
||||
export const DCSMapsZoomLevelsByTheatre: { [key: string]: { minNativeZoom?: number, maxNativeZoom?: number, minZoom?: number }[] } = {
|
||||
"Syria": [],
|
||||
"MarianaIslands": [{ minNativeZoom: 1, maxNativeZoom: 13, }, { minNativeZoom: 14, maxNativeZoom: 18, minZoom: 14 }],
|
||||
"Nevada": [],
|
||||
"PersianGulf": [],
|
||||
"Caucasus": [],
|
||||
"Falklands": [],
|
||||
"Normandy": [],
|
||||
"SinaiMap": [],
|
||||
export const mapMirrors = {
|
||||
"DCS Map mirror 1": "https://maps.dcsolympus.com/maps",
|
||||
"DCS Map mirror 2": "https://refugees.dcsolympus.com/maps"
|
||||
}
|
||||
|
||||
export const defaultMapLayers = {
|
||||
|
||||
16
frontend/react/src/dom.d.ts
vendored
16
frontend/react/src/dom.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
import { ServerStatus } from "./interfaces";
|
||||
import { Unit } from "./unit/unit";
|
||||
|
||||
interface CustomEventMap {
|
||||
@ -6,25 +7,16 @@ interface CustomEventMap {
|
||||
"unitsSelection": CustomEvent<Unit[]>,
|
||||
"unitsDeselection": CustomEvent<Unit[]>,
|
||||
"clearSelection": CustomEvent<any>,
|
||||
"unitCreation": CustomEvent<Unit>,
|
||||
"unitDeletion": CustomEvent<Unit>,
|
||||
"unitDeath": CustomEvent<Unit>,
|
||||
"unitUpdated": CustomEvent<Unit>,
|
||||
"unitMoveCommand": CustomEvent<Unit>,
|
||||
"unitAttackCommand": CustomEvent<Unit>,
|
||||
"unitLandCommand": CustomEvent<Unit>,
|
||||
"unitSetAltitudeCommand": CustomEvent<Unit>,
|
||||
"unitSetSpeedCommand": CustomEvent<Unit>,
|
||||
"unitSetOption": CustomEvent<Unit>,
|
||||
"groupCreation": CustomEvent<Unit[]>,
|
||||
"groupDeletion": CustomEvent<Unit[]>,
|
||||
"mapStateChanged": CustomEvent<string>,
|
||||
"mapContextMenu": CustomEvent<any>,
|
||||
"mapOptionChanged": CustomEvent<any>,
|
||||
"mapOptionsChanged": CustomEvent<any>,
|
||||
"mapOptionsChanged": CustomEvent<any>, // TODO not very clear, why the two options?
|
||||
"commandModeOptionsChanged": CustomEvent<any>,
|
||||
"contactsUpdated": CustomEvent<Unit>,
|
||||
"activeCoalitionChanged": CustomEvent<any>
|
||||
"activeCoalitionChanged": CustomEvent<any>,
|
||||
"serverStatusUpdated": CustomEvent<ServerStatus>
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@ -282,4 +282,13 @@ export interface ShortcutMouseOptions extends ShortcutOptions {
|
||||
|
||||
export interface Manager {
|
||||
add: CallableFunction;
|
||||
}
|
||||
|
||||
export interface ServerStatus {
|
||||
frameRate: number,
|
||||
load: number,
|
||||
elapsedTime: number,
|
||||
missionTime: DateAndTime["time"],
|
||||
connected: boolean,
|
||||
paused: boolean
|
||||
}
|
||||
@ -11,8 +11,7 @@ import { bearing, /*createCheckboxOption, createSliderInputOption, createTextInp
|
||||
import { DestinationPreviewMarker } from "./markers/destinationpreviewmarker";
|
||||
import { TemporaryUnitMarker } from "./markers/temporaryunitmarker";
|
||||
import { ClickableMiniMap } from "./clickableminimap";
|
||||
import { SVGInjector } from '@tanem/svg-injector'
|
||||
import { defaultMapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, MOVE_UNIT, SHOW_UNIT_CONTACTS, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, SHOW_UNIT_LABELS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, /*MAP_MARKER_CONTROLS,*/ DCS_LINK_PORT, DCSMapsZoomLevelsByTheatre, DCS_LINK_RATIO, MAP_OPTIONS_DEFAULTS, MAP_HIDDEN_TYPES_DEFAULTS, SPAWN_UNIT } from "../constants/constants";
|
||||
import { mapMirrors, defaultMapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, MOVE_UNIT, SHOW_UNIT_CONTACTS, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, SHOW_UNIT_LABELS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, /*MAP_MARKER_CONTROLS,*/ DCS_LINK_PORT, DCS_LINK_RATIO, MAP_OPTIONS_DEFAULTS, MAP_HIDDEN_TYPES_DEFAULTS, SPAWN_UNIT } from "../constants/constants";
|
||||
import { CoalitionArea } from "./coalitionarea/coalitionarea";
|
||||
//import { CoalitionAreaContextMenu } from "../contextmenus/coalitionareacontextmenu";
|
||||
import { DrawingCursor } from "./coalitionarea/drawingcursor";
|
||||
@ -133,7 +132,7 @@ export class Map extends L.Map {
|
||||
|
||||
this.#ID = ID;
|
||||
|
||||
this.setLayer("DCS Map");
|
||||
this.setLayer("DCS Map mirror 2");
|
||||
|
||||
/* Minimap */
|
||||
var minimapLayer = new L.TileLayer(this.#mapLayers[Object.keys(this.#mapLayers)[0]].urlTemplate, { minZoom: 0, maxZoom: 13 });
|
||||
@ -268,25 +267,39 @@ export class Map extends L.Map {
|
||||
} else {
|
||||
this.#layer = new L.TileLayer(layerData.urlTemplate, layerData);
|
||||
}
|
||||
/* DCS core layers are handled here */
|
||||
} else if (["DCS Map", "DCS Satellite"].includes(layerName)) {
|
||||
/* DCS core layers are handled here */
|
||||
} else if (["DCS Map mirror 1", "DCS Map mirror 2"].includes(layerName) ) {
|
||||
let layerData = this.#mapLayers["ArcGIS Satellite"];
|
||||
let layers = [new L.TileLayer(layerData.urlTemplate, layerData)];
|
||||
|
||||
let template = `https://maps.dcsolympus.com/maps/${layerName === "DCS Map" ? "alt" : "sat"}-{theatre}-modern/{z}/{x}/{y}.png`;
|
||||
layers.push(...DCSMapsZoomLevelsByTheatre[theatre].map((nativeZoomLevels: any) => {
|
||||
return new L.TileLayer(template.replace("{theatre}", theatre.toLowerCase()), { ...nativeZoomLevels, maxZoom: 20, crossOrigin: "" });
|
||||
}));
|
||||
|
||||
this.#layer = new L.LayerGroup(layers);
|
||||
/* Load the configuration file */
|
||||
const mirror = mapMirrors[layerName as keyof typeof mapMirrors];
|
||||
const request = new Request(mirror + "/config.json");
|
||||
fetch(request).then((response) => {
|
||||
if (response.status === 200) {
|
||||
return response.json();
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}).then((res: any) => {
|
||||
if ("alt-" + theatre.toLowerCase() in res) {
|
||||
let template = `${mirror}/alt-${theatre.toLowerCase()}/{z}/{x}/{y}.png`;
|
||||
layers.push(...res["alt-" + theatre.toLowerCase()].map((layerConfig: any) => {
|
||||
return new L.TileLayer(template, {...layerConfig, crossOrigin: ""});
|
||||
}));
|
||||
}
|
||||
this.#layer = new L.LayerGroup(layers);
|
||||
this.#layer?.addTo(this);
|
||||
}).catch(() => {
|
||||
this.#layer = new L.LayerGroup(layers);
|
||||
this.#layer?.addTo(this);
|
||||
})
|
||||
}
|
||||
|
||||
this.#layer?.addTo(this);
|
||||
this.#layerName = layerName;
|
||||
}
|
||||
|
||||
getLayers() {
|
||||
let layers = ["DCS Map", "DCS Satellite"]
|
||||
let layers = ["DCS Map mirror 1", "DCS Map mirror 2"];
|
||||
layers.push(...Object.keys(this.#mapLayers));
|
||||
return layers;
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@ export class MissionManager {
|
||||
#airbases: { [name: string]: Airbase } = {};
|
||||
#theatre: string = "";
|
||||
#dateAndTime: DateAndTime = {date: {Year: 0, Month: 0, Day: 0}, time: {h: 0, m: 0, s: 0}, startTime: 0, elapsedTime: 0};
|
||||
#load: number = 0;
|
||||
#frameRate: number = 0;
|
||||
#commandModeOptions: CommandModeOptions = {commandMode: NONE, restrictSpawns: false, restrictToCoalition: false, setupTime: Infinity, spawnPoints: {red: Infinity, blue: Infinity}, eras: []};
|
||||
#remainingSetupTime: number = 0;
|
||||
#spentSpawnPoint: number = 0;
|
||||
@ -212,6 +214,22 @@ export class MissionManager {
|
||||
this.refreshSpawnPoints();
|
||||
}
|
||||
|
||||
setLoad(load: number) {
|
||||
this.#load = load;
|
||||
}
|
||||
|
||||
getLoad() {
|
||||
return this.#load;
|
||||
}
|
||||
|
||||
setFrameRate(frameRate: number) {
|
||||
this.#frameRate = frameRate;
|
||||
}
|
||||
|
||||
getFrameRate() {
|
||||
return this.#frameRate;
|
||||
}
|
||||
|
||||
showCommandModeDialog() {
|
||||
//const options = this.getCommandModeOptions()
|
||||
//const { restrictSpawns, restrictToCoalition, setupTime } = options;
|
||||
|
||||
@ -5,8 +5,9 @@ import { AIRBASES_URI, BULLSEYE_URI, COMMANDS_URI, LOGS_URI, MISSION_URI, NONE,
|
||||
//import { LogPanel } from '../panels/logpanel';
|
||||
//import { Popup } from '../popups/popup';
|
||||
//import { ConnectionStatusPanel } from '../panels/connectionstatuspanel';
|
||||
import { AirbasesData, BullseyesData, GeneralSettings, MissionData, Radio, ServerRequestOptions, TACAN } from '../interfaces';
|
||||
import { AirbasesData, BullseyesData, GeneralSettings, MissionData, Radio, ServerRequestOptions, ServerStatus, TACAN } from '../interfaces';
|
||||
import { zeroAppend } from '../other/utils';
|
||||
import { SiTheregister } from 'react-icons/si';
|
||||
|
||||
export class ServerManager {
|
||||
#connected: boolean = false;
|
||||
@ -80,8 +81,10 @@ export class ServerManager {
|
||||
const result = JSON.parse(xmlHttp.responseText);
|
||||
this.#lastUpdateTimes[uri] = callback(result);
|
||||
|
||||
//if (result.frameRate !== undefined && result.load !== undefined)
|
||||
// (getApp().getPanelsManager().get("serverStatus") as ServerStatusPanel).update(result.frameRate, result.load);
|
||||
if (result.frameRate !== undefined && result.load !== undefined) {
|
||||
getApp().getMissionManager().setLoad(result.load);
|
||||
getApp().getMissionManager().setFrameRate(result.frameRate);
|
||||
}
|
||||
}
|
||||
} else if (xmlHttp.status == 401) {
|
||||
/* Bad credentials */
|
||||
@ -489,40 +492,25 @@ export class ServerManager {
|
||||
var time = getApp().getUnitsManager()?.update(buffer);
|
||||
return time;
|
||||
}, true);
|
||||
|
||||
const elapsedMissionTime = getApp().getMissionManager().getDateAndTime().elapsedTime;
|
||||
this.#serverIsPaused = (elapsedMissionTime === this.#previousMissionElapsedTime);
|
||||
this.#previousMissionElapsedTime = elapsedMissionTime;
|
||||
|
||||
//const csp = (getApp().getPanelsManager().get("connectionStatus") as ConnectionStatusPanel);
|
||||
|
||||
//if (this.getConnected()) {
|
||||
// if (this.getServerIsPaused()) {
|
||||
// csp.showServerPaused();
|
||||
// } else {
|
||||
// csp.showConnected();
|
||||
// }
|
||||
//} else {
|
||||
// csp.showDisconnected();
|
||||
//}
|
||||
|
||||
}
|
||||
}, (this.getServerIsPaused() ? 500 : 5000)));
|
||||
|
||||
// Mission clock and elapsed time
|
||||
this.#intervals.push(window.setInterval(() => {
|
||||
|
||||
if (!this.getConnected() || this.#serverIsPaused) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elapsedMissionTime = getApp().getMissionManager().getDateAndTime().elapsedTime;
|
||||
|
||||
//const csp = (getApp().getPanelsManager().get("connectionStatus") as ConnectionStatusPanel);
|
||||
//const mt = getApp().getMissionManager().getDateAndTime().time;
|
||||
|
||||
//csp.setMissionTime([mt.h, mt.m, mt.s].map(n => zeroAppend(n, 2)).join(":"));
|
||||
//csp.setElapsedTime(new Date(elapsedMissionTime * 1000).toISOString().substring(11, 19));
|
||||
this.#serverIsPaused = (elapsedMissionTime === this.#previousMissionElapsedTime);
|
||||
this.#previousMissionElapsedTime = elapsedMissionTime;
|
||||
|
||||
document.dispatchEvent(new CustomEvent("serverStatusUpdated", {
|
||||
detail: {
|
||||
frameRate: getApp().getMissionManager().getFrameRate(),
|
||||
load: getApp().getMissionManager().getLoad(),
|
||||
elapsedTime: getApp().getMissionManager().getDateAndTime().elapsedTime,
|
||||
missionTime: getApp().getMissionManager().getDateAndTime().time,
|
||||
connected: this.getConnected(),
|
||||
paused: this.getPaused()
|
||||
} as ServerStatus
|
||||
}));
|
||||
|
||||
}, 1000));
|
||||
|
||||
|
||||
79
frontend/react/src/ui/panels/minimappanel.tsx
Normal file
79
frontend/react/src/ui/panels/minimappanel.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { zeroAppend } from "../../other/utils";
|
||||
import { DateAndTime } from "../../interfaces";
|
||||
|
||||
export function MiniMapPanel(props: {
|
||||
|
||||
}) {
|
||||
var [frameRate, setFrameRate] = useState(0);
|
||||
var [load, setLoad] = useState(0);
|
||||
var [elapsedTime, setElapsedTime] = useState(0);
|
||||
var [missionTime, setMissionTime] = useState({ h: 0, m: 0, s: 0 } as DateAndTime["time"]);
|
||||
var [connected, setConnected] = useState(false);
|
||||
var [paused, setPaused] = useState(false);
|
||||
var [showMissionTime, setShowMissionTime] = useState(false);
|
||||
|
||||
document.addEventListener("serverStatusUpdated", (ev) => {
|
||||
setFrameRate(ev.detail.frameRate);
|
||||
setLoad(ev.detail.load);
|
||||
setElapsedTime(ev.detail.elapsedTime);
|
||||
setMissionTime(ev.detail.missionTime);
|
||||
setConnected(ev.detail.connected);
|
||||
setPaused(ev.detail.paused);
|
||||
})
|
||||
|
||||
// A bit of a hack to set the rounded borders to the minimap
|
||||
useEffect(() => {
|
||||
let miniMap = document.querySelector(".leaflet-control-minimap");
|
||||
if (miniMap) {
|
||||
miniMap.classList.add("rounded-t-lg")
|
||||
}
|
||||
})
|
||||
|
||||
// Compute the time string depending on mission or elapsed time
|
||||
let hours = 0;
|
||||
let minutes = 0;
|
||||
let seconds = 0;
|
||||
|
||||
if (showMissionTime) {
|
||||
hours = missionTime.h;
|
||||
minutes = missionTime.m;
|
||||
seconds = missionTime.s;
|
||||
} else {
|
||||
hours = Math.floor(elapsedTime / 3600);
|
||||
minutes = Math.floor((elapsedTime / 60)) % 60;
|
||||
seconds = Math.round(elapsedTime) % 60;
|
||||
}
|
||||
|
||||
let timeString = `${zeroAppend(hours, 2)}:${zeroAppend(minutes, 2)}:${zeroAppend(seconds, 2)}`
|
||||
|
||||
// Choose frame rate string color
|
||||
let frameRateColor = "#8BFF63";
|
||||
if (frameRate < 30)
|
||||
frameRateColor = "#F05252";
|
||||
else if (frameRate >= 30 && frameRate < 60)
|
||||
frameRateColor = "#FF9900"
|
||||
|
||||
// Choose load string color
|
||||
let loadColor = "#8BFF63";
|
||||
if (load > 1000)
|
||||
loadColor = "#F05252";
|
||||
else if (load >= 100 && load < 1000)
|
||||
loadColor = "#FF9900"
|
||||
|
||||
return <div onClick={() => setShowMissionTime(!showMissionTime)} className="absolute w-[288px] top-[233px] right-[10px] z-ui-0 text-sm dark:text-gray-200 bg-gray-200 dark:bg-olympus-800/90 backdrop-blur-lg backdrop-grayscale flex items-center justify-between p-3 rounded-b-lg">
|
||||
{
|
||||
!connected ?
|
||||
<div className="font-semibold animate-pulse flex items-center gap-2"><div className="bg-[#F05252] relative w-4 h-4 rounded-full"></div>Server disconnected</div> :
|
||||
paused ?
|
||||
<div className="font-semibold animate-pulse flex items-center gap-2"><div className="bg-[#FF9900] relative w-4 h-4 rounded-full"></div>Server paused</div> :
|
||||
<>
|
||||
<div className="font-semibold">FPS: <span style={{ 'color': frameRateColor }} className="font-semibold">{frameRate}</span> </div>
|
||||
<div className="font-semibold">Load: <span style={{ 'color': loadColor }} className="font-semibold">{load}</span> </div>
|
||||
<div className="font-semibold">{showMissionTime ? "MT" : "ET"}: {timeString} </div>
|
||||
<div className="bg-[#8BFF63] relative w-4 h-4 rounded-full"></div>
|
||||
</>
|
||||
}
|
||||
|
||||
</div>
|
||||
}
|
||||
@ -15,6 +15,7 @@ import { BLUE_COMMANDER, GAME_MASTER, MAP_HIDDEN_TYPES_DEFAULTS, MAP_OPTIONS_DEF
|
||||
import { getApp, setupApp } from '../olympusapp'
|
||||
import { LoginModal } from './modals/login'
|
||||
import { sha256 } from 'js-sha256'
|
||||
import { MiniMapPanel } from './panels/minimappanel'
|
||||
|
||||
export type OlympusState = {
|
||||
mainMenuVisible: boolean,
|
||||
@ -141,10 +142,12 @@ export function UI() {
|
||||
open={optionsMenuVisible}
|
||||
onClose={() => setOptionsMenuVisible(false)}
|
||||
/>
|
||||
<MiniMapPanel />
|
||||
<UnitControlMenu />
|
||||
<div id='map-container' className='h-full w-screen' />
|
||||
</div>
|
||||
</div>
|
||||
<div id='map-container' className='fixed h-full w-screen top-0 left-0' />
|
||||
|
||||
</EventsProvider>
|
||||
</StateProvider>
|
||||
</div>
|
||||
|
||||
@ -343,7 +343,7 @@ export class Map extends L.Map {
|
||||
}
|
||||
|
||||
getLayers() {
|
||||
let layers = ["DCS Map mirror 1", "DCS Map mirror 2"]
|
||||
let layers = ["DCS Map mirror 1", "DCS Map mirror 2"];
|
||||
layers.push(...Object.keys(this.#mapLayers));
|
||||
return layers;
|
||||
}
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "v1.0.4"
|
||||
"version": "v2.0.0"
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user