mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Add cargo weight and draw argument support
Introduces cargo weight and draw argument properties to units across backend, frontend, and Python API. Adds related commands, data extraction, and registration logic, enabling setting and reading of cargo weight and custom draw arguments for units. Includes new API examples and updates to interfaces, data types, and Lua backend for full feature integration.
This commit is contained in:
parent
73a7ea74f3
commit
3eef91fb24
@ -22,6 +22,8 @@ public:
|
||||
virtual void setRacetrackLength(double newValue);
|
||||
virtual void setRacetrackAnchor(Coords newValue);
|
||||
virtual void setRacetrackBearing(double newValue);
|
||||
|
||||
virtual void setCargoWeight(double newValue);
|
||||
|
||||
protected:
|
||||
virtual void AIloop();
|
||||
|
||||
@ -538,4 +538,44 @@ public:
|
||||
private:
|
||||
const unsigned int spotID;
|
||||
const Coords destination;
|
||||
};
|
||||
|
||||
/* Set cargo weight */
|
||||
class SetCargoWeight : public Command
|
||||
{
|
||||
public:
|
||||
SetCargoWeight(unsigned int ID, double weight, function<void(void)> callback = []() {}) :
|
||||
Command(callback),
|
||||
ID(ID),
|
||||
weight(weight)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const unsigned int ID;
|
||||
const double weight;
|
||||
};
|
||||
|
||||
/* Register draw argument */
|
||||
class RegisterDrawArgument : public Command
|
||||
{
|
||||
public:
|
||||
RegisterDrawArgument(unsigned int ID, unsigned int argument, bool active, function<void(void)> callback = []() {}) :
|
||||
Command(callback),
|
||||
ID(ID),
|
||||
argument(argument),
|
||||
active(active)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const unsigned int ID;
|
||||
const unsigned int argument;
|
||||
const bool active;
|
||||
};
|
||||
@ -70,6 +70,8 @@ namespace DataIndex {
|
||||
aimMethodRange,
|
||||
acquisitionRange,
|
||||
airborne,
|
||||
cargoWeight,
|
||||
drawArguments,
|
||||
lastIndex,
|
||||
endOfData = 255
|
||||
};
|
||||
@ -159,6 +161,11 @@ namespace DataTypes {
|
||||
unsigned int ID = 0;
|
||||
unsigned char detectionMethod = 0;
|
||||
};
|
||||
|
||||
struct DrawArgument {
|
||||
unsigned int argument = 0;
|
||||
double value = 0.0;
|
||||
};
|
||||
}
|
||||
#pragma pack(pop)
|
||||
|
||||
@ -167,6 +174,7 @@ bool operator==(const DataTypes::Radio& lhs, const DataTypes::Radio& rhs);
|
||||
bool operator==(const DataTypes::GeneralSettings& lhs, const DataTypes::GeneralSettings& rhs);
|
||||
bool operator==(const DataTypes::Ammo& lhs, const DataTypes::Ammo& rhs);
|
||||
bool operator==(const DataTypes::Contact& lhs, const DataTypes::Contact& rhs);
|
||||
bool operator==(const DataTypes::DrawArgument& lhs, const DataTypes::DrawArgument& rhs);
|
||||
|
||||
struct SpawnOptions {
|
||||
string unitType;
|
||||
|
||||
@ -19,6 +19,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void setFrameRate(double newFrameRate) { frameRate = newFrameRate; }
|
||||
|
||||
@ -130,9 +130,11 @@ public:
|
||||
virtual void setAcquisitionRange(double newValue) { updateValue(acquisitionRange, newValue, DataIndex::acquisitionRange); }
|
||||
virtual void setRadarState(bool newValue) { updateValue(radarState, newValue, DataIndex::radarState); }
|
||||
virtual void setAirborne(bool newValue) { updateValue(airborne, newValue, DataIndex::airborne); }
|
||||
virtual void setCargoWeight(double newValue) { updateValue(cargoWeight, newValue, DataIndex::cargoWeight); }
|
||||
virtual void setDrawArguments(vector<DataTypes::DrawArgument> newValue);
|
||||
|
||||
/********** Getters **********/
|
||||
virtual string getCategory() { return category; };
|
||||
virtual string getCategory() { return category; }
|
||||
virtual bool getAlive() { return alive; }
|
||||
virtual unsigned char getAlarmState() { return alarmState; }
|
||||
virtual bool getHuman() { return human; }
|
||||
@ -197,6 +199,8 @@ public:
|
||||
virtual double getAcquisitionRange() { return acquisitionRange; }
|
||||
virtual bool getRadarState() { return radarState; }
|
||||
virtual bool getAirborne() { return airborne; }
|
||||
virtual double getCargoWeight() { return cargoWeight; }
|
||||
virtual vector<DataTypes::DrawArgument> getDrawArguments() { return drawArguments; }
|
||||
|
||||
protected:
|
||||
unsigned int ID;
|
||||
@ -267,6 +271,8 @@ protected:
|
||||
double aimMethodRange = 0;
|
||||
double acquisitionRange = 0;
|
||||
bool airborne = false;
|
||||
double cargoWeight = 0;
|
||||
vector<DataTypes::DrawArgument> drawArguments;
|
||||
|
||||
/********** Other **********/
|
||||
unsigned int taskCheckCounter = 0;
|
||||
|
||||
@ -428,4 +428,14 @@ void AirUnit::setRacetrackBearing(double newRacetrackBearing) {
|
||||
|
||||
triggerUpdate(DataIndex::racetrackBearing);
|
||||
}
|
||||
}
|
||||
|
||||
void AirUnit::setCargoWeight(double newCargoWeight) {
|
||||
if (cargoWeight != newCargoWeight) {
|
||||
cargoWeight = newCargoWeight;
|
||||
triggerUpdate(DataIndex::cargoWeight);
|
||||
|
||||
Command* command = dynamic_cast<Command*>(new SetCargoWeight(this->ID, cargoWeight));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
}
|
||||
@ -318,4 +318,27 @@ string DeleteSpot::getString()
|
||||
commandSS << "Olympus.deleteSpot, "
|
||||
<< spotID;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* SetCargoWeight command */
|
||||
string SetCargoWeight::getString()
|
||||
{
|
||||
std::ostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.setCargoWeight, "
|
||||
<< ID << ", "
|
||||
<< weight;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* RegisterDrawArgument command */
|
||||
string RegisterDrawArgument::getString()
|
||||
{
|
||||
std::ostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.registerDrawArgument, "
|
||||
<< ID << ", "
|
||||
<< argument << ", "
|
||||
<< active;
|
||||
return commandSS.str();
|
||||
}
|
||||
@ -12,19 +12,24 @@ bool operator==(const DataTypes::Radio& lhs, const DataTypes::Radio& rhs)
|
||||
|
||||
bool operator==(const DataTypes::GeneralSettings& lhs, const DataTypes::GeneralSettings& rhs)
|
||||
{
|
||||
return lhs.prohibitAA == rhs.prohibitAA && lhs.prohibitAfterburner == rhs.prohibitAfterburner && lhs.prohibitAG == rhs.prohibitAG &&
|
||||
return lhs.prohibitAA == rhs.prohibitAA && lhs.prohibitAfterburner == rhs.prohibitAfterburner && lhs.prohibitAG == rhs.prohibitAG &&
|
||||
lhs.prohibitAirWpn == rhs.prohibitAirWpn && lhs.prohibitJettison == rhs.prohibitJettison;
|
||||
}
|
||||
|
||||
bool operator==(const DataTypes::Ammo& lhs, const DataTypes::Ammo& rhs)
|
||||
{
|
||||
return lhs.category == rhs.category && lhs.guidance == rhs.guidance && lhs.missileCategory == rhs.missileCategory &&
|
||||
return lhs.category == rhs.category && lhs.guidance == rhs.guidance && lhs.missileCategory == rhs.missileCategory &&
|
||||
lhs.quantity == rhs.quantity && strcmp(lhs.name, rhs.name) == 0;
|
||||
}
|
||||
|
||||
bool operator==(const DataTypes::DrawArgument& lhs, const DataTypes::DrawArgument& rhs)
|
||||
{
|
||||
return lhs.argument == rhs.argument && lhs.value == rhs.value;
|
||||
}
|
||||
|
||||
bool operator==(const DataTypes::Contact& lhs, const DataTypes::Contact& rhs)
|
||||
{
|
||||
return lhs.detectionMethod == rhs.detectionMethod && lhs.ID == rhs.ID;
|
||||
return lhs.detectionMethod == rhs.detectionMethod && lhs.ID == rhs.ID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -827,6 +827,31 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
unitsManager->loadDatabases();
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setCargoWeight") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr) {
|
||||
double weight = value[L"weight"].as_double();
|
||||
unit->setCargoWeight(weight);
|
||||
log(username + " set weight to unit " + unit->getUnitName() + "(" + unit->getName() + "), " + to_string(weight), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("registerDrawArgument") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr) {
|
||||
int argument = value[L"argument"].as_integer();
|
||||
bool active = value[L"active"].as_bool();
|
||||
|
||||
command = dynamic_cast<Command*>(new RegisterDrawArgument(ID, argument, active));
|
||||
|
||||
log(username + " registered draw argument " + to_string(argument) + " for unit " + unit->getUnitName() + "(" + unit->getName() + "), value:" + to_string(active), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else
|
||||
{
|
||||
log("Unknown command: " + key);
|
||||
|
||||
@ -128,6 +128,20 @@ void Unit::update(json::value json, double dt)
|
||||
setAmmo(ammo);
|
||||
}
|
||||
|
||||
if (json.has_object_field(L"drawArguments")) {
|
||||
vector<DataTypes::DrawArgument> drawArguments;
|
||||
for (auto const& el : json[L"drawArguments"].as_object()) {
|
||||
DataTypes::DrawArgument drawArgumentItem;
|
||||
auto drawArgumentJson = el.second;
|
||||
if (drawArgumentJson.has_number_field(L"argument"))
|
||||
drawArgumentItem.argument = drawArgumentJson[L"argument"].as_number().to_uint32();
|
||||
if (drawArgumentJson.has_number_field(L"value"))
|
||||
drawArgumentItem.value = drawArgumentJson[L"value"].as_number().to_double();
|
||||
drawArguments.push_back(drawArgumentItem);
|
||||
}
|
||||
setDrawArguments(drawArguments);
|
||||
}
|
||||
|
||||
if (json.has_object_field(L"contacts")) {
|
||||
vector<DataTypes::Contact> contacts;
|
||||
for (auto const& el : json[L"contacts"].as_object()) {
|
||||
@ -328,6 +342,8 @@ void Unit::getData(stringstream& ss, unsigned long long time)
|
||||
case DataIndex::aimMethodRange: appendNumeric(ss, datumIndex, aimMethodRange); break;
|
||||
case DataIndex::acquisitionRange: appendNumeric(ss, datumIndex, acquisitionRange); break;
|
||||
case DataIndex::airborne: appendNumeric(ss, datumIndex, airborne); break;
|
||||
case DataIndex::cargoWeight: appendNumeric(ss, datumIndex, cargoWeight); break;
|
||||
case DataIndex::drawArguments: appendVector(ss, datumIndex, drawArguments); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -699,6 +715,24 @@ void Unit::setGeneralSettings(DataTypes::GeneralSettings newGeneralSettings, boo
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::setDrawArguments(vector<DataTypes::DrawArgument> newDrawArguments)
|
||||
{
|
||||
if (drawArguments.size() == newDrawArguments.size()) {
|
||||
bool equal = true;
|
||||
for (int i = 0; i < drawArguments.size(); i++) {
|
||||
if (drawArguments.at(i) != newDrawArguments.at(i))
|
||||
{
|
||||
equal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (equal)
|
||||
return;
|
||||
}
|
||||
drawArguments = newDrawArguments;
|
||||
triggerUpdate(DataIndex::drawArguments);
|
||||
}
|
||||
|
||||
void Unit::setDesiredSpeed(double newDesiredSpeed)
|
||||
{
|
||||
if (desiredSpeed != newDesiredSpeed) {
|
||||
|
||||
@ -66,7 +66,7 @@ std::string random_string(size_t length)
|
||||
|
||||
bool operator== (const Coords& a, const Coords& b) { return a.lat == b.lat && a.lng == b.lng && a.alt == b.alt && a.threshold == b.threshold; }
|
||||
bool operator!= (const Coords& a, const Coords& b) { return !(a == b); }
|
||||
bool operator== (const Coords& a, const double& b) { return a.lat == b && a.lng == b && a.alt == b && a.threshold == b }
|
||||
bool operator== (const Coords& a, const double& b) { return a.lat == b && a.lng == b && a.alt == b && a.threshold == b; }
|
||||
bool operator!= (const Coords& a, const double& b) { return !(a == b); }
|
||||
|
||||
bool operator== (const Offset& a, const Offset& b) { return a.x == b.x && a.y == b.y && a.z == b.z; }
|
||||
|
||||
6
frontend/react/.vscode/tasks.json
vendored
6
frontend/react/.vscode/tasks.json
vendored
@ -1,12 +1,6 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "check-setup",
|
||||
"type": "shell",
|
||||
"command": "cd .. ; ./check_setup.bat",
|
||||
"isBackground": false
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "dev",
|
||||
|
||||
@ -547,6 +547,8 @@ export enum DataIndexes {
|
||||
aimMethodRange,
|
||||
acquisitionRange,
|
||||
airborne,
|
||||
cargoWeight,
|
||||
drawingArguments,
|
||||
endOfData = 255,
|
||||
}
|
||||
|
||||
|
||||
@ -219,6 +219,11 @@ export interface Offset {
|
||||
z: number;
|
||||
}
|
||||
|
||||
export interface DrawingArgument {
|
||||
argument: number;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface UnitData {
|
||||
category: string;
|
||||
markerCategory: string;
|
||||
@ -286,6 +291,8 @@ export interface UnitData {
|
||||
aimMethodRange: number;
|
||||
acquisitionRange: number;
|
||||
airborne: boolean;
|
||||
cargoWeight: number;
|
||||
drawingArguments: DrawingArgument[];
|
||||
}
|
||||
|
||||
export interface LoadoutItemBlueprint {
|
||||
|
||||
18
frontend/react/src/map/latlng.ts
Normal file
18
frontend/react/src/map/latlng.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import * as L from "leaflet";
|
||||
|
||||
export class LatLng extends L.LatLng {
|
||||
threshold: number;
|
||||
|
||||
constructor(lat: number, lng: number, alt: number, threshold: number) {
|
||||
super(lat, lng, alt);
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
setThreshold(threshold: number) {
|
||||
this.threshold = threshold;
|
||||
}
|
||||
|
||||
getThreshold() {
|
||||
return this.threshold;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import { LatLng } from "leaflet";
|
||||
import { Ammo, Contact, GeneralSettings, Offset, Radio, TACAN } from "../interfaces";
|
||||
import { Ammo, Contact, DrawingArgument, GeneralSettings, Offset, Radio, TACAN } from "../interfaces";
|
||||
|
||||
export class DataExtractor {
|
||||
#seekPosition = 0;
|
||||
@ -58,7 +58,9 @@ export class DataExtractor {
|
||||
}
|
||||
|
||||
extractLatLng() {
|
||||
return new LatLng(this.extractFloat64(), this.extractFloat64(), this.extractFloat64());
|
||||
let latlng = new LatLng(this.extractFloat64(), this.extractFloat64(), this.extractFloat64());
|
||||
let threshold = this.extractFloat64();
|
||||
return latlng;
|
||||
}
|
||||
|
||||
extractFromBitmask(bitmask: number, position: number) {
|
||||
@ -104,6 +106,14 @@ export class DataExtractor {
|
||||
return value;
|
||||
}
|
||||
|
||||
extractDrawingArgument() {
|
||||
const value: DrawingArgument = {
|
||||
argument: this.extractUInt32(),
|
||||
value: this.extractFloat64(),
|
||||
};
|
||||
return value;
|
||||
}
|
||||
|
||||
extractGeneralSettings() {
|
||||
const value: GeneralSettings = {
|
||||
prohibitJettison: this.extractBool(),
|
||||
@ -159,4 +169,13 @@ export class DataExtractor {
|
||||
};
|
||||
return value;
|
||||
}
|
||||
|
||||
extractDrawingArguments() {
|
||||
const value: DrawingArgument[] = [];
|
||||
const size = this.extractUInt16();
|
||||
for (let idx = 0; idx < size; idx++) {
|
||||
value.push(this.extractDrawingArgument());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker, Map, Point, LeafletMouseEvent, DomEvent, DomUtil, Circle } from "leaflet";
|
||||
import { LatLng, Polyline, DivIcon, CircleMarker, Map, Point, DomEvent } from "leaflet";
|
||||
import { getApp } from "../olympusapp";
|
||||
import {
|
||||
enumToCoalition,
|
||||
@ -54,7 +54,7 @@ import {
|
||||
} from "../constants/constants";
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { Weapon } from "../weapon/weapon";
|
||||
import { AlarmState, Ammo, Contact, GeneralSettings, LoadoutBlueprint, ObjectIconOptions, Offset, Radio, TACAN, UnitBlueprint, UnitData } from "../interfaces";
|
||||
import { AlarmState, Ammo, Contact, DrawingArgument, GeneralSettings, LoadoutBlueprint, ObjectIconOptions, Offset, Radio, TACAN, UnitBlueprint, UnitData } from "../interfaces";
|
||||
import { RangeCircle } from "../map/rangecircle";
|
||||
import { Group } from "./group";
|
||||
import { ContextActionSet } from "./contextactionset";
|
||||
@ -159,6 +159,8 @@ export abstract class Unit extends CustomMarker {
|
||||
#racetrackAnchor: LatLng = new LatLng(0, 0);
|
||||
#racetrackBearing: number = 0;
|
||||
#airborne: boolean = false;
|
||||
#cargoWeight: number = 0;
|
||||
#drawingArguments: DrawingArgument[] = [];
|
||||
|
||||
/* Other members used to draw the unit, mostly ancillary stuff like targets, ranges and so on */
|
||||
#blueprint: UnitBlueprint | null = null;
|
||||
@ -406,6 +408,12 @@ export abstract class Unit extends CustomMarker {
|
||||
getAirborne() {
|
||||
return this.#airborne;
|
||||
}
|
||||
getCargoWeight() {
|
||||
return this.#cargoWeight;
|
||||
}
|
||||
getDrawingArguments() {
|
||||
return this.#drawingArguments;
|
||||
}
|
||||
|
||||
static getConstructor(type: string) {
|
||||
if (type === "GroundUnit") return GroundUnit;
|
||||
@ -797,6 +805,12 @@ export abstract class Unit extends CustomMarker {
|
||||
case DataIndexes.airborne:
|
||||
this.#airborne = dataExtractor.extractBool();
|
||||
break;
|
||||
case DataIndexes.cargoWeight:
|
||||
this.#cargoWeight = dataExtractor.extractFloat64();
|
||||
break;
|
||||
case DataIndexes.drawingArguments:
|
||||
this.#drawingArguments = dataExtractor.extractDrawingArguments();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -920,6 +934,8 @@ export abstract class Unit extends CustomMarker {
|
||||
aimMethodRange: this.#aimMethodRange,
|
||||
acquisitionRange: this.#acquisitionRange,
|
||||
airborne: this.#airborne,
|
||||
cargoWeight: this.#cargoWeight,
|
||||
drawingArguments: this.#drawingArguments,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@ Olympus.unitIndex = 0 -- Counter used to spread the computational load of data
|
||||
Olympus.unitStep = 50 -- Max number of units that get updated each cycle
|
||||
Olympus.units = {} -- Table holding references to all the currently existing units
|
||||
Olympus.unitsInitialLife = {} -- getLife0 returns 0 for ships, so we need to store the initial life of units
|
||||
Olympus.drawArguments = {} -- Table that sets what drawArguments to read for each unit
|
||||
|
||||
Olympus.weaponIndex = 0 -- Counter used to spread the computational load of data retrievial from DCS
|
||||
Olympus.weaponStep = 50 -- Max number of weapons that get updated each cycle
|
||||
@ -1087,10 +1088,38 @@ function Olympus.setOnOff(groupName, onOff)
|
||||
end
|
||||
end
|
||||
|
||||
-- Get the unit description
|
||||
function getUnitDescription(unit)
|
||||
return unit:getDescr()
|
||||
end
|
||||
|
||||
-- Set the unit cargo weight
|
||||
function Olympus.setCargoWeight(ID, weight)
|
||||
Olympus.debug("Olympus.setCargoWeight " .. ID .. " " .. tostring(weight), 2)
|
||||
|
||||
local unit = Olympus.getUnitByID(ID)
|
||||
if unit ~= nil and unit:isExist() then
|
||||
trigger.action.setUnitInternalCargo(unit:getName(), weight)
|
||||
end
|
||||
end
|
||||
|
||||
-- Register a drawArgument to be read for a unit
|
||||
function Olympus.registerDrawArgument(ID, argument, active)
|
||||
Olympus.debug("Olympus.registerDrawArgument " .. ID .. " " .. tostring(argument) .. " " .. tostring(active), 2)
|
||||
|
||||
-- Create the table if it does not exist
|
||||
if Olympus.drawArguments[ID] == nil then
|
||||
Olympus.drawArguments[ID] = {}
|
||||
end
|
||||
|
||||
-- Set the draw argument to true or false
|
||||
if active then
|
||||
Olympus.drawArguments[ID][argument] = true
|
||||
else
|
||||
Olympus.drawArguments[ID][argument] = false
|
||||
end
|
||||
end
|
||||
|
||||
-- This function gets the navpoints from the DCS mission
|
||||
function Olympus.getNavPoints()
|
||||
local function extract_tag(str)
|
||||
@ -1293,6 +1322,20 @@ function Olympus.setUnitsData(arg, time)
|
||||
table["radarState"] = false
|
||||
end
|
||||
end ]]
|
||||
|
||||
-- Read the draw arguments
|
||||
local drawArguments = {}
|
||||
if Olympus.drawArguments[ID] ~= nil then
|
||||
for argument, active in pairs(Olympus.drawArguments[ID]) do
|
||||
if active then
|
||||
drawArguments[#drawArguments + 1] = {
|
||||
argument = argument,
|
||||
value = unit:getDrawArgumentValue(argument)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
table["drawArguments"] = drawArguments
|
||||
|
||||
local group = unit:getGroup()
|
||||
if group ~= nil then
|
||||
|
||||
24
scripts/python/API/.vscode/launch.json
vendored
24
scripts/python/API/.vscode/launch.json
vendored
@ -27,6 +27,30 @@
|
||||
"program": "example_disembarked_infantry.py",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": false,
|
||||
},
|
||||
{
|
||||
"name": "Example set cargo weight",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "example_set_cargo_weight.py",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": false,
|
||||
},
|
||||
{
|
||||
"name": "Example draw argument",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "example_draw_argument.py",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": false,
|
||||
},
|
||||
{
|
||||
"name": "Example precise movement",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "example_precise_movement.py",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": false,
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import struct
|
||||
from typing import List
|
||||
from data.data_types import LatLng, TACAN, Radio, GeneralSettings, Ammo, Contact, Offset
|
||||
from data.data_types import DrawArgument, LatLng, TACAN, Radio, GeneralSettings, Ammo, Contact, Offset
|
||||
|
||||
class DataExtractor:
|
||||
def __init__(self, buffer: bytes):
|
||||
@ -48,6 +48,7 @@ class DataExtractor:
|
||||
lat = self.extract_float64()
|
||||
lng = self.extract_float64()
|
||||
alt = self.extract_float64()
|
||||
threshold = self.extract_float64()
|
||||
return LatLng(lat, lng, alt)
|
||||
|
||||
def extract_from_bitmask(self, bitmask: int, position: int) -> bool:
|
||||
@ -136,4 +137,14 @@ class DataExtractor:
|
||||
x=self.extract_float64(),
|
||||
y=self.extract_float64(),
|
||||
z=self.extract_float64()
|
||||
)
|
||||
)
|
||||
|
||||
def extract_draw_arguments(self) -> List[DrawArgument]:
|
||||
value = []
|
||||
size = self.extract_uint16()
|
||||
for _ in range(size):
|
||||
value.append(DrawArgument(
|
||||
argument=self.extract_uint32(),
|
||||
value=self.extract_float64()
|
||||
))
|
||||
return value
|
||||
@ -67,4 +67,6 @@ class DataIndexes(Enum):
|
||||
AIM_METHOD_RANGE = 63
|
||||
ACQUISITION_RANGE = 64
|
||||
AIRBORNE = 65
|
||||
CARGO_WEIGHT = 66
|
||||
DRAW_ARGUMENTS = 67
|
||||
END_OF_DATA = 255
|
||||
@ -8,13 +8,15 @@ class LatLng:
|
||||
lat: float
|
||||
lng: float
|
||||
alt: float
|
||||
|
||||
threshold: Optional[float] = 0 # Optional threshold for proximity checks
|
||||
|
||||
def toJSON(self):
|
||||
"""Convert LatLng to a JSON serializable dictionary."""
|
||||
return {
|
||||
"lat": self.lat,
|
||||
"lng": self.lng,
|
||||
"alt": self.alt
|
||||
"alt": self.alt,
|
||||
"threshold": self.threshold
|
||||
}
|
||||
|
||||
def project_with_bearing_and_distance(self, d, bearing):
|
||||
@ -88,4 +90,9 @@ class Contact:
|
||||
class Offset:
|
||||
x: float
|
||||
y: float
|
||||
z: float
|
||||
z: float
|
||||
|
||||
@dataclass
|
||||
class DrawArgument:
|
||||
argument: int
|
||||
value: float
|
||||
31
scripts/python/API/example_draw_argument.py
Normal file
31
scripts/python/API/example_draw_argument.py
Normal file
@ -0,0 +1,31 @@
|
||||
from api import API
|
||||
|
||||
def on_api_startup(api: API):
|
||||
units = api.update_units()
|
||||
for unit in units.values():
|
||||
if unit.name == "UH-1H":
|
||||
# Register draw argument 43 for UH-1H
|
||||
unit.register_draw_argument(43)
|
||||
|
||||
def on_api_update(api: API):
|
||||
units = api.get_units()
|
||||
for unit in units.values():
|
||||
if unit.name == "UH-1H":
|
||||
print(f"Draw Arguments for {unit.name}:")
|
||||
for draw_arg in unit.draw_arguments:
|
||||
print(f" Argument: {draw_arg.argument}, Value: {draw_arg.value}")
|
||||
|
||||
##############################################################################################
|
||||
# Main entry point for the script. It registers the callbacks and starts the API.
|
||||
##############################################################################################
|
||||
if __name__ == "__main__":
|
||||
# Initialize the API
|
||||
api = API()
|
||||
|
||||
# Register the callbacks
|
||||
api.register_on_update_callback(on_api_update)
|
||||
api.register_on_startup_callback(on_api_startup)
|
||||
|
||||
# Start the API, this will run forever until stopped
|
||||
api.run()
|
||||
|
||||
@ -1,5 +1,13 @@
|
||||
from api import API
|
||||
from kronos.kronos import Kronos
|
||||
|
||||
def on_api_startup(api: API):
|
||||
units = api.update_units()
|
||||
for unit in units.values():
|
||||
if unit.name == "Infantry AK Ins":
|
||||
current_pos = unit.position
|
||||
next_pos = current_pos.project_with_bearing_and_distance(20, 0) # Move 20 meters north
|
||||
next_pos.threshold = 2 # Set threshold to 1 meter, very precise
|
||||
unit.set_path([next_pos])
|
||||
|
||||
##############################################################################################
|
||||
# Main entry point for the script. It registers the callbacks and starts the API.
|
||||
@ -8,13 +16,9 @@ if __name__ == "__main__":
|
||||
# Initialize the API
|
||||
api = API()
|
||||
|
||||
# Initialize Kronos with the API
|
||||
kronos = Kronos(api)
|
||||
|
||||
# Register the callbacks
|
||||
api.register_on_startup_callback(kronos.on_startup)
|
||||
api.register_on_startup_callback(on_api_startup)
|
||||
|
||||
# Start the API, this will run forever until stopped
|
||||
api.run()
|
||||
|
||||
|
||||
29
scripts/python/API/example_set_cargo_weight.py
Normal file
29
scripts/python/API/example_set_cargo_weight.py
Normal file
@ -0,0 +1,29 @@
|
||||
from api import API
|
||||
|
||||
def on_api_startup(api: API):
|
||||
units = api.update_units()
|
||||
for unit in units.values():
|
||||
if unit.name == "UH-1H":
|
||||
# Set cargo weight to 5000 kg
|
||||
unit.set_cargo_weight(5000.0)
|
||||
|
||||
def on_api_update(api: API):
|
||||
units = api.get_units()
|
||||
for unit in units.values():
|
||||
if unit.name == "UH-1H":
|
||||
print(f"Cargo Weight for {unit.name}: {unit.cargo_weight} kg")
|
||||
|
||||
##############################################################################################
|
||||
# Main entry point for the script. It registers the callbacks and starts the API.
|
||||
##############################################################################################
|
||||
if __name__ == "__main__":
|
||||
# Initialize the API
|
||||
api = API()
|
||||
|
||||
# Register the callbacks
|
||||
api.register_on_update_callback(on_api_update)
|
||||
api.register_on_startup_callback(on_api_startup)
|
||||
|
||||
# Start the API, this will run forever until stopped
|
||||
api.run()
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
# Setup a logger for the module
|
||||
import logging
|
||||
logger = logging.getLogger("Kronos")
|
||||
logger.setLevel(logging.INFO)
|
||||
handler = logging.StreamHandler()
|
||||
formatter = logging.Formatter('[%(asctime)s] %(name)s - %(levelname)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
logger.addHandler(handler)
|
||||
|
||||
class Kronos():
|
||||
def __init__(self, api):
|
||||
self.api = api
|
||||
|
||||
def on_startup(self):
|
||||
logger.info("Kronos API started")
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"port": 4512
|
||||
},
|
||||
"authentication": {
|
||||
"gameMasterPassword": "a474219e5e9503c84d59500bb1bda3d9ade81e52d9fa1c234278770892a6dd74",
|
||||
"gameMasterPassword": "a00a5973aacb17e4659125fbe10f4160d096dd84b2f586d2d75669462a30106d",
|
||||
"blueCommanderPassword": "7d2e1ef898b21db7411f725a945b76ec8dcad340ed705eaf801bc82be6fe8a4a",
|
||||
"redCommanderPassword": "abc5de7abdb8ed98f6d11d22c9d17593e339fde9cf4b9e170541b4f41af937e3"
|
||||
},
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
import re
|
||||
|
||||
# Read the file
|
||||
with open('unit.py', 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Pattern to match callback invocations
|
||||
pattern = r'self\.on_property_change_callbacks\[\"(\w+)\"\]\(self, self\.(\w+)\)'
|
||||
replacement = r'self._trigger_callback("\1", self.\2)'
|
||||
|
||||
# Replace all matches
|
||||
new_content = re.sub(pattern, replacement, content)
|
||||
|
||||
# Write back to file
|
||||
with open('unit.py', 'w', encoding='utf-8') as f:
|
||||
f.write(new_content)
|
||||
|
||||
print('Updated all callback invocations')
|
||||
@ -3,7 +3,7 @@ import asyncio
|
||||
|
||||
from data.data_extractor import DataExtractor
|
||||
from data.data_indexes import DataIndexes
|
||||
from data.data_types import LatLng, TACAN, Radio, GeneralSettings, Ammo, Contact, Offset
|
||||
from data.data_types import DrawArgument, LatLng, TACAN, Radio, GeneralSettings, Ammo, Contact, Offset
|
||||
from data.roes import ROES
|
||||
from data.states import states
|
||||
from utils.utils import enum_to_coalition
|
||||
@ -81,6 +81,8 @@ class Unit:
|
||||
self.targeting_range = 0.0
|
||||
self.aim_method_range = 0.0
|
||||
self.acquisition_range = 0.0
|
||||
self.cargo_weight = 0.0
|
||||
self.draw_arguments: List[DrawArgument] = []
|
||||
|
||||
self.previous_total_ammo = 0
|
||||
self.total_ammo = 0
|
||||
@ -654,6 +656,20 @@ class Unit:
|
||||
# Trigger callbacks for property change
|
||||
if "airborne" in self.on_property_change_callbacks:
|
||||
self._trigger_callback("airborne", self.airborne)
|
||||
elif datum_index == DataIndexes.CARGO_WEIGHT.value:
|
||||
cargo_weight = data_extractor.extract_float64()
|
||||
if cargo_weight != self.cargo_weight:
|
||||
self.cargo_weight = cargo_weight
|
||||
# Trigger callbacks for property change
|
||||
if "cargo_weight" in self.on_property_change_callbacks:
|
||||
self._trigger_callback("cargo_weight", self.cargo_weight)
|
||||
elif datum_index == DataIndexes.DRAW_ARGUMENTS.value:
|
||||
draw_arguments = data_extractor.extract_draw_arguments()
|
||||
if draw_arguments != self.draw_arguments:
|
||||
self.draw_arguments = draw_arguments
|
||||
# Trigger callbacks for property change
|
||||
if "draw_arguments" in self.on_property_change_callbacks:
|
||||
self._trigger_callback("draw_arguments", self.draw_arguments)
|
||||
|
||||
# --- API functions requiring ID ---
|
||||
def set_path(self, path: List[LatLng]):
|
||||
@ -758,6 +774,8 @@ class Unit:
|
||||
def set_engagement_properties(self, barrel_height, muzzle_velocity, aim_time, shots_to_fire, shots_base_interval, shots_base_scatter, engagement_range, targeting_range, aim_method_range, acquisition_range):
|
||||
return self.api.send_command({"setEngagementProperties": {"ID": self.ID, "barrelHeight": barrel_height, "muzzleVelocity": muzzle_velocity, "aimTime": aim_time, "shotsToFire": shots_to_fire, "shotsBaseInterval": shots_base_interval, "shotsBaseScatter": shots_base_scatter, "engagementRange": engagement_range, "targetingRange": targeting_range, "aimMethodRange": aim_method_range, "acquisitionRange": acquisition_range}})
|
||||
|
||||
|
||||
def set_cargo_weight(self, cargo_weight: float):
|
||||
return self.api.send_command({"setCargoWeight": {"ID": self.ID, "weight": cargo_weight}})
|
||||
|
||||
|
||||
def register_draw_argument(self, argument: int, active: bool = True):
|
||||
return self.api.send_command({"registerDrawArgument": {"ID": self.ID, "argument": argument, "active": active}})
|
||||
Loading…
x
Reference in New Issue
Block a user