Split client into frontend website and server

This commit is contained in:
Pax1601
2024-02-08 22:04:23 +01:00
parent 55f3bd5adb
commit 5ca6c97cbe
792 changed files with 149898 additions and 13872 deletions

View File

@@ -0,0 +1,8 @@
mkdir .\\..\\DCSOlympus\\client\\public\\plugins\\boilerplateplugin
copy .\\index.js .\\..\\DCSOlympus\\client\\public\\plugins\\boilerplateplugin\\index.js
copy .\\plugin.json .\\..\\DCSOlympus\\client\\public\\plugins\\boilerplateplugin\\plugin.json
copy .\\style.css .\\..\\DCSOlympus\\client\\public\\plugins\\boilerplateplugin\\style.css
mkdir .\\..\\DCSOlympus\\client\\public\\plugins\\boilerplateplugin\\images
copy .\\images\\*.* .\\..\\DCSOlympus\\client\\public\\plugins\\boilerplateplugin\\images\\

Binary file not shown.

After

Width:  |  Height:  |  Size: 928 B

View File

@@ -0,0 +1,14 @@
{
"name": "boilerplateplugin",
"version": "v0.0.1",
"private": true,
"scripts": {
"build": "browserify ./src/index.ts -p [ tsify --noImplicitAny] > index.js && copy.bat"
},
"devDependencies": {
"@types/sortablejs": "^1.15.4",
"browserify": "^17.0.0",
"sortablejs": "^1.15.0",
"tsify": "^5.0.4"
}
}

View File

@@ -0,0 +1,7 @@
{
"name": "Boilerplate",
"version": "0.0.1",
"description": "Base plugin starter",
"authorName": "",
"authorContact": ""
}

View File

@@ -0,0 +1,3 @@
# Boilerplate plugin
See: https://github.com/Pax1601/DCSOlympus/wiki/Developer-Guide

View File

@@ -0,0 +1,27 @@
import { OlympusPlugin } from "interfaces";
import { OlympusApp } from "olympusapp";
export class BoilerplatePlugin implements OlympusPlugin {
#app!: OlympusApp;
constructor() {
}
/**
* @param app <OlympusApp>
*
* @returns boolean on success/fail
*/
initialize(app: OlympusApp) : boolean {
this.#app = app;
return true; // Return true on success
}
getName() {
return "Boilerplate";
}
}

View File

@@ -0,0 +1,5 @@
import { BoilerplatePlugin } from "./boilerplate";
globalThis.getOlympusPlugin = () => {
return new BoilerplatePlugin();
}

View File

@@ -0,0 +1,104 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "ES2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
"rootDirs": ["./src", "./@types"], /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
"typeRoots": [
"./node_modules/@types",
"@types"
], /* Specify multiple folders that act like './node_modules/@types'. */
"types": [
"olympus"
], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": [
"src/*.ts",
"../DCSOlympus/client/@types/olympus/index.d.ts"
]
}

View File

@@ -0,0 +1,5 @@
mkdir .\\..\\..\\public\\plugins\\controltipsplugin
copy .\\index.js .\\..\\..\\public\\plugins\\controltipsplugin\\index.js
copy .\\plugin.json .\\..\\..\\public\\plugins\\controltipsplugin\\plugin.json
copy .\\style.css .\\..\\..\\public\\plugins\\controltipsplugin\\style.css

View File

