diff --git a/client/src/map/map.ts b/client/src/map/map.ts index 30803c55..4bd58cda 100644 --- a/client/src/map/map.ts +++ b/client/src/map/map.ts @@ -616,7 +616,7 @@ export class Map extends L.Map { #showDestinationCursors() { const singleCursor = !this.#shiftKey; - const selectedUnitsCount = getUnitsManager().getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }).length; + const selectedUnitsCount = getUnitsManager().getSelectedUnits({ excludeHumans: false, onlyOnePerGroup: true }).length; if (selectedUnitsCount > 0) { if (singleCursor && this.#destinationPreviewCursors.length != 1) { this.#hideDestinationCursors(); diff --git a/client/src/mission/missionhandler.ts b/client/src/mission/missionhandler.ts index 163b2295..e1c9bbe3 100644 --- a/client/src/mission/missionhandler.ts +++ b/client/src/mission/missionhandler.ts @@ -1,9 +1,9 @@ import { LatLng } from "leaflet"; -import { getInfoPopup, getMap, getUnitsManager } from ".."; +import { getInfoPopup, getMap } from ".."; import { Airbase } from "./airbase"; import { Bullseye } from "./bullseye"; -import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "../constants/constants"; -import { setCommandModeOptions } from "../server/server"; +import { BLUE_COMMANDER, GAME_MASTER, NONE, RED_COMMANDER } from "../constants/constants"; +import { refreshAll, setCommandModeOptions } from "../server/server"; import { Dropdown } from "../controls/dropdown"; import { groundUnitDatabase } from "../unit/groundunitdatabase"; import { createCheckboxOption, getCheckboxOptions } from "../other/utils"; @@ -16,7 +16,7 @@ export class MissionHandler { #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}; - #commandModeOptions: CommandModeOptions = {commandMode: "Hide all", restrictSpawns: false, restrictToCoalition: false, setupTime: Infinity, spawnPoints: {red: Infinity, blue: Infinity}, eras: []}; + #commandModeOptions: CommandModeOptions = {commandMode: NONE, restrictSpawns: false, restrictToCoalition: false, setupTime: Infinity, spawnPoints: {red: Infinity, blue: Infinity}, eras: []}; #remainingSetupTime: number = 0; #spentSpawnPoint: number = 0; #commandModeDialog: HTMLElement; @@ -183,6 +183,15 @@ export class MissionHandler { } #setcommandModeOptions(commandModeOptions: CommandModeOptions) { + /* Refresh all the data if we have exited the NONE state */ + if (this.#commandModeOptions.commandMode === NONE && commandModeOptions.commandMode !== NONE) + refreshAll(); + + /* Refresh the page if we have lost Game Master priviledges */ + if (this.#commandModeOptions.commandMode === GAME_MASTER && commandModeOptions.commandMode !== GAME_MASTER) + location.reload(); + + /* Check if any option has changed */ var commandModeOptionsChanged = (!commandModeOptions.eras.every((value: string, idx: number) => {return value === this.getCommandModeOptions().eras[idx]}) || commandModeOptions.spawnPoints.red !== this.getCommandModeOptions().spawnPoints.red || commandModeOptions.spawnPoints.blue !== this.getCommandModeOptions().spawnPoints.blue || @@ -195,7 +204,6 @@ export class MissionHandler { if (commandModeOptionsChanged) { document.dispatchEvent(new CustomEvent("commandModeOptionsChanged", { detail: this })); - document.getElementById("command-mode-toolbar")?.classList.remove("hide"); const el = document.getElementById("command-mode"); if (el) { diff --git a/client/src/panels/unitcontrolpanel.ts b/client/src/panels/unitcontrolpanel.ts index 821fc6a2..d2e90a59 100644 --- a/client/src/panels/unitcontrolpanel.ts +++ b/client/src/panels/unitcontrolpanel.ts @@ -22,6 +22,8 @@ export class UnitControlPanel extends Panel { #radioCallsignDropdown: Dropdown; #optionButtons: { [key: string]: HTMLButtonElement[] } = {} #advancedSettingsDialog: HTMLElement; + #units: Unit[] = []; + #selectedUnitsTypes: string[] = []; constructor(ID: string) { super(ID); @@ -96,9 +98,11 @@ export class UnitControlPanel extends Panel { } addButtons() { - var units = getUnitsManager().getSelectedUnits(); - if (units.length < 20) { - this.getElement().querySelector("#selected-units-container")?.replaceChildren(...units.map((unit: Unit, index: number) => { + this.#units = getUnitsManager().getSelectedUnits(); + this.#selectedUnitsTypes = getUnitsManager().getSelectedUnitsTypes(); + + if (this.#units.length < 20) { + this.getElement().querySelector("#selected-units-container")?.replaceChildren(...this.#units.map((unit: Unit, index: number) => { var button = document.createElement("button"); var callsign = unit.getUnitName() || ""; var label = unit.getDatabase()?.getByName(unit.getName())?.label || unit.getName(); @@ -125,37 +129,34 @@ export class UnitControlPanel extends Panel { update() { if (this.getVisible()){ const element = this.getElement(); - const units = getUnitsManager().getSelectedUnits(); - const selectedUnitsTypes = getUnitsManager().getSelectedUnitsTypes(); - - if (element != null && units.length > 0) { + if (element != null && this.#units.length > 0) { /* Toggle visibility of control elements */ - element.toggleAttribute("data-show-categories-tooltip", selectedUnitsTypes.length > 1); - element.toggleAttribute("data-show-speed-slider", selectedUnitsTypes.length == 1); - element.toggleAttribute("data-show-altitude-slider", selectedUnitsTypes.length == 1 && (selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter"))); + element.toggleAttribute("data-show-categories-tooltip", this.#selectedUnitsTypes.length > 1); + element.toggleAttribute("data-show-speed-slider", this.#selectedUnitsTypes.length == 1); + element.toggleAttribute("data-show-altitude-slider", this.#selectedUnitsTypes.length == 1 && (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter"))); element.toggleAttribute("data-show-roe", true); - element.toggleAttribute("data-show-threat", (selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter")) && !(selectedUnitsTypes.includes("GroundUnit") || selectedUnitsTypes.includes("NavyUnit"))); - element.toggleAttribute("data-show-emissions-countermeasures", (selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter")) && !(selectedUnitsTypes.includes("GroundUnit") || selectedUnitsTypes.includes("NavyUnit"))); - element.toggleAttribute("data-show-on-off", (selectedUnitsTypes.includes("GroundUnit") || selectedUnitsTypes.includes("NavyUnit")) && !(selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter"))); - element.toggleAttribute("data-show-follow-roads", (selectedUnitsTypes.length == 1 && selectedUnitsTypes.includes("GroundUnit"))); - element.toggleAttribute("data-show-advanced-settings-button", units.length == 1); + element.toggleAttribute("data-show-threat", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit"))); + element.toggleAttribute("data-show-emissions-countermeasures", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit"))); + element.toggleAttribute("data-show-on-off", (this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")) && !(this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter"))); + element.toggleAttribute("data-show-follow-roads", (this.#selectedUnitsTypes.length == 1 && this.#selectedUnitsTypes.includes("GroundUnit"))); + element.toggleAttribute("data-show-advanced-settings-button", this.#units.length == 1); - /* Flight controls */ - var desiredAltitude = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitude()}); - var desiredAltitudeType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitudeType()}); - var desiredSpeed = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeed()}); - var desiredSpeedType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeedType()}); - var onOff = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOnOff()}); - var followRoads = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getFollowRoads()}); - - if (selectedUnitsTypes.length == 1) { + if (this.#selectedUnitsTypes.length == 1) { + /* Flight controls */ + var desiredAltitude = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitude()}); + var desiredAltitudeType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitudeType()}); + var desiredSpeed = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeed()}); + var desiredSpeedType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeedType()}); + var onOff = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOnOff()}); + var followRoads = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getFollowRoads()}); + this.#altitudeTypeSwitch.setValue(desiredAltitudeType != undefined? desiredAltitudeType == "AGL": undefined, false); this.#speedTypeSwitch.setValue(desiredSpeedType != undefined? desiredSpeedType == "GS": undefined, false); - this.#speedSlider.setMinMax(minSpeedValues[selectedUnitsTypes[0]], maxSpeedValues[selectedUnitsTypes[0]]); - this.#altitudeSlider.setMinMax(minAltitudeValues[selectedUnitsTypes[0]], maxAltitudeValues[selectedUnitsTypes[0]]); - this.#speedSlider.setIncrement(speedIncrements[selectedUnitsTypes[0]]); - this.#altitudeSlider.setIncrement(altitudeIncrements[selectedUnitsTypes[0]]); + this.#speedSlider.setMinMax(minSpeedValues[this.#selectedUnitsTypes[0]], maxSpeedValues[this.#selectedUnitsTypes[0]]); + this.#altitudeSlider.setMinMax(minAltitudeValues[this.#selectedUnitsTypes[0]], maxAltitudeValues[this.#selectedUnitsTypes[0]]); + this.#speedSlider.setIncrement(speedIncrements[this.#selectedUnitsTypes[0]]); + this.#altitudeSlider.setIncrement(altitudeIncrements[this.#selectedUnitsTypes[0]]); this.#speedSlider.setActive(desiredSpeed != undefined); if (desiredSpeed != undefined) @@ -172,15 +173,15 @@ export class UnitControlPanel extends Panel { /* Option buttons */ this.#optionButtons["ROE"].forEach((button: HTMLButtonElement) => { - button.classList.toggle("selected", units.every((unit: Unit) => unit.getROE() === button.value)) + button.classList.toggle("selected", this.#units.every((unit: Unit) => unit.getROE() === button.value)) }); this.#optionButtons["reactionToThreat"].forEach((button: HTMLButtonElement) => { - button.classList.toggle("selected", units.every((unit: Unit) => unit.getReactionToThreat() === button.value)) + button.classList.toggle("selected", this.#units.every((unit: Unit) => unit.getReactionToThreat() === button.value)) }); this.#optionButtons["emissionsCountermeasures"].forEach((button: HTMLButtonElement) => { - button.classList.toggle("selected", units.every((unit: Unit) => unit.getEmissionsCountermeasures() === button.value)) + button.classList.toggle("selected", this.#units.every((unit: Unit) => unit.getEmissionsCountermeasures() === button.value)) }); this.#onOffSwitch.setValue(onOff, false); diff --git a/client/src/server/server.ts b/client/src/server/server.ts index 6abcd9a5..ce9c5f9c 100644 --- a/client/src/server/server.ts +++ b/client/src/server/server.ts @@ -1,7 +1,7 @@ import { LatLng } from 'leaflet'; import { getConnectionStatusPanel, getInfoPopup, getLogPanel, getMissionHandler, getServerStatusPanel, getUnitsManager, getWeaponsManager, setLoginStatus } from '..'; import { GeneralSettings, Radio, TACAN } from '../@types/unit'; -import { ROEs, emissionsCountermeasures, reactionsToThreat } from '../constants/constants'; +import { NONE, ROEs, emissionsCountermeasures, reactionsToThreat } from '../constants/constants'; var connected: boolean = false; var paused: boolean = false; @@ -20,6 +20,13 @@ var password = ""; var sessionHash: string | null = null; var lastUpdateTimes: {[key: string]: number} = {} +lastUpdateTimes[UNITS_URI] = Date.now(); +lastUpdateTimes[WEAPONS_URI] = Date.now(); +lastUpdateTimes[LOGS_URI] = Date.now(); +lastUpdateTimes[AIRBASES_URI] = Date.now(); +lastUpdateTimes[BULLSEYE_URI] = Date.now(); +lastUpdateTimes[MISSION_URI] = Date.now(); + var demoEnabled = false; export function toggleDemoEnabled() { @@ -339,26 +346,6 @@ export function setCommandModeOptions(restrictSpawns: boolean, restrictToCoaliti } export function startUpdate() { - window.setInterval(() => { - if (!getPaused()) { - getAirbases((data: AirbasesData) => { - checkSessionHash(data.sessionHash); - getMissionHandler()?.updateAirbases(data); - return data.time; - }); - } - }, 10000); - - window.setInterval(() => { - if (!getPaused()){ - getBullseye((data: BullseyesData) => { - checkSessionHash(data.sessionHash); - getMissionHandler()?.updateBullseyes(data); - return data.time; - }); - } - }, 10000); - window.setInterval(() => { if (!getPaused()) { getMission((data: MissionData) => { @@ -370,7 +357,27 @@ export function startUpdate() { }, 1000); window.setInterval(() => { - if (!getPaused()) { + if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { + getAirbases((data: AirbasesData) => { + checkSessionHash(data.sessionHash); + getMissionHandler()?.updateAirbases(data); + return data.time; + }); + } + }, 10000); + + window.setInterval(() => { + if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE){ + getBullseye((data: BullseyesData) => { + checkSessionHash(data.sessionHash); + getMissionHandler()?.updateBullseyes(data); + return data.time; + }); + } + }, 10000); + + window.setInterval(() => { + if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { getLogs((data: any) => { checkSessionHash(data.sessionHash); getLogPanel().appendLogs(data.logs) @@ -380,7 +387,7 @@ export function startUpdate() { }, 1000); window.setInterval(() => { - if (!getPaused()) { + if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { getUnits((buffer: ArrayBuffer) => { var time = getUnitsManager()?.update(buffer); return time; @@ -389,7 +396,7 @@ export function startUpdate() { }, 250); window.setInterval(() => { - if (!getPaused()) { + if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { getWeapons((buffer: ArrayBuffer) => { var time = getWeaponsManager()?.update(buffer); return time; @@ -398,7 +405,7 @@ export function startUpdate() { }, 250); window.setInterval(() => { - if (!getPaused()) { + if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { getUnits((buffer: ArrayBuffer) => { var time = getUnitsManager()?.update(buffer); return time; @@ -408,9 +415,39 @@ export function startUpdate() { }, 5000); } +export function refreshAll() { + getAirbases((data: AirbasesData) => { + checkSessionHash(data.sessionHash); + getMissionHandler()?.updateAirbases(data); + return data.time; + }); + + getBullseye((data: BullseyesData) => { + checkSessionHash(data.sessionHash); + getMissionHandler()?.updateBullseyes(data); + return data.time; + }); + + getLogs((data: any) => { + checkSessionHash(data.sessionHash); + getLogPanel().appendLogs(data.logs) + return data.time; + }); + + getWeapons((buffer: ArrayBuffer) => { + var time = getWeaponsManager()?.update(buffer); + return time; + }, false); + + getUnits((buffer: ArrayBuffer) => { + var time = getUnitsManager()?.update(buffer); + return time; + }, true); +} + export function checkSessionHash(newSessionHash: string) { if (sessionHash != null) { - if (newSessionHash != sessionHash) + if (newSessionHash !== sessionHash) location.reload(); } else diff --git a/client/src/unit/unit.ts b/client/src/unit/unit.ts index 6f6c879f..289b47d4 100644 --- a/client/src/unit/unit.ts +++ b/client/src/unit/unit.ts @@ -406,9 +406,11 @@ export class Unit extends CustomMarker { el.setAttribute("data-object", `unit-${this.getMarkerCategory()}`); el.setAttribute("data-coalition", this.#coalition); + var iconOptions = this.getIconOptions(); + // Generate and append elements depending on active options // Velocity vector - if (this.getIconOptions().showVvi) { + if (iconOptions.showVvi) { var vvi = document.createElement("div"); vvi.classList.add("unit-vvi"); vvi.toggleAttribute("data-rotate-to-heading"); @@ -416,7 +418,7 @@ export class Unit extends CustomMarker { } // Hotgroup indicator - if (this.getIconOptions().showHotgroup) { + if (iconOptions.showHotgroup) { var hotgroup = document.createElement("div"); hotgroup.classList.add("unit-hotgroup"); var hotgroupId = document.createElement("div"); @@ -426,26 +428,26 @@ export class Unit extends CustomMarker { } // Main icon - if (this.getIconOptions().showUnitIcon) { + if (iconOptions.showUnitIcon) { var unitIcon = document.createElement("div"); unitIcon.classList.add("unit-icon"); var img = document.createElement("img"); img.src = `/resources/theme/images/units/${this.getMarkerCategory()}.svg`; img.onload = () => SVGInjector(img); unitIcon.appendChild(img); - unitIcon.toggleAttribute("data-rotate-to-heading", this.getIconOptions().rotateToHeading); + unitIcon.toggleAttribute("data-rotate-to-heading", iconOptions.rotateToHeading); el.append(unitIcon); } // State icon - if (this.getIconOptions().showState) { + if (iconOptions.showState) { var state = document.createElement("div"); state.classList.add("unit-state"); el.appendChild(state); } // Short label - if (this.getIconOptions().showShortLabel) { + if (iconOptions.showShortLabel) { var shortLabel = document.createElement("div"); shortLabel.classList.add("unit-short-label"); shortLabel.innerText = getUnitDatabaseByCategory(this.getMarkerCategory())?.getByName(this.#name)?.shortLabel || ""; @@ -453,7 +455,7 @@ export class Unit extends CustomMarker { } // Fuel indicator - if (this.getIconOptions().showFuel) { + if (iconOptions.showFuel) { var fuelIndicator = document.createElement("div"); fuelIndicator.classList.add("unit-fuel"); var fuelLevel = document.createElement("div"); @@ -463,7 +465,7 @@ export class Unit extends CustomMarker { } // Ammo indicator - if (this.getIconOptions().showAmmo) { + if (iconOptions.showAmmo) { var ammoIndicator = document.createElement("div"); ammoIndicator.classList.add("unit-ammo"); for (let i = 0; i <= 3; i++) @@ -472,7 +474,7 @@ export class Unit extends CustomMarker { } // Unit summary - if (this.getIconOptions().showSummary) { + if (iconOptions.showSummary) { var summary = document.createElement("div"); summary.classList.add("unit-summary"); var callsign = document.createElement("div"); @@ -482,7 +484,7 @@ export class Unit extends CustomMarker { altitude.classList.add("unit-altitude"); var speed = document.createElement("div"); speed.classList.add("unit-speed"); - if (this.getIconOptions().showCallsign) summary.appendChild(callsign); + if (iconOptions.showCallsign) summary.appendChild(callsign); summary.appendChild(altitude); summary.appendChild(speed); el.appendChild(summary); @@ -499,7 +501,7 @@ export class Unit extends CustomMarker { (hiddenUnits.includes(this.getMarkerCategory())) || (hiddenUnits.includes(this.#coalition)) || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0) || - (getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getMap().getZoom() < 13)) && + (getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getMap().getZoom() < 13 && (this.belongsToCommandedCoalition() || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0)))) && !(this.getSelected()); this.setHidden(hidden || !this.#alive); diff --git a/client/src/unit/unitsmanager.ts b/client/src/unit/unitsmanager.ts index c0c30a5b..b0f4bead 100644 --- a/client/src/unit/unitsmanager.ts +++ b/client/src/unit/unitsmanager.ts @@ -95,7 +95,7 @@ export class UnitsManager { if (this.#requestDetectionUpdate && getMissionHandler().getCommandModeOptions().commandMode != GAME_MASTER) { for (let ID in this.#units) { var unit = this.#units[ID]; - if (!unit.belongsToCommandedCoalition()) + if (unit.getAlive() && !unit.belongsToCommandedCoalition()) unit.setDetectionMethods(this.getUnitDetectedMethods(unit)); } this.#requestDetectionUpdate = false; @@ -651,7 +651,8 @@ export class UnitsManager { var groups = JSON.parse(contents); for (let groupName in groups) { if (groupName !== "" && groups[groupName].length > 0 && groups[groupName].every((unit: any) => {return unit.category == "GroundUnit";})) { - var units = groups[groupName].map((unit: any) => {return {unitType: unit.name, location: unit.position}}); + var aliveUnits = groups[groupName].filter((unit: any) => {return unit.alive}); + var units = aliveUnits.map((unit: any) => {return {unitType: unit.name, location: unit.position}}); getUnitsManager().spawnUnits("GroundUnit", units, groups[groupName][0].coalition, true); } } @@ -714,9 +715,9 @@ export class UnitsManager { #onUnitSelection(unit: Unit) { if (this.getSelectedUnits().length > 0) { - getMap().setState(MOVE_UNIT); /* Disable the firing of the selection event for a certain amount of time. This avoids firing many events if many units are selected */ if (!this.#selectionEventDisabled) { + getMap().setState(MOVE_UNIT); window.setTimeout(() => { document.dispatchEvent(new CustomEvent("unitsSelection", { detail: this.getSelectedUnits() })); this.#selectionEventDisabled = false; diff --git a/olympus.json b/olympus.json index 683f600f..a3409e65 100644 --- a/olympus.json +++ b/olympus.json @@ -1,6 +1,6 @@ { "server": { - "address": "localhost", + "address": "88.99.250.188", "port": 30000 }, "authentication": { diff --git a/scripts/OlympusCommand.lua b/scripts/OlympusCommand.lua index 28abaddb..71f08f46 100644 --- a/scripts/OlympusCommand.lua +++ b/scripts/OlympusCommand.lua @@ -1,6 +1,6 @@ local version = "v0.4.1-alpha" -local debug = true +local debug = false Olympus.OlympusDLL = nil @@ -53,26 +53,33 @@ function Olympus.getUnitByID(ID) return Olympus.units[ID]; end -function Olympus.getCountryIDByCoalition(coalition) - local countryID = 0 - if coalition == 'red' then - countryID = country.id.CJTF_RED - elseif coalition == 'blue' then - countryID = country.id.CJTF_BLUE - else - countryID = country.id.UN_PEACEKEEPERS +function Olympus.getCountryIDByCoalition(coalitionString) + for countryName, countryId in pairs(country.id) do + if coalition.getCountryCoalition(countryId) == Olympus.getCoalitionIDByCoalition(coalitionString) then + return countryId + end end - return countryID + return 0 +end + +function Olympus.getCoalitionIDByCoalition(coalitionString) + local coalitionID = 0 + if coalitionString == "red" then + coalitionID = 1 + elseif coalitionString == "blue" then + coalitionID = 2 + end + return coalitionID end function Olympus.getCoalitionByCoalitionID(coalitionID) - local coalition = "neutral" + local coalitionString = "neutral" if coalitionID == 1 then - coalition = "red" + coalitionString = "red" elseif coalitionID == 2 then - coalition = "blue" + coalitionString = "blue" end - return coalition + return coalitionString end -- Builds a valid task depending on the provided options @@ -569,10 +576,9 @@ function Olympus.clone(ID, lat, lng, category) Olympus.debug("Olympus.clone " .. ID .. ", " .. category, 2) local unit = Olympus.getUnitByID(ID) if unit then - local coalition = Olympus.getCoalitionByCoalitionID(unit:getCoalition()) -- TODO: understand category in this script local spawnTable = { - coalition = coalition, + coalition = Olympus.getCoalitionByCoalitionID(unit:getCoalition()), category = category, units = { [1] = { @@ -663,9 +669,7 @@ function Olympus.setUnitsData(arg, time) index = index + 1 if index > startIndex then if unit ~= nil then - local table = {} - table["category"] = "None" - + local table = {} -- Get the object category in Olympus name local objectCategory = unit:getCategory() if objectCategory == Object.Category.UNIT then @@ -684,7 +688,7 @@ function Olympus.setUnitsData(arg, time) end -- If the category is handled by Olympus, get the data - if table["category"] ~= "None" then + if table["category"] ~= nil then -- Compute unit position and heading local lat, lng, alt = coord.LOtoLL(unit:getPoint()) local position = unit:getPosition() @@ -699,34 +703,40 @@ function Olympus.setUnitsData(arg, time) table["position"]["alt"] = alt table["speed"] = mist.vec.mag(unit:getVelocity()) table["heading"] = heading - table["isAlive"] = unit:isExist() + table["isAlive"] = unit:isExist() and unit:isActive() and unit:getLife() >= 1 - -- Get the targets detected by the group controller local group = unit:getGroup() - local controller = group:getController() - - local contacts = {} - for det, enum in pairs(Controller.Detection) do - local controllerTargets = unit:getController():getDetectedTargets(enum) - for i, target in ipairs(controllerTargets) do - if target.object ~= nil and target.visible then - target["detectionMethod"] = det - contacts[#contacts + 1] = target + if group ~= nil then + local controller = group:getController() + if controller ~= nil then + -- Get the targets detected by the unit controller + local contacts = {} + local unitController = unit:getController() + if unitController ~= nil then + for det, enum in pairs(Controller.Detection) do + local controllerTargets = unitController:getDetectedTargets(enum) + for i, target in ipairs(controllerTargets) do + if target ~= nil and target.object ~= nil and target.visible then + target["detectionMethod"] = det + contacts[#contacts + 1] = target + end + end + end end + + table["country"] = unit:getCountry() + table["unitName"] = unit:getName() + table["groupName"] = group:getName() + table["isHuman"] = (unit:getPlayerName() ~= nil) + table["hasTask"] = controller:hasTask() + table["ammo"] = unit:getAmmo() --TODO remove a lot of stuff we don't really need + table["fuel"] = unit:getFuel() + table["life"] = unit:getLife() / unit:getLife0() + table["contacts"] = contacts + + units[ID] = table end end - - table["country"] = unit:getCountry() - table["unitName"] = unit:getName() - table["groupName"] = group:getName() - table["isHuman"] = (unit:getPlayerName() ~= nil) - table["hasTask"] = controller:hasTask() - table["ammo"] = unit:getAmmo() --TODO remove a lot of stuff we don't really need - table["fuel"] = unit:getFuel() - table["life"] = unit:getLife() / unit:getLife0() - table["contacts"] = contacts - - units[ID] = table end else units[ID] = {isAlive = false} @@ -762,8 +772,7 @@ function Olympus.setWeaponsData(arg, time) if index > startIndex then if weapon ~= nil then local table = {} - table["category"] = "None" - + -- Get the object category in Olympus name local objectCategory = weapon:getCategory() if objectCategory == Object.Category.WEAPON then @@ -780,7 +789,7 @@ function Olympus.setWeaponsData(arg, time) end -- If the category is handled by Olympus, get the data - if table["category"] ~= "None" then + if table["category"] ~= nil then -- Compute weapon position and heading local lat, lng, alt = coord.LOtoLL(weapon:getPoint()) local position = weapon:getPosition() @@ -964,12 +973,16 @@ handler = {} function handler:onEvent(event) if event.id == 1 then local weapon = event.weapon - Olympus.weapons[weapon["id_"]] = weapon - Olympus.debug("New weapon created " .. weapon["id_"], 2) + if Olympus ~= nil and Olympus.weapons ~= nil then + Olympus.weapons[weapon["id_"]] = weapon + Olympus.debug("New weapon created " .. weapon["id_"], 2) + end elseif event.id == 15 then local unit = event.initiator - Olympus.units[unit["id_"]] = unit - Olympus.debug("New unit created " .. unit["id_"], 2) + if Olympus ~= nil and Olympus.units ~= nil then + Olympus.units[unit["id_"]] = unit + Olympus.debug("New unit created " .. unit["id_"], 2) + end end end world.addEventHandler(handler) diff --git a/src/core/src/unit.cpp b/src/core/src/unit.cpp index 3edd5625..4a7cba8c 100644 --- a/src/core/src/unit.cpp +++ b/src/core/src/unit.cpp @@ -85,8 +85,9 @@ void Unit::update(json::value json, double dt) DataTypes::Ammo ammoItem; auto ammoJson = el.second; ammoItem.quantity = ammoJson[L"count"].as_number().to_uint32(); - string name = to_string(ammoJson[L"desc"][L"displayName"].as_string()).substr(0, sizeof(ammoItem.name) - 1); - strcpy_s(ammoItem.name, sizeof(ammoItem.name), name.c_str()); + string name = to_string(ammoJson[L"desc"][L"displayName"].as_string()); + name = name.substr(min(name.length(), sizeof(ammoItem.name) - 1)); + strcpy_s(ammoItem.name, sizeof(ammoItem.name) - 1, name.c_str()); if (ammoJson[L"desc"].has_number_field(L"guidance")) ammoItem.guidance = ammoJson[L"desc"][L"guidance"].as_number().to_uint32(); @@ -211,48 +212,53 @@ void Unit::getData(stringstream& ss, unsigned long long time) const unsigned char endOfData = DataIndex::endOfData; ss.write((const char*)&ID, sizeof(ID)); - for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++) - { - if (checkFreshness(datumIndex, time)) { - switch (datumIndex) { - case DataIndex::category: appendString(ss, datumIndex, category); break; - case DataIndex::alive: appendNumeric(ss, datumIndex, alive); break; - case DataIndex::human: appendNumeric(ss, datumIndex, human); break; - case DataIndex::controlled: appendNumeric(ss, datumIndex, controlled); break; - case DataIndex::coalition: appendNumeric(ss, datumIndex, coalition); break; - case DataIndex::country: appendNumeric(ss, datumIndex, country); break; - case DataIndex::name: appendString(ss, datumIndex, name); break; - case DataIndex::unitName: appendString(ss, datumIndex, unitName); break; - case DataIndex::groupName: appendString(ss, datumIndex, groupName); break; - case DataIndex::state: appendNumeric(ss, datumIndex, state); break; - case DataIndex::task: appendString(ss, datumIndex, task); break; - case DataIndex::hasTask: appendNumeric(ss, datumIndex, hasTask); break; - case DataIndex::position: appendNumeric(ss, datumIndex, position); break; - case DataIndex::speed: appendNumeric(ss, datumIndex, speed); break; - case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break; - case DataIndex::isTanker: appendNumeric(ss, datumIndex, isTanker); break; - case DataIndex::isAWACS: appendNumeric(ss, datumIndex, isAWACS); break; - case DataIndex::onOff: appendNumeric(ss, datumIndex, onOff); break; - case DataIndex::followRoads: appendNumeric(ss, datumIndex, followRoads); break; - case DataIndex::fuel: appendNumeric(ss, datumIndex, fuel); break; - case DataIndex::desiredSpeed: appendNumeric(ss, datumIndex, desiredSpeed); break; - case DataIndex::desiredSpeedType: appendNumeric(ss, datumIndex, desiredSpeedType); break; - case DataIndex::desiredAltitude: appendNumeric(ss, datumIndex, desiredAltitude); break; - case DataIndex::desiredAltitudeType: appendNumeric(ss, datumIndex, desiredAltitudeType); break; - case DataIndex::leaderID: appendNumeric(ss, datumIndex, leaderID); break; - case DataIndex::formationOffset: appendNumeric(ss, datumIndex, formationOffset); break; - case DataIndex::targetID: appendNumeric(ss, datumIndex, targetID); break; - case DataIndex::targetPosition: appendNumeric(ss, datumIndex, targetPosition); break; - case DataIndex::ROE: appendNumeric(ss, datumIndex, ROE); break; - case DataIndex::reactionToThreat: appendNumeric(ss, datumIndex, reactionToThreat); break; - case DataIndex::emissionsCountermeasures: appendNumeric(ss, datumIndex, emissionsCountermeasures); break; - case DataIndex::TACAN: appendNumeric(ss, datumIndex, TACAN); break; - case DataIndex::radio: appendNumeric(ss, datumIndex, radio); break; - case DataIndex::generalSettings: appendNumeric(ss, datumIndex, generalSettings); break; - case DataIndex::ammo: appendVector(ss, datumIndex, ammo); break; - case DataIndex::contacts: appendVector(ss, datumIndex, contacts); break; - case DataIndex::activePath: appendList(ss, datumIndex, activePath); break; - case DataIndex::isLeader: appendNumeric(ss, datumIndex, isLeader); break; + if (!alive) { + appendNumeric(ss, DataIndex::alive, alive); + } + else { + for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++) + { + if (checkFreshness(datumIndex, time)) { + switch (datumIndex) { + case DataIndex::category: appendString(ss, datumIndex, category); break; + case DataIndex::alive: appendNumeric(ss, datumIndex, alive); break; + case DataIndex::human: appendNumeric(ss, datumIndex, human); break; + case DataIndex::controlled: appendNumeric(ss, datumIndex, controlled); break; + case DataIndex::coalition: appendNumeric(ss, datumIndex, coalition); break; + case DataIndex::country: appendNumeric(ss, datumIndex, country); break; + case DataIndex::name: appendString(ss, datumIndex, name); break; + case DataIndex::unitName: appendString(ss, datumIndex, unitName); break; + case DataIndex::groupName: appendString(ss, datumIndex, groupName); break; + case DataIndex::state: appendNumeric(ss, datumIndex, state); break; + case DataIndex::task: appendString(ss, datumIndex, task); break; + case DataIndex::hasTask: appendNumeric(ss, datumIndex, hasTask); break; + case DataIndex::position: appendNumeric(ss, datumIndex, position); break; + case DataIndex::speed: appendNumeric(ss, datumIndex, speed); break; + case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break; + case DataIndex::isTanker: appendNumeric(ss, datumIndex, isTanker); break; + case DataIndex::isAWACS: appendNumeric(ss, datumIndex, isAWACS); break; + case DataIndex::onOff: appendNumeric(ss, datumIndex, onOff); break; + case DataIndex::followRoads: appendNumeric(ss, datumIndex, followRoads); break; + case DataIndex::fuel: appendNumeric(ss, datumIndex, fuel); break; + case DataIndex::desiredSpeed: appendNumeric(ss, datumIndex, desiredSpeed); break; + case DataIndex::desiredSpeedType: appendNumeric(ss, datumIndex, desiredSpeedType); break; + case DataIndex::desiredAltitude: appendNumeric(ss, datumIndex, desiredAltitude); break; + case DataIndex::desiredAltitudeType: appendNumeric(ss, datumIndex, desiredAltitudeType); break; + case DataIndex::leaderID: appendNumeric(ss, datumIndex, leaderID); break; + case DataIndex::formationOffset: appendNumeric(ss, datumIndex, formationOffset); break; + case DataIndex::targetID: appendNumeric(ss, datumIndex, targetID); break; + case DataIndex::targetPosition: appendNumeric(ss, datumIndex, targetPosition); break; + case DataIndex::ROE: appendNumeric(ss, datumIndex, ROE); break; + case DataIndex::reactionToThreat: appendNumeric(ss, datumIndex, reactionToThreat); break; + case DataIndex::emissionsCountermeasures: appendNumeric(ss, datumIndex, emissionsCountermeasures); break; + case DataIndex::TACAN: appendNumeric(ss, datumIndex, TACAN); break; + case DataIndex::radio: appendNumeric(ss, datumIndex, radio); break; + case DataIndex::generalSettings: appendNumeric(ss, datumIndex, generalSettings); break; + case DataIndex::ammo: appendVector(ss, datumIndex, ammo); break; + case DataIndex::contacts: appendVector(ss, datumIndex, contacts); break; + case DataIndex::activePath: appendList(ss, datumIndex, activePath); break; + case DataIndex::isLeader: appendNumeric(ss, datumIndex, isLeader); break; + } } } }