Fixed update error and added update trigger

This commit is contained in:
Pax1601
2023-06-25 19:04:12 +02:00
parent dd2e858db4
commit 1989219579
18 changed files with 385 additions and 318 deletions

View File

@@ -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,

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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 "";
}
}

View File

@@ -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);
}

View File

@@ -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) {