@@ -0,0 +1,377 @@
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _ControlTipsPlugin_instances, _ControlTipsPlugin_element, _ControlTipsPlugin_app, _ControlTipsPlugin_shortcutManager, _ControlTipsPlugin_cursorIsHoveringOverUnit, _ControlTipsPlugin_cursorIsHoveringOverAirbase, _ControlTipsPlugin_mouseoverElement, _ControlTipsPlugin_updateTips;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ControlTipsPlugin = void 0;
const SHOW_CONTROL_TIPS = "Show control tips";
class ControlTipsPlugin {
constructor() {
_ControlTipsPlugin_instances.add(this);
_ControlTipsPlugin_element.set(this, void 0);
_ControlTipsPlugin_app.set(this, void 0);
_ControlTipsPlugin_shortcutManager.set(this, void 0);
_ControlTipsPlugin_cursorIsHoveringOverUnit.set(this, false);
_ControlTipsPlugin_cursorIsHoveringOverAirbase.set(this, false);
_ControlTipsPlugin_mouseoverElement.set(this, void 0);
__classPrivateFieldSet(this, _ControlTipsPlugin_element, document.createElement("div"), "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_element, "f").id = "control-tips-panel";
document.body.appendChild(__classPrivateFieldGet(this, _ControlTipsPlugin_element, "f"));
}
getName() {
return "Control Tips Plugin";
}
initialize(app) {
__classPrivateFieldSet(this, _ControlTipsPlugin_app, app, "f");
__classPrivateFieldSet(this, _ControlTipsPlugin_shortcutManager, __classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getShortcutManager(), "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_shortcutManager, "f").onKeyDown(() => {
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
__classPrivateFieldGet(this, _ControlTipsPlugin_shortcutManager, "f").onKeyUp(() => {
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("airbaseMouseover", (ev) => {
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, true, "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("airbaseMouseout", (ev) => {
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, false, "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("unitDeselection", (ev) => {
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("unitMouseover", (ev) => {
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, true, "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("unitMouseout", (ev) => {
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, false, "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("unitsSelection", (ev) => {
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("mapOptionsChanged", () => {
this.toggle(!__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getMap().getVisibilityOptions()[SHOW_CONTROL_TIPS]);
});
document.addEventListener("mouseover", (ev) => {
if (ev.target instanceof HTMLElement) {
__classPrivateFieldSet(this, _ControlTipsPlugin_mouseoverElement, ev.target, "f");
}
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("mouseup", (ev) => {
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getMap().addVisibilityOption(SHOW_CONTROL_TIPS, true);
return true;
}
getElement() {
return __classPrivateFieldGet(this, _ControlTipsPlugin_element, "f");
}
toggle(bool) {
this.getElement().classList.toggle("hide", bool);
}
}
exports.ControlTipsPlugin = ControlTipsPlugin;
_ControlTipsPlugin_element = new WeakMap(), _ControlTipsPlugin_app = new WeakMap(), _ControlTipsPlugin_shortcutManager = new WeakMap(), _ControlTipsPlugin_cursorIsHoveringOverUnit = new WeakMap(), _ControlTipsPlugin_cursorIsHoveringOverAirbase = new WeakMap(), _ControlTipsPlugin_mouseoverElement = new WeakMap(), _ControlTipsPlugin_instances = new WeakSet(), _ControlTipsPlugin_updateTips = function _ControlTipsPlugin_updateTips() {
const combos = [
{
"keys": [],
"tips": [
{
"key": `SHIFT`,
"action": `Box select`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": false
},
{
"key": `Mouse1`,
"action": `Deselect`,
"showIfUnitSelected": true
},
{
"key": `Mouse1+drag`,
"action": `Move map`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": false
},
{
"key": `Mouse2`,
"action": `Spawn menu`,
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse2`,
"action": `Airbase menu`,
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": true,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse2`,
"action": `Set first waypoint`,
"showIfHoveringOverAirbase": false,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2 (hold)`,
"action": `Interact (ground)`,
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"unitsMustBeControlled": true
},
{
"key": `Shift`,
"action": "<em> in formation...</em>",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": "CTRL",
"action": "<em> ... more</em>",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"unitsMustBeControlled": true
},
{
"key": "CTRL",
"action": " Pin tool",
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"unitsMustBeControlled": true
},
{
"key": "CTRL+Mouse2",
"action": " Airbase menu",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse1`,
"action": "Toggle Blue/Red",
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
},
{
"key": `Mouse2`,
"action": "Set Neutral",
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
},
{
"key": `Mouse1`,
"action": "Toggle time display",
"mouseoverSelector": "#connection-status-panel[data-is-connected] #connection-status-message abbr"
},
{
"key": `Mouse1 or Z`,
"action": "Change location system",
"mouseoverSelector": "#coordinates-tool, #coordinates-tool *"
},
{
"key": `Comma`,
"action": "Decrease precision",
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
},
{
"key": `Period`,
"action": "Increase precision",
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
}
]
},
{
"keys": ["ControlLeft"],
"tips": [
{
"key": `Mouse1`,
"action": "Toggle pin",
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse1`,
"action": "Toggle selection",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": true
},
{
"key": `Mouse2`,
"action": `Add waypoint`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2`,
"action": `Interact (airbase)`,
"showIfHoveringOverAirbase": true,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2`,
"action": `Interact (unit)`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": true,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Shift`,
"action": "<em> in formation...</em>",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": `[Num 1-9]`,
"action": "Set hotgroup",
"showIfUnitSelected": true
}
]
},
{
"keys": ["ShiftLeft"],
"tips": [
{
"key": `Mouse1+drag`,
"action": "Box select",
"showIfUnitSelected": false
},
{
"key": `Mouse2`,
"action": "Set first formation waypoint",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": `[Num 1-9]`,
"action": "Add to hotgroup",
"showIfUnitSelected": true
},
{
"key": "CTRL",
"action": "<em> ... more</em>",
"minSelectedUnits": 2,
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"unitsMustBeControlled": true
}
]
},
{
"keys": ["ControlLeft", "ShiftLeft"],
"tips": [
{
"key": `Mouse2`,
"action": "Add formation waypoint",
"showIfUnitSelected": true,
"minSelectedUnits": 2,
"unitsMustBeControlled": true
}, {
"key": `[Num 1-9]`,
"action": "Add hotgroup to selection",
"callback": (tip) => {
return (Object.values(__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getUnitsManager().getUnits()).some((unit) => {
return unit.getAlive() && unit.getControlled() && unit.getHotgroup();
}));
},
"showIfUnitSelected": true,
"minSelectedUnits": 1
}
]
}
];
const currentCombo = combos.find((combo) => __classPrivateFieldGet(this, _ControlTipsPlugin_shortcutManager, "f").keyComboMatches(combo.keys)) || combos[0];
const element = this.getElement();
element.innerHTML = "";
let numSelectedUnits = 0;
let numSelectedControlledUnits = 0;
let unitSelectionContainsControlled = false;
if (__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getUnitsManager()) {
let selectedUnits = Object.values(__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getUnitsManager().getSelectedUnits());
numSelectedUnits = selectedUnits.length;
numSelectedControlledUnits = selectedUnits.filter((unit) => unit.getControlled()).length;
unitSelectionContainsControlled = numSelectedControlledUnits > 0;
}
const tipsIncludesActiveMouseover = (currentCombo.tips.some((tip) => {
if (!tip.mouseoverSelector) {
return false;
}
if (__classPrivateFieldGet(this, _ControlTipsPlugin_mouseoverElement, "f") instanceof HTMLElement === false) {
return false;
}
if (!__classPrivateFieldGet(this, _ControlTipsPlugin_mouseoverElement, "f").matches(tip.mouseoverSelector)) {
return false;
}
return true;
}));
currentCombo.tips.filter((tip) => {
if (numSelectedUnits > 0) {
if (tip.showIfUnitSelected === false) {
return false;
}
if (tip.unitsMustBeControlled === true && unitSelectionContainsControlled === false) {
return false;
}
if (typeof tip.minSelectedUnits === "number" && numSelectedControlledUnits < tip.minSelectedUnits) {
return false;
}
}
if (numSelectedUnits === 0 && tip.showIfUnitSelected === true) {
return false;
}
if (typeof tip.showIfHoveringOverAirbase === "boolean") {
if (tip.showIfHoveringOverAirbase !== __classPrivateFieldGet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, "f")) {
return false;
}
}
if (typeof tip.showIfHoveringOverUnit === "boolean") {
if (tip.showIfHoveringOverUnit !== __classPrivateFieldGet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, "f")) {
return false;
}
}
if (tipsIncludesActiveMouseover && (typeof tip.mouseoverSelector !== "string" || !__classPrivateFieldGet(this, _ControlTipsPlugin_mouseoverElement, "f").matches(tip.mouseoverSelector))) {
return false;
}
if (!tipsIncludesActiveMouseover && typeof tip.mouseoverSelector === "string") {
return false;
}
if (typeof tip.callback === "function" && !tip.callback(tip)) {
return false;
}
element.innerHTML += `<div><span class="key">${tip.key}</span><span class="action">${tip.action}</span></div>`;
});
};
},{}],2:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const controltipsplugin_1 = require("./controltipsplugin");
globalThis.getOlympusPlugin = () => {
return new controltipsplugin_1.ControlTipsPlugin();
};
},{"./controltipsplugin":1}]},{},[2]);

View File

@@ -0,0 +1,29 @@
{
"name": "ControlTipsPlugin",
"version": "v0.0.1",
"private": true,
"scripts": {
"build": "browserify ./src/index.ts -p [ tsify --noImplicitAny] > index.js && copy.bat",
"build-release": "browserify ./src/index.ts -p [ tsify --noImplicitAny] > index.js && copy.bat"
},
"dependencies": {},
"devDependencies": {
"@babel/preset-env": "^7.21.4",
"@types/node": "^18.16.1",
"@types/sortablejs": "^1.15.0",
"babelify": "^10.0.0",
"browserify": "^17.0.0",
"concurrently": "^7.6.0",
"cp": "^0.2.0",
"esmify": "^2.1.1",
"nodemon": "^2.0.20",
"requirejs": "^2.3.6",
"sortablejs": "^1.15.0",
"tinyify": "^4.0.0",
"tsify": "^5.0.4",
"tslib": "latest",
"typescript": "^4.9.4",
"usng.js": "^0.4.5",
"watchify": "^4.0.0"
}
}

View File

@@ -0,0 +1,6 @@
{
"name": "Control Tip Plugin",
"version": "0.0.1",
"description": "This plugin shows useful control tips on the right side of the screen. The tips change dynamically depending on what the user does",
"author": "Peekaboo"
}

View File

@@ -0,0 +1,396 @@
import { OlympusPlugin } from "interfaces";
import { OlympusApp } from "olympusapp";
import { Unit } from "unit/unit";
const SHOW_CONTROL_TIPS = "Show control tips"
export class ControlTipsPlugin implements OlympusPlugin {
#element: HTMLElement;
#app: any;
#shortcutManager: any;
#cursorIsHoveringOverUnit: boolean = false;
#cursorIsHoveringOverAirbase: boolean = false;
#mouseoverElement!: HTMLElement;
constructor() {
this.#element = document.createElement("div");
this.#element.id = "control-tips-panel";
document.body.appendChild(this.#element);
}
getName() {
return "Control Tips Plugin"
}
initialize(app: any) {
this.#app = app;
this.#shortcutManager = this.#app.getShortcutManager();
this.#shortcutManager.onKeyDown(() => {
this.#updateTips()
});
this.#shortcutManager.onKeyUp(() => {
this.#updateTips()
});
document.addEventListener("airbaseMouseover", (ev: CustomEventInit) => {
this.#cursorIsHoveringOverAirbase = true;
this.#updateTips();
});
document.addEventListener("airbaseMouseout", (ev: CustomEventInit) => {
this.#cursorIsHoveringOverAirbase = false;
this.#updateTips();
});
document.addEventListener("unitDeselection", (ev: CustomEventInit ) => {
this.#updateTips();
});
document.addEventListener("unitMouseover", (ev: CustomEventInit) => {
this.#cursorIsHoveringOverUnit = true;
this.#updateTips();
});
document.addEventListener("unitMouseout", (ev: CustomEventInit) => {
this.#cursorIsHoveringOverUnit = false;
this.#updateTips();
});
document.addEventListener("unitsSelection", (ev: CustomEventInit ) => {
this.#updateTips();
});
document.addEventListener("mapOptionsChanged", () => {
this.toggle( !this.#app.getMap().getVisibilityOptions()[SHOW_CONTROL_TIPS] );
});
document.addEventListener( "mouseover", ( ev: MouseEvent ) => {
if ( ev.target instanceof HTMLElement ) {
this.#mouseoverElement = <HTMLElement>ev.target;
}
this.#updateTips();
});
document.addEventListener( "mouseup", ( ev: MouseEvent ) => {
this.#updateTips();
});
this.#updateTips();
this.#app.getMap().addVisibilityOption(SHOW_CONTROL_TIPS, true);
return true;
}
getElement() {
return this.#element;
}
toggle(bool?: boolean) {
this.getElement().classList.toggle("hide", bool);
}
#updateTips() {
const combos: Array<object> = [
{
"keys": [],
"tips": [
{
"key": `SHIFT`,
"action": `Box select`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": false
},
{
"key": `Mouse1`,
"action": `Deselect`,
"showIfUnitSelected": true
},
{
"key": `Mouse1+drag`,
"action": `Move map`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": false
},
{
"key": `Mouse2`,
"action": `Spawn menu`,
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse2`,
"action": `Airbase menu`,
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": true,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse2`,
"action": `Set first waypoint`,
"showIfHoveringOverAirbase": false,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2 (hold)`,
"action": `Interact (ground)`,
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"unitsMustBeControlled": true
},
{
"key": `Shift`,
"action": "<em> in formation...</em>",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": "CTRL",
"action": "<em> ... more</em>",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"unitsMustBeControlled": true
},
{
"key": "CTRL",
"action": " Pin tool",
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"unitsMustBeControlled": true
},
{
"key": "CTRL+Mouse2",
"action": " Airbase menu",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse1`,
"action": "Toggle Blue/Red",
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
},
{
"key": `Mouse2`,
"action": "Set Neutral",
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
},
{
"key": `Mouse1`,
"action": "Toggle time display",
"mouseoverSelector": "#connection-status-panel[data-is-connected] #connection-status-message abbr"
},
{
"key": `Mouse1 or Z`,
"action": "Change location system",
"mouseoverSelector": "#coordinates-tool, #coordinates-tool *"
},
{
"key": `Comma`,
"action": "Decrease precision",
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
},
{
"key": `Period`,
"action": "Increase precision",
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
}
]
},
{
"keys": ["ControlLeft"],
"tips": [
{
"key": `Mouse1`,
"action": "Toggle pin",
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse1`,
"action": "Toggle selection",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": true
},
{
"key": `Mouse2`,
"action": `Add waypoint`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2`,
"action": `Interact (airbase)`,
"showIfHoveringOverAirbase": true,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2`,
"action": `Interact (unit)`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": true,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Shift`,
"action": "<em> in formation...</em>",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": `[Num 1-9]`,
"action": "Set hotgroup",
"showIfUnitSelected": true
}
]
},
{
"keys": ["ShiftLeft"],
"tips": [
{
"key": `Mouse1+drag`,
"action": "Box select",
"showIfUnitSelected": false
},
{
"key": `Mouse2`,
"action": "Set first formation waypoint",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": `[Num 1-9]`,
"action": "Add to hotgroup",
"showIfUnitSelected": true
},
{
"key": "CTRL",
"action": "<em> ... more</em>",
"minSelectedUnits": 2,
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"unitsMustBeControlled": true
}
]
},
{
"keys": ["ControlLeft", "ShiftLeft"],
"tips": [
{
"key": `Mouse2`,
"action": "Add formation waypoint",
"showIfUnitSelected": true,
"minSelectedUnits": 2,
"unitsMustBeControlled": true
}, {
"key": `[Num 1-9]`,
"action": "Add hotgroup to selection",
"callback": ( tip:object ) => {
return (Object.values<Unit>( this.#app.getUnitsManager().getUnits() ).some( ( unit:Unit ) => {
return unit.getAlive() && unit.getControlled() && unit.getHotgroup();
}));
},
"showIfUnitSelected": true,
"minSelectedUnits": 1
}
]
}
];
const currentCombo: any = combos.find((combo: any) => this.#shortcutManager.keyComboMatches(combo.keys)) || combos[0];
const element = this.getElement();
element.innerHTML = "";
let numSelectedUnits = 0;
let numSelectedControlledUnits = 0;
let unitSelectionContainsControlled = false;
if (this.#app.getUnitsManager()) {
let selectedUnits = Object.values(this.#app.getUnitsManager().getSelectedUnits());
numSelectedUnits = selectedUnits.length;
numSelectedControlledUnits = selectedUnits.filter((unit: any) => unit.getControlled()).length;
unitSelectionContainsControlled = numSelectedControlledUnits > 0;
}
const tipsIncludesActiveMouseover = ( currentCombo.tips.some( ( tip:any ) => {
if ( !tip.mouseoverSelector ) {
return false;
}
if ( this.#mouseoverElement instanceof HTMLElement === false ) {
return false;
}
if ( !this.#mouseoverElement.matches( tip.mouseoverSelector ) ) {
return false;
}
return true;
}));
currentCombo.tips.filter((tip: any) => {
if (numSelectedUnits > 0) {
if (tip.showIfUnitSelected === false) {
return false;
}
if (tip.unitsMustBeControlled === true && unitSelectionContainsControlled === false) {
return false;
}
if ( typeof tip.minSelectedUnits === "number" && numSelectedControlledUnits < tip.minSelectedUnits ) {
return false;
}
}
if (numSelectedUnits === 0 && tip.showIfUnitSelected === true) {
return false;
}
if (typeof tip.showIfHoveringOverAirbase === "boolean") {
if (tip.showIfHoveringOverAirbase !== this.#cursorIsHoveringOverAirbase) {
return false;
}
}
if (typeof tip.showIfHoveringOverUnit === "boolean") {
if (tip.showIfHoveringOverUnit !== this.#cursorIsHoveringOverUnit) {
return false;
}
}
if ( tipsIncludesActiveMouseover && ( typeof tip.mouseoverSelector !== "string" || !this.#mouseoverElement.matches( tip.mouseoverSelector ) ) ) {
return false;
}
if ( !tipsIncludesActiveMouseover && typeof tip.mouseoverSelector === "string" ) {
return false;
}
if ( typeof tip.callback === "function" && !tip.callback( tip ) ) {
return false;
}
element.innerHTML += `<div><span class="key">${tip.key}</span><span class="action">${tip.action}</span></div>`;
});
}
}

View File

@@ -0,0 +1,5 @@
import { ControlTipsPlugin } from "./controltipsplugin";
globalThis.getOlympusPlugin = () => {
return new ControlTipsPlugin();
}

View File

@@ -0,0 +1,33 @@
#control-tips-panel {
align-self: center;
display: flex;
flex-flow: column wrap;
font-size: 13px;
justify-self: flex-end;
position: absolute;
right: 10px;
row-gap: 20px;
text-align: right;
z-index: 999;
}
#control-tips-panel>* {
align-items: center;
align-self: end;
background-color: var(--background-steel);
border-radius: var(--border-radius-md);
color: white;
column-gap: 8px;
display: flex;
justify-items: right;
opacity: .9;
padding: 5px;
width: fit-content;
}
#control-tips-panel>*>.key {
background-color: var(--background-grey);
border-radius: var(--border-radius-sm);
color: white;
padding: 1px 4px;
}

