mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
feat: added laser code change, target move, and delete
Note: deleted lasers are not removed from table and keep being drawn. Also added a cooler looking server page
This commit is contained in:
@@ -4,12 +4,26 @@ import { ServerStatus } from "../interfaces";
|
||||
import { FaCheck, FaXmark } from "react-icons/fa6";
|
||||
import { zeroAppend } from "../other/utils";
|
||||
import { colors } from "../constants/constants";
|
||||
import { CircularProgressbar, buildStyles } from "react-circular-progressbar";
|
||||
import "react-circular-progressbar/dist/styles.css";
|
||||
import { Line } from "react-chartjs-2";
|
||||
import { Chart, LineElement, LinearScale, Title, CategoryScale, Legend, PointElement } from "chart.js";
|
||||
|
||||
Chart.register(LineElement, LinearScale, Title, CategoryScale, Legend, PointElement);
|
||||
|
||||
export function ServerOverlay() {
|
||||
const [serverStatus, setServerStatus] = useState({} as ServerStatus);
|
||||
const [loadData, setLoadData] = useState<number[]>([]);
|
||||
const [frameRateData, setFrameRateData] = useState<number[]>([]);
|
||||
const [timeLabels, setTimeLabels] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
ServerStatusUpdatedEvent.on((status) => setServerStatus(status));
|
||||
ServerStatusUpdatedEvent.on((status) => {
|
||||
setServerStatus(status);
|
||||
setLoadData((prevData) => [...prevData, status.load].slice(-300));
|
||||
setFrameRateData((prevData) => [...prevData, status.frameRate].slice(-300));
|
||||
setTimeLabels((prevLabels) => [...prevLabels, new Date().toLocaleTimeString()].slice(-300));
|
||||
});
|
||||
}, []);
|
||||
|
||||
let loadColor = colors.OLYMPUS_GREEN;
|
||||
@@ -20,9 +34,9 @@ export function ServerOverlay() {
|
||||
if (serverStatus.frameRate < 30) frameRateColor = colors.OLYMPUS_RED;
|
||||
else if (serverStatus.frameRate >= 30 && serverStatus.frameRate < 60) frameRateColor = colors.OLYMPUS_ORANGE;
|
||||
|
||||
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 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;
|
||||
@@ -31,43 +45,136 @@ export function ServerOverlay() {
|
||||
let MTtimeString = `${zeroAppend(MThours, 2)}:${zeroAppend(MTminutes, 2)}:${zeroAppend(MTseconds, 2)}`;
|
||||
let ETtimeString = `${zeroAppend(EThours, 2)}:${zeroAppend(ETminutes, 2)}:${zeroAppend(ETseconds, 2)}`;
|
||||
|
||||
const missionTime = new Date();
|
||||
missionTime.setHours(MThours);
|
||||
missionTime.setMinutes(MTminutes);
|
||||
missionTime.setSeconds(MTseconds);
|
||||
|
||||
const data = {
|
||||
labels: timeLabels,
|
||||
datasets: [
|
||||
{
|
||||
label: "Server Load",
|
||||
data: loadData,
|
||||
borderColor: colors.LIGHT_BLUE,
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
pointRadius: 0,
|
||||
yAxisID: "y-load", // Specify the y-axis for load
|
||||
},
|
||||
{
|
||||
label: "Server Framerate",
|
||||
data: frameRateData,
|
||||
borderColor: colors.WHITE,
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
pointRadius: 0,
|
||||
yAxisID: "y-framerate", // Specify the y-axis for framerate
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const options = {
|
||||
animation: false,
|
||||
responsive: true,
|
||||
scales: {
|
||||
x: {
|
||||
type: "category",
|
||||
labels: timeLabels,
|
||||
},
|
||||
"y-framerate": {
|
||||
type: "linear",
|
||||
position: "left",
|
||||
beginAtZero: true,
|
||||
max: 120, // Max value for framerate
|
||||
},
|
||||
"y-load": {
|
||||
type: "linear",
|
||||
position: "right",
|
||||
beginAtZero: true,
|
||||
max: 2000, // Max value for load
|
||||
grid: {
|
||||
drawOnChartArea: false, // Only want the grid lines for one axis to show up
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: "top",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
absolute left-0 top-0 z-50 h-full w-full flex-col bg-olympus-900 p-5
|
||||
absolute left-0 top-0 z-50 flex h-full w-full flex-col bg-black
|
||||
bg-opacity-80 p-5 backdrop-blur-sm animate-fadeIn
|
||||
`}
|
||||
>
|
||||
<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
|
||||
className={`
|
||||
m-auto flex w-3/4 max-w-4xl flex-col items-center rounded-lg bg-white
|
||||
bg-opacity-10 p-5 shadow-lg animate-slideIn
|
||||
`}
|
||||
>
|
||||
<h2 className="mb-5 text-4xl font-bold text-white drop-shadow-lg">DCS Olympus Server</h2>
|
||||
<div className="flex w-full gap-12">
|
||||
<div className="flex w-72 flex-col gap-4 text-lg text-white">
|
||||
<div className="flex justify-between">
|
||||
<div className="font-semibold">Connected to DCS:</div>
|
||||
<div>{serverStatus.connected ? <FaCheck className={`
|
||||
text-2xl text-green-500
|
||||
`} /> : <FaXmark className={`text-2xl text-red-500`} />}</div>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<div className="font-semibold">Elapsed time:</div>
|
||||
<div>{ETtimeString}</div>
|
||||
</div>
|
||||
<div className="flex justify-between">
|
||||
<div className="font-semibold">Mission local time:</div>
|
||||
<div>{MTtimeString}</div>
|
||||
</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 className="flex items-center justify-between gap-5 text-white">
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="mb-2 font-semibold">Load</div>
|
||||
<div className="h-24 w-24">
|
||||
<CircularProgressbar
|
||||
value={serverStatus.load}
|
||||
maxValue={2000}
|
||||
text={`${serverStatus.load}`}
|
||||
styles={buildStyles({
|
||||
textColor: loadColor,
|
||||
pathColor: loadColor,
|
||||
trailColor: "rgba(255, 255, 255, 0.2)",
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="mb-2 font-semibold">Framerate</div>
|
||||
<div className="h-24 w-24">
|
||||
<CircularProgressbar
|
||||
value={serverStatus.frameRate}
|
||||
maxValue={120}
|
||||
text={`${serverStatus.frameRate} fps`}
|
||||
styles={buildStyles({
|
||||
textColor: frameRateColor,
|
||||
pathColor: frameRateColor,
|
||||
trailColor: "rgba(255, 255, 255, 0.2)",
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-10 w-full flex-1">
|
||||
{/* @ts-ignore */}
|
||||
<Line data={data} options={options} />
|
||||
</div>
|
||||
</div>
|
||||
<img src="images/olympus-500x500.png" className={`
|
||||
absolute right-4 top-4 ml-auto flex h-24
|
||||
`}></img>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -121,4 +121,32 @@ input[type="range"]:focus::-moz-range-thumb {
|
||||
100% {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bouncing-ball {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: transparent;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
animation: bounce 2s infinite;
|
||||
}
|
||||
|
||||
.ball-logo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 20%, 50%, 80%, 100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
40% {
|
||||
transform: translateY(-150px);
|
||||
}
|
||||
60% {
|
||||
transform: translateY(-75px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,7 @@ import { MainMenu } from "./panels/mainmenu";
|
||||
import { SideBar } from "./panels/sidebar";
|
||||
import { OptionsMenu } from "./panels/optionsmenu";
|
||||
import { MapHiddenTypes, MapOptions } from "../types/types";
|
||||
import {
|
||||
NO_SUBSTATE,
|
||||
OlympusState,
|
||||
OlympusSubState,
|
||||
OptionsSubstate,
|
||||
UnitControlSubState
|
||||
} from "../constants/constants";
|
||||
import { NO_SUBSTATE, OlympusState, OlympusSubState, OptionsSubstate, UnitControlSubState } from "../constants/constants";
|
||||
import { getApp, setupApp } from "../olympusapp";
|
||||
import { LoginModal } from "./modals/loginmodal";
|
||||
|
||||
@@ -30,7 +24,7 @@ import { ProtectionPromptModal } from "./modals/protectionpromptmodal";
|
||||
import { KeybindModal } from "./modals/keybindmodal";
|
||||
import { UnitExplosionMenu } from "./panels/unitexplosionmenu";
|
||||
import { JTACMenu } from "./panels/jtacmenu";
|
||||
import { AppStateChangedEvent } from "../events";
|
||||
import { AppStateChangedEvent, ServerStatusUpdatedEvent } from "../events";
|
||||
import { GameMasterMenu } from "./panels/gamemastermenu";
|
||||
import { InfoBar } from "./panels/infobar";
|
||||
import { HotGroupBar } from "./panels/hotgroupsbar";
|
||||
@@ -41,6 +35,7 @@ import { AWACSMenu } from "./panels/awacsmenu";
|
||||
import { ServerOverlay } from "./serveroverlay";
|
||||
import { ImportExportModal } from "./modals/importexportmodal";
|
||||
import { WarningModal } from "./modals/warningmodal";
|
||||
import { ServerStatus } from "../interfaces";
|
||||
|
||||
export type OlympusUIState = {
|
||||
mainMenuVisible: boolean;
|
||||
@@ -57,12 +52,19 @@ export type OlympusUIState = {
|
||||
export function UI() {
|
||||
const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED);
|
||||
const [appSubState, setAppSubState] = useState(NO_SUBSTATE as OlympusSubState);
|
||||
const [serverStatus, setServerStatus] = useState({} as ServerStatus);
|
||||
const [connectedOnce, setConnectedOnce] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
AppStateChangedEvent.on((state, subState) => {
|
||||
setAppState(state);
|
||||
setAppSubState(subState);
|
||||
});
|
||||
ServerStatusUpdatedEvent.on((status) => {
|
||||
// If we connected at least once, record it
|
||||
if (status.connected) setConnectedOnce(true);
|
||||
setServerStatus(status);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -76,11 +78,7 @@ export function UI() {
|
||||
font-sans
|
||||
`}
|
||||
>
|
||||
{appState !== OlympusState.SERVER && (
|
||||
<>
|
||||
<Header />
|
||||
</>
|
||||
)}
|
||||
{appState !== OlympusState.SERVER && <Header />}
|
||||
<div className="flex h-full w-full flex-row-reverse">
|
||||
{appState === OlympusState.SERVER && <ServerOverlay />}
|
||||
|
||||
@@ -138,6 +136,45 @@ export function UI() {
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{!serverStatus.connected && appState !== OlympusState.LOGIN && (
|
||||
<div
|
||||
className={`
|
||||
absolute left-0 top-0 z-50 flex h-screen w-screen items-center
|
||||
justify-center bg-gray-900 bg-opacity-80 text-white backdrop-blur-sm
|
||||
`}
|
||||
>
|
||||
<div className="flex flex-col items-center justify-center gap-4">
|
||||
<div className="bouncing-ball">
|
||||
<img
|
||||
src="images/olympus-500x500.png"
|
||||
alt="Olympus Logo"
|
||||
className={`ball-logo`}
|
||||
/>
|
||||
</div>
|
||||
{!connectedOnce && <div>Establishing connection</div>}
|
||||
{connectedOnce && <div>Connection lost</div>}
|
||||
{!connectedOnce && <div className="text-gray-400">Trying to connect with the server, please wait...</div>}
|
||||
{connectedOnce && (
|
||||
<div className="text-gray-400">
|
||||
Try reloading this page. However, this usually means that you internet connection is down, or that the server is offline, paused, or loading a
|
||||
new mission.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{appState === OlympusState.NOT_INITIALIZED && (
|
||||
<div
|
||||
className={`
|
||||
absolute left-0 top-0 z-50 flex h-screen w-screen items-center
|
||||
justify-center bg-gray-900 text-white
|
||||
`}
|
||||
>
|
||||
Loading...
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user