mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Fixed update error and added update trigger
This commit is contained in:
4
client/src/@types/unit.d.ts
vendored
4
client/src/@types/unit.d.ts
vendored
@@ -52,8 +52,8 @@ interface UnitData {
|
||||
human: boolean,
|
||||
controlled: boolean,
|
||||
hasTask: boolean,
|
||||
desiredAltitudeType: boolean,
|
||||
desiredSpeedType: boolean,
|
||||
desiredAltitudeType: string,
|
||||
desiredSpeedType: string,
|
||||
isTanker: boolean,
|
||||
isAWACS: boolean,
|
||||
onOff: boolean,
|
||||
|
||||
@@ -671,7 +671,7 @@ export class Map extends L.Map {
|
||||
|
||||
/* Show the active cursor depending on the active state */
|
||||
if (this.#state === IDLE || this.#state === COALITIONAREA_INTERACT) this.#showDefaultCursor();
|
||||
else if (this.#state === MOVE_UNIT) this.#showDestinationCursors(!e.originalEvent.shiftKey);
|
||||
else if (this.#state === MOVE_UNIT) this.#showDestinationCursors(e && e.originaleEvent && !e.originalEvent.shiftKey);
|
||||
else if ([BOMBING, CARPET_BOMBING, FIRE_AT_AREA].includes(this.#state)) this.#showTargetCursor();
|
||||
else if (this.#state === COALITIONAREA_DRAW_POLYGON) this.#showDrawingCursor();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { LatLng } from 'leaflet';
|
||||
import { getConnectionStatusPanel, getInfoPopup, getMissionData, getUnitDataTable, getUnitsManager, setConnectionStatus } from '..';
|
||||
import { SpawnOptions } from '../controls/mapcontextmenu';
|
||||
import { GeneralSettings, Radio, TACAN } from '../@types/unit';
|
||||
import { ROEs, emissionsCountermeasures, reactionsToThreat } from '../constants/constants';
|
||||
|
||||
var connected: boolean = false;
|
||||
var paused: boolean = false;
|
||||
@@ -38,19 +39,21 @@ export function GET(callback: CallableFunction, uri: string, options?: { time?:
|
||||
if (options?.time != undefined)
|
||||
optionsString = `time=${options.time}`;
|
||||
|
||||
|
||||
xmlHttp.open("GET", `${demoEnabled ? DEMO_ADDRESS : REST_ADDRESS}/${uri}${optionsString ? `?${optionsString}` : ''}`, true);
|
||||
if (credentials)
|
||||
xmlHttp.setRequestHeader("Authorization", "Basic " + credentials);
|
||||
|
||||
if (uri === UNITS_URI)
|
||||
xmlHttp.responseType = "arraybuffer";
|
||||
|
||||
xmlHttp.onload = function (e) {
|
||||
if (xmlHttp.status == 200) {
|
||||
var data = JSON.parse(xmlHttp.responseText);
|
||||
if (uri !== UNITS_URI || (options?.time == 0) || parseInt(data.time) > lastUpdateTime) {
|
||||
setConnected(true);
|
||||
if (xmlHttp.responseType == 'arraybuffer')
|
||||
callback(xmlHttp.response);
|
||||
else {
|
||||
var data = JSON.parse(xmlHttp.responseText);
|
||||
callback(data);
|
||||
lastUpdateTime = parseInt(data.time);
|
||||
if (isNaN(lastUpdateTime))
|
||||
lastUpdateTime = 0;
|
||||
setConnected(true);
|
||||
}
|
||||
} else if (xmlHttp.status == 401) {
|
||||
console.error("Incorrect username/password");
|
||||
@@ -96,6 +99,10 @@ export function setAddress(address: string, port: number) {
|
||||
console.log(`Setting REST address to ${REST_ADDRESS}`)
|
||||
}
|
||||
|
||||
export function setLastUpdateTime(newLastUpdateTime: number) {
|
||||
lastUpdateTime = newLastUpdateTime;
|
||||
}
|
||||
|
||||
export function getAirbases(callback: CallableFunction) {
|
||||
GET(callback, AIRBASES_URI);
|
||||
}
|
||||
@@ -223,19 +230,19 @@ export function createFormation(ID: number, isLeader: boolean, wingmenIDs: numbe
|
||||
}
|
||||
|
||||
export function setROE(ID: number, ROE: string) {
|
||||
var command = { "ID": ID, "ROE": ROE }
|
||||
var command = { "ID": ID, "ROE": ROEs.indexOf(ROE) }
|
||||
var data = { "setROE": command }
|
||||
POST(data, () => { });
|
||||
}
|
||||
|
||||
export function setReactionToThreat(ID: number, reactionToThreat: string) {
|
||||
var command = { "ID": ID, "reactionToThreat": reactionToThreat }
|
||||
var command = { "ID": ID, "reactionToThreat": reactionsToThreat.indexOf(reactionToThreat) }
|
||||
var data = { "setReactionToThreat": command }
|
||||
POST(data, () => { });
|
||||
}
|
||||
|
||||
export function setEmissionsCountermeasures(ID: number, emissionCountermeasure: string) {
|
||||
var command = { "ID": ID, "emissionsCountermeasures": emissionCountermeasure }
|
||||
var command = { "ID": ID, "emissionsCountermeasures": emissionsCountermeasures.indexOf(emissionCountermeasure) }
|
||||
var data = { "setEmissionsCountermeasures": command }
|
||||
POST(data, () => { });
|
||||
}
|
||||
@@ -300,8 +307,11 @@ export function startUpdate() {
|
||||
/* On the first connection, force request of full data */
|
||||
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
|
||||
getBullseye((data: BullseyesData) => getMissionData()?.update(data));
|
||||
getMission((data: any) => { getMissionData()?.update(data) });
|
||||
getUnits((data: UnitsData) => getUnitsManager()?.update(data.units), true /* Does a full refresh */);
|
||||
getMission((data: any) => {
|
||||
getMissionData()?.update(data);
|
||||
checkSessionHash(data.sessionHash);
|
||||
});
|
||||
getUnits((buffer: ArrayBuffer) => getUnitsManager()?.update(buffer), true /* Does a full refresh */);
|
||||
|
||||
requestUpdate();
|
||||
requestRefresh();
|
||||
@@ -309,10 +319,9 @@ export function startUpdate() {
|
||||
|
||||
export function requestUpdate() {
|
||||
/* Main update rate = 250ms is minimum time, equal to server update time. */
|
||||
getUnits((data: UnitsData) => {
|
||||
getUnits((buffer: ArrayBuffer) => {
|
||||
if (!getPaused()) {
|
||||
getUnitsManager()?.update(data.units);
|
||||
checkSessionHash(data.sessionHash);
|
||||
getUnitsManager()?.update(buffer);
|
||||
}
|
||||
}, false);
|
||||
window.setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
|
||||
|
||||
@@ -17,85 +17,81 @@ export class DataExtractor {
|
||||
extractData(offset: number) {
|
||||
this.#offset = offset;
|
||||
|
||||
const ID = this.#extractUInt32();
|
||||
const bitmask = this.#extractUInt32();
|
||||
const ID = this.extractUInt32();
|
||||
const bitmask = this.extractUInt32();
|
||||
|
||||
const unitData: UnitData = {
|
||||
ID: ID,
|
||||
alive: this.#extractFromBitmask(bitmask, 0),
|
||||
human: this.#extractFromBitmask(bitmask, 1),
|
||||
controlled: this.#extractFromBitmask(bitmask, 2),
|
||||
hasTask: this.#extractFromBitmask(bitmask, 3),
|
||||
desiredAltitudeType: this.#extractFromBitmask(bitmask, 16),
|
||||
desiredSpeedType: this.#extractFromBitmask(bitmask, 17),
|
||||
isTanker: this.#extractFromBitmask(bitmask, 18),
|
||||
isAWACS: this.#extractFromBitmask(bitmask, 19),
|
||||
onOff: this.#extractFromBitmask(bitmask, 20),
|
||||
followRoads: this.#extractFromBitmask(bitmask, 21),
|
||||
EPLRS: this.#extractFromBitmask(bitmask, 22),
|
||||
alive: this.extractFromBitmask(bitmask, 0),
|
||||
human: this.extractFromBitmask(bitmask, 1),
|
||||
controlled: this.extractFromBitmask(bitmask, 2),
|
||||
hasTask: this.extractFromBitmask(bitmask, 3),
|
||||
desiredAltitudeType: this.extractFromBitmask(bitmask, 16)? "AGL": "ASL",
|
||||
desiredSpeedType: this.extractFromBitmask(bitmask, 17)? "GS": "CAS",
|
||||
isTanker: this.extractFromBitmask(bitmask, 18),
|
||||
isAWACS: this.extractFromBitmask(bitmask, 19),
|
||||
onOff: this.extractFromBitmask(bitmask, 20),
|
||||
followRoads: this.extractFromBitmask(bitmask, 21),
|
||||
EPLRS: this.extractFromBitmask(bitmask, 22),
|
||||
generalSettings: {
|
||||
prohibitAA: this.#extractFromBitmask(bitmask, 23),
|
||||
prohibitAfterburner: this.#extractFromBitmask(bitmask, 24),
|
||||
prohibitAG: this.#extractFromBitmask(bitmask, 25),
|
||||
prohibitAirWpn: this.#extractFromBitmask(bitmask, 26),
|
||||
prohibitJettison: this.#extractFromBitmask(bitmask, 27),
|
||||
prohibitAA: this.extractFromBitmask(bitmask, 23),
|
||||
prohibitAfterburner: this.extractFromBitmask(bitmask, 24),
|
||||
prohibitAG: this.extractFromBitmask(bitmask, 25),
|
||||
prohibitAirWpn: this.extractFromBitmask(bitmask, 26),
|
||||
prohibitJettison: this.extractFromBitmask(bitmask, 27),
|
||||
},
|
||||
position: new LatLng(
|
||||
this.#extractFloat64(),
|
||||
this.#extractFloat64(),
|
||||
this.#extractFloat64()
|
||||
this.extractFloat64(),
|
||||
this.extractFloat64(),
|
||||
this.extractFloat64()
|
||||
),
|
||||
speed: this.#extractFloat64(),
|
||||
heading: this.#extractFloat64(),
|
||||
fuel: this.#extractUInt16(),
|
||||
desiredSpeed: this.#extractFloat64(),
|
||||
desiredAltitude: this.#extractFloat64(),
|
||||
targetID: this.#extractUInt32(),
|
||||
leaderID: 0,
|
||||
speed: this.extractFloat64(),
|
||||
heading: this.extractFloat64(),
|
||||
fuel: this.extractUInt16(),
|
||||
desiredSpeed: this.extractFloat64(),
|
||||
desiredAltitude: this.extractFloat64(),
|
||||
leaderID: this.extractUInt32(),
|
||||
targetID: this.extractUInt32(),
|
||||
targetPosition: new LatLng(
|
||||
this.#extractFloat64(),
|
||||
this.#extractFloat64(),
|
||||
this.#extractFloat64()
|
||||
this.extractFloat64(),
|
||||
this.extractFloat64(),
|
||||
this.extractFloat64()
|
||||
),
|
||||
state: this.#getState(this.#extractUint8()),
|
||||
ROE: this.#getROE(this.#extractUint8()),
|
||||
reactionToThreat: this.#getReactionToThreat(this.#extractUint8()),
|
||||
emissionsCountermeasures: this.#getEmissionCountermeasure(this.#extractUint8()),
|
||||
state: this.#getState(this.extractUInt8()),
|
||||
ROE: this.#getROE(this.extractUInt8()),
|
||||
reactionToThreat: this.#getReactionToThreat(this.extractUInt8()),
|
||||
emissionsCountermeasures: this.#getEmissionCountermeasure(this.extractUInt8()),
|
||||
coalition: this.#getCoalition(this.extractUInt8()),
|
||||
TACAN: {
|
||||
isOn: this.#extractBool(),
|
||||
channel: this.#extractUint8(),
|
||||
XY: this.#extractChar(),
|
||||
callsign: this.#extractString(4)
|
||||
isOn: this.extractBool(),
|
||||
channel: this.extractUInt8(),
|
||||
XY: this.extractChar(),
|
||||
callsign: this.extractString(4)
|
||||
},
|
||||
radio: {
|
||||
frequency: this.#extractUInt32(),
|
||||
callsign: this.#extractUint8(),
|
||||
callsignNumber: this.#extractUint8()
|
||||
frequency: this.extractUInt32(),
|
||||
callsign: this.extractUInt8(),
|
||||
callsignNumber: this.extractUInt8()
|
||||
},
|
||||
activePath: [],
|
||||
ammo: [],
|
||||
contacts: [],
|
||||
task: "",
|
||||
name: "",
|
||||
unitName: "",
|
||||
groupName: "",
|
||||
category: "",
|
||||
coalition: "",
|
||||
task: ""
|
||||
}
|
||||
|
||||
const pathLength = this.#extractUInt16();
|
||||
const ammoLength = this.#extractUInt16();
|
||||
const contactsLength = this.#extractUInt16();
|
||||
const nameLength = this.#extractUInt16();
|
||||
const unitNameLength = this.#extractUInt16();
|
||||
const groupNameLength = this.#extractUInt16();
|
||||
const categoryLength = this.#extractUInt16();
|
||||
const coalitionLength = this.#extractUInt16();
|
||||
const pathLength = this.extractUInt16();
|
||||
const ammoLength = this.extractUInt16();
|
||||
const contactsLength = this.extractUInt16();
|
||||
const taskLength = this.extractUInt8();
|
||||
|
||||
if (pathLength > 0) {
|
||||
unitData.activePath = [];
|
||||
for (let idx = 0; idx < pathLength; idx++) {
|
||||
unitData.activePath.push(new LatLng(this.#extractFloat64(), this.#extractFloat64(), this.#extractFloat64()));
|
||||
unitData.activePath.push(new LatLng(this.extractFloat64(), this.extractFloat64(), this.extractFloat64()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,11 +99,11 @@ export class DataExtractor {
|
||||
unitData.ammo = [];
|
||||
for (let idx = 0; idx < pathLength; idx++) {
|
||||
unitData.ammo.push({
|
||||
quantity: this.#extractUInt16(),
|
||||
name: this.#extractString(32),
|
||||
guidance: this.#extractUint8(),
|
||||
category: this.#extractUint8(),
|
||||
missileCategory: this.#extractUint8()
|
||||
quantity: this.extractUInt16(),
|
||||
name: this.extractString(32),
|
||||
guidance: this.extractUInt8(),
|
||||
category: this.extractUInt8(),
|
||||
missileCategory: this.extractUInt8()
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -116,77 +112,92 @@ export class DataExtractor {
|
||||
unitData.contacts = [];
|
||||
for (let idx = 0; idx < pathLength; idx++) {
|
||||
unitData.contacts.push({
|
||||
ID: this.#extractUInt32(),
|
||||
detectionMethod: this.#extractUint8()
|
||||
ID: this.extractUInt32(),
|
||||
detectionMethod: this.extractUInt8()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (taskLength > 0) {
|
||||
unitData.task = this.extractString(taskLength);
|
||||
}
|
||||
|
||||
const nameLength = this.extractUInt16();
|
||||
const unitNameLength = this.extractUInt16();
|
||||
const groupNameLength = this.extractUInt16();
|
||||
const categoryLength = this.extractUInt16();
|
||||
|
||||
if (nameLength > 0) {
|
||||
unitData.name = this.#extractString(nameLength);
|
||||
unitData.name = this.extractString(nameLength);
|
||||
}
|
||||
|
||||
if (unitNameLength > 0) {
|
||||
unitData.unitName = this.#extractString(unitNameLength);
|
||||
unitData.unitName = this.extractString(unitNameLength);
|
||||
}
|
||||
|
||||
if (groupNameLength > 0) {
|
||||
unitData.groupName = this.#extractString(groupNameLength);
|
||||
unitData.groupName = this.extractString(groupNameLength);
|
||||
}
|
||||
|
||||
if (categoryLength > 0) {
|
||||
unitData.category = this.#extractString(categoryLength);
|
||||
}
|
||||
|
||||
if (coalitionLength > 0) {
|
||||
unitData.coalition = this.#extractString(coalitionLength);
|
||||
unitData.category = this.extractString(categoryLength);
|
||||
}
|
||||
|
||||
return {data: unitData, offset: this.#offset};
|
||||
}
|
||||
|
||||
#extractBool() {
|
||||
extractBool() {
|
||||
const value = this.#dataview.getUint8(this.#offset);
|
||||
this.#offset += 1;
|
||||
return value > 0;
|
||||
}
|
||||
|
||||
#extractUint8() {
|
||||
extractUInt8() {
|
||||
const value = this.#dataview.getUint8(this.#offset);
|
||||
this.#offset += 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
#extractUInt16() {
|
||||
const value = this.#dataview.getUint16(this.#offset);
|
||||
extractUInt16() {
|
||||
const value = this.#dataview.getUint16(this.#offset, true);
|
||||
this.#offset += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
#extractUInt32() {
|
||||
const value = this.#dataview.getUint32(this.#offset);
|
||||
extractUInt32() {
|
||||
const value = this.#dataview.getUint32(this.#offset, true);
|
||||
this.#offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
#extractFloat64() {
|
||||
const value = this.#dataview.getFloat64(this.#offset);
|
||||
extractUInt64() {
|
||||
const value = this.#dataview.getBigUint64(this.#offset, true);
|
||||
this.#offset += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
#extractFromBitmask(bitmask: number, position: number) {
|
||||
return (bitmask >> position & 1) > 0;
|
||||
extractFloat64() {
|
||||
const value = this.#dataview.getFloat64(this.#offset, true);
|
||||
this.#offset += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
#extractString(length: number) {
|
||||
const value = this.#decoder.decode(this.#buffer.slice(this.#offset, length));
|
||||
extractFromBitmask(bitmask: number, position: number) {
|
||||
return ((bitmask >> position) & 1) > 0;
|
||||
}
|
||||
|
||||
extractString(length: number) {
|
||||
const value = this.#decoder.decode(this.#buffer.slice(this.#offset, this.#offset +length));
|
||||
this.#offset += length;
|
||||
return value;
|
||||
}
|
||||
|
||||
#extractChar() {
|
||||
return this.#extractString(1);
|
||||
extractChar() {
|
||||
return this.extractString(1);
|
||||
}
|
||||
|
||||
getOffset() {
|
||||
return this.#offset;
|
||||
}
|
||||
|
||||
#getState(state: number) {
|
||||
@@ -216,4 +227,13 @@ export class DataExtractor {
|
||||
else
|
||||
return emissionsCountermeasures[0];
|
||||
}
|
||||
|
||||
#getCoalition(coalitionID: number) {
|
||||
switch (coalitionID){
|
||||
case 0: return "neutral";
|
||||
case 1: return "red";
|
||||
case 2: return "blue";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,8 @@ export class Unit extends CustomMarker {
|
||||
human: false,
|
||||
controlled: false,
|
||||
hasTask: false,
|
||||
desiredAltitudeType: false,
|
||||
desiredSpeedType: false,
|
||||
desiredAltitudeType: "AGL",
|
||||
desiredSpeedType: "GS",
|
||||
isTanker: false,
|
||||
isAWACS: false,
|
||||
onOff: false,
|
||||
@@ -222,7 +222,6 @@ export class Unit extends CustomMarker {
|
||||
var updateMarker = positionChanged || headingChanged || aliveChanged || stateChanged || controlledChanged || !getMap().hasLayer(this);
|
||||
|
||||
/* Assign the data */
|
||||
/* TODO Allow for partial updates */
|
||||
this.#data = data;
|
||||
|
||||
/* Fire an event when a unit dies */
|
||||
@@ -406,10 +405,10 @@ export class Unit extends CustomMarker {
|
||||
var path: any = {};
|
||||
if (this.getData().activePath.length > 0) {
|
||||
path = this.getData().activePath;
|
||||
path[(Object.keys(path).length + 1).toString()] = latlng;
|
||||
path[(Object.keys(path).length).toString()] = latlng;
|
||||
}
|
||||
else {
|
||||
path = { "1": latlng };
|
||||
path = [latlng];
|
||||
}
|
||||
addDestination(this.ID, path);
|
||||
}
|
||||
@@ -779,7 +778,7 @@ export class Unit extends CustomMarker {
|
||||
/* Update the position of the existing markers (to avoid creating markers uselessly) */
|
||||
for (let WP in this.getData().activePath) {
|
||||
var destination = this.getData().activePath[WP];
|
||||
this.#pathMarkers[parseInt(WP) - 1].setLatLng([destination.lat, destination.lng]);
|
||||
this.#pathMarkers[parseInt(WP)].setLatLng([destination.lat, destination.lng]);
|
||||
points.push(new LatLng(destination.lat, destination.lng));
|
||||
this.#pathPolyline.setLatLngs(points);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { LatLng, LatLngBounds } from "leaflet";
|
||||
import { getHotgroupPanel, getInfoPopup, getMap, getMissionHandler } from "..";
|
||||
import { Unit } from "./unit";
|
||||
import { cloneUnit, spawnGroundUnit } from "../server/server";
|
||||
import { base64ToBytes, deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polygonArea, randomPointInPoly, randomUnitBlueprintByRole } from "../other/utils";
|
||||
import { cloneUnit, setLastUpdateTime, spawnGroundUnit } from "../server/server";
|
||||
import { deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polygonArea, randomPointInPoly, randomUnitBlueprintByRole } from "../other/utils";
|
||||
import { CoalitionArea } from "../map/coalitionarea";
|
||||
import { Airbase } from "../missionhandler/airbase";
|
||||
import { groundUnitsDatabase } from "./groundunitsdatabase";
|
||||
@@ -70,13 +70,13 @@ export class UnitsManager {
|
||||
|
||||
}
|
||||
|
||||
update(encodedData: string) {
|
||||
update(buffer: ArrayBuffer) {
|
||||
var updatedUnits: Unit[] = [];
|
||||
var buffer = base64ToBytes(encodedData);
|
||||
var dataExtractor = new DataExtractor(buffer);
|
||||
var data: {[key: string]: UnitData} = {};
|
||||
|
||||
var offset = 0;
|
||||
var updateTime = Number(dataExtractor.extractUInt64());
|
||||
var offset = dataExtractor.getOffset();
|
||||
while (offset < buffer.byteLength) {
|
||||
const result = dataExtractor.extractData(offset);
|
||||
data[result.data.ID] = result.data;
|
||||
@@ -106,6 +106,8 @@ export class UnitsManager {
|
||||
// if (!updatedUnits.includes(unit))
|
||||
// unit.setData(null);
|
||||
//});
|
||||
|
||||
setLastUpdateTime(updateTime);
|
||||
}
|
||||
|
||||
setHiddenType(key: string, value: boolean) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
local version = "v0.3.0-alpha"
|
||||
|
||||
local debug = false
|
||||
local debug = FALSE
|
||||
|
||||
Olympus.unitCounter = 1
|
||||
Olympus.payloadRegistry = {}
|
||||
|
||||
8
src/.vscode/settings.json
vendored
8
src/.vscode/settings.json
vendored
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.ejs": "html",
|
||||
"xstring": "cpp",
|
||||
"vector": "cpp",
|
||||
"list": "cpp"
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@
|
||||
#include "logger.h"
|
||||
#include "commands.h"
|
||||
|
||||
#include <chrono>
|
||||
using namespace std::chrono;
|
||||
|
||||
#define TASK_CHECK_INIT_VALUE 10
|
||||
|
||||
namespace State
|
||||
@@ -79,8 +82,10 @@ namespace DataTypes {
|
||||
unsigned short fuel;
|
||||
double desiredSpeed;
|
||||
double desiredAltitude;
|
||||
unsigned int leaderID;
|
||||
unsigned int targetID;
|
||||
Coords targetPosition;
|
||||
unsigned char coalition;
|
||||
unsigned char state;
|
||||
unsigned char ROE;
|
||||
unsigned char reactionToThreat;
|
||||
@@ -90,11 +95,7 @@ namespace DataTypes {
|
||||
unsigned short pathLength;
|
||||
unsigned short ammoLength;
|
||||
unsigned short contactsLength;
|
||||
unsigned char nameLength;
|
||||
unsigned char unitNameLength;
|
||||
unsigned char groupNameLength;
|
||||
unsigned char categoryLength;
|
||||
unsigned char coalitionLength;
|
||||
unsigned char taskLength;
|
||||
};
|
||||
}
|
||||
#pragma pack(pop)
|
||||
@@ -112,18 +113,18 @@ public:
|
||||
void runAILoop();
|
||||
void updateExportData(json::value json, double dt = 0);
|
||||
void updateMissionData(json::value json);
|
||||
unsigned int getUpdateData(char* &data);
|
||||
void getData(stringstream &ss, bool refresh);
|
||||
unsigned int getDataPacket(char* &data);
|
||||
void getData(stringstream &ss, unsigned long long time, bool refresh);
|
||||
virtual string getCategory() { return "No category"; };
|
||||
|
||||
/********** Base data **********/
|
||||
void setControlled(bool newControlled) { controlled = newControlled; }
|
||||
void setName(string newName) { name = newName; }
|
||||
void setUnitName(string newUnitName) { unitName = newUnitName; }
|
||||
void setGroupName(string newGroupName) { groupName = newGroupName; }
|
||||
void setAlive(bool newAlive) { alive = newAlive; }
|
||||
void setCountry(unsigned int newCountry) { country = newCountry; }
|
||||
void setHuman(bool newHuman) { human = newHuman; }
|
||||
void setControlled(bool newValue) { updateValue(controlled, newValue); }
|
||||
void setName(string newValue) { updateValue(name, newValue); }
|
||||
void setUnitName(string newValue) { updateValue(unitName, newValue); }
|
||||
void setGroupName(string newValue) { updateValue(groupName, newValue); }
|
||||
void setAlive(bool newValue) { updateValue(alive, newValue); }
|
||||
void setCountry(unsigned int newValue) { updateValue(country, newValue); }
|
||||
void setHuman(bool newValue) { updateValue(human, newValue); }
|
||||
|
||||
bool getControlled() { return controlled; }
|
||||
string getName() { return name; }
|
||||
@@ -134,51 +135,50 @@ public:
|
||||
bool getHuman() { return human; }
|
||||
|
||||
/********** Flight data **********/
|
||||
void setPosition(Coords newPosition) { position = newPosition; }
|
||||
void setHeading(double newHeading) {heading = newHeading; }
|
||||
void setSpeed(double newSpeed) {speed = newSpeed; }
|
||||
void setPosition(Coords newValue) { updateValue(position, newValue); }
|
||||
void setHeading(double newValue) { updateValue(heading, newValue); }
|
||||
void setSpeed(double newValue) { updateValue(speed, newValue); }
|
||||
|
||||
Coords getPosition() { return position; }
|
||||
double getHeading() { return heading; }
|
||||
double getSpeed() { return speed; }
|
||||
|
||||
/********** Mission data **********/
|
||||
void setFuel(short newFuel) { fuel = newFuel; }
|
||||
void setFuel(unsigned short newValue) { updateValue(fuel, newValue); }
|
||||
void setAmmo(vector<DataTypes::Ammo> newAmmo) { ammo = newAmmo; }
|
||||
void setContacts(vector<DataTypes::Contact> newContacts) {contacts = newContacts; }
|
||||
void setHasTask(bool newHasTask);
|
||||
void setCoalitionID(unsigned int newCoalitionID);
|
||||
void setContacts(vector<DataTypes::Contact> newContacts) { contacts = newContacts; }
|
||||
void setHasTask(bool newValue) { updateValue(hasTask, newValue); }
|
||||
void setCoalition(unsigned char newValue) { updateValue(coalition, newValue);}
|
||||
|
||||
double getFuel() { return fuel; }
|
||||
vector<DataTypes::Ammo> getAmmo() { return ammo; }
|
||||
vector<DataTypes::Contact> getTargets() { return contacts; }
|
||||
bool getHasTask() { return hasTask; }
|
||||
string getCoalition() { return coalition; }
|
||||
unsigned int getCoalitionID();
|
||||
unsigned int getCoalition() { return coalition; }
|
||||
|
||||
/********** Formation data **********/
|
||||
void setLeaderID(unsigned int newLeaderID) { leaderID = newLeaderID; }
|
||||
void setLeaderID(unsigned int newValue) { updateValue(leaderID, newValue); }
|
||||
void setFormationOffset(Offset formationOffset);
|
||||
|
||||
unsigned int getLeaderID() { return leaderID; }
|
||||
Offset getFormationoffset() { return formationOffset; }
|
||||
|
||||
/********** Task data **********/
|
||||
void setCurrentTask(string newCurrentTask) { currentTask = newCurrentTask; }
|
||||
void setDesiredSpeed(double newDesiredSpeed);
|
||||
void setDesiredAltitude(double newDesiredAltitude);
|
||||
void setDesiredSpeedType(string newDesiredSpeedType);
|
||||
void setDesiredAltitudeType(string newDesiredAltitudeType);
|
||||
void setActiveDestination(Coords newActiveDestination) { activeDestination = newActiveDestination; }
|
||||
void setActivePath(list<Coords> newActivePath);
|
||||
void setTargetID(unsigned int newTargetID) { targetID = newTargetID; }
|
||||
void setTargetPosition(Coords newTargetPosition);
|
||||
void setIsTanker(bool newIsTanker);
|
||||
void setIsAWACS(bool newIsAWACS);
|
||||
virtual void setOnOff(bool newOnOff) { onOff = newOnOff; };
|
||||
virtual void setFollowRoads(bool newFollowRoads) { followRoads = newFollowRoads; };
|
||||
void setTask(string newValue) { updateValue(task, newValue); }
|
||||
void setDesiredSpeed(double newValue);
|
||||
void setDesiredAltitude(double newValue);
|
||||
void setDesiredSpeedType(string newValue);
|
||||
void setDesiredAltitudeType(string newValue);
|
||||
void setActiveDestination(Coords newValue) { updateValue(activeDestination, newValue); }
|
||||
void setActivePath(list<Coords> newValue);
|
||||
void setTargetID(unsigned int newValue) { updateValue(targetID, newValue); }
|
||||
void setTargetPosition(Coords newValue) { updateValue(targetPosition, newValue); }
|
||||
void setIsTanker(bool newValue);
|
||||
void setIsAWACS(bool newValue);
|
||||
virtual void setOnOff(bool newValue) { updateValue(onOff, newValue); };
|
||||
virtual void setFollowRoads(bool newValue) { updateValue(followRoads, newValue); };
|
||||
|
||||
string getCurrentTask() { return currentTask; }
|
||||
string getTask() { return task; }
|
||||
virtual double getDesiredSpeed() { return desiredSpeed; };
|
||||
virtual double getDesiredAltitude() { return desiredAltitude; };
|
||||
virtual bool getDesiredSpeedType() { return desiredSpeedType; };
|
||||
@@ -193,13 +193,13 @@ public:
|
||||
bool getFollowRoads() { return followRoads; };
|
||||
|
||||
/********** Options data **********/
|
||||
void setROE(unsigned char newROE, bool force = false);
|
||||
void setReactionToThreat(unsigned char newReactionToThreat, bool force = false);
|
||||
void setEmissionsCountermeasures(unsigned char newEmissionsCountermeasures, bool force = false);
|
||||
void setTACAN(Options::TACAN newTACAN, bool force = false);
|
||||
void setRadio(Options::Radio newradio, bool force = false);
|
||||
void setGeneralSettings(Options::GeneralSettings newGeneralSettings, bool force = false);
|
||||
void setEPLRS(bool newEPLRS, bool force = false);
|
||||
void setROE(unsigned char newValue, bool force = false);
|
||||
void setReactionToThreat(unsigned char newValue, bool force = false);
|
||||
void setEmissionsCountermeasures(unsigned char newValue, bool force = false);
|
||||
void setTACAN(Options::TACAN newValue, bool force = false);
|
||||
void setRadio(Options::Radio newValue, bool force = false);
|
||||
void setGeneralSettings(Options::GeneralSettings newValue, bool force = false);
|
||||
void setEPLRS(bool newValue, bool force = false);
|
||||
|
||||
unsigned char getROE() { return ROE; }
|
||||
unsigned char getReactionToThreat() { return reactionToThreat; }
|
||||
@@ -220,6 +220,8 @@ public:
|
||||
void pushActivePathFront(Coords newActivePathFront);
|
||||
void pushActivePathBack(Coords newActivePathBack);
|
||||
void popActivePathFront();
|
||||
void triggerUpdate() { lastUpdateTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); }
|
||||
unsigned long long getLastUpdateTime() { return lastUpdateTime; };
|
||||
|
||||
protected:
|
||||
unsigned int ID;
|
||||
@@ -247,18 +249,18 @@ protected:
|
||||
vector<DataTypes::Ammo> ammo;
|
||||
vector<DataTypes::Contact> contacts;
|
||||
bool hasTask = false;
|
||||
string coalition = "";
|
||||
unsigned char coalition;
|
||||
|
||||
/********** Formation data **********/
|
||||
unsigned int leaderID = NULL;
|
||||
Offset formationOffset = Offset(NULL);
|
||||
|
||||
/********** Task data **********/
|
||||
string currentTask = "";
|
||||
string task = "";
|
||||
double desiredSpeed = 0;
|
||||
double desiredAltitude = 0;
|
||||
bool desiredSpeedType = 0;
|
||||
bool desiredAltitudeType = 0;
|
||||
bool desiredSpeedType = 1;
|
||||
bool desiredAltitudeType = 1;
|
||||
list<Coords> activePath;
|
||||
Coords activeDestination = Coords(NULL);
|
||||
unsigned int targetID = NULL;
|
||||
@@ -277,10 +279,14 @@ protected:
|
||||
Options::GeneralSettings generalSettings;
|
||||
bool EPLRS = false;
|
||||
|
||||
/********** Data packet **********/
|
||||
DataTypes::DataPacket dataPacket;
|
||||
|
||||
/********** State machine **********/
|
||||
unsigned char state = State::NONE;
|
||||
|
||||
/********** Other **********/
|
||||
unsigned long long lastUpdateTime = 0;
|
||||
Coords oldPosition = Coords(0); // Used to approximate speed
|
||||
|
||||
/********** Functions **********/
|
||||
@@ -295,4 +301,14 @@ protected:
|
||||
void goToDestination(string enrouteTask = "nil");
|
||||
bool checkTaskFailed();
|
||||
void resetTaskFailedCounter();
|
||||
|
||||
template <typename T>
|
||||
void updateValue(T& value, T& newValue)
|
||||
{
|
||||
if (newValue != value)
|
||||
{
|
||||
triggerUpdate();
|
||||
*(&value) = newValue;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
void updateExportData(lua_State* L, double dt = 0);
|
||||
void updateMissionData(json::value missionData);
|
||||
void runAILoop();
|
||||
string getUnitData(bool refresh);
|
||||
string getUnitData(stringstream &ss, unsigned long long time, bool refresh);
|
||||
void deleteUnit(unsigned int ID, bool explosion);
|
||||
void acquireControl(unsigned int ID);
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ void AirUnit::AIloop()
|
||||
/* State machine */
|
||||
switch (state) {
|
||||
case State::IDLE: {
|
||||
currentTask = "Idle";
|
||||
setTask("Idle");
|
||||
|
||||
if (!getHasTask())
|
||||
{
|
||||
@@ -147,17 +147,17 @@ void AirUnit::AIloop()
|
||||
if (isTanker)
|
||||
{
|
||||
enrouteTask = "{ id = 'Tanker' }";
|
||||
currentTask = "Tanker";
|
||||
setTask("Tanker");
|
||||
}
|
||||
else if (isAWACS)
|
||||
{
|
||||
enrouteTask = "{ id = 'AWACS' }";
|
||||
currentTask = "AWACS";
|
||||
setTask("AWACS");
|
||||
}
|
||||
else
|
||||
{
|
||||
enrouteTask = "nil";
|
||||
currentTask = "Reaching destination";
|
||||
setTask("Reaching destination");
|
||||
}
|
||||
|
||||
if (activeDestination == NULL || !getHasTask())
|
||||
@@ -179,7 +179,7 @@ void AirUnit::AIloop()
|
||||
}
|
||||
case State::LAND: {
|
||||
string enrouteTask = "{ id = 'Land' }";
|
||||
currentTask = "Landing";
|
||||
setTask("Landing");
|
||||
|
||||
if (activeDestination == NULL)
|
||||
{
|
||||
@@ -203,7 +203,7 @@ void AirUnit::AIloop()
|
||||
<< "targetID = " << targetID << ","
|
||||
<< "}";
|
||||
string enrouteTask = enrouteTaskSS.str();
|
||||
currentTask = "Attacking " + getTargetName();
|
||||
setTask("Attacking " + getTargetName());
|
||||
|
||||
if (!getHasTask())
|
||||
{
|
||||
@@ -223,7 +223,7 @@ void AirUnit::AIloop()
|
||||
break;
|
||||
}
|
||||
|
||||
currentTask = "Following " + getTargetName();
|
||||
setTask("Following " + getTargetName());
|
||||
|
||||
Unit* leader = unitsManager->getUnit(leaderID);
|
||||
if (!getHasTask()) {
|
||||
@@ -247,7 +247,7 @@ void AirUnit::AIloop()
|
||||
break;
|
||||
}
|
||||
case State::REFUEL: {
|
||||
currentTask = "Refueling";
|
||||
setTask("Refueling");
|
||||
|
||||
if (!getHasTask()) {
|
||||
if (fuel <= initialFuel) {
|
||||
@@ -265,7 +265,7 @@ void AirUnit::AIloop()
|
||||
}
|
||||
}
|
||||
case State::BOMB_POINT: {
|
||||
currentTask = "Bombing point";
|
||||
setTask("Bombing point");
|
||||
|
||||
if (!getHasTask()) {
|
||||
std::ostringstream taskSS;
|
||||
@@ -276,7 +276,7 @@ void AirUnit::AIloop()
|
||||
}
|
||||
}
|
||||
case State::CARPET_BOMB: {
|
||||
currentTask = "Carpet bombing";
|
||||
setTask("Carpet bombing");
|
||||
|
||||
if (!getHasTask()) {
|
||||
std::ostringstream taskSS;
|
||||
@@ -288,7 +288,7 @@ void AirUnit::AIloop()
|
||||
break;
|
||||
}
|
||||
case State::BOMB_BUILDING: {
|
||||
currentTask = "Bombing building";
|
||||
setTask("Bombing building");
|
||||
|
||||
if (!getHasTask()) {
|
||||
std::ostringstream taskSS;
|
||||
|
||||
@@ -85,13 +85,14 @@ extern "C" DllExport int coreFrame(lua_State* L)
|
||||
|
||||
if (unitsManager != nullptr) {
|
||||
unitsManager->updateExportData(L, duration.count());
|
||||
//unitsManager->runAILoop();
|
||||
unitsManager->runAILoop();
|
||||
|
||||
}
|
||||
before = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
if (scheduler != nullptr)
|
||||
//scheduler->execute(L);
|
||||
scheduler->execute(L);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ void GroundUnit::AIloop()
|
||||
{
|
||||
switch (state) {
|
||||
case State::IDLE: {
|
||||
currentTask = "Idle";
|
||||
setTask("Idle");
|
||||
if (getHasTask())
|
||||
resetTask();
|
||||
break;
|
||||
@@ -102,7 +102,7 @@ void GroundUnit::AIloop()
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA: {
|
||||
currentTask = "Firing at area";
|
||||
setTask("Firing at area");
|
||||
|
||||
if (!getHasTask()) {
|
||||
std::ostringstream taskSS;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
extern UnitsManager* unitsManager;
|
||||
|
||||
Scheduler::Scheduler(lua_State* L):
|
||||
Scheduler::Scheduler(lua_State* L) :
|
||||
load(0)
|
||||
{
|
||||
LogInfo(L, "Scheduler constructor called successfully");
|
||||
@@ -25,16 +25,15 @@ void Scheduler::appendCommand(Command* command)
|
||||
|
||||
void Scheduler::execute(lua_State* L)
|
||||
{
|
||||
/* Decrease the active computation load. New commands can be sent only if the load has reached 0.
|
||||
/* Decrease the active computation load. New commands can be sent only if the load has reached 0.
|
||||
This is needed to avoid server lag. */
|
||||
if (load > 0) {
|
||||
load--;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int priority = CommandPriority::IMMEDIATE;
|
||||
while (priority >= CommandPriority::LOW)
|
||||
{
|
||||
int priority = CommandPriority::IMMEDIATE;
|
||||
while (priority >= CommandPriority::LOW) {
|
||||
for (auto command : commands)
|
||||
{
|
||||
if (command->getPriority() == priority)
|
||||
@@ -42,13 +41,15 @@ void Scheduler::execute(lua_State* L)
|
||||
string commandString = "Olympus.protectedCall(" + command->getString(L) + ")";
|
||||
if (dostring_in(L, "server", (commandString)))
|
||||
log("Error executing command " + commandString);
|
||||
else
|
||||
log("Command '" + commandString + "' executed correctly, current load " + to_string(load));
|
||||
load = command->getLoad();
|
||||
commands.remove(command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
priority--;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void Scheduler::handleRequest(string key, json::value value)
|
||||
@@ -66,11 +67,11 @@ void Scheduler::handleRequest(string key, json::value value)
|
||||
string unitName = unit->getUnitName();
|
||||
json::value path = value[L"path"];
|
||||
list<Coords> newPath;
|
||||
for (unsigned int i = 1; i <= path.as_object().size(); i++)
|
||||
for (unsigned int i = 0; i < path.as_array().size(); i++)
|
||||
{
|
||||
string WP = to_string(i);
|
||||
double lat = path[to_wstring(i)][L"lat"].as_double();
|
||||
double lng = path[to_wstring(i)][L"lng"].as_double();
|
||||
double lat = path[i][L"lat"].as_double();
|
||||
double lng = path[i][L"lng"].as_double();
|
||||
log(unitName + " set path destination " + WP + " (" + to_string(lat) + ", " + to_string(lng) + ")");
|
||||
Coords dest; dest.lat = lat; dest.lng = lng;
|
||||
newPath.push_back(dest);
|
||||
@@ -126,7 +127,7 @@ void Scheduler::handleRequest(string key, json::value value)
|
||||
|
||||
string unitName;
|
||||
string targetName;
|
||||
|
||||
|
||||
if (unit != nullptr)
|
||||
unitName = unit->getUnitName();
|
||||
else
|
||||
@@ -197,11 +198,11 @@ void Scheduler::handleRequest(string key, json::value value)
|
||||
}
|
||||
else if (key.compare("setSpeedType") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr)
|
||||
unit->setDesiredSpeedType(to_string(value[L"speedType"]));
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr)
|
||||
unit->setDesiredSpeedType(to_string(value[L"speedType"]));
|
||||
}
|
||||
else if (key.compare("setAltitude") == 0)
|
||||
{
|
||||
@@ -233,7 +234,7 @@ void Scheduler::handleRequest(string key, json::value value)
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unsigned char ROE = value[L"ROE"].as_number().is_uint32();
|
||||
unsigned char ROE = value[L"ROE"].as_number().to_uint32();
|
||||
unit->setROE(ROE);
|
||||
}
|
||||
else if (key.compare("setReactionToThreat") == 0)
|
||||
@@ -241,7 +242,7 @@ void Scheduler::handleRequest(string key, json::value value)
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unsigned char reactionToThreat = value[L"reactionToThreat"].as_number().is_uint32();
|
||||
unsigned char reactionToThreat = value[L"reactionToThreat"].as_number().to_uint32();
|
||||
unit->setReactionToThreat(reactionToThreat);
|
||||
}
|
||||
else if (key.compare("setEmissionsCountermeasures") == 0)
|
||||
@@ -249,7 +250,7 @@ void Scheduler::handleRequest(string key, json::value value)
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unsigned char emissionsCountermeasures = value[L"emissionsCountermeasures"].as_number().is_uint32();
|
||||
unsigned char emissionsCountermeasures = value[L"emissionsCountermeasures"].as_number().to_uint32();
|
||||
unit->setEmissionsCountermeasures(emissionsCountermeasures);
|
||||
}
|
||||
else if (key.compare("landAt") == 0)
|
||||
@@ -317,7 +318,7 @@ void Scheduler::handleRequest(string key, json::value value)
|
||||
}
|
||||
}
|
||||
else if (key.compare("setFollowRoads") == 0)
|
||||
{
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
bool followRoads = value[L"followRoads"].as_bool();
|
||||
@@ -325,7 +326,7 @@ void Scheduler::handleRequest(string key, json::value value)
|
||||
unit->setFollowRoads(followRoads);
|
||||
}
|
||||
else if (key.compare("setOnOff") == 0)
|
||||
{
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
bool onOff = value[L"onOff"].as_bool();
|
||||
@@ -389,10 +390,11 @@ void Scheduler::handleRequest(string key, json::value value)
|
||||
{
|
||||
log("Unknown command: " + key);
|
||||
}
|
||||
|
||||
|
||||
if (command != nullptr)
|
||||
{
|
||||
appendCommand(command);
|
||||
log("New command appended correctly to stack. Current server load: " + to_string(load));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,10 +69,11 @@ void Server::handle_get(http_request request)
|
||||
/* Lock for thread safety */
|
||||
lock_guard<mutex> guard(mutexLock);
|
||||
|
||||
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
|
||||
|
||||
http_response response(status_codes::OK);
|
||||
string authorization = to_base64("admin:" + password);
|
||||
log(authorization);
|
||||
if (password == "" || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second == L"Basic " + to_wstring(authorization)))
|
||||
if (password.length() == 0 || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second.compare(L"Basic " + to_wstring(authorization)) == 0))
|
||||
{
|
||||
std::exception_ptr eptr;
|
||||
try {
|
||||
@@ -96,28 +97,34 @@ void Server::handle_get(http_request request)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO would be nice to optimize this
|
||||
answer[L"units"] = json::value(to_wstring(unitsManager->getUnitData(time == 0)));
|
||||
}
|
||||
else if (URI.compare(LOGS_URI) == 0)
|
||||
{
|
||||
auto logs = json::value::object();
|
||||
getLogsJSON(logs, 100); // By reference, for thread safety. Get the last 100 log entries
|
||||
answer[L"logs"] = logs;
|
||||
}
|
||||
else if (URI.compare(AIRBASES_URI) == 0)
|
||||
answer[L"airbases"] = airbases;
|
||||
else if (URI.compare(BULLSEYE_URI) == 0)
|
||||
answer[L"bullseyes"] = bullseyes;
|
||||
else if (URI.compare(MISSION_URI) == 0)
|
||||
answer[L"mission"] = mission;
|
||||
bool refresh = (time == 0);
|
||||
unsigned long long updateTime = ms.count();
|
||||
|
||||
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
|
||||
answer[L"time"] = json::value::string(to_wstring(ms.count()));
|
||||
answer[L"sessionHash"] = json::value::string(to_wstring(sessionHash));
|
||||
stringstream ss;
|
||||
ss.write((char*)&updateTime, sizeof(updateTime));
|
||||
unitsManager->getUnitData(ss, time, refresh);
|
||||
response.set_body(concurrency::streams::bytestream::open_istream(ss.str()));
|
||||
}
|
||||
else {
|
||||
if (URI.compare(LOGS_URI) == 0)
|
||||
{
|
||||
auto logs = json::value::object();
|
||||
getLogsJSON(logs, 100); // By reference, for thread safety. Get the last 100 log entries
|
||||
answer[L"logs"] = logs;
|
||||
}
|
||||
else if (URI.compare(AIRBASES_URI) == 0)
|
||||
answer[L"airbases"] = airbases;
|
||||
else if (URI.compare(BULLSEYE_URI) == 0)
|
||||
answer[L"bullseyes"] = bullseyes;
|
||||
else if (URI.compare(MISSION_URI) == 0)
|
||||
answer[L"mission"] = mission;
|
||||
|
||||
|
||||
answer[L"time"] = json::value::string(to_wstring(ms.count()));
|
||||
answer[L"sessionHash"] = json::value::string(to_wstring(sessionHash));
|
||||
response.set_body(answer);
|
||||
}
|
||||
}
|
||||
|
||||
response.set_body(answer);
|
||||
}
|
||||
catch (...) {
|
||||
eptr = std::current_exception(); // capture
|
||||
@@ -140,7 +147,7 @@ void Server::handle_request(http_request request, function<void(json::value cons
|
||||
{
|
||||
http_response response(status_codes::OK);
|
||||
string authorization = to_base64("admin:" + password);
|
||||
if (password == "" || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second.compare(L"Basic " + to_wstring(authorization))))
|
||||
if (password.length() == 0 || (request.headers().has(L"Authorization") && request.headers().find(L"Authorization")->second.compare(L"Basic " + to_wstring(authorization)) == 0))
|
||||
{
|
||||
auto answer = json::value::object();
|
||||
request.extract_json().then([&answer, &action](pplx::task<json::value> task)
|
||||
|
||||
@@ -45,6 +45,24 @@ Unit::~Unit()
|
||||
|
||||
void Unit::initialize(json::value json)
|
||||
{
|
||||
if (json.has_string_field(L"Name"))
|
||||
setName(to_string(json[L"Name"]));
|
||||
if (json.has_string_field(L"UnitName"))
|
||||
setUnitName(to_string(json[L"UnitName"]));
|
||||
if (json.has_string_field(L"GroupName"))
|
||||
setGroupName(to_string(json[L"GroupName"]));
|
||||
if (json.has_number_field(L"Country"))
|
||||
setCountry(json[L"Country"].as_number().to_int32());
|
||||
if (json.has_number_field(L"CoalitionID"))
|
||||
setCoalition(json[L"CoalitionID"].as_number().to_int32());
|
||||
|
||||
if (json.has_object_field(L"Flags"))
|
||||
setHuman(json[L"Flags"][L"Human"].as_bool());
|
||||
|
||||
/* All units which contain the name "Olympus" are automatically under AI control */
|
||||
if (getUnitName().find("Olympus") != string::npos)
|
||||
setControlled(true);
|
||||
|
||||
updateExportData(json);
|
||||
setDefaults();
|
||||
}
|
||||
@@ -92,6 +110,21 @@ void Unit::runAILoop() {
|
||||
|
||||
void Unit::updateExportData(json::value json, double dt)
|
||||
{
|
||||
Coords newPosition = Coords(NULL);
|
||||
double newHeading = 0;
|
||||
double newSpeed = 0;
|
||||
|
||||
if (json.has_object_field(L"LatLongAlt"))
|
||||
{
|
||||
setPosition({
|
||||
json[L"LatLongAlt"][L"Lat"].as_number().to_double(),
|
||||
json[L"LatLongAlt"][L"Long"].as_number().to_double(),
|
||||
json[L"LatLongAlt"][L"Alt"].as_number().to_double()
|
||||
});
|
||||
}
|
||||
if (json.has_number_field(L"Heading"))
|
||||
setHeading(json[L"Heading"].as_number().to_double());
|
||||
|
||||
/* Compute speed (loGetWorldObjects does not provide speed, we compute it for better performance instead of relying on many lua calls) */
|
||||
if (oldPosition != NULL)
|
||||
{
|
||||
@@ -100,35 +133,7 @@ void Unit::updateExportData(json::value json, double dt)
|
||||
if (dt > 0)
|
||||
setSpeed(getSpeed() * 0.95 + (dist / dt) * 0.05);
|
||||
}
|
||||
|
||||
if (json.has_string_field(L"Name"))
|
||||
setName(to_string(json[L"Name"]));
|
||||
if (json.has_string_field(L"UnitName"))
|
||||
setUnitName(to_string(json[L"UnitName"]));
|
||||
if (json.has_string_field(L"GroupName"))
|
||||
setGroupName(to_string(json[L"GroupName"]));
|
||||
if (json.has_number_field(L"Country"))
|
||||
setCountry(json[L"Country"].as_number().to_int32());
|
||||
if (json.has_number_field(L"CoalitionID"))
|
||||
setCoalitionID(json[L"CoalitionID"].as_number().to_int32());
|
||||
if (json.has_object_field(L"LatLongAlt"))
|
||||
{
|
||||
Coords position = {
|
||||
json[L"LatLongAlt"][L"Lat"].as_number().to_double(),
|
||||
json[L"LatLongAlt"][L"Long"].as_number().to_double(),
|
||||
json[L"LatLongAlt"][L"Alt"].as_number().to_double()
|
||||
};
|
||||
setPosition(position);
|
||||
}
|
||||
if (json.has_number_field(L"Heading"))
|
||||
setHeading(json[L"Heading"].as_number().to_double());
|
||||
if (json.has_object_field(L"Flags"))
|
||||
setHuman(json[L"Flags"][L"Human"].as_bool());
|
||||
|
||||
/* All units which contain the name "Olympus" are automatically under AI control */
|
||||
if (getUnitName().find("Olympus") != string::npos)
|
||||
setControlled(true);
|
||||
|
||||
|
||||
oldPosition = position;
|
||||
}
|
||||
|
||||
@@ -175,7 +180,7 @@ void Unit::updateMissionData(json::value json)
|
||||
setHasTask(json[L"hasTask"].as_bool());
|
||||
}
|
||||
|
||||
unsigned int Unit::getUpdateData(char* &data)
|
||||
unsigned int Unit::getDataPacket(char* &data)
|
||||
{
|
||||
/* Reserve data for:
|
||||
1) DataPacket;
|
||||
@@ -217,34 +222,31 @@ unsigned int Unit::getUpdateData(char* &data)
|
||||
fuel,
|
||||
desiredSpeed,
|
||||
desiredAltitude,
|
||||
leaderID,
|
||||
targetID,
|
||||
targetPosition,
|
||||
state,
|
||||
ROE,
|
||||
reactionToThreat,
|
||||
emissionsCountermeasures,
|
||||
coalition,
|
||||
TACAN,
|
||||
radio,
|
||||
activePath.size(),
|
||||
ammo.size(),
|
||||
contacts.size(),
|
||||
name.size(),
|
||||
unitName.size(),
|
||||
groupName.size(),
|
||||
getCategory().size(),
|
||||
coalition.size()
|
||||
task.size()
|
||||
};
|
||||
|
||||
memcpy(data + offset, &dataPacket, sizeof(dataPacket));
|
||||
offset += sizeof(dataPacket);
|
||||
|
||||
/* Prepare the path vector and copy it to memory */
|
||||
std::vector<Coords> path;
|
||||
for (const Coords& c : activePath)
|
||||
path.push_back(c);
|
||||
memcpy(data + offset, &path, activePath.size() * sizeof(Coords));
|
||||
offset += activePath.size() * sizeof(Coords);
|
||||
|
||||
for (const Coords& c : activePath) {
|
||||
memcpy(data + offset, &c, sizeof(Coords));
|
||||
offset += sizeof(Coords);
|
||||
}
|
||||
|
||||
/* Copy the ammo vector to memory */
|
||||
memcpy(data + offset, &ammo, ammo.size() * sizeof(DataTypes::Ammo));
|
||||
offset += ammo.size() * sizeof(DataTypes::Ammo);
|
||||
@@ -256,10 +258,12 @@ unsigned int Unit::getUpdateData(char* &data)
|
||||
return offset;
|
||||
}
|
||||
|
||||
void Unit::getData(stringstream &ss, bool refresh)
|
||||
void Unit::getData(stringstream &ss, unsigned long long time, bool refresh)
|
||||
{
|
||||
if (time > lastUpdateTime && !refresh) return;
|
||||
|
||||
char* data;
|
||||
unsigned int size = getUpdateData(data);
|
||||
unsigned int size = getDataPacket(data);
|
||||
|
||||
/* Prepare the data packet and copy it to memory */
|
||||
/* If the unit is in a group, get the update data from the group leader and only replace the position, speed and heading */
|
||||
@@ -271,15 +275,25 @@ void Unit::getData(stringstream &ss, bool refresh)
|
||||
}
|
||||
|
||||
ss.write(data, size);
|
||||
delete data;
|
||||
ss << task;
|
||||
|
||||
if (refresh) {
|
||||
ss << name;
|
||||
ss << unitName;
|
||||
ss << groupName;
|
||||
ss << getCategory();
|
||||
ss << coalition;
|
||||
}
|
||||
unsigned short nameLength = name.length();
|
||||
unsigned short unitNameLength = unitName.length();
|
||||
unsigned short groupNameLength = groupName.length();
|
||||
unsigned short categoryLength = getCategory().length();
|
||||
|
||||
ss.write((char*)&nameLength, sizeof(nameLength));
|
||||
ss.write((char*)&unitNameLength, sizeof(unitNameLength));
|
||||
ss.write((char*)&groupNameLength, sizeof(groupNameLength));
|
||||
ss.write((char*)&categoryLength, sizeof(categoryLength));
|
||||
|
||||
ss << name;
|
||||
ss << unitName;
|
||||
ss << groupName;
|
||||
ss << getCategory();
|
||||
|
||||
|
||||
delete data;
|
||||
}
|
||||
|
||||
void Unit::setActivePath(list<Coords> newPath)
|
||||
@@ -315,26 +329,6 @@ void Unit::popActivePathFront()
|
||||
setActivePath(path);
|
||||
}
|
||||
|
||||
void Unit::setCoalitionID(unsigned int newCoalitionID)
|
||||
{
|
||||
if (newCoalitionID == 0)
|
||||
coalition = "neutral";
|
||||
else if (newCoalitionID == 1)
|
||||
coalition = "red";
|
||||
else
|
||||
coalition = "blue";
|
||||
}
|
||||
|
||||
unsigned int Unit::getCoalitionID()
|
||||
{
|
||||
if (coalition == "neutral")
|
||||
return 0;
|
||||
else if (coalition == "red")
|
||||
return 1;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
string Unit::getTargetName()
|
||||
{
|
||||
if (isTargetAlive())
|
||||
@@ -398,6 +392,8 @@ void Unit::setFormationOffset(Offset newFormationOffset)
|
||||
{
|
||||
formationOffset = newFormationOffset;
|
||||
resetTask();
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
void Unit::setROE(unsigned char newROE, bool force)
|
||||
@@ -406,6 +402,8 @@ void Unit::setROE(unsigned char newROE, bool force)
|
||||
ROE = newROE;
|
||||
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ROE, static_cast<unsigned int>(ROE)));
|
||||
scheduler->appendCommand(command);
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,6 +414,8 @@ void Unit::setReactionToThreat(unsigned char newReactionToThreat, bool force)
|
||||
|
||||
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::REACTION_ON_THREAT, static_cast<unsigned int>(reactionToThreat)));
|
||||
scheduler->appendCommand(command);
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,6 +464,8 @@ void Unit::setEmissionsCountermeasures(unsigned char newEmissionsCountermeasures
|
||||
|
||||
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ECM_USING, ECMEnum));
|
||||
scheduler->appendCommand(command);
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,15 +478,23 @@ void Unit::landAt(Coords loc)
|
||||
|
||||
void Unit::setIsTanker(bool newIsTanker)
|
||||
{
|
||||
isTanker = newIsTanker;
|
||||
resetTask();
|
||||
if (isTanker != newIsTanker) {
|
||||
isTanker = newIsTanker;
|
||||
resetTask();
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::setIsAWACS(bool newIsAWACS)
|
||||
{
|
||||
isAWACS = newIsAWACS;
|
||||
resetTask();
|
||||
setEPLRS(isAWACS);
|
||||
if (isAWACS != newIsAWACS) {
|
||||
isAWACS = newIsAWACS;
|
||||
resetTask();
|
||||
setEPLRS(isAWACS);
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::setTACAN(Options::TACAN newTACAN, bool force)
|
||||
@@ -517,6 +527,8 @@ void Unit::setTACAN(Options::TACAN newTACAN, bool force)
|
||||
Command* command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,6 +563,8 @@ void Unit::setRadio(Options::Radio newRadio, bool force)
|
||||
<< "}";
|
||||
command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
|
||||
scheduler->appendCommand(command);
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,6 +604,8 @@ void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings, bool
|
||||
scheduler->appendCommand(command);
|
||||
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ENGAGE_AIR_WEAPONS, !generalSettings.prohibitAirWpn));
|
||||
scheduler->appendCommand(command);
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,6 +616,8 @@ void Unit::setDesiredSpeed(double newDesiredSpeed)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
void Unit::setDesiredAltitude(double newDesiredAltitude)
|
||||
@@ -609,6 +627,8 @@ void Unit::setDesiredAltitude(double newDesiredAltitude)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
void Unit::setDesiredSpeedType(string newDesiredSpeedType)
|
||||
@@ -618,6 +638,8 @@ void Unit::setDesiredSpeedType(string newDesiredSpeedType)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
void Unit::setDesiredAltitudeType(string newDesiredAltitudeType)
|
||||
@@ -627,6 +649,8 @@ void Unit::setDesiredAltitudeType(string newDesiredAltitudeType)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
triggerUpdate();
|
||||
}
|
||||
|
||||
void Unit::goToDestination(string enrouteTask)
|
||||
@@ -669,12 +693,16 @@ bool Unit::setActiveDestination()
|
||||
{
|
||||
activeDestination = activePath.front();
|
||||
log(unitName + " active destination set to queue front");
|
||||
|
||||
triggerUpdate();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
activeDestination = Coords(0);
|
||||
log(unitName + " active destination set to NULL");
|
||||
|
||||
triggerUpdate();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -695,11 +723,6 @@ bool Unit::updateActivePath(bool looping)
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::setTargetPosition(Coords newTargetPosition)
|
||||
{
|
||||
targetPosition = newTargetPosition;
|
||||
}
|
||||
|
||||
bool Unit::checkTaskFailed()
|
||||
{
|
||||
if (getHasTask())
|
||||
@@ -714,8 +737,3 @@ bool Unit::checkTaskFailed()
|
||||
void Unit::resetTaskFailedCounter() {
|
||||
taskCheckCounter = TASK_CHECK_INIT_VALUE;
|
||||
}
|
||||
|
||||
void Unit::setHasTask(bool newHasTask)
|
||||
{
|
||||
hasTask = newHasTask;
|
||||
}
|
||||
@@ -154,11 +154,10 @@ void UnitsManager::runAILoop() {
|
||||
unit.second->runAILoop();
|
||||
}
|
||||
|
||||
string UnitsManager::getUnitData(bool refresh)
|
||||
string UnitsManager::getUnitData(stringstream &ss, unsigned long long time, bool refresh)
|
||||
{
|
||||
stringstream ss;
|
||||
for (auto const& p : units)
|
||||
p.second->getData(ss, refresh);
|
||||
p.second->getData(ss, time, refresh);
|
||||
return to_base64(ss.str());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "framework.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Coords {
|
||||
double lat = 0;
|
||||
double lng = 0;
|
||||
@@ -12,6 +13,7 @@ struct Offset {
|
||||
double y = 0;
|
||||
double z = 0;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
|
||||
const DllExport std::string CurrentDateTime();
|
||||
|
||||
Reference in New Issue
Block a user