View File

@@ -0,0 +1,104 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "ES2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
"rootDirs": ["./src", "../../@types"], /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
"typeRoots": [
"./node_modules/@types",
"../../@types"
], /* Specify multiple folders that act like './node_modules/@types'. */
"types": [
"olympus"
], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": [
"src/*.ts",
"../../@types/olympus/*.d.ts"
]
}

View File

@@ -0,0 +1,20 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Chrome",
"port": 9222,
"urlFilter": "http://localhost:3000/*",
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}../../public/",
"sourceMapPathOverrides": {
"src/*": "src/*"
},
"preLaunchTask": "start"
}
]
}

View File

@@ -0,0 +1,13 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "start",
"type": "shell",
"command": "npm run start",
"isBackground": true
}
]
}

View File

@@ -0,0 +1,5 @@
mkdir .\\..\\..\\public\\plugins\\databasemanager
copy .\\index.js .\\..\\..\\public\\plugins\\databasemanager\\index.js
copy .\\plugin.json .\\..\\..\\public\\plugins\\databasemanager\\plugin.json
copy .\\style.css .\\..\\..\\public\\plugins\\databasemanager\\style.css

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,32 @@
{
"name": "DatabaseManagerPlugin",
"version": "v0.0.1",
"private": true,
"scripts": {
"build": "browserify ./src/index.ts -p [ tsify --noImplicitAny] > index.js && copy.bat",
"build-release": "browserify ./src/index.ts -p [ tsify --noImplicitAny] -p [ tinyify ] > index.js && copy.bat",
"start": "npm run copy & concurrently --kill-others \"npm run watch\"",
"copy": "copy.bat",
"watch": "watchify ./src/index.ts --debug -o ../../public/plugins/databasemanager/index.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js']"
},
"dependencies": {},
"devDependencies": {
"@babel/preset-env": "^7.21.4",
"@types/node": "^18.16.1",
"@types/sortablejs": "^1.15.0",
"babelify": "^10.0.0",
"browserify": "^17.0.0",
"concurrently": "^7.6.0",
"cp": "^0.2.0",
"esmify": "^2.1.1",
"nodemon": "^2.0.20",
"requirejs": "^2.3.6",
"sortablejs": "^1.15.0",
"tinyify": "^4.0.0",
"tsify": "^5.0.4",
"tslib": "latest",
"typescript": "^4.9.4",
"usng.js": "^0.4.5",
"watchify": "^4.0.0"
}
}

View File

@@ -0,0 +1,6 @@
{
"name": "Control Tip Plugin",
"version": "0.0.1",
"description": "This plugin shows useful control tips on the right side of the screen. The tips change dynamically depending on what the user does",
"author": "Peekaboo"
}

View File

