mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Renamed files
This commit is contained in:
parent
64df9b142d
commit
53911cf314
@ -1,6 +1,6 @@
|
||||
import { AICFormationContextDataInterface, AICFormationDescriptor } from "./AICFormationDescriptor";
|
||||
import { AICFormationDescriptorPhrase } from "./AICFormationDescriptorPhrase";
|
||||
import { AICFormationDescriptorSection } from "./AICFormationDescriptorSection";
|
||||
import { AICFormationContextDataInterface, AICFormationDescriptor } from "./aicformationdescriptor";
|
||||
import { AICFormationDescriptorPhrase } from "./aicformationdescriptorphrase";
|
||||
import { AICFormationDescriptorSection } from "./aicformationdescriptorsection";
|
||||
|
||||
export interface AICFormationInterface {
|
||||
"icon" : string,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { AICFormation, AICFormationInterface } from "../AICFormation";
|
||||
import { AICFormationContextDataInterface } from "../AICFormationDescriptor";
|
||||
import { AICFormationDescriptorSection } from "../AICFormationDescriptorSection";
|
||||
import { AICFormationDescriptorComponent } from "../AICFormationDescriptorComponent";
|
||||
import { AICFormationDescriptorPhrase } from "../AICFormationDescriptorPhrase";
|
||||
import { AICFormation, AICFormationInterface } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
export class AICFormation_Azimuth extends AICFormation implements AICFormationInterface {
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { AICFormation, AICFormationInterface } from "../AICFormation";
|
||||
import { AICFormationContextDataInterface } from "../AICFormationDescriptor";
|
||||
import { AICFormationDescriptorSection } from "../AICFormationDescriptorSection";
|
||||
import { AICFormationDescriptorComponent } from "../AICFormationDescriptorComponent";
|
||||
import { AICFormationDescriptorPhrase } from "../AICFormationDescriptorPhrase";
|
||||
import { AICFormation, AICFormationInterface } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
export class AICFormation_Range extends AICFormation implements AICFormationInterface {
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { AICFormation, AICFormationInterface } from "../AICFormation";
|
||||
import { AICFormationContextDataInterface, AICFormationDescriptor } from "../AICFormationDescriptor";
|
||||
import { AICFormation, AICFormationInterface } from "../aicformation";
|
||||
import { AICFormationContextDataInterface, AICFormationDescriptor } from "../aicformationdescriptor";
|
||||
|
||||
export class AICFormation_Single extends AICFormation implements AICFormationInterface {
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { AICFormation } from "./AICFormation";
|
||||
import { AICFormationDescriptorSection } from "./AICFormationDescriptorSection";
|
||||
import { AICFormationDescriptorSection_Formation } from "./AICFormationDescriptorSection/Formation";
|
||||
import { AICFormationDescriptorSection_Unit } from "./AICFormationDescriptorSection/Unit";
|
||||
import { AICFormationDescriptorSection_NumGroups } from "./AICFormationDescriptorSection/NumGroups";
|
||||
import { AICFormationDescriptorSection_Who } from "./AICFormationDescriptorSection/Who";
|
||||
import { AICFormation } from "./aicformation";
|
||||
import { AICFormationDescriptorSection } from "./aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorSection_Formation } from "./aicformationdescriptorsection/formation";
|
||||
import { AICFormationDescriptorSection_Unit } from "./aicformationdescriptorsection/unit";
|
||||
import { AICFormationDescriptorSection_NumGroups } from "./aicformationdescriptorsection/numgroups";
|
||||
import { AICFormationDescriptorSection_Who } from "./aicformationdescriptorsection/who";
|
||||
|
||||
|
||||
export interface AICFormationContextDataInterface {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { AICFormationDescriptorComponent } from "../AICFormationDescriptorComponent";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
|
||||
export abstract class AICFormactionDescriptorComponent_Distance extends AICFormationDescriptorComponent {
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { AICFormactionDescriptorComponent_Distance } from "../Distance";
|
||||
import { AICFormactionDescriptorComponent_Distance } from "../distance";
|
||||
|
||||
export class AICFormationDescriptorComponent_Distance_Range extends AICFormactionDescriptorComponent_Distance {
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { AICFormation } from "./AICFormation";
|
||||
import { AICFormationContextDataInterface } from "./AICFormationDescriptor";
|
||||
import { AICFormationDescriptorComponent } from "./AICFormationDescriptorComponent";
|
||||
import { AICFormation } from "./aicformation";
|
||||
import { AICFormationContextDataInterface } from "./aicformationdescriptor";
|
||||
import { AICFormationDescriptorComponent } from "./aicformationdescriptorcomponent";
|
||||
|
||||
export interface AICFormationDescriptorPhraseInterface {
|
||||
"generate" : CallableFunction,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { AICFormation } from "./AICFormation";
|
||||
import { AICFormationContextDataInterface } from "./AICFormationDescriptor";
|
||||
import { AICFormationDescriptorPhrase } from "./AICFormationDescriptorPhrase";
|
||||
import { AICFormation } from "./aicformation";
|
||||
import { AICFormationContextDataInterface } from "./aicformationdescriptor";
|
||||
import { AICFormationDescriptorPhrase } from "./aicformationdescriptorphrase";
|
||||
|
||||
export interface AICFormationDescriptorSectionInterface {
|
||||
"generate" : CallableFunction,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { AICFormation } from "../AICFormation";
|
||||
import { AICFormationContextDataInterface } from "../AICFormationDescriptor";
|
||||
import { AICFormationDescriptorSection } from "../AICFormationDescriptorSection";
|
||||
import { AICFormationDescriptorComponent } from "../AICFormationDescriptorComponent";
|
||||
import { AICFormationDescriptorPhrase } from "../AICFormationDescriptorPhrase";
|
||||
import { AICFormation } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
export class AICFormationDescriptorSection_Formation extends AICFormationDescriptorSection {
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { AICFormation } from "../AICFormation";
|
||||
import { AICFormationContextDataInterface } from "../AICFormationDescriptor";
|
||||
import { AICFormationDescriptorSection } from "../AICFormationDescriptorSection";
|
||||
import { AICFormationDescriptorComponent } from "../AICFormationDescriptorComponent";
|
||||
import { AICFormationDescriptorPhrase } from "../AICFormationDescriptorPhrase";
|
||||
import { AICFormation } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
export class AICFormationDescriptorSection_NumGroups extends AICFormationDescriptorSection {
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { AICFormation } from "../AICFormation";
|
||||
import { AICFormationContextDataInterface } from "../AICFormationDescriptor";
|
||||
import { AICFormationDescriptorSection } from "../AICFormationDescriptorSection";
|
||||
import { AICFormationDescriptorComponent } from "../AICFormationDescriptorComponent";
|
||||
import { AICFormationDescriptorPhrase } from "../AICFormationDescriptorPhrase";
|
||||
import { AICFormation } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
interface addUnitInformationInterface {
|
||||
omitTrack?: boolean
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { AICFormation } from "../AICFormation";
|
||||
import { AICFormationContextDataInterface } from "../AICFormationDescriptor";
|
||||
import { AICFormationDescriptorSection } from "../AICFormationDescriptorSection";
|
||||
import { AICFormationDescriptorComponent } from "../AICFormationDescriptorComponent";
|
||||
import { AICFormationDescriptorPhrase } from "../AICFormationDescriptorPhrase";
|
||||
import { AICFormation } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
export class AICFormationDescriptorSection_Who extends AICFormationDescriptorSection {
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { ToggleableFeature } from "../ToggleableFeature";
|
||||
import { AICFormation_Azimuth } from "./AICFormation/Azimuth";
|
||||
import { AICFormation_Range } from "./AICFormation/Range";
|
||||
import { AICFormation_Single } from "./AICFormation/Single";
|
||||
import { AICFormationDescriptorSection } from "./AICFormationDescriptorSection";
|
||||
import { ToggleableFeature } from "../toggleablefeature";
|
||||
import { AICFormation_Azimuth } from "./aicformation/azimuth";
|
||||
import { AICFormation_Range } from "./aicformation/range";
|
||||
import { AICFormation_Single } from "./aicformation/single";
|
||||
import { AICFormationDescriptorSection } from "./aicformationdescriptorsection";
|
||||
|
||||
|
||||
export class AIC extends ToggleableFeature {
|
||||
|
||||
54
client/src/aic/aicformation.ts
Normal file
54
client/src/aic/aicformation.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import { AICFormationContextDataInterface, AICFormationDescriptor } from "./aicformationdescriptor";
|
||||
import { AICFormationDescriptorPhrase } from "./aicformationdescriptorphrase";
|
||||
import { AICFormationDescriptorSection } from "./aicformationdescriptorsection";
|
||||
|
||||
export interface AICFormationInterface {
|
||||
"icon" : string,
|
||||
"label" : string,
|
||||
"name" : string,
|
||||
"numGroups" : number,
|
||||
"summary" : string,
|
||||
"unitBreakdown" : string[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
export abstract class AICFormation {
|
||||
|
||||
"icon" = "";
|
||||
"label" = "";
|
||||
"name" = "";
|
||||
"numGroups" = 1;
|
||||
"summary" = "";
|
||||
"unitBreakdown":string[] = []
|
||||
|
||||
|
||||
constructor() {
|
||||
|
||||
this.unitBreakdown = [];
|
||||
}
|
||||
|
||||
|
||||
addToDescriptorPhrase( section: AICFormationDescriptorSection, phrase: AICFormationDescriptorPhrase, contextData: AICFormationContextDataInterface ) {
|
||||
return phrase;
|
||||
}
|
||||
|
||||
|
||||
getDescriptor( contextData: AICFormationContextDataInterface ) {
|
||||
|
||||
return new AICFormationDescriptor().generate( this, contextData );
|
||||
|
||||
}
|
||||
|
||||
|
||||
hasUnitBreakdown() {
|
||||
return this.unitBreakdown.length > 0;
|
||||
}
|
||||
|
||||
|
||||
showFormationNameInDescriptor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
38
client/src/aic/aicformation/azimuth.ts
Normal file
38
client/src/aic/aicformation/azimuth.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { AICFormation, AICFormationInterface } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
export class AICFormation_Azimuth extends AICFormation implements AICFormationInterface {
|
||||
|
||||
"icon" = "azimuth.png";
|
||||
"label" = "Azimuth";
|
||||
"name" = "azimuth";
|
||||
"numGroups" = 2;
|
||||
"summary" = "Two contacts, side-by-side in a line perpedicular to the perspective.";
|
||||
"unitBreakdown" = [ "<compass> group", "<compass> group" ];
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
addToDescriptorPhrase( section: AICFormationDescriptorSection, phrase: AICFormationDescriptorPhrase, contextData: AICFormationContextDataInterface ) {
|
||||
|
||||
switch ( section.name ) {
|
||||
|
||||
case "formation":
|
||||
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "<distance>" ) );
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "track <compass>" ) );
|
||||
|
||||
}
|
||||
|
||||
return phrase;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
38
client/src/aic/aicformation/range.ts
Normal file
38
client/src/aic/aicformation/range.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { AICFormation, AICFormationInterface } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
export class AICFormation_Range extends AICFormation implements AICFormationInterface {
|
||||
|
||||
"icon" = "range.png";
|
||||
"label" = "Range";
|
||||
"name" = "range";
|
||||
"numGroups" = 2;
|
||||
"summary" = "Two contacts, one behind the other";
|
||||
"unitBreakdown" = [ "Lead group", "Trail group" ];
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
addToDescriptorPhrase( section: AICFormationDescriptorSection, phrase: AICFormationDescriptorPhrase, contextData: AICFormationContextDataInterface ) {
|
||||
|
||||
switch ( section.name ) {
|
||||
|
||||
case "formation":
|
||||
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "<distance>" ) );
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "track <compass>" ) );
|
||||
|
||||
|
||||
}
|
||||
|
||||
return phrase;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
24
client/src/aic/aicformation/single.ts
Normal file
24
client/src/aic/aicformation/single.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { AICFormation, AICFormationInterface } from "../aicformation";
|
||||
import { AICFormationContextDataInterface, AICFormationDescriptor } from "../aicformationdescriptor";
|
||||
|
||||
export class AICFormation_Single extends AICFormation implements AICFormationInterface {
|
||||
|
||||
"icon" = "single.png";
|
||||
"label" = "Single";
|
||||
"name" = "single";
|
||||
"numGroups" = 1;
|
||||
"summary" = "One contact on its own";
|
||||
"unitBreakdown" = [];
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
|
||||
showFormationNameInDescriptor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
55
client/src/aic/aicformationdescriptor.ts
Normal file
55
client/src/aic/aicformationdescriptor.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { AICFormation } from "./aicformation";
|
||||
import { AICFormationDescriptorSection } from "./aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorSection_Formation } from "./aicformationdescriptorsection/formation";
|
||||
import { AICFormationDescriptorSection_Unit } from "./aicformationdescriptorsection/unit";
|
||||
import { AICFormationDescriptorSection_NumGroups } from "./aicformationdescriptorsection/numgroups";
|
||||
import { AICFormationDescriptorSection_Who } from "./aicformationdescriptorsection/who";
|
||||
|
||||
|
||||
export interface AICFormationContextDataInterface {
|
||||
"aicCallsign" : string,
|
||||
"bullseyeName" : string,
|
||||
"control" : "broadcast" | "tactical",
|
||||
"numGroups" : number
|
||||
}
|
||||
|
||||
|
||||
export class AICFormationDescriptor {
|
||||
|
||||
#sections:AICFormationDescriptorSection[] = [
|
||||
new AICFormationDescriptorSection_Who(),
|
||||
new AICFormationDescriptorSection_NumGroups(),
|
||||
new AICFormationDescriptorSection_Formation(),
|
||||
new AICFormationDescriptorSection_Unit()
|
||||
]
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
addSection( section:AICFormationDescriptorSection ) {
|
||||
this.#sections.push( section );
|
||||
}
|
||||
|
||||
|
||||
getSections() {
|
||||
return this.#sections;
|
||||
}
|
||||
|
||||
|
||||
generate( formation:AICFormation, contextData: AICFormationContextDataInterface ) {
|
||||
|
||||
let output:object[] = [];
|
||||
|
||||
for ( const section of this.#sections ) {
|
||||
output.push(
|
||||
section.generate( formation, contextData )
|
||||
);
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
18
client/src/aic/aicformationdescriptorcomponent.ts
Normal file
18
client/src/aic/aicformationdescriptorcomponent.ts
Normal file
@ -0,0 +1,18 @@
|
||||
interface ComponentInterface {
|
||||
"label" : string;
|
||||
"value" : string;
|
||||
}
|
||||
|
||||
export class AICFormationDescriptorComponent implements ComponentInterface {
|
||||
|
||||
label = "(not set)";
|
||||
value = "(not set)";
|
||||
|
||||
constructor( value:any, label?:string ) {
|
||||
|
||||
this.label = label || "(not set)";
|
||||
this.value = value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
|
||||
export abstract class AICFormactionDescriptorComponent_Distance extends AICFormationDescriptorComponent {
|
||||
|
||||
constructor( value:string, label?:string ) {
|
||||
super( value, label );
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
import { AICFormactionDescriptorComponent_Distance } from "../distance";
|
||||
|
||||
export class AICFormationDescriptorComponent_Distance_Range extends AICFormactionDescriptorComponent_Distance {
|
||||
|
||||
constructor( value:string, label?:string ) {
|
||||
super( value, label );
|
||||
}
|
||||
|
||||
}
|
||||
40
client/src/aic/aicformationdescriptorphrase.ts
Normal file
40
client/src/aic/aicformationdescriptorphrase.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { AICFormation } from "./aicformation";
|
||||
import { AICFormationContextDataInterface } from "./aicformationdescriptor";
|
||||
import { AICFormationDescriptorComponent } from "./aicformationdescriptorcomponent";
|
||||
|
||||
export interface AICFormationDescriptorPhraseInterface {
|
||||
"generate" : CallableFunction,
|
||||
"label" : string,
|
||||
"name" : string
|
||||
}
|
||||
|
||||
export class AICFormationDescriptorPhrase {
|
||||
|
||||
#components : AICFormationDescriptorComponent[] = [];
|
||||
label = "";
|
||||
name = "";
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
addComponent( component:AICFormationDescriptorComponent ) {
|
||||
this.#components.push( component );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
getComponents() {
|
||||
return this.#components;
|
||||
}
|
||||
|
||||
|
||||
generate( formation:AICFormation, contextData: AICFormationContextDataInterface ) {
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
40
client/src/aic/aicformationdescriptorsection.ts
Normal file
40
client/src/aic/aicformationdescriptorsection.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { AICFormation } from "./aicformation";
|
||||
import { AICFormationContextDataInterface } from "./aicformationdescriptor";
|
||||
import { AICFormationDescriptorPhrase } from "./aicformationdescriptorphrase";
|
||||
|
||||
export interface AICFormationDescriptorSectionInterface {
|
||||
"generate" : CallableFunction,
|
||||
"label" : string,
|
||||
"name" : string,
|
||||
"omitSection" : boolean
|
||||
}
|
||||
|
||||
export abstract class AICFormationDescriptorSection {
|
||||
|
||||
#phrases : AICFormationDescriptorPhrase[] = [];
|
||||
label = "";
|
||||
name = "";
|
||||
omitSection = false;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
addPhrase( phrase:AICFormationDescriptorPhrase ) {
|
||||
this.#phrases.push( phrase );
|
||||
}
|
||||
|
||||
|
||||
generate( formation:AICFormation, contextData: AICFormationContextDataInterface ) {
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
getPhrases() {
|
||||
return this.#phrases;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
39
client/src/aic/aicformationdescriptorsection/formation.ts
Normal file
39
client/src/aic/aicformationdescriptorsection/formation.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { AICFormation } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
export class AICFormationDescriptorSection_Formation extends AICFormationDescriptorSection {
|
||||
|
||||
label = "Formation";
|
||||
name = "formation";
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
|
||||
generate( formation:AICFormation, contextData: AICFormationContextDataInterface ) {
|
||||
|
||||
if ( !formation.showFormationNameInDescriptor() ) {
|
||||
this.omitSection = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
let phrase = new AICFormationDescriptorPhrase();
|
||||
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( formation.label, "Formation" ) );
|
||||
|
||||
phrase = formation.addToDescriptorPhrase( this, phrase, contextData );
|
||||
|
||||
this.addPhrase( phrase );
|
||||
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
35
client/src/aic/aicformationdescriptorsection/numgroups.ts
Normal file
35
client/src/aic/aicformationdescriptorsection/numgroups.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { AICFormation } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
export class AICFormationDescriptorSection_NumGroups extends AICFormationDescriptorSection {
|
||||
|
||||
label = "Groups";
|
||||
name = "numgroups";
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
|
||||
generate( formation:AICFormation, contextData: AICFormationContextDataInterface ) {
|
||||
|
||||
let value = "Single group";
|
||||
|
||||
if ( contextData.numGroups > 1 ) {
|
||||
value = contextData.numGroups + " groups";
|
||||
}
|
||||
|
||||
let phrase = new AICFormationDescriptorPhrase();
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( value, "Number of groups" ) );
|
||||
this.addPhrase( phrase );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
83
client/src/aic/aicformationdescriptorsection/unit.ts
Normal file
83
client/src/aic/aicformationdescriptorsection/unit.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { AICFormation } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
interface addUnitInformationInterface {
|
||||
omitTrack?: boolean
|
||||
}
|
||||
|
||||
export class AICFormationDescriptorSection_Unit extends AICFormationDescriptorSection {
|
||||
|
||||
label = "Unit";
|
||||
name = "unit";
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
|
||||
addUnitInformation( formation:AICFormation, contextData: AICFormationContextDataInterface, phrase: AICFormationDescriptorPhrase, options?:addUnitInformationInterface ) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
const originPoint = ( contextData.control === "broadcast" ) ? contextData.bullseyeName : "BRAA";
|
||||
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( originPoint, "Bearing origin point" ) );
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "<bearing>", "Bearing" ) );
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "<range>", "Range" ) );
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "<altitude>", "Altitude" ) );
|
||||
|
||||
if ( contextData.control === "broadcast" ) {
|
||||
if ( !options.hasOwnProperty( "omitTrack" ) || options.omitTrack !== true ) {
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "track <compass>", "Tracking" ) );
|
||||
}
|
||||
} else {
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "[hot|flanking [left|right]|beam <compass>|cold]", "Azimuth" ) );
|
||||
}
|
||||
|
||||
return phrase;
|
||||
|
||||
}
|
||||
|
||||
|
||||
generate( formation:AICFormation, contextData: AICFormationContextDataInterface ) {
|
||||
|
||||
if ( formation.hasUnitBreakdown() ) {
|
||||
|
||||
for ( const [ i, unitRef ] of formation.unitBreakdown.entries() ) {
|
||||
|
||||
let phrase = new AICFormationDescriptorPhrase();
|
||||
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( unitRef, "Unit reference" ) );
|
||||
|
||||
if ( i === 0 ) {
|
||||
this.addUnitInformation( formation, contextData, phrase, { "omitTrack": true } );
|
||||
} else {
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "<altitude>" ) );
|
||||
}
|
||||
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "hostile" ) );
|
||||
|
||||
this.addPhrase( phrase );
|
||||
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
this.addPhrase(
|
||||
this.addUnitInformation( formation, contextData, new AICFormationDescriptorPhrase() )
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
35
client/src/aic/aicformationdescriptorsection/who.ts
Normal file
35
client/src/aic/aicformationdescriptorsection/who.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { AICFormation } from "../aicformation";
|
||||
import { AICFormationContextDataInterface } from "../aicformationdescriptor";
|
||||
import { AICFormationDescriptorSection } from "../aicformationdescriptorsection";
|
||||
import { AICFormationDescriptorComponent } from "../aicformationdescriptorcomponent";
|
||||
import { AICFormationDescriptorPhrase } from "../aicformationdescriptorphrase";
|
||||
|
||||
export class AICFormationDescriptorSection_Who extends AICFormationDescriptorSection {
|
||||
|
||||
label = "Who";
|
||||
name = "who";
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
|
||||
generate( formation:AICFormation, contextData: AICFormationContextDataInterface ) {
|
||||
|
||||
let phrase = new AICFormationDescriptorPhrase();
|
||||
|
||||
if ( contextData.control === "tactical" ) {
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( "<their callsign>", "Their callsign" ) );
|
||||
}
|
||||
|
||||
phrase.addComponent( new AICFormationDescriptorComponent( contextData.aicCallsign, "Your callsign" ) );
|
||||
|
||||
this.addPhrase( phrase );
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { ToggleableFeature } from "../ToggleableFeature";
|
||||
import { ToggleableFeature } from "../toggleablefeature";
|
||||
import Sortable from 'sortablejs';
|
||||
import { ATCFLightList } from "./FlightList";
|
||||
import { ATCFLightList } from "./flightlist";
|
||||
|
||||
export class ATC extends ToggleableFeature {
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ATCMockAPI } from "../ATCMockAPI";
|
||||
import { ATCMockAPI } from "../atcmockapi";
|
||||
|
||||
export class ATCMockAPI_Flights extends ATCMockAPI {
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ATCMockAPI_Flights } from "./ATCMockAPI/Flights";
|
||||
import { ATCMockAPI_Flights } from "./atcmockapi/flights";
|
||||
|
||||
export class ATCFLightList {
|
||||
|
||||
|
||||
87
client/src/atc/atc.ts
Normal file
87
client/src/atc/atc.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import { ToggleableFeature } from "../toggleablefeature";
|
||||
import Sortable from 'sortablejs';
|
||||
import { ATCFLightList } from "./flightlist";
|
||||
|
||||
export class ATC extends ToggleableFeature {
|
||||
|
||||
constructor() {
|
||||
|
||||
super( true );
|
||||
|
||||
//this.#generateFlightList();
|
||||
|
||||
let $list = document.getElementById( "atc-strip-board-arrivals" );
|
||||
|
||||
if ( $list instanceof HTMLElement ) {
|
||||
Sortable.create( $list, {
|
||||
"handle": ".handle"
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#generateFlightList() {
|
||||
|
||||
const flightList = new ATCFLightList();
|
||||
const flights:any = flightList.getFlights( true );
|
||||
|
||||
const $tbody = document.getElementById( "atc-flight-list-table-body" );
|
||||
|
||||
if ( $tbody instanceof HTMLElement ) {
|
||||
|
||||
if ( flights.length > 0 ) {
|
||||
|
||||
let flight:any = {};
|
||||
|
||||
let $button, i;
|
||||
|
||||
for ( [ i, flight ] of flights.entries() ) {
|
||||
|
||||
const $row = document.createElement( "tr" );
|
||||
$row.dataset.status = flight.status
|
||||
|
||||
let $td = document.createElement( "td" );
|
||||
$td.innerText = flight.name;
|
||||
$row.appendChild( $td );
|
||||
|
||||
$td = document.createElement( "td" );
|
||||
$td.innerText = flight.takeOffTime;
|
||||
$row.appendChild( $td );
|
||||
|
||||
$td = document.createElement( "td" );
|
||||
$td.innerText = "00:0" + ( 5 + i );
|
||||
$row.appendChild( $td );
|
||||
|
||||
$td = document.createElement( "td" );
|
||||
$td.innerText = flight.status;
|
||||
$row.appendChild( $td );
|
||||
|
||||
|
||||
$td = document.createElement( "td" );
|
||||
$button = document.createElement( "button" );
|
||||
$button.innerText = "...";
|
||||
|
||||
$td.appendChild( $button );
|
||||
|
||||
$row.appendChild( $td );
|
||||
|
||||
|
||||
$tbody.appendChild( $row );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected onStatusUpdate(): void {
|
||||
|
||||
document.body.classList.toggle( "atc-enabled", this.getStatus() );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
7
client/src/atc/atcmockapi.ts
Normal file
7
client/src/atc/atcmockapi.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export abstract class ATCMockAPI {
|
||||
|
||||
constructor() {}
|
||||
|
||||
generateMockData() {}
|
||||
|
||||
}
|
||||
40
client/src/atc/atcmockapi/flights.ts
Normal file
40
client/src/atc/atcmockapi/flights.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { ATCMockAPI } from "../atcmockapi";
|
||||
|
||||
export class ATCMockAPI_Flights extends ATCMockAPI {
|
||||
|
||||
|
||||
generateMockData() {
|
||||
|
||||
let data = [];
|
||||
const statuses = [ "unknown", "checkedIn", "readyToTaxi" ]
|
||||
|
||||
for ( const [ i, flightName ] of [ "Shark", "Whale", "Dolphin" ].entries() ) {
|
||||
|
||||
data.push({
|
||||
"name": flightName,
|
||||
"status": statuses[ i ],
|
||||
"takeOffTime": "18:0" + i
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
localStorage.setItem( "flightList", JSON.stringify( data ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
get( generateMockDataIfEmpty?:boolean ) : object {
|
||||
|
||||
generateMockDataIfEmpty = generateMockDataIfEmpty || false;
|
||||
|
||||
let data = localStorage.getItem( "flightList" ) || "[]";
|
||||
|
||||
if ( data === "[]" && generateMockDataIfEmpty ) {
|
||||
this.generateMockData();
|
||||
}
|
||||
|
||||
return JSON.parse( data );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
18
client/src/atc/flightlist.ts
Normal file
18
client/src/atc/flightlist.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { ATCMockAPI_Flights } from "./atcmockapi/flights";
|
||||
|
||||
export class ATCFLightList {
|
||||
|
||||
|
||||
constructor() {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
getFlights( generateMockDataIfEmpty?:boolean ) {
|
||||
let api = new ATCMockAPI_Flights();
|
||||
return api.get( generateMockDataIfEmpty );
|
||||
}
|
||||
|
||||
}
|
||||
161
client/src/featureswitches.ts
Normal file
161
client/src/featureswitches.ts
Normal file
@ -0,0 +1,161 @@
|
||||
export interface FeatureSwitchInterface {
|
||||
"defaultEnabled": boolean, // default on/off state (if allowed by masterSwitch)
|
||||
"label": string,
|
||||
"masterSwitch": boolean, // on/off regardless of user preference
|
||||
"name": string,
|
||||
"onEnabled"?: CallableFunction,
|
||||
"options"?: object,
|
||||
"removeArtifactsIfDisabled"?: boolean
|
||||
}
|
||||
|
||||
|
||||
class FeatureSwitch {
|
||||
|
||||
// From config param
|
||||
defaultEnabled;
|
||||
label;
|
||||
masterSwitch;
|
||||
name;
|
||||
onEnabled;
|
||||
removeArtifactsIfDisabled = true;
|
||||
|
||||
// Self-set
|
||||
userPreference;
|
||||
|
||||
|
||||
constructor( config:FeatureSwitchInterface ) {
|
||||
|
||||
this.defaultEnabled = config.defaultEnabled;
|
||||
this.label = config.label;
|
||||
this.masterSwitch = config.masterSwitch;
|
||||
this.name = config.name;
|
||||
this.onEnabled = config.onEnabled;
|
||||
|
||||
this.userPreference = this.getUserPreference();
|
||||
|
||||
}
|
||||
|
||||
|
||||
getUserPreference() {
|
||||
|
||||
let preferences = JSON.parse( localStorage.getItem( "featureSwitches" ) || "{}" );
|
||||
|
||||
return ( preferences.hasOwnProperty( this.name ) ) ? preferences[ this.name ] : this.defaultEnabled;
|
||||
|
||||
}
|
||||
|
||||
|
||||
isEnabled() {
|
||||
|
||||
if ( !this.masterSwitch ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.userPreference;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class FeatureSwitches {
|
||||
|
||||
#featureSwitches:FeatureSwitch[] = [
|
||||
|
||||
new FeatureSwitch({
|
||||
"defaultEnabled": false,
|
||||
"label": "AIC",
|
||||
"masterSwitch": true,
|
||||
"name": "aic"
|
||||
}),
|
||||
|
||||
new FeatureSwitch({
|
||||
"defaultEnabled": false,
|
||||
"label": "AI Formations",
|
||||
"masterSwitch": true,
|
||||
"name": "ai-formations",
|
||||
"removeArtifactsIfDisabled": false
|
||||
}),
|
||||
|
||||
new FeatureSwitch({
|
||||
"defaultEnabled": false,
|
||||
"label": "ATC",
|
||||
"masterSwitch": true,
|
||||
"name": "atc"
|
||||
}),
|
||||
|
||||
new FeatureSwitch({
|
||||
"defaultEnabled": false,
|
||||
"label": "Force show unit control panel",
|
||||
"masterSwitch": true,
|
||||
"name": "forceShowUnitControlPanel"
|
||||
}),
|
||||
|
||||
new FeatureSwitch({
|
||||
"defaultEnabled": false,
|
||||
"label": "Show splash screen",
|
||||
"masterSwitch": true,
|
||||
"name": "splashScreen"
|
||||
})
|
||||
|
||||
];
|
||||
|
||||
|
||||
constructor() {
|
||||
|
||||
this.#testSwitches();
|
||||
|
||||
this.savePreferences();
|
||||
|
||||
}
|
||||
|
||||
|
||||
getSwitch( switchName:string ) {
|
||||
|
||||
return this.#featureSwitches.find( featureSwitch => featureSwitch.name === switchName );
|
||||
|
||||
}
|
||||
|
||||
|
||||
#testSwitches() {
|
||||
|
||||
for ( const featureSwitch of this.#featureSwitches ) {
|
||||
|
||||
if ( featureSwitch.isEnabled() ) {
|
||||
|
||||
if ( typeof featureSwitch.onEnabled === "function" ) {
|
||||
featureSwitch.onEnabled();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
document.querySelectorAll( "[data-feature-switch='" + featureSwitch.name + "']" ).forEach( el => {
|
||||
|
||||
if ( featureSwitch.removeArtifactsIfDisabled === false ) {
|
||||
el.remove();
|
||||
} else {
|
||||
el.classList.add( "hide" );
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
document.body.classList.toggle( "feature-" + featureSwitch.name, featureSwitch.isEnabled() );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
savePreferences() {
|
||||
|
||||
let preferences:any = {};
|
||||
|
||||
for ( const featureSwitch of this.#featureSwitches ) {
|
||||
preferences[ featureSwitch.name ] = featureSwitch.isEnabled();
|
||||
}
|
||||
|
||||
localStorage.setItem( "featureSwitches", JSON.stringify( preferences ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,8 +6,8 @@ import { MissionHandler } from "./missionhandler/missionhandler";
|
||||
import { UnitControlPanel } from "./panels/unitcontrolpanel";
|
||||
import { MouseInfoPanel } from "./panels/mouseinfopanel";
|
||||
import { AIC } from "./aic/aic";
|
||||
import { ATC } from "./atc/ATC";
|
||||
import { FeatureSwitches } from "./FeatureSwitches";
|
||||
import { ATC } from "./atc/atc";
|
||||
import { FeatureSwitches } from "./featureswitches";
|
||||
import { LogPanel } from "./panels/logpanel";
|
||||
import { getAirbases, getBulllseye as getBulllseyes, getMission, getUnits, toggleDemoEnabled } from "./server/server";
|
||||
|
||||
|
||||
35
client/src/toggleablefeature.ts
Normal file
35
client/src/toggleablefeature.ts
Normal file
@ -0,0 +1,35 @@
|
||||
export abstract class ToggleableFeature {
|
||||
|
||||
#status:boolean = false;
|
||||
|
||||
|
||||
constructor( defaultStatus:boolean ) {
|
||||
|
||||
this.#status = defaultStatus;
|
||||
|
||||
this.onStatusUpdate();
|
||||
|
||||
}
|
||||
|
||||
|
||||
getStatus() : boolean {
|
||||
return this.#status;
|
||||
}
|
||||
|
||||
|
||||
protected onStatusUpdate() {}
|
||||
|
||||
|
||||
toggleStatus( force?:boolean ) : void {
|
||||
|
||||
if ( force ) {
|
||||
this.#status = force;
|
||||
} else {
|
||||
this.#status = !this.#status;
|
||||
}
|
||||
|
||||
this.onStatusUpdate();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
BIN
missions/olympus.miz
Normal file
BIN
missions/olympus.miz
Normal file
Binary file not shown.
275
src/core/include/commands.h
Normal file
275
src/core/include/commands.h
Normal file
@ -0,0 +1,275 @@
|
||||
#pragma once
|
||||
#include "framework.h"
|
||||
#include "luatools.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace CommandPriority {
|
||||
enum CommandPriorities { LOW, MEDIUM, HIGH };
|
||||
};
|
||||
|
||||
namespace CommandType {
|
||||
enum CommandTypes { NO_TYPE, MOVE, SMOKE, SPAWN_AIR, SPAWN_GROUND, CLONE, FOLLOW, RESET_TASK, SET_OPTION, SET_COMMAND, SET_TASK };
|
||||
};
|
||||
|
||||
namespace SetCommandType {
|
||||
enum SetCommandTypes {
|
||||
ROE = 0,
|
||||
REACTION_ON_THREAT = 1,
|
||||
RADAR_USING = 3,
|
||||
FLARE_USING = 4,
|
||||
FORMATION = 5,
|
||||
RTB_ON_BINGO = 6,
|
||||
SILENCE = 7,
|
||||
RTB_ON_OUT_OF_AMMO = 10,
|
||||
ECM_USING = 13,
|
||||
PROHIBIT_AA = 14,
|
||||
PROHIBIT_JETT = 15,
|
||||
PROHIBIT_AB = 16,
|
||||
PROHIBIT_AG = 17,
|
||||
MISSILE_ATTACK = 18,
|
||||
PROHIBIT_WP_PASS_REPORT = 19,
|
||||
OPTION_RADIO_USAGE_CONTACT = 21,
|
||||
OPTION_RADIO_USAGE_ENGAGE = 22,
|
||||
OPTION_RADIO_USAGE_KILL = 23,
|
||||
JETT_TANKS_IF_EMPTY = 25,
|
||||
FORCED_ATTACK = 26
|
||||
};
|
||||
}
|
||||
|
||||
namespace ROE {
|
||||
enum ROEs {
|
||||
WEAPON_FREE = 0,
|
||||
OPEN_FIRE_WEAPON_FREE = 1,
|
||||
OPEN_FIRE = 2,
|
||||
RETURN_FIRE = 3,
|
||||
WEAPON_HOLD = 4,
|
||||
};
|
||||
}
|
||||
|
||||
namespace ReactionToThreat {
|
||||
enum ReactionToThreats {
|
||||
NO_REACTION = 0,
|
||||
PASSIVE_DEFENCE = 1,
|
||||
EVADE_FIRE = 2,
|
||||
BYPASS_AND_ESCAPE = 3,
|
||||
ALLOW_ABORT_MISSION = 4
|
||||
};
|
||||
}
|
||||
|
||||
/* Base command class */
|
||||
class Command
|
||||
{
|
||||
public:
|
||||
int getPriority() { return priority; }
|
||||
int getType() { return type; }
|
||||
virtual wstring getString(lua_State* L) = 0;
|
||||
virtual int getLoad() = 0;
|
||||
|
||||
protected:
|
||||
int priority = CommandPriority::LOW;
|
||||
int type = CommandType::NO_TYPE;
|
||||
};
|
||||
|
||||
/* Simple low priority move command (from user click) */
|
||||
class Move : public Command
|
||||
{
|
||||
public:
|
||||
Move(int ID, Coords destination, double speed, double altitude, wstring unitCategory, wstring taskOptions):
|
||||
ID(ID),
|
||||
destination(destination),
|
||||
speed(speed),
|
||||
altitude(altitude),
|
||||
unitCategory(unitCategory),
|
||||
taskOptions(taskOptions)
|
||||
{
|
||||
priority = CommandPriority::HIGH;
|
||||
type = CommandType::MOVE;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
const Coords destination;
|
||||
const wstring unitCategory;
|
||||
const double speed;
|
||||
const double altitude;
|
||||
const wstring taskOptions;
|
||||
};
|
||||
|
||||
/* Smoke command */
|
||||
class Smoke : public Command
|
||||
{
|
||||
public:
|
||||
Smoke(wstring color, Coords location) :
|
||||
color(color),
|
||||
location(location)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
type = CommandType::SMOKE;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const wstring color;
|
||||
const Coords location;
|
||||
};
|
||||
|
||||
/* Spawn ground unit command */
|
||||
class SpawnGroundUnit : public Command
|
||||
{
|
||||
public:
|
||||
SpawnGroundUnit(wstring coalition, wstring unitType, Coords location) :
|
||||
coalition(coalition),
|
||||
unitType(unitType),
|
||||
location(location)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
type = CommandType::SPAWN_GROUND;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 100; }
|
||||
|
||||
private:
|
||||
const wstring coalition;
|
||||
const wstring unitType;
|
||||
const Coords location;
|
||||
};
|
||||
|
||||
/* Spawn air unit command */
|
||||
class SpawnAircraft : public Command
|
||||
{
|
||||
public:
|
||||
SpawnAircraft(wstring coalition, wstring unitType, Coords location, wstring payloadName, wstring airbaseName) :
|
||||
coalition(coalition),
|
||||
unitType(unitType),
|
||||
location(location),
|
||||
payloadName(payloadName),
|
||||
airbaseName(airbaseName)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
type = CommandType::SPAWN_AIR;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 100; }
|
||||
|
||||
private:
|
||||
const wstring coalition;
|
||||
const wstring unitType;
|
||||
const Coords location;
|
||||
const wstring payloadName;
|
||||
const wstring airbaseName;
|
||||
};
|
||||
|
||||
/* Clone unit command */
|
||||
class Clone : public Command
|
||||
{
|
||||
public:
|
||||
Clone(int ID, Coords location) :
|
||||
ID(ID),
|
||||
location(location)
|
||||
{
|
||||
priority = CommandPriority::LOW;
|
||||
type = CommandType::CLONE;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 100; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
const Coords location;
|
||||
};
|
||||
|
||||
/* Delete unit command */
|
||||
class Delete : public Command
|
||||
{
|
||||
public:
|
||||
Delete(int ID) :
|
||||
ID(ID)
|
||||
{
|
||||
priority = CommandPriority::HIGH;
|
||||
type = CommandType::CLONE;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 20; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
};
|
||||
|
||||
/* Follow command */
|
||||
class SetTask : public Command
|
||||
{
|
||||
public:
|
||||
SetTask(int ID, wstring task) :
|
||||
ID(ID),
|
||||
task(task)
|
||||
{
|
||||
priority = CommandPriority::MEDIUM;
|
||||
type = CommandType::FOLLOW;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 10; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
const wstring task;
|
||||
};
|
||||
|
||||
/* Reset task command */
|
||||
class ResetTask : public Command
|
||||
{
|
||||
public:
|
||||
ResetTask(int ID) :
|
||||
ID(ID)
|
||||
{
|
||||
priority = CommandPriority::HIGH;
|
||||
type = CommandType::RESET_TASK;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 10; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
};
|
||||
|
||||
/* Set command */
|
||||
class SetCommand : public Command
|
||||
{
|
||||
public:
|
||||
SetCommand(int ID, wstring command) :
|
||||
ID(ID),
|
||||
command(command)
|
||||
{
|
||||
priority = CommandPriority::HIGH;
|
||||
type = CommandType::RESET_TASK;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 10; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
const wstring command;
|
||||
};
|
||||
|
||||
/* Set option command */
|
||||
class SetOption : public Command
|
||||
{
|
||||
public:
|
||||
SetOption(int ID, int optionID, int optionValue) :
|
||||
ID(ID),
|
||||
optionID(optionID),
|
||||
optionValue(optionValue)
|
||||
{
|
||||
priority = CommandPriority::HIGH;
|
||||
type = CommandType::RESET_TASK;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 10; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
const int optionID;
|
||||
const int optionValue;
|
||||
};
|
||||
20
src/core/include/scheduler.h
Normal file
20
src/core/include/scheduler.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "framework.h"
|
||||
#include "luatools.h"
|
||||
#include "commands.h"
|
||||
|
||||
class Scheduler
|
||||
{
|
||||
public:
|
||||
Scheduler(lua_State* L);
|
||||
~Scheduler();
|
||||
|
||||
void appendCommand(Command* command);
|
||||
void execute(lua_State* L);
|
||||
void handleRequest(wstring key, json::value value);
|
||||
|
||||
private:
|
||||
list<Command*> commands;
|
||||
int load;
|
||||
};
|
||||
|
||||
184
src/core/include/unit.h
Normal file
184
src/core/include/unit.h
Normal file
@ -0,0 +1,184 @@
|
||||
#pragma once
|
||||
#include "framework.h"
|
||||
#include "utils.h"
|
||||
#include "dcstools.h"
|
||||
#include "luatools.h"
|
||||
#include "measure.h"
|
||||
|
||||
namespace State
|
||||
{
|
||||
enum States
|
||||
{
|
||||
IDLE,
|
||||
REACH_DESTINATION,
|
||||
ATTACK,
|
||||
WINGMAN,
|
||||
FOLLOW,
|
||||
LAND,
|
||||
REFUEL,
|
||||
AWACS,
|
||||
EWR,
|
||||
TANKER,
|
||||
RUN_AWAY
|
||||
};
|
||||
};
|
||||
|
||||
class Unit
|
||||
{
|
||||
public:
|
||||
Unit(json::value json, int ID);
|
||||
~Unit();
|
||||
|
||||
/********** Public methods **********/
|
||||
int getID() { return ID; }
|
||||
void updateExportData(json::value json);
|
||||
void updateMissionData(json::value json);
|
||||
json::value getData(long long time);
|
||||
|
||||
/********** Base data **********/
|
||||
void setAI(bool newAI) { AI = newAI; addMeasure(L"AI", json::value(newAI)); }
|
||||
void setName(wstring newName) { name = newName; addMeasure(L"name", json::value(newName));}
|
||||
void setUnitName(wstring newUnitName) { unitName = newUnitName; addMeasure(L"unitName", json::value(newUnitName));}
|
||||
void setGroupName(wstring newGroupName) { groupName = newGroupName; addMeasure(L"groupName", json::value(newGroupName));}
|
||||
void setAlive(bool newAlive) { alive = newAlive; addMeasure(L"alive", json::value(newAlive));}
|
||||
void setType(json::value newType) { type = newType; addMeasure(L"type", newType);}
|
||||
void setCountry(int newCountry) { country = newCountry; addMeasure(L"country", json::value(newCountry));}
|
||||
bool getAI() { return AI; }
|
||||
wstring getName() { return name; }
|
||||
wstring getUnitName() { return unitName; }
|
||||
wstring getGroupName() { return groupName; }
|
||||
bool getAlive() { return alive; }
|
||||
json::value getType() { return type; }
|
||||
int getCountry() { return country; }
|
||||
|
||||
/********** Flight data **********/
|
||||
void setLatitude(double newLatitude) {latitude = newLatitude; addMeasure(L"latitude", json::value(newLatitude));}
|
||||
void setLongitude(double newLongitude) {longitude = newLongitude; addMeasure(L"longitude", json::value(newLongitude));}
|
||||
void setAltitude(double newAltitude) {altitude = newAltitude; addMeasure(L"altitude", json::value(newAltitude));}
|
||||
void setHeading(double newHeading) {heading = newHeading; addMeasure(L"heading", json::value(newHeading));}
|
||||
void setSpeed(double newSpeed) {speed = newSpeed; addMeasure(L"speed", json::value(newSpeed));}
|
||||
double getLatitude() { return latitude; }
|
||||
double getLongitude() { return longitude; }
|
||||
double getAltitude() { return altitude; }
|
||||
double getHeading() { return heading; }
|
||||
double getSpeed() { return speed; }
|
||||
|
||||
/********** Mission data **********/
|
||||
void setFuel(double newFuel) { fuel = newFuel; addMeasure(L"fuel", json::value(newFuel));}
|
||||
void setAmmo(json::value newAmmo) { ammo = newAmmo; addMeasure(L"ammo", json::value(newAmmo));}
|
||||
void setTargets(json::value newTargets) {targets = newTargets; addMeasure(L"targets", json::value(newTargets));}
|
||||
void setHasTask(bool newHasTask) { hasTask = newHasTask; addMeasure(L"hasTask", json::value(newHasTask));}
|
||||
void setCoalitionID(int newCoalitionID);
|
||||
void setFlags(json::value newFlags) { flags = newFlags; addMeasure(L"flags", json::value(newFlags));}
|
||||
double getFuel() { return fuel; }
|
||||
json::value getAmmo() { return ammo; }
|
||||
json::value getTargets() { return targets; }
|
||||
bool getHasTask() { return hasTask; }
|
||||
wstring getCoalition() { return coalition; }
|
||||
int getCoalitionID();
|
||||
json::value getFlags() { return flags; }
|
||||
|
||||
/********** Formation data **********/
|
||||
void setIsLeader(bool newIsLeader);
|
||||
void setIsWingman(bool newIsWingman);
|
||||
void setLeader(Unit* newLeader);
|
||||
void setWingmen(vector<Unit*> newWingmen);
|
||||
void setFormation(wstring newFormation) { formation = newFormation; addMeasure(L"formation", json::value(formation));}
|
||||
void setFormationOffset(Offset formationOffset);
|
||||
bool getIsLeader() { return isLeader; }
|
||||
bool getIsWingman() { return isWingman; }
|
||||
Unit* getLeader() { return leader; }
|
||||
vector<Unit*> getWingmen() { return wingmen; }
|
||||
wstring getFormation() { return formation; }
|
||||
Offset getFormationoffset() { return formationOffset; }
|
||||
|
||||
/********** Task data **********/
|
||||
void setCurrentTask(wstring newCurrentTask) { currentTask = newCurrentTask;addMeasure(L"currentTask", json::value(newCurrentTask)); }
|
||||
virtual void setTargetSpeed(double newTargetSpeed) { targetSpeed = newTargetSpeed; addMeasure(L"targetSpeed", json::value(newTargetSpeed));}
|
||||
virtual void setTargetAltitude(double newTargetAltitude) { targetAltitude = newTargetAltitude; addMeasure(L"targetAltitude", json::value(newTargetAltitude));} //TODO fix, double definition
|
||||
void setActiveDestination(Coords newActiveDestination) { activeDestination = newActiveDestination; addMeasure(L"activeDestination", json::value("")); } // TODO fix
|
||||
void setActivePath(list<Coords> newActivePath);
|
||||
void setTargetID(int newTargetID) { targetID = newTargetID; addMeasure(L"targetID", json::value(newTargetID));}
|
||||
wstring getCurrentTask() { return currentTask; }
|
||||
virtual double getTargetSpeed() { return targetSpeed; };
|
||||
virtual double getTargetAltitude() { return targetAltitude; };
|
||||
Coords getActiveDestination() { return activeDestination; }
|
||||
list<Coords> getActivePath() { return activePath; }
|
||||
int getTargetID() { return targetID; }
|
||||
|
||||
/********** Options data **********/
|
||||
void setROE(wstring newROE);
|
||||
void setReactionToThreat(wstring newReactionToThreat);
|
||||
wstring getROE() { return ROE; }
|
||||
wstring getReactionToThreat() {return reactionToThreat;}
|
||||
|
||||
/********** Control functions **********/
|
||||
void landAt(Coords loc);
|
||||
virtual void changeSpeed(wstring change){};
|
||||
virtual void changeAltitude(wstring change){};
|
||||
void resetActiveDestination();
|
||||
virtual void setState(int newState) { state = newState; };
|
||||
void resetTask();
|
||||
|
||||
protected:
|
||||
int ID;
|
||||
|
||||
map<wstring, Measure*> measures;
|
||||
|
||||
/********** Base data **********/
|
||||
bool AI = false;
|
||||
wstring name = L"undefined";
|
||||
wstring unitName = L"undefined";
|
||||
wstring groupName = L"undefined";
|
||||
bool alive = true;
|
||||
json::value type = json::value::null();
|
||||
int country = NULL;
|
||||
|
||||
/********** Flight data **********/
|
||||
double latitude = NULL;
|
||||
double longitude = NULL;
|
||||
double altitude = NULL;
|
||||
double speed = NULL;
|
||||
double heading = NULL;
|
||||
|
||||
/********** Mission data **********/
|
||||
double fuel = 0;
|
||||
json::value ammo = json::value::null();
|
||||
json::value targets = json::value::null();
|
||||
bool hasTask = false;
|
||||
wstring coalition = L"";
|
||||
json::value flags = json::value::null();
|
||||
|
||||
/********** Formation data **********/
|
||||
bool isLeader = false;
|
||||
bool isWingman = false;
|
||||
wstring formation = L"";
|
||||
Unit *leader = nullptr;
|
||||
vector<Unit *> wingmen;
|
||||
Offset formationOffset = Offset(NULL);
|
||||
|
||||
/********** Task data **********/
|
||||
wstring currentTask = L"";
|
||||
double targetSpeed = 0;
|
||||
double targetAltitude = 0;
|
||||
list<Coords> activePath;
|
||||
Coords activeDestination = Coords(0);
|
||||
int targetID = NULL;
|
||||
|
||||
/********** Options data **********/
|
||||
wstring ROE = L"";
|
||||
wstring reactionToThreat = L"";
|
||||
|
||||
/********** State machine **********/
|
||||
int state = State::IDLE;
|
||||
|
||||
/********** Other **********/
|
||||
Coords oldPosition = Coords(0); // Used to approximate speed
|
||||
|
||||
/********** Functions **********/
|
||||
virtual wstring getCategory() { return L"No category"; };
|
||||
wstring getTargetName();
|
||||
bool isTargetAlive();
|
||||
virtual void AIloop() = 0;
|
||||
void addMeasure(wstring key, json::value value);
|
||||
};
|
||||
135
src/core/src/commands.cpp
Normal file
135
src/core/src/commands.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
#include "commands.h"
|
||||
#include "logger.h"
|
||||
#include "dcstools.h"
|
||||
|
||||
/* Move command */
|
||||
wstring Move::getString(lua_State* L)
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.move, "
|
||||
<< ID << ", "
|
||||
<< destination.lat << ", "
|
||||
<< destination.lng << ", "
|
||||
<< altitude << ", "
|
||||
<< speed << ", "
|
||||
<< "\"" << unitCategory << "\"" << ", "
|
||||
<< taskOptions;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* Smoke command */
|
||||
wstring Smoke::getString(lua_State* L)
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.smoke, "
|
||||
<< "\"" << color << "\"" << ", "
|
||||
<< location.lat << ", "
|
||||
<< location.lng;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* Spawn ground command */
|
||||
wstring SpawnGroundUnit::getString(lua_State* L)
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.spawnGroundUnit, "
|
||||
<< "\"" << coalition << "\"" << ", "
|
||||
<< "\"" << unitType << "\"" << ", "
|
||||
<< location.lat << ", "
|
||||
<< location.lng;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* Spawn air command */
|
||||
wstring SpawnAircraft::getString(lua_State* L)
|
||||
{
|
||||
std::wostringstream optionsSS;
|
||||
optionsSS.precision(10);
|
||||
optionsSS << "{"
|
||||
<< "payloadName = \"" << payloadName << "\", "
|
||||
<< "airbaseName = \"" << airbaseName << "\","
|
||||
<< "}";
|
||||
|
||||
std::wostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.spawnAircraft, "
|
||||
<< "\"" << coalition << "\"" << ", "
|
||||
<< "\"" << unitType << "\"" << ", "
|
||||
<< location.lat << ", "
|
||||
<< location.lng << ","
|
||||
<< optionsSS.str();
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* Clone unit command */
|
||||
wstring Clone::getString(lua_State* L)
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.clone, "
|
||||
<< ID << ", "
|
||||
<< location.lat << ", "
|
||||
<< location.lng;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* Delete unit command */
|
||||
wstring Delete::getString(lua_State* L)
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.delete, "
|
||||
<< ID;
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* Set task command */
|
||||
wstring SetTask::getString(lua_State* L)
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.setTask, "
|
||||
<< ID << ","
|
||||
<< task;
|
||||
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* Reset task command */
|
||||
wstring ResetTask::getString(lua_State* L)
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.resetTask, "
|
||||
<< ID;
|
||||
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* Set command command */
|
||||
wstring SetCommand::getString(lua_State* L)
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.setCommand, "
|
||||
<< ID << ","
|
||||
<< command;
|
||||
|
||||
return commandSS.str();
|
||||
}
|
||||
|
||||
/* Set option command */
|
||||
wstring SetOption::getString(lua_State* L)
|
||||
{
|
||||
std::wostringstream commandSS;
|
||||
commandSS.precision(10);
|
||||
commandSS << "Olympus.setOption, "
|
||||
<< ID << ","
|
||||
<< optionID << ","
|
||||
<< optionValue;
|
||||
|
||||
return commandSS.str();
|
||||
}
|
||||
263
src/core/src/scheduler.cpp
Normal file
263
src/core/src/scheduler.cpp
Normal file
@ -0,0 +1,263 @@
|
||||
#include "scheduler.h"
|
||||
#include "logger.h"
|
||||
#include "dcstools.h"
|
||||
#include "unitsManager.h"
|
||||
#include "utils.h"
|
||||
#include "unit.h"
|
||||
|
||||
extern UnitsManager* unitsManager;
|
||||
|
||||
Scheduler::Scheduler(lua_State* L):
|
||||
load(0)
|
||||
{
|
||||
LogInfo(L, "Scheduler constructor called successfully");
|
||||
}
|
||||
|
||||
Scheduler::~Scheduler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Scheduler::appendCommand(Command* command)
|
||||
{
|
||||
commands.push_back(command);
|
||||
}
|
||||
|
||||
void Scheduler::execute(lua_State* L)
|
||||
{
|
||||
/* Decrease the active computation load. New commands can be sent only if the load has reached 0.
|
||||
This is needed to avoid server lag. */
|
||||
if (load > 0) {
|
||||
load--;
|
||||
return;
|
||||
}
|
||||
|
||||
int priority = CommandPriority::HIGH;
|
||||
while (priority >= CommandPriority::LOW)
|
||||
{
|
||||
for (auto command : commands)
|
||||
{
|
||||
if (command->getPriority() == priority)
|
||||
{
|
||||
wstring commandString = L"Olympus.protectedCall(" + command->getString(L) + L")";
|
||||
if (dostring_in(L, "server", to_string(commandString)))
|
||||
log(L"Error executing command " + commandString);
|
||||
load = command->getLoad();
|
||||
commands.remove(command);
|
||||
return;
|
||||
}
|
||||
}
|
||||
priority--;
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler::handleRequest(wstring key, json::value value)
|
||||
{
|
||||
Command* command = nullptr;
|
||||
|
||||
log(L"Received request with ID: " + key);
|
||||
if (key.compare(L"setPath") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
{
|
||||
wstring unitName = unit->getUnitName();
|
||||
json::value path = value[L"path"];
|
||||
list<Coords> newPath;
|
||||
for (int i = 1; i <= path.as_object().size(); i++)
|
||||
{
|
||||
wstring WP = to_wstring(i);
|
||||
double lat = path[WP][L"lat"].as_double();
|
||||
double lng = path[WP][L"lng"].as_double();
|
||||
log(unitName + L" set path destination " + WP + L" (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
|
||||
Coords dest; dest.lat = lat; dest.lng = lng;
|
||||
newPath.push_back(dest);
|
||||
}
|
||||
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
{
|
||||
unit->setActivePath(newPath);
|
||||
unit->setState(State::REACH_DESTINATION);
|
||||
log(unitName + L" new path set successfully");
|
||||
}
|
||||
else
|
||||
log(unitName + L" not found, request will be discarded");
|
||||
}
|
||||
}
|
||||
else if (key.compare(L"smoke") == 0)
|
||||
{
|
||||
wstring color = value[L"color"].as_string();
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
log(L"Adding " + color + L" smoke at (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
command = dynamic_cast<Command*>(new Smoke(color, loc));
|
||||
}
|
||||
else if (key.compare(L"spawnGround") == 0)
|
||||
{
|
||||
wstring coalition = value[L"coalition"].as_string();
|
||||
wstring type = value[L"type"].as_string();
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
log(L"Spawning " + coalition + L" ground unit of type " + type + L" at (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
command = dynamic_cast<Command*>(new SpawnGroundUnit(coalition, type, loc));
|
||||
}
|
||||
else if (key.compare(L"spawnAir") == 0)
|
||||
{
|
||||
wstring coalition = value[L"coalition"].as_string();
|
||||
wstring type = value[L"type"].as_string();
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
wstring payloadName = value[L"payloadName"].as_string();
|
||||
wstring airbaseName = value[L"airbaseName"].as_string();
|
||||
log(L"Spawning " + coalition + L" air unit of type " + type + L" with payload " + payloadName + L" at (" + to_wstring(lat) + L", " + to_wstring(lng) + L" " + airbaseName + L")");
|
||||
command = dynamic_cast<Command*>(new SpawnAircraft(coalition, type, loc, payloadName, airbaseName));
|
||||
}
|
||||
else if (key.compare(L"attackUnit") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
int targetID = value[L"targetID"].as_integer();
|
||||
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
Unit* target = unitsManager->getUnit(targetID);
|
||||
|
||||
wstring unitName;
|
||||
wstring targetName;
|
||||
|
||||
if (unit != nullptr)
|
||||
unitName = unit->getUnitName();
|
||||
else
|
||||
return;
|
||||
|
||||
if (target != nullptr)
|
||||
targetName = target->getUnitName();
|
||||
else
|
||||
return;
|
||||
|
||||
log(L"Unit " + unitName + L" attacking unit " + targetName);
|
||||
unit->setTargetID(targetID);
|
||||
unit->setState(State::ATTACK);
|
||||
}
|
||||
else if (key.compare(L"stopAttack") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
unit->setState(State::REACH_DESTINATION);
|
||||
else
|
||||
return;
|
||||
}
|
||||
else if (key.compare(L"changeSpeed") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
unit->changeSpeed(value[L"change"].as_string());
|
||||
}
|
||||
else if (key.compare(L"changeAltitude") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
unit->changeAltitude(value[L"change"].as_string());
|
||||
}
|
||||
else if (key.compare(L"setSpeed") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
unit->setTargetSpeed(value[L"speed"].as_double());
|
||||
}
|
||||
else if (key.compare(L"setAltitude") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
if (unit != nullptr)
|
||||
unit->setTargetAltitude(value[L"altitude"].as_double());
|
||||
}
|
||||
else if (key.compare(L"cloneUnit") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
command = dynamic_cast<Command*>(new Clone(ID, loc));
|
||||
log(L"Cloning unit " + to_wstring(ID));
|
||||
}
|
||||
else if (key.compare(L"setLeader") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
bool isLeader = value[L"isLeader"].as_bool();
|
||||
if (isLeader)
|
||||
{
|
||||
json::value wingmenIDs = value[L"wingmenIDs"];
|
||||
vector<Unit*> wingmen;
|
||||
if (unit != nullptr)
|
||||
{
|
||||
for (auto itr = wingmenIDs.as_array().begin(); itr != wingmenIDs.as_array().end(); itr++)
|
||||
{
|
||||
Unit* wingman = unitsManager->getUnit(itr->as_integer());
|
||||
if (wingman != nullptr)
|
||||
wingmen.push_back(wingman);
|
||||
}
|
||||
unit->setFormation(L"Line abreast");
|
||||
unit->setIsLeader(true);
|
||||
unit->setWingmen(wingmen);
|
||||
log(L"Setting " + unit->getName() + L" as formation leader");
|
||||
}
|
||||
}
|
||||
else {
|
||||
unit->setIsLeader(false);
|
||||
}
|
||||
}
|
||||
else if (key.compare(L"setFormation") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
wstring formation = value[L"formation"].as_string();
|
||||
unit->setFormation(formation);
|
||||
}
|
||||
else if (key.compare(L"setROE") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
wstring ROE = value[L"ROE"].as_string();
|
||||
unit->setROE(ROE);
|
||||
}
|
||||
else if (key.compare(L"setReactionToThreat") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
wstring reactionToThreat = value[L"reactionToThreat"].as_string();
|
||||
unit->setReactionToThreat(reactionToThreat);
|
||||
}
|
||||
else if (key.compare(L"landAt") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
unit->landAt(loc);
|
||||
}
|
||||
else if (key.compare(L"deleteUnit") == 0)
|
||||
{
|
||||
int ID = value[L"ID"].as_integer();
|
||||
unitsManager->deleteUnit(ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
log(L"Unknown command: " + key);
|
||||
}
|
||||
|
||||
if (command != nullptr)
|
||||
{
|
||||
appendCommand(command);
|
||||
}
|
||||
}
|
||||
|
||||
322
src/core/src/unit.cpp
Normal file
322
src/core/src/unit.cpp
Normal file
@ -0,0 +1,322 @@
|
||||
#include "unit.h"
|
||||
#include "utils.h"
|
||||
#include "logger.h"
|
||||
#include "commands.h"
|
||||
#include "scheduler.h"
|
||||
#include "defines.h"
|
||||
#include "unitsManager.h"
|
||||
|
||||
#include <chrono>
|
||||
using namespace std::chrono;
|
||||
|
||||
#include <GeographicLib/Geodesic.hpp>
|
||||
using namespace GeographicLib;
|
||||
|
||||
extern Scheduler* scheduler;
|
||||
extern UnitsManager* unitsManager;
|
||||
|
||||
Unit::Unit(json::value json, int ID) :
|
||||
ID(ID)
|
||||
{
|
||||
log("Creating unit with ID: " + to_string(ID));
|
||||
}
|
||||
|
||||
Unit::~Unit()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Unit::addMeasure(wstring key, json::value value)
|
||||
{
|
||||
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
|
||||
if (measures.find(key) == measures.end())
|
||||
measures[key] = new Measure(value, ms.count());
|
||||
else
|
||||
{
|
||||
if (measures[key]->getValue() != value)
|
||||
{
|
||||
measures[key]->setValue(value);
|
||||
measures[key]->setTime(ms.count());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::updateExportData(json::value json)
|
||||
{
|
||||
/* Compute speed (loGetWorldObjects does not provide speed, we compute it for better performance instead of relying on many lua calls) */
|
||||
if (oldPosition != NULL)
|
||||
{
|
||||
double dist = 0;
|
||||
Geodesic::WGS84().Inverse(latitude, longitude, oldPosition.lat, oldPosition.lng, dist);
|
||||
setSpeed(getSpeed() * 0.95 + (dist / UPDATE_TIME_INTERVAL) * 0.05);
|
||||
}
|
||||
oldPosition = Coords(latitude, longitude, altitude);
|
||||
|
||||
if (json.has_string_field(L"Name"))
|
||||
setName(json[L"Name"].as_string());
|
||||
if (json.has_string_field(L"UnitName"))
|
||||
setUnitName(json[L"UnitName"].as_string());
|
||||
if (json.has_string_field(L"GroupName"))
|
||||
setGroupName(json[L"GroupName"].as_string());
|
||||
if (json.has_object_field(L"Type"))
|
||||
setType(json[L"Type"]);
|
||||
if (json.has_number_field(L"Country"))
|
||||
setCountry(json[L"Country"].as_number().to_int32());
|
||||
if (json.has_number_field(L"CoalitionID"))
|
||||
setCoalitionID(json[L"CoalitionID"].as_number().to_int32());
|
||||
if (json.has_object_field(L"LatLongAlt"))
|
||||
{
|
||||
setLatitude(json[L"LatLongAlt"][L"Lat"].as_number().to_double());
|
||||
setLongitude(json[L"LatLongAlt"][L"Long"].as_number().to_double());
|
||||
setAltitude(json[L"LatLongAlt"][L"Alt"].as_number().to_double());
|
||||
}
|
||||
if (json.has_number_field(L"Heading"))
|
||||
setHeading(json[L"Heading"].as_number().to_double());
|
||||
if (json.has_object_field(L"Flags"))
|
||||
setFlags(json[L"Flags"]);
|
||||
|
||||
/* All units which contain the name "Olympus" are automatically under AI control */
|
||||
/* TODO: I don't really like using this method */
|
||||
setAI(getUnitName().find(L"Olympus") != wstring::npos);
|
||||
|
||||
/* If the unit is alive and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */
|
||||
if (getAI() && getAlive() && getFlags()[L"Human"].as_bool() == false)
|
||||
AIloop();
|
||||
}
|
||||
|
||||
void Unit::updateMissionData(json::value json)
|
||||
{
|
||||
if (json.has_number_field(L"fuel"))
|
||||
setFuel(int(json[L"fuel"].as_number().to_double() * 100));
|
||||
if (json.has_object_field(L"ammo"))
|
||||
setAmmo(json[L"ammo"]);
|
||||
if (json.has_object_field(L"targets"))
|
||||
setTargets(json[L"targets"]);
|
||||
if (json.has_boolean_field(L"hasTask"))
|
||||
setHasTask(json[L"hasTask"].as_bool());
|
||||
}
|
||||
|
||||
json::value Unit::getData(long long time)
|
||||
{
|
||||
auto json = json::value::object();
|
||||
|
||||
/********** Base data **********/
|
||||
json[L"baseData"] = json::value::object();
|
||||
for (auto key : { L"AI", L"name", L"unitName", L"groupName", L"alive", L"category"})
|
||||
{
|
||||
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
|
||||
json[L"baseData"][key] = measures[key]->getValue();
|
||||
}
|
||||
|
||||
/********** Flight data **********/
|
||||
json[L"flightData"] = json::value::object();
|
||||
for (auto key : { L"latitude", L"longitude", L"altitude", L"speed", L"heading"})
|
||||
{
|
||||
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
|
||||
json[L"flightData"][key] = measures[key]->getValue();
|
||||
}
|
||||
|
||||
/********** Mission data **********/
|
||||
json[L"missionData"] = json::value::object();
|
||||
for (auto key : { L"fuel", L"ammo", L"targets", L"hasTask", L"coalition", L"flags"})
|
||||
{
|
||||
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
|
||||
json[L"missionData"][key] = measures[key]->getValue();
|
||||
}
|
||||
|
||||
/********** Formation data **********/
|
||||
json[L"formationData"] = json::value::object();
|
||||
for (auto key : { L"isLeader", L"isWingman", L"formation", L"wingmenIDs", L"leaderID" })
|
||||
{
|
||||
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
|
||||
json[L"missionData"][key] = measures[key]->getValue();
|
||||
}
|
||||
|
||||
/********** Task data **********/
|
||||
json[L"taskData"] = json::value::object();
|
||||
for (auto key : { L"currentTask", L"targetSpeed", L"targetAltitude", L"activePath" })
|
||||
{
|
||||
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
|
||||
json[L"taskData"][key] = measures[key]->getValue();
|
||||
}
|
||||
|
||||
/********** Options data **********/
|
||||
json[L"optionsData"] = json::value::object();
|
||||
for (auto key : { L"ROE", L"reactionToThreat" })
|
||||
{
|
||||
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
|
||||
json[L"optionsData"][key] = measures[key]->getValue();
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
void Unit::setActivePath(list<Coords> newPath)
|
||||
{
|
||||
if (state != State::WINGMAN && state != State::FOLLOW)
|
||||
{
|
||||
activePath = newPath;
|
||||
resetActiveDestination();
|
||||
}
|
||||
|
||||
auto path = json::value::object();
|
||||
if (activePath.size() > 0) {
|
||||
int count = 1;
|
||||
for (auto& destination : activePath)
|
||||
{
|
||||
auto json = json::value::object();
|
||||
json[L"lat"] = destination.lat;
|
||||
json[L"lng"] = destination.lng;
|
||||
json[L"alt"] = destination.alt;
|
||||
path[to_wstring(count++)] = json;
|
||||
}
|
||||
}
|
||||
addMeasure(L"activePath", path);
|
||||
}
|
||||
|
||||
void Unit::setCoalitionID(int newCoalitionID)
|
||||
{
|
||||
if (newCoalitionID == 0)
|
||||
coalition = L"neutral";
|
||||
else if (newCoalitionID == 1)
|
||||
coalition = L"red";
|
||||
else
|
||||
coalition = L"blue";
|
||||
addMeasure(L"coalition", json::value(coalition));
|
||||
}
|
||||
|
||||
int Unit::getCoalitionID()
|
||||
{
|
||||
if (coalition == L"neutral")
|
||||
return 0;
|
||||
else if (coalition == L"red")
|
||||
return 1;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
void Unit::setLeader(Unit* newLeader)
|
||||
{
|
||||
leader = newLeader;
|
||||
if (leader != nullptr)
|
||||
addMeasure(L"leaderID", json::value(leader->getID()));
|
||||
}
|
||||
|
||||
void Unit::setWingmen(vector<Unit*> newWingmen) {
|
||||
wingmen = newWingmen;
|
||||
auto wingmenIDs = json::value::object();
|
||||
int i = 0;
|
||||
for (auto itr = wingmen.begin(); itr != wingmen.end(); itr++)
|
||||
wingmenIDs[i++] = (*itr)->getID();
|
||||
addMeasure(L"wingmen", wingmenIDs);
|
||||
}
|
||||
|
||||
wstring Unit::getTargetName()
|
||||
{
|
||||
if (isTargetAlive())
|
||||
{
|
||||
Unit* target = unitsManager->getUnit(targetID);
|
||||
if (target != nullptr)
|
||||
return target->getUnitName();
|
||||
}
|
||||
return L"";
|
||||
}
|
||||
|
||||
bool Unit::isTargetAlive()
|
||||
{
|
||||
if (targetID == NULL)
|
||||
return false;
|
||||
|
||||
Unit* target = unitsManager->getUnit(targetID);
|
||||
if (target != nullptr)
|
||||
return target->alive;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void Unit::resetActiveDestination()
|
||||
{
|
||||
activeDestination = Coords(NULL);
|
||||
}
|
||||
|
||||
void Unit::resetTask()
|
||||
{
|
||||
Command* command = dynamic_cast<Command*>(new ResetTask(ID));
|
||||
scheduler->appendCommand(command);
|
||||
}
|
||||
|
||||
void Unit::setIsLeader(bool newIsLeader) {
|
||||
isLeader = newIsLeader;
|
||||
if (!isLeader) {
|
||||
for (auto wingman : wingmen)
|
||||
{
|
||||
wingman->setFormation(L"");
|
||||
wingman->setIsWingman(false);
|
||||
wingman->setLeader(nullptr);
|
||||
}
|
||||
}
|
||||
addMeasure(L"isLeader", json::value(newIsLeader));
|
||||
}
|
||||
|
||||
void Unit::setIsWingman(bool newIsWingman)
|
||||
{
|
||||
isWingman = newIsWingman;
|
||||
if (isWingman)
|
||||
setState(State::WINGMAN);
|
||||
else
|
||||
setState(State::IDLE);
|
||||
|
||||
addMeasure(L"isWingman", json::value(isWingman));
|
||||
}
|
||||
|
||||
void Unit::setFormationOffset(Offset newFormationOffset)
|
||||
{
|
||||
formationOffset = newFormationOffset;
|
||||
resetTask();
|
||||
}
|
||||
|
||||
void Unit::setROE(wstring newROE) {
|
||||
ROE = newROE;
|
||||
int ROEEnum;
|
||||
if (newROE.compare(L"Free") == 0)
|
||||
ROEEnum = ROE::WEAPON_FREE;
|
||||
else if (newROE.compare(L"Designated free") == 0)
|
||||
ROEEnum = ROE::OPEN_FIRE_WEAPON_FREE;
|
||||
else if (newROE.compare(L"Designated") == 0)
|
||||
ROEEnum = ROE::OPEN_FIRE;
|
||||
else if (newROE.compare(L"Return") == 0)
|
||||
ROEEnum = ROE::RETURN_FIRE;
|
||||
else if (newROE.compare(L"Hold") == 0)
|
||||
ROEEnum = ROE::WEAPON_HOLD;
|
||||
else
|
||||
return;
|
||||
Command* command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::ROE, ROEEnum));
|
||||
scheduler->appendCommand(command);
|
||||
addMeasure(L"ROE", json::value(newROE));
|
||||
}
|
||||
|
||||
void Unit::setReactionToThreat(wstring newReactionToThreat) {
|
||||
reactionToThreat = newReactionToThreat;
|
||||
int reactionToThreatEnum;
|
||||
if (newReactionToThreat.compare(L"None") == 0)
|
||||
reactionToThreatEnum = ReactionToThreat::NO_REACTION;
|
||||
else if (newReactionToThreat.compare(L"Passive") == 0)
|
||||
reactionToThreatEnum = ReactionToThreat::PASSIVE_DEFENCE;
|
||||
else if (newReactionToThreat.compare(L"Evade") == 0)
|
||||
reactionToThreatEnum = ReactionToThreat::EVADE_FIRE;
|
||||
else if (newReactionToThreat.compare(L"Escape") == 0)
|
||||
reactionToThreatEnum = ReactionToThreat::BYPASS_AND_ESCAPE;
|
||||
else if (newReactionToThreat.compare(L"Abort") == 0)
|
||||
reactionToThreatEnum = ReactionToThreat::ALLOW_ABORT_MISSION;
|
||||
else
|
||||
return;
|
||||
Command* command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::REACTION_ON_THREAT, reactionToThreatEnum));
|
||||
scheduler->appendCommand(command);
|
||||
addMeasure(L"reactionToThreat", json::value(newReactionToThreat));
|
||||
}
|
||||
|
||||
void Unit::landAt(Coords loc) {
|
||||
activePath.clear();
|
||||
activePath.push_back(loc);
|
||||
setState(State::LAND);
|
||||
}
|
||||
42
src/olympus.sln
Normal file
42
src/olympus.sln
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.3.32929.385
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "core\core.vcxproj", "{8A48D855-0E01-42BA-BD8C-07B0877C68DF}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logger", "logger\logger.vcxproj", "{873ECABE-FCFE-4217-AC15-91959C3CF1C6}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dcstools", "dcstools\dcstools.vcxproj", "{2B255368-39A0-431A-A6DE-CC739AC70DC1}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luatools", "luatools\luatools.vcxproj", "{DE139EC1-4F88-47D5-BE73-F41915FE14A3}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "utils", "utils\utils.vcxproj", "{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "olympus", "olympus\olympus.vcxproj", "{5F3FC91E-1FBC-4223-8011-9708DE913474}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.Release|x64.ActiveCfg = Release|x64
|
||||
{8A48D855-0E01-42BA-BD8C-07B0877C68DF}.Release|x64.Build.0 = Release|x64
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.Release|x64.ActiveCfg = Release|x64
|
||||
{873ECABE-FCFE-4217-AC15-91959C3CF1C6}.Release|x64.Build.0 = Release|x64
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.Release|x64.ActiveCfg = Release|x64
|
||||
{2B255368-39A0-431A-A6DE-CC739AC70DC1}.Release|x64.Build.0 = Release|x64
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.Release|x64.ActiveCfg = Release|x64
|
||||
{DE139EC1-4F88-47D5-BE73-F41915FE14A3}.Release|x64.Build.0 = Release|x64
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.Release|x64.ActiveCfg = Release|x64
|
||||
{B85009CE-4A5C-4A5A-B85D-001B3A2651B2}.Release|x64.Build.0 = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.Release|x64.ActiveCfg = Release|x64
|
||||
{5F3FC91E-1FBC-4223-8011-9708DE913474}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {FAB9F592-7511-4EB9-B365-078842ED9BDD}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
29
src/olympus/olympus.filters
Normal file
29
src/olympus/olympus.filters
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="inc">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
120
src/olympus/olympus.vcxproj
Normal file
120
src/olympus/olympus.vcxproj
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\olympus.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\dcstools\dcstools.vcxproj">
|
||||
<Project>{2b255368-39a0-431a-a6de-cc739ac70dc1}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\logger\logger.vcxproj">
|
||||
<Project>{873ecabe-fcfe-4217-ac15-91959c3cf1c6}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\utils\utils.vcxproj">
|
||||
<Project>{b85009ce-4a5c-4a5a-b85d-001b3a2651b2}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{5f3fc91e-1fbc-4223-8011-9708de913474}</ProjectGuid>
|
||||
<RootNamespace>Olympus</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>olympus</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>.\..\..\bin\$(Platform)\$(Configuration)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>.\..\..\bin\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgAutoLink>true</VcpkgAutoLink>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS; _DEBUG;OLYMPUS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>include; ..\..\third-party\lua\include; ..\utils\include; ..\shared\include</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<AssemblerOutput>AssemblyCode</AssemblerOutput>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>lua.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS; NDEBUG;OLYMPUS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>
|
||||
</PrecompiledHeaderFile>
|
||||
<AdditionalIncludeDirectories>include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<AssemblerOutput>NoListing</AssemblerOutput>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>lua.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
16
src/olympus/olympus.vcxproj.filters
Normal file
16
src/olympus/olympus.vcxproj.filters
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{c021f649-26ec-4040-abd4-13132def4a81}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{2809fbbc-77d2-465e-afef-230525a60c66}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\olympus.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
152
src/olympus/src/olympus.cpp
Normal file
152
src/olympus/src/olympus.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
#include "framework.h"
|
||||
#include "dcstools.h"
|
||||
#include "logger.h"
|
||||
#include "utils.h"
|
||||
|
||||
/* Run-time linking to core dll allows for "hot swap". This is useful for development but could be removed when stable.*/
|
||||
HINSTANCE hGetProcIDDLL = NULL;
|
||||
typedef int(__stdcall* f_coreInit)(lua_State* L);
|
||||
typedef int(__stdcall* f_coreDeinit)(lua_State* L);
|
||||
typedef int(__stdcall* f_coreFrame)(lua_State* L);
|
||||
typedef int(__stdcall* f_coreMissionData)(lua_State* L);
|
||||
f_coreInit coreInit = nullptr;
|
||||
f_coreDeinit coreDeinit = nullptr;
|
||||
f_coreFrame coreFrame = nullptr;
|
||||
f_coreMissionData coreMissionData = nullptr;
|
||||
|
||||
static int onSimulationStart(lua_State* L)
|
||||
{
|
||||
log("onSimulationStart callback called successfully");
|
||||
|
||||
string modLocation;
|
||||
string dllLocation;
|
||||
char* buf = nullptr;
|
||||
size_t sz = 0;
|
||||
if (_dupenv_s(&buf, &sz, "DCSOLYMPUS_PATH") == 0 && buf != nullptr)
|
||||
{
|
||||
modLocation = buf;
|
||||
free(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
log("DCSOLYMPUS_PATH environment variable is missing");
|
||||
goto error;
|
||||
}
|
||||
dllLocation = modLocation + "\\bin\\core.dll";
|
||||
|
||||
log("Loading core.dll");
|
||||
hGetProcIDDLL = LoadLibrary(to_wstring(dllLocation).c_str());
|
||||
|
||||
if (!hGetProcIDDLL) {
|
||||
LogError(L, "Error loading core DLL");
|
||||
goto error;
|
||||
}
|
||||
|
||||
log("Core DLL loaded successfully");
|
||||
|
||||
coreInit = (f_coreInit)GetProcAddress(hGetProcIDDLL, "coreInit");
|
||||
if (!coreInit)
|
||||
{
|
||||
LogError(L, "Error getting coreInit ProcAddress from DLL");
|
||||
goto error;
|
||||
}
|
||||
|
||||
coreDeinit = (f_coreDeinit)GetProcAddress(hGetProcIDDLL, "coreDeinit");
|
||||
if (!coreInit)
|
||||
{
|
||||
LogError(L, "Error getting coreDeinit ProcAddress from DLL");
|
||||
goto error;
|
||||
}
|
||||
|
||||
coreFrame = (f_coreFrame)GetProcAddress(hGetProcIDDLL, "coreFrame");
|
||||
if (!coreFrame)
|
||||
{
|
||||
LogError(L, "Error getting coreFrame ProcAddress from DLL");
|
||||
goto error;
|
||||
}
|
||||
|
||||
coreMissionData = (f_coreFrame)GetProcAddress(hGetProcIDDLL, "coreMissionData");
|
||||
if (!coreFrame)
|
||||
{
|
||||
LogError(L, "Error getting coreMissionData ProcAddress from DLL");
|
||||
goto error;
|
||||
}
|
||||
|
||||
coreInit(L);
|
||||
|
||||
LogInfo(L, "Module loaded and started successfully.");
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
LogError(L, "Error while loading module, see Olympus.log in temporary folder for additional details.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int onSimulationFrame(lua_State* L)
|
||||
{
|
||||
if (coreFrame)
|
||||
{
|
||||
coreFrame(L);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int onSimulationStop(lua_State* L)
|
||||
{
|
||||
log("onSimulationStop callback called successfully");
|
||||
if (hGetProcIDDLL)
|
||||
{
|
||||
log("Trying to unload core DLL");
|
||||
if (coreDeinit)
|
||||
{
|
||||
coreDeinit(L);
|
||||
}
|
||||
|
||||
if (FreeLibrary(hGetProcIDDLL))
|
||||
{
|
||||
log("Core DLL unloaded successfully");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogError(L, "Error unloading DLL");
|
||||
goto error;
|
||||
}
|
||||
|
||||
coreInit = nullptr;
|
||||
coreDeinit = nullptr;
|
||||
coreFrame = nullptr;
|
||||
coreMissionData = nullptr;
|
||||
}
|
||||
|
||||
hGetProcIDDLL = NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
LogError(L, "Error while unloading module, see Olympus.log in temporary folder for additional details.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setMissionData(lua_State* L)
|
||||
{
|
||||
if (coreMissionData)
|
||||
{
|
||||
coreMissionData(L);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg Map[] = {
|
||||
{"onSimulationStart", onSimulationStart},
|
||||
{"onSimulationFrame", onSimulationFrame},
|
||||
{"onSimulationStop", onSimulationStop},
|
||||
{"setMissionData", setMissionData },
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
extern "C" DllExport int luaopen_olympus(lua_State * L)
|
||||
{
|
||||
luaL_register(L, "olympus", Map);
|
||||
return 1;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user