10 Commits

Author SHA1 Message Date
Pax1601
fa0643987b Remove need for path variable 2023-12-06 12:37:59 +01:00
Pax1601
dcff462b32 v0.4.11-alpha-rc3 2023-12-06 09:15:44 +01:00
Pax1601
fa04e5f8bb Merge pull request #670 from Pax1601/650-robots-can-be-sent-to-refuel-while-protected
Added extra protection for robots
2023-12-06 08:17:21 +01:00
Pax1601
c8d5f9ce0e Formatted file 2023-12-06 08:17:01 +01:00
Pax1601
55642a89b1 Merge pull request #671 from Pax1601/651-control-tips-quick-options-shown-but-nothing-happens
Removed Quick Options option
2023-12-06 08:12:00 +01:00
PeekabooSteam
f305aa3929 Removed Quick Options option 2023-12-05 21:51:32 +00:00
PeekabooSteam
47ee88c339 Added extra protection for robots 2023-12-05 20:44:26 +00:00
Pax1601
022e041f68 Merge branch 'main' of https://github.com/Pax1601/DCSOlympus 2023-12-05 19:30:50 +01:00
Pax1601
0cc53890c1 v0.4.10-alpha-rc2 2023-12-05 19:30:34 +01:00
Pax1601
e37f7a4977 v0.4.10-alpha-rc1 2023-12-05 19:18:37 +01:00
22 changed files with 340 additions and 179 deletions

View File