@@ -0,0 +1,110 @@
import { LoadoutBlueprint, UnitBlueprint } from "interfaces";
import { UnitEditor } from "./uniteditor";
import { LoadoutEditor } from "./loadouteditor";
import { addCheckboxInput, addDropdownInput, addLoadoutsScroll, addNewElementInput, addStringInput } from "./utils";
/** Database editor for Air Units, both Aircraft and Helicopter since they are identical in terms of datbase entries.
*
*/
export class AirUnitEditor extends UnitEditor {
#loadoutEditor: LoadoutEditor | null = null;
constructor(contentDiv1: HTMLElement, contentDiv2: HTMLElement, contentDiv3: HTMLElement) {
super(contentDiv1, contentDiv2, contentDiv3);
/* The loadout editor allows to edit the loadout (who could have thought eh?) */
this.#loadoutEditor = new LoadoutEditor(this.contentDiv3);
/* Refresh the loadout editor if needed */
this.contentDiv3.addEventListener("refresh", () => {
if (this.visible)
this.#loadoutEditor?.show();
});
}
/** Sets a unit blueprint as the currently active one
*
* @param blueprint The blueprint to edit
*/
setBlueprint(blueprint: UnitBlueprint) {
this.blueprint = blueprint;
if (this.blueprint !== null) {
this.contentDiv2.replaceChildren();
var title = document.createElement("label");
title.innerText = "Unit properties";
this.contentDiv2.appendChild(title);
addStringInput(this.contentDiv2, "Name", blueprint.name, "text", (value: string) => { blueprint.name = value; }, true);
addStringInput(this.contentDiv2, "Label", blueprint.label, "text", (value: string) => { blueprint.label = value; });
addStringInput(this.contentDiv2, "Short label", blueprint.shortLabel, "text", (value: string) => { blueprint.shortLabel = value; });
addDropdownInput(this.contentDiv2, "Coalition", blueprint.coalition, ["", "blue", "red"], (value: string) => {blueprint.coalition = value; });
addDropdownInput(this.contentDiv2, "Era", blueprint.era, ["WW2", "Early Cold War", "Mid Cold War", "Late Cold War", "Modern"], (value: string) => {blueprint.era = value; });
addStringInput(this.contentDiv2, "Filename", blueprint.filename ?? "", "text", (value: string) => { blueprint.filename = value; });
addStringInput(this.contentDiv2, "Cost", String(blueprint.cost) ?? "", "number", (value: string) => { blueprint.cost = parseFloat(value); });
addCheckboxInput(this.contentDiv2, "Can target point", blueprint.canTargetPoint ?? false, (value: boolean) => {blueprint.canTargetPoint = value;})
addStringInput(this.contentDiv2, "Description", blueprint.description ?? "", "text", (value: string) => {blueprint.description = value; });
addStringInput(this.contentDiv2, "Tags", blueprint.tags ?? "", "text", (value: string) => {blueprint.tags = value; });
/* Add a scrollable list of loadouts that the user can edit */
var title = document.createElement("label");
title.innerText = "Loadouts";
this.contentDiv2.appendChild(title);
addLoadoutsScroll(this.contentDiv2, blueprint.loadouts ?? [], (loadout: LoadoutBlueprint) => {
this.#loadoutEditor?.setLoadout(loadout);
this.#loadoutEditor?.show();
});
addNewElementInput(this.contentDiv2, (ev: MouseEvent, input: HTMLInputElement) => { this.addLoadout(input.value); });
this.#loadoutEditor?.hide();
}
}
/** Add a new empty blueprint
*
* @param key Blueprint key
*/
addBlueprint(key: string) {
if (this.database != null) {
this.database.blueprints[key] = {
name: key,
coalition: "",
label: "",
shortLabel: "",
era: "",
loadouts: [],
enabled: true
}
this.show();
this.setBlueprint(this.database.blueprints[key]);
}
}
/** Add a new empty loadout to the currently active blueprint
*
* @param loadoutName The name of the new loadout
*/
addLoadout(loadoutName: string) {
if (loadoutName && this.blueprint !== null) {
this.blueprint.loadouts?.push({
name: loadoutName,
code: "",
fuel: 1,
items: [],
roles: [],
enabled: true
})
this.setBlueprint(this.blueprint);
}
}
/** Hide the editor
*
*/
hide() {
super.hide();
this.#loadoutEditor?.hide();
}
}

View File

