From 8977ba9b6d8e465bef664badda1b44db514e6c2a Mon Sep 17 00:00:00 2001 From: Pax1601 Date: Fri, 15 Sep 2023 09:36:27 +0200 Subject: [PATCH 1/3] Added basic simulated firefight state --- .../public/stylesheets/other/contextmenus.css | 4 + client/src/constants/constants.ts | 2 +- client/src/map/map.ts | 8 +- client/src/server/server.ts | 6 + client/src/unit/unit.ts | 6 +- client/src/unit/unitsmanager.ts | 12 ++ scripts/OlympusCommand.lua | 27 ++-- scripts/python/generateGunData.py | 21 ++++ scripts/python/gundata.h | 109 ++++++++++++++++ src/core/core.vcxproj | 1 + src/core/core.vcxproj.filters | 3 + src/core/include/commands.h | 50 +++++--- src/core/include/datatypes.h | 8 +- src/core/include/gundata.h | 116 ++++++++++++++++++ src/core/include/unit.h | 2 + src/core/src/airunit.cpp | 18 ++- src/core/src/groundunit.cpp | 53 +++++++- src/core/src/navyunit.cpp | 28 ++++- src/core/src/scheduler.cpp | 13 ++ src/core/src/unit.cpp | 18 ++- 20 files changed, 461 insertions(+), 44 deletions(-) create mode 100644 scripts/python/generateGunData.py create mode 100644 scripts/python/gundata.h create mode 100644 src/core/include/gundata.h diff --git a/client/public/stylesheets/other/contextmenus.css b/client/public/stylesheets/other/contextmenus.css index 877dac63..fe9e5837 100644 --- a/client/public/stylesheets/other/contextmenus.css +++ b/client/public/stylesheets/other/contextmenus.css @@ -369,6 +369,10 @@ content: url("/resources/theme/images/icons/crosshairs-solid.svg"); } +#simulate-fire-fight::before { + content: url("/resources/theme/images/icons/crosshairs-solid.svg"); +} + #follow::before { content: url("/resources/theme/images/icons/follow.svg"); } diff --git a/client/src/constants/constants.ts b/client/src/constants/constants.ts index d1124434..6e6a35fa 100644 --- a/client/src/constants/constants.ts +++ b/client/src/constants/constants.ts @@ -20,7 +20,7 @@ export const IRST = 8; export const RWR = 16; export const DLINK = 32; -export const states: string[] = ["none", "idle", "reach-destination", "attack", "follow", "land", "refuel", "AWACS", "tanker", "bomb-point", "carpet-bomb", "bomb-building", "fire-at-area"]; +export const states: string[] = ["none", "idle", "reach-destination", "attack", "follow", "land", "refuel", "AWACS", "tanker", "bomb-point", "carpet-bomb", "bomb-building", "fire-at-area", "simulate-fire-fight"]; export const ROEs: string[] = ["free", "designated", "", "return", "hold"]; export const reactionsToThreat: string[] = ["none", "manoeuvre", "passive", "evade"]; export const emissionsCountermeasures: string[] = ["silent", "attack", "defend", "free"]; diff --git a/client/src/map/map.ts b/client/src/map/map.ts index 93f86408..c2575192 100644 --- a/client/src/map/map.ts +++ b/client/src/map/map.ts @@ -579,8 +579,10 @@ export class Map extends L.Map { } } else if (selectedUnitTypes.length === 1 && ["GroundUnit", "NavyUnit"].includes(selectedUnitTypes[0])) { - if (selectedUnits.every((unit: Unit) => { return ["Gun Artillery", "Rocket Artillery", "Infantry", "IFV", "Tank", "Cruiser", "Destroyer", "Frigate"].includes(unit.getType()) })) + if (selectedUnits.every((unit: Unit) => { return ["Gun Artillery", "Rocket Artillery", "Infantry", "IFV", "Tank", "Cruiser", "Destroyer", "Frigate"].includes(unit.getType()) })) { options["fire-at-area"] = { text: "Fire at area", tooltip: "Fire at a large area" }; + options["simulate-fire-fight"] = { text: "Simulate fire fight", tooltip: "Simulate a fire fight by shooting randomly in a certain large area" }; + } else getInfoPopup().setText(`Selected units can not perform point actions.`); } @@ -604,6 +606,10 @@ export class Map extends L.Map { getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); getUnitsManager().selectedUnitsFireAtArea(this.getMouseCoordinates()); } + else if (option === "simulate-fire-fight") { + getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); + getUnitsManager().selectedUnitsSimulateFireFight(this.getMouseCoordinates()); + } }); } }, 150); diff --git a/client/src/server/server.ts b/client/src/server/server.ts index 05695c86..9938d026 100644 --- a/client/src/server/server.ts +++ b/client/src/server/server.ts @@ -319,6 +319,12 @@ export function fireAtArea(ID: number, latlng: LatLng, callback: CallableFunctio POST(data, callback); } +export function simulateFireFight(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "location": latlng } + var data = { "simulateFireFight": command } + POST(data, callback); +} + export function setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => {}) { var command = { "ID": ID, diff --git a/client/src/unit/unit.ts b/client/src/unit/unit.ts index 540ee7b7..e077187e 100644 --- a/client/src/unit/unit.ts +++ b/client/src/unit/unit.ts @@ -1,7 +1,7 @@ import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker, Map, Point } from 'leaflet'; import { getMap, getMissionHandler, getUnitsManager, getWeaponsManager } from '..'; import { enumToCoalition, enumToEmissioNCountermeasure, getMarkerCategoryByName, enumToROE, enumToReactionToThreat, enumToState, getUnitDatabaseByCategory, mToFt, msToKnots, rad2deg, bearing, deg2rad, ftToM } from '../other/utils'; -import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit, setEmissionsCountermeasures, setSpeedType, setAltitudeType, setOnOff, setFollowRoads, bombPoint, carpetBomb, bombBuilding, fireAtArea } from '../server/server'; +import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit, setEmissionsCountermeasures, setSpeedType, setAltitudeType, setOnOff, setFollowRoads, bombPoint, carpetBomb, bombBuilding, fireAtArea, simulateFireFight } from '../server/server'; import { CustomMarker } from '../map/markers/custommarker'; import { SVGInjector } from '@tanem/svg-injector'; import { UnitDatabase } from './databases/unitdatabase'; @@ -717,6 +717,10 @@ export class Unit extends CustomMarker { fireAtArea(this.ID, latlng); } + simulateFireFight(latlng: LatLng) { + simulateFireFight(this.ID, latlng); + } + /***********************************************/ onAdd(map: Map): this { super.onAdd(map); diff --git a/client/src/unit/unitsmanager.ts b/client/src/unit/unitsmanager.ts index cf1808a3..ba877ea3 100644 --- a/client/src/unit/unitsmanager.ts +++ b/client/src/unit/unitsmanager.ts @@ -605,6 +605,18 @@ export class UnitsManager { this.#showActionMessage(selectedUnits, `unit bombing point`); } + /** Instruct the selected units to simulate a fire fight at specific coordinates + * + * @param latlng Location to fire at + */ + selectedUnitsSimulateFireFight(latlng: LatLng) { + var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }); + for (let idx in selectedUnits) { + selectedUnits[idx].simulateFireFight(latlng); + } + this.#showActionMessage(selectedUnits, `unit simulating fire fight`); + } + /*********************** Control operations on selected units ************************/ /** See getUnitsCategories for more info * diff --git a/scripts/OlympusCommand.lua b/scripts/OlympusCommand.lua index 6518d6ca..d38f380e 100644 --- a/scripts/OlympusCommand.lua +++ b/scripts/OlympusCommand.lua @@ -1,6 +1,6 @@ local version = "v0.4.4-alpha" -local debug = false -- True enables debug printing using DCS messages +local debug = true -- True enables debug printing using DCS messages -- .dll related variables Olympus.OlympusDLL = nil @@ -229,13 +229,24 @@ function Olympus.buildTask(groupName, options) -- Fire at a specific point elseif options['id'] == 'FireAtPoint' and options['lat'] and options['lng'] and options['radius'] then local point = coord.LLtoLO(options['lat'], options['lng'], 0) - task = { - id = 'FireAtPoint', - params = { - point = {x = point.x, y = point.z}, - radius = options['radius'] - } - } + if options['alt'] then + task = { + id = 'FireAtPoint', + params = { + point = {x = point.x, y = point.z}, + radius = options['radius'], + altitude = options['alt'] + } + } + else + task = { + id = 'FireAtPoint', + params = { + point = {x = point.x, y = point.z}, + radius = options['radius'] + } + } + end end end return task diff --git a/scripts/python/generateGunData.py b/scripts/python/generateGunData.py new file mode 100644 index 00000000..858cc28e --- /dev/null +++ b/scripts/python/generateGunData.py @@ -0,0 +1,21 @@ +import sys +import json +import inspect +import difflib +from slpp import slpp as lua + +SEARCH_FOLDER = "D:\\Eagle Dynamics\\DCS World OpenBeta" + +sys.path.append("..\\..\\..\\dcs-master\\dcs-master") + +from dcs.vehicles import * + +with open("gundata.h", "w") as f: + for unit in vehicle_map.values(): + if unit in Artillery.__dict__.values() or unit in Armor.__dict__.values() or unit in Infantry.__dict__.values(): + f.write('{"' + unit.id + '", {0.9, 860}}, \n') + +# Done! +print("Done!") + + \ No newline at end of file diff --git a/scripts/python/gundata.h b/scripts/python/gundata.h new file mode 100644 index 00000000..d28a26e5 --- /dev/null +++ b/scripts/python/gundata.h @@ -0,0 +1,109 @@ +{"2B11 mortar", {0.9, 860}}, +{"SAU Gvozdika", {0.9, 860}}, +{"SAU Msta", {0.9, 860}}, +{"SAU Akatsia", {0.9, 860}}, +{"SAU 2-C9", {0.9, 860}}, +{"M-109", {0.9, 860}}, +{"SpGH_Dana", {0.9, 860}}, +{"AAV7", {0.9, 860}}, +{"BMD-1", {0.9, 860}}, +{"BMP-1", {0.9, 860}}, +{"BMP-2", {0.9, 860}}, +{"BMP-3", {0.9, 860}}, +{"BRDM-2", {0.9, 860}}, +{"BTR_D", {0.9, 860}}, +{"Cobra", {0.9, 860}}, +{"LAV-25", {0.9, 860}}, +{"M1043 HMMWV Armament", {0.9, 860}}, +{"M1045 HMMWV TOW", {0.9, 860}}, +{"M1126 Stryker ICV", {0.9, 860}}, +{"M-113", {0.9, 860}}, +{"M1134 Stryker ATGM", {0.9, 860}}, +{"M-2 Bradley", {0.9, 860}}, +{"MCV-80", {0.9, 860}}, +{"MTLB", {0.9, 860}}, +{"Marder", {0.9, 860}}, +{"TPZ", {0.9, 860}}, +{"Grad_FDDM", {0.9, 860}}, +{"Paratrooper RPG-16", {0.9, 860}}, +{"Paratrooper AKS-74", {0.9, 860}}, +{"Infantry AK Ins", {0.9, 860}}, +{"Soldier AK", {0.9, 860}}, +{"Infantry AK", {0.9, 860}}, +{"Soldier M249", {0.9, 860}}, +{"Soldier M4", {0.9, 860}}, +{"Soldier M4 GRG", {0.9, 860}}, +{"Soldier RPG", {0.9, 860}}, +{"MLRS FDDM", {0.9, 860}}, +{"Infantry AK ver2", {0.9, 860}}, +{"Infantry AK ver3", {0.9, 860}}, +{"Grad-URAL", {0.9, 860}}, +{"Uragan_BM-27", {0.9, 860}}, +{"Smerch", {0.9, 860}}, +{"Smerch_HE", {0.9, 860}}, +{"MLRS", {0.9, 860}}, +{"Challenger2", {0.9, 860}}, +{"Leclerc", {0.9, 860}}, +{"M-60", {0.9, 860}}, +{"M1128 Stryker MGS", {0.9, 860}}, +{"M-1 Abrams", {0.9, 860}}, +{"T-55", {0.9, 860}}, +{"T-72B", {0.9, 860}}, +{"T-80UD", {0.9, 860}}, +{"T-90", {0.9, 860}}, +{"Leopard1A3", {0.9, 860}}, +{"Merkava_Mk4", {0.9, 860}}, +{"JTAC", {0.9, 860}}, +{"Infantry Animated", {0.9, 860}}, +{"HL_DSHK", {0.9, 860}}, +{"HL_KORD", {0.9, 860}}, +{"tt_DSHK", {0.9, 860}}, +{"tt_KORD", {0.9, 860}}, +{"HL_B8M1", {0.9, 860}}, +{"tt_B8M1", {0.9, 860}}, +{"M4_Sherman", {0.9, 860}}, +{"M2A1_halftrack", {0.9, 860}}, +{"BTR-80", {0.9, 860}}, +{"T-72B3", {0.9, 860}}, +{"PT_76", {0.9, 860}}, +{"BTR-82A", {0.9, 860}}, +{"Chieftain_mk3", {0.9, 860}}, +{"Pz_IV_H", {0.9, 860}}, +{"Leopard-2A5", {0.9, 860}}, +{"Leopard-2", {0.9, 860}}, +{"leopard-2A4", {0.9, 860}}, +{"leopard-2A4_trs", {0.9, 860}}, +{"Sd_Kfz_251", {0.9, 860}}, +{"T155_Firtina", {0.9, 860}}, +{"VAB_Mephisto", {0.9, 860}}, +{"ZTZ96B", {0.9, 860}}, +{"ZBD04A", {0.9, 860}}, +{"PLZ05", {0.9, 860}}, +{"TYPE-59", {0.9, 860}}, +{"Tiger_I", {0.9, 860}}, +{"Tiger_II_H", {0.9, 860}}, +{"Pz_V_Panther_G", {0.9, 860}}, +{"Jagdpanther_G1", {0.9, 860}}, +{"JagdPz_IV", {0.9, 860}}, +{"Stug_IV", {0.9, 860}}, +{"SturmPzIV", {0.9, 860}}, +{"Wespe124", {0.9, 860}}, +{"Sd_Kfz_234_2_Puma", {0.9, 860}}, +{"soldier_mauser98", {0.9, 860}}, +{"Stug_III", {0.9, 860}}, +{"Elefant_SdKfz_184", {0.9, 860}}, +{"Pak40", {0.9, 860}}, +{"LeFH_18-40-105", {0.9, 860}}, +{"Cromwell_IV", {0.9, 860}}, +{"M4A4_Sherman_FF", {0.9, 860}}, +{"soldier_wwii_br_01", {0.9, 860}}, +{"Centaur_IV", {0.9, 860}}, +{"Churchill_VII", {0.9, 860}}, +{"Daimler_AC", {0.9, 860}}, +{"Tetrarch", {0.9, 860}}, +{"M12_GMC", {0.9, 860}}, +{"soldier_wwii_us", {0.9, 860}}, +{"M10_GMC", {0.9, 860}}, +{"M8_Greyhound", {0.9, 860}}, +{"M2A1-105", {0.9, 860}}, +{"M4_Tractor", {0.9, 860}}, diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 7c46020d..da1d2d5e 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -37,6 +37,7 @@ + diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 56fade36..cfb10c59 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -54,6 +54,9 @@ Header Files + + Header Files + diff --git a/src/core/include/commands.h b/src/core/include/commands.h index 58279826..6bf3da9d 100644 --- a/src/core/include/commands.h +++ b/src/core/include/commands.h @@ -95,21 +95,26 @@ namespace ECMUse { class Command { public: + Command(function callback) : callback(callback) {}; unsigned int getPriority() { return priority; } virtual string getString() = 0; virtual unsigned int getLoad() = 0; const string getHash() { return hash; } + void executeCallback() { callback(); } protected: unsigned int priority = CommandPriority::LOW; const string hash = random_string(16); + function callback; }; /* Simple low priority move command (from user click) */ class Move : public Command { public: - Move(string groupName, Coords destination, double speed, string speedType, double altitude, string altitudeType, string taskOptions, string category): + Move(string groupName, Coords destination, double speed, string speedType, double altitude, + string altitudeType, string taskOptions, string category, function callback = []() {}) : + Command(callback), groupName(groupName), destination(destination), speed(speed), @@ -139,7 +144,8 @@ private: class Smoke : public Command { public: - Smoke(string color, Coords location) : + Smoke(string color, Coords location, function callback = [](){}) : + Command(callback), color(color), location(location) { @@ -157,7 +163,8 @@ private: class SpawnGroundUnits : public Command { public: - SpawnGroundUnits(string coalition, vector spawnOptions, string country, bool immediate) : + SpawnGroundUnits(string coalition, vector spawnOptions, string country, bool immediate, function callback = [](){}) : + Command(callback), coalition(coalition), spawnOptions(spawnOptions), country(country), @@ -179,7 +186,8 @@ private: class SpawnNavyUnits : public Command { public: - SpawnNavyUnits(string coalition, vector spawnOptions, string country, bool immediate) : + SpawnNavyUnits(string coalition, vector spawnOptions, string country, bool immediate, function callback = [](){}) : + Command(callback), coalition(coalition), spawnOptions(spawnOptions), country(country), @@ -201,7 +209,8 @@ private: class SpawnAircrafts : public Command { public: - SpawnAircrafts(string coalition, vector spawnOptions, string airbaseName, string country, bool immediate) : + SpawnAircrafts(string coalition, vector spawnOptions, string airbaseName, string country, bool immediate, function callback = [](){}) : + Command(callback), coalition(coalition), spawnOptions(spawnOptions), airbaseName(airbaseName), @@ -221,12 +230,12 @@ private: const bool immediate; }; - /* Spawn helicopter command */ class SpawnHelicopters : public Command { public: - SpawnHelicopters(string coalition, vector spawnOptions, string airbaseName, string country, bool immediate) : + SpawnHelicopters(string coalition, vector spawnOptions, string airbaseName, string country, bool immediate, function callback = [](){}) : + Command(callback), coalition(coalition), spawnOptions(spawnOptions), airbaseName(airbaseName), @@ -250,7 +259,8 @@ private: class Clone : public Command { public: - Clone(vector cloneOptions, bool deleteOriginal) : + Clone(vector cloneOptions, bool deleteOriginal, function callback = [](){}) : + Command(callback), cloneOptions(cloneOptions), deleteOriginal(deleteOriginal) { @@ -268,7 +278,8 @@ private: class Delete : public Command { public: - Delete(unsigned int ID, bool explosion, bool immediate ) : + Delete(unsigned int ID, bool explosion, bool immediate, function callback = [](){}) : + Command(callback), ID(ID), explosion(explosion), immediate(immediate) @@ -289,7 +300,8 @@ private: class SetTask : public Command { public: - SetTask(string groupName, string task) : + SetTask(string groupName, string task, function callback = [](){}) : + Command(callback), groupName(groupName), task(task) { @@ -307,7 +319,8 @@ private: class ResetTask : public Command { public: - ResetTask(string groupName) : + ResetTask(string groupName, function callback = [](){}) : + Command(callback), groupName(groupName) { priority = CommandPriority::HIGH; @@ -323,7 +336,8 @@ private: class SetCommand : public Command { public: - SetCommand(string groupName, string command) : + SetCommand(string groupName, string command, function callback = [](){}) : + Command(callback), groupName(groupName), command(command) { @@ -341,7 +355,8 @@ private: class SetOption : public Command { public: - SetOption(string groupName, unsigned int optionID, unsigned int optionValue) : + SetOption(string groupName, unsigned int optionID, unsigned int optionValue, function callback = [](){}) : + Command(callback), groupName(groupName), optionID(optionID), optionValue(optionValue), @@ -351,7 +366,8 @@ public: priority = CommandPriority::HIGH; }; - SetOption(string groupName, unsigned int optionID, bool optionBool) : + SetOption(string groupName, unsigned int optionID, bool optionBool, function callback = [](){}) : + Command(callback), groupName(groupName), optionID(optionID), optionValue(0), @@ -375,7 +391,8 @@ private: class SetOnOff : public Command { public: - SetOnOff(string groupName, bool onOff) : + SetOnOff(string groupName, bool onOff, function callback = [](){}) : + Command(callback), groupName(groupName), onOff(onOff) { @@ -393,7 +410,8 @@ private: class Explosion : public Command { public: - Explosion(unsigned int intensity, Coords location) : + Explosion(unsigned int intensity, Coords location, function callback = [](){}) : + Command(callback), location(location), intensity(intensity) { diff --git a/src/core/include/datatypes.h b/src/core/include/datatypes.h index f3859456..f8be70fa 100644 --- a/src/core/include/datatypes.h +++ b/src/core/include/datatypes.h @@ -64,7 +64,8 @@ namespace State BOMB_POINT, CARPET_BOMB, BOMB_BUILDING, - FIRE_AT_AREA + FIRE_AT_AREA, + SIMULATE_FIRE_FIGHT }; }; @@ -125,4 +126,9 @@ struct SpawnOptions { struct CloneOptions { unsigned int ID; Coords location; +}; + +struct GunDataItem { + double barrelHeight; + double muzzleVelocity; }; \ No newline at end of file diff --git a/src/core/include/gundata.h b/src/core/include/gundata.h new file mode 100644 index 00000000..b463f423 --- /dev/null +++ b/src/core/include/gundata.h @@ -0,0 +1,116 @@ +#pragma once + +#include "framework.h" +#include "datatypes.h" + +map gunData = { +{"2B11 mortar", {0.9, 860}}, +{"SAU Gvozdika", {0.9, 860}}, +{"SAU Msta", {0.9, 860}}, +{"SAU Akatsia", {0.9, 860}}, +{"SAU 2-C9", {0.9, 860}}, +{"M-109", {0.9, 860}}, +{"SpGH_Dana", {0.9, 860}}, +{"AAV7", {0.9, 860}}, +{"BMD-1", {0.9, 860}}, +{"BMP-1", {0.9, 860}}, +{"BMP-2", {0.9, 860}}, +{"BMP-3", {0.9, 860}}, +{"BRDM-2", {0.9, 860}}, +{"BTR_D", {0.9, 860}}, +{"Cobra", {0.9, 860}}, +{"LAV-25", {0.9, 860}}, +{"M1043 HMMWV Armament", {0.9, 860}}, +{"M1045 HMMWV TOW", {0.9, 860}}, +{"M1126 Stryker ICV", {0.9, 860}}, +{"M-113", {0.9, 860}}, +{"M1134 Stryker ATGM", {0.9, 860}}, +{"M-2 Bradley", {0.9, 860}}, +{"MCV-80", {0.9, 860}}, +{"MTLB", {0.9, 860}}, +{"Marder", {0.9, 860}}, +{"TPZ", {0.9, 860}}, +{"Grad_FDDM", {0.9, 860}}, +{"Paratrooper RPG-16", {0.9, 860}}, +{"Paratrooper AKS-74", {0.9, 860}}, +{"Infantry AK Ins", {0.9, 860}}, +{"Soldier AK", {0.4, 860}}, +{"Infantry AK", {0.9, 860}}, +{"Soldier M249", {0.9, 860}}, +{"Soldier M4", {0.9, 860}}, +{"Soldier M4 GRG", {0.9, 860}}, +{"Soldier RPG", {0.9, 860}}, +{"MLRS FDDM", {0.9, 860}}, +{"Infantry AK ver2", {0.9, 860}}, +{"Infantry AK ver3", {0.9, 860}}, +{"Grad-URAL", {0.9, 860}}, +{"Uragan_BM-27", {0.9, 860}}, +{"Smerch", {0.9, 860}}, +{"Smerch_HE", {0.9, 860}}, +{"MLRS", {0.9, 860}}, +{"Challenger2", {0.9, 860}}, +{"Leclerc", {0.9, 860}}, +{"M-60", {0.9, 860}}, +{"M1128 Stryker MGS", {0.9, 860}}, +{"M-1 Abrams", {0.9, 860}}, +{"T-55", {0.9, 860}}, +{"T-72B", {0.9, 860}}, +{"T-80UD", {0.9, 860}}, +{"T-90", {0.9, 860}}, +{"Leopard1A3", {0.9, 860}}, +{"Merkava_Mk4", {0.9, 860}}, +{"JTAC", {0.9, 860}}, +{"Infantry Animated", {0.9, 860}}, +{"HL_DSHK", {0.9, 860}}, +{"HL_KORD", {0.9, 860}}, +{"tt_DSHK", {0.9, 860}}, +{"tt_KORD", {0.9, 860}}, +{"HL_B8M1", {0.9, 860}}, +{"tt_B8M1", {0.9, 860}}, +{"M4_Sherman", {0.9, 860}}, +{"M2A1_halftrack", {0.9, 860}}, +{"BTR-80", {0.9, 860}}, +{"T-72B3", {0.9, 860}}, +{"PT_76", {0.9, 860}}, +{"BTR-82A", {0.9, 860}}, +{"Chieftain_mk3", {0.9, 860}}, +{"Pz_IV_H", {0.9, 860}}, +{"Leopard-2A5", {0.9, 860}}, +{"Leopard-2", {0.9, 860}}, +{"leopard-2A4", {0.9, 860}}, +{"leopard-2A4_trs", {0.9, 860}}, +{"Sd_Kfz_251", {0.9, 860}}, +{"T155_Firtina", {0.9, 860}}, +{"VAB_Mephisto", {0.9, 860}}, +{"ZTZ96B", {0.9, 860}}, +{"ZBD04A", {0.9, 860}}, +{"PLZ05", {0.9, 860}}, +{"TYPE-59", {0.9, 860}}, +{"Tiger_I", {0.9, 860}}, +{"Tiger_II_H", {0.9, 860}}, +{"Pz_V_Panther_G", {0.9, 860}}, +{"Jagdpanther_G1", {0.9, 860}}, +{"JagdPz_IV", {0.9, 860}}, +{"Stug_IV", {0.9, 860}}, +{"SturmPzIV", {0.9, 860}}, +{"Wespe124", {0.9, 860}}, +{"Sd_Kfz_234_2_Puma", {0.9, 860}}, +{"soldier_mauser98", {0.9, 860}}, +{"Stug_III", {0.9, 860}}, +{"Elefant_SdKfz_184", {0.9, 860}}, +{"Pak40", {0.9, 860}}, +{"LeFH_18-40-105", {0.9, 860}}, +{"Cromwell_IV", {0.9, 860}}, +{"M4A4_Sherman_FF", {0.9, 860}}, +{"soldier_wwii_br_01", {0.9, 860}}, +{"Centaur_IV", {0.9, 860}}, +{"Churchill_VII", {0.9, 860}}, +{"Daimler_AC", {0.9, 860}}, +{"Tetrarch", {0.9, 860}}, +{"M12_GMC", {0.9, 860}}, +{"soldier_wwii_us", {0.9, 860}}, +{"M10_GMC", {0.9, 860}}, +{"M8_Greyhound", {0.9, 860}}, +{"M2A1-105", {0.9, 860}}, +{"M4_Tractor", {0.9, 860}}, +}; \ No newline at end of file diff --git a/src/core/include/unit.h b/src/core/include/unit.h index b0fdc56e..b36b4d9b 100644 --- a/src/core/include/unit.h +++ b/src/core/include/unit.h @@ -54,6 +54,7 @@ public: void resetTask(); bool checkTaskFailed(); void resetTaskFailedCounter(); + void setHasTaskAssigned(bool newHasTaskAssigned); void triggerUpdate(unsigned char datumIndex); @@ -185,6 +186,7 @@ protected: /********** Other **********/ unsigned int taskCheckCounter = 0; + bool hasTaskAssigned = false; double initialFuel = 0; map updateTimeMap; unsigned long long lastLoopTime = 0; diff --git a/src/core/src/airunit.cpp b/src/core/src/airunit.cpp index 2ea3e1c9..875f64d4 100644 --- a/src/core/src/airunit.cpp +++ b/src/core/src/airunit.cpp @@ -162,7 +162,7 @@ void AirUnit::AIloop() desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << (desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "'}"; } - Command* command = dynamic_cast(new SetTask(groupName, taskSS.str())); + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); scheduler->appendCommand(command); setHasTask(true); } @@ -267,7 +267,7 @@ void AirUnit::AIloop() << "z = " << formationOffset.z << "}," << "}"; - Command* command = dynamic_cast(new SetTask(groupName, taskSS.str())); + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); scheduler->appendCommand(command); setHasTask(true); } @@ -283,7 +283,7 @@ void AirUnit::AIloop() taskSS << "{" << "id = 'Refuel'" << "}"; - Command* command = dynamic_cast(new SetTask(groupName, taskSS.str())); + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); scheduler->appendCommand(command); setHasTask(true); } @@ -297,8 +297,10 @@ void AirUnit::AIloop() if (!getHasTask()) { std::ostringstream taskSS; + taskSS.precision(10); + taskSS << "{id = 'Bombing', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}"; - Command* command = dynamic_cast(new SetTask(groupName, taskSS.str())); + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); scheduler->appendCommand(command); setHasTask(true); } @@ -308,8 +310,10 @@ void AirUnit::AIloop() if (!getHasTask()) { std::ostringstream taskSS; + taskSS.precision(10); + taskSS << "{id = 'CarpetBombing', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}"; - Command* command = dynamic_cast(new SetTask(groupName, taskSS.str())); + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); scheduler->appendCommand(command); setHasTask(true); } @@ -320,8 +324,10 @@ void AirUnit::AIloop() if (!getHasTask()) { std::ostringstream taskSS; + taskSS.precision(10); + taskSS << "{id = 'AttackMapObject', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}"; - Command* command = dynamic_cast(new SetTask(groupName, taskSS.str())); + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); scheduler->appendCommand(command); setHasTask(true); } diff --git a/src/core/src/groundunit.cpp b/src/core/src/groundunit.cpp index 693f8091..69e76b83 100644 --- a/src/core/src/groundunit.cpp +++ b/src/core/src/groundunit.cpp @@ -4,7 +4,8 @@ #include "commands.h" #include "scheduler.h" #include "defines.h" -#include "unitsManager.h" +#include "unitsmanager.h" +#include "gundata.h" #include using namespace GeographicLib; @@ -49,6 +50,10 @@ void GroundUnit::setState(unsigned char newState) setTargetPosition(Coords(NULL)); break; } + case State::SIMULATE_FIRE_FIGHT: { + setTargetPosition(Coords(NULL)); + break; + } default: break; } @@ -70,12 +75,16 @@ void GroundUnit::setState(unsigned char newState) resetActiveDestination(); break; } + case State::SIMULATE_FIRE_FIGHT: { + clearActivePath(); + resetActiveDestination(); + break; + } default: break; } - if (newState != state) - resetTask(); + resetTask(); log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState)); state = newState; @@ -122,8 +131,42 @@ void GroundUnit::AIloop() if (!getHasTask()) { std::ostringstream taskSS; + taskSS.precision(10); taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1000}"; - Command* command = dynamic_cast(new SetTask(groupName, taskSS.str())); + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); + scheduler->appendCommand(command); + setHasTask(true); + } + } + case State::SIMULATE_FIRE_FIGHT: { + setTask("Simulating fire fight"); + + if (!getHasTask() || ((double)(rand()) / (double)(RAND_MAX)) < 0.01) { + double dist; + double bearing1; + double bearing2; + Geodesic::WGS84().Inverse(position.lat, position.lng, targetPosition.lat, targetPosition.lng, dist, bearing1, bearing2); + + double r = 5; /* m */ + /* Default gun values */ + double barrelHeight = 1.0; /* m */ + double muzzleVelocity = 860; /* m/s */ + if (gunData.find(name) != gunData.end()) { + barrelHeight = gunData[name].barrelHeight; + muzzleVelocity = gunData[name].muzzleVelocity; + } + + double barrelElevation = r * (9.81 * dist / (2 * muzzleVelocity * muzzleVelocity) - barrelHeight / dist); /* m */ + + double lat = 0; + double lng = 0; + double randomBearing = bearing1 + (((double)(rand()) / (double)(RAND_MAX) - 0.5) * 2) * 45; + Geodesic::WGS84().Direct(position.lat, position.lng, randomBearing, r, lat, lng); + + std::ostringstream taskSS; + taskSS.precision(10); + taskSS << "{id = 'FireAtPoint', lat = " << lat << ", lng = " << lng << ", alt = " << barrelElevation + barrelHeight << ", radius = 0.001}"; + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); scheduler->appendCommand(command); setHasTask(true); } @@ -161,4 +204,4 @@ void GroundUnit::setFollowRoads(bool newFollowRoads, bool force) Unit::setFollowRoads(newFollowRoads, force); resetActiveDestination(); /* Reset active destination to apply option*/ } -} \ No newline at end of file +} diff --git a/src/core/src/navyunit.cpp b/src/core/src/navyunit.cpp index 1892a8ca..d2c68a3d 100644 --- a/src/core/src/navyunit.cpp +++ b/src/core/src/navyunit.cpp @@ -49,6 +49,10 @@ void NavyUnit::setState(unsigned char newState) setTargetPosition(Coords(NULL)); break; } + case State::SIMULATE_FIRE_FIGHT: { + setTargetPosition(Coords(NULL)); + break; + } default: break; } @@ -68,6 +72,13 @@ void NavyUnit::setState(unsigned char newState) case State::FIRE_AT_AREA: { clearActivePath(); resetActiveDestination(); + resetTask(); + break; + } + case State::SIMULATE_FIRE_FIGHT: { + clearActivePath(); + resetActiveDestination(); + resetTask(); break; } default: @@ -118,8 +129,23 @@ void NavyUnit::AIloop() if (!getHasTask()) { std::ostringstream taskSS; + taskSS.precision(10); + taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1000}"; - Command* command = dynamic_cast(new SetTask(groupName, taskSS.str())); + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); + scheduler->appendCommand(command); + setHasTask(true); + } + } + case State::SIMULATE_FIRE_FIGHT: { + setTask("Simulating fire fight"); + + if (!getHasTask()) { + std::ostringstream taskSS; + taskSS.precision(10); + + taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1}"; + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); scheduler->appendCommand(command); setHasTask(true); } diff --git a/src/core/src/scheduler.cpp b/src/core/src/scheduler.cpp index 742f5c5b..182318bd 100644 --- a/src/core/src/scheduler.cpp +++ b/src/core/src/scheduler.cpp @@ -61,6 +61,7 @@ void Scheduler::execute(lua_State* L) load = command->getLoad(); commands.remove(command); executedCommandsHashes.push_back(command->getHash()); + command->executeCallback(); /* Execute the command callback (this is a lambda function that can be used to execute a function when the command is run) */ delete command; return; } @@ -561,6 +562,18 @@ void Scheduler::handleRequest(string key, json::value value, string username, js unit->setTargetPosition(loc); log(username + " tasked unit " + unit->getName() + " to fire at area", true); } + else if (key.compare("simulateFireFight") == 0) + { + unsigned int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); + double lat = value[L"location"][L"lat"].as_double(); + double lng = value[L"location"][L"lng"].as_double(); + Coords loc; loc.lat = lat; loc.lng = lng; + Unit* unit = unitsManager->getGroupLeader(ID); + unit->setState(State::SIMULATE_FIRE_FIGHT); + unit->setTargetPosition(loc); + log(username + " tasked unit " + unit->getName() + " to simulate a fire fight", true); + } else if (key.compare("setCommandModeOptions") == 0) { setCommandModeOptions(value); log(username + " updated the Command Mode Options", true); diff --git a/src/core/src/unit.cpp b/src/core/src/unit.cpp index 4b2f2fa0..4aaf5d8a 100644 --- a/src/core/src/unit.cpp +++ b/src/core/src/unit.cpp @@ -146,8 +146,10 @@ void Unit::runAILoop() { /* If the unit is alive, controlled, is the leader of the group and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */ if (getAlive() && getControlled() && !getHuman() && getIsLeader()) { - if (checkTaskFailed() && state != State::IDLE && state != State::LAND) + if (checkTaskFailed() && state != State::IDLE && state != State::LAND) { + log(unitName + " has no task, switching to IDLE state"); setState(State::IDLE); + } AIloop(); } @@ -397,7 +399,7 @@ void Unit::resetActiveDestination() void Unit::resetTask() { - Command* command = dynamic_cast(new ResetTask(groupName)); + Command* command = dynamic_cast(new ResetTask(groupName, [this]() { this->setHasTaskAssigned(false); })); scheduler->appendCommand(command); setHasTask(false); resetTaskFailedCounter(); @@ -660,7 +662,7 @@ void Unit::goToDestination(string enrouteTask) { if (activeDestination != NULL) { - Command* command = dynamic_cast(new Move(groupName, activeDestination, getDesiredSpeed(), getDesiredSpeedType() ? "GS" : "CAS", getDesiredAltitude(), getDesiredAltitudeType() ? "AGL" : "ASL", enrouteTask, getCategory())); + Command* command = dynamic_cast(new Move(groupName, activeDestination, getDesiredSpeed(), getDesiredSpeedType() ? "GS" : "CAS", getDesiredAltitude(), getDesiredAltitudeType() ? "AGL" : "ASL", enrouteTask, getCategory(), [this]() { this->setHasTaskAssigned(true); })); scheduler->appendCommand(command); setHasTask(true); } @@ -732,7 +734,7 @@ bool Unit::checkTaskFailed() return false; else { if (taskCheckCounter > 0) - taskCheckCounter--; + taskCheckCounter -= hasTaskAssigned; return taskCheckCounter == 0; } } @@ -741,6 +743,14 @@ void Unit::resetTaskFailedCounter() { taskCheckCounter = TASK_CHECK_INIT_VALUE; } +void Unit::setHasTaskAssigned(bool newHasTaskAssigned) { + hasTaskAssigned = newHasTaskAssigned; + if (hasTaskAssigned) + log(unitName + " was assigned a new task"); + else + log(unitName + " no task assigned"); +} + void Unit::triggerUpdate(unsigned char datumIndex) { updateTimeMap[datumIndex] = duration_cast(system_clock::now().time_since_epoch()).count(); } From fd2b7a00e15bab35f0f46422e8f32166544e9add Mon Sep 17 00:00:00 2001 From: Pax1601 Date: Wed, 20 Sep 2023 18:58:21 +0200 Subject: [PATCH 2/3] Moved gun data into databases jsons, made core read from databases --- .../databases/units/groundunitdatabase.json | 4 +- client/src/server/server.ts | 495 ------------------ client/src/server/servermanager.ts | 6 + client/src/unit/unit.ts | 2 +- src/core/core.vcxproj | 1 - src/core/core.vcxproj.filters | 3 - src/core/include/aircraft.h | 5 + src/core/include/datatypes.h | 5 - src/core/include/groundunit.h | 3 + src/core/include/gundata.h | 116 ---- src/core/include/helicopter.h | 5 + src/core/include/navyunit.h | 4 +- src/core/src/aircraft.cpp | 20 + src/core/src/core.cpp | 9 + src/core/src/groundunit.cpp | 33 +- src/core/src/helicopter.cpp | 20 + src/core/src/navyunit.cpp | 20 + src/core/src/server.cpp | 2 +- src/shared/include/defines.h | 8 +- 19 files changed, 131 insertions(+), 630 deletions(-) delete mode 100644 client/src/server/server.ts delete mode 100644 src/core/include/gundata.h diff --git a/client/public/databases/units/groundunitdatabase.json b/client/public/databases/units/groundunitdatabase.json index 08e24921..263e32f5 100644 --- a/client/public/databases/units/groundunitdatabase.json +++ b/client/public/databases/units/groundunitdatabase.json @@ -2074,7 +2074,9 @@ "shortLabel": "Infantry AK", "filename": "", "type": "Infantry", - "enabled": true + "enabled": true, + "muzzleVelocity": 860, + "barrelHeight": 0.9 }, "KAMAZ Truck": { "name": "KAMAZ Truck", diff --git a/client/src/server/server.ts b/client/src/server/server.ts deleted file mode 100644 index 9938d026..00000000 --- a/client/src/server/server.ts +++ /dev/null @@ -1,495 +0,0 @@ -import { LatLng } from 'leaflet'; -import { getConnectionStatusPanel, getInfoPopup, getLogPanel, getMissionHandler, getServerStatusPanel, getUnitsManager, getWeaponsManager, setLoginStatus } from '..'; -import { GeneralSettings, Radio, TACAN } from '../@types/unit'; -import { AIRBASES_URI, BULLSEYE_URI, COMMANDS_URI, LOGS_URI, MISSION_URI, NONE, ROEs, UNITS_URI, WEAPONS_URI, emissionsCountermeasures, reactionsToThreat } from '../constants/constants'; - -var connected: boolean = false; -var paused: boolean = false; - -var REST_ADDRESS = "http://localhost:30000/olympus"; -var DEMO_ADDRESS = window.location.href + "demo"; - -var username = ""; -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() { - demoEnabled = !demoEnabled; -} - -export function setCredentials(newUsername: string, newPassword: string) { - username = newUsername; - password = newPassword; -} - -export function GET(callback: CallableFunction, uri: string, options?: ServerRequestOptions, responseType?: string) { - var xmlHttp = new XMLHttpRequest(); - - /* Assemble the request options string */ - var optionsString = ''; - if (options?.time != undefined) - optionsString = `time=${options.time}`; - if (options?.commandHash != undefined) - optionsString = `commandHash=${options.commandHash}`; - - /* On the connection */ - xmlHttp.open("GET", `${demoEnabled ? DEMO_ADDRESS : REST_ADDRESS}/${uri}${optionsString ? `?${optionsString}` : ''}`, true); - - /* If provided, set the credentials */ - if (username && password) - xmlHttp.setRequestHeader("Authorization", "Basic " + btoa(`${username}:${password}`)); - - /* If specified, set the response type */ - if (responseType) - xmlHttp.responseType = responseType as XMLHttpRequestResponseType; - - xmlHttp.onload = function (e) { - if (xmlHttp.status == 200) { - /* Success */ - setConnected(true); - if (xmlHttp.responseType == 'arraybuffer') - lastUpdateTimes[uri] = callback(xmlHttp.response); - else { - const result = JSON.parse(xmlHttp.responseText); - lastUpdateTimes[uri] = callback(result); - - if (result.frameRate !== undefined && result.load !== undefined) - getServerStatusPanel().update(result.frameRate, result.load); - } - } else if (xmlHttp.status == 401) { - /* Bad credentials */ - console.error("Incorrect username/password"); - setLoginStatus("failed"); - } else { - /* Failure, probably disconnected */ - setConnected(false); - } - }; - xmlHttp.onerror = function (res) { - console.error("An error occurred during the XMLHttpRequest"); - setConnected(false); - }; - xmlHttp.send(null); -} - -export function POST(request: object, callback: CallableFunction) { - var xmlHttp = new XMLHttpRequest(); - xmlHttp.open("PUT", demoEnabled ? DEMO_ADDRESS : REST_ADDRESS); - xmlHttp.setRequestHeader("Content-Type", "application/json"); - if (username && password) - xmlHttp.setRequestHeader("Authorization", "Basic " + btoa(`${username}:${password}`)); - xmlHttp.onload = (res: any) => { - var res = JSON.parse(xmlHttp.responseText); - callback(res); - }; - xmlHttp.send(JSON.stringify(request)); -} - -export function getConfig(callback: CallableFunction) { - var xmlHttp = new XMLHttpRequest(); - xmlHttp.open("GET", window.location.href + "config", true); - xmlHttp.onload = function (e) { - var data = JSON.parse(xmlHttp.responseText); - callback(data); - }; - xmlHttp.onerror = function () { - console.error("An error occurred during the XMLHttpRequest, could not retrieve configuration file"); - }; - xmlHttp.send(null); -} - -export function setAddress(address: string, port: number) { - REST_ADDRESS = `http://${address}:${port}/olympus` - console.log(`Setting REST address to ${REST_ADDRESS}`) -} - -export function getAirbases(callback: CallableFunction) { - GET(callback, AIRBASES_URI); -} - -export function getBullseye(callback: CallableFunction) { - GET(callback, BULLSEYE_URI); -} - -export function getLogs(callback: CallableFunction, refresh: boolean = false) { - GET(callback, LOGS_URI, { time: refresh ? 0 : lastUpdateTimes[LOGS_URI]}); -} - -export function getMission(callback: CallableFunction) { - GET(callback, MISSION_URI); -} - -export function getUnits(callback: CallableFunction, refresh: boolean = false) { - GET(callback, UNITS_URI, { time: refresh ? 0 : lastUpdateTimes[UNITS_URI] }, 'arraybuffer'); -} - -export function getWeapons(callback: CallableFunction, refresh: boolean = false) { - GET(callback, WEAPONS_URI, { time: refresh ? 0 : lastUpdateTimes[WEAPONS_URI] }, 'arraybuffer'); -} - -export function isCommandExecuted(callback: CallableFunction, commandHash: string) { - GET(callback, COMMANDS_URI, { commandHash: commandHash}); -} - -export function addDestination(ID: number, path: any, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "path": path } - var data = { "setPath": command } - POST(data, callback); -} - -export function spawnSmoke(color: string, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "color": color, "location": latlng }; - var data = { "smoke": command } - POST(data, callback); -} - -export function spawnExplosion(intensity: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "intensity": intensity, "location": latlng }; - var data = { "explosion": command } - POST(data, callback); -} - -export function spawnAircrafts(units: any, coalition: string, airbaseName: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { - var command = { "units": units, "coalition": coalition, "airbaseName": airbaseName, "country": country, "immediate": immediate, "spawnPoints": spawnPoints }; - var data = { "spawnAircrafts": command } - POST(data, callback); -} - -export function spawnHelicopters(units: any, coalition: string, airbaseName: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { - var command = { "units": units, "coalition": coalition, "airbaseName": airbaseName, "country": country, "immediate": immediate, "spawnPoints": spawnPoints }; - var data = { "spawnHelicopters": command } - POST(data, callback); -} - -export function spawnGroundUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { - var command = { "units": units, "coalition": coalition, "country": country, "immediate": immediate, "spawnPoints": spawnPoints };; - var data = { "spawnGroundUnits": command } - POST(data, callback); -} - -export function spawnNavyUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { - var command = { "units": units, "coalition": coalition, "country": country, "immediate": immediate, "spawnPoints": spawnPoints }; - var data = { "spawnNavyUnits": command } - POST(data, callback); -} - -export function attackUnit(ID: number, targetID: number, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "targetID": targetID }; - var data = { "attackUnit": command } - POST(data, callback); -} - -export function followUnit(ID: number, targetID: number, offset: { "x": number, "y": number, "z": number }, callback: CallableFunction = () => {}) { - // X: front-rear, positive front - // Y: top-bottom, positive bottom - // Z: left-right, positive right - - var command = { "ID": ID, "targetID": targetID, "offsetX": offset["x"], "offsetY": offset["y"], "offsetZ": offset["z"] }; - var data = { "followUnit": command } - POST(data, callback); -} - -export function cloneUnits(units: {ID: number, location: LatLng}[], deleteOriginal: boolean, spawnPoints: number, callback: CallableFunction = () => {}) { - var command = { "units": units, "deleteOriginal": deleteOriginal, "spawnPoints": spawnPoints }; - var data = { "cloneUnits": command } - POST(data, callback); -} - -export function deleteUnit(ID: number, explosion: boolean, immediate: boolean, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "explosion": explosion, "immediate": immediate }; - var data = { "deleteUnit": command } - POST(data, callback); -} - -export function landAt(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng }; - var data = { "landAt": command } - POST(data, callback); -} - -export function changeSpeed(ID: number, speedChange: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "change": speedChange } - var data = { "changeSpeed": command } - POST(data, callback); -} - -export function setSpeed(ID: number, speed: number, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "speed": speed } - var data = { "setSpeed": command } - POST(data, callback); -} - -export function setSpeedType(ID: number, speedType: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "speedType": speedType } - var data = { "setSpeedType": command } - POST(data, callback); -} - -export function changeAltitude(ID: number, altitudeChange: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "change": altitudeChange } - var data = { "changeAltitude": command } - POST(data, callback); -} - -export function setAltitudeType(ID: number, altitudeType: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "altitudeType": altitudeType } - var data = { "setAltitudeType": command } - POST(data, callback); -} - -export function setAltitude(ID: number, altitude: number, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "altitude": altitude } - var data = { "setAltitude": command } - POST(data, callback); -} - -export function createFormation(ID: number, isLeader: boolean, wingmenIDs: number[], callback: CallableFunction = () => {}) { - var command = { "ID": ID, "wingmenIDs": wingmenIDs, "isLeader": isLeader } - var data = { "setLeader": command } - POST(data, callback); -} - -export function setROE(ID: number, ROE: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "ROE": ROEs.indexOf(ROE) } - var data = { "setROE": command } - POST(data, callback); -} - -export function setReactionToThreat(ID: number, reactionToThreat: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "reactionToThreat": reactionsToThreat.indexOf(reactionToThreat) } - var data = { "setReactionToThreat": command } - POST(data, callback); -} - -export function setEmissionsCountermeasures(ID: number, emissionCountermeasure: string, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "emissionsCountermeasures": emissionsCountermeasures.indexOf(emissionCountermeasure) } - var data = { "setEmissionsCountermeasures": command } - POST(data, callback); -} - -export function setOnOff(ID: number, onOff: boolean, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "onOff": onOff } - var data = { "setOnOff": command } - POST(data, callback); -} - -export function setFollowRoads(ID: number, followRoads: boolean, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "followRoads": followRoads } - var data = { "setFollowRoads": command } - POST(data, callback); -} - -export function refuel(ID: number, callback: CallableFunction = () => {}) { - var command = { "ID": ID }; - var data = { "refuel": command } - POST(data, callback); -} - -export function bombPoint(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng } - var data = { "bombPoint": command } - POST(data, callback); -} - -export function carpetBomb(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng } - var data = { "carpetBomb": command } - POST(data, callback); -} - -export function bombBuilding(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng } - var data = { "bombBuilding": command } - POST(data, callback); -} - -export function fireAtArea(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng } - var data = { "fireAtArea": command } - POST(data, callback); -} - -export function simulateFireFight(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng } - var data = { "simulateFireFight": command } - POST(data, callback); -} - -export function setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => {}) { - var command = { - "ID": ID, - "isTanker": isTanker, - "isAWACS": isAWACS, - "TACAN": TACAN, - "radio": radio, - "generalSettings": generalSettings - }; - - var data = { "setAdvancedOptions": command }; - POST(data, callback); -} - -export function setCommandModeOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: {blue: number, red: number}, eras: string[], setupTime: number, callback: CallableFunction = () => {}) { - var command = { - "restrictSpawns": restrictSpawns, - "restrictToCoalition": restrictToCoalition, - "spawnPoints": spawnPoints, - "eras": eras, - "setupTime": setupTime - }; - - var data = { "setCommandModeOptions": command }; - POST(data, callback); -} - -export function startUpdate() { - window.setInterval(() => { - if (!getPaused()) { - getMission((data: MissionData) => { - checkSessionHash(data.sessionHash); - getMissionHandler()?.updateMission(data); - return data.time; - }); - } - }, 1000); - - window.setInterval(() => { - 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) - return data.time; - }); - } - }, 1000); - - window.setInterval(() => { - if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { - getUnits((buffer: ArrayBuffer) => { - var time = getUnitsManager()?.update(buffer); - return time; - }, false); - } - }, 250); - - window.setInterval(() => { - if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { - getWeapons((buffer: ArrayBuffer) => { - var time = getWeaponsManager()?.update(buffer); - return time; - }, false); - } - }, 250); - - window.setInterval(() => { - if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { - getUnits((buffer: ArrayBuffer) => { - var time = getUnitsManager()?.update(buffer); - return time; - }, true); - getConnectionStatusPanel()?.update(getConnected()); - } - }, 5000); - - window.setInterval(() => { - if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) { - getWeapons((buffer: ArrayBuffer) => { - var time = getWeaponsManager()?.update(buffer); - return time; - }, true); - } - }, 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; - }, true); - - getUnits((buffer: ArrayBuffer) => { - var time = getUnitsManager()?.update(buffer); - return time; - }, true); -} - -export function checkSessionHash(newSessionHash: string) { - if (sessionHash != null) { - if (newSessionHash !== sessionHash) - location.reload(); - } - else - sessionHash = newSessionHash; -} - -export function setConnected(newConnected: boolean) { - if (connected != newConnected) - newConnected ? getInfoPopup().setText("Connected to DCS Olympus server") : getInfoPopup().setText("Disconnected from DCS Olympus server"); - connected = newConnected; - - if (connected) { - document.querySelector("#splash-screen")?.classList.add("hide"); - document.querySelector("#gray-out")?.classList.add("hide"); - } -} - -export function getConnected() { - return connected; -} - -export function setPaused(newPaused: boolean) { - paused = newPaused; - paused ? getInfoPopup().setText("View paused") : getInfoPopup().setText("View unpaused"); -} - -export function getPaused() { - return paused; -} \ No newline at end of file diff --git a/client/src/server/servermanager.ts b/client/src/server/servermanager.ts index d2747e69..8df86f62 100644 --- a/client/src/server/servermanager.ts +++ b/client/src/server/servermanager.ts @@ -322,6 +322,12 @@ export class ServerManager { this.POST(data, callback); } + simulateFireFight(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "location": latlng } + var data = { "simulateFireFight": command } + this.POST(data, callback); + } + setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => {}) { var command = { "ID": ID, diff --git a/client/src/unit/unit.ts b/client/src/unit/unit.ts index e9cb4084..bd8cb3d3 100644 --- a/client/src/unit/unit.ts +++ b/client/src/unit/unit.ts @@ -723,7 +723,7 @@ export class Unit extends CustomMarker { } simulateFireFight(latlng: LatLng) { - simulateFireFight(this.ID, latlng); + getApp().getServerManager().simulateFireFight(this.ID, latlng); } /***********************************************/ diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index da1d2d5e..7c46020d 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -37,7 +37,6 @@ - diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index cfb10c59..56fade36 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -54,9 +54,6 @@ Header Files - - Header Files - diff --git a/src/core/include/aircraft.h b/src/core/include/aircraft.h index be27e35b..a3fa2b2a 100644 --- a/src/core/include/aircraft.h +++ b/src/core/include/aircraft.h @@ -6,6 +6,11 @@ class Aircraft : public AirUnit public: Aircraft(json::value json, unsigned int ID); + static void loadDatabase(string path); + virtual void changeSpeed(string change); virtual void changeAltitude(string change); + +protected: + static json::value database; }; \ No newline at end of file diff --git a/src/core/include/datatypes.h b/src/core/include/datatypes.h index f8be70fa..207b72ee 100644 --- a/src/core/include/datatypes.h +++ b/src/core/include/datatypes.h @@ -127,8 +127,3 @@ struct CloneOptions { unsigned int ID; Coords location; }; - -struct GunDataItem { - double barrelHeight; - double muzzleVelocity; -}; \ No newline at end of file diff --git a/src/core/include/groundunit.h b/src/core/include/groundunit.h index 46e1b78d..8ef0fb35 100644 --- a/src/core/include/groundunit.h +++ b/src/core/include/groundunit.h @@ -8,6 +8,8 @@ class GroundUnit : public Unit public: GroundUnit(json::value json, unsigned int ID); + static void loadDatabase(string path); + virtual void setState(unsigned char newState); virtual void setDefaults(bool force = false); @@ -17,4 +19,5 @@ public: protected: virtual void AIloop(); + static json::value database; }; \ No newline at end of file diff --git a/src/core/include/gundata.h b/src/core/include/gundata.h deleted file mode 100644 index b463f423..00000000 --- a/src/core/include/gundata.h +++ /dev/null @@ -1,116 +0,0 @@ -#pragma once - -#include "framework.h" -#include "datatypes.h" - -map gunData = { -{"2B11 mortar", {0.9, 860}}, -{"SAU Gvozdika", {0.9, 860}}, -{"SAU Msta", {0.9, 860}}, -{"SAU Akatsia", {0.9, 860}}, -{"SAU 2-C9", {0.9, 860}}, -{"M-109", {0.9, 860}}, -{"SpGH_Dana", {0.9, 860}}, -{"AAV7", {0.9, 860}}, -{"BMD-1", {0.9, 860}}, -{"BMP-1", {0.9, 860}}, -{"BMP-2", {0.9, 860}}, -{"BMP-3", {0.9, 860}}, -{"BRDM-2", {0.9, 860}}, -{"BTR_D", {0.9, 860}}, -{"Cobra", {0.9, 860}}, -{"LAV-25", {0.9, 860}}, -{"M1043 HMMWV Armament", {0.9, 860}}, -{"M1045 HMMWV TOW", {0.9, 860}}, -{"M1126 Stryker ICV", {0.9, 860}}, -{"M-113", {0.9, 860}}, -{"M1134 Stryker ATGM", {0.9, 860}}, -{"M-2 Bradley", {0.9, 860}}, -{"MCV-80", {0.9, 860}}, -{"MTLB", {0.9, 860}}, -{"Marder", {0.9, 860}}, -{"TPZ", {0.9, 860}}, -{"Grad_FDDM", {0.9, 860}}, -{"Paratrooper RPG-16", {0.9, 860}}, -{"Paratrooper AKS-74", {0.9, 860}}, -{"Infantry AK Ins", {0.9, 860}}, -{"Soldier AK", {0.4, 860}}, -{"Infantry AK", {0.9, 860}}, -{"Soldier M249", {0.9, 860}}, -{"Soldier M4", {0.9, 860}}, -{"Soldier M4 GRG", {0.9, 860}}, -{"Soldier RPG", {0.9, 860}}, -{"MLRS FDDM", {0.9, 860}}, -{"Infantry AK ver2", {0.9, 860}}, -{"Infantry AK ver3", {0.9, 860}}, -{"Grad-URAL", {0.9, 860}}, -{"Uragan_BM-27", {0.9, 860}}, -{"Smerch", {0.9, 860}}, -{"Smerch_HE", {0.9, 860}}, -{"MLRS", {0.9, 860}}, -{"Challenger2", {0.9, 860}}, -{"Leclerc", {0.9, 860}}, -{"M-60", {0.9, 860}}, -{"M1128 Stryker MGS", {0.9, 860}}, -{"M-1 Abrams", {0.9, 860}}, -{"T-55", {0.9, 860}}, -{"T-72B", {0.9, 860}}, -{"T-80UD", {0.9, 860}}, -{"T-90", {0.9, 860}}, -{"Leopard1A3", {0.9, 860}}, -{"Merkava_Mk4", {0.9, 860}}, -{"JTAC", {0.9, 860}}, -{"Infantry Animated", {0.9, 860}}, -{"HL_DSHK", {0.9, 860}}, -{"HL_KORD", {0.9, 860}}, -{"tt_DSHK", {0.9, 860}}, -{"tt_KORD", {0.9, 860}}, -{"HL_B8M1", {0.9, 860}}, -{"tt_B8M1", {0.9, 860}}, -{"M4_Sherman", {0.9, 860}}, -{"M2A1_halftrack", {0.9, 860}}, -{"BTR-80", {0.9, 860}}, -{"T-72B3", {0.9, 860}}, -{"PT_76", {0.9, 860}}, -{"BTR-82A", {0.9, 860}}, -{"Chieftain_mk3", {0.9, 860}}, -{"Pz_IV_H", {0.9, 860}}, -{"Leopard-2A5", {0.9, 860}}, -{"Leopard-2", {0.9, 860}}, -{"leopard-2A4", {0.9, 860}}, -{"leopard-2A4_trs", {0.9, 860}}, -{"Sd_Kfz_251", {0.9, 860}}, -{"T155_Firtina", {0.9, 860}}, -{"VAB_Mephisto", {0.9, 860}}, -{"ZTZ96B", {0.9, 860}}, -{"ZBD04A", {0.9, 860}}, -{"PLZ05", {0.9, 860}}, -{"TYPE-59", {0.9, 860}}, -{"Tiger_I", {0.9, 860}}, -{"Tiger_II_H", {0.9, 860}}, -{"Pz_V_Panther_G", {0.9, 860}}, -{"Jagdpanther_G1", {0.9, 860}}, -{"JagdPz_IV", {0.9, 860}}, -{"Stug_IV", {0.9, 860}}, -{"SturmPzIV", {0.9, 860}}, -{"Wespe124", {0.9, 860}}, -{"Sd_Kfz_234_2_Puma", {0.9, 860}}, -{"soldier_mauser98", {0.9, 860}}, -{"Stug_III", {0.9, 860}}, -{"Elefant_SdKfz_184", {0.9, 860}}, -{"Pak40", {0.9, 860}}, -{"LeFH_18-40-105", {0.9, 860}}, -{"Cromwell_IV", {0.9, 860}}, -{"M4A4_Sherman_FF", {0.9, 860}}, -{"soldier_wwii_br_01", {0.9, 860}}, -{"Centaur_IV", {0.9, 860}}, -{"Churchill_VII", {0.9, 860}}, -{"Daimler_AC", {0.9, 860}}, -{"Tetrarch", {0.9, 860}}, -{"M12_GMC", {0.9, 860}}, -{"soldier_wwii_us", {0.9, 860}}, -{"M10_GMC", {0.9, 860}}, -{"M8_Greyhound", {0.9, 860}}, -{"M2A1-105", {0.9, 860}}, -{"M4_Tractor", {0.9, 860}}, -}; \ No newline at end of file diff --git a/src/core/include/helicopter.h b/src/core/include/helicopter.h index 3c72693b..5c0246ae 100644 --- a/src/core/include/helicopter.h +++ b/src/core/include/helicopter.h @@ -6,6 +6,11 @@ class Helicopter : public AirUnit public: Helicopter(json::value json, unsigned int ID); + static void loadDatabase(string path); + virtual void changeSpeed(string change); virtual void changeAltitude(string change); + +protected: + static json::value database; }; \ No newline at end of file diff --git a/src/core/include/navyunit.h b/src/core/include/navyunit.h index 24ed244d..23f86fe7 100644 --- a/src/core/include/navyunit.h +++ b/src/core/include/navyunit.h @@ -8,6 +8,8 @@ class NavyUnit : public Unit public: NavyUnit(json::value json, unsigned int ID); + static void loadDatabase(string path); + virtual void setState(unsigned char newState); virtual void setDefaults(bool force = false); @@ -16,5 +18,5 @@ public: protected: virtual void AIloop(); - + static json::value database; }; \ No newline at end of file diff --git a/src/core/src/aircraft.cpp b/src/core/src/aircraft.cpp index e8a932dd..be3021f9 100644 --- a/src/core/src/aircraft.cpp +++ b/src/core/src/aircraft.cpp @@ -11,6 +11,26 @@ using namespace GeographicLib; extern Scheduler* scheduler; extern UnitsManager* unitsManager; +json::value Aircraft::database = json::value(); + +void Aircraft::loadDatabase(string path) { + char* buf = nullptr; + size_t sz = 0; + if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr) + { + std::ifstream ifstream(string(buf) + path); + std::stringstream ss; + ss << ifstream.rdbuf(); + std::error_code errorCode; + database = json::value::parse(ss.str(), errorCode); + if (database.is_object()) + log("Aircrafts database loaded correctly"); + else + log("Error reading Aircrafts database file"); + + free(buf); + } +} /* Aircraft */ Aircraft::Aircraft(json::value json, unsigned int ID) : AirUnit(json, ID) diff --git a/src/core/src/core.cpp b/src/core/src/core.cpp index 3fc42753..e41128e9 100644 --- a/src/core/src/core.cpp +++ b/src/core/src/core.cpp @@ -7,6 +7,10 @@ #include "scheduler.h" #include "scriptLoader.h" #include "luatools.h" +#include "aircraft.h" +#include "helicopter.h" +#include "groundunit.h" +#include "navyunit.h" #include using namespace std::chrono; @@ -59,6 +63,11 @@ extern "C" DllExport int coreInit(lua_State* L) server = new Server(L); scheduler = new Scheduler(L); + Aircraft::loadDatabase(AIRCRAFT_DATABASE_PATH); + Helicopter::loadDatabase(HELICOPTER_DATABASE_PATH); + GroundUnit::loadDatabase(GROUNDUNIT_DATABASE_PATH); + NavyUnit::loadDatabase(NAVYUNIT_DATABASE_PATH); + registerLuaFunctions(L); server->start(L); diff --git a/src/core/src/groundunit.cpp b/src/core/src/groundunit.cpp index 69e76b83..61aa867f 100644 --- a/src/core/src/groundunit.cpp +++ b/src/core/src/groundunit.cpp @@ -5,13 +5,32 @@ #include "scheduler.h" #include "defines.h" #include "unitsmanager.h" -#include "gundata.h" #include using namespace GeographicLib; extern Scheduler* scheduler; extern UnitsManager* unitsManager; +json::value GroundUnit::database = json::value(); + +void GroundUnit::loadDatabase(string path) { + char* buf = nullptr; + size_t sz = 0; + if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr) + { + std::ifstream ifstream(string(buf) + path); + std::stringstream ss; + ss << ifstream.rdbuf(); + std::error_code errorCode; + database = json::value::parse(ss.str(), errorCode); + if (database.is_object()) + log("Ground Units database loaded correctly"); + else + log("Error reading Ground Units database file"); + + free(buf); + } +} /* Ground unit */ GroundUnit::GroundUnit(json::value json, unsigned int ID) : Unit(json, ID) @@ -151,16 +170,20 @@ void GroundUnit::AIloop() /* Default gun values */ double barrelHeight = 1.0; /* m */ double muzzleVelocity = 860; /* m/s */ - if (gunData.find(name) != gunData.end()) { - barrelHeight = gunData[name].barrelHeight; - muzzleVelocity = gunData[name].muzzleVelocity; + if (database.has_object_field(to_wstring(name))) { + json::value databaseEntry = database[to_wstring(name)]; + if (databaseEntry.has_number_field(L"barrelHeight") && databaseEntry.has_number_field(L"muzzleVelocity")) { + barrelHeight = databaseEntry[L"barrelHeight"].as_number().to_double(); + muzzleVelocity = databaseEntry[L"muzzleVelocity"].as_number().to_double(); + log(to_string(barrelHeight) + " " + to_string(muzzleVelocity)); + } } double barrelElevation = r * (9.81 * dist / (2 * muzzleVelocity * muzzleVelocity) - barrelHeight / dist); /* m */ double lat = 0; double lng = 0; - double randomBearing = bearing1 + (((double)(rand()) / (double)(RAND_MAX) - 0.5) * 2) * 45; + double randomBearing = bearing1 + (((double)(rand()) / (double)(RAND_MAX) - 0.5) * 2) * 15; Geodesic::WGS84().Direct(position.lat, position.lng, randomBearing, r, lat, lng); std::ostringstream taskSS; diff --git a/src/core/src/helicopter.cpp b/src/core/src/helicopter.cpp index 6d24022e..bfd6caab 100644 --- a/src/core/src/helicopter.cpp +++ b/src/core/src/helicopter.cpp @@ -11,6 +11,26 @@ using namespace GeographicLib; extern Scheduler* scheduler; extern UnitsManager* unitsManager; +json::value Helicopter::database = json::value(); + +void Helicopter::loadDatabase(string path) { + char* buf = nullptr; + size_t sz = 0; + if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr) + { + std::ifstream ifstream(string(buf) + path); + std::stringstream ss; + ss << ifstream.rdbuf(); + std::error_code errorCode; + database = json::value::parse(ss.str(), errorCode); + if (database.is_object()) + log("Helicopters database loaded correctly"); + else + log("Error reading Helicopters database file"); + + free(buf); + } +} /* Helicopter */ Helicopter::Helicopter(json::value json, unsigned int ID) : AirUnit(json, ID) diff --git a/src/core/src/navyunit.cpp b/src/core/src/navyunit.cpp index d2c68a3d..0c66380d 100644 --- a/src/core/src/navyunit.cpp +++ b/src/core/src/navyunit.cpp @@ -11,6 +11,26 @@ using namespace GeographicLib; extern Scheduler* scheduler; extern UnitsManager* unitsManager; +json::value NavyUnit::database = json::value(); + +void NavyUnit::loadDatabase(string path) { + char* buf = nullptr; + size_t sz = 0; + if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr) + { + std::ifstream ifstream(string(buf) + path); + std::stringstream ss; + ss << ifstream.rdbuf(); + std::error_code errorCode; + database = json::value::parse(ss.str(), errorCode); + if (database.is_object()) + log("Navy Units database loaded correctly"); + else + log("Error reading Navy Units database file"); + + free(buf); + } +} /* Navy Unit */ NavyUnit::NavyUnit(json::value json, unsigned int ID) : Unit(json, ID) diff --git a/src/core/src/server.cpp b/src/core/src/server.cpp index 2817846a..e3be2f2f 100644 --- a/src/core/src/server.cpp +++ b/src/core/src/server.cpp @@ -291,7 +291,7 @@ void Server::task() size_t sz = 0; if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr) { - std::ifstream ifstream(string(buf) + "\\olympus.json"); + std::ifstream ifstream(string(buf) + OLYMPUS_JSON_PATH); std::stringstream ss; ss << ifstream.rdbuf(); std::error_code errorCode; diff --git a/src/shared/include/defines.h b/src/shared/include/defines.h index e8f8fc14..fc15746e 100644 --- a/src/shared/include/defines.h +++ b/src/shared/include/defines.h @@ -12,4 +12,10 @@ #define MISSION_URI "mission" #define COMMANDS_URI "commands" -#define FRAMERATE_TIME_INTERVAL 0.05 \ No newline at end of file +#define FRAMERATE_TIME_INTERVAL 0.05 + +#define OLYMPUS_JSON_PATH "\\olympus.json" +#define AIRCRAFT_DATABASE_PATH "\\client\\public\\databases\\units\\aircraftdatabase.json" +#define HELICOPTER_DATABASE_PATH "\\client\\public\\databases\\units\\helicopterdatabase.json" +#define GROUNDUNIT_DATABASE_PATH "\\client\\public\\databases\\units\\groundunitdatabase.json" +#define NAVYUNIT_DATABASE_PATH "\\client\\public\\databases\\units\\navyunitdatabase.json" From f3155e618b08da02b1121caba70f74e1c4a029e3 Mon Sep 17 00:00:00 2001 From: Pax1601 Date: Fri, 22 Sep 2023 16:05:03 +0200 Subject: [PATCH 3/3] Added target altitude effect to simulated fire fight --- client/demo.js | 18 ++++++++++++++++- client/public/stylesheets/leaflet/leaflet.css | 7 +------ client/src/map/map.ts | 4 ++-- client/src/other/utils.ts | 15 ++++++++++++++ client/src/server/servermanager.ts | 4 ++-- client/src/unit/unit.ts | 4 ++-- client/src/unit/unitsmanager.ts | 20 +++++++++++++------ src/core/src/groundunit.cpp | 2 +- src/core/src/scheduler.cpp | 3 ++- 9 files changed, 56 insertions(+), 21 deletions(-) diff --git a/client/demo.js b/client/demo.js index 99c65f9a..3a5b86a5 100644 --- a/client/demo.js +++ b/client/demo.js @@ -96,7 +96,23 @@ const DEMO_UNIT_DATA = { ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ], contacts: [{ID: 1, detectionMethod: 16}], activePath: [ ] - }, + }, ["7"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "T-55", unitName: "Cool guy 2-1", groupName: "Cool group 10", state: 1, task: "Being cool", + hasTask: false, position: { lat: 37.2, lng: -116.2, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50, + desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0, + formationOffset: { x: 0, y: 0, z: 0 }, + targetID: 0, + targetPosition: { lat: 0, lng: 0, alt: 0 }, + ROE: 1, + reactionToThreat: 1, + emissionsCountermeasures: 1, + TACAN: { isOn: false, XY: 'Y', callsign: 'TKR', channel: 40 }, + radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 }, + generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false }, + ammo: [{ quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } ], + contacts: [{ID: 1001, detectionMethod: 16}], + activePath: [ ], + isLeader: true + }, } const DEMO_WEAPONS_DATA = { diff --git a/client/public/stylesheets/leaflet/leaflet.css b/client/public/stylesheets/leaflet/leaflet.css index 9ade8dc4..1981009f 100644 --- a/client/public/stylesheets/leaflet/leaflet.css +++ b/client/public/stylesheets/leaflet/leaflet.css @@ -60,11 +60,6 @@ padding: 0; } -.leaflet-container img.leaflet-tile { - /* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */ - mix-blend-mode: plus-lighter; -} - .leaflet-container.leaflet-touch-zoom { -ms-touch-action: pan-x pan-y; touch-action: pan-x pan-y; @@ -651,7 +646,7 @@ svg.leaflet-image-layer.leaflet-interactive path { } /* Printing */ - + @media print { /* Prevent printers from removing background-images of controls. */ .leaflet-control { diff --git a/client/src/map/map.ts b/client/src/map/map.ts index 89a967e5..e4a4c05c 100644 --- a/client/src/map/map.ts +++ b/client/src/map/map.ts @@ -608,8 +608,8 @@ export class Map extends L.Map { getApp().getUnitsManager().selectedUnitsFireAtArea(this.getMouseCoordinates()); } else if (option === "simulate-fire-fight") { - getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); - getUnitsManager().selectedUnitsSimulateFireFight(this.getMouseCoordinates()); + getApp().getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); + getApp().getUnitsManager().selectedUnitsSimulateFireFight(this.getMouseCoordinates()); } }); } diff --git a/client/src/other/utils.ts b/client/src/other/utils.ts index 78d025e2..29956750 100644 --- a/client/src/other/utils.ts +++ b/client/src/other/utils.ts @@ -397,4 +397,19 @@ export function getCheckboxOptions(dropdown: Dropdown) { values[key] = value; } return values; +} + +export function getGroundElevation(latlng: LatLng, callback: CallableFunction) { + /* Get the ground elevation from the server endpoint */ + const xhr = new XMLHttpRequest(); + xhr.open('GET', `api/elevation/${latlng.lat}/${latlng.lng}`, true); + xhr.timeout = 500; // ms + xhr.responseType = 'json'; + xhr.onload = () => { + var status = xhr?.status; + if (status === 200) { + callback(xhr.response) + } + }; + xhr.send(); } \ No newline at end of file diff --git a/client/src/server/servermanager.ts b/client/src/server/servermanager.ts index 8df86f62..2af8f08b 100644 --- a/client/src/server/servermanager.ts +++ b/client/src/server/servermanager.ts @@ -322,8 +322,8 @@ export class ServerManager { this.POST(data, callback); } - simulateFireFight(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { - var command = { "ID": ID, "location": latlng } + simulateFireFight(ID: number, latlng: LatLng, altitude: number, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "location": latlng, "altitude": altitude } var data = { "simulateFireFight": command } this.POST(data, callback); } diff --git a/client/src/unit/unit.ts b/client/src/unit/unit.ts index ee73bdc0..272067d1 100644 --- a/client/src/unit/unit.ts +++ b/client/src/unit/unit.ts @@ -722,8 +722,8 @@ export class Unit extends CustomMarker { getApp().getServerManager().fireAtArea(this.ID, latlng); } - simulateFireFight(latlng: LatLng) { - getApp().getServerManager().simulateFireFight(this.ID, latlng); + simulateFireFight(latlng: LatLng, groundElevation: number | null) { + getApp().getServerManager().simulateFireFight(this.ID, latlng, groundElevation?? 0); } /***********************************************/ diff --git a/client/src/unit/unitsmanager.ts b/client/src/unit/unitsmanager.ts index 71720d6b..a5b05bb8 100644 --- a/client/src/unit/unitsmanager.ts +++ b/client/src/unit/unitsmanager.ts @@ -1,7 +1,7 @@ import { LatLng, LatLngBounds } from "leaflet"; import { getApp } from ".."; import { Unit } from "./unit"; -import { bearingAndDistanceToLatLng, deg2rad, getUnitDatabaseByCategory, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polyContains, polygonArea, randomPointInPoly, randomUnitBlueprint } from "../other/utils"; +import { bearingAndDistanceToLatLng, deg2rad, getGroundElevation, getUnitDatabaseByCategory, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polyContains, polygonArea, randomPointInPoly, randomUnitBlueprint } from "../other/utils"; import { CoalitionArea } from "../map/coalitionarea/coalitionarea"; import { groundUnitDatabase } from "./databases/groundunitdatabase"; import { DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT } from "../constants/constants"; @@ -590,7 +590,7 @@ export class UnitsManager { for (let idx in selectedUnits) { selectedUnits[idx].carpetBomb(latlng); } - this.#showActionMessage(selectedUnits, `unit bombing point`); + this.#showActionMessage(selectedUnits, `unit carpet bombing point`); } /** Instruct the selected units to fire at specific coordinates @@ -602,7 +602,7 @@ export class UnitsManager { for (let idx in selectedUnits) { selectedUnits[idx].fireAtArea(latlng); } - this.#showActionMessage(selectedUnits, `unit bombing point`); + this.#showActionMessage(selectedUnits, `unit firing at area`); } /** Instruct the selected units to simulate a fire fight at specific coordinates @@ -611,9 +611,17 @@ export class UnitsManager { */ selectedUnitsSimulateFireFight(latlng: LatLng) { var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }); - for (let idx in selectedUnits) { - selectedUnits[idx].simulateFireFight(latlng); - } + getGroundElevation(latlng, (response: string) => { + var groundElevation: number | null = null; + try { + groundElevation = parseFloat(response); + } catch { + console.log("Simulate fire fight: could not retrieve ground elevation") + } + for (let idx in selectedUnits) { + selectedUnits[idx].simulateFireFight(latlng, groundElevation); + } + }); this.#showActionMessage(selectedUnits, `unit simulating fire fight`); } diff --git a/src/core/src/groundunit.cpp b/src/core/src/groundunit.cpp index 61aa867f..1d54b8b4 100644 --- a/src/core/src/groundunit.cpp +++ b/src/core/src/groundunit.cpp @@ -179,7 +179,7 @@ void GroundUnit::AIloop() } } - double barrelElevation = r * (9.81 * dist / (2 * muzzleVelocity * muzzleVelocity) - barrelHeight / dist); /* m */ + double barrelElevation = r * (9.81 * dist / (2 * muzzleVelocity * muzzleVelocity) + (targetPosition.alt - (position.alt + barrelHeight)) / dist); /* m */ double lat = 0; double lng = 0; diff --git a/src/core/src/scheduler.cpp b/src/core/src/scheduler.cpp index 182318bd..095764d2 100644 --- a/src/core/src/scheduler.cpp +++ b/src/core/src/scheduler.cpp @@ -568,7 +568,8 @@ void Scheduler::handleRequest(string key, json::value value, string username, js unitsManager->acquireControl(ID); double lat = value[L"location"][L"lat"].as_double(); double lng = value[L"location"][L"lng"].as_double(); - Coords loc; loc.lat = lat; loc.lng = lng; + double alt = value[L"altitude"].as_double(); + Coords loc; loc.lat = lat; loc.lng = lng; loc.alt = alt; Unit* unit = unitsManager->getGroupLeader(ID); unit->setState(State::SIMULATE_FIRE_FIGHT); unit->setTargetPosition(loc);