mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
feat: Implemented server mode
This commit is contained in:
73
frontend/react/src/ui/serveroverlay.tsx
Normal file
73
frontend/react/src/ui/serveroverlay.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { ServerStatusUpdatedEvent } from "../events";
|
||||
import { ServerStatus } from "../interfaces";
|
||||
import { FaCheck, FaXmark } from "react-icons/fa6";
|
||||
import { zeroAppend } from "../other/utils";
|
||||
|
||||
export function ServerOverlay() {
|
||||
const [serverStatus, setServerStatus] = useState({} as ServerStatus);
|
||||
|
||||
useEffect(() => {
|
||||
ServerStatusUpdatedEvent.on((status) => setServerStatus(status));
|
||||
}, []);
|
||||
|
||||
let loadColor = "#8BFF63";
|
||||
if (serverStatus.load > 1000) loadColor = "#F05252";
|
||||
else if (serverStatus.load >= 100 && serverStatus.load < 1000) loadColor = "#FF9900";
|
||||
|
||||
let frameRateColor = "#8BFF63";
|
||||
if (serverStatus.frameRate < 30) frameRateColor = "#F05252";
|
||||
else if (serverStatus.frameRate >= 30 && serverStatus.frameRate < 60) frameRateColor = "#FF9900";
|
||||
|
||||
|
||||
const MThours = serverStatus.missionTime? serverStatus.missionTime.h: 0;
|
||||
const MTminutes = serverStatus.missionTime? serverStatus.missionTime.m: 0;
|
||||
const MTseconds = serverStatus.missionTime? serverStatus.missionTime.s: 0;
|
||||
|
||||
const EThours = Math.floor((serverStatus.elapsedTime ?? 0) / 3600);
|
||||
const ETminutes = Math.floor((serverStatus.elapsedTime ?? 0) / 60) % 60;
|
||||
const ETseconds = Math.round(serverStatus.elapsedTime ?? 0) % 60;
|
||||
|
||||
let MTtimeString = `${zeroAppend(MThours, 2)}:${zeroAppend(MTminutes, 2)}:${zeroAppend(MTseconds, 2)}`;
|
||||
let ETtimeString = `${zeroAppend(EThours, 2)}:${zeroAppend(ETminutes, 2)}:${zeroAppend(ETseconds, 2)}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
absolute left-0 top-0 z-50 h-full w-full flex-col bg-olympus-900 p-5
|
||||
`}
|
||||
>
|
||||
<div className="flex-col content-center">
|
||||
<h2 className="mb-10 text-3xl font-bold text-white">DCS Olympus server</h2>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex gap-5 text-white">
|
||||
<div className="w-64">Connected to DCS:</div>
|
||||
<div>{serverStatus.connected? <FaCheck className={`
|
||||
text-xl text-green-500
|
||||
`}/> : <FaXmark className={`text-xl text-red-500`}/>}</div>
|
||||
</div>
|
||||
<div className="flex gap-5 text-white">
|
||||
<div className="w-64">Server load:</div>
|
||||
<div style={{color: loadColor}}>{serverStatus.load}</div>
|
||||
</div>
|
||||
<div className="flex gap-5 text-white">
|
||||
<div className="w-64">Server framerate:</div>
|
||||
<div style={{color: frameRateColor}}>{serverStatus.frameRate} fps</div>
|
||||
</div>
|
||||
<div className="flex gap-5 text-white">
|
||||
<div className="w-64">Elapsed time:</div>
|
||||
<div>{ETtimeString}</div>
|
||||
</div>
|
||||
<div className="flex gap-5 text-white">
|
||||
<div className="w-64">Mission local time:</div>
|
||||
<div>{MTtimeString}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<img src="./images/olympus-500x500.png" className={`
|
||||
absolute right-4 top-4 ml-auto flex h-24
|
||||
`}></img>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import { SpawnContextMenu } from "./contextmenus/spawncontextmenu";
|
||||
import { CoordinatesPanel } from "./panels/coordinatespanel";
|
||||
import { RadiosSummaryPanel } from "./panels/radiossummarypanel";
|
||||
import { AWACSMenu } from "./panels/awacsmenu";
|
||||
import { ServerOverlay } from "./serveroverlay";
|
||||
|
||||
export type OlympusUIState = {
|
||||
mainMenuVisible: boolean;
|
||||
@@ -58,7 +59,7 @@ export function UI() {
|
||||
|
||||
useEffect(() => {
|
||||
setupApp();
|
||||
})
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -67,50 +68,64 @@ export function UI() {
|
||||
font-sans
|
||||
`}
|
||||
>
|
||||
<Header />
|
||||
{appState !== OlympusState.SERVER && (
|
||||
<>
|
||||
<Header />
|
||||
</>
|
||||
)}
|
||||
<div className="flex h-full w-full flex-row-reverse">
|
||||
<LoginModal open={appState === OlympusState.LOGIN} />
|
||||
<ProtectionPromptModal open={appState === OlympusState.UNIT_CONTROL && appSubState == UnitControlSubState.PROTECTION} />
|
||||
<KeybindModal open={appState === OlympusState.OPTIONS && appSubState === OptionsSubstate.KEYBIND} />
|
||||
|
||||
{appState === OlympusState.SERVER && <ServerOverlay />}
|
||||
|
||||
{appState !== OlympusState.SERVER && (
|
||||
<>
|
||||
<LoginModal open={appState === OlympusState.LOGIN} />
|
||||
<ProtectionPromptModal open={appState === OlympusState.UNIT_CONTROL && appSubState == UnitControlSubState.PROTECTION} />
|
||||
<KeybindModal open={appState === OlympusState.OPTIONS && appSubState === OptionsSubstate.KEYBIND} />
|
||||
</>
|
||||
)}
|
||||
|
||||
<div id="map-container" className="z-0 h-full w-screen" />
|
||||
|
||||
<MainMenu open={appState === OlympusState.MAIN_MENU} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<SpawnMenu open={appState === OlympusState.SPAWN} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<OptionsMenu open={appState === OlympusState.OPTIONS} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<UnitControlMenu
|
||||
open={
|
||||
appState === OlympusState.UNIT_CONTROL &&
|
||||
![UnitControlSubState.FORMATION, UnitControlSubState.UNIT_EXPLOSION_MENU].includes(appSubState as UnitControlSubState)
|
||||
}
|
||||
onClose={() => getApp().setState(OlympusState.IDLE)}
|
||||
/>
|
||||
<FormationMenu
|
||||
open={appState === OlympusState.UNIT_CONTROL && appSubState === UnitControlSubState.FORMATION}
|
||||
onClose={() => getApp().setState(OlympusState.IDLE)}
|
||||
/>
|
||||
<DrawingMenu open={appState === OlympusState.DRAW} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<AirbaseMenu open={appState === OlympusState.AIRBASE} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<AudioMenu open={appState === OlympusState.AUDIO} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<GameMasterMenu open={appState === OlympusState.GAME_MASTER} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<UnitExplosionMenu
|
||||
open={appState === OlympusState.UNIT_CONTROL && appSubState === UnitControlSubState.UNIT_EXPLOSION_MENU}
|
||||
onClose={() => getApp().setState(OlympusState.IDLE)}
|
||||
/>
|
||||
{/*}<JTACMenu open={appState === OlympusState.JTAC} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
{appState !== OlympusState.SERVER && (
|
||||
<>
|
||||
<MainMenu open={appState === OlympusState.MAIN_MENU} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<SpawnMenu open={appState === OlympusState.SPAWN} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<OptionsMenu open={appState === OlympusState.OPTIONS} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<UnitControlMenu
|
||||
open={
|
||||
appState === OlympusState.UNIT_CONTROL &&
|
||||
![UnitControlSubState.FORMATION, UnitControlSubState.UNIT_EXPLOSION_MENU].includes(appSubState as UnitControlSubState)
|
||||
}
|
||||
onClose={() => getApp().setState(OlympusState.IDLE)}
|
||||
/>
|
||||
<FormationMenu
|
||||
open={appState === OlympusState.UNIT_CONTROL && appSubState === UnitControlSubState.FORMATION}
|
||||
onClose={() => getApp().setState(OlympusState.IDLE)}
|
||||
/>
|
||||
<DrawingMenu open={appState === OlympusState.DRAW} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<AirbaseMenu open={appState === OlympusState.AIRBASE} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<AudioMenu open={appState === OlympusState.AUDIO} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<GameMasterMenu open={appState === OlympusState.GAME_MASTER} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<UnitExplosionMenu
|
||||
open={appState === OlympusState.UNIT_CONTROL && appSubState === UnitControlSubState.UNIT_EXPLOSION_MENU}
|
||||
onClose={() => getApp().setState(OlympusState.IDLE)}
|
||||
/>
|
||||
{/*}<JTACMenu open={appState === OlympusState.JTAC} onClose={() => getApp().setState(OlympusState.IDLE)} />
|
||||
<AWACSMenu open={appState === OlympusState.AWACS} onClose={() => getApp().setState(OlympusState.IDLE)} />{*/}
|
||||
|
||||
<MiniMapPanel />
|
||||
<ControlsPanel />
|
||||
<CoordinatesPanel />
|
||||
<RadiosSummaryPanel />
|
||||
<MiniMapPanel />
|
||||
<ControlsPanel />
|
||||
<CoordinatesPanel />
|
||||
<RadiosSummaryPanel />
|
||||
|
||||
<SideBar />
|
||||
<InfoBar />
|
||||
<HotGroupBar />
|
||||
<SideBar />
|
||||
<InfoBar />
|
||||
<HotGroupBar />
|
||||
|
||||
<MapContextMenu />
|
||||
<SpawnContextMenu />
|
||||
<MapContextMenu />
|
||||
<SpawnContextMenu />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user