@@ -0,0 +1,424 @@
import { OlympusPlugin, UnitBlueprint } from "interfaces";
import { AirUnitEditor } from "./airuniteditor";
import { OlympusApp } from "olympusapp";
import { GroundUnitEditor } from "./grounduniteditor";
import { PrimaryToolbar } from "toolbars/primarytoolbar";
import { NavyUnitEditor } from "./navyuniteditor";
/** Database Manager
*
* This database provides a user interface to allow easier and convenient unit databases manipulation. It allows to edit all the fields of the units databases, save them
* on the server, and restore the defaults.
*
* TODO:
* Add ability to manage liveries
*
*/
export class DatabaseManagerPlugin implements OlympusPlugin {
#app!: OlympusApp;
#element: HTMLElement;
#mainContentContainer: HTMLElement;
#contentDiv1: HTMLElement;
#contentDiv2: HTMLElement;
#contentDiv3: HTMLElement;
/* Upper tab buttons */
#button1: HTMLButtonElement;
#button2: HTMLButtonElement;
#button3: HTMLButtonElement;
#button4: HTMLButtonElement;
/* Lower operation buttons */
#button5: HTMLButtonElement;
#button6: HTMLButtonElement;
#button7: HTMLButtonElement;
#button8: HTMLButtonElement;
#button9: HTMLButtonElement;
/* Database editors */
#aircraftEditor: AirUnitEditor;
#helicopterEditor: AirUnitEditor;
#groundUnitEditor: GroundUnitEditor;
#navyUnitEditor: NavyUnitEditor;
constructor() {
/* Create main HTML element */
this.#element = document.createElement("div");
this.#element.id = "database-manager-panel";
this.#element.oncontextmenu = () => { return false; }
this.#element.classList.add("ol-dialog");
document.body.appendChild(this.#element);
/* Start hidden */
this.toggle(false);
/* Create the top tab buttons container and buttons */
let topButtonContainer = document.createElement("div");
this.#button1 = document.createElement("button");
this.#button1.classList.add("tab-button");
this.#button1.textContent = "Aircraft database";
this.#button1.onclick = () => { this.#hideAll(); this.#aircraftEditor.show(); this.#button1.classList.add("selected"); };
topButtonContainer.appendChild(this.#button1);
this.#button2 = document.createElement("button");
this.#button2.classList.add("tab-button");
this.#button2.textContent = "Helicopter database";
this.#button2.onclick = () => { this.#hideAll(); this.#helicopterEditor.show(); this.#button2.classList.add("selected"); };
topButtonContainer.appendChild(this.#button2);
this.#button3 = document.createElement("button");
this.#button3.classList.add("tab-button");
this.#button3.textContent = "Ground Unit database";
this.#button3.onclick = () => { this.#hideAll(); this.#groundUnitEditor.show(); this.#button3.classList.add("selected"); };
topButtonContainer.appendChild(this.#button3);
this.#button4 = document.createElement("button");
this.#button4.classList.add("tab-button");
this.#button4.textContent = "Navy Unit database";
this.#button4.onclick = () => { this.#hideAll(); this.#navyUnitEditor.show(); this.#button4.classList.add("selected"); };
topButtonContainer.appendChild(this.#button4);
this.#element.appendChild(topButtonContainer);
/* Create the container for the database editor elements and the elements themselves */
this.#mainContentContainer = document.createElement("div");
this.#mainContentContainer.classList.add("dm-container");
this.#element.appendChild(this.#mainContentContainer);
this.#contentDiv1 = document.createElement("div");
this.#contentDiv1.classList.add("dm-content-container", "ol-scrollable");
this.#mainContentContainer.appendChild(this.#contentDiv1);
this.#contentDiv2 = document.createElement("div");
this.#contentDiv2.classList.add("dm-content-container", "ol-scrollable");
this.#mainContentContainer.appendChild(this.#contentDiv2);
this.#contentDiv3 = document.createElement("div");
this.#contentDiv3.classList.add("dm-content-container", "ol-scrollable");
this.#mainContentContainer.appendChild(this.#contentDiv3);
/* Create the database editors, which use the three divs created before */
this.#aircraftEditor = new AirUnitEditor(this.#contentDiv1, this.#contentDiv2, this.#contentDiv3);
this.#helicopterEditor = new AirUnitEditor(this.#contentDiv1, this.#contentDiv2, this.#contentDiv3);
this.#groundUnitEditor = new GroundUnitEditor(this.#contentDiv1, this.#contentDiv2, this.#contentDiv3);
this.#navyUnitEditor = new NavyUnitEditor(this.#contentDiv1, this.#contentDiv2, this.#contentDiv3);
/* Create the bottom buttons container. These buttons allow to save, restore, reset, and discard the changes */
let bottomButtonContainer = document.createElement("div");
this.#button5 = document.createElement("button");
this.#button5.textContent = "Save";
this.#button5.title = "Save the changes on the server"
this.#button5.onclick = () => { this.#saveDatabases();};
bottomButtonContainer.appendChild(this.#button5);
this.#button6 = document.createElement("button");
this.#button6.textContent = "Discard";
this.#button6.title = "Discard all changes and reload the database from the server";
this.#button6.onclick = () => { this.#loadDatabases(); };
bottomButtonContainer.appendChild(this.#button6);
this.#button7 = document.createElement("button");
this.#button7.textContent = "Reset defaults";
this.#button7.onclick = () => { this.#resetToDefaultDatabases(); };
this.#button7.title = "Reset the databases to the default values";
bottomButtonContainer.appendChild(this.#button7);
this.#button8 = document.createElement("button");
this.#button8.textContent = "Restore previous";
this.#button8.onclick = () => { this.#restoreToPreviousDatabases(); };
this.#button8.title = "Restore the previously saved databases. Use this if you saved a database by mistake.";
bottomButtonContainer.appendChild(this.#button8);
this.#button9 = document.createElement("button");
this.#button9.textContent = "Close";
this.#button9.title = "Close the Database Manager"
this.#button9.onclick = () => { this.toggle(false); };
bottomButtonContainer.appendChild(this.#button9);
this.#element.appendChild(bottomButtonContainer);
}
/**
*
* @returns The name of the plugin
*/
getName() {
return "Database Control Plugin"
}
/** Initialize the plugin
*
* @param app The OlympusApp singleton
* @returns True if successfull
*/
initialize(app: any) {
this.#app = app;
const contextManager = this.#app.getContextManager();
contextManager.add( "databaseManager", {
"allowUnitCopying": false,
"allowUnitPasting": false,
"useSpawnMenu": false,
"useUnitControlPanel": false,
"useUnitInfoPanel": false
});
/* Load the databases and initialize the editors */
this.#loadDatabases();
/* Add a button to the main Olympus App to allow the users to open the dialog */
var mainButtonDiv = document.createElement("div");
var mainButton = document.createElement("button");
mainButton.textContent = "Database manager";
mainButtonDiv.appendChild(mainButton);
var toolbar: PrimaryToolbar = this.#app?.getToolbarsManager().get("primaryToolbar") as PrimaryToolbar;
var elements = toolbar.getMainDropdown().getOptionElements();
var arr = Array.prototype.slice.call(elements);
arr.splice(arr.length - 3, 0, mainButtonDiv);
toolbar.getMainDropdown().setOptionsElements(arr);
mainButton.onclick = () => {
toolbar.getMainDropdown().close();
if (this.#app?.getMissionManager().getCommandModeOptions().commandMode === "Game master")
this.toggle();
}
return true;
}
/**
*
* @returns The main container element
*/
getElement() {
return this.#element;
}
/** Toggles the visibility of the dialog
*
* @param bool Force a specific visibility state
*/
toggle(bool?: boolean) {
if (bool)
this.getElement().classList.toggle("hide", !bool);
else
this.getElement().classList.toggle("hide");
if ( this.#app )
this.#app.getContextManager().setContext( this.getElement().classList.contains("hide") ? "olympus" : "databaseManager" );
}
/** Hide all the editors
*
*/
#hideAll() {
this.#aircraftEditor.hide();
this.#helicopterEditor.hide();
this.#groundUnitEditor.hide();
this.#navyUnitEditor.hide();
this.#button1.classList.remove("selected");
this.#button2.classList.remove("selected");
this.#button3.classList.remove("selected");
this.#button4.classList.remove("selected");
}
/** Load the databases from the app to the editor. Note, this does not reload the databases from the server to the app
*
*/
#loadDatabases() {
var aircraftDatabase = this.#app?.getAircraftDatabase();
if (aircraftDatabase != null)
this.#aircraftEditor.setDatabase(aircraftDatabase);
var helicopterDatabase = this.#app?.getHelicopterDatabase();
if (helicopterDatabase != null)
this.#helicopterEditor.setDatabase(helicopterDatabase);
var groundUnitDatabase = this.#app?.getGroundUnitDatabase();
if (groundUnitDatabase != null)
this.#groundUnitEditor.setDatabase(groundUnitDatabase);
var navyUnitDatabase = this.#app?.getNavyUnitDatabase();
if (navyUnitDatabase != null)
this.#navyUnitEditor.setDatabase(navyUnitDatabase);
this.#hideAll();
this.#aircraftEditor.show();
this.#button1.classList.add("selected");
}
/** Save the databases on the server and reloads it to apply the changes
*
*/
#saveDatabases() {
var aircraftDatabase = this.#aircraftEditor.getDatabase();
if (aircraftDatabase){
this.#uploadDatabase(aircraftDatabase, "aircraftdatabase", "Aircraft database", () => {
var helicopterDatabase = this.#helicopterEditor.getDatabase();
if (helicopterDatabase) {
this.#uploadDatabase(helicopterDatabase, "helicopterDatabase", "Helicopter database", () => {
var groundUnitDatabase = this.#groundUnitEditor.getDatabase();
if (groundUnitDatabase) {
this.#uploadDatabase(groundUnitDatabase, "groundUnitDatabase", "Ground Unit database", () => {
var navyUnitDatabase = this.#navyUnitEditor.getDatabase();
if (navyUnitDatabase) {
this.#uploadDatabase(navyUnitDatabase, "navyUnitDatabase", "Navy Unit database", () => {
this.#app?.getAircraftDatabase().load(() => {});
this.#app?.getHelicopterDatabase().load(() => {});
this.#app?.getGroundUnitDatabase().load(() => {});
this.#app?.getNavyUnitDatabase().load(() => {});
this.#app?.getServerManager().reloadDatabases(() => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("Olympus core databases reloaded");
})
});
}
});
}
});
}
});
}
}
/** Resets the databases to the default values
*
*/
#resetToDefaultDatabases() {
this.#resetToDefaultDatabase("aircraftdatabase", "Aircraft database", () => {
this.#app?.getAircraftDatabase().load(() => {
this.#resetToDefaultDatabase("helicopterdatabase", "Helicopter database", () => {
this.#app?.getHelicopterDatabase().load(() => {
this.#resetToDefaultDatabase("groundunitdatabase", "Ground Unit database", () => {
this.#app?.getGroundUnitDatabase().load(() => {
this.#resetToDefaultDatabase("navyunitdatabase", "Navy Unit database", () => {
this.#app?.getNavyUnitDatabase().load(() => {
this.#loadDatabases();
this.#app?.getServerManager().reloadDatabases(() => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("Olympus core databases reloaded");
})
this.#hideAll();
this.#aircraftEditor.show();
this.#button1.classList.add("selected");
});
});
});
});
});
});
});
});
}
/** Restores the databases to the previous saved values. This is useful if you saved the databases by mistake and want to undo the error.
*
*/
#restoreToPreviousDatabases() {
this.#restoreToPreviousDatabase("aircraftdatabase", "Aircraft database", () => {
this.#app?.getAircraftDatabase().load(() => {
this.#restoreToPreviousDatabase("helicopterdatabase", "Helicopter database", () => {
this.#app?.getHelicopterDatabase().load(() => {
this.#restoreToPreviousDatabase("groundunitdatabase", "Ground Unit database", () => {
this.#app?.getGroundUnitDatabase().load(() => {
this.#restoreToPreviousDatabase("navyunitdatabase", "Navy Unit database", () => {
this.#app?.getNavyUnitDatabase().load(() => {
this.#loadDatabases();
this.#app?.getServerManager().reloadDatabases(() => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("Olympus core databases reloaded");
})
this.#hideAll();
this.#aircraftEditor.show();
this.#button1.classList.add("selected");
});
});
});
});
});
});
});
});
}
/** Upload a single database to the server
*
* @param database The database
* @param name The name of the database as it will be saved on the server
* @param label A label used in the info popup
*/
#uploadDatabase(database: { blueprints: { [key: string]: UnitBlueprint } }, name: string, label: string, callback: CallableFunction) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("PUT", "/api/databases/save/units/" + name);
xmlHttp.setRequestHeader("Content-Type", "application/json");
xmlHttp.onload = (res: any) => {
if (xmlHttp.status == 200) {
this.#app?.getPopupsManager().get("infoPopup")?.setText(label + " saved successfully");
callback();
}
else {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while saving the " + label);
}
};
xmlHttp.onerror = (res: any) => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while saving the " + label);
}
xmlHttp.send(JSON.stringify(database));
}
/** Resets a database to its default values on the server. NOTE: this only resets the database on the server, it will not reload it in the app.
*
* @param name The name of the database as it is saved on the server
* @param label A label used in the info popup
* @param callback Called when the operation is completed
*/
#resetToDefaultDatabase(name: string, label: string, callback: CallableFunction) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("PUT", "/api/databases/reset/units/" + name);
xmlHttp.setRequestHeader("Content-Type", "application/json");
xmlHttp.onload = (res: any) => {
if (xmlHttp.status == 200) {
this.#app?.getPopupsManager().get("infoPopup")?.setText(label + " reset successfully");
callback();
}
else {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while resetting the " + label);
}
};
xmlHttp.onerror = (res: any) => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while resetting the " + label)
}
xmlHttp.send("");
}
/** Restores a database to its previously saved values on the server. NOTE: this only restores the database on the server, it will not reload it in the app.
*
* @param name The name of the database as it is saved on the server
* @param label A label used in the info popup
* @param callback Called when the operation is completed
*/
#restoreToPreviousDatabase(name: string, label: string, callback: CallableFunction) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("PUT", "/api/databases/restore/units/" + name);
xmlHttp.setRequestHeader("Content-Type", "application/json");
xmlHttp.onload = (res: any) => {
if (xmlHttp.status == 200) {
this.#app?.getPopupsManager().get("infoPopup")?.setText(label + " restored successfully");
callback();
}
else {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while restoring the " + label);
}
};
xmlHttp.onerror = (res: any) => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while restoring the " + label)
}
xmlHttp.send("");
}
}

View File

