diff --git a/client/package-lock.json b/client/package-lock.json index 7d7b205d..a21cccf9 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,12 +1,12 @@ { "name": "DCSOlympus", - "version": "v0.4.0-alpha", + "version": "v0.4.1-alpha", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "DCSOlympus", - "version": "v0.4.0-alpha", + "version": "v0.4.1-alpha", "dependencies": { "cookie-parser": "~1.4.4", "debug": "~2.6.9", diff --git a/client/package.json b/client/package.json index 95934695..adeb53ef 100644 --- a/client/package.json +++ b/client/package.json @@ -2,7 +2,7 @@ "name": "DCSOlympus", "node-main": "./bin/www", "main": "http://localhost:3000", - "version": "v0.4.0-alpha", + "version": "v0.4.1-alpha", "private": true, "scripts": { "copy": "copy.bat", diff --git a/client/src/constants/constants.ts b/client/src/constants/constants.ts index be4eb2a5..fc208481 100644 --- a/client/src/constants/constants.ts +++ b/client/src/constants/constants.ts @@ -140,6 +140,7 @@ export const CARPET_BOMBING = "Carpet bombing"; export const FIRE_AT_AREA = "Fire at area"; export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area"; export const visibilityControls: string[] = ["human", "dcs", "aircraft", "groundunit-sam", "groundunit-other", "navyunit", "airbase"]; +export const visibilityControlsTypes: string[][] = [["human"], ["dcs"], ["aircraft"], ["groundunit-sam", "groundunit-sam-radar", "groundunit-sam-launcher"], ["groundunit-other", "groundunit-ewr"], ["navyunit"], ["airbase"]]; export const visibilityControlsTootlips: string[] = ["Toggle human players visibility", "Toggle DCS controlled units visibility", "Toggle aircrafts visibility", "Toggle SAM units visibility", "Toggle ground units (not SAM) visibility", "Toggle navy units visibility", "Toggle airbases visibility"]; export const IADSTypes = ["AAA", "MANPADS", "SAM Site", "Radar"]; diff --git a/client/src/map/map.ts b/client/src/map/map.ts index 4bd58cda..51574d35 100644 --- a/client/src/map/map.ts +++ b/client/src/map/map.ts @@ -12,7 +12,7 @@ import { DestinationPreviewMarker } from "./destinationpreviewmarker"; import { TemporaryUnitMarker } from "./temporaryunitmarker"; import { ClickableMiniMap } from "./clickableminimap"; import { SVGInjector } from '@tanem/svg-injector' -import { layers as mapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, visibilityControls, visibilityControlsTootlips, FIRE_AT_AREA, MOVE_UNIT, CARPET_BOMBING, BOMBING, SHOW_CONTACT_LINES, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS } from "../constants/constants"; +import { layers as mapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, visibilityControls, visibilityControlsTootlips, FIRE_AT_AREA, MOVE_UNIT, CARPET_BOMBING, BOMBING, SHOW_CONTACT_LINES, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, visibilityControlsTypes } from "../constants/constants"; import { TargetMarker } from "./targetmarker"; import { CoalitionArea } from "./coalitionarea"; import { CoalitionAreaContextMenu } from "../controls/coalitionareacontextmenu"; @@ -120,7 +120,7 @@ export class Map extends L.Map { document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => { const el = ev.detail._element; el?.classList.toggle("off"); - getUnitsManager().setHiddenType(ev.detail.type, !el?.classList.contains("off")); + ev.detail.types.forEach((type: string) => getUnitsManager().setHiddenType(type, !el?.classList.contains("off"))); Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility()); }); @@ -150,7 +150,7 @@ export class Map extends L.Map { /* Option buttons */ this.#optionButtons["visibility"] = visibilityControls.map((option: string, index: number) => { - return this.#createOptionButton(option, `visibility/${option.toLowerCase()}.svg`, visibilityControlsTootlips[index], "toggleUnitVisibility", `{"type": "${option}"}`); + return this.#createOptionButton(option, `visibility/${option.toLowerCase()}.svg`, visibilityControlsTootlips[index], "toggleUnitVisibility", `{"types": "${visibilityControlsTypes[index]}"}`); }); document.querySelector("#unit-visibility-control")?.append(...this.#optionButtons["visibility"]); diff --git a/client/src/mission/missionhandler.ts b/client/src/mission/missionhandler.ts index e1c9bbe3..4ce104b6 100644 --- a/client/src/mission/missionhandler.ts +++ b/client/src/mission/missionhandler.ts @@ -184,8 +184,9 @@ export class MissionHandler { #setcommandModeOptions(commandModeOptions: CommandModeOptions) { /* Refresh all the data if we have exited the NONE state */ + var requestRefresh = false; if (this.#commandModeOptions.commandMode === NONE && commandModeOptions.commandMode !== NONE) - refreshAll(); + requestRefresh = true; /* Refresh the page if we have lost Game Master priviledges */ if (this.#commandModeOptions.commandMode === GAME_MASTER && commandModeOptions.commandMode !== GAME_MASTER) @@ -214,6 +215,9 @@ export class MissionHandler { document.querySelector("#spawn-points-container")?.classList.toggle("hide", this.getCommandModeOptions().commandMode === GAME_MASTER || !this.getCommandModeOptions().restrictSpawns); document.querySelector("#command-mode-settings-button")?.classList.toggle("hide", this.getCommandModeOptions().commandMode !== GAME_MASTER); + + if (requestRefresh) + refreshAll(); } #onAirbaseClick(e: any) { diff --git a/client/src/server/dataextractor.ts b/client/src/server/dataextractor.ts index 278d4a72..d22b6201 100644 --- a/client/src/server/dataextractor.ts +++ b/client/src/server/dataextractor.ts @@ -13,6 +13,10 @@ export class DataExtractor { this.#decoder = new TextDecoder("utf-8"); } + setSeekPosition(seekPosition: number) { + this.#seekPosition = seekPosition; + } + getSeekPosition() { return this.#seekPosition; } @@ -67,7 +71,13 @@ export class DataExtractor { var stringBuffer = this.#buffer.slice(this.#seekPosition, this.#seekPosition + length); var view = new Int8Array(stringBuffer); var stringLength = length; - view.forEach((value: number, idx: number) => { if (value === 0) stringLength = idx; }); + view.every((value: number, idx: number) => { + if (value === 0) { + stringLength = idx; + return false; + } else + return true; + }); const value = this.#decoder.decode(stringBuffer); this.#seekPosition += length; return value.substring(0, stringLength).trim(); diff --git a/client/src/server/server.ts b/client/src/server/server.ts index ce9c5f9c..4c8ef77b 100644 --- a/client/src/server/server.ts +++ b/client/src/server/server.ts @@ -413,6 +413,15 @@ export function startUpdate() { getConnectionStatusPanel()?.update(getConnected()); } }, 5000); + + window.setInterval(() => { + if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { + getWeapons((buffer: ArrayBuffer) => { + var time = getWeaponsManager()?.update(buffer); + return time; + }, false); + } + }, 5000); } export function refreshAll() { @@ -437,7 +446,7 @@ export function refreshAll() { getWeapons((buffer: ArrayBuffer) => { var time = getWeaponsManager()?.update(buffer); return time; - }, false); + }, true); getUnits((buffer: ArrayBuffer) => { var time = getUnitsManager()?.update(buffer); diff --git a/client/src/unit/unit.ts b/client/src/unit/unit.ts index 289b47d4..abe147cb 100644 --- a/client/src/unit/unit.ts +++ b/client/src/unit/unit.ts @@ -190,7 +190,7 @@ export class Unit extends CustomMarker { case DataIndexes.alive: this.setAlive(dataExtractor.extractBool()); updateMarker = true; break; case DataIndexes.human: this.#human = dataExtractor.extractBool(); break; case DataIndexes.controlled: this.#controlled = dataExtractor.extractBool(); updateMarker = true; break; - case DataIndexes.coalition: this.#coalition = enumToCoalition(dataExtractor.extractUInt8()); break; + case DataIndexes.coalition: this.#coalition = enumToCoalition(dataExtractor.extractUInt8()); updateMarker = true; break; case DataIndexes.country: this.#country = dataExtractor.extractUInt8(); break; case DataIndexes.name: this.#name = dataExtractor.extractString(); break; case DataIndexes.unitName: this.#unitName = dataExtractor.extractString(); break; @@ -500,7 +500,7 @@ export class Unit extends CustomMarker { (this.#controlled == false && hiddenUnits.includes("dcs")) || (hiddenUnits.includes(this.getMarkerCategory())) || (hiddenUnits.includes(this.#coalition)) || - (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0) || + (!this.belongsToCommandedCoalition() && (this.#detectionMethods.length == 0 || (this.#detectionMethods.length == 1 && this.#detectionMethods[0] === RWR))) || (getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getMap().getZoom() < 13 && (this.belongsToCommandedCoalition() || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0)))) && !(this.getSelected()); @@ -748,6 +748,11 @@ export class Unit extends CustomMarker { options["fire-at-area"] = { text: "Fire at area", tooltip: "Fire at a large area" }; } + if ((selectedUnits.length === 0 && this.getCategory() == "NavyUnit") || selectedUnitTypes.length === 1 && ["NavyUnit"].includes(selectedUnitTypes[0])) { + if (selectedUnits.concat([this]).every((unit: Unit) => { return ["Cruiser", "Destroyer", "Frigate"].includes(this.getType()) })) + options["fire-at-area"] = { text: "Fire at area", tooltip: "Fire at a large area" }; + } + if (selectedUnitTypes.length === 1 && ["NavyUnit", "GroundUnit"].includes(selectedUnitTypes[0]) && getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getCoalition()}) !== undefined) options["group"] = { text: "Create group", tooltip: "Create a group from the selected units." }; diff --git a/client/src/unit/unitsmanager.ts b/client/src/unit/unitsmanager.ts index b0f4bead..047c64ec 100644 --- a/client/src/unit/unitsmanager.ts +++ b/client/src/unit/unitsmanager.ts @@ -1,7 +1,7 @@ import { LatLng, LatLngBounds } from "leaflet"; import { getHotgroupPanel, getInfoPopup, getMap, getMissionHandler, getUnitsManager } from ".."; import { Unit } from "./unit"; -import { cloneUnit, deleteUnit, spawnAircrafts, spawnGroundUnits, spawnHelicopters, spawnNavyUnits } from "../server/server"; +import { cloneUnit, deleteUnit, refreshAll, spawnAircrafts, spawnGroundUnits, spawnHelicopters, spawnNavyUnits } from "../server/server"; import { bearingAndDistanceToLatLng, deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polyContains, polygonArea, randomPointInPoly, randomUnitBlueprint } from "../other/utils"; import { CoalitionArea } from "../map/coalitionarea"; import { groundUnitDatabase } from "./groundunitdatabase"; @@ -35,7 +35,7 @@ export class UnitsManager { document.addEventListener('exportToFile', () => this.exportToFile()); document.addEventListener('importFromFile', () => this.importFromFile()); document.addEventListener('contactsUpdated', (e: CustomEvent) => {this.#requestDetectionUpdate = true}); - document.addEventListener("commandModeOptionsChanged", () => {Object.values(this.#units).forEach((unit: Unit) => unit.updateVisibility())}); + document.addEventListener('commandModeOptionsChanged', () => {Object.values(this.#units).forEach((unit: Unit) => unit.updateVisibility())}); } getSelectableAircraft() { @@ -76,7 +76,6 @@ export class UnitsManager { update(buffer: ArrayBuffer) { var dataExtractor = new DataExtractor(buffer); var updateTime = Number(dataExtractor.extractUInt64()); - var requestRefresh = false; while (dataExtractor.getSeekPosition() < buffer.byteLength) { const ID = dataExtractor.extractUInt32(); if (!(ID in this.#units)) { @@ -86,18 +85,40 @@ export class UnitsManager { this.addUnit(ID, category); } else { - requestRefresh = true; + /* Inconsistent data, we need to wait for a refresh */ + return updateTime; } } - this.#units[ID]?.setData(dataExtractor); + this.#units[ID]?.setData(dataExtractor); } if (this.#requestDetectionUpdate && getMissionHandler().getCommandModeOptions().commandMode != GAME_MASTER) { + /* Create a dictionary of empty detection methods arrays */ + var detectionMethods: {[key: string]: number[]} = {}; for (let ID in this.#units) { - var unit = this.#units[ID]; - if (unit.getAlive() && !unit.belongsToCommandedCoalition()) - unit.setDetectionMethods(this.getUnitDetectedMethods(unit)); + const unit = this.#units[ID]; + detectionMethods[ID] = []; } + + /* Fill the array with the detection methods */ + for (let ID in this.#units) { + const unit = this.#units[ID]; + if (unit.getAlive() && unit.belongsToCommandedCoalition()){ + const contacts = unit.getContacts(); + contacts.forEach((contact: Contact) => { + const contactID = contact.ID; + if (!(detectionMethods[contactID].includes(contact.detectionMethod))) + detectionMethods[contactID]?.push(contact.detectionMethod); + }) + } + } + + /* Set the detection methods for every unit */ + for (let ID in this.#units) { + const unit = this.#units[ID]; + unit.setDetectionMethods(detectionMethods[ID]); + } + this.#requestDetectionUpdate = false; } @@ -650,10 +671,10 @@ export class UnitsManager { var contents = e.target.result; 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";})) { + if (groupName !== "" && groups[groupName].length > 0 && (groups[groupName].every((unit: any) => {return unit.category == "GroundUnit";}) || groups[groupName].every((unit: any) => {return unit.category == "NavyUnit";}))) { 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); + getUnitsManager().spawnUnits(groups[groupName][0].category, units, groups[groupName][0].coalition, true); } } }; diff --git a/client/src/weapon/weaponsmanager.ts b/client/src/weapon/weaponsmanager.ts index 3a3a9b2e..e3accd27 100644 --- a/client/src/weapon/weaponsmanager.ts +++ b/client/src/weapon/weaponsmanager.ts @@ -39,7 +39,6 @@ export class WeaponsManager { update(buffer: ArrayBuffer) { var dataExtractor = new DataExtractor(buffer); var updateTime = Number(dataExtractor.extractUInt64()); - var requestRefresh = false; while (dataExtractor.getSeekPosition() < buffer.byteLength) { const ID = dataExtractor.extractUInt32(); if (!(ID in this.#weapons)) { @@ -49,7 +48,8 @@ export class WeaponsManager { this.addWeapon(ID, category); } else { - requestRefresh = true; + /* Inconsistent data, we need to wait for a refresh */ + return updateTime; } } this.#weapons[ID]?.setData(dataExtractor); diff --git a/client/views/other/dialogs.ejs b/client/views/other/dialogs.ejs index 542e0d88..1d00ce6d 100644 --- a/client/views/other/dialogs.ejs +++ b/client/views/other/dialogs.ejs @@ -3,7 +3,7 @@

DCS Olympus

Dynamic Unit Command

-
Version v0.4.0-alpha
+
Version v0.4.1-alpha
diff --git a/client/views/toolbars/primary.ejs b/client/views/toolbars/primary.ejs index eb0b60a1..de1a6eae 100644 --- a/client/views/toolbars/primary.ejs +++ b/client/views/toolbars/primary.ejs @@ -6,7 +6,7 @@

DCS Olympus

-
version v0.4.0-alpha
+
version v0.4.1-alpha
Discord diff --git a/installer/olympus.iss b/installer/olympus.iss index 17e3ed59..602b48fb 100644 --- a/installer/olympus.iss +++ b/installer/olympus.iss @@ -1,5 +1,5 @@ #define nwjsFolder "C:\Users\dpass\Documents\nwjs\" -#define version "v0.4.0-alpha" +#define version "v0.4.1-alpha" [Setup] AppName=DCS Olympus @@ -31,7 +31,7 @@ Source: "..\client\routes\*"; DestDir: "{app}\Mods\Services\Olympus\client\route Source: "..\client\views\*"; DestDir: "{app}\Mods\Services\Olympus\client\views"; Flags: ignoreversion recursesubdirs; Source: "..\client\*.*"; DestDir: "{app}\Mods\Services\Olympus\client"; Flags: ignoreversion; Source: "..\img\olympus.ico"; DestDir: "{app}\Mods\Services\Olympus\img"; Flags: ignoreversion; -;Source: "{#nwjsFolder}\*.*"; DestDir: "{app}\Mods\Services\Olympus\client"; Flags: ignoreversion recursesubdirs; +Source: "{#nwjsFolder}\*.*"; DestDir: "{app}\Mods\Services\Olympus\client"; Flags: ignoreversion recursesubdirs; [Code] function NeedsAddPath(Param: string): boolean; diff --git a/mod/entry.lua b/mod/entry.lua index a28956fd..dbdfe274 100644 --- a/mod/entry.lua +++ b/mod/entry.lua @@ -15,7 +15,7 @@ declare_plugin(self_ID, shortName = "Olympus", fileMenuName = "Olympus", - version = "v0.4.0-alpha", + version = "v0.4.1-alpha", state = "installed", developerName= "DCS Refugees 767 squadron", info = _("DCS Olympus is a mod for DCS World. It allows users to spawn, control, task, group, and remove units from a DCS World server using a real-time map interface, similarly to Real Time Strategy games. The user interface also provides useful informations units, like loadouts, fuel, tasking, and so on. In the future, more features for DCS World GCI and JTAC will be available."), diff --git a/olympus.json b/olympus.json index a3409e65..683f600f 100644 --- a/olympus.json +++ b/olympus.json @@ -1,6 +1,6 @@ { "server": { - "address": "88.99.250.188", + "address": "localhost", "port": 30000 }, "authentication": { diff --git a/scripts/OlympusCommand.lua b/scripts/OlympusCommand.lua index 71f08f46..799497e8 100644 --- a/scripts/OlympusCommand.lua +++ b/scripts/OlympusCommand.lua @@ -2,7 +2,6 @@ local version = "v0.4.1-alpha" local debug = false - Olympus.OlympusDLL = nil Olympus.DLLsloaded = false Olympus.OlympusModPath = os.getenv('DCSOLYMPUS_PATH')..'\\bin\\' @@ -227,7 +226,6 @@ function Olympus.move(groupName, lat, lng, altitude, altitudeType, speed, speedT if category == "Aircraft" then local startPoint = mist.getLeadPos(group) local endPoint = coord.LLtoLO(lat, lng, 0) - if altitudeType == "AGL" then altitude = land.getHeight({x = endPoint.x, y = endPoint.z}) + altitude end @@ -313,11 +311,15 @@ function Olympus.move(groupName, lat, lng, altitude, altitudeType, speed, speedT end Olympus.debug("Olympus.move executed successfully on Helicopter", 2) elseif category == "GroundUnit" then + local startPoint = mist.getLeadPos(group) + local endPoint = coord.LLtoLO(lat, lng, 0) + local bearing = math.atan2(endPoint.z - startPoint.z, endPoint.x - startPoint.x) + vars = { group = group, - point = coord.LLtoLO(lat, lng, 0), - heading = 0, + point = endPoint, + heading = bearing, speed = speed } @@ -331,11 +333,15 @@ function Olympus.move(groupName, lat, lng, altitude, altitudeType, speed, speedT mist.groupToRandomPoint(vars) Olympus.debug("Olympus.move executed succesfully on GroundUnit", 2) elseif category == "NavyUnit" then + local startPoint = mist.getLeadPos(group) + local endPoint = coord.LLtoLO(lat, lng, 0) + local bearing = math.atan2(endPoint.z - startPoint.z, endPoint.x - startPoint.x) + vars = { group = group, - point = coord.LLtoLO(lat, lng, 0), - heading = 0, + point = endPoint, + heading = bearing, speed = speed } mist.groupToRandomPoint(vars) @@ -550,7 +556,7 @@ function Olympus.generateNavyUnitsTable(units) ["y"] = spawnLocation.z + value.dy, ["heading"] = 0, ["skill"] = "High", - ["name"] = "NavyUnit-" .. Olympus.unitCounter .. "-" .. #unitTable + 1, + ["name"] = "Olympus-" .. Olympus.unitCounter .. "-" .. #unitTable + 1, ["transportable"] = { ["randomTransportable"] = false } } end @@ -562,7 +568,7 @@ function Olympus.generateNavyUnitsTable(units) ["y"] = spawnLocation.z, ["heading"] = 0, ["skill"] = "High", - ["name"] = "NavyUnit-" .. Olympus.unitCounter .. "-" .. #unitTable + 1, + ["name"] = "Olympus-" .. Olympus.unitCounter .. "-" .. #unitTable + 1, ["transportable"] = { ["randomTransportable"] = false } } end diff --git a/scripts/OlympusHook.lua b/scripts/OlympusHook.lua index 3310a8c4..7ba26180 100644 --- a/scripts/OlympusHook.lua +++ b/scripts/OlympusHook.lua @@ -1,4 +1,4 @@ -local version = 'v0.4.0-alpha' +local version = 'v0.4.1-alpha' Olympus = {} Olympus.OlympusDLL = nil diff --git a/src/core/include/navyunit.h b/src/core/include/navyunit.h index c82ee83d..24ed244d 100644 --- a/src/core/include/navyunit.h +++ b/src/core/include/navyunit.h @@ -1,12 +1,20 @@ #pragma once #include "unit.h" +#define NAVY_DEST_DIST_THR 100 + class NavyUnit : public Unit { public: NavyUnit(json::value json, unsigned int ID); - virtual void AIloop(); + + virtual void setState(unsigned char newState); + virtual void setDefaults(bool force = false); virtual void changeSpeed(string change); + virtual void setOnOff(bool newOnOff, bool force = false); + +protected: + virtual void AIloop(); }; \ No newline at end of file diff --git a/src/core/src/navyunit.cpp b/src/core/src/navyunit.cpp index 7b86fb72..1892a8ca 100644 --- a/src/core/src/navyunit.cpp +++ b/src/core/src/navyunit.cpp @@ -21,23 +21,132 @@ NavyUnit::NavyUnit(json::value json, unsigned int ID) : Unit(json, ID) setDesiredSpeed(10); }; +void NavyUnit::setDefaults(bool force) +{ + if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return; + + /* Set the default IDLE state */ + setState(State::IDLE); + + /* Set the default options */ + setROE(ROE::OPEN_FIRE_WEAPON_FREE, force); + setOnOff(onOff, force); + setFollowRoads(followRoads, force); +} + +void NavyUnit::setState(unsigned char newState) +{ + /************ Perform any action required when LEAVING a state ************/ + if (newState != state) { + switch (state) { + case State::IDLE: { + break; + } + case State::REACH_DESTINATION: { + break; + } + case State::FIRE_AT_AREA: { + setTargetPosition(Coords(NULL)); + break; + } + default: + break; + } + } + + /************ Perform any action required when ENTERING a state ************/ + switch (newState) { + case State::IDLE: { + clearActivePath(); + resetActiveDestination(); + break; + } + case State::REACH_DESTINATION: { + resetActiveDestination(); + break; + } + case State::FIRE_AT_AREA: { + clearActivePath(); + resetActiveDestination(); + break; + } + default: + break; + } + + if (newState != state) + resetTask(); + + log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState)); + state = newState; + + triggerUpdate(DataIndex::state); +} + void NavyUnit::AIloop() { - /* TODO */ + switch (state) { + case State::IDLE: { + setTask("Idle"); + if (getHasTask()) + resetTask(); + break; + } + case State::REACH_DESTINATION: { + string enrouteTask = "{}"; + bool looping = false; + + if (activeDestination == NULL || !getHasTask()) + { + if (!setActiveDestination()) + setState(State::IDLE); + else + goToDestination(enrouteTask); + } + else { + if (isDestinationReached(NAVY_DEST_DIST_THR)) { + if (updateActivePath(looping) && setActiveDestination()) + goToDestination(enrouteTask); + else + setState(State::IDLE); + } + } + break; + } + case State::FIRE_AT_AREA: { + setTask("Firing at area"); + + if (!getHasTask()) { + std::ostringstream taskSS; + taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1000}"; + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str())); + scheduler->appendCommand(command); + setHasTask(true); + } + } + default: + break; + } } void NavyUnit::changeSpeed(string change) { if (change.compare("stop") == 0) - { - - } + setState(State::IDLE); else if (change.compare("slow") == 0) - { - - } + setDesiredSpeed(getDesiredSpeed() - knotsToMs(5)); else if (change.compare("fast") == 0) - { + setDesiredSpeed(getDesiredSpeed() + knotsToMs(5)); + if (getDesiredSpeed() < 0) + setDesiredSpeed(0); +} + +void NavyUnit::setOnOff(bool newOnOff, bool force) +{ + if (newOnOff != onOff || force) { + Unit::setOnOff(newOnOff, force); + Command* command = dynamic_cast(new SetOnOff(groupName, onOff)); + scheduler->appendCommand(command); } } \ No newline at end of file diff --git a/src/core/src/unit.cpp b/src/core/src/unit.cpp index 4a7cba8c..4b2f2fa0 100644 --- a/src/core/src/unit.cpp +++ b/src/core/src/unit.cpp @@ -84,19 +84,26 @@ void Unit::update(json::value json, double dt) for (auto const& el : json[L"ammo"].as_object()) { 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()); - 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(); + if (ammoJson.has_number_field(L"count")) + ammoItem.quantity = ammoJson[L"count"].as_number().to_uint32(); - if (ammoJson[L"desc"].has_number_field(L"category")) - ammoItem.category = ammoJson[L"desc"][L"category"].as_number().to_uint32(); + if (ammoJson.has_object_field(L"desc")) { + if (ammoJson[L"desc"].has_string_field(L"displayName")) { + string name = to_string(ammoJson[L"desc"][L"displayName"].as_string()); + name = name.substr(0, min(name.size(), sizeof(ammoItem.name) - 1)); + strcpy_s(ammoItem.name, sizeof(ammoItem.name), name.c_str()); + } - if (ammoJson[L"desc"].has_number_field(L"missileCategory")) - ammoItem.missileCategory = ammoJson[L"desc"][L"missileCategory"].as_number().to_uint32(); + if (ammoJson[L"desc"].has_number_field(L"guidance")) + ammoItem.guidance = ammoJson[L"desc"][L"guidance"].as_number().to_uint32(); + + if (ammoJson[L"desc"].has_number_field(L"category")) + ammoItem.category = ammoJson[L"desc"][L"category"].as_number().to_uint32(); + + if (ammoJson[L"desc"].has_number_field(L"missileCategory")) + ammoItem.missileCategory = ammoJson[L"desc"][L"missileCategory"].as_number().to_uint32(); + } ammo.push_back(ammoItem); } setAmmo(ammo); @@ -212,8 +219,11 @@ void Unit::getData(stringstream& ss, unsigned long long time) const unsigned char endOfData = DataIndex::endOfData; ss.write((const char*)&ID, sizeof(ID)); - if (!alive) { - appendNumeric(ss, DataIndex::alive, alive); + if (!alive && time == 0) { + unsigned char datumIndex = DataIndex::category; + appendString(ss, datumIndex, category); + datumIndex = DataIndex::alive; + appendNumeric(ss, datumIndex, alive); } else { for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++) diff --git a/src/core/src/weapon.cpp b/src/core/src/weapon.cpp index 597c9108..d826bacb 100644 --- a/src/core/src/weapon.cpp +++ b/src/core/src/weapon.cpp @@ -72,17 +72,25 @@ void Weapon::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::coalition: appendNumeric(ss, datumIndex, coalition); break; - case DataIndex::name: appendString(ss, datumIndex, name); 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; + if (!alive && time == 0) { + unsigned char datumIndex = DataIndex::category; + appendString(ss, datumIndex, category); + datumIndex = DataIndex::alive; + appendNumeric(ss, datumIndex, 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::coalition: appendNumeric(ss, datumIndex, coalition); break; + case DataIndex::name: appendString(ss, datumIndex, name); 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; + } } } } diff --git a/src/shared/include/defines.h b/src/shared/include/defines.h index 13608f69..5de8ace4 100644 --- a/src/shared/include/defines.h +++ b/src/shared/include/defines.h @@ -1,6 +1,6 @@ #pragma once -#define VERSION "v0.4.0-alpha" +#define VERSION "v0.4.1-alpha" #define LOG_NAME "Olympus_log.txt" #define REST_ADDRESS "http://localhost:30000" #define REST_URI "olympus"