DCSOlympus/client/src/units/dataextractor.ts

219 lines
7.2 KiB
TypeScript

import { LatLng } from "leaflet";
import { UnitData } from "../@types/unit";
import { ROEs, emissionsCountermeasures, reactionsToThreat, states } from "../constants/constants";
export class DataExtractor {
#offset = 0;
#dataview: DataView;
#decoder: TextDecoder;
#buffer: ArrayBuffer;
constructor(buffer: ArrayBuffer) {
this.#buffer = buffer;
this.#dataview = new DataView(this.#buffer);
this.#decoder = new TextDecoder("utf-8");
}
extractData(offset: number) {
this.#offset = offset;
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),
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),
},
position: new LatLng(
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,
targetPosition: new LatLng(
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()),
TACAN: {
isOn: this.#extractBool(),
channel: this.#extractUint8(),
XY: this.#extractChar(),
callsign: this.#extractString(4)
},
radio: {
frequency: this.#extractUInt32(),
callsign: this.#extractUint8(),
callsignNumber: this.#extractUint8()
},
activePath: [],
ammo: [],
contacts: [],
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();
if (pathLength > 0) {
unitData.activePath = [];
for (let idx = 0; idx < pathLength; idx++) {
unitData.activePath.push(new LatLng(this.#extractFloat64(), this.#extractFloat64(), this.#extractFloat64()));
}
}
if (ammoLength > 0) {
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()
});
}
}
if (contactsLength > 0) {
unitData.contacts = [];
for (let idx = 0; idx < pathLength; idx++) {
unitData.contacts.push({
ID: this.#extractUInt32(),
detectionMethod: this.#extractUint8()
});
}
}
if (nameLength > 0) {
unitData.name = this.#extractString(nameLength);
}
if (unitNameLength > 0) {
unitData.unitName = this.#extractString(unitNameLength);
}
if (groupNameLength > 0) {
unitData.groupName = this.#extractString(groupNameLength);
}
if (categoryLength > 0) {
unitData.category = this.#extractString(categoryLength);
}
if (coalitionLength > 0) {
unitData.coalition = this.#extractString(coalitionLength);
}
return {data: unitData, offset: this.#offset};
}
#extractBool() {
const value = this.#dataview.getUint8(this.#offset);
this.#offset += 1;
return value > 0;
}
#extractUint8() {
const value = this.#dataview.getUint8(this.#offset);
this.#offset += 1;
return value;
}
#extractUInt16() {
const value = this.#dataview.getUint16(this.#offset);
this.#offset += 2;
return value;
}
#extractUInt32() {
const value = this.#dataview.getUint32(this.#offset);
this.#offset += 4;
return value;
}
#extractFloat64() {
const value = this.#dataview.getFloat64(this.#offset);
this.#offset += 8;
return value;
}
#extractFromBitmask(bitmask: number, position: number) {
return (bitmask >> position & 1) > 0;
}
#extractString(length: number) {
const value = this.#decoder.decode(this.#buffer.slice(this.#offset, length));
this.#offset += length;
return value;
}
#extractChar() {
return this.#extractString(1);
}
#getState(state: number) {
if (state < states.length)
return states[state];
else
return states[0];
}
#getROE(ROE: number) {
if (ROE < ROEs.length)
return ROEs[ROE];
else
return ROEs[0];
}
#getReactionToThreat(reactionToThreat: number) {
if (reactionToThreat < reactionsToThreat.length)
return reactionsToThreat[reactionToThreat];
else
return reactionsToThreat[0];
}
#getEmissionCountermeasure(emissionCountermeasure: number) {
if (emissionCountermeasure < emissionsCountermeasures.length)
return emissionsCountermeasures[emissionCountermeasure];
else
return emissionsCountermeasures[0];
}
}