@@ -0,0 +1,77 @@
import { UnitBlueprint } from "interfaces";
import { UnitEditor } from "./uniteditor";
import { addCheckboxInput, addDropdownInput, addStringInput } from "./utils";
/** Database editor for ground units
*
*/
export class GroundUnitEditor extends UnitEditor {
#blueprint: UnitBlueprint | null = null;
constructor(contentDiv1: HTMLElement, contentDiv2: HTMLElement, contentDiv3: HTMLElement) {
super(contentDiv1, contentDiv2, contentDiv3);
}
/** Sets a unit blueprint as the currently active one
*
* @param blueprint The blueprint to edit
*/
setBlueprint(blueprint: UnitBlueprint) {
this.#blueprint = blueprint;
if (this.#blueprint !== null) {
this.contentDiv2.replaceChildren();
var title = document.createElement("label");
title.innerText = "Unit properties";
this.contentDiv2.appendChild(title);
addStringInput(this.contentDiv2, "Name", blueprint.name, "text", (value: string) => {blueprint.name = value; }, true);
addStringInput(this.contentDiv2, "Label", blueprint.label, "text", (value: string) => {blueprint.label = value; });
addStringInput(this.contentDiv2, "Short label", blueprint.shortLabel, "text", (value: string) => {blueprint.shortLabel = value; });
addStringInput(this.contentDiv2, "Type", blueprint.type?? "", "text", (value: string) => {blueprint.type = value; });
addStringInput(this.contentDiv2, "Unit when grouped", blueprint.unitWhenGrouped?? "", "text", (value: string) => {blueprint.unitWhenGrouped = value; });
addDropdownInput(this.contentDiv2, "Coalition", blueprint.coalition, ["", "blue", "red"], (value: string) => {blueprint.coalition = value; });
addDropdownInput(this.contentDiv2, "Era", blueprint.era, ["WW2", "Early Cold War", "Mid Cold War", "Late Cold War", "Modern"], (value: string) => {blueprint.era = value; });
//addStringInput(this.contentDiv2, "Filename", blueprint.filename?? "", "text", (value: string) => {blueprint.filename = value; });
addStringInput(this.contentDiv2, "Cost", String(blueprint.cost)?? "", "number", (value: string) => {blueprint.cost = parseFloat(value); });
addStringInput(this.contentDiv2, "Acquisition range [m]", String(blueprint.acquisitionRange)?? "", "number", (value: string) => {blueprint.acquisitionRange = parseFloat(value); });
addStringInput(this.contentDiv2, "Engagement range [m]", String(blueprint.engagementRange)?? "", "number", (value: string) => {blueprint.engagementRange = parseFloat(value); });
addStringInput(this.contentDiv2, "Targeting range [m]", String(blueprint.targetingRange)?? "", "number", (value: string) => {blueprint.targetingRange = parseFloat(value); });
addStringInput(this.contentDiv2, "Aim method range [m]", String(blueprint.aimMethodRange)?? "", "number", (value: string) => {blueprint.aimMethodRange = parseFloat(value); });
addStringInput(this.contentDiv2, "Barrel height [m]", String(blueprint.barrelHeight)?? "", "number", (value: string) => {blueprint.barrelHeight = parseFloat(value); });
addStringInput(this.contentDiv2, "Muzzle velocity [m/s]", String(blueprint.muzzleVelocity)?? "", "number", (value: string) => {blueprint.muzzleVelocity = parseFloat(value); });
addStringInput(this.contentDiv2, "Aim time [s]", String(blueprint.aimTime)?? "", "number", (value: string) => {blueprint.aimTime = parseFloat(value); });
addStringInput(this.contentDiv2, "Shots to fire", String(blueprint.shotsToFire)?? "", "number", (value: string) => {blueprint.shotsToFire = Math.round(parseFloat(value)); });
addStringInput(this.contentDiv2, "Shots base interval [s]", String(blueprint.shotsBaseInterval)?? "", "number", (value: string) => {blueprint.shotsBaseInterval = Math.round(parseFloat(value)); });
addStringInput(this.contentDiv2, "Shots base scatter [°]", String(blueprint.shotsBaseScatter)?? "", "number", (value: string) => {blueprint.shotsBaseScatter = Math.round(parseFloat(value)); });
addStringInput(this.contentDiv2, "Alertness time constant [s]", String(blueprint.alertnessTimeConstant)?? "", "number", (value: string) => {blueprint.alertnessTimeConstant = Math.round(parseFloat(value)); });
addCheckboxInput(this.contentDiv2, "Can target point", blueprint.canTargetPoint ?? false, (value: boolean) => {blueprint.canTargetPoint = value;})
addCheckboxInput(this.contentDiv2, "Can rearm", blueprint.canRearm ?? false, (value: boolean) => {blueprint.canRearm = value;})
addCheckboxInput(this.contentDiv2, "Can operate as AAA", blueprint.canAAA ?? false, (value: boolean) => {blueprint.canAAA = value;})
addCheckboxInput(this.contentDiv2, "Indirect fire (e.g. mortar)", blueprint.indirectFire ?? false, (value: boolean) => {blueprint.indirectFire = value;})
addStringInput(this.contentDiv2, "Description", blueprint.description ?? "", "text", (value: string) => {blueprint.description = value; });
addStringInput(this.contentDiv2, "Tags", blueprint.tags ?? "", "text", (value: string) => {blueprint.tags = value; });
addStringInput(this.contentDiv2, "Marker file", blueprint.markerFile ?? "", "text", (value: string) => {blueprint.markerFile = value; });
}
}
/** Add a new empty blueprint
*
* @param key Blueprint key
*/
addBlueprint(key: string) {
if (this.database != null) {
this.database.blueprints[key] = {
name: key,
coalition: "",
label: "",
shortLabel: "",
era: "",
enabled: true
}
this.show();
this.setBlueprint(this.database.blueprints[key]);
}
}
}

View File

@@ -0,0 +1,5 @@
import { DatabaseManagerPlugin } from "./databasemanagerplugin";
globalThis.getOlympusPlugin = () => {
return new DatabaseManagerPlugin();
}

View File