@@ -2031,6 +2031,19 @@ declare module "unit/unitsmanager" {
* @param category Either "Aircraft", "Helicopter", "GroundUnit", or "NavyUnit". Determines what class will be used to create the new unit accordingly.
*/
addUnit(ID: number, category: string): void;
/** Sort units segregated groups based on controlling type and protection, if DCS-controlled
*
* @param units <Unit[]>
* @returns Object
*/
segregateUnits(units: Unit[]): {
[key: string]: [];
};
/**
*
* @param numOfProtectedUnits number
*/
showProtectedUnitsPopup(numOfProtectedUnits: number): void;
/** Update the data of all the units. The data is directly decoded from the binary buffer received from the REST Server. This is necessary for performance and bandwidth reasons.
*
* @param buffer The arraybuffer, encoded according to the ICD defined in: TODO Add reference to ICD

View File

@@ -112,5 +112,5 @@ function onListening() {
debug('Listening on ' + bind);
}
console.log("DCS Olympus server v0.4.9-alpha-rc1 started correctly!")
console.log("DCS Olympus server v0.4.11-alpha-rc3 started correctly!")
console.log("Waiting for connections...")

View File

@@ -1,12 +1,12 @@
{
"name": "DCSOlympus",
"version": "v0.4.9-alpha-rc1",
"version": "v0.4.11-alpha-rc3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "DCSOlympus",
"version": "v0.4.9-alpha-rc1",
"version": "v0.4.11-alpha-rc3",
"dependencies": {
"@turf/turf": "^6.5.0",
"body-parser": "^1.20.2",

View File

@@ -2,7 +2,7 @@
"name": "DCSOlympus",
"node-main": "./bin/www",
"main": "http://localhost:3000",
"version": "v0.4.9-alpha-rc1",
"version": "v0.4.11-alpha-rc3",
"private": true,
"scripts": {
"build": "browserify .\\src\\index.ts --debug -o .\\public\\javascripts\\bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ] && copy.bat",

View File

@@ -125,13 +125,6 @@ export class ControlTipsPlugin implements OlympusPlugin {
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse2`,
"action": `Quick options`,
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": true
},
{
"key": `Mouse2`,
"action": `Airbase menu`,

View File

@@ -29,7 +29,7 @@ import { UnitListPanel } from "./panels/unitlistpanel";
import { ContextManager } from "./context/contextmanager";
import { Context } from "./context/context";
var VERSION = "v0.4.9-alpha-rc1";
var VERSION = "v0.4.11-alpha-rc3";
var DEBUG = false;
export class OlympusApp {
@@ -262,9 +262,7 @@ export class OlympusApp {
const latestVersionSpan = document.getElementById("latest-version") as HTMLElement;
if (latestVersionSpan) {
latestVersionSpan.innerHTML = this.#latestVersion ?? "Unknown";
if (this.#latestVersion !== VERSION) {
latestVersionSpan.classList.add("new-version");
}
latestVersionSpan.classList.toggle("new-version", this.#latestVersion !== VERSION);
}
})
}

View File

@@ -31,8 +31,8 @@ export class UnitsManager {
#slowDeleteDialog!: Dialog;
#units: { [ID: number]: Unit };
#groups: { [groupName: string]: Group } = {};
#unitDataExport!:UnitDataFileExport;
#unitDataImport!:UnitDataFileImport;
#unitDataExport!: UnitDataFileExport;
#unitDataImport!: UnitDataFileImport;
constructor() {
this.#copiedUnits = [];
@@ -100,6 +100,46 @@ export class UnitsManager {
}
}
/** Sort units segregated groups based on controlling type and protection, if DCS-controlled
*
* @param units <Unit[]>
* @returns Object
*/
segregateUnits(units: Unit[]): { [key: string]: [] } {
const data: any = {
controllable: [],
dcsProtected: [],
dcsUnprotected: [],
human: [],
olympus: []
};
const map = getApp().getMap();
units.forEach(unit => {
if (unit.getHuman())
data.human.push(unit);
else if (unit.isControlledByOlympus())
data.olympus.push(unit);
else if (map.getIsUnitProtected(unit))
data.dcsProtected.push(unit);
else
data.dcsUnprotected.push(unit);
});
data.controllable = [].concat(data.dcsUnprotected, data.human, data.olympus);
return data;
}
/**
*
* @param numOfProtectedUnits number
*/
showProtectedUnitsPopup(numOfProtectedUnits: number) {
if (numOfProtectedUnits < 1)
return;
const messageText = (numOfProtectedUnits === 1) ? `Unit is protected` : `All selected units are protected`;
(getApp().getPopupsManager().get("infoPopup") as Popup).setText(messageText);
}
/** Update the data of all the units. The data is directly decoded from the binary buffer received from the REST Server. This is necessary for performance and bandwidth reasons.
*
* @param buffer The arraybuffer, encoded according to the ICD defined in: TODO Add reference to ICD
@@ -262,8 +302,7 @@ export class UnitsManager {
}
if (options) {
if (options.showProtectionReminder === true && numProtectedUnits > selectedUnits.length && selectedUnits.length === 0) {
const messageText = (numProtectedUnits === 1) ? `Unit is protected` : `All selected units are protected`;
(getApp().getPopupsManager().get("infoPopup") as Popup).setText(messageText);
this.showProtectedUnitsPopup(numProtectedUnits);
// Cheap way for now until we use more locks
let lock = <HTMLElement>document.querySelector("#unit-visibility-control button.lock");
lock.classList.add("prompt");
@@ -365,8 +404,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
/* Compute the destination for each unit. If mantainRelativePosition is true, compute the destination so to hold the relative positions */
var unitDestinations: { [key: number]: LatLng } = {};
@@ -399,8 +443,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: false });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
for (let idx in units) {
const unit = units[idx];
@@ -425,8 +474,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.landAt(latlng));
@@ -442,8 +496,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.changeSpeed(speedChange));
}
@@ -457,8 +516,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.changeAltitude(altitudeChange));
}
@@ -472,8 +536,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setSpeed(speed));
this.#showActionMessage(units, `setting speed to ${msToKnots(speed)} kts`);
@@ -488,8 +557,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setSpeedType(speedType));
this.#showActionMessage(units, `setting speed type to ${speedType}`);
@@ -504,8 +578,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setAltitude(altitude));
this.#showActionMessage(units, `setting altitude to ${mToFt(altitude)} ft`);
@@ -520,8 +599,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setAltitudeType(altitudeType));
this.#showActionMessage(units, `setting altitude type to ${altitudeType}`);
@@ -536,8 +620,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setROE(ROE));
this.#showActionMessage(units, `ROE set to ${ROE}`);
@@ -552,8 +641,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setReactionToThreat(reactionToThreat));
this.#showActionMessage(units, `reaction to threat set to ${reactionToThreat}`);
@@ -568,8 +662,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setEmissionsCountermeasures(emissionCountermeasure));
this.#showActionMessage(units, `emissions & countermeasures set to ${emissionCountermeasure}`);
@@ -584,8 +683,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setOnOff(onOff));
this.#showActionMessage(units, `unit active set to ${onOff}`);
@@ -600,8 +704,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setFollowRoads(followRoads));
this.#showActionMessage(units, `follow roads set to ${followRoads}`);
@@ -617,8 +726,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setOperateAs(operateAs));
this.#showActionMessage(units, `operate as set to ${operateAs}`);
@@ -633,8 +747,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.attackUnit(ID));
this.#showActionMessage(units, `attacking unit ${this.getUnitByID(ID)?.getUnitName()}`);
@@ -647,11 +766,14 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units.forEach((unit: Unit) => unit.refuel());
this.#showActionMessage(units, `sent to nearest tanker`);
segregatedUnits.controllable.forEach((unit: Unit) => unit.refuel());
this.#showActionMessage(segregatedUnits.controllable, `sent to nearest tanker`);
}
/** Instruct the selected units to follow another unit in a formation. Only works for aircrafts and helicopters.
@@ -665,8 +787,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
if (offset == undefined) {
/* Simple formations with fixed offsets */
@@ -683,8 +810,7 @@ export class UnitsManager {
var count = 1;
var xr = 0; var yr = 1; var zr = -1;
var layer = 1;
for (let idx in units) {
var unit = units[idx];
units.forEach((unit: Unit) => {
if (unit.ID !== ID) {
if (offset != undefined)
/* Offset is set, apply it */
@@ -705,7 +831,7 @@ export class UnitsManager {
}
count++;
}
}
})
this.#showActionMessage(units, `following unit ${this.getUnitByID(ID)?.getUnitName()}`);
}
@@ -718,8 +844,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.bombPoint(latlng));
this.#showActionMessage(units, `unit bombing point`);
@@ -734,8 +865,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.carpetBomb(latlng));
this.#showActionMessage(units, `unit carpet bombing point`);
@@ -750,8 +886,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.fireAtArea(latlng));
this.#showActionMessage(units, `unit firing at area`);
@@ -766,8 +907,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
getGroundElevation(latlng, (response: string) => {
var groundElevation: number | null = null;
@@ -788,8 +934,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.scenicAAA());
this.#showActionMessage(units, `unit set to perform scenic AAA`);
@@ -802,8 +953,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.missOnPurpose());
this.#showActionMessage(units, `unit set to perform miss-on-purpose AAA`);
@@ -818,9 +974,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.landAtPoint(latlng));
this.#showActionMessage(units, `unit landing at point`);
@@ -835,8 +995,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setShotsScatter(shotsScatter));
this.#showActionMessage(units, `shots scatter set to ${shotsScatter}`);
@@ -851,8 +1016,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
units.forEach((unit: Unit) => unit.setShotsIntensity(shotsIntensity));
this.#showActionMessage(units, `shots intensity set to ${shotsIntensity}`);
@@ -883,8 +1053,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: false, showProtectionReminder: true });
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
if (this.getUnitsCategories(units).length == 1) {
var unitsData: { ID: number, location: LatLng }[] = [];
@@ -929,8 +1104,13 @@ export class UnitsManager {
if (units === null)
units = this.getSelectedUnits({ excludeProtected: true, showProtectionReminder: true }); /* Can be applied to humans too */
if (units.length === 0)
const segregatedUnits = this.segregateUnits(units);
if (segregatedUnits.controllable.length === 0) {
this.showProtectedUnitsPopup(segregatedUnits.dcsProtected.length);
return;
}
units = segregatedUnits.controllable;
const selectionContainsAHuman = units.some((unit: Unit) => {
return unit.getHuman() === true;
@@ -1005,7 +1185,7 @@ export class UnitsManager {
*
*/
copy(units: Unit[] | null = null) {
if ( !getApp().getContextManager().getCurrentContext().getAllowUnitCopying() )
if (!getApp().getContextManager().getCurrentContext().getAllowUnitCopying())
return;
if (units === null)
@@ -1025,7 +1205,7 @@ export class UnitsManager {
* @returns True if units were pasted successfully
*/
paste() {
if ( !getApp().getContextManager().getCurrentContext().getAllowUnitPasting() )
if (!getApp().getContextManager().getCurrentContext().getAllowUnitPasting())
return;
let spawnPoints = 0;
@@ -1127,7 +1307,7 @@ export class UnitsManager {
if (Math.random() < IADSDensities[type]) {
/* Get a random blueprint depending on the selected parameters and spawn the unit */
const unitBlueprint = randomUnitBlueprint(groundUnitDatabase, { type: type, eras: activeEras, ranges: activeRanges });
if (unitBlueprint)
if (unitBlueprint)
this.spawnUnits("GroundUnit", [{ unitType: unitBlueprint.name, location: latlng, liveryID: "" }], coalitionArea.getCoalition(), false, "", "");
}
}
@@ -1152,7 +1332,7 @@ export class UnitsManager {
if (Math.random() < IADSDensities[type]) {
/* Get a random blueprint depending on the selected parameters and spawn the unit */
const unitBlueprint = randomUnitBlueprint(groundUnitDatabase, { type: type, eras: activeEras, ranges: activeRanges });
if (unitBlueprint)
if (unitBlueprint)
this.spawnUnits("GroundUnit", [{ unitType: unitBlueprint.name, location: latlng, liveryID: "" }], coalitionArea.getCoalition(), false, "", "");
}
}
@@ -1169,7 +1349,7 @@ export class UnitsManager {
this.#unitDataExport = new UnitDataFileExport("unit-export-dialog");
this.#unitDataExport.showForm(Object.values(this.#units));
}
/** Import ground and navy units from file
* TODO: extend to support aircraft and helicopters
*/

View File

@@ -3,7 +3,7 @@
<div id="app-summary">
<h2>DCS Olympus</h2>
<h4>Dynamic Unit Command</h4>
<div class="app-version">Version <span class="app-version-number">v0.4.9-alpha-rc1</span></div>
<div class="app-version">Version <span class="app-version-number">v0.4.11-alpha-rc3</span></div>
<div class="app-version">Latest version <span id="latest-version" class="app-version-number"></span></div>
</div>

View File

@@ -6,7 +6,7 @@
<div class="ol-select-options">
<div id="toolbar-summary">
<h3>DCS Olympus</h3>
<div class="accent-green app-version-number">version v0.4.9-alpha-rc1</div>
<div class="accent-green app-version-number">version v0.4.11-alpha-rc3</div>
</div>
<div>
<a href="https://discord.gg/wWXyVVBZT7" target="_blank">Discord</a>

View File

@@ -1,6 +1,6 @@
#define nwjsFolder "..\..\nwjs\"
#define nodejsFolder "..\..\node\"
#define version "v0.4.9-alpha-rc1"
#define version "v0.4.11-alpha-rc3"
[Setup]
AppName=DCS Olympus
@@ -51,36 +51,11 @@ Source: "..\scripts\python\configurator\dist\configurator.exe"; DestDir: "{app}\
[Run]
Filename: "{app}\Mods\Services\Olympus\configurator.exe"; Parameters: -a {code:GetAddress} -c {code:GetClientPort} -b {code:GetBackendPort} -p {code:GetPassword} -bp {code:GetBluePassword} -rp {code:GetRedPassword}; Check: CheckCallConfigurator
[Registry]
Root: HKCU; Subkey: "Environment"; ValueType: string; ValueName: "DCSOLYMPUS_PATH"; ValueData: "{app}\Mods\Services\Olympus"; Flags: preservestringtype
Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};%DCSOLYMPUS_PATH%\bin"; Check: NeedsAddPath('%DCSOLYMPUS_PATH%\bin');
[Setup]
; Tell Windows Explorer to reload the environment
ChangesEnvironment=yes
[Icons]
Name: "{userdesktop}\DCS Olympus Client"; Filename: "{app}\Mods\Services\Olympus\client\nw.exe"; Tasks: desktopicon; IconFilename: "{app}\Mods\Services\Olympus\img\olympus.ico"; Check: CheckLocalInstall
Name: "{userdesktop}\DCS Olympus Server"; Filename: "{app}\Mods\Services\Olympus\client\node.exe"; Tasks: desktopicon; IconFilename: "{app}\Mods\Services\Olympus\img\olympus_server.ico"; Parameters: ".\bin\www"; Check: CheckServerInstall
Name: "{userdesktop}\DCS Olympus Configurator"; Filename: "{app}\Mods\Services\Olympus\configurator.exe"; Tasks: desktopicon; IconFilename: "{app}\Mods\Services\Olympus\img\olympus_configurator.ico"; Check: CheckServerInstall
[Code]
function NeedsAddPath(Param: string): boolean;
var
OrigPath: string;
begin
if not RegQueryStringValue(HKCU,
'Environment',
'Path', OrigPath)
then begin
Result := True;
exit;
end;
{ look for the path with leading and trailing semicolon }
{ Pos() returns 0 if not found }
Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0;
end;
[Code]
var
lblLocalInstall: TLabel;

View File

@@ -15,7 +15,7 @@ declare_plugin(self_ID,
shortName = "Olympus",
fileMenuName = "Olympus",
version = "v0.4.9-alpha-rc1",
version = "v0.4.11-alpha-rc3",
state = "installed",
developerName= "DCS Refugees 767 squadron",
info = _("DCS Olympus is a mod for DCS World. It allows users to spawn, control, task, group, and remove units from a DCS World server using a real-time map interface, similarly to Real Time Strategy games. The user interface also provides useful informations units, like loadouts, fuel, tasking, and so on. In the future, more features for DCS World GCI and JTAC will be available."),

View File

@@ -1,11 +1,10 @@
local version = "v0.4.9-alpha-rc1"
local version = "v0.4.11-alpha-rc3"
local debug = false -- True enables debug printing using DCS messages
-- .dll related variables
Olympus.OlympusDLL = nil
Olympus.DLLsloaded = false
Olympus.OlympusModPath = os.getenv('DCSOLYMPUS_PATH')..'\\bin\\'
-- Logger reference
Olympus.log = mist.Logger:new("Olympus", 'info')
@@ -31,6 +30,10 @@ Olympus.weapons = {} -- Table holding references to all the currently existing
Olympus.missionStartTime = DCS.getRealTime()
Olympus.napalmCounter = 1
Olympus.fireCounter = 1
-- Load the current instance folder
local lfs = require('lfs')
------------------------------------------------------------------------------------------------------
-- Olympus functions
------------------------------------------------------------------------------------------------------
@@ -49,7 +52,7 @@ end
-- Loads the olympus .dll
function Olympus.loadDLLs()
-- Add the .dll paths
package.cpath = package.cpath..';'..Olympus.OlympusModPath..'?.dll;'
package.cpath = package.cpath..';'..Olympus.instancePath..'?.dll;'
local status
status, Olympus.OlympusDLL = pcall(require, 'olympus')
@@ -1361,6 +1364,10 @@ end
------------------------------------------------------------------------------------------------------
-- Olympus startup script
------------------------------------------------------------------------------------------------------
Olympus.instancePath = lfs.writedir().."Mods\\Services\\Olympus\\bin\\"
Olympus.notify("Starting DCS Olympus backend session in "..Olympus.instancePath, 2)
local OlympusName = 'Olympus ' .. version .. ' C++ module';
Olympus.DLLsloaded = Olympus.loadDLLs()
if Olympus.DLLsloaded then
@@ -1402,11 +1409,3 @@ Olympus.initializeUnits()
Olympus.notify("OlympusCommand script " .. version .. " loaded successfully", 2, true)
-- Load the current instance folder
local lfs = require('lfs')
Olympus.instancePath = lfs.writedir().."Mods\\Services\\Olympus"
Olympus.notify("Starting DCS Olympus backend session in "..Olympus.instancePath, 2)
Olympus.OlympusDLL.setInstancePath()

View File

@@ -1,10 +1,10 @@
local version = 'v0.4.9-alpha-rc1'
local version = 'v0.4.11-alpha-rc3'
local lfs = require("lfs")
Olympus = {}
Olympus.OlympusDLL = nil
Olympus.cppRESTDLL = nil
Olympus.DLLsloaded = false
Olympus.OlympusModPath = os.getenv('DCSOLYMPUS_PATH')..'\\bin\\'
Olympus.OlympusModPath = lfs.writedir().."Mods\\Services\\Olympus\\bin\\"
log.write('Olympus.HOOKS.LUA', log.INFO,'Executing OlympusHook.lua')
@@ -14,7 +14,7 @@ function Olympus.loadDLLs()
local status
log.write('Olympus.HOOKS.LUA', log.INFO, 'Loading olympus.dll from ['..Olympus.OlympusModPath..']')
status, Olympus.OlympusDLL = pcall(require, 'olympus')
status, Olympus.OlympusDLL = require("olympus")
if status then
log.write('Olympus.HOOKS.LUA', log.INFO, 'olympus.dll loaded successfully')
return true

View File

@@ -52,8 +52,12 @@ extern "C" DllExport int coreDeinit(lua_State* L)
}
/* Called when DCS simulation starts. All singletons are instantiated, and the custom Lua functions are registered in the Lua state. */
extern "C" DllExport int coreInit(lua_State* L)
extern "C" DllExport int coreInit(lua_State* L, const char* path)
{
instancePath = path;
log("Initializing core.dll with instance path " + instancePath);
sessionHash = random_string(16);
unitsManager = new UnitsManager(L);
weaponsManager = new WeaponsManager(L);
@@ -70,20 +74,6 @@ extern "C" DllExport int coreInit(lua_State* L)
return(0);
}
extern "C" DllExport int coreInstancePath(lua_State * L)
{
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
lua_getglobal(L, "Olympus");
lua_getfield(L, -1, "instancePath");
instancePath = lua_tostring(L, -1);
log("Setting instance path to " + instancePath);
return(0);
}
extern "C" DllExport int coreFrame(lua_State* L)
{
if (!initialized)

View File

@@ -5,6 +5,8 @@
#include <algorithm>
extern string instancePath;
bool executeLuaScript(lua_State* L, string path)
{
replace(path.begin(), path.end(), '\\', '/');
@@ -36,21 +38,8 @@ void registerLuaFunctions(lua_State* L)
log("protectedCall registered successfully");
}
char* buf = nullptr;
size_t sz = 0;
if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr)
{
modLocation = buf;
free(buf);
}
else
{
log("DCSOLYMPUS_PATH environment variable is missing");
return;
}
executeLuaScript(L, modLocation + "\\Scripts\\mist.lua");
executeLuaScript(L, modLocation + "\\Scripts\\OlympusCommand.lua");
executeLuaScript(L, modLocation + "\\Scripts\\unitPayloads.lua");
executeLuaScript(L, modLocation + "\\Scripts\\templates.lua");
executeLuaScript(L, instancePath + "..\\Scripts\\mist.lua");
executeLuaScript(L, instancePath + "..\\Scripts\\OlympusCommand.lua");
executeLuaScript(L, instancePath + "..\\Scripts\\unitPayloads.lua");
executeLuaScript(L, instancePath + "..\\Scripts\\templates.lua");
}

View File

@@ -5,6 +5,7 @@ void DllExport stackUpdate(lua_State* L, int& stackDepth, int initialStack = 0);
void DllExport stackPop(lua_State* L, int popDepth = 1);
void DllExport stackClean(lua_State* L, int stackDepth);
void DllExport luaTableToJSON(lua_State* L, int index, json::value& json, bool logKeys = false);
void DllExport luaLogTableKeys(lua_State* L, int index);
#define STACK_UPDATE stackUpdate(L, stackDepth, initialStack);
#define STACK_INIT int stackDepth = 0; int initialStack = 0; stackUpdate(L, initialStack);

View File

@@ -18,6 +18,29 @@ void stackClean(lua_State* L, int stackDepth)
lua_pop(L, stackDepth);
}
void luaLogTableKeys(lua_State* L, int index)
{
if (lua_istable(L, index))
{
STACK_INIT;
lua_pushvalue(L, index);
lua_pushnil(L);
while (lua_next(L, -2))
{
lua_pushvalue(L, -2);
const char* key = lua_tostring(L, -1);
log(key);
lua_pop(L, 2);
}
lua_pop(L, 1);
STACK_CLEAN;
}
}
void luaTableToJSON(lua_State* L, int index, json::value& json, bool logKeys)
{
if (lua_istable(L, index))

BIN
src/olympus/olympus.aps Normal file

Binary file not shown.

View File

@@ -20,6 +20,9 @@
<ProjectReference Include="..\logger\logger.vcxproj">
<Project>{873ecabe-fcfe-4217-ac15-91959c3cf1c6}</Project>
</ProjectReference>
<ProjectReference Include="..\luatools\luatools.vcxproj">
<Project>{de139ec1-4f88-47d5-be73-f41915fe14a3}</Project>
</ProjectReference>
<ProjectReference Include="..\utils\utils.vcxproj">
<Project>{b85009ce-4a5c-4a5a-b85d-001b3a2651b2}</Project>
</ProjectReference>
@@ -112,6 +115,7 @@
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>lua.lib</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
<DelayLoadDLLs>dcstools.dll;logger.dll;utils.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

View File

@@ -5,40 +5,26 @@
/* Run-time linking to core dll allows for "hot swap". This is useful for development but could be removed when stable.*/
HINSTANCE hGetProcIDDLL = NULL;
typedef int(__stdcall* f_coreInit)(lua_State* L);
typedef int(__stdcall* f_coreInit)(lua_State* L, const char* path);
typedef int(__stdcall* f_coreDeinit)(lua_State* L);
typedef int(__stdcall* f_coreFrame)(lua_State* L);
typedef int(__stdcall* f_coreUnitsData)(lua_State* L);
typedef int(__stdcall* f_coreWeaponsData)(lua_State* L);
typedef int(__stdcall* f_coreMissionData)(lua_State* L);
typedef int(__stdcall* f_coreInstancePath)(lua_State* L);
f_coreInit coreInit = nullptr;
f_coreDeinit coreDeinit = nullptr;
f_coreFrame coreFrame = nullptr;
f_coreUnitsData coreUnitsData = nullptr;
f_coreWeaponsData coreWeaponsData = nullptr;
f_coreMissionData coreMissionData = nullptr;
f_coreInstancePath coreInstancePath = nullptr;
string modPath;
static int onSimulationStart(lua_State* L)
{
log("onSimulationStart callback called successfully");
string modLocation;
string dllLocation;
char* buf = nullptr;
size_t sz = 0;
if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr)
{
modLocation = buf;
free(buf);
}
else
{
log("DCSOLYMPUS_PATH environment variable is missing");
goto error;
}
dllLocation = modLocation + "\\bin\\core.dll";
string dllLocation = modPath + "\\core.dll";
log("Loading core.dll");
hGetProcIDDLL = LoadLibrary(to_wstring(dllLocation).c_str());
@@ -92,14 +78,7 @@ static int onSimulationStart(lua_State* L)
goto error;
}
coreInstancePath = (f_coreInstancePath)GetProcAddress(hGetProcIDDLL, "coreInstancePath");
if (!coreInstancePath)
{
LogError(L, "Error getting coreInstancePath ProcAddress from DLL");
goto error;
}
coreInit(L);
coreInit(L, modPath.c_str());
LogInfo(L, "Module loaded and started successfully.");
@@ -146,7 +125,6 @@ static int onSimulationStop(lua_State* L)
coreUnitsData = nullptr;
coreWeaponsData = nullptr;
coreMissionData = nullptr;
coreInstancePath = nullptr;
}
hGetProcIDDLL = NULL;
@@ -185,15 +163,6 @@ static int setMissionData(lua_State* L)
return 0;
}
static int setInstancePath(lua_State* L)
{
if (coreInstancePath)
{
coreInstancePath(L);
}
return 0;
}
static const luaL_Reg Map[] = {
{"onSimulationStart", onSimulationStart},
{"onSimulationFrame", onSimulationFrame},
@@ -201,12 +170,39 @@ static const luaL_Reg Map[] = {
{"setUnitsData", setUnitsData },
{"setWeaponsData", setWeaponsData },
{"setMissionData", setMissionData },
{"setInstancePath", setInstancePath },
{NULL, NULL}
};
extern "C" DllExport int luaopen_olympus(lua_State * L)
{
lua_getglobal(L, "require");
lua_pushstring(L, "lfs");
lua_pcall(L, 1, 1, 0);
lua_getfield(L, -1, "writedir");
lua_pcall(L, 0, 1, 0);
if (lua_isstring(L, -1)) {
modPath = string(lua_tostring(L, -1)) + "Mods\\Services\\Olympus\\bin\\";
SetDllDirectoryA(modPath.c_str());
LogInfo(L, "Instance location retrieved successfully");
}
else {
/* Log without using the helper dlls because we have not loaded them yet here */
lua_getglobal(L, "log");
lua_getfield(L, -1, "ERROR");
int errorLevel = (int)lua_tointeger(L, -1);
lua_getglobal(L, "log");
lua_getfield(L, -1, "write");
lua_pushstring(L, "Olympus.dll");
lua_pushnumber(L, errorLevel);
lua_pushstring(L, "An error has occurred while trying to retrieve Olympus's instance location");
lua_pcall(L, 3, 0, 0);
return 0;
}
LogInfo(L, "Loading .dlls from " + modPath);
luaL_register(L, "olympus", Map);
return 1;
}

View File

@@ -1,6 +1,6 @@
#pragma once
#define VERSION "v0.4.9-alpha-rc1"
#define VERSION "v0.4.11-alpha-rc3"
#define LOG_NAME "Olympus_log.txt"
#define REST_ADDRESS "http://localhost:30000"
#define REST_URI "olympus"
@@ -14,8 +14,8 @@
#define FRAMERATE_TIME_INTERVAL 0.05
#define OLYMPUS_JSON_PATH "\\olympus.json"
#define AIRCRAFT_DATABASE_PATH "\\client\\public\\databases\\units\\aircraftdatabase.json"
#define HELICOPTER_DATABASE_PATH "\\client\\public\\databases\\units\\helicopterdatabase.json"
#define GROUNDUNIT_DATABASE_PATH "\\client\\public\\databases\\units\\groundunitdatabase.json"
#define NAVYUNIT_DATABASE_PATH "\\client\\public\\databases\\units\\navyunitdatabase.json"
#define OLYMPUS_JSON_PATH "..\\olympus.json"
#define AIRCRAFT_DATABASE_PATH "..\\client\\public\\databases\\units\\aircraftdatabase.json"
#define HELICOPTER_DATABASE_PATH "..\\client\\public\\databases\\units\\helicopterdatabase.json"
#define GROUNDUNIT_DATABASE_PATH "..\\client\\public\\databases\\units\\groundunitdatabase.json"
#define NAVYUNIT_DATABASE_PATH "..\\client\\public\\databases\\units\\navyunitdatabase.json"

View File

@@ -1,3 +1,3 @@
{
"version": "v0.4.9-alpha-rc1"
"version": "v0.4.11-alpha-rc3"
}