mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Compare commits
24 Commits
v0.4.9-alp
...
v0.4.11-al
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa0643987b | ||
|
|
dcff462b32 | ||
|
|
fa04e5f8bb | ||
|
|
c8d5f9ce0e | ||
|
|
55642a89b1 | ||
|
|
f305aa3929 | ||
|
|
47ee88c339 | ||
|
|
022e041f68 | ||
|
|
0cc53890c1 | ||
|
|
e37f7a4977 | ||
|
|
8d03c6a767 | ||
|
|
e29fdfd8c7 | ||
|
|
af619c3687 | ||
|
|
6afb6682ea | ||
|
|
9c2c7f45c6 | ||
|
|
7fbc19e90a | ||
|
|
8f2f73dc0e | ||
|
|
24a1681337 | ||
|
|
304e8ba3a0 | ||
|
|
45b840fa72 | ||
|
|
82704f042b | ||
|
|
87d71da55e | ||
|
|
71cf7c67f7 | ||
|
|
62142ed976 |
28
build.bat
Normal file
28
build.bat
Normal file
@@ -0,0 +1,28 @@
|
||||
call git clean -fx
|
||||
|
||||
cd src
|
||||
msbuild olympus.sln /t:Rebuild /p:Configuration=Release
|
||||
cd ..
|
||||
|
||||
cd scripts/python/configurator
|
||||
call build_configurator.bat
|
||||
cd ../../..
|
||||
|
||||
cd client
|
||||
rmdir /s /q "hgt"
|
||||
call npm install
|
||||
call npm run emit-declarations
|
||||
call npm run build-release
|
||||
|
||||
cd "plugins\controltips"
|
||||
call npm install
|
||||
call npm run build-release
|
||||
cd "..\.."
|
||||
|
||||
cd "plugins\databasemanager"
|
||||
call npm install
|
||||
call npm run build-release
|
||||
cd "..\.."
|
||||
|
||||
call npm prune --production
|
||||
cd ..
|
||||
@@ -1,30 +1,2 @@
|
||||
call git clean -fx
|
||||
|
||||
cd src
|
||||
msbuild olympus.sln /t:Rebuild /p:Configuration=Release
|
||||
cd ..
|
||||
|
||||
cd scripts/python/configurator
|
||||
call build_configurator.bat
|
||||
cd ../../..
|
||||
|
||||
cd client
|
||||
rmdir /s /q "hgt"
|
||||
call npm install
|
||||
call npm run emit-declarations
|
||||
call npm run build-release
|
||||
|
||||
cd "plugins\controltips"
|
||||
call npm install
|
||||
call npm run build-release
|
||||
cd "..\.."
|
||||
|
||||
cd "plugins\databasemanager"
|
||||
call npm install
|
||||
call npm run build-release
|
||||
cd "..\.."
|
||||
|
||||
call npm prune --production
|
||||
cd ..
|
||||
|
||||
call build.bat
|
||||
call "C:\Program Files (x86)\Inno Setup 6\iscc.exe" "installer\olympus.iss"
|
||||
|
||||
22
client/@types/olympus/index.d.ts
vendored
22
client/@types/olympus/index.d.ts
vendored
@@ -158,6 +158,10 @@ declare module "constants/constants" {
|
||||
bounds: LatLngBounds;
|
||||
zoom: number;
|
||||
};
|
||||
SinaiMap: {
|
||||
bounds: LatLngBounds;
|
||||
zoom: number;
|
||||
};
|
||||
};
|
||||
export const mapLayers: {
|
||||
"ArcGIS Satellite": {
|
||||
@@ -2027,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
|
||||
@@ -2396,7 +2413,7 @@ declare module "server/servermanager" {
|
||||
constructor();
|
||||
toggleDemoEnabled(): void;
|
||||
setCredentials(newUsername: string, newPassword: string): void;
|
||||
GET(callback: CallableFunction, uri: string, options?: ServerRequestOptions, responseType?: string): void;
|
||||
GET(callback: CallableFunction, uri: string, options?: ServerRequestOptions, responseType?: string, force?: boolean): void;
|
||||
PUT(request: object, callback: CallableFunction): void;
|
||||
getConfig(callback: CallableFunction): void;
|
||||
setAddress(address: string, port: number): void;
|
||||
@@ -2464,6 +2481,9 @@ declare module "server/servermanager" {
|
||||
setPaused(newPaused: boolean): void;
|
||||
getPaused(): boolean;
|
||||
getServerIsPaused(): boolean;
|
||||
getRequests(): {
|
||||
[key: string]: XMLHttpRequest;
|
||||
};
|
||||
}
|
||||
}
|
||||
declare module "panels/unitlistpanel" {
|
||||
|
||||
@@ -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...")
|
||||
|
||||
4
client/package-lock.json
generated
4
client/package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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`,
|
||||
|
||||
@@ -62,6 +62,16 @@
|
||||
height: 180px;
|
||||
}
|
||||
|
||||
#hotgroup-panel {
|
||||
bottom: 40px;
|
||||
column-gap: 10px;
|
||||
display: flex;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
translate: -50%;
|
||||
z-index: 9998;
|
||||
}
|
||||
|
||||
#info-popup {
|
||||
position: absolute;
|
||||
width: fit-content;
|
||||
|
||||
@@ -994,16 +994,6 @@ nav.ol-panel> :last-child {
|
||||
}
|
||||
}
|
||||
|
||||
#hotgroup-panel {
|
||||
bottom: 40px;
|
||||
column-gap: 10px;
|
||||
display: flex;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
translate: -50%;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
#hotgroup-panel>div {
|
||||
align-items: center;
|
||||
background-color: var(--background-steel);
|
||||
|
||||
@@ -116,6 +116,13 @@ export const minimapBoundaries = [
|
||||
new LatLng(48.12, 3.70),
|
||||
new LatLng(50.44, 3.70),
|
||||
new LatLng(50.44, -3.29)
|
||||
],
|
||||
[ // Sinai
|
||||
new LatLng(34.312222, 28.523333),
|
||||
new LatLng(25.946944, 28.523333),
|
||||
new LatLng(25.946944, 36.897778),
|
||||
new LatLng(34.312222, 36.897778),
|
||||
new LatLng(34.312222, 28.523333)
|
||||
]
|
||||
];
|
||||
|
||||
@@ -127,6 +134,7 @@ export const mapBounds = {
|
||||
"Caucasus": { bounds: new LatLngBounds([39.6170191, 27.634935], [47.3907982, 49.3101946]), zoom: 4 },
|
||||
"Falklands": { bounds: new LatLngBounds([-49.097217, -79.418267], [-56.874517, -43.316433]), zoom: 3 },
|
||||
"Normandy": { bounds: new LatLngBounds([50.44, -3.29], [48.12, 3.70]), zoom: 5 },
|
||||
"SinaiMap": { bounds: new LatLngBounds([34.312222, 28.523333], [25.946944, 36.897778]), zoom: 4 },
|
||||
}
|
||||
|
||||
export const mapLayers = {
|
||||
@@ -134,7 +142,7 @@ export const mapLayers = {
|
||||
urlTemplate: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
|
||||
minZoom: 1,
|
||||
maxZoom: 19,
|
||||
attribution: "Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, GetApp().getMap()ping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community"
|
||||
attribution: "Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Mapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community"
|
||||
},
|
||||
"USGS Topo": {
|
||||
urlTemplate: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}',
|
||||
|
||||
@@ -68,7 +68,8 @@ export class CoalitionAreaContextMenu extends ContextMenu {
|
||||
const area = this.getCoalitionArea();
|
||||
if (area)
|
||||
getApp().getUnitsManager().createIADS(area, getCheckboxOptions(this.#iadsTypesDropdown), getCheckboxOptions(this.#iadsErasDropdown), getCheckboxOptions(this.#iadsRangesDropdown), this.#iadsDensitySlider.getValue(), this.#iadsDistributionSlider.getValue());
|
||||
})
|
||||
this.hide();
|
||||
});
|
||||
this.hide();
|
||||
}
|
||||
|
||||
@@ -110,7 +111,7 @@ export class CoalitionAreaContextMenu extends ContextMenu {
|
||||
this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => {
|
||||
element.setAttribute("data-coalition", this.getCoalitionArea()?.getCoalition())
|
||||
});
|
||||
this.#coalitionSwitch.setValue(this.getCoalitionArea()?.getCoalition() === "red");
|
||||
this.#coalitionSwitch.setValue(this.getCoalitionArea()?.getCoalition() === "blue");
|
||||
}
|
||||
|
||||
/** Get the CoalitionArea object the contextmenu is editing
|
||||
|
||||
@@ -26,7 +26,7 @@ export class Dropdown {
|
||||
|
||||
if (options != null) this.setOptions(options);
|
||||
|
||||
this.#value.addEventListener("click", (ev) => { this.#toggle(); });
|
||||
(this.#container.querySelector(".ol-select-value") as HTMLElement)?.addEventListener("click", (ev) => { this.#toggle(); });
|
||||
|
||||
document.addEventListener("click", (ev) => {
|
||||
if (!(this.#value.contains(ev.target as Node) || this.#options.contains(ev.target as Node) || this.#container.contains(ev.target as Node))) {
|
||||
|
||||
@@ -29,7 +29,8 @@ 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 {
|
||||
/* Global data */
|
||||
@@ -261,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);
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -298,7 +297,7 @@ export class OlympusApp {
|
||||
shortcutManager.addKeyboardShortcut("toggleDemo", {
|
||||
"altKey": false,
|
||||
"callback": () => {
|
||||
this.getServerManager().toggleDemoEnabled();
|
||||
if (DEBUG === true) this.getServerManager().toggleDemoEnabled();
|
||||
},
|
||||
"code": "KeyT",
|
||||
"context": "olympus",
|
||||
|
||||
@@ -16,11 +16,12 @@ export class ServerManager {
|
||||
#username = "";
|
||||
#password = "";
|
||||
#sessionHash: string | null = null;
|
||||
#lastUpdateTimes: {[key: string]: number} = {}
|
||||
#lastUpdateTimes: { [key: string]: number } = {}
|
||||
#demoEnabled = false;
|
||||
#previousMissionElapsedTime:number = 0; // Track if mission elapsed time is increasing (i.e. is the server paused)
|
||||
#previousMissionElapsedTime: number = 0; // Track if mission elapsed time is increasing (i.e. is the server paused)
|
||||
#serverIsPaused: boolean = false;
|
||||
#intervals: number[] = [];
|
||||
#requests: { [key: string]: XMLHttpRequest } = {};
|
||||
|
||||
constructor() {
|
||||
this.#lastUpdateTimes[UNITS_URI] = Date.now();
|
||||
@@ -40,9 +41,20 @@ export class ServerManager {
|
||||
this.#password = newPassword;
|
||||
}
|
||||
|
||||
GET(callback: CallableFunction, uri: string, options?: ServerRequestOptions, responseType?: string) {
|
||||
GET(callback: CallableFunction, uri: string, options?: ServerRequestOptions, responseType: string = 'text', force: boolean = false) {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
|
||||
/* If a request on this uri is still pending (meaning it's not done or did not yet fail), skip the request, to avoid clogging the TCP workers */
|
||||
/* If we are forcing the request we don't care if one already exists, just send it. CAREFUL: this makes sense only for low frequency requests, like refreshes, when we
|
||||
are reasonably confident any previous request will be done before we make a new one on the same URI. */
|
||||
if (uri in this.#requests && this.#requests[uri].readyState !== 4 && !force) {
|
||||
console.warn(`GET request on ${uri} URI still pending, skipping...`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!force)
|
||||
this.#requests[uri] = xmlHttp;
|
||||
|
||||
/* Assemble the request options string */
|
||||
var optionsString = '';
|
||||
if (options?.time != undefined)
|
||||
@@ -83,9 +95,11 @@ export class ServerManager {
|
||||
this.setConnected(false);
|
||||
}
|
||||
};
|
||||
xmlHttp.onerror = (res) => {
|
||||
console.error("An error occurred during the XMLHttpRequest");
|
||||
this.setConnected(false);
|
||||
xmlHttp.onreadystatechange = (res) => {
|
||||
if (xmlHttp.readyState == 4 && xmlHttp.status === 0) {
|
||||
console.error("An error occurred during the XMLHttpRequest");
|
||||
this.setConnected(false);
|
||||
}
|
||||
};
|
||||
xmlHttp.send(null);
|
||||
}
|
||||
@@ -130,7 +144,7 @@ export class ServerManager {
|
||||
}
|
||||
|
||||
getLogs(callback: CallableFunction, refresh: boolean = false) {
|
||||
this.GET(callback, LOGS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[LOGS_URI]});
|
||||
this.GET(callback, LOGS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[LOGS_URI] }, 'text', refresh);
|
||||
}
|
||||
|
||||
getMission(callback: CallableFunction) {
|
||||
@@ -138,66 +152,66 @@ export class ServerManager {
|
||||
}
|
||||
|
||||
getUnits(callback: CallableFunction, refresh: boolean = false) {
|
||||
this.GET(callback, UNITS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[UNITS_URI] }, 'arraybuffer');
|
||||
this.GET(callback, UNITS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[UNITS_URI] }, 'arraybuffer', refresh);
|
||||
}
|
||||
|
||||
getWeapons(callback: CallableFunction, refresh: boolean = false) {
|
||||
this.GET(callback, WEAPONS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[WEAPONS_URI] }, 'arraybuffer');
|
||||
this.GET(callback, WEAPONS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[WEAPONS_URI] }, 'arraybuffer', refresh);
|
||||
}
|
||||
|
||||
isCommandExecuted(callback: CallableFunction, commandHash: string) {
|
||||
this.GET(callback, COMMANDS_URI, { commandHash: commandHash});
|
||||
this.GET(callback, COMMANDS_URI, { commandHash: commandHash });
|
||||
}
|
||||
|
||||
addDestination(ID: number, path: any, callback: CallableFunction = () => {}) {
|
||||
addDestination(ID: number, path: any, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "path": path }
|
||||
var data = { "setPath": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
spawnSmoke(color: string, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
spawnSmoke(color: string, latlng: LatLng, callback: CallableFunction = () => { }) {
|
||||
var command = { "color": color, "location": latlng };
|
||||
var data = { "smoke": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
spawnExplosion(intensity: number, explosionType: string, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
spawnExplosion(intensity: number, explosionType: string, latlng: LatLng, callback: CallableFunction = () => { }) {
|
||||
var command = { "explosionType": explosionType, "intensity": intensity, "location": latlng };
|
||||
var data = { "explosion": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
spawnAircrafts(units: any, coalition: string, airbaseName: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) {
|
||||
spawnAircrafts(units: any, coalition: string, airbaseName: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "units": units, "coalition": coalition, "airbaseName": airbaseName, "country": country, "immediate": immediate, "spawnPoints": spawnPoints };
|
||||
var data = { "spawnAircrafts": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
spawnHelicopters(units: any, coalition: string, airbaseName: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) {
|
||||
spawnHelicopters(units: any, coalition: string, airbaseName: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "units": units, "coalition": coalition, "airbaseName": airbaseName, "country": country, "immediate": immediate, "spawnPoints": spawnPoints };
|
||||
var data = { "spawnHelicopters": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
spawnGroundUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) {
|
||||
spawnGroundUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "units": units, "coalition": coalition, "country": country, "immediate": immediate, "spawnPoints": spawnPoints };;
|
||||
var data = { "spawnGroundUnits": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
spawnNavyUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) {
|
||||
spawnNavyUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "units": units, "coalition": coalition, "country": country, "immediate": immediate, "spawnPoints": spawnPoints };
|
||||
var data = { "spawnNavyUnits": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
attackUnit(ID: number, targetID: number, callback: CallableFunction = () => {}) {
|
||||
attackUnit(ID: number, targetID: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "targetID": targetID };
|
||||
var data = { "attackUnit": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
followUnit(ID: number, targetID: number, offset: { "x": number, "y": number, "z": number }, callback: CallableFunction = () => {}) {
|
||||
followUnit(ID: number, targetID: number, offset: { "x": number, "y": number, "z": number }, callback: CallableFunction = () => { }) {
|
||||
// X: front-rear, positive front
|
||||
// Y: top-bottom, positive bottom
|
||||
// Z: left-right, positive right
|
||||
@@ -207,172 +221,172 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
cloneUnits(units: {ID: number, location: LatLng}[], deleteOriginal: boolean, spawnPoints: number, callback: CallableFunction = () => {}) {
|
||||
cloneUnits(units: { ID: number, location: LatLng }[], deleteOriginal: boolean, spawnPoints: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "units": units, "deleteOriginal": deleteOriginal, "spawnPoints": spawnPoints };
|
||||
var data = { "cloneUnits": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
deleteUnit(ID: number, explosion: boolean, explosionType: string, immediate: boolean, callback: CallableFunction = () => {}) {
|
||||
deleteUnit(ID: number, explosion: boolean, explosionType: string, immediate: boolean, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "explosion": explosion, "explosionType": explosionType, "immediate": immediate };
|
||||
var data = { "deleteUnit": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
landAt(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
landAt(ID: number, latlng: LatLng, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "location": latlng };
|
||||
var data = { "landAt": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
changeSpeed(ID: number, speedChange: string, callback: CallableFunction = () => {}) {
|
||||
changeSpeed(ID: number, speedChange: string, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "change": speedChange }
|
||||
var data = { "changeSpeed": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setSpeed(ID: number, speed: number, callback: CallableFunction = () => {}) {
|
||||
setSpeed(ID: number, speed: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "speed": speed }
|
||||
var data = { "setSpeed": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setSpeedType(ID: number, speedType: string, callback: CallableFunction = () => {}) {
|
||||
setSpeedType(ID: number, speedType: string, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "speedType": speedType }
|
||||
var data = { "setSpeedType": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
changeAltitude(ID: number, altitudeChange: string, callback: CallableFunction = () => {}) {
|
||||
changeAltitude(ID: number, altitudeChange: string, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "change": altitudeChange }
|
||||
var data = { "changeAltitude": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setAltitudeType(ID: number, altitudeType: string, callback: CallableFunction = () => {}) {
|
||||
setAltitudeType(ID: number, altitudeType: string, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "altitudeType": altitudeType }
|
||||
var data = { "setAltitudeType": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setAltitude(ID: number, altitude: number, callback: CallableFunction = () => {}) {
|
||||
setAltitude(ID: number, altitude: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "altitude": altitude }
|
||||
var data = { "setAltitude": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
createFormation(ID: number, isLeader: boolean, wingmenIDs: number[], callback: CallableFunction = () => {}) {
|
||||
createFormation(ID: number, isLeader: boolean, wingmenIDs: number[], callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "wingmenIDs": wingmenIDs, "isLeader": isLeader }
|
||||
var data = { "setLeader": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setROE(ID: number, ROE: string, callback: CallableFunction = () => {}) {
|
||||
setROE(ID: number, ROE: string, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "ROE": ROEs.indexOf(ROE) }
|
||||
var data = { "setROE": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setReactionToThreat(ID: number, reactionToThreat: string, callback: CallableFunction = () => {}) {
|
||||
setReactionToThreat(ID: number, reactionToThreat: string, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "reactionToThreat": reactionsToThreat.indexOf(reactionToThreat) }
|
||||
var data = { "setReactionToThreat": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setEmissionsCountermeasures(ID: number, emissionCountermeasure: string, callback: CallableFunction = () => {}) {
|
||||
setEmissionsCountermeasures(ID: number, emissionCountermeasure: string, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "emissionsCountermeasures": emissionsCountermeasures.indexOf(emissionCountermeasure) }
|
||||
var data = { "setEmissionsCountermeasures": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setOnOff(ID: number, onOff: boolean, callback: CallableFunction = () => {}) {
|
||||
setOnOff(ID: number, onOff: boolean, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "onOff": onOff }
|
||||
var data = { "setOnOff": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setFollowRoads(ID: number, followRoads: boolean, callback: CallableFunction = () => {}) {
|
||||
setFollowRoads(ID: number, followRoads: boolean, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "followRoads": followRoads }
|
||||
var data = { "setFollowRoads": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setOperateAs(ID: number, operateAs: number, callback: CallableFunction = () => {}) {
|
||||
setOperateAs(ID: number, operateAs: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "operateAs": operateAs }
|
||||
var data = { "setOperateAs": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
|
||||
refuel(ID: number, callback: CallableFunction = () => {}) {
|
||||
refuel(ID: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID };
|
||||
var data = { "refuel": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
bombPoint(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
bombPoint(ID: number, latlng: LatLng, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "location": latlng }
|
||||
var data = { "bombPoint": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
carpetBomb(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
carpetBomb(ID: number, latlng: LatLng, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "location": latlng }
|
||||
var data = { "carpetBomb": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
bombBuilding(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
bombBuilding(ID: number, latlng: LatLng, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "location": latlng }
|
||||
var data = { "bombBuilding": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
fireAtArea(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
fireAtArea(ID: number, latlng: LatLng, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "location": latlng }
|
||||
var data = { "fireAtArea": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
simulateFireFight(ID: number, latlng: LatLng, altitude: number, callback: CallableFunction = () => {}) {
|
||||
simulateFireFight(ID: number, latlng: LatLng, altitude: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "location": latlng, "altitude": altitude }
|
||||
var data = { "simulateFireFight": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
// TODO: Remove coalition
|
||||
scenicAAA(ID: number, coalition: string, callback: CallableFunction = () => {}) {
|
||||
scenicAAA(ID: number, coalition: string, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "coalition": coalition }
|
||||
var data = { "scenicAAA": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
// TODO: Remove coalition
|
||||
missOnPurpose(ID: number, coalition: string, callback: CallableFunction = () => {}) {
|
||||
missOnPurpose(ID: number, coalition: string, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "coalition": coalition }
|
||||
var data = { "missOnPurpose": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
landAtPoint(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
landAtPoint(ID: number, latlng: LatLng, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "location": latlng }
|
||||
var data = { "landAtPoint": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setShotsScatter(ID: number, shotsScatter: number, callback: CallableFunction = () => {}) {
|
||||
setShotsScatter(ID: number, shotsScatter: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "shotsScatter": shotsScatter }
|
||||
var data = { "setShotsScatter": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setShotsIntensity(ID: number, shotsIntensity: number, callback: CallableFunction = () => {}) {
|
||||
setShotsIntensity(ID: number, shotsIntensity: number, callback: CallableFunction = () => { }) {
|
||||
var command = { "ID": ID, "shotsIntensity": shotsIntensity }
|
||||
var data = { "setShotsIntensity": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setAdvacedOptions(ID: number, isActiveTanker: boolean, isActiveAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => {}) {
|
||||
setAdvacedOptions(ID: number, isActiveTanker: boolean, isActiveAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => { }) {
|
||||
var command = {
|
||||
"ID": ID,
|
||||
"isActiveTanker": isActiveTanker,
|
||||
@@ -386,7 +400,7 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setCommandModeOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: {blue: number, red: number}, eras: string[], setupTime: number, callback: CallableFunction = () => {}) {
|
||||
setCommandModeOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: { blue: number, red: number }, eras: string[], setupTime: number, callback: CallableFunction = () => { }) {
|
||||
var command = {
|
||||
"restrictSpawns": restrictSpawns,
|
||||
"restrictToCoalition": restrictToCoalition,
|
||||
@@ -399,7 +413,7 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
reloadDatabases(callback: CallableFunction = () => {}) {
|
||||
reloadDatabases(callback: CallableFunction = () => { }) {
|
||||
var data = { "reloadDatabases": {} };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
@@ -430,7 +444,7 @@ export class ServerManager {
|
||||
}, 10000));
|
||||
|
||||
this.#intervals.push(window.setInterval(() => {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE){
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getBullseye((data: BullseyesData) => {
|
||||
this.checkSessionHash(data.sessionHash);
|
||||
getApp().getMissionManager()?.updateBullseyes(data);
|
||||
@@ -452,7 +466,7 @@ export class ServerManager {
|
||||
this.#intervals.push(window.setInterval(() => {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getUnits((buffer: ArrayBuffer) => {
|
||||
var time = getApp().getUnitsManager()?.update(buffer);
|
||||
var time = getApp().getUnitsManager()?.update(buffer);
|
||||
return time;
|
||||
}, false);
|
||||
}
|
||||
@@ -461,7 +475,7 @@ export class ServerManager {
|
||||
this.#intervals.push(window.setInterval(() => {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getWeapons((buffer: ArrayBuffer) => {
|
||||
var time = getApp().getWeaponsManager()?.update(buffer);
|
||||
var time = getApp().getWeaponsManager()?.update(buffer);
|
||||
return time;
|
||||
}, false);
|
||||
}
|
||||
@@ -470,18 +484,18 @@ export class ServerManager {
|
||||
this.#intervals.push(window.setInterval(() => {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getUnits((buffer: ArrayBuffer) => {
|
||||
var time = getApp().getUnitsManager()?.update(buffer);
|
||||
var time = getApp().getUnitsManager()?.update(buffer);
|
||||
return time;
|
||||
}, true);
|
||||
|
||||
const elapsedMissionTime = getApp().getMissionManager().getDateAndTime().elapsedTime;
|
||||
this.#serverIsPaused = ( elapsedMissionTime === this.#previousMissionElapsedTime );
|
||||
const elapsedMissionTime = getApp().getMissionManager().getDateAndTime().elapsedTime;
|
||||
this.#serverIsPaused = (elapsedMissionTime === this.#previousMissionElapsedTime);
|
||||
this.#previousMissionElapsedTime = elapsedMissionTime;
|
||||
|
||||
const csp = (getApp().getPanelsManager().get("connectionStatus") as ConnectionStatusPanel);
|
||||
|
||||
if ( this.getConnected() ) {
|
||||
if ( this.getServerIsPaused() ) {
|
||||
if (this.getConnected()) {
|
||||
if (this.getServerIsPaused()) {
|
||||
csp.showServerPaused();
|
||||
} else {
|
||||
csp.showConnected();
|
||||
@@ -491,29 +505,29 @@ export class ServerManager {
|
||||
}
|
||||
|
||||
}
|
||||
}, ( this.getServerIsPaused() ? 500 : 5000 )));
|
||||
}, (this.getServerIsPaused() ? 500 : 5000)));
|
||||
|
||||
// Mission clock and elapsed time
|
||||
this.#intervals.push(window.setInterval( () => {
|
||||
|
||||
if ( !this.getConnected() || this.#serverIsPaused ) {
|
||||
this.#intervals.push(window.setInterval(() => {
|
||||
|
||||
if (!this.getConnected() || this.#serverIsPaused) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elapsedMissionTime = getApp().getMissionManager().getDateAndTime().elapsedTime;
|
||||
|
||||
const csp = (getApp().getPanelsManager().get("connectionStatus") as ConnectionStatusPanel);
|
||||
const mt = getApp().getMissionManager().getDateAndTime().time;
|
||||
const mt = getApp().getMissionManager().getDateAndTime().time;
|
||||
|
||||
csp.setMissionTime( [ mt.h, mt.m, mt.s ].map( n => zeroAppend( n, 2 )).join( ":" ) );
|
||||
csp.setElapsedTime( new Date( elapsedMissionTime * 1000 ).toISOString().substring( 11, 19 ) );
|
||||
csp.setMissionTime([mt.h, mt.m, mt.s].map(n => zeroAppend(n, 2)).join(":"));
|
||||
csp.setElapsedTime(new Date(elapsedMissionTime * 1000).toISOString().substring(11, 19));
|
||||
|
||||
}, 1000));
|
||||
|
||||
this.#intervals.push(window.setInterval(() => {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getWeapons((buffer: ArrayBuffer) => {
|
||||
var time = getApp().getWeaponsManager()?.update(buffer);
|
||||
var time = getApp().getWeaponsManager()?.update(buffer);
|
||||
return time;
|
||||
}, true);
|
||||
}
|
||||
@@ -540,12 +554,12 @@ export class ServerManager {
|
||||
});
|
||||
|
||||
this.getWeapons((buffer: ArrayBuffer) => {
|
||||
var time = getApp().getWeaponsManager()?.update(buffer);
|
||||
var time = getApp().getWeaponsManager()?.update(buffer);
|
||||
return time;
|
||||
}, true);
|
||||
|
||||
this.getUnits((buffer: ArrayBuffer) => {
|
||||
var time = getApp().getUnitsManager()?.update(buffer);
|
||||
var time = getApp().getUnitsManager()?.update(buffer);
|
||||
return time;
|
||||
}, true);
|
||||
}
|
||||
@@ -587,4 +601,8 @@ export class ServerManager {
|
||||
getServerIsPaused() {
|
||||
return this.#serverIsPaused;
|
||||
}
|
||||
|
||||
getRequests() {
|
||||
return this.#requests;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export class UnitDataFileImport extends UnitDataFile {
|
||||
return { unitType: unitData.name, location: unitData.position, liveryID: "" }
|
||||
});
|
||||
|
||||
unitsManager.spawnUnits(category, unitsToSpawn, coalition, true);
|
||||
unitsManager.spawnUnits(category, unitsToSpawn, coalition, false);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
@@ -1114,7 +1294,7 @@ export class UnitsManager {
|
||||
/* Check if the city is inside the coalition area */
|
||||
if (polyContains(new LatLng(airbase.getLatLng().lat, airbase.getLatLng().lng), coalitionArea)) {
|
||||
/* Arbitrary formula to obtain a number of units */
|
||||
var pointsNumber = 2 + 40 * density / 100;
|
||||
var pointsNumber = 2 + 10 * density / 100;
|
||||
for (let i = 0; i < pointsNumber; i++) {
|
||||
/* Place the unit nearby the airbase, depending on the distribution parameter */
|
||||
var bearing = Math.random() * 360;
|
||||
@@ -1127,11 +1307,8 @@ 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) {
|
||||
this.spawnUnits("GroundUnit", [{ unitType: unitBlueprint.name, location: latlng, liveryID: "" }], coalitionArea.getCoalition(), true, "", "", (res: any) =>{
|
||||
getApp().getMap().addTemporaryMarker(latlng, unitBlueprint.name, getApp().getActiveCoalition(), res.commandHash);
|
||||
});
|
||||
}
|
||||
if (unitBlueprint)
|
||||
this.spawnUnits("GroundUnit", [{ unitType: unitBlueprint.name, location: latlng, liveryID: "" }], coalitionArea.getCoalition(), false, "", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1142,7 +1319,7 @@ export class UnitsManager {
|
||||
/* Check if the city is inside the coalition area */
|
||||
if (polyContains(new LatLng(city.lat, city.lng), coalitionArea)) {
|
||||
/* Arbitrary formula to obtain a number of units depending on the city population */
|
||||
var pointsNumber = 2 + Math.pow(city.pop, 0.2) * density / 100;
|
||||
var pointsNumber = 2 + Math.pow(city.pop, 0.15) * density / 100;
|
||||
for (let i = 0; i < pointsNumber; i++) {
|
||||
/* Place the unit nearby the city, depending on the distribution parameter */
|
||||
var bearing = Math.random() * 360;
|
||||
@@ -1155,11 +1332,8 @@ 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) {
|
||||
this.spawnUnits("GroundUnit", [{ unitType: unitBlueprint.name, location: latlng, liveryID: "" }], coalitionArea.getCoalition(), true, "", "", (res: any) =>{
|
||||
getApp().getMap().addTemporaryMarker(latlng, unitBlueprint.name, getApp().getActiveCoalition(), res.commandHash);
|
||||
});
|
||||
}
|
||||
if (unitBlueprint)
|
||||
this.spawnUnits("GroundUnit", [{ unitType: unitBlueprint.name, location: latlng, liveryID: "" }], coalitionArea.getCoalition(), false, "", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1175,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
|
||||
*/
|
||||
|
||||
@@ -52,8 +52,7 @@
|
||||
<button class="explosion-button" title="" data-on-click="contextMenuExplosion" data-on-click-params='{ "explosionType": "normal", "strength": 10 }'>Big explosion</button>
|
||||
<button class="explosion-button" title="" data-on-click="contextMenuExplosion" data-on-click-params='{ "explosionType": "phosphorous"}'>White phosphorous</button>
|
||||
<button class="explosion-button" title="" data-on-click="contextMenuExplosion" data-on-click-params='{ "explosionType": "napalm"}'>Napalm</button>
|
||||
<button class="explosion-button" title="" data-on-click="contextMenuExplosion" data-on-click-params='{ "explosionType": "secondary"}'>Explosion with secondaries</button>
|
||||
<button class="explosion-button" title="" data-on-click="contextMenuExplosion" data-on-click-params='{ "explosionType": "secondary"}'>Explosion with debries</button>
|
||||
<button class="explosion-button" title="" data-on-click="contextMenuExplosion" data-on-click-params='{ "explosionType": "fire"}'>Static fire</button>
|
||||
<button class="explosion-button" title="" data-on-click="contextMenuExplosion" data-on-click-params='{ "explosionType": "depthCharge"}'>Depth charge</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -3,13 +3,13 @@
|
||||
<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>
|
||||
|
||||
<form id="authentication-form">
|
||||
<div><h5>Username</h5> <input type="text" id="username" name="username" required autocomplete="username" placeholder="Enter username..."></div>
|
||||
<div><h5>Password</h5> <input type="password" id="password" name="password" minlength="8" required autocomplete="current-password" placeholder="Enter password..."></div>
|
||||
<div><h5>Name</h5> <input type="text" id="username" name="username" required autocomplete="username" placeholder="Enter name..."></div>
|
||||
<div><h5>Server password</h5> <input type="password" id="password" name="password" required autocomplete="current-password" placeholder="Enter server password..."></div>
|
||||
<button type="submit" id="connection-button" class="ol-button-apply">Connect</button>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
<div><button class="ol-button-white" data-on-click="deleteSelectedUnits" title="Immediately remove the unit from the simulation"><img src="/resources/theme/images/icons/trash-can-regular.svg" inject-svg>Delete</button></div>
|
||||
<div class="hr"><hr></div>
|
||||
<div><button class="ol-button-warning" data-on-click="explodeSelectedUnits" data-on-click-params='{ "type": "normal" }' title="Normal explosion"><img src="/resources/theme/images/icons/explosion-solid.svg" inject-svg>Blow up</button></div>
|
||||
<div><button class="ol-button-warning" data-on-click="explodeSelectedUnits" data-on-click-params='{ "type": "secondary" }' title="The unit will keep exploding at random intervals, simulating ammunition cooking"><img src="/resources/theme/images/icons/burst-solid.svg" inject-svg>Cook off</button></div>
|
||||
<div><button class="ol-button-warning" data-on-click="explodeSelectedUnits" data-on-click-params='{ "type": "secondary" }' title="Small explosion with debries"><img src="/resources/theme/images/icons/burst-solid.svg" inject-svg>Cook off</button></div>
|
||||
<div><button class="ol-button-warning" data-on-click="explodeSelectedUnits" data-on-click-params='{ "type": "phosphorous" }' title="White phosphorous explosion"><img src="/resources/theme/images/icons/smog-solid.svg" inject-svg>Phosp.</button></div>
|
||||
<div><button class="ol-button-warning" data-on-click="explodeSelectedUnits" data-on-click-params='{ "type": "napalm" }' title="Napalm"><img src="/resources/theme/images/icons/fire-solid.svg" inject-svg>Napalm</button></div>
|
||||
</div>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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."),
|
||||
|
||||
@@ -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')
|
||||
@@ -510,10 +513,11 @@ function Olympus.removeFire (smokeName)
|
||||
end
|
||||
|
||||
function Olympus.secondaries(vec3)
|
||||
trigger.action.explosion(vec3, 1)
|
||||
for i = 1, 10 do
|
||||
timer.scheduleFunction(Olympus.randomDebries, vec3, timer.getTime() + math.random(0, 180))
|
||||
end
|
||||
Olympus.randomDebrie(vec3)
|
||||
--trigger.action.explosion(vec3, 1)
|
||||
--for i = 1, 10 do
|
||||
-- timer.scheduleFunction(Olympus.randomDebries, vec3, timer.getTime() + math.random(0, 180))
|
||||
--end
|
||||
end
|
||||
|
||||
function Olympus.randomDebries(vec3)
|
||||
@@ -914,7 +918,7 @@ function Olympus.setTask(groupName, taskOptions)
|
||||
end
|
||||
end
|
||||
|
||||
-- Reset the dask of a group
|
||||
-- Reset the task of a group
|
||||
function Olympus.resetTask(groupName)
|
||||
Olympus.debug("Olympus.resetTask " .. groupName, 2)
|
||||
local group = Group.getByName(groupName)
|
||||
@@ -1360,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
|
||||
@@ -1401,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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "airunit.h"
|
||||
|
||||
#define AIRCRAFT_DEST_DIST_THR 2000 // Meters
|
||||
|
||||
class Aircraft : public AirUnit
|
||||
{
|
||||
public:
|
||||
@@ -11,6 +13,8 @@ public:
|
||||
virtual void changeSpeed(string change);
|
||||
virtual void changeAltitude(string change);
|
||||
|
||||
virtual double getDestinationReachedThreshold() { return AIRCRAFT_DEST_DIST_THR; }
|
||||
|
||||
protected:
|
||||
static json::value database;
|
||||
};
|
||||
@@ -17,6 +17,7 @@ public:
|
||||
|
||||
virtual void changeSpeed(string change) = 0;
|
||||
virtual void changeAltitude(string change) = 0;
|
||||
virtual double getDestinationReachedThreshold() { return AIR_DEST_DIST_THR; }
|
||||
|
||||
protected:
|
||||
virtual void AIloop();
|
||||
|
||||
@@ -124,10 +124,10 @@ public:
|
||||
taskOptions(taskOptions),
|
||||
category(category)
|
||||
{
|
||||
priority = CommandPriority::HIGH;
|
||||
priority = CommandPriority::MEDIUM;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 2; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -173,7 +173,7 @@ public:
|
||||
priority = immediate? CommandPriority::IMMEDIATE: CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return immediate? 1: 30; }
|
||||
virtual unsigned int getLoad() { return immediate? 5: 30; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -196,7 +196,7 @@ public:
|
||||
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 30; }
|
||||
virtual unsigned int getLoad() { return immediate ? 5 : 60; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -220,7 +220,7 @@ public:
|
||||
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 30; }
|
||||
virtual unsigned int getLoad() { return immediate ? 5 : 45; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -245,7 +245,7 @@ public:
|
||||
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return immediate ? 1 : 30; }
|
||||
virtual unsigned int getLoad() { return immediate ? 5 : 45; }
|
||||
|
||||
private:
|
||||
const string coalition;
|
||||
@@ -289,7 +289,7 @@ public:
|
||||
immediate = immediate;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return immediate? 1: 5; }
|
||||
virtual unsigned int getLoad() { return immediate? 1: 30; }
|
||||
|
||||
private:
|
||||
const unsigned int ID;
|
||||
@@ -310,7 +310,7 @@ public:
|
||||
priority = CommandPriority::MEDIUM;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -328,7 +328,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -346,7 +346,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -379,7 +379,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -401,7 +401,7 @@ public:
|
||||
priority = CommandPriority::HIGH;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 1; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const string groupName;
|
||||
@@ -421,7 +421,7 @@ public:
|
||||
priority = CommandPriority::MEDIUM;
|
||||
};
|
||||
virtual string getString();
|
||||
virtual unsigned int getLoad() { return 4; }
|
||||
virtual unsigned int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const Coords location;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "airunit.h"
|
||||
|
||||
#define HELICOPTER_DEST_DIST_THR 500 // Meters
|
||||
|
||||
class Helicopter : public AirUnit
|
||||
{
|
||||
public:
|
||||
@@ -11,6 +13,8 @@ public:
|
||||
virtual void changeSpeed(string change);
|
||||
virtual void changeAltitude(string change);
|
||||
|
||||
virtual double getDestinationReachedThreshold() { return HELICOPTER_DEST_DIST_THR; }
|
||||
|
||||
protected:
|
||||
static json::value database;
|
||||
};
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
void setEras(vector<string> newEras) { eras = newEras; }
|
||||
void setCommandModeOptions(json::value newOptions);
|
||||
|
||||
int getFrameRate() { return frameRate; };
|
||||
int getFrameRate() { return static_cast<int>(round(frameRate)); };
|
||||
int getLoad();
|
||||
bool getRestrictSpawns() { return restrictSpawns; }
|
||||
bool getRestrictToCoalition() { return restrictToCoalition; }
|
||||
|
||||
@@ -220,7 +220,7 @@ protected:
|
||||
virtual void AIloop() = 0;
|
||||
|
||||
void appendString(stringstream& ss, const unsigned char& datumIndex, const string& datumValue) {
|
||||
const unsigned short size = datumValue.size();
|
||||
const unsigned short size = static_cast<unsigned short>(datumValue.size());
|
||||
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||
ss.write((const char*)&size, sizeof(unsigned short));
|
||||
ss << datumValue;
|
||||
@@ -245,7 +245,7 @@ protected:
|
||||
|
||||
template <typename T>
|
||||
void appendVector(stringstream& ss, const unsigned char& datumIndex, vector<T>& datumValue) {
|
||||
const unsigned short size = datumValue.size();
|
||||
const unsigned short size = static_cast<unsigned short>(datumValue.size());
|
||||
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||
ss.write((const char*)&size, sizeof(unsigned short));
|
||||
|
||||
@@ -255,7 +255,7 @@ protected:
|
||||
|
||||
template <typename T>
|
||||
void appendList(stringstream& ss, const unsigned char& datumIndex, list<T>& datumValue) {
|
||||
const unsigned short size = datumValue.size();
|
||||
const unsigned short size = static_cast<unsigned short>(datumValue.size());;
|
||||
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||
ss.write((const char*)&size, sizeof(unsigned short));
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ protected:
|
||||
|
||||
/********** Private methods **********/
|
||||
void appendString(stringstream& ss, const unsigned char& datumIndex, const string& datumValue) {
|
||||
const unsigned short size = datumValue.size();
|
||||
const unsigned short size = static_cast<unsigned short>(datumValue.size());
|
||||
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||
ss.write((const char*)&size, sizeof(unsigned short));
|
||||
ss << datumValue;
|
||||
|
||||
@@ -34,7 +34,6 @@ Aircraft::Aircraft(json::value json, unsigned int ID) : AirUnit(json, ID)
|
||||
setCategory("Aircraft");
|
||||
setDesiredSpeed(knotsToMs(300));
|
||||
setDesiredAltitude(ftToM(20000));
|
||||
|
||||
};
|
||||
|
||||
void Aircraft::changeSpeed(string change)
|
||||
@@ -48,11 +47,6 @@ void Aircraft::changeSpeed(string change)
|
||||
|
||||
if (getDesiredSpeed() < knotsToMs(50))
|
||||
setDesiredSpeed(knotsToMs(50));
|
||||
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
}
|
||||
|
||||
void Aircraft::changeAltitude(string change)
|
||||
@@ -69,14 +63,9 @@ void Aircraft::changeAltitude(string change)
|
||||
if (getDesiredAltitude() > 5000)
|
||||
setDesiredAltitude(getDesiredAltitude() + ftToM(2500));
|
||||
else if (getDesiredAltitude() >= 0)
|
||||
setDesiredAltitude(getDesiredAltitude() + ftToM(500));
|
||||
setDesiredAltitude(getDesiredAltitude() + ftToM(500));
|
||||
}
|
||||
|
||||
if (getDesiredAltitude() < 0)
|
||||
setDesiredAltitude(0);
|
||||
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
}
|
||||
@@ -146,12 +146,15 @@ void AirUnit::setState(unsigned char newState)
|
||||
break;
|
||||
}
|
||||
|
||||
resetTask();
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
|
||||
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
|
||||
state = newState;
|
||||
|
||||
triggerUpdate(DataIndex::state);
|
||||
|
||||
AIloop();
|
||||
}
|
||||
|
||||
void AirUnit::AIloop()
|
||||
@@ -218,7 +221,7 @@ void AirUnit::AIloop()
|
||||
goToDestination(enrouteTask);
|
||||
}
|
||||
else {
|
||||
if (isDestinationReached(AIR_DEST_DIST_THR)) {
|
||||
if (isDestinationReached(getDestinationReachedThreshold())) {
|
||||
if (updateActivePath(looping) && setActiveDestination())
|
||||
goToDestination(enrouteTask);
|
||||
else
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -104,7 +104,6 @@ void GroundUnit::setState(unsigned char newState)
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
resetTask();
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA: {
|
||||
@@ -135,12 +134,15 @@ void GroundUnit::setState(unsigned char newState)
|
||||
break;
|
||||
}
|
||||
|
||||
resetTask();
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
|
||||
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
|
||||
state = newState;
|
||||
|
||||
triggerUpdate(DataIndex::state);
|
||||
|
||||
AIloop();
|
||||
}
|
||||
|
||||
void GroundUnit::AIloop()
|
||||
@@ -217,7 +219,7 @@ void GroundUnit::AIloop()
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
setTask("Simulating fire fight");
|
||||
|
||||
if (internalCounter == 0 && targetPosition != Coords(NULL)) {
|
||||
if (internalCounter == 0 && targetPosition != Coords(NULL) && scheduler->getLoad() == 0) {
|
||||
/* Get the distance and bearing to the target */
|
||||
Coords scatteredTargetPosition = targetPosition;
|
||||
double distance;
|
||||
@@ -226,7 +228,7 @@ void GroundUnit::AIloop()
|
||||
Geodesic::WGS84().Inverse(getPosition().lat, getPosition().lng, scatteredTargetPosition.lat, scatteredTargetPosition.lng, distance, bearing1, bearing2);
|
||||
|
||||
/* Compute the scattered position applying a random scatter to the shot */
|
||||
double scatterDistance = distance * tan(10 /* degs */ * (ShotsScatter::LOW - shotsScatter) / 57.29577) * RANDOM_MINUS_ONE_TO_ONE;
|
||||
double scatterDistance = distance * tan(10 /* degs */ * (ShotsScatter::LOW - shotsScatter) / 57.29577 + 2 /* degs */) * RANDOM_MINUS_ONE_TO_ONE;
|
||||
Geodesic::WGS84().Direct(scatteredTargetPosition.lat, scatteredTargetPosition.lng, bearing1 + 90, scatterDistance, scatteredTargetPosition.lat, scatteredTargetPosition.lng);
|
||||
|
||||
/* Recover the data from the database */
|
||||
@@ -257,7 +259,7 @@ void GroundUnit::AIloop()
|
||||
}
|
||||
|
||||
/* Wait an amout of time depending on the shots intensity */
|
||||
internalCounter = ((ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL;
|
||||
internalCounter = static_cast<unsigned int>(((ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL);
|
||||
}
|
||||
|
||||
if (targetPosition == Coords(NULL))
|
||||
@@ -265,7 +267,7 @@ void GroundUnit::AIloop()
|
||||
|
||||
/* Fallback if something went wrong */
|
||||
if (internalCounter == 0)
|
||||
internalCounter = 20 / FRAMERATE_TIME_INTERVAL;
|
||||
internalCounter = static_cast<unsigned int>(20 / FRAMERATE_TIME_INTERVAL);
|
||||
internalCounter--;
|
||||
|
||||
break;
|
||||
@@ -300,7 +302,7 @@ void GroundUnit::AIloop()
|
||||
}
|
||||
|
||||
if (internalCounter == 0)
|
||||
internalCounter = 20 / FRAMERATE_TIME_INTERVAL;
|
||||
internalCounter = static_cast<unsigned int>(20 / FRAMERATE_TIME_INTERVAL);
|
||||
internalCounter--;
|
||||
|
||||
break;
|
||||
@@ -390,7 +392,7 @@ void GroundUnit::AIloop()
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
|
||||
internalCounter = (aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL;
|
||||
internalCounter = static_cast<unsigned int>((aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL);
|
||||
}
|
||||
/* Else, do miss on purpose */
|
||||
else {
|
||||
@@ -412,13 +414,13 @@ void GroundUnit::AIloop()
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
|
||||
internalCounter = (aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL;
|
||||
internalCounter = static_cast<unsigned int>((aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL);
|
||||
}
|
||||
else if (distance < aimMethodRange) {
|
||||
/* If the unit is closer than the aim method range, use the aim method range */
|
||||
aimAtPoint(Coords(aimLat, aimLng, aimAlt));
|
||||
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
|
||||
internalCounter = (aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL;
|
||||
internalCounter = static_cast<unsigned int>((aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL);
|
||||
}
|
||||
else {
|
||||
/* Else just wake the unit up with an impossible command */
|
||||
@@ -431,7 +433,7 @@ void GroundUnit::AIloop()
|
||||
setTargetPosition(Coords(NULL));
|
||||
|
||||
/* Don't wait too long before checking again */
|
||||
internalCounter = 5 / FRAMERATE_TIME_INTERVAL;
|
||||
internalCounter = static_cast<unsigned int>(5 / FRAMERATE_TIME_INTERVAL);
|
||||
}
|
||||
}
|
||||
missOnPurposeTarget = target;
|
||||
@@ -450,7 +452,7 @@ void GroundUnit::AIloop()
|
||||
if (databaseEntry.has_number_field(L"alertnessTimeConstant"))
|
||||
alertnessTimeConstant = databaseEntry[L"alertnessTimeConstant"].as_number().to_double();
|
||||
}
|
||||
internalCounter = (5 + RANDOM_ZERO_TO_ONE * alertnessTimeConstant * 0 /* TODO: remove to enable alertness again */) / FRAMERATE_TIME_INTERVAL;
|
||||
internalCounter = static_cast<unsigned int>((5 + RANDOM_ZERO_TO_ONE * alertnessTimeConstant * 0 /* TODO: remove to enable alertness again */) / FRAMERATE_TIME_INTERVAL);
|
||||
missOnPurposeTarget = nullptr;
|
||||
setTargetPosition(Coords(NULL));
|
||||
}
|
||||
|
||||
@@ -41,33 +41,31 @@ void Helicopter::changeSpeed(string change)
|
||||
if (change.compare("stop") == 0)
|
||||
setState(State::IDLE);
|
||||
else if (change.compare("slow") == 0)
|
||||
desiredSpeed -= knotsToMs(10);
|
||||
setDesiredSpeed(getDesiredSpeed() - knotsToMs(10));
|
||||
else if (change.compare("fast") == 0)
|
||||
desiredSpeed += knotsToMs(10);
|
||||
if (desiredSpeed < 0)
|
||||
desiredSpeed = 0;
|
||||
setDesiredSpeed(getDesiredSpeed() + knotsToMs(10));
|
||||
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
if (getDesiredSpeed() < knotsToMs(0))
|
||||
setDesiredSpeed(knotsToMs(0));
|
||||
}
|
||||
|
||||
void Helicopter::changeAltitude(string change)
|
||||
{
|
||||
if (change.compare("descend") == 0)
|
||||
{
|
||||
if (desiredAltitude > 100)
|
||||
desiredAltitude -= ftToM(100);
|
||||
else if (desiredAltitude > 0)
|
||||
desiredAltitude -= ftToM(10);
|
||||
if (getDesiredAltitude() > 100)
|
||||
setDesiredAltitude(getDesiredAltitude() - ftToM(100));
|
||||
else if (getDesiredAltitude() > 0)
|
||||
setDesiredAltitude(getDesiredAltitude() - ftToM(10));
|
||||
}
|
||||
else if (change.compare("climb") == 0)
|
||||
{
|
||||
if (desiredAltitude > 100)
|
||||
desiredAltitude += ftToM(100);
|
||||
else if (desiredAltitude >= 0)
|
||||
desiredAltitude += ftToM(10);
|
||||
if (getDesiredAltitude() > 100)
|
||||
setDesiredAltitude(getDesiredAltitude() + ftToM(100));
|
||||
else if (getDesiredAltitude() >= 0)
|
||||
setDesiredAltitude(getDesiredAltitude() + ftToM(10));
|
||||
}
|
||||
if (desiredAltitude < 0)
|
||||
desiredAltitude = 0;
|
||||
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
}
|
||||
if (getDesiredAltitude() < 0)
|
||||
setDesiredAltitude(0);
|
||||
}
|
||||
@@ -93,34 +93,33 @@ void NavyUnit::setState(unsigned char newState)
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
resetTask();
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
resetTask();
|
||||
break;
|
||||
}
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
resetTask();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (newState != state)
|
||||
resetTask();
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
|
||||
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
|
||||
state = newState;
|
||||
|
||||
triggerUpdate(DataIndex::state);
|
||||
|
||||
AIloop();
|
||||
}
|
||||
|
||||
void NavyUnit::AIloop()
|
||||
@@ -188,15 +187,9 @@ void NavyUnit::AIloop()
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
setTask("Simulating fire fight");
|
||||
|
||||
if (!getHasTask()) {
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
// TODO
|
||||
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1}";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
}
|
||||
setState(State::IDLE);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -56,7 +56,13 @@ void Scheduler::execute(lua_State* L)
|
||||
log("Error executing command " + commandString);
|
||||
else
|
||||
log("Command '" + commandString + "' executed correctly, current load " + to_string(getLoad()));
|
||||
load = command->getLoad();
|
||||
|
||||
/* Adjust the load depending on the fps */
|
||||
double fpsMultiplier = 20;
|
||||
if (getFrameRate() + 3 > 0)
|
||||
fpsMultiplier = static_cast<unsigned int>(max(1, 60 / (getFrameRate() + 3))); /* Multiplier between 1 and 20 */
|
||||
|
||||
load = static_cast<unsigned int>(command->getLoad() * fpsMultiplier);
|
||||
commands.remove(command);
|
||||
executedCommandsHashes.push_back(command->getHash());
|
||||
command->executeCallback(); /* Execute the command callback (this is a lambda function that can be used to execute a function when the command is run) */
|
||||
@@ -82,7 +88,7 @@ void Scheduler::setCommandModeOptions(json::value value) {
|
||||
setRedSpawnPoints(value[L"spawnPoints"][L"red"].as_number().to_int32());
|
||||
}
|
||||
if (value.has_array_field(L"eras")) {
|
||||
int length = value[L"eras"].as_array().size();
|
||||
int length = static_cast<int>(value[L"eras"].as_array().size());
|
||||
vector<string> newEras;
|
||||
for (int idx = 0; idx < length; idx++)
|
||||
newEras.push_back(to_string(value[L"eras"].as_array().at(idx)));
|
||||
@@ -132,6 +138,8 @@ bool Scheduler::checkSpawnPoints(int spawnPoints, string coalition)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Scheduler::handleRequest(string key, json::value value, string username, json::value& answer)
|
||||
@@ -254,7 +262,7 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
unsigned int leaderID = value[L"targetID"].as_double();
|
||||
unsigned int leaderID = value[L"targetID"].as_integer();
|
||||
double offsetX = value[L"offsetX"].as_double();
|
||||
double offsetY = value[L"offsetY"].as_double();
|
||||
double offsetZ = value[L"offsetZ"].as_double();
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ void Server::handle_get(http_request request)
|
||||
try {
|
||||
time = stoull((*(query.find(L"time"))).second);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
catch (...) {
|
||||
time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,7 +430,11 @@ void Unit::resetTask()
|
||||
void Unit::setFormationOffset(Offset newFormationOffset)
|
||||
{
|
||||
formationOffset = newFormationOffset;
|
||||
resetTask();
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::formationOffset);
|
||||
}
|
||||
@@ -519,7 +523,11 @@ void Unit::setIsActiveTanker(bool newIsActiveTanker)
|
||||
{
|
||||
if (isActiveTanker != newIsActiveTanker) {
|
||||
isActiveTanker = newIsActiveTanker;
|
||||
resetTask();
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::isActiveTanker);
|
||||
}
|
||||
@@ -529,7 +537,11 @@ void Unit::setIsActiveAWACS(bool newIsActiveAWACS)
|
||||
{
|
||||
if (isActiveAWACS != newIsActiveAWACS) {
|
||||
isActiveAWACS = newIsActiveAWACS;
|
||||
resetTask();
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::isActiveAWACS);
|
||||
}
|
||||
@@ -644,10 +656,11 @@ void Unit::setDesiredSpeed(double newDesiredSpeed)
|
||||
{
|
||||
if (desiredSpeed != newDesiredSpeed) {
|
||||
desiredSpeed = newDesiredSpeed;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::desiredSpeed);
|
||||
}
|
||||
@@ -657,10 +670,11 @@ void Unit::setDesiredAltitude(double newDesiredAltitude)
|
||||
{
|
||||
if (desiredAltitude != newDesiredAltitude) {
|
||||
desiredAltitude = newDesiredAltitude;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::desiredAltitude);
|
||||
}
|
||||
@@ -670,10 +684,11 @@ void Unit::setDesiredSpeedType(string newDesiredSpeedType)
|
||||
{
|
||||
if (desiredSpeedType != (newDesiredSpeedType.compare("GS") == 0)) {
|
||||
desiredSpeedType = newDesiredSpeedType.compare("GS") == 0;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::desiredSpeedType);
|
||||
}
|
||||
@@ -683,10 +698,11 @@ void Unit::setDesiredAltitudeType(string newDesiredAltitudeType)
|
||||
{
|
||||
if (desiredAltitudeType != (newDesiredAltitudeType.compare("AGL") == 0)) {
|
||||
desiredAltitudeType = newDesiredAltitudeType.compare("AGL") == 0;
|
||||
if (state == State::IDLE)
|
||||
resetTask();
|
||||
else
|
||||
goToDestination(); /* Send the command to reach the destination */
|
||||
|
||||
/* Apply the change */
|
||||
setHasTask(false);
|
||||
resetTaskFailedCounter();
|
||||
AIloop();
|
||||
|
||||
triggerUpdate(DataIndex::desiredAltitudeType);
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ void getAllUnits(lua_State* L, map<unsigned int, json::value>& unitJSONs)
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, 2) != 0)
|
||||
{
|
||||
unsigned int ID = lua_tonumber(L, -2);
|
||||
unsigned int ID = static_cast<unsigned int>(lua_tonumber(L, -2));
|
||||
if (unitJSONs.find(ID) == unitJSONs.end())
|
||||
unitJSONs[ID] = json::value::object();
|
||||
luaTableToJSON(L, -1, unitJSONs[ID]);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
BIN
src/olympus/olympus.aps
Normal file
Binary file not shown.
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
4
third-party/base64/include/base64.hpp
vendored
4
third-party/base64/include/base64.hpp
vendored
@@ -18,7 +18,7 @@ namespace base64 {
|
||||
uint32_t bit_stream = 0;
|
||||
const std::string base64_chars = get_base64_chars();
|
||||
std::string encoded;
|
||||
encoded.reserve(ceil(4.0 / 3.0 * size));
|
||||
encoded.reserve(static_cast<unsigned long>(ceil(4.0 / 3.0 * size)));
|
||||
int offset = 0;
|
||||
for (unsigned int idx = 0; idx < size; idx++) {
|
||||
unsigned char c = data[idx];
|
||||
@@ -63,7 +63,7 @@ namespace base64 {
|
||||
auto num_val = base64_chars.find(c);
|
||||
if (num_val != std::string::npos) {
|
||||
offset = 18 - counter % 4 * 6;
|
||||
bit_stream += num_val << offset;
|
||||
bit_stream += static_cast<uint32_t>(num_val << offset);
|
||||
if (offset == 12) {
|
||||
decoded += static_cast<char>(bit_stream >> 16 & 0xff);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"version": "v0.4.9-alpha-rc1"
|
||||
"version": "v0.4.11-alpha-rc3"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user