@@ -0,0 +1,55 @@
import { LoadoutBlueprint } from "interfaces";
import { addLoadoutItemsEditor, addStringInput, arrayToString, stringToArray } from "./utils";
/** The LoadoutEditor allows the user to edit a loadout
*
*/
export class LoadoutEditor {
#contentDiv: HTMLElement;
#loadout: LoadoutBlueprint | null = null;
#visible: boolean = false;
constructor(contentDiv: HTMLElement) {
this.#contentDiv = contentDiv;
this.#contentDiv.addEventListener("refresh", () => {
if (this.#visible)
this.show();
})
}
/** Set the loadout to edit
*
* @param loadout The loadout to edit
*/
setLoadout(loadout: LoadoutBlueprint) {
this.#loadout = loadout;
}
/** Show the editor
*
*/
show() {
this.#visible = true;
this.#contentDiv.replaceChildren();
var title = document.createElement("label");
title.innerText = "Loadout properties";
this.#contentDiv.appendChild(title);
if (this.#loadout) {
var loadout = this.#loadout;
addStringInput(this.#contentDiv, "Name", loadout.name, "text", (value: string) => {loadout.name = value; this.#contentDiv.dispatchEvent(new Event("refresh"));});
addStringInput(this.#contentDiv, "Code", loadout.code, "text", (value: string) => {loadout.code = value; });
addStringInput(this.#contentDiv, "Roles", arrayToString(loadout.roles), "text", (value: string) => {loadout.roles = stringToArray(value);});
addLoadoutItemsEditor(this.#contentDiv, this.#loadout);
}
}
/** Hide the editor
*
*/
hide() {
this.#visible = false;
this.#contentDiv.replaceChildren();
}
}

View File

@@ -0,0 +1,60 @@
import { UnitBlueprint } from "interfaces";
import { UnitEditor } from "./uniteditor";
import { addDropdownInput, addStringInput } from "./utils";
/** Database editor for navy units
*
*/
export class NavyUnitEditor extends UnitEditor {
#blueprint: UnitBlueprint | null = null;
constructor(contentDiv1: HTMLElement, contentDiv2: HTMLElement, contentDiv3: HTMLElement) {
super(contentDiv1, contentDiv2, contentDiv3);
}
/** Sets a unit blueprint as the currently active one
*
* @param blueprint The blueprint to edit
*/
setBlueprint(blueprint: UnitBlueprint) {
this.#blueprint = blueprint;
if (this.#blueprint !== null) {
this.contentDiv2.replaceChildren();
var title = document.createElement("label");
title.innerText = "Unit properties";
this.contentDiv2.appendChild(title);
addStringInput(this.contentDiv2, "Name", blueprint.name, "text", (value: string) => {blueprint.name = value; }, true);
addStringInput(this.contentDiv2, "Label", blueprint.label, "text", (value: string) => {blueprint.label = value; });
addStringInput(this.contentDiv2, "Short label", blueprint.shortLabel, "text", (value: string) => {blueprint.shortLabel = value; });
addStringInput(this.contentDiv2, "Type", blueprint.type?? "", "text", (value: string) => {blueprint.type = value; });
addDropdownInput(this.contentDiv2, "Coalition", blueprint.coalition, ["", "blue", "red"], (value: string) => {blueprint.coalition = value; });
addDropdownInput(this.contentDiv2, "Era", blueprint.era, ["WW2", "Early Cold War", "Mid Cold War", "Late Cold War", "Modern"], (value: string) => {blueprint.era = value; });
//addStringInput(this.contentDiv2, "Filename", blueprint.filename?? "", "text", (value: string) => {blueprint.filename = value; });
addStringInput(this.contentDiv2, "Cost", String(blueprint.cost)?? "", "number", (value: string) => {blueprint.cost = parseFloat(value); });
addStringInput(this.contentDiv2, "Barrel height [m]", String(blueprint.barrelHeight)?? "", "number", (value: string) => {blueprint.barrelHeight = parseFloat(value); });
addStringInput(this.contentDiv2, "Muzzle velocity [m/s]", String(blueprint.muzzleVelocity)?? "", "number", (value: string) => {blueprint.muzzleVelocity = parseFloat(value); });
}
}
/** Add a new empty blueprint
*
* @param key Blueprint key
*/
addBlueprint(key: string) {
if (this.database != null) {
this.database.blueprints[key] = {
name: key,
coalition: "",
label: "",
shortLabel: "",
era: "",
enabled: true
}
this.show();
this.setBlueprint(this.database.blueprints[key]);
}
}
}

View File

@@ -0,0 +1,117 @@
import { UnitBlueprint } from "interfaces";
import { UnitDatabase } from "unit/databases/unitdatabase";
import { addBlueprintsScroll, addNewElementInput } from "./utils";
/** Base abstract class of Unit database editors
*
*/
export abstract class UnitEditor {
blueprint: UnitBlueprint | null = null;
database: {blueprints: {[key: string]: UnitBlueprint}} | null = null;
visible: boolean = false;
contentDiv1: HTMLElement;
contentDiv2: HTMLElement;
contentDiv3: HTMLElement;
constructor(contentDiv1: HTMLElement, contentDiv2: HTMLElement, contentDiv3: HTMLElement) {
this.contentDiv1 = contentDiv1;
this.contentDiv2 = contentDiv2;
this.contentDiv3 = contentDiv3;
/* Refresh the list of units if it changes */
this.contentDiv1.addEventListener("refresh", () => {
if (this.visible)
this.show();
})
/* If the unit properties or loadout are edited, reload the editor */
this.contentDiv2.addEventListener("refresh", () => {
if (this.visible) {
if (this.blueprint !== null)
this.setBlueprint(this.blueprint);
}
});
this.contentDiv3.addEventListener("refresh", () => {
if (this.visible) {
if (this.blueprint !== null)
this.setBlueprint(this.blueprint);
}
});
}
/**
*
* @param database The database that the editor will operate on
*/
setDatabase(database: UnitDatabase) {
this.database = JSON.parse(JSON.stringify({blueprints: database.getBlueprints(true)}));
}
/** Show the editor
* @param filter String filter
*/
show(filter: string = "") {
this.visible = true;
this.contentDiv1.replaceChildren();
this.contentDiv2.replaceChildren();
this.contentDiv3.replaceChildren();
/* Create the list of units. Each unit is clickable to activate the editor on it */
if (this.database != null) {
var title = document.createElement("label");
title.innerText = "Units list";
this.contentDiv1.appendChild(title);
var filterInput = document.createElement("input");
filterInput.value = filter;
this.contentDiv1.appendChild(filterInput);
filterInput.onchange = (e: Event) => {
this.show((e.target as HTMLInputElement).value);
}
this.addBlueprints(filter);
}
}
/** Hide the editor
*
*/
hide() {
this.visible = false;
this.contentDiv1.replaceChildren();
this.contentDiv2.replaceChildren();
this.contentDiv3.replaceChildren();
}
/**
*
* @returns The edited database
*/
getDatabase() {
return this.database;
}
/**
*
* @param filter String filter
*/
addBlueprints(filter: string = "") {
if (this.database) {
addBlueprintsScroll(this.contentDiv1, this.database, filter, (key: string) => {
if (this.database != null)
this.setBlueprint(this.database.blueprints[key])
});
addNewElementInput(this.contentDiv1, (ev: MouseEvent, input: HTMLInputElement) => {
if (input.value != "")
this.addBlueprint((input).value);
});
}
}
/* Abstract methods which will depend on the specific type of units */
abstract setBlueprint(blueprint: UnitBlueprint): void;
abstract addBlueprint(key: string): void;
}

View File

@@ -0,0 +1,297 @@
import { LoadoutBlueprint, LoadoutItemBlueprint, UnitBlueprint } from "interfaces";
/** This file contains a set of utility functions that are reused in the various editors and allows to declutter the classes
*
*/
/** Add a string input in the form of String: [ value ]
*
* @param div The HTMLElement that will contain the input
* @param key The key of the input, which will be used as label
* @param value The initial value of the input
* @param type The type of the input, e.g. "Text" or "Number" as per html standard
* @param callback Callback called when the user enters a new value
* @param disabled If true, the input will be disabled and read only
*/
export function addStringInput(div: HTMLElement, key: string, value: string, type: string, callback: CallableFunction, disabled?: boolean) {
var row = document.createElement("div");
var dt = document.createElement("dt");
var dd = document.createElement("dd");
dt.innerText = key;
var input = document.createElement("input");
input.value = value;
input.textContent = value;
input.type = type?? "text";
input.disabled = disabled?? false;
input.onchange = () => callback(input.value);
dd.appendChild(input);
row.appendChild(dt);
row.appendChild(dd);
row.classList.add("input-row");
div.appendChild(row);
}
/** Add a dropdown (select) input
*
* @param div The HTMLElement that will contain the input
* @param key The key of the input, which will be used as label
* @param value The initial value of the input
* @param options The dropdown options
*/
export function addDropdownInput(div: HTMLElement, key: string, value: string, options: string[], callback: CallableFunction, disabled?: boolean) {
var row = document.createElement("div");
var dt = document.createElement("dt");
var dd = document.createElement("dd");
dt.innerText = key;
var select = document.createElement("select");
options.forEach((option: string) => {
var el = document.createElement("option");
el.value = option;
el.innerText = option;
select.appendChild(el);
});
select.value = value;
select.disabled = disabled?? false;
select.onchange = () => callback(select.value);
dd.appendChild(select);
row.appendChild(dt);
row.appendChild(dd);
row.classList.add("input-row");
div.appendChild(row);
}
/** Add a checkbox input in the form of String: [ value ]
*
* @param div The HTMLElement that will contain the input
* @param key The key of the input, which will be used as label
* @param value The initial value of the input
* @param callback Callback called when the user enters a new value
* @param disabled If true, the input will be disabled and read only
*/
export function addCheckboxInput(div: HTMLElement, key: string, value: boolean, callback: CallableFunction, disabled?: boolean) {
var row = document.createElement("div");
var dt = document.createElement("dt");
var dd = document.createElement("dd");
dt.innerText = key;
var input = document.createElement("input");
input.checked = value;
input.type = "checkbox";
input.disabled = disabled?? false;
input.onchange = () => callback(input.checked);
dd.appendChild(input);
row.appendChild(dt);
row.appendChild(dd);
row.classList.add("input-row");
div.appendChild(row);
}
/** Create a loadout items editor. This editor allows to add or remove loadout items, as well as changing their name and quantity
*
* @param div The HTMLElement that will contain the editor
* @param loadout The loadout to edit
*/
export function addLoadoutItemsEditor(div: HTMLElement, loadout: LoadoutBlueprint) {
var itemsEl = document.createElement("div");
itemsEl.classList.add("dm-scroll-container", "dm-items-container");
/* Create a row for each loadout item to allow and change the name and quantity of the item itself */
loadout.items.sort((a: LoadoutItemBlueprint, b: LoadoutItemBlueprint) => a.name.localeCompare(b.name, undefined, {sensitivity: 'base'}));
loadout.items.forEach((item: LoadoutItemBlueprint, index: number) => {
var rowDiv = document.createElement("div");
var nameLabel = document.createElement("label");
nameLabel.innerText = "Name"
rowDiv.appendChild(nameLabel);
var nameInput = document.createElement("input");
rowDiv.appendChild(nameInput);
nameInput.textContent = item.name;
nameInput.value = item.name
nameInput.onchange = () => { loadout.items[index].name = nameInput.value; }
var quantityLabel = document.createElement("label");
quantityLabel.innerText = "Quantity"
rowDiv.appendChild(quantityLabel);
var quantityInput = document.createElement("input");
rowDiv.appendChild(quantityInput);
quantityInput.textContent = String(item.quantity);
quantityInput.value = String(item.quantity);
quantityInput.type = "number";
quantityInput.step = "1";
quantityInput.onchange = () => { loadout.items[index].quantity = parseInt(quantityInput.value); }
/* This button allows to remove the item */
var button = document.createElement("button");
button.innerText = "X";
button.onclick = () => {
loadout.items.splice(index, 1);
div.dispatchEvent(new Event("refresh"));
}
rowDiv.appendChild(button);
itemsEl.appendChild(rowDiv);
})
div.appendChild(itemsEl);
/* Button to add a new item to the loadout */
var inputDiv = document.createElement("div");
inputDiv.classList.add("dm-new-item-input");
var button = document.createElement("button");
button.innerText = "Add";
inputDiv.appendChild(button);
div.appendChild(inputDiv);
button.addEventListener("click", (ev: MouseEvent) => {
loadout?.items.push({
name: "",
quantity: 1
})
div.dispatchEvent(new Event("refresh"));
});
}
/** Add a input and button to create a new element in a list. It uses a generic callback to actually add the element.
*
* @param div The HTMLElement that will contain the input and button
* @param callback Callback called when the user clicks on "Add"
*/
export function addNewElementInput(div: HTMLElement, callback: CallableFunction) {
var inputDiv = document.createElement("div");
inputDiv.classList.add("dm-new-element-input");
var input = document.createElement("input");
inputDiv.appendChild(input);
var button = document.createElement("button");
button.innerText = "Add";
button.addEventListener("click", (ev: MouseEvent) => callback(ev, input));
inputDiv.appendChild(button);
div.appendChild(inputDiv);
}
/** Add a scrollable list of blueprints
*
* @param div The HTMLElement that will contain the list
* @param database The database that will be used to fill the list of blueprints
* @param filter A string filter that will be executed to filter the blueprints to add
* @param callback Callback called when the user clicks on one of the elements
*/
export function addBlueprintsScroll(div: HTMLElement, database: {blueprints: {[key: string]: UnitBlueprint}}, filter: string, callback: CallableFunction) {
var scrollDiv = document.createElement("div");
scrollDiv.classList.add("dm-scroll-container");
if (database !== null) {
var blueprints: {[key: string]: UnitBlueprint} = database.blueprints;
for (let key of Object.keys(blueprints).sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))) {
var addKey = true;
if (filter !== "") {
try {
var blueprint = blueprints[key];
addKey = eval(filter);
} catch {
console.error("An error has occurred evaluating the blueprint filter")
}
}
if (addKey) {
var rowDiv = document.createElement("div");
scrollDiv.appendChild(rowDiv);
let text = document.createElement("div");
text.innerHTML = `<div>${key}</div> <div>${blueprints[key].label}</div>`;
text.onclick = () => {
callback(key);
const collection = document.getElementsByClassName("blueprint-selected");
for (let i = 0; i < collection.length; i++) {
collection[i].classList.remove("blueprint-selected");
}
text.classList.add("blueprint-selected");
}
rowDiv.appendChild(text);
let checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = blueprints[key].enabled;
checkbox.onclick = () => {
console.log(checkbox.checked);
blueprints[key].enabled = checkbox.checked;
}
rowDiv.appendChild(checkbox);
/* This button allows to remove an element from the list. It requires a refresh. */
var button = document.createElement("button");
button.innerText = "X";
button.onclick = () => {
delete blueprints[key];
div.dispatchEvent(new Event("refresh"));
}
rowDiv.appendChild(button);
}
}
}
div.appendChild(scrollDiv);
}
/** Add a scrollable list of loadouts
*
* @param div The HTMLElement that will contain the list
* @param loadouts The loadouts that will be used to fill the list
* @param callback Callback called when the user clicks on one of the elements
*/
export function addLoadoutsScroll(div: HTMLElement, loadouts: LoadoutBlueprint[], callback: CallableFunction) {
var loadoutsEl = document.createElement("div");
loadoutsEl.classList.add("dm-scroll-container", "dm-loadout-container")
loadouts.sort((a: LoadoutBlueprint, b: LoadoutBlueprint) => a.name.localeCompare(b.name, undefined, {sensitivity: 'base'}));
loadouts.forEach((loadout: LoadoutBlueprint, index: number) => {
var rowDiv = document.createElement("div");
loadoutsEl.appendChild(rowDiv);
var text = document.createElement("label");
text.textContent = loadout.name;
text.onclick = () => { callback(loadout) };
rowDiv.appendChild(text);
/* The "Empty loadout" can not be removed */
if (loadout.name !== "Empty loadout") {
let checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = loadout.enabled;
checkbox.onclick = () => {
console.log(checkbox.checked);
loadout.enabled = checkbox.checked;
}
rowDiv.appendChild(checkbox);
/* This button allows to remove an element from the list. It requires a refresh. */
var button = document.createElement("button");
button.innerText = "X";
button.onclick = () => {
loadouts.splice(index, 1);
div.dispatchEvent(new Event("refresh"));
}
rowDiv.appendChild(button);
}
});
div.appendChild(loadoutsEl);
}
/** Converts an array of string into a single string like [val1, val2, val3]
*
* @param array The input array of strings
* @returns The string
*/
export function arrayToString(array: string[]) {
return "[" + array.join( ", " ) + "]";
}
/** Converts an a single string like [val1, val2, val3] into an array
*
* @param input The input string
* @returns The array
*/
export function stringToArray(input: string) {
return input.match( /(\w)+/g ) ?? [];
}

View File

@@ -0,0 +1,295 @@
#database-manager-panel {
flex-direction: column;
display: flex;
width: 80%;
height: 80%;
padding: 10px;
border-radius: 5px;
background-color: var(--background-steel) !important;
z-index: 9999999;
}
@media (min-width: 1200px) {
.dm-container {
flex-direction: row;
}
}
@media (max-width: 1200px) {
.dm-container {
flex-direction: column;
overflow-y: auto;
}
}
#database-manager-panel * {
font-size: 13;
font-family: 'Open Sans', sans-serif !important;
user-select: none;
}
#database-manager-panel>div:first-child {
display: flex;
align-items: center;
}
#database-manager-panel>div:last-child {
display: flex;
column-gap: 5px;
align-items: center;
justify-content: end;
justify-items: end;
margin-top: 5px;
}
#database-manager-panel>div:last-child>button {
border: 1px solid white;
}
.dm-container {
background-color: var(--background-grey);
border: 2px solid #777777;
position: relative;
display: flex;
width: 100%;
padding: 5px;
height: calc(100% - 64px - 5px);
border-radius: 0px 5px 5px 5px;
}
.dm-content-container {
position: relative;
margin: 10px;
display: flex;
flex-direction: column;
row-gap: 5px;
max-height: 100%;
padding: 10px;
}
@media (min-width: 1200px) {
.dm-content-container {
height: calc(100% - 20px);
}
.dm-content-container:nth-of-type(1) {
width: 400px;
}
.dm-content-container:nth-of-type(2) {
width: 500px;
}
.dm-content-container:nth-of-type(3) {
flex: 1;
}
}
@media (max-width: 1200px) {
.dm-content-container {
width: calc(100% - 20px);
}
.dm-content-container:nth-of-type(1) {
height: 30%;
}
.dm-content-container:nth-of-type(2) {
height: 50%;
}
.dm-content-container:nth-of-type(3) {
flex: 1;
}
}
.dm-content-container>label {
font-size: 18px !important;
font-weight: bold;
}
.dm-scroll-container {
display: flex;
flex-direction: column;
overflow-y: scroll;
max-height: 100%;
color: black;
font-weight: bold;
}
#database-manager-panel input {
font-weight: bold;
}
.dm-scroll-container>div:nth-child(even) {
background-color: gainsboro;
}
.dm-scroll-container>div:nth-child(odd) {
background-color: white;
}
.dm-scroll-container>div *:nth-child(1) {
height: 100%;
width: calc(100% - 25px);
padding: 2px;
word-wrap: break-word;
}
.dm-scroll-container>div *:nth-child(1):hover {
background-color: var(--accent-dark-blue);
color: white;
cursor: pointer;
}
.blueprint-selected {
background-color: var(--accent-light-blue) !important;
color: white;
}
.dm-scroll-container>div {
display: flex;
align-items: center;
justify-content: space-between;
}
.dm-scroll-container>div>div {
display: flex;
align-items: center;
justify-content: space-between;
}
.dm-scroll-container>div>button {
height: 20px;
width: 20px;
padding: 0px;
}
.dm-scroll-container>div>div>div:nth-child(1) {
width: fit-content;
}
.dm-scroll-container>div>div>div:nth-child(2) {
overflow: hidden;
text-wrap: nowrap;
text-overflow: ellipsis;
font-weight: normal;
}
.input-row {
width: 100%;
display: flex;
flex-direction: row;
}
@media (max-width: 1200px) {
.dm-content-container label {
width: 100%;
}
.input-row {
width: 50%;
}
}
.input-row>dt {
width: 250px;
}
.input-row>dd {
width: 100%;
text-align: right;
}
.input-row>dd>* {
width: 100%;
font-weight: bold;
}
.input-row>dd>*[type="checkbox"] {
width: 20px;
font-weight: bold;
}
.dm-loadout-container {
max-height: 100%;
max-width: 500px;
width: 100%;
}
.dm-items-container {
max-height: 100%;
height: fit-content;
}
.dm-items-container>div {
display: flex;
align-items: center;
column-gap: 2px;
}
.dm-items-container>div>label {
width: 80px !important;
}
.dm-items-container div>input:nth-of-type(1) {
flex: 1;
font-weight: bold;
}
.dm-items-container div>input:nth-of-type(2) {
width: 40px;
font-weight: bold;
}
.dm-new-element-input {
display: flex;
flex-direction: row;
column-gap: 2px;
width: 100%;
align-items: center;
}
.dm-new-element-input>input {
width: 100%;
}
.dm-new-element-input>button {
width: 60px;
}
.dm-new-item-input {
display: flex;
justify-content: end;
}
.dm-new-item-input>button {
width: 60px;
}
.tab-button {
transform: translateY(+3px);
background-color: var(--background-steel);
border-radius: 0;
border-bottom: 2px solid transparent !important;
border-top: 2px solid #777777 !important;
border-left: 2px solid #777777 !important;
border-right: 0px solid #777777 !important;
}
.tab-button.selected {
background-color: var(--background-grey);
z-index: 10;
}
.tab-button:first-of-type {
border-top-left-radius: 5px;
}
.tab-button:last-of-type {
border-top-right-radius: 5px;
border-right: 2px solid #777777 !important;
}
#database-manager-panel button :not(.dm-scroll-container>div) {
border: 1px solid white;
}

View File

@@ -0,0 +1,103 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "ES2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
"rootDirs": ["./src"], /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
"typeRoots": [
"./node_modules/@types",
"../../@types"
], /* Specify multiple folders that act like './node_modules/@types'. */
"types": [
"olympus"
], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": [
"src/*.ts"
]
}