import React, { useEffect, useRef, useState } from "react"; import { OlRoundStateButton, OlStateButton, OlLockStateButton } from "../components/olstatebutton"; import { faSkull, faCamera, faFlag, faVolumeHigh, faDrawPolygon, faTriangleExclamation, faWifi, faObjectGroup } from "@fortawesome/free-solid-svg-icons"; import { OlDropdownItem, OlDropdown } from "../components/oldropdown"; import { OlLabelToggle } from "../components/ollabeltoggle"; import { getApp, IP, VERSION } from "../../olympusapp"; import { olButtonsVisibilityAirbase, olButtonsVisibilityAircraft, olButtonsVisibilityDcs, olButtonsVisibilityGroundunit, olButtonsVisibilityGroundunitSam, olButtonsVisibilityHelicopter, olButtonsVisibilityHuman, olButtonsVisibilityNavyunit, olButtonsVisibilityOlympus, } from "../components/olicons"; import { FaChevronLeft, FaChevronRight, FaFloppyDisk } from "react-icons/fa6"; import { CommandModeOptionsChangedEvent, ConfigLoadedEvent, EnabledCommandModesChangedEvent, HiddenTypesChangedEvent, MapOptionsChangedEvent, MapSourceChangedEvent, SessionDataChangedEvent, SessionDataSavedEvent, } from "../../events"; import { BLUE_COMMANDER, COMMAND_MODE_OPTIONS_DEFAULTS, GAME_MASTER, LoginSubState, MAP_HIDDEN_TYPES_DEFAULTS, MAP_OPTIONS_DEFAULTS, OlympusState, RED_COMMANDER, } from "../../constants/constants"; import { OlympusConfig } from "../../interfaces"; import { FaCheck, FaRedo, FaSpinner } from "react-icons/fa"; import { OlExpandingTooltip } from "../components/olexpandingtooltip"; export function Header() { const [mapHiddenTypes, setMapHiddenTypes] = useState(MAP_HIDDEN_TYPES_DEFAULTS); const [mapOptions, setMapOptions] = useState(MAP_OPTIONS_DEFAULTS); const [mapSource, setMapSource] = useState(""); const [mapSources, setMapSources] = useState([] as string[]); const [scrolledLeft, setScrolledLeft] = useState(true); const [scrolledRight, setScrolledRight] = useState(false); const [audioEnabled, setAudioEnabled] = useState(false); const [commandModeOptions, setCommandModeOptions] = useState(COMMAND_MODE_OPTIONS_DEFAULTS); const [savingSessionData, setSavingSessionData] = useState(false); const [latestVersion, setLatestVersion] = useState(""); const [isLatestVersion, setIsLatestVersion] = useState(false); const [isBetaVersion, setIsBetaVersion] = useState(false); const [isDevVersion, setIsDevVersion] = useState(false); const [enabledCommandModes, setEnabledCommandModes] = useState([] as string[]); const [loadingNewCommandMode, setLoadingNewCommandMode] = useState(false); useEffect(() => { HiddenTypesChangedEvent.on((hiddenTypes) => setMapHiddenTypes({ ...hiddenTypes })); MapOptionsChangedEvent.on((mapOptions) => { setMapOptions({ ...mapOptions }); }); MapSourceChangedEvent.on((source) => setMapSource(source)); ConfigLoadedEvent.on((config: OlympusConfig) => { // Timeout needed to make sure the map configuration has updated window.setTimeout(() => { var sources = Object.keys(getApp().getMap().getMirrors()).concat(getApp().getMap().getLayers()); setMapSources(sources); }, 200); }); CommandModeOptionsChangedEvent.on((commandModeOptions) => { setCommandModeOptions(commandModeOptions); setLoadingNewCommandMode(false); }); SessionDataChangedEvent.on(() => setSavingSessionData(true)); SessionDataSavedEvent.on(() => setSavingSessionData(false)); EnabledCommandModesChangedEvent.on((enabledCommandModes) => setEnabledCommandModes(enabledCommandModes)); /* Check if we are running the latest version */ const request = new Request("https://raw.githubusercontent.com/Pax1601/DCSOlympus/main/version.json"); fetch(request) .then((response) => { if (response.status === 200) { return response.json(); } else { throw new Error("Error connecting to Github to retrieve latest version"); } }) .then((res) => { setLatestVersion(res["version"]); if (VERSION === "{{OLYMPUS_VERSION_NUMBER}}") { console.log("OLYMPUS_VERSION_NUMBER is not set. Skipping version check."); setIsDevVersion(true); } else { setIsDevVersion(false); /* Check if the new version is newer than the current one */ /* Extract the version numbers */ const currentVersion = VERSION.replace("v", "").split("."); const newVersion = res["version"].replace("v", "").split("."); setIsBetaVersion(true); setIsLatestVersion(true); /* Compare the version numbers */ for (var i = 0; i < currentVersion.length; i++) { if (parseInt(newVersion[i]) > parseInt(currentVersion[i])) { setIsLatestVersion(false); } } /* Check if this is a beta version checking if this version is newer */ for (var i = 0; i < currentVersion.length; i++) { if (parseInt(newVersion[i]) < parseInt(currentVersion[i])) { setIsBetaVersion(false); } } } }); }, []); /* Initialize the "scroll" position of the element */ var scrollRef = useRef(null); useEffect(() => { if (scrollRef.current) onScroll(scrollRef.current); }); function onScroll(el) { const sl = el.scrollLeft; const sr = el.scrollWidth - el.scrollLeft - el.clientWidth; sl < 1 && !scrolledLeft && setScrolledLeft(true); sl > 1 && scrolledLeft && setScrolledLeft(false); sr < 1 && !scrolledRight && setScrolledRight(true); sr > 1 && scrolledRight && setScrolledRight(false); } return (
{ if (scrollRef.current) { if (e.deltaY > 0) (scrollRef.current as HTMLElement).scrollLeft += 100; else (scrollRef.current as HTMLElement).scrollLeft -= 100; } }} > {!scrolledLeft && ( )}
onScroll(ev.target)} ref={scrollRef} > {commandModeOptions.commandMode === GAME_MASTER && (
{ if (enabledCommandModes.length > 0) { let blueCommandModeIndex = enabledCommandModes.indexOf(BLUE_COMMANDER); let redCommandModeIndex = enabledCommandModes.indexOf(RED_COMMANDER); if (blueCommandModeIndex >= 0) getApp().getServerManager().setActiveCommandMode(BLUE_COMMANDER); else if (redCommandModeIndex >= 0) getApp().getServerManager().setActiveCommandMode(RED_COMMANDER); setLoadingNewCommandMode(true); } }} > Game Master {enabledCommandModes.length > 0 && ( <>{loadingNewCommandMode ? : } )}
)} {commandModeOptions.commandMode === BLUE_COMMANDER && (
{ if (enabledCommandModes.length > 0) { let gameMasterCommandModeIndex = enabledCommandModes.indexOf(GAME_MASTER); let redCommandModeIndex = enabledCommandModes.indexOf(RED_COMMANDER); if (redCommandModeIndex >= 0) getApp().getServerManager().setActiveCommandMode(RED_COMMANDER); else if (gameMasterCommandModeIndex >= 0) getApp().getServerManager().setActiveCommandMode(GAME_MASTER); setLoadingNewCommandMode(true); } }} > BLUE Commander {enabledCommandModes.length > 0 && ( <>{loadingNewCommandMode ? : } )}
)} {commandModeOptions.commandMode === RED_COMMANDER && (
{ if (enabledCommandModes.length > 0) { let gameMasterCommandModeIndex = enabledCommandModes.indexOf(GAME_MASTER); let blueCommandModeIndex = enabledCommandModes.indexOf(BLUE_COMMANDER); if (gameMasterCommandModeIndex >= 0) getApp().getServerManager().setActiveCommandMode(GAME_MASTER); else if (blueCommandModeIndex >= 0) getApp().getServerManager().setActiveCommandMode(BLUE_COMMANDER); setLoadingNewCommandMode(true); } }} > RED Commander {enabledCommandModes.length > 0 && ( <>{loadingNewCommandMode ? : } )}
)}
{ getApp().getMap().setOption("protectDCSUnits", !mapOptions.protectDCSUnits); }} tooltip={() => (

By default, Mission Editor units are protected from being commanded or deleted. This option allows you to unlock them, so they can be commanded or deleted like any other unit.{" "}

If units are protected, you will still be able to control them, but a prompt will be shown to require your confirmation.

Once a unit has been commanded, it will be unlocked and will become an Olympus unit, completely abandoning its previuos mission.

} /> )} /> { audioEnabled ? getApp().getAudioManager().stop() : getApp().getAudioManager().start(); setAudioEnabled(!audioEnabled); }} tooltip={() => (

If this option is enabled, you will be able to access the radio and audio features of DCS Olympus.

For this to work, a SRS Server need to be installed and running on the same machine on which the DCS Olympus server is running.

For security reasons, this feature will only work if a secure connection (i.e., using https) is established with the server. It is also suggested to use Google Chrome for optimal compatibility.{" "}

} /> )} icon={faVolumeHigh} />
{Object.entries({ human: olButtonsVisibilityHuman, olympus: olButtonsVisibilityOlympus, dcs: olButtonsVisibilityDcs, }).map((entry) => { return ( { getApp().getMap().setHiddenType(entry[0], !mapHiddenTypes[entry[0]]); }} checked={!mapHiddenTypes[entry[0]]} icon={entry[1]} tooltip={"Hide/show " + entry[0] + " units"} /> ); })}
getApp().getMap().setHiddenType("blue", !mapHiddenTypes["blue"])} checked={!mapHiddenTypes["blue"]} icon={faFlag} className={"!text-blue-500"} tooltip={"Hide/show blue units"} /> getApp().getMap().setHiddenType("red", !mapHiddenTypes["red"])} checked={!mapHiddenTypes["red"]} icon={faFlag} className={"!text-red-500"} tooltip={"Hide/show red units"} /> getApp().getMap().setHiddenType("neutral", !mapHiddenTypes["neutral"])} checked={!mapHiddenTypes["neutral"]} icon={faFlag} className={"!text-gray-500"} tooltip={"Hide/show neutral units"} />
{Object.entries({ aircraft: olButtonsVisibilityAircraft, helicopter: olButtonsVisibilityHelicopter, "groundunit-sam": olButtonsVisibilityGroundunitSam, groundunit: olButtonsVisibilityGroundunit, navyunit: olButtonsVisibilityNavyunit, airbase: olButtonsVisibilityAirbase, dead: faSkull, }).map((entry) => { return ( { getApp().getMap().setHiddenType(entry[0], !mapHiddenTypes[entry[0]]); }} checked={!mapHiddenTypes[entry[0]]} icon={entry[1]} tooltip={"Hide/show " + entry[0] + " units"} /> ); })}
{ getApp().getMap().setOption("showMissionDrawings", !mapOptions.showMissionDrawings); }} tooltip={() => ( )} /> getApp().getMap().setOption("showUnitsEngagementRings", !mapOptions.showUnitsEngagementRings)} checked={mapOptions.showUnitsEngagementRings} icon={faTriangleExclamation} className={""} tooltip={"Hide/show units engagement rings"} /> getApp().getMap().setOption("showUnitsAcquisitionRings", !mapOptions.showUnitsAcquisitionRings)} checked={mapOptions.showUnitsAcquisitionRings} icon={faWifi} className={""} tooltip={"Hide/show units acquisition rings"} /> getApp().getMap().setOption("clusterGroundUnits", !mapOptions.clusterGroundUnits)} checked={mapOptions.clusterGroundUnits} icon={faObjectGroup} className={""} tooltip={"Enable/disable ground unit clustering"} />
{ getApp() .getMap() .setOption("cameraPluginMode", mapOptions.cameraPluginMode === "live" ? "map" : "live"); }} tooltip={() => ( )} /> { getApp().getMap().setOption("cameraPluginEnabled", !mapOptions.cameraPluginEnabled); }} tooltip={() => ( )} /> {mapSources.map((source) => { return ( getApp().getMap().setLayerName(source)}>
{source}
); })}
{!scrolledRight && ( )}
); }