Renamed src to backend

This commit is contained in:
Pax1601
2024-01-03 16:19:16 +01:00
parent a0634a7f99
commit 8024db9579
76 changed files with 0 additions and 0 deletions

12
backend/DCSOlympus.props Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<PropertyGroup Label="Vcpkg">
<VcpkgEnableManifest>true</VcpkgEnableManifest>
<VcpkgAutoLink>true</VcpkgAutoLink>
</PropertyGroup>
<ItemDefinitionGroup />
<ItemGroup />
</Project>

90
backend/core/core.filters Normal file
View File

@@ -0,0 +1,90 @@
<?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>{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="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="pch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\Commands.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\DCSUtils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\defines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\logger.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\LUAUtils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\RESTServer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\Scheduler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\Unit.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\UnitsHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\UnitsHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\Unit.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\Scheduler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\LUAUtils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\logger.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\DCSUtils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\Commands.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\RESTServer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

110
backend/core/core.rc Normal file
View File

@@ -0,0 +1,110 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Italian (Italy) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Italian (Italy) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// English (United Kingdom) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,0
PRODUCTVERSION 1,0,3,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "DCS Olympus"
VALUE "FileDescription", "DCS Olympus"
VALUE "FileVersion", "1.0.3.0"
VALUE "InternalName", "core.dll"
VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "core.dll"
VALUE "ProductName", "DCS Olympus"
VALUE "ProductVersion", "1.0.3.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United Kingdom) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

215
backend/core/core.vcxproj Normal file
View File

@@ -0,0 +1,215 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</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="..\luatools\luatools.vcxproj">
<Project>{de139ec1-4f88-47d5-be73-f41915fe14a3}</Project>
</ProjectReference>
<ProjectReference Include="..\utils\utils.vcxproj">
<Project>{b85009ce-4a5c-4a5a-b85d-001b3a2651b2}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\aircraft.h" />
<ClInclude Include="include\airunit.h" />
<ClInclude Include="include\commands.h" />
<ClInclude Include="include\datatypes.h" />
<ClInclude Include="include\groundunit.h" />
<ClInclude Include="include\helicopter.h" />
<ClInclude Include="include\navyunit.h" />
<ClInclude Include="include\scheduler.h" />
<ClInclude Include="include\scriptloader.h" />
<ClInclude Include="include\server.h" />
<ClInclude Include="include\unit.h" />
<ClInclude Include="include\unitsmanager.h" />
<ClInclude Include="include\weapon.h" />
<ClInclude Include="include\weaponsmanager.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\aircraft.cpp" />
<ClCompile Include="src\airunit.cpp" />
<ClCompile Include="src\commands.cpp" />
<ClCompile Include="src\core.cpp" />
<ClCompile Include="src\datatypes.cpp" />
<ClCompile Include="src\groundunit.cpp" />
<ClCompile Include="src\helicopter.cpp" />
<ClCompile Include="src\navyunit.cpp" />
<ClCompile Include="src\scheduler.cpp" />
<ClCompile Include="src\scriptloader.cpp" />
<ClCompile Include="src\server.cpp" />
<ClCompile Include="src\unit.cpp" />
<ClCompile Include="src\unitsmanager.cpp" />
<ClCompile Include="src\weapon.cpp" />
<ClCompile Include="src\weaponsmanager.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="core.rc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{8a48d855-0e01-42ba-bd8c-07b0877c68df}</ProjectGuid>
<RootNamespace>core</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<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|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\DCSOlympus.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\DCSOlympus.props" />
</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" />
<Import Project="..\DCSOlympus.props" />
</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" />
<Import Project="..\DCSOlympus.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>.\..\..\bin\$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>.\..\..\bin\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;OLYMPUSCORE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;OLYMPUSCORE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;CORE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>include;..\..\third-party\GeographicLib-2.1.1\include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>lua.lib; GeographicLib-i.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
<Version>{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}</Version>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;CORE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>include;..\..\third-party\base64\include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>lua.lib; GeographicLib-i.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\third-party\lua; </AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,106 @@
<?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>{cc40b2d0-5e40-4a2b-bfc7-df3aef133737}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{1be98bb1-2aa0-40b5-bac9-3d073e079771}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\aircraft.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\airunit.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\commands.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\groundunit.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\helicopter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\navyunit.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\scheduler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\scriptloader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\server.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\unit.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\unitsmanager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\weapon.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\datatypes.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\weaponsmanager.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\aircraft.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\airunit.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\commands.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\core.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\groundunit.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\helicopter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\navyunit.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\scheduler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\scriptloader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\server.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\unit.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\unitsmanager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\weapon.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\datatypes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\weaponsmanager.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="core.rc" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,20 @@
#pragma once
#include "airunit.h"
#define AIRCRAFT_DEST_DIST_THR 2000 // Meters
class Aircraft : public AirUnit
{
public:
Aircraft(json::value json, unsigned int ID);
static void loadDatabase(string path);
virtual void changeSpeed(string change);
virtual void changeAltitude(string change);
virtual double getDestinationReachedThreshold() { return AIRCRAFT_DEST_DIST_THR; }
protected:
static json::value database;
};

View File

@@ -0,0 +1,24 @@
#pragma once
#include "framework.h"
#include "utils.h"
#include "dcstools.h"
#include "luatools.h"
#include "Unit.h"
#define AIR_DEST_DIST_THR 2000 // Meters
class AirUnit : public Unit
{
public:
AirUnit(json::value json, unsigned int ID);
virtual void setDefaults(bool force = false);
virtual void setState(unsigned char newState);
virtual void changeSpeed(string change) = 0;
virtual void changeAltitude(string change) = 0;
virtual double getDestinationReachedThreshold() { return AIR_DEST_DIST_THR; }
protected:
virtual void AIloop();
};

View File

@@ -0,0 +1,432 @@
#pragma once
#include "framework.h"
#include "luatools.h"
#include "utils.h"
#include "logger.h"
#include "datatypes.h"
namespace CommandPriority {
enum CommandPriorities { LOW, MEDIUM, HIGH, IMMEDIATE };
};
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,
ENGAGE_AIR_WEAPONS = 20,
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 ReactionsToThreat {
NO_REACTION = 0,
PASSIVE_DEFENCE = 1,
EVADE_FIRE = 2,
BYPASS_AND_ESCAPE = 3,
ALLOW_ABORT_MISSION = 4
};
}
namespace EmissionCountermeasure {
enum ReactionsToThreat {
SILENT = 0,
ATTACK = 1,
DEFEND = 2,
FREE = 3
};
}
namespace RadarUse {
enum RadarUses {
NEVER = 0,
FOR_ATTACK_ONLY = 1,
FOR_SEARCH_IF_REQUIRED = 2,
FOR_CONTINUOUS_SEARCH = 3
};
}
namespace FlareUse {
enum FlareUses {
NEVER = 0,
AGAINST_FIRED_MISSILE = 1,
WHEN_FLYING_IN_SAM_WEZ = 2,
WHEN_FLYING_NEAR_ENEMIES = 3
};
}
namespace ECMUse {
enum ECMUses {
NEVER_USE = 0,
USE_IF_ONLY_LOCK_BY_RADAR = 1,
USE_IF_DETECTED_LOCK_BY_RADAR = 2,
ALWAYS_USE = 3
};
}
/* Base command class */
class Command
{
public:
Command(function<void(void)> callback) : callback(callback) {};
unsigned int getPriority() { return priority; }
virtual string getString() = 0;
virtual unsigned int getLoad() = 0;
const string getHash() { return hash; }
void executeCallback() { callback(); }
protected:
unsigned int priority = CommandPriority::LOW;
const string hash = random_string(16);
function<void(void)> callback;
};
/* Simple low priority move command (from user click) */
class Move : public Command
{
public:
Move(string groupName, Coords destination, double speed, string speedType, double altitude,
string altitudeType, string taskOptions, string category, bool onRoad, function<void(void)> callback = []() {}) :
Command(callback),
groupName(groupName),
destination(destination),
speed(speed),
speedType(speedType),
altitude(altitude),
altitudeType(altitudeType),
taskOptions(taskOptions),
category(category),
onRoad(onRoad)
{
priority = CommandPriority::MEDIUM;
};
virtual string getString();
virtual unsigned int getLoad() { return onRoad? 45: 5; }
private:
const string groupName;
const Coords destination;
const double speed;
const string speedType;
const double altitude;
const string altitudeType;
const string taskOptions;
const string category;
const bool onRoad;
};
/* Smoke command */
class Smoke : public Command
{
public:
Smoke(string color, Coords location, function<void(void)> callback = [](){}) :
Command(callback),
color(color),
location(location)
{
priority = CommandPriority::LOW;
};
virtual string getString();
virtual unsigned int getLoad() { return 2; }
private:
const string color;
const Coords location;
};
/* Spawn ground unit command */
class SpawnGroundUnits : public Command
{
public:
SpawnGroundUnits(string coalition, vector<SpawnOptions> spawnOptions, string country, bool immediate, function<void(void)> callback = [](){}) :
Command(callback),
coalition(coalition),
spawnOptions(spawnOptions),
country(country),
immediate(immediate)
{
priority = immediate? CommandPriority::IMMEDIATE: CommandPriority::LOW;
};
virtual string getString();
virtual unsigned int getLoad() { return immediate? 5: 30; }
private:
const string coalition;
const vector<SpawnOptions> spawnOptions;
const string country;
const bool immediate;
};
/* Spawn navy unit command */
class SpawnNavyUnits : public Command
{
public:
SpawnNavyUnits(string coalition, vector<SpawnOptions> spawnOptions, string country, bool immediate, function<void(void)> callback = [](){}) :
Command(callback),
coalition(coalition),
spawnOptions(spawnOptions),
country(country),
immediate(immediate)
{
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
};
virtual string getString();
virtual unsigned int getLoad() { return immediate ? 5 : 60; }
private:
const string coalition;
const vector<SpawnOptions> spawnOptions;
const string country;
const bool immediate;
};
/* Spawn aircraft command */
class SpawnAircrafts : public Command
{
public:
SpawnAircrafts(string coalition, vector<SpawnOptions> spawnOptions, string airbaseName, string country, bool immediate, function<void(void)> callback = [](){}) :
Command(callback),
coalition(coalition),
spawnOptions(spawnOptions),
airbaseName(airbaseName),
country(country),
immediate(immediate)
{
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
};
virtual string getString();
virtual unsigned int getLoad() { return immediate ? 5 : 45; }
private:
const string coalition;
const vector<SpawnOptions> spawnOptions;
const string airbaseName;
const string country;
const bool immediate;
};
/* Spawn helicopter command */
class SpawnHelicopters : public Command
{
public:
SpawnHelicopters(string coalition, vector<SpawnOptions> spawnOptions, string airbaseName, string country, bool immediate, function<void(void)> callback = [](){}) :
Command(callback),
coalition(coalition),
spawnOptions(spawnOptions),
airbaseName(airbaseName),
country(country),
immediate(immediate)
{
priority = immediate ? CommandPriority::IMMEDIATE : CommandPriority::LOW;
};
virtual string getString();
virtual unsigned int getLoad() { return immediate ? 5 : 45; }
private:
const string coalition;
const vector<SpawnOptions> spawnOptions;
const string airbaseName;
const string country;
const bool immediate;
};
/* Clone unit command */
class Clone : public Command
{
public:
Clone(vector<CloneOptions> cloneOptions, bool deleteOriginal, function<void(void)> callback = [](){}) :
Command(callback),
cloneOptions(cloneOptions),
deleteOriginal(deleteOriginal)
{
priority = CommandPriority::LOW;
};
virtual string getString();
virtual unsigned int getLoad() { return 30; }
private:
const vector<CloneOptions> cloneOptions;
const bool deleteOriginal;
};
/* Delete unit command */
class Delete : public Command
{
public:
Delete(unsigned int ID, bool explosion, string explosionType, bool immediate, function<void(void)> callback = [](){}) :
Command(callback),
ID(ID),
explosion(explosion),
explosionType(explosionType),
immediate(immediate)
{
priority = CommandPriority::HIGH;
immediate = immediate;
};
virtual string getString();
virtual unsigned int getLoad() { return immediate? 1: 30; }
private:
const unsigned int ID;
const bool explosion;
const string explosionType;
const bool immediate;
};
/* SetTask command */
class SetTask : public Command
{
public:
SetTask(string groupName, string task, function<void(void)> callback = [](){}) :
Command(callback),
groupName(groupName),
task(task)
{
priority = CommandPriority::MEDIUM;
};
virtual string getString();
virtual unsigned int getLoad() { return 5; }
private:
const string groupName;
const string task;
};
/* Reset task command */
class ResetTask : public Command
{
public:
ResetTask(string groupName, function<void(void)> callback = [](){}) :
Command(callback),
groupName(groupName)
{
priority = CommandPriority::HIGH;
};
virtual string getString();
virtual unsigned int getLoad() { return 5; }
private:
const string groupName;
};
/* Set command */
class SetCommand : public Command
{
public:
SetCommand(string groupName, string command, function<void(void)> callback = [](){}) :
Command(callback),
groupName(groupName),
command(command)
{
priority = CommandPriority::HIGH;
};
virtual string getString();
virtual unsigned int getLoad() { return 5; }
private:
const string groupName;
const string command;
};
/* Set option command */
class SetOption : public Command
{
public:
SetOption(string groupName, unsigned int optionID, unsigned int optionValue, function<void(void)> callback = [](){}) :
Command(callback),
groupName(groupName),
optionID(optionID),
optionValue(optionValue),
optionBool(false),
isBoolean(false)
{
priority = CommandPriority::HIGH;
};
SetOption(string groupName, unsigned int optionID, bool optionBool, function<void(void)> callback = [](){}) :
Command(callback),
groupName(groupName),
optionID(optionID),
optionValue(0),
optionBool(optionBool),
isBoolean(true)
{
priority = CommandPriority::HIGH;
};
virtual string getString();
virtual unsigned int getLoad() { return 5; }
private:
const string groupName;
const unsigned int optionID;
const unsigned int optionValue;
const bool optionBool;
const bool isBoolean;
};
/* Set on off */
class SetOnOff : public Command
{
public:
SetOnOff(string groupName, bool onOff, function<void(void)> callback = [](){}) :
Command(callback),
groupName(groupName),
onOff(onOff)
{
priority = CommandPriority::HIGH;
};
virtual string getString();
virtual unsigned int getLoad() { return 5; }
private:
const string groupName;
const bool onOff;
};
/* Make a ground explosion */
class Explosion : public Command
{
public:
Explosion(unsigned int intensity, string explosionType, Coords location, function<void(void)> callback = [](){}) :
Command(callback),
location(location),
intensity(intensity),
explosionType(explosionType)
{
priority = CommandPriority::MEDIUM;
};
virtual string getString();
virtual unsigned int getLoad() { return 5; }
private:
const Coords location;
const unsigned int intensity;
const string explosionType;
};

View File

@@ -0,0 +1,161 @@
#pragma once
#include "framework.h"
#include "utils.h"
namespace DataIndex {
enum DataIndexes {
startOfData = 0,
category,
alive,
human,
controlled,
coalition,
country,
name,
unitName,
groupName,
state,
task,
hasTask,
position,
speed,
horizontalVelocity,
verticalVelocity,
heading,
track,
isActiveTanker,
isActiveAWACS,
onOff,
followRoads,
fuel,
desiredSpeed,
desiredSpeedType,
desiredAltitude,
desiredAltitudeType,
leaderID,
formationOffset,
targetID,
targetPosition,
ROE,
reactionToThreat,
emissionsCountermeasures,
TACAN,
radio,
generalSettings,
ammo,
contacts,
activePath,
isLeader,
operateAs,
shotsScatter,
shotsIntensity,
health,
lastIndex,
endOfData = 255
};
}
namespace State
{
enum States
{
NONE = 0,
IDLE,
REACH_DESTINATION,
ATTACK,
FOLLOW,
LAND,
REFUEL,
AWACS,
TANKER,
BOMB_POINT,
CARPET_BOMB,
BOMB_BUILDING,
FIRE_AT_AREA,
SIMULATE_FIRE_FIGHT,
SCENIC_AAA,
MISS_ON_PURPOSE,
LAND_AT_POINT
};
};
namespace ShotsScatter
{
enum ShotsScatters
{
NONE = 0,
HIGH,
MEDIUM,
LOW
};
};
namespace ShotsIntensity
{
enum ShotsIntensities
{
NONE = 0,
LOW,
MEDIUM,
HIGH
};
};
#pragma pack(push, 1)
namespace DataTypes {
struct TACAN
{
bool isOn = false;
unsigned char channel = 40;
char XY = 'X';
char callsign[4];
};
struct Radio
{
unsigned int frequency = 124000000; // MHz
unsigned char callsign = 1;
unsigned char callsignNumber = 1;
};
struct GeneralSettings
{
bool prohibitJettison = false;
bool prohibitAA = false;
bool prohibitAG = false;
bool prohibitAfterburner = false;
bool prohibitAirWpn = false;
};
struct Ammo {
unsigned short quantity = 0;
char name[33];
unsigned char guidance = 0;
unsigned char category = 0;
unsigned char missileCategory = 0;
};
struct Contact {
unsigned int ID = 0;
unsigned char detectionMethod = 0;
};
}
#pragma pack(pop)
bool operator==(const DataTypes::TACAN& lhs, const DataTypes::TACAN& rhs);
bool operator==(const DataTypes::Radio& lhs, const DataTypes::Radio& rhs);
bool operator==(const DataTypes::GeneralSettings& lhs, const DataTypes::GeneralSettings& rhs);
bool operator==(const DataTypes::Ammo& lhs, const DataTypes::Ammo& rhs);
bool operator==(const DataTypes::Contact& lhs, const DataTypes::Contact& rhs);
struct SpawnOptions {
string unitType;
Coords location;
string loadout;
string liveryID;
};
struct CloneOptions {
unsigned int ID;
Coords location;
};

View File

@@ -0,0 +1,25 @@
#pragma once
#include "unit.h"
#define GROUND_DEST_DIST_THR 10
class GroundUnit : public Unit
{
public:
GroundUnit(json::value json, unsigned int ID);
static void loadDatabase(string path);
virtual void setState(unsigned char newState);
virtual void setDefaults(bool force = false);
virtual void changeSpeed(string change);
virtual void setOnOff(bool newOnOff, bool force = false);
virtual void setFollowRoads(bool newFollowRoads, bool force = false);
void aimAtPoint(Coords aimTarget);
protected:
virtual void AIloop();
static json::value database;
};

View File

@@ -0,0 +1,20 @@
#pragma once
#include "airunit.h"
#define HELICOPTER_DEST_DIST_THR 500 // Meters
class Helicopter : public AirUnit
{
public:
Helicopter(json::value json, unsigned int ID);
static void loadDatabase(string path);
virtual void changeSpeed(string change);
virtual void changeAltitude(string change);
virtual double getDestinationReachedThreshold() { return HELICOPTER_DEST_DIST_THR; }
protected:
static json::value database;
};

View File

@@ -0,0 +1,22 @@
#pragma once
#include "unit.h"
#define NAVY_DEST_DIST_THR 100
class NavyUnit : public Unit
{
public:
NavyUnit(json::value json, unsigned int ID);
static void loadDatabase(string path);
virtual void setState(unsigned char newState);
virtual void setDefaults(bool force = false);
virtual void changeSpeed(string change);
virtual void setOnOff(bool newOnOff, bool force = false);
protected:
virtual void AIloop();
static json::value database;
};

View File

@@ -0,0 +1,50 @@
#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(string key, json::value value, string username, json::value& answer);
bool checkSpawnPoints(int spawnPoints, string coalition);
bool isCommandExecuted(string commandHash) { return (find(executedCommandsHashes.begin(), executedCommandsHashes.end(), commandHash) != executedCommandsHashes.end()); }
void setFrameRate(double newFrameRate) { frameRate = newFrameRate; }
void setRestrictSpawns(bool newRestrictSpawns) { restrictSpawns = newRestrictSpawns; }
void setRestrictToCoalition(bool newRestrictToCoalition) { restrictToCoalition = newRestrictToCoalition; }
void setSetupTime(unsigned int newSetupTime) { setupTime = newSetupTime; }
void setBlueSpawnPoints(int newBlueSpawnPoints) { blueSpawnPoints = newBlueSpawnPoints; }
void setRedSpawnPoints(int newRedSpawnPoints) { redSpawnPoints = newRedSpawnPoints; }
void setEras(vector<string> newEras) { eras = newEras; }
void setCommandModeOptions(json::value newOptions);
int getFrameRate() { return static_cast<int>(round(frameRate)); };
int getLoad();
bool getRestrictSpawns() { return restrictSpawns; }
bool getRestrictToCoalition() { return restrictToCoalition; }
unsigned int getSetupTime() { return setupTime; }
int getBlueSpawnPoints() { return blueSpawnPoints; }
int getRedSpawnPoints() { return redSpawnPoints; }
vector<string> getEras() { return eras; }
json::value getCommandModeOptions();
private:
list<Command*> commands;
list<string> executedCommandsHashes;
unsigned int load = 0;
double frameRate = 0;
bool restrictSpawns = false;
bool restrictToCoalition = false;
unsigned int setupTime = 300;
int blueSpawnPoints = 10000;
int redSpawnPoints = 10000;
vector<string> eras = { "WW2", "Early Cold War", "Mid Cold War", "Late Cold War", "Modern" };
};

View File

@@ -0,0 +1,17 @@
#pragma once
#include "framework.h"
#define PROTECTED_CALL "Olympus = {}\n \
function Olympus.protectedCall(...)\n\n \
local status, retval = pcall(...)\n \
if not status then\n \
if Olympus.log ~= nil then\n \
Olympus.log:error(retval)\n \
else\n \
trigger.action.outText(\"Olympus critical error: \" ..retval, 20)\n \
end\n \
end\n \
end\n \
trigger.action.outText(\"Olympus.protectedCall registered successfully\", 10)\n"
void registerLuaFunctions(lua_State* L);

View File

@@ -0,0 +1,40 @@
#pragma once
#include "framework.h"
#include "luatools.h"
using namespace web::http;
using namespace web::http::experimental::listener;
class UnitsManager;
class Scheduler;
class Server
{
public:
Server(lua_State* L);
void start(lua_State* L);
void stop(lua_State* L);
private:
std::thread* serverThread;
void handle_options(http_request request);
void handle_get(http_request request);
void handle_request(http_request request, function<void(json::value const&, json::value&)> action);
void handle_put(http_request request);
string extractUsername(http_request& request);
string extractPassword(http_request& request);
void task();
atomic<bool> runListener;
string gameMasterPassword = "";
string blueCommanderPassword = "";
string redCommanderPassword = "";
string atcPassword = "";
string observerPassword = "";
};

265
backend/core/include/unit.h Normal file
View File

@@ -0,0 +1,265 @@
#pragma once
#include "framework.h"
#include "utils.h"
#include "dcstools.h"
#include "luatools.h"
#include "logger.h"
#include "commands.h"
#include "datatypes.h"
#include <chrono>
using namespace std::chrono;
#define TASK_CHECK_INIT_VALUE 10
class Unit
{
public:
Unit(json::value json, unsigned int ID);
~Unit();
/********** Methods **********/
void initialize(json::value json);
virtual void setDefaults(bool force = false);
void runAILoop();
void update(json::value json, double dt);
void refreshLeaderData(unsigned long long time);
unsigned int getID() { return ID; }
void getData(stringstream& ss, unsigned long long time);
Coords getActiveDestination() { return activeDestination; }
virtual void changeSpeed(string change) {};
virtual void changeAltitude(string change) {};
bool setActiveDestination();
void resetActiveDestination();
void landAt(Coords loc);
bool updateActivePath(bool looping);
void clearActivePath();
void pushActivePathFront(Coords newActivePathFront);
void pushActivePathBack(Coords newActivePathBack);
void popActivePathFront();
void goToDestination(string enrouteTask = "nil");
bool isDestinationReached(double threshold);
string getTargetName();
string getLeaderName();
bool isTargetAlive();
bool isLeaderAlive();
void resetTask();
bool checkTaskFailed();
void resetTaskFailedCounter();
void setHasTaskAssigned(bool newHasTaskAssigned);
void setEnableTaskCheckFailed(bool newEnableTaskCheckFailed) { enableTaskFailedCheck = newEnableTaskCheckFailed; }
bool getEnableTaskCheckFailed() { return enableTaskFailedCheck; }
void triggerUpdate(unsigned char datumIndex);
bool hasFreshData(unsigned long long time);
bool checkFreshness(unsigned char datumIndex, unsigned long long time);
/********** Setters **********/
virtual void setCategory(string newValue) { updateValue(category, newValue, DataIndex::category); }
virtual void setAlive(bool newValue) { updateValue(alive, newValue, DataIndex::alive); }
virtual void setHuman(bool newValue) { updateValue(human, newValue, DataIndex::human); }
virtual void setControlled(bool newValue) { updateValue(controlled, newValue, DataIndex::controlled); }
virtual void setCoalition(unsigned char newValue) { updateValue(coalition, newValue, DataIndex::coalition); }
virtual void setCountry(unsigned char newValue) { updateValue(country, newValue, DataIndex::country); }
virtual void setName(string newValue) { updateValue(name, newValue, DataIndex::name); }
virtual void setUnitName(string newValue) { updateValue(unitName, newValue, DataIndex::unitName); }
virtual void setGroupName(string newValue) { updateValue(groupName, newValue, DataIndex::groupName); }
virtual void setState(unsigned char newValue) { updateValue(state, newValue, DataIndex::state); };
virtual void setTask(string newValue) { updateValue(task, newValue, DataIndex::task); }
virtual void setHasTask(bool newValue);
virtual void setPosition(Coords newValue) { updateValue(position, newValue, DataIndex::position); }
virtual void setSpeed(double newValue) { updateValue(speed, newValue, DataIndex::speed); }
virtual void setHorizontalVelocity(double newValue) { updateValue(horizontalVelocity, newValue, DataIndex::horizontalVelocity); }
virtual void setVerticalVelocity(double newValue) { updateValue(verticalVelocity, newValue, DataIndex::verticalVelocity); }
virtual void setHeading(double newValue) { updateValue(heading, newValue, DataIndex::heading); }
virtual void setTrack(double newValue) { updateValue(track, newValue, DataIndex::track); }
virtual void setIsActiveTanker(bool newValue);
virtual void setIsActiveAWACS(bool newValue);
virtual void setOnOff(bool newValue, bool force = false) { updateValue(onOff, newValue, DataIndex::onOff); };
virtual void setFollowRoads(bool newValue, bool force = false) { updateValue(followRoads, newValue, DataIndex::followRoads); };
virtual void setFuel(unsigned short newValue) { updateValue(fuel, newValue, DataIndex::fuel); }
virtual void setDesiredSpeed(double newValue);
virtual void setDesiredSpeedType(string newValue);
virtual void setDesiredAltitude(double newValue);
virtual void setDesiredAltitudeType(string newValue);
virtual void setLeaderID(unsigned int newValue) { updateValue(leaderID, newValue, DataIndex::leaderID); }
virtual void setFormationOffset(Offset formationOffset);
virtual void setTargetID(unsigned int newValue) { updateValue(targetID, newValue, DataIndex::targetID); }
virtual void setTargetPosition(Coords newValue) { updateValue(targetPosition, newValue, DataIndex::targetPosition); }
virtual void setROE(unsigned char newValue, bool force = false);
virtual void setReactionToThreat(unsigned char newValue, bool force = false);
virtual void setEmissionsCountermeasures(unsigned char newValue, bool force = false);
virtual void setTACAN(DataTypes::TACAN newValue, bool force = false);
virtual void setRadio(DataTypes::Radio newValue, bool force = false);
virtual void setGeneralSettings(DataTypes::GeneralSettings newValue, bool force = false);
virtual void setAmmo(vector<DataTypes::Ammo> newValue);
virtual void setContacts(vector<DataTypes::Contact> newValue);
virtual void setActivePath(list<Coords> newValue);
virtual void setIsLeader(bool newValue) { updateValue(isLeader, newValue, DataIndex::isLeader); }
virtual void setOperateAs(unsigned char newValue) { updateValue(operateAs, newValue, DataIndex::operateAs); }
virtual void setShotsScatter(unsigned char newValue) { updateValue(shotsScatter, newValue, DataIndex::shotsScatter); }
virtual void setShotsIntensity(unsigned char newValue) { updateValue(shotsIntensity, newValue, DataIndex::shotsIntensity); }
virtual void setHealth(unsigned char newValue) { updateValue(health, newValue, DataIndex::health); }
/********** Getters **********/
virtual string getCategory() { return category; };
virtual bool getAlive() { return alive; }
virtual bool getHuman() { return human; }
virtual bool getControlled() { return controlled; }
virtual unsigned char getCoalition() { return coalition; }
virtual unsigned char getCountry() { return country; }
virtual string getName() { return name; }
virtual string getUnitName() { return unitName; }
virtual string getGroupName() { return groupName; }
virtual unsigned char getState() { return state; }
virtual string getTask() { return task; }
virtual bool getHasTask() { return hasTask; }
virtual Coords getPosition() { return position; }
virtual double getSpeed() { return speed; }
virtual double getHorizontalVelocity() { return horizontalVelocity; }
virtual double getVerticalVelocity() { return verticalVelocity; }
virtual double getHeading() { return heading; }
virtual double getTrack() { return track; }
virtual bool getIsActiveTanker() { return isActiveTanker; }
virtual bool getIsActiveAWACS() { return isActiveAWACS; }
virtual bool getOnOff() { return onOff; };
virtual bool getFollowRoads() { return followRoads; };
virtual unsigned short getFuel() { return fuel; }
virtual double getDesiredSpeed() { return desiredSpeed; };
virtual bool getDesiredSpeedType() { return desiredSpeedType; };
virtual double getDesiredAltitude() { return desiredAltitude; };
virtual bool getDesiredAltitudeType() { return desiredAltitudeType; };
virtual unsigned int getLeaderID() { return leaderID; }
virtual Offset getFormationOffset() { return formationOffset; }
virtual unsigned int getTargetID() { return targetID; }
virtual Coords getTargetPosition() { return targetPosition; }
virtual unsigned char getROE() { return ROE; }
virtual unsigned char getReactionToThreat() { return reactionToThreat; }
virtual unsigned char getEmissionsCountermeasures() { return emissionsCountermeasures; };
virtual DataTypes::TACAN getTACAN() { return TACAN; }
virtual DataTypes::Radio getRadio() { return radio; }
virtual DataTypes::GeneralSettings getGeneralSettings() { return generalSettings; }
virtual vector<DataTypes::Ammo> getAmmo() { return ammo; }
virtual vector<DataTypes::Contact> getContacts() { return contacts; }
virtual list<Coords> getActivePath() { return activePath; }
virtual bool getIsLeader() { return isLeader; }
virtual unsigned char getOperateAs() { return operateAs; }
virtual unsigned char getShotsScatter() { return shotsScatter; }
virtual unsigned char getShotsIntensity() { return shotsIntensity; }
virtual unsigned char getHealth() { return health; }
protected:
unsigned int ID;
string category;
bool alive = false;
bool human = false;
bool controlled = false;
unsigned char coalition = NULL;
unsigned char country = NULL;
string name = "";
string unitName = "";
string groupName = "";
unsigned char state = State::NONE;
string task = "";
bool hasTask = false;
Coords position = Coords(NULL);
double speed = NULL;
double horizontalVelocity = NULL;
double verticalVelocity = NULL;
double heading = NULL;
double track = NULL;
bool isActiveTanker = false;
bool isActiveAWACS = false;
bool onOff = true;
bool followRoads = false;
unsigned short fuel = 0;
double desiredSpeed = 0;
bool desiredSpeedType = 0; /* CAS */
double desiredAltitude = 1;
bool desiredAltitudeType = 0; /* ASL */
unsigned int leaderID = NULL;
Offset formationOffset = Offset(NULL);
unsigned int targetID = NULL;
Coords targetPosition = Coords(NULL);
unsigned char ROE = ROE::OPEN_FIRE_WEAPON_FREE;
unsigned char reactionToThreat = ReactionToThreat::EVADE_FIRE;
unsigned char emissionsCountermeasures = EmissionCountermeasure::DEFEND;
DataTypes::TACAN TACAN;
DataTypes::Radio radio;
DataTypes::GeneralSettings generalSettings;
vector<DataTypes::Ammo> ammo;
vector<DataTypes::Contact> contacts;
list<Coords> activePath;
bool isLeader = false;
unsigned char operateAs = 2;
Coords activeDestination = Coords(NULL);
unsigned char shotsScatter = 2;
unsigned char shotsIntensity = 2;
unsigned char health = 100;
/********** Other **********/
unsigned int taskCheckCounter = 0;
unsigned int internalCounter = 0;
Unit* missOnPurposeTarget = nullptr;
bool hasTaskAssigned = false;
double initialFuel = 0;
map<unsigned char, unsigned long long> updateTimeMap;
unsigned long long lastLoopTime = 0;
bool enableTaskFailedCheck = false;
/********** Private methods **********/
virtual void AIloop() = 0;
void appendString(stringstream& ss, const unsigned char& datumIndex, const string& datumValue) {
const unsigned short size = static_cast<unsigned short>(datumValue.size());
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&size, sizeof(unsigned short));
ss << datumValue;
}
/********** Template methods **********/
template <typename T>
void updateValue(T& value, T& newValue, unsigned char datumIndex)
{
if (newValue != value)
{
triggerUpdate(datumIndex);
value = newValue;
}
}
template <typename T>
void appendNumeric(stringstream& ss, const unsigned char& datumIndex, T& datumValue) {
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&datumValue, sizeof(T));
}
template <typename T>
void appendVector(stringstream& ss, const unsigned char& datumIndex, vector<T>& datumValue) {
const unsigned short size = static_cast<unsigned short>(datumValue.size());
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&size, sizeof(unsigned short));
for (auto& el : datumValue)
ss.write((const char*)&el, sizeof(T));
}
template <typename T>
void appendList(stringstream& ss, const unsigned char& datumIndex, list<T>& datumValue) {
const unsigned short size = static_cast<unsigned short>(datumValue.size());;
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&size, sizeof(unsigned short));
for (auto& el: datumValue)
ss.write((const char*)&el, sizeof(T));
}
};

View File

@@ -0,0 +1,34 @@
#pragma once
#include "framework.h"
#include "dcstools.h"
class Unit;
class UnitsManager
{
public:
UnitsManager(lua_State* L);
~UnitsManager();
map<unsigned int, Unit*>& getUnits() { return units; };
Unit* getUnit(unsigned int ID);
bool isUnitInGroup(Unit* unit);
bool isUnitGroupLeader(Unit* unit, Unit*& leader);
Unit* getGroupLeader(unsigned int ID);
Unit* getGroupLeader(Unit* unit);
vector<Unit*> getGroupMembers(string groupName);
void update(json::value& missionData, double dt);
void runAILoop();
void getUnitData(stringstream &ss, unsigned long long time);
void deleteUnit(unsigned int ID, bool explosion, string explosionType, bool immediate);
void acquireControl(unsigned int ID);
void loadDatabases();
Unit* getClosestUnit(Unit* unit, unsigned char coalition, vector<string> categories, double &distance);
map<Unit*, double> getUnitsInRange(Unit* unit, unsigned char coalition, vector<string> categories, double range);
private:
map<unsigned int, Unit*> units;
json::value missionDB;
};

View File

@@ -0,0 +1,116 @@
#pragma once
#include "framework.h"
#include "utils.h"
#include "dcstools.h"
#include "luatools.h"
#include "logger.h"
#include "commands.h"
#include "datatypes.h"
#include <chrono>
using namespace std::chrono;
class Weapon
{
public:
Weapon(json::value json, unsigned int ID);
~Weapon();
/********** Methods **********/
void initialize(json::value json);
void update(json::value json, double dt);
unsigned int getID() { return ID; }
void getData(stringstream& ss, unsigned long long time);
void triggerUpdate(unsigned char datumIndex);
bool hasFreshData(unsigned long long time);
bool checkFreshness(unsigned char datumIndex, unsigned long long time);
/********** Setters **********/
virtual void setCategory(string newValue) { updateValue(category, newValue, DataIndex::category); }
virtual void setAlive(bool newValue) { updateValue(alive, newValue, DataIndex::alive); }
virtual void setCoalition(unsigned char newValue) { updateValue(coalition, newValue, DataIndex::coalition); }
virtual void setName(string newValue) { updateValue(name, newValue, DataIndex::name); }
virtual void setPosition(Coords newValue) { updateValue(position, newValue, DataIndex::position); }
virtual void setSpeed(double newValue) { updateValue(speed, newValue, DataIndex::speed); }
virtual void setHeading(double newValue) { updateValue(heading, newValue, DataIndex::heading); }
/********** Getters **********/
virtual string getCategory() { return category; };
virtual bool getAlive() { return alive; }
virtual unsigned char getCoalition() { return coalition; }
virtual string getName() { return name; }
virtual Coords getPosition() { return position; }
virtual double getSpeed() { return speed; }
virtual double getHeading() { return heading; }
protected:
unsigned int ID;
string category;
bool alive = false;
unsigned char coalition = NULL;
string name = "";
Coords position = Coords(NULL);
double speed = NULL;
double heading = NULL;
/********** Other **********/
map<unsigned char, unsigned long long> updateTimeMap;
/********** Private methods **********/
void appendString(stringstream& ss, const unsigned char& datumIndex, const string& datumValue) {
const unsigned short size = static_cast<unsigned short>(datumValue.size());
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&size, sizeof(unsigned short));
ss << datumValue;
}
/********** Template methods **********/
template <typename T>
void updateValue(T& value, T& newValue, unsigned char datumIndex)
{
if (newValue != value)
{
triggerUpdate(datumIndex);
value = newValue;
}
}
template <typename T>
void appendNumeric(stringstream& ss, const unsigned char& datumIndex, T& datumValue) {
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&datumValue, sizeof(T));
}
template <typename T>
void appendVector(stringstream& ss, const unsigned char& datumIndex, vector<T>& datumValue) {
const unsigned short size = datumValue.size();
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&size, sizeof(unsigned short));
for (auto& el : datumValue)
ss.write((const char*)&el, sizeof(T));
}
template <typename T>
void appendList(stringstream& ss, const unsigned char& datumIndex, list<T>& datumValue) {
const unsigned short size = datumValue.size();
ss.write((const char*)&datumIndex, sizeof(unsigned char));
ss.write((const char*)&size, sizeof(unsigned short));
for (auto& el : datumValue)
ss.write((const char*)&el, sizeof(T));
}
};
class Missile : public Weapon
{
public:
Missile(json::value json, unsigned int ID);
};
class Bomb : public Weapon
{
public:
Bomb(json::value json, unsigned int ID);
};

View File

@@ -0,0 +1,21 @@
#pragma once
#include "framework.h"
#include "dcstools.h"
class Weapon;
class WeaponsManager
{
public:
WeaponsManager(lua_State* L);
~WeaponsManager();
map<unsigned int, Weapon*>& getWeapons() { return weapons; };
Weapon* getWeapon(unsigned int ID);
void update(json::value& missionData, double dt);
void getWeaponData(stringstream& ss, unsigned long long time);
private:
map<unsigned int, Weapon*> weapons;
};

14
backend/core/resource.h Normal file
View File

@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by core.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,71 @@
#include "aircraft.h"
#include "utils.h"
#include "logger.h"
#include "commands.h"
#include "scheduler.h"
#include "defines.h"
#include "unitsManager.h"
#include <GeographicLib/Geodesic.hpp>
using namespace GeographicLib;
extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
json::value Aircraft::database = json::value();
extern string instancePath;
void Aircraft::loadDatabase(string path) {
std::ifstream ifstream(instancePath + path);
std::stringstream ss;
ss << ifstream.rdbuf();
std::error_code errorCode;
database = json::value::parse(ss.str(), errorCode);
if (database.is_object())
log("Aircrafts database loaded correctly from " + instancePath + path);
else
log("Error reading Aircrafts database file");
}
/* Aircraft */
Aircraft::Aircraft(json::value json, unsigned int ID) : AirUnit(json, ID)
{
log("New Aircraft created with ID: " + to_string(ID));
setCategory("Aircraft");
setDesiredSpeed(knotsToMs(300));
setDesiredAltitude(ftToM(20000));
};
void Aircraft::changeSpeed(string change)
{
if (change.compare("stop") == 0)
setState(State::IDLE);
else if (change.compare("slow") == 0)
setDesiredSpeed(getDesiredSpeed() - knotsToMs(25));
else if (change.compare("fast") == 0)
setDesiredSpeed(getDesiredSpeed() + knotsToMs(25));
if (getDesiredSpeed() < knotsToMs(50))
setDesiredSpeed(knotsToMs(50));
}
void Aircraft::changeAltitude(string change)
{
if (change.compare("descend") == 0)
{
if (getDesiredAltitude() > 5000)
setDesiredAltitude(getDesiredAltitude() - ftToM(2500));
else if (getDesiredAltitude() > 0)
setDesiredAltitude(getDesiredAltitude() - ftToM(500));
}
else if (change.compare("climb") == 0)
{
if (getDesiredAltitude() > 5000)
setDesiredAltitude(getDesiredAltitude() + ftToM(2500));
else if (getDesiredAltitude() >= 0)
setDesiredAltitude(getDesiredAltitude() + ftToM(500));
}
if (getDesiredAltitude() < 0)
setDesiredAltitude(0);
}

View File

@@ -0,0 +1,379 @@
#include "airunit.h"
#include "utils.h"
#include "logger.h"
#include "commands.h"
#include "scheduler.h"
#include "defines.h"
#include "unitsManager.h"
#include <GeographicLib/Geodesic.hpp>
using namespace GeographicLib;
extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
/* Air unit */
AirUnit::AirUnit(json::value json, unsigned int ID) : Unit(json, ID)
{
};
void AirUnit::setDefaults(bool force)
{
if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return;
/* Set the default IDLE state */
setState(State::IDLE);
/* Set desired altitude to be equal to current altitude so the unit does not climb/descend after spawn */
setDesiredAltitude(position.alt);
/* Set the default options */
setROE(ROE::OPEN_FIRE_WEAPON_FREE, force);
setReactionToThreat(ReactionToThreat::EVADE_FIRE, force);
setEmissionsCountermeasures(EmissionCountermeasure::DEFEND, force);
strcpy_s(TACAN.callsign, 4, "TKR");
setTACAN(TACAN, force);
setRadio(radio, force);
setGeneralSettings(generalSettings, force);
}
void AirUnit::setState(unsigned char newState)
{
Coords currentTargetPosition = getTargetPosition();
/************ Perform any action required when LEAVING a state ************/
if (newState != state) {
switch (state) {
case State::IDLE: {
break;
}
case State::REACH_DESTINATION: {
break;
}
case State::ATTACK: {
setTargetID(NULL);
break;
}
case State::FOLLOW: {
setLeaderID(NULL);
break;
}
case State::LAND: {
break;
}
case State::REFUEL: {
break;
}
case State::BOMB_POINT:
case State::CARPET_BOMB:
case State::BOMB_BUILDING: {
setTargetPosition(Coords(NULL));
break;
}
case State::LAND_AT_POINT: {
break;
}
default:
break;
}
}
/************ Perform any action required when ENTERING a state ************/
switch (newState) {
case State::IDLE: {
setEnableTaskCheckFailed(false);
clearActivePath();
resetActiveDestination();
break;
}
case State::REACH_DESTINATION: {
setEnableTaskCheckFailed(true);
resetActiveDestination();
break;
}
case State::ATTACK: {
setEnableTaskCheckFailed(true);
if (isTargetAlive()) {
Unit* target = unitsManager->getUnit(targetID);
Coords targetPosition = Coords(target->getPosition().lat, target->getPosition().lng, 0);
clearActivePath();
pushActivePathFront(targetPosition);
resetActiveDestination();
}
break;
}
case State::FOLLOW: {
setEnableTaskCheckFailed(true);
clearActivePath();
resetActiveDestination();
break;
}
case State::LAND: {
setEnableTaskCheckFailed(false);
resetActiveDestination();
break;
}
case State::REFUEL: {
setEnableTaskCheckFailed(true);
initialFuel = fuel;
clearActivePath();
resetActiveDestination();
break;
}
case State::BOMB_POINT:
case State::CARPET_BOMB:
case State::BOMB_BUILDING: {
setTargetPosition(currentTargetPosition);
setEnableTaskCheckFailed(true);
clearActivePath();
resetActiveDestination();
break;
}
case State::LAND_AT_POINT: {
setEnableTaskCheckFailed(true);
resetActiveDestination();
break;
}
default:
break;
}
setHasTask(false);
resetTaskFailedCounter();
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
state = newState;
triggerUpdate(DataIndex::state);
AIloop();
}
void AirUnit::AIloop()
{
srand(static_cast<unsigned int>(time(NULL)) + ID);
/* State machine */
switch (state) {
case State::IDLE: {
if (isActiveTanker)
setTask("Tanker racetrack");
else if (isActiveAWACS)
setTask("AWACS racetrack");
else
setTask("Idle");
if (!getHasTask())
{
std::ostringstream taskSS;
if (isActiveTanker) {
taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track', altitude = " <<
desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" <<
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "' }}";
}
else if (isActiveAWACS) {
taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Circle', altitude = " <<
desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" <<
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "' }}";
}
else {
taskSS << "{ id = 'Orbit', pattern = 'Circle', altitude = " <<
desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" <<
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "'}";
}
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
break;
}
case State::REACH_DESTINATION: {
string enrouteTask = "";
bool looping = false;
if (isActiveTanker)
{
enrouteTask = "{ id = 'Tanker' }";
setTask("Tanker");
}
else if (isActiveAWACS)
{
enrouteTask = "{ id = 'AWACS' }";
setTask("AWACS");
}
else
{
enrouteTask = "nil";
setTask("Reaching destination");
}
if (activeDestination == NULL || !getHasTask())
{
if (!setActiveDestination())
setState(State::IDLE);
else
goToDestination(enrouteTask);
}
else {
if (isDestinationReached(getDestinationReachedThreshold())) {
if (updateActivePath(looping) && setActiveDestination())
goToDestination(enrouteTask);
else
setState(State::IDLE);
}
}
break;
}
case State::LAND: {
string enrouteTask = "{ id = 'Land' }";
setTask("Landing");
if (activeDestination == NULL)
{
setActiveDestination();
goToDestination(enrouteTask);
}
break;
}
case State::ATTACK: {
/* If the target is not alive (either not set or was succesfully destroyed) go back to REACH_DESTINATION */
if (!isTargetAlive()) {
setState(State::REACH_DESTINATION);
break;
}
/* Attack state is an "enroute" task, meaning the unit will keep trying to attack even if a new destination is set. This is useful to
manoeuvre the unit so that it can detect and engage the target. */
std::ostringstream enrouteTaskSS;
enrouteTaskSS << "{"
<< "id = 'EngageUnit'" << ","
<< "targetID = " << targetID << ","
<< "}";
string enrouteTask = enrouteTaskSS.str();
setTask("Attacking " + getTargetName());
if (!getHasTask())
{
setActiveDestination();
goToDestination(enrouteTask);
}
break;
}
case State::FOLLOW: {
clearActivePath();
activeDestination = Coords(NULL);
/* If the leader is not alive (either not set or was destroyed) go back to IDLE */
if (!isLeaderAlive()) {
setState(State::IDLE);
break;
}
setTask("Following " + getTargetName());
Unit* leader = unitsManager->getUnit(leaderID);
if (!getHasTask()) {
if (leader != nullptr && leader->getAlive() && formationOffset != NULL)
{
std::ostringstream taskSS;
taskSS << "{"
<< "id = 'FollowUnit'" << ", "
<< "leaderID = " << leader->getID() << ","
<< "offset = {"
<< "x = " << formationOffset.x << ","
<< "y = " << formationOffset.y << ","
<< "z = " << formationOffset.z
<< "},"
<< "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
}
break;
}
case State::REFUEL: {
setTask("Refueling");
if (!getHasTask()) {
if (fuel <= initialFuel) {
std::ostringstream taskSS;
taskSS << "{"
<< "id = 'Refuel'"
<< "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
else {
setState(State::IDLE);
}
}
break;
}
case State::BOMB_POINT: {
setTask("Bombing point");
if (!getHasTask()) {
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'Bombing', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
break;
}
case State::CARPET_BOMB: {
setTask("Carpet bombing");
if (!getHasTask()) {
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'CarpetBombing', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
break;
}
case State::BOMB_BUILDING: {
setTask("Bombing building");
if (!getHasTask()) {
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'AttackMapObject', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
break;
}
case State::LAND_AT_POINT: {
setTask("Landing at point");
if (!getHasTask()) {
setActiveDestination();
std::ostringstream taskSS;
taskSS.precision(10),
taskSS << "{"
<< "id = 'LandAtPoint', "
<< "lat = " << activeDestination.lat << ", "
<< "lng = " << activeDestination.lng
<< "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
break;
}
default:
break;
}
}

View File

@@ -0,0 +1,251 @@
#include "commands.h"
#include "logger.h"
#include "dcstools.h"
#include "unit.h"
#include "unitsmanager.h"
extern UnitsManager* unitsManager;
/* Move command */
string Move::getString()
{
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.move, "
<< "\"" << groupName << "\"" << ", "
<< destination.lat << ", "
<< destination.lng << ", "
<< altitude << ", "
<< "\"" << altitudeType << "\"" << ", "
<< speed << ", "
<< "\"" << speedType << "\"" << ", "
<< "\"" << category << "\"" << ", "
<< taskOptions;
return commandSS.str();
}
/* Smoke command */
string Smoke::getString()
{
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.smoke, "
<< "\"" << color << "\"" << ", "
<< location.lat << ", "
<< location.lng;
return commandSS.str();
}
/* Spawn ground units command */
string SpawnGroundUnits::getString()
{
std::ostringstream unitsSS;
unitsSS.precision(10);
for (int i = 0; i < spawnOptions.size(); i++) {
unitsSS << "[" << i + 1 << "] = {"
<< "unitType = " << "\"" << spawnOptions[i].unitType << "\"" << ", "
<< "lat = " << spawnOptions[i].location.lat << ", "
<< "lng = " << spawnOptions[i].location.lng << ", "
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << " }, ";
}
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.spawnUnits, {"
<< "category = " << "\"" << "GroundUnit" << "\"" << ", "
<< "coalition = " << "\"" << coalition << "\"" << ", "
<< "country = \"" << country << "\", "
<< "units = " << "{" << unitsSS.str() << "}" << "}";
return commandSS.str();
}
/* Spawn ground units command */
string SpawnNavyUnits::getString()
{
std::ostringstream unitsSS;
unitsSS.precision(10);
for (int i = 0; i < spawnOptions.size(); i++) {
unitsSS << "[" << i + 1 << "] = {"
<< "unitType = " << "\"" << spawnOptions[i].unitType << "\"" << ", "
<< "lat = " << spawnOptions[i].location.lat << ", "
<< "lng = " << spawnOptions[i].location.lng << ", "
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << " }, ";
}
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.spawnUnits, {"
<< "category = " << "\"" << "NavyUnit" << "\"" << ", "
<< "coalition = " << "\"" << coalition << "\"" << ", "
<< "country = \"" << country << "\", "
<< "units = " << "{" << unitsSS.str() << "}" << "}";
return commandSS.str();
}
/* Spawn aircrafts command */
string SpawnAircrafts::getString()
{
std::ostringstream unitsSS;
unitsSS.precision(10);
for (int i = 0; i < spawnOptions.size(); i++) {
unitsSS << "[" << i + 1 << "] = {"
<< "unitType = " << "\"" << spawnOptions[i].unitType << "\"" << ", "
<< "lat = " << spawnOptions[i].location.lat << ", "
<< "lng = " << spawnOptions[i].location.lng << ", "
<< "alt = " << spawnOptions[i].location.alt << ", "
<< "loadout = \"" << spawnOptions[i].loadout << "\"" << ", "
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << " }, ";
}
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.spawnUnits, {"
<< "category = " << "\"" << "Aircraft" << "\"" << ", "
<< "coalition = " << "\"" << coalition << "\"" << ", "
<< "airbaseName = \"" << airbaseName << "\", "
<< "country = \"" << country << "\", "
<< "units = " << "{" << unitsSS.str() << "}" << "}";
return commandSS.str();
}
/* Spawn helicopters command */
string SpawnHelicopters::getString()
{
std::ostringstream unitsSS;
unitsSS.precision(10);
for (int i = 0; i < spawnOptions.size(); i++) {
unitsSS << "[" << i + 1 << "] = {"
<< "unitType = " << "\"" << spawnOptions[i].unitType << "\"" << ", "
<< "lat = " << spawnOptions[i].location.lat << ", "
<< "lng = " << spawnOptions[i].location.lng << ", "
<< "alt = " << spawnOptions[i].location.alt << ", "
<< "loadout = \"" << spawnOptions[i].loadout << "\"" << ", "
<< "liveryID = " << "\"" << spawnOptions[i].liveryID << "\"" << " }, ";
}
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.spawnUnits, {"
<< "category = " << "\"" << "Helicopter" << "\"" << ", "
<< "coalition = " << "\"" << coalition << "\"" << ", "
<< "airbaseName = \"" << airbaseName << "\", "
<< "country = \"" << country << "\", "
<< "units = " << "{" << unitsSS.str() << "}" << "}";
return commandSS.str();
}
/* Clone unit command */
string Clone::getString()
{
std::ostringstream unitsSS;
unitsSS.precision(10);
for (int i = 0; i < cloneOptions.size(); i++) {
unitsSS << "[" << i + 1 << "] = {"
<< "ID = " << cloneOptions[i].ID << ", "
<< "lat = " << cloneOptions[i].location.lat << ", "
<< "lng = " << cloneOptions[i].location.lng << " }, ";
}
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.clone, "
<< "{" << unitsSS.str() << "}" << ", "
<< (deleteOriginal ? "true" : "false");
return commandSS.str();
}
/* Delete unit command */
string Delete::getString()
{
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.delete, "
<< ID << ", "
<< (explosion ? "true" : "false") << ", "
<< "\"" << explosionType << "\"";
return commandSS.str();
}
/* Set task command */
string SetTask::getString()
{
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.setTask, "
<< "\"" << groupName << "\"" << ", "
<< task;
return commandSS.str();
}
/* Reset task command */
string ResetTask::getString()
{
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.resetTask, "
<< "\"" << groupName << "\"";
return commandSS.str();
}
/* Set command command */
string SetCommand::getString()
{
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.setCommand, "
<< "\"" << groupName << "\"" << ", "
<< command;
return commandSS.str();
}
/* Set option command */
string SetOption::getString()
{
std::ostringstream commandSS;
commandSS.precision(10);
if (!isBoolean) {
commandSS << "Olympus.setOption, "
<< "\"" << groupName << "\"" << ", "
<< optionID << ", "
<< optionValue;
} else {
commandSS << "Olympus.setOption, "
<< "\"" << groupName << "\"" << ", "
<< optionID << ", "
<< (optionBool? "true": "false");
}
return commandSS.str();
}
/* Set onOff command */
string SetOnOff::getString()
{
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.setOnOff, "
<< "\"" << groupName << "\"" << ", "
<< (onOff ? "true" : "false");
return commandSS.str();
}
/* Explosion command */
string Explosion::getString()
{
std::ostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.explosion, "
<< intensity << ", "
<< "\"" << explosionType << "\"" << ", "
<< location.lat << ", "
<< location.lng;
return commandSS.str();
}

163
backend/core/src/core.cpp Normal file
View File

@@ -0,0 +1,163 @@
#include "dcstools.h"
#include "logger.h"
#include "defines.h"
#include "unitsManager.h"
#include "weaponsManager.h"
#include "server.h"
#include "scheduler.h"
#include "scriptLoader.h"
#include "luatools.h"
#include <chrono>
using namespace std::chrono;
auto lastUnitsUpdate = std::chrono::system_clock::now();
auto lastWeaponsUpdate = std::chrono::system_clock::now();
auto lastExecution = std::chrono::system_clock::now();
/* Singleton objects */
UnitsManager* unitsManager = nullptr;
WeaponsManager* weaponsManager = nullptr;
Server* server = nullptr;
Scheduler* scheduler = nullptr;
/* Data jsons */
json::value missionData = json::value::object();
mutex mutexLock;
string sessionHash;
string instancePath;
bool initialized = false;
unsigned int frameCounter = 0;
/* Called when DCS simulation stops. All singleton instances are deleted. */
extern "C" DllExport int coreDeinit(lua_State* L)
{
if (!initialized)
return (0);
log("Olympus coreDeinit called successfully");
server->stop(L);
delete unitsManager;
delete weaponsManager;
delete server;
delete scheduler;
log("All singletons objects destroyed successfully");
return(0);
}
/* Called when DCS simulation starts. All singletons are instantiated, and the custom Lua functions are registered in the Lua state. */
extern "C" DllExport int coreInit(lua_State* L, const char* path)
{
instancePath = path;
log("Initializing core.dll with instance path " + instancePath);
sessionHash = random_string(16);
log("Random session hash " + sessionHash);
unitsManager = new UnitsManager(L);
weaponsManager = new WeaponsManager(L);
server = new Server(L);
scheduler = new Scheduler(L);
registerLuaFunctions(L);
server->start(L);
unitsManager->loadDatabases();
initialized = true;
return(0);
}
extern "C" DllExport int coreFrame(lua_State* L)
{
if (!initialized)
return (0);
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
frameCounter++;
const std::chrono::duration<double> executionDuration = std::chrono::system_clock::now() - lastExecution;
if (executionDuration.count() > (20 * FRAMERATE_TIME_INTERVAL)) {
if (executionDuration.count() > 0) {
scheduler->setFrameRate(frameCounter / executionDuration.count());
frameCounter = 0;
}
lastExecution = std::chrono::system_clock::now();
}
if (scheduler != nullptr)
scheduler->execute(L);
return(0);
}
extern "C" DllExport int coreUnitsData(lua_State * L)
{
if (!initialized)
return (0);
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
json::value unitsData = json::value::object();
lua_getglobal(L, "Olympus");
lua_getfield(L, -1, "unitsData");
luaTableToJSON(L, -1, unitsData);
const std::chrono::duration<double> updateDuration = std::chrono::system_clock::now() - lastUnitsUpdate;
if (unitsData.has_object_field(L"units")) {
unitsManager->update(unitsData[L"units"], updateDuration.count());
}
lastUnitsUpdate = std::chrono::system_clock::now();
return(0);
}
extern "C" DllExport int coreWeaponsData(lua_State * L)
{
if (!initialized)
return (0);
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
json::value weaponsData = json::value::object();
lua_getglobal(L, "Olympus");
lua_getfield(L, -1, "weaponsData");
luaTableToJSON(L, -1, weaponsData);
const std::chrono::duration<double> updateDuration = std::chrono::system_clock::now() - lastWeaponsUpdate;
if (weaponsData.has_object_field(L"weapons")) {
weaponsManager->update(weaponsData[L"weapons"], updateDuration.count());
}
lastWeaponsUpdate = std::chrono::system_clock::now();
return(0);
}
extern "C" DllExport int coreMissionData(lua_State * L)
{
if (!initialized)
return (0);
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
lua_getglobal(L, "Olympus");
lua_getfield(L, -1, "missionData");
luaTableToJSON(L, -1, missionData);
return(0);
}

View File

@@ -0,0 +1,30 @@
#include "datatypes.h"
bool operator==(const DataTypes::TACAN& lhs, const DataTypes::TACAN& rhs)
{
return lhs.isOn == rhs.isOn && lhs.channel == rhs.channel && lhs.XY == rhs.XY && strcmp(lhs.callsign, rhs.callsign) == 0;
}
bool operator==(const DataTypes::Radio& lhs, const DataTypes::Radio& rhs)
{
return lhs.frequency == rhs.frequency && lhs.callsign == rhs.callsign && lhs.callsignNumber == rhs.callsignNumber;
}
bool operator==(const DataTypes::GeneralSettings& lhs, const DataTypes::GeneralSettings& rhs)
{
return lhs.prohibitAA == rhs.prohibitAA && lhs.prohibitAfterburner == rhs.prohibitAfterburner && lhs.prohibitAG == rhs.prohibitAG &&
lhs.prohibitAirWpn == rhs.prohibitAirWpn && lhs.prohibitJettison == rhs.prohibitJettison;
}
bool operator==(const DataTypes::Ammo& lhs, const DataTypes::Ammo& rhs)
{
return lhs.category == rhs.category && lhs.guidance == rhs.guidance && lhs.missileCategory == rhs.missileCategory &&
lhs.quantity == rhs.quantity && strcmp(lhs.name, rhs.name) == 0;
}
bool operator==(const DataTypes::Contact& lhs, const DataTypes::Contact& rhs)
{
return lhs.detectionMethod == rhs.detectionMethod && lhs.ID == rhs.ID;
}

View File

@@ -0,0 +1,566 @@
#include "groundunit.h"
#include "utils.h"
#include "logger.h"
#include "commands.h"
#include "scheduler.h"
#include "defines.h"
#include "unitsmanager.h"
#include <GeographicLib/Geodesic.hpp>
using namespace GeographicLib;
extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
json::value GroundUnit::database = json::value();
extern string instancePath;
#define RANDOM_ZERO_TO_ONE (double)(rand()) / (double)(RAND_MAX)
#define RANDOM_MINUS_ONE_TO_ONE (((double)(rand()) / (double)(RAND_MAX) - 0.5) * 2)
void GroundUnit::loadDatabase(string path) {
std::ifstream ifstream(instancePath + path);
std::stringstream ss;
ss << ifstream.rdbuf();
std::error_code errorCode;
database = json::value::parse(ss.str(), errorCode);
if (database.is_object())
log("GroundUnits database loaded correctly from " + instancePath + path);
else
log("Error reading GroundUnits database file");
}
/* Ground unit */
GroundUnit::GroundUnit(json::value json, unsigned int ID) : Unit(json, ID)
{
log("New Ground Unit created with ID: " + to_string(ID));
setCategory("GroundUnit");
setDesiredSpeed(10);
};
void GroundUnit::setDefaults(bool force)
{
if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return;
/* Set the default IDLE state */
setState(State::IDLE);
/* Set the default options */
setROE(ROE::WEAPON_FREE, force);
setOnOff(onOff, force);
setFollowRoads(followRoads, force);
}
void GroundUnit::setState(unsigned char newState)
{
Coords currentTargetPosition = getTargetPosition();
/************ Perform any action required when LEAVING a state ************/
if (newState != state) {
switch (state) {
case State::IDLE: {
break;
}
case State::REACH_DESTINATION: {
break;
}
case State::ATTACK: {
setTargetID(NULL);
break;
}
case State::FIRE_AT_AREA:
case State::SIMULATE_FIRE_FIGHT:
case State::SCENIC_AAA:
case State::MISS_ON_PURPOSE: {
setTargetPosition(Coords(NULL));
break;
}
default:
break;
}
}
/************ Perform any action required when ENTERING a state ************/
switch (newState) {
case State::IDLE: {
setEnableTaskCheckFailed(false);
clearActivePath();
resetActiveDestination();
break;
}
case State::REACH_DESTINATION: {
setEnableTaskCheckFailed(true);
resetActiveDestination();
break;
}
case State::ATTACK: {
setEnableTaskCheckFailed(true);
clearActivePath();
resetActiveDestination();
break;
}
case State::FIRE_AT_AREA: {
setTargetPosition(currentTargetPosition);
setEnableTaskCheckFailed(true);
clearActivePath();
resetActiveDestination();
break;
}
case State::SIMULATE_FIRE_FIGHT: {
setTargetPosition(currentTargetPosition);
setEnableTaskCheckFailed(false);
clearActivePath();
resetActiveDestination();
break;
}
case State::SCENIC_AAA: {
setEnableTaskCheckFailed(false);
clearActivePath();
resetActiveDestination();
break;
}
case State::MISS_ON_PURPOSE: {
setEnableTaskCheckFailed(false);
clearActivePath();
resetActiveDestination();
break;
}
default:
break;
}
setHasTask(false);
resetTaskFailedCounter();
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
state = newState;
triggerUpdate(DataIndex::state);
AIloop();
}
void GroundUnit::AIloop()
{
srand(static_cast<unsigned int>(time(NULL)) + ID);
switch (state) {
case State::IDLE: {
setTask("Idle");
if (getHasTask())
resetTask();
break;
}
case State::REACH_DESTINATION: {
setTask("Reaching destination");
string enrouteTask = "";
bool looping = false;
std::ostringstream taskSS;
taskSS << "{ id = 'FollowRoads', value = " << (getFollowRoads() ? "true" : "false") << " }";
enrouteTask = taskSS.str();
if (activeDestination == NULL || !getHasTask())
{
if (!setActiveDestination())
setState(State::IDLE);
else
goToDestination(enrouteTask);
}
else {
if (isDestinationReached(GROUND_DEST_DIST_THR)) {
if (updateActivePath(looping) && setActiveDestination())
goToDestination(enrouteTask);
else
setState(State::IDLE);
}
}
break;
}
case State::ATTACK: {
Unit* target = unitsManager->getUnit(getTargetID());
if (target != nullptr) {
setTask("Attacking " + target->getUnitName());
if (!getHasTask()) {
/* Send the command */
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'AttackUnit', unitID = " << target->getID() << " }";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
}
else {
setState(State::IDLE);
}
break;
}
case State::FIRE_AT_AREA: {
setTask("Firing at area");
if (!getHasTask()) {
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 100}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
break;
}
case State::SIMULATE_FIRE_FIGHT: {
setTask("Simulating fire fight");
if (internalCounter == 0 && targetPosition != Coords(NULL) && scheduler->getLoad() < 30) {
/* Get the distance and bearing to the target */
Coords scatteredTargetPosition = targetPosition;
double distance;
double bearing1;
double bearing2;
Geodesic::WGS84().Inverse(getPosition().lat, getPosition().lng, scatteredTargetPosition.lat, scatteredTargetPosition.lng, distance, bearing1, bearing2);
/* Compute the scattered position applying a random scatter to the shot */
double scatterDistance = distance * tan(10 /* degs */ * (ShotsScatter::LOW - shotsScatter) / 57.29577 + 2 / 57.29577 /* degs */) * RANDOM_MINUS_ONE_TO_ONE;
Geodesic::WGS84().Direct(scatteredTargetPosition.lat, scatteredTargetPosition.lng, bearing1 + 90, scatterDistance, scatteredTargetPosition.lat, scatteredTargetPosition.lng);
/* Recover the data from the database */
double aimTime = 2; /* s */
bool indirectFire = false;
double shotsBaseInterval = 15; /* s */
if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)];
if (databaseEntry.has_number_field(L"aimTime"))
aimTime = databaseEntry[L"aimTime"].as_number().to_double();
if (databaseEntry.has_boolean_field(L"indirectFire"))
indirectFire = databaseEntry[L"indirectFire"].as_bool();
if (databaseEntry.has_number_field(L"shotsBaseInterval"))
shotsBaseInterval = databaseEntry[L"shotsBaseInterval"].as_number().to_double();
}
/* If the unit is of the indirect fire type, like a mortar, simply shoot at the target */
if (indirectFire) {
log(unitName + "(" + name + ")" + " simulating fire fight with indirect fire");
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << scatteredTargetPosition.lat << ", lng = " << scatteredTargetPosition.lng << ", radius = 100}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
/* Otherwise use the aim method */
else {
log(unitName + "(" + name + ")" + " simulating fire fight with aim at point method");
aimAtPoint(scatteredTargetPosition);
}
/* Wait an amout of time depending on the shots intensity */
internalCounter = static_cast<unsigned int>(((ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + aimTime) / FRAMERATE_TIME_INTERVAL);
}
if (targetPosition == Coords(NULL))
setState(State::IDLE);
/* Fallback if something went wrong */
if (internalCounter == 0)
internalCounter = static_cast<unsigned int>(3 / FRAMERATE_TIME_INTERVAL);
internalCounter--;
break;
}
case State::SCENIC_AAA: {
setTask("Scenic AAA");
/* Only perform scenic functions when the scheduler is "free" */
if (((!getHasTask() && scheduler->getLoad() < 30) || internalCounter == 0)) {
double distance = 0;
unsigned char unitCoalition = coalition == 0 ? getOperateAs() : coalition;
unsigned char targetCoalition = unitCoalition == 2 ? 1 : 2;
Unit* target = unitsManager->getClosestUnit(this, targetCoalition, { "Aircraft", "Helicopter" }, distance);
/* Recover the data from the database */
double aimTime = 2; /* s */
double shotsBaseInterval = 15; /* s */
if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)];
if (databaseEntry.has_number_field(L"aimTime"))
aimTime = databaseEntry[L"aimTime"].as_number().to_double();
if (databaseEntry.has_number_field(L"shotsBaseInterval"))
shotsBaseInterval = databaseEntry[L"shotsBaseInterval"].as_number().to_double();
}
/* Only run if an enemy air unit is closer than 20km to avoid useless load */
if (target != nullptr && distance < 20000 /* m */) {
double r = 15; /* m */
double barrelElevation = r * tan(acos(((double)(rand()) / (double)(RAND_MAX))));
double lat = 0;
double lng = 0;
double randomBearing = ((double)(rand()) / (double)(RAND_MAX)) * 360;
Geodesic::WGS84().Direct(position.lat, position.lng, randomBearing, r, lat, lng);
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << lat << ", lng = " << lng << ", alt = " << position.alt + barrelElevation << ", radius = 0.001}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
/* Wait an amout of time depending on the shots intensity */
internalCounter = static_cast<unsigned int>(((ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + aimTime) / FRAMERATE_TIME_INTERVAL);
}
}
if (internalCounter == 0)
internalCounter = static_cast<unsigned int>(3 / FRAMERATE_TIME_INTERVAL);
internalCounter--;
break;
}
case State::MISS_ON_PURPOSE: {
setTask("Missing on purpose");
/* Check that the unit can perform AAA duties */
bool canAAA = false;
if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)];
if (databaseEntry.has_boolean_field(L"canAAA"))
canAAA = databaseEntry[L"canAAA"].as_bool();
}
if (canAAA) {
/* Only perform scenic functions when the scheduler is "free" */
/* Only run this when the internal counter reaches 0 to avoid excessive computations when no nearby target */
if (scheduler->getLoad() < 30 && internalCounter == 0) {
double distance = 0;
unsigned char unitCoalition = coalition == 0 ? getOperateAs() : coalition;
unsigned char targetCoalition = unitCoalition == 2 ? 1 : 2;
/* Default gun values */
double barrelHeight = 1.0; /* m */
double muzzleVelocity = 860; /* m/s */
double aimTime = 10; /* s */
unsigned int shotsToFire = 10;
double shotsBaseInterval = 15; /* s */
double shotsBaseScatter = 2; /* degs */
double engagementRange = 10000; /* m */
double targetingRange = 0; /* m */
double aimMethodRange = 0; /* m */
double acquisitionRange = 0; /* m */
/* Load gun values from database */
if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)];
if (databaseEntry.has_number_field(L"barrelHeight"))
barrelHeight = databaseEntry[L"barrelHeight"].as_number().to_double();
if (databaseEntry.has_number_field(L"muzzleVelocity"))
muzzleVelocity = databaseEntry[L"muzzleVelocity"].as_number().to_double();
if (databaseEntry.has_number_field(L"aimTime"))
aimTime = databaseEntry[L"aimTime"].as_number().to_double();
if (databaseEntry.has_number_field(L"shotsToFire"))
shotsToFire = databaseEntry[L"shotsToFire"].as_number().to_uint32();
if (databaseEntry.has_number_field(L"engagementRange"))
engagementRange = databaseEntry[L"engagementRange"].as_number().to_double();
if (databaseEntry.has_number_field(L"shotsBaseInterval"))
shotsBaseInterval = databaseEntry[L"shotsBaseInterval"].as_number().to_double();
if (databaseEntry.has_number_field(L"shotsBaseScatter"))
shotsBaseScatter = databaseEntry[L"shotsBaseScatter"].as_number().to_double();
if (databaseEntry.has_number_field(L"targetingRange"))
targetingRange = databaseEntry[L"targetingRange"].as_number().to_double();
if (databaseEntry.has_number_field(L"aimMethodRange"))
aimMethodRange = databaseEntry[L"aimMethodRange"].as_number().to_double();
if (databaseEntry.has_number_field(L"acquisitionRange"))
acquisitionRange = databaseEntry[L"acquisitionRange"].as_number().to_double();
}
/* Get all the units in range and select one at random */
double range = max(max(engagementRange, aimMethodRange), acquisitionRange);
map<Unit*, double> targets = unitsManager->getUnitsInRange(this, targetCoalition, { "Aircraft", "Helicopter" }, range);
Unit* target = nullptr;
unsigned int index = static_cast<unsigned int>((RANDOM_ZERO_TO_ONE * (targets.size() - 1)));
for (auto const& p : targets) {
if (index-- == 0) {
target = p.first;
distance = p.second;
}
}
/* Only do if we have a valid target close enough for AAA */
if (target != nullptr) {
/* Approximate the flight time */
if (muzzleVelocity != 0)
aimTime += distance / muzzleVelocity;
/* If the target is in targeting range and we are in highest precision mode, target it */
if (distance < targetingRange && shotsScatter == ShotsScatter::LOW) {
/* Send the command */
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'AttackUnit', unitID = " << target->getID() << " }";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
internalCounter = static_cast<unsigned int>((aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL);
}
/* Else, do miss on purpose */
else {
/* Compute where the target will be in aimTime seconds, plus the effect of scatter. */
double scatterDistance = distance * tan(shotsBaseScatter * (ShotsScatter::LOW - shotsScatter) / 57.29577) * (RANDOM_ZERO_TO_ONE - 0.1);
double aimDistance = target->getHorizontalVelocity() * aimTime + scatterDistance;
double aimLat = 0;
double aimLng = 0;
Geodesic::WGS84().Direct(target->getPosition().lat, target->getPosition().lng, target->getTrack() * 57.29577, aimDistance, aimLat, aimLng); /* TODO make util to convert degrees and radians function */
double aimAlt = target->getPosition().alt + target->getVerticalVelocity() * aimTime + distance * tan(shotsBaseScatter * (ShotsScatter::LOW - shotsScatter) / 57.29577) * RANDOM_ZERO_TO_ONE; // Force to always miss high never low
/* Send the command */
if (distance < engagementRange) {
/* If the unit is closer than the engagement range, use the fire at point method */
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << aimLat << ", lng = " << aimLng << ", alt = " << aimAlt << ", radius = 0.001, expendQty = " << shotsToFire << " }";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
internalCounter = static_cast<unsigned int>((aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL);
}
else if (distance < aimMethodRange) {
/* If the unit is closer than the aim method range, use the aim method range */
aimAtPoint(Coords(aimLat, aimLng, aimAlt));
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
internalCounter = static_cast<unsigned int>((aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL);
}
else {
/* Else just wake the unit up with an impossible command */
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << 0 << ", lng = " << 0 << ", alt = " << 0 << ", radius = 0.001, expendQty = " << 0 << " }";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
setTargetPosition(Coords(NULL));
/* Don't wait too long before checking again */
internalCounter = static_cast<unsigned int>(5 / FRAMERATE_TIME_INTERVAL);
}
}
missOnPurposeTarget = target;
}
else {
if (getHasTask())
resetTask();
}
}
/* If no valid target was detected */
if (internalCounter == 0) {
double alertnessTimeConstant = 10; /* s */
if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)];
if (databaseEntry.has_number_field(L"alertnessTimeConstant"))
alertnessTimeConstant = databaseEntry[L"alertnessTimeConstant"].as_number().to_double();
}
internalCounter = static_cast<unsigned int>((5 + RANDOM_ZERO_TO_ONE * alertnessTimeConstant * 0 /* TODO: remove to enable alertness again */) / FRAMERATE_TIME_INTERVAL);
missOnPurposeTarget = nullptr;
setTargetPosition(Coords(NULL));
}
internalCounter--;
}
else {
setState(State::IDLE);
}
break;
}
default:
break;
}
}
void GroundUnit::aimAtPoint(Coords aimTarget) {
double dist;
double bearing1;
double bearing2;
Geodesic::WGS84().Inverse(position.lat, position.lng, aimTarget.lat, aimTarget.lng, dist, bearing1, bearing2);
/* Aim point distance */
double r = 15; /* m */
/* Default gun values */
double barrelHeight = 1.0; /* m */
double muzzleVelocity = 860; /* m/s */
double shotsBaseScatter = 5; /* degs */
if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)];
if (databaseEntry.has_number_field(L"barrelHeight") && databaseEntry.has_number_field(L"muzzleVelocity")) {
barrelHeight = databaseEntry[L"barrelHeight"].as_number().to_double();
muzzleVelocity = databaseEntry[L"muzzleVelocity"].as_number().to_double();
}
if (databaseEntry.has_number_field(L"shotsBaseScatter"))
shotsBaseScatter = databaseEntry[L"shotsBaseScatter"].as_number().to_double();
}
/* Compute the elevation angle of the gun*/
double deltaHeight = (aimTarget.alt - (position.alt + barrelHeight));
double alpha = 9.81 / 2 * dist * dist / (muzzleVelocity * muzzleVelocity);
double inner = dist * dist - 4 * alpha * (alpha + deltaHeight);
/* Check we can reach the target*/
if (inner > 0) {
/* Compute elevation and bearing */
double barrelElevation = r * (dist - sqrt(inner)) / (2 * alpha);
double lat = 0;
double lng = 0;
Geodesic::WGS84().Direct(position.lat, position.lng, bearing1, r, lat, lng);
log(unitName + "(" + name + ")" + " shooting with aim at point method. Barrel elevation: " + to_string(barrelElevation * 57.29577) + "°, bearing: " + to_string(bearing1) + "°");
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << lat << ", lng = " << lng << ", alt = " << position.alt + barrelElevation + barrelHeight << ", radius = 0.001}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
else {
log("Target out of range for " + unitName + "(" + name + ")");
}
}
void GroundUnit::changeSpeed(string change)
{
if (change.compare("stop") == 0)
setState(State::IDLE);
else if (change.compare("slow") == 0)
setDesiredSpeed(getDesiredSpeed() - knotsToMs(5));
else if (change.compare("fast") == 0)
setDesiredSpeed(getDesiredSpeed() + knotsToMs(5));
if (getDesiredSpeed() < 0)
setDesiredSpeed(0);
}
void GroundUnit::setOnOff(bool newOnOff, bool force)
{
if (newOnOff != onOff || force) {
Unit::setOnOff(newOnOff, force);
Command* command = dynamic_cast<Command*>(new SetOnOff(groupName, onOff));
scheduler->appendCommand(command);
}
}
void GroundUnit::setFollowRoads(bool newFollowRoads, bool force)
{
if (newFollowRoads != followRoads || force) {
Unit::setFollowRoads(newFollowRoads, force);
resetActiveDestination(); /* Reset active destination to apply option*/
}
}

View File

@@ -0,0 +1,71 @@
#include "helicopter.h"
#include "utils.h"
#include "logger.h"
#include "commands.h"
#include "scheduler.h"
#include "defines.h"
#include "unitsManager.h"
#include <GeographicLib/Geodesic.hpp>
using namespace GeographicLib;
extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
json::value Helicopter::database = json::value();
extern string instancePath;
void Helicopter::loadDatabase(string path) {
std::ifstream ifstream(instancePath + path);
std::stringstream ss;
ss << ifstream.rdbuf();
std::error_code errorCode;
database = json::value::parse(ss.str(), errorCode);
if (database.is_object())
log("Helicopters database loaded correctly from " + instancePath + path);
else
log("Error reading Helicopters database file");
}
/* Helicopter */
Helicopter::Helicopter(json::value json, unsigned int ID) : AirUnit(json, ID)
{
log("New Helicopter created with ID: " + to_string(ID));
setCategory("Helicopter");
setDesiredSpeed(knotsToMs(100));
setDesiredAltitude(ftToM(5000));
};
void Helicopter::changeSpeed(string change)
{
if (change.compare("stop") == 0)
setState(State::IDLE);
else if (change.compare("slow") == 0)
setDesiredSpeed(getDesiredSpeed() - knotsToMs(10));
else if (change.compare("fast") == 0)
setDesiredSpeed(getDesiredSpeed() + knotsToMs(10));
if (getDesiredSpeed() < knotsToMs(0))
setDesiredSpeed(knotsToMs(0));
}
void Helicopter::changeAltitude(string change)
{
if (change.compare("descend") == 0)
{
if (getDesiredAltitude() > 100)
setDesiredAltitude(getDesiredAltitude() - ftToM(100));
else if (getDesiredAltitude() > 0)
setDesiredAltitude(getDesiredAltitude() - ftToM(10));
}
else if (change.compare("climb") == 0)
{
if (getDesiredAltitude() > 100)
setDesiredAltitude(getDesiredAltitude() + ftToM(100));
else if (getDesiredAltitude() >= 0)
setDesiredAltitude(getDesiredAltitude() + ftToM(10));
}
if (getDesiredAltitude() < 0)
setDesiredAltitude(0);
}

View File

@@ -0,0 +1,236 @@
#include "navyunit.h"
#include "utils.h"
#include "logger.h"
#include "commands.h"
#include "scheduler.h"
#include "defines.h"
#include "unitsManager.h"
#include <GeographicLib/Geodesic.hpp>
using namespace GeographicLib;
extern Scheduler* scheduler;
extern UnitsManager* unitsManager;
json::value NavyUnit::database = json::value();
extern string instancePath;
void NavyUnit::loadDatabase(string path) {
std::ifstream ifstream(instancePath + path);
std::stringstream ss;
ss << ifstream.rdbuf();
std::error_code errorCode;
database = json::value::parse(ss.str(), errorCode);
if (database.is_object())
log("NavyUnits database loaded correctly from " + instancePath + path);
else
log("Error reading NavyUnits database file");
}
/* Navy Unit */
NavyUnit::NavyUnit(json::value json, unsigned int ID) : Unit(json, ID)
{
log("New Navy Unit created with ID: " + to_string(ID));
setCategory("NavyUnit");
setDesiredSpeed(10);
};
void NavyUnit::setDefaults(bool force)
{
if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return;
/* Set the default IDLE state */
setState(State::IDLE);
/* Set the default options */
setROE(ROE::WEAPON_FREE, force);
setOnOff(onOff, force);
setFollowRoads(followRoads, force);
}
void NavyUnit::setState(unsigned char newState)
{
Coords currentTargetPosition = getTargetPosition();
/************ Perform any action required when LEAVING a state ************/
if (newState != state) {
switch (state) {
case State::IDLE: {
break;
}
case State::REACH_DESTINATION: {
break;
}
case State::ATTACK: {
setTargetID(NULL);
break;
}
case State::FIRE_AT_AREA:
case State::SIMULATE_FIRE_FIGHT:
case State::SCENIC_AAA:
case State::MISS_ON_PURPOSE: {
setTargetPosition(Coords(NULL));
break;
}
default:
break;
}
}
/************ Perform any action required when ENTERING a state ************/
switch (newState) {
case State::IDLE: {
setEnableTaskCheckFailed(false);
clearActivePath();
resetActiveDestination();
break;
}
case State::REACH_DESTINATION: {
setEnableTaskCheckFailed(true);
resetActiveDestination();
break;
}
case State::ATTACK: {
setEnableTaskCheckFailed(true);
clearActivePath();
resetActiveDestination();
break;
}
case State::FIRE_AT_AREA: {
setTargetPosition(currentTargetPosition);
setEnableTaskCheckFailed(true);
clearActivePath();
resetActiveDestination();
break;
}
case State::SIMULATE_FIRE_FIGHT: {
setTargetPosition(currentTargetPosition);
setEnableTaskCheckFailed(false);
clearActivePath();
resetActiveDestination();
break;
}
case State::SCENIC_AAA: {
setEnableTaskCheckFailed(false);
clearActivePath();
resetActiveDestination();
break;
}
case State::MISS_ON_PURPOSE: {
setEnableTaskCheckFailed(false);
clearActivePath();
resetActiveDestination();
break;
}
default:
break;
}
setHasTask(false);
resetTaskFailedCounter();
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
state = newState;
triggerUpdate(DataIndex::state);
AIloop();
}
void NavyUnit::AIloop()
{
srand(static_cast<unsigned int>(time(NULL)) + ID);
switch (state) {
case State::IDLE: {
setTask("Idle");
if (getHasTask())
resetTask();
break;
}
case State::REACH_DESTINATION: {
string enrouteTask = "{}";
bool looping = false;
if (activeDestination == NULL || !getHasTask())
{
if (!setActiveDestination())
setState(State::IDLE);
else
goToDestination(enrouteTask);
}
else {
if (isDestinationReached(NAVY_DEST_DIST_THR)) {
if (updateActivePath(looping) && setActiveDestination())
goToDestination(enrouteTask);
else
setState(State::IDLE);
}
}
break;
}
case State::ATTACK: {
Unit* target = unitsManager->getUnit(getTargetID());
if (target != nullptr) {
setTask("Attacking " + target->getUnitName());
if (!getHasTask()) {
/* Send the command */
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'AttackUnit', unitID = " << target->getID() << " }";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
}
else {
setState(State::IDLE);
}
}
case State::FIRE_AT_AREA: {
setTask("Firing at area");
if (!getHasTask()) {
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1000}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
}
case State::SIMULATE_FIRE_FIGHT: {
setTask("Simulating fire fight");
// TODO
setState(State::IDLE);
}
default:
break;
}
}
void NavyUnit::changeSpeed(string change)
{
if (change.compare("stop") == 0)
setState(State::IDLE);
else if (change.compare("slow") == 0)
setDesiredSpeed(getDesiredSpeed() - knotsToMs(5));
else if (change.compare("fast") == 0)
setDesiredSpeed(getDesiredSpeed() + knotsToMs(5));
if (getDesiredSpeed() < 0)
setDesiredSpeed(0);
}
void NavyUnit::setOnOff(bool newOnOff, bool force)
{
if (newOnOff != onOff || force) {
Unit::setOnOff(newOnOff, force);
Command* command = dynamic_cast<Command*>(new SetOnOff(groupName, onOff));
scheduler->appendCommand(command);
}
}

View File

@@ -0,0 +1,691 @@
#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)
{
LogInfo(L, "Scheduler constructor called successfully");
}
Scheduler::~Scheduler()
{
}
/* Appends a */
void Scheduler::appendCommand(Command* newCommand)
{
for (auto command : commands) {
if (command->getString().compare(newCommand->getString()) == 0 && command->getPriority() == newCommand->getPriority())
return;
}
commands.push_back(newCommand);
}
int Scheduler::getLoad()
{
int currentLoad = 0;
for (auto command : commands) {
currentLoad += command->getLoad();
}
return currentLoad;
}
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::IMMEDIATE;
while (priority >= CommandPriority::LOW) {
for (auto command : commands)
{
if (command->getPriority() == priority)
{
string commandString = "Olympus.protectedCall(" + command->getString() + ")";
if (dostring_in(L, "server", (commandString)))
log("Error executing command " + commandString);
else
log("Command '" + commandString + "' executed correctly, current load " + to_string(getLoad()));
/* Adjust the load depending on the fps */
double fpsMultiplier = 20;
if (getFrameRate() + 3 > 0)
fpsMultiplier = static_cast<unsigned int>(max(1, 60 / (getFrameRate() + 3))); /* Multiplier between 1 and 20 */
load = static_cast<unsigned int>(command->getLoad() * fpsMultiplier);
commands.remove(command);
executedCommandsHashes.push_back(command->getHash());
command->executeCallback(); /* Execute the command callback (this is a lambda function that can be used to execute a function when the command is run) */
delete command;
return;
}
}
priority--;
};
}
void Scheduler::setCommandModeOptions(json::value value) {
if (value.has_boolean_field(L"restrictSpawns"))
setRestrictSpawns(value[L"restrictSpawns"].as_bool());
if (value.has_boolean_field(L"restrictToCoalition"))
setRestrictToCoalition(value[L"restrictToCoalition"].as_bool());
if (value.has_number_field(L"setupTime"))
setSetupTime(value[L"setupTime"].as_number().to_int32());
if (value.has_object_field(L"spawnPoints")) {
if (value[L"spawnPoints"].has_number_field(L"blue"))
setBlueSpawnPoints(value[L"spawnPoints"][L"blue"].as_number().to_int32());
if (value[L"spawnPoints"].has_number_field(L"red"))
setRedSpawnPoints(value[L"spawnPoints"][L"red"].as_number().to_int32());
}
if (value.has_array_field(L"eras")) {
int length = static_cast<int>(value[L"eras"].as_array().size());
vector<string> newEras;
for (int idx = 0; idx < length; idx++)
newEras.push_back(to_string(value[L"eras"].as_array().at(idx)));
setEras(newEras);
}
}
json::value Scheduler::getCommandModeOptions() {
json::value json = json::value::object();
json[L"restrictSpawns"] = json::value(getRestrictSpawns());
json[L"restrictToCoalition"] = json::value(getRestrictToCoalition());
json[L"setupTime"] = json::value(getSetupTime());
json[L"spawnPoints"] = json::value::object();
json[L"spawnPoints"][L"blue"] = json::value(getBlueSpawnPoints());
json[L"spawnPoints"][L"red"] = json::value(getRedSpawnPoints());
int idx = 0;
json[L"eras"] = json::value::array();
for (string era : getEras())
json[L"eras"][idx++] = json::value(to_wstring(era));
return json;
}
bool Scheduler::checkSpawnPoints(int spawnPoints, string coalition)
{
if (!getRestrictSpawns()) return true;
if (coalition.compare("blue") == 0) {
if (getBlueSpawnPoints() - spawnPoints >= 0) {
setBlueSpawnPoints(getBlueSpawnPoints() - spawnPoints);
return true;
}
else {
log("Not enough blue coalition spawn points available. Available: " + to_string(getBlueSpawnPoints()) + ", required: " + to_string(spawnPoints));
return false;
}
}
else if (coalition.compare("red") == 0) {
if (getRedSpawnPoints() - spawnPoints >= 0) {
setRedSpawnPoints(getRedSpawnPoints() - spawnPoints);
return true;
}
else {
log("Not enough red coalition spawn points available. Available: " + to_string(getRedSpawnPoints()) + ", required: " + to_string(spawnPoints));
return false;
}
}
return false;
}
void Scheduler::handleRequest(string key, json::value value, string username, json::value& answer)
{
Command* command = nullptr;
log("Received request with ID: " + key);
log(L"Incoming command raw value: " + value.serialize());
/************************/
if (key.compare("setPath") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
{
json::value path = value[L"path"];
list<Coords> newPath;
for (unsigned int i = 0; i < path.as_array().size(); i++)
{
string WP = to_string(i);
double lat = path[i][L"lat"].as_double();
double lng = path[i][L"lng"].as_double();
Coords dest; dest.lat = lat; dest.lng = lng;
newPath.push_back(dest);
}
unit->setActivePath(newPath);
unit->setState(State::REACH_DESTINATION);
log(username + " updated destination path for unit " + unit->getUnitName() + "(" + unit->getName() + ")", true);
}
}
/************************/
else if (key.compare("smoke") == 0)
{
string color = to_string(value[L"color"]);
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 Smoke(color, loc));
log(username + " added a " + color + " smoke at (" + to_string(lat) + ", " + to_string(lng) + ")", true);
}
/************************/
else if (key.compare("spawnAircrafts") == 0 || key.compare("spawnHelicopters") == 0)
{
bool immediate = value[L"immediate"].as_bool();
string coalition = to_string(value[L"coalition"]);
string airbaseName = to_string(value[L"airbaseName"]);
string country = to_string(value[L"country"]);
int spawnPoints = value[L"spawnPoints"].as_number().to_int32();
if (!checkSpawnPoints(spawnPoints, coalition)) return;
vector<SpawnOptions> spawnOptions;
for (auto unit : value[L"units"].as_array()) {
string unitType = to_string(unit[L"unitType"]);
double lat = unit[L"location"][L"lat"].as_double();
double lng = unit[L"location"][L"lng"].as_double();
double alt = unit[L"altitude"].as_double();
Coords location; location.lat = lat; location.lng = lng; location.alt = alt;
string loadout = to_string(unit[L"loadout"]);
string liveryID = to_string(unit[L"liveryID"]);
spawnOptions.push_back({unitType, location, loadout, liveryID});
log(username + " spawned a " + coalition + " " + unitType, true);
}
if (key.compare("spawnAircrafts") == 0)
command = dynamic_cast<Command*>(new SpawnAircrafts(coalition, spawnOptions, airbaseName, country, immediate));
else
command = dynamic_cast<Command*>(new SpawnHelicopters(coalition, spawnOptions, airbaseName, country, immediate));
}
/************************/
else if (key.compare("spawnGroundUnits") == 0 || key.compare("spawnNavyUnits") == 0)
{
bool immediate = value[L"immediate"].as_bool();
string coalition = to_string(value[L"coalition"]);
string country = to_string(value[L"country"]);
int spawnPoints = value[L"spawnPoints"].as_number().to_int32();
if (!checkSpawnPoints(spawnPoints, coalition)) return;
vector<SpawnOptions> spawnOptions;
for (auto unit : value[L"units"].as_array()) {
string unitType = to_string(unit[L"unitType"]);
double lat = unit[L"location"][L"lat"].as_double();
double lng = unit[L"location"][L"lng"].as_double();
Coords location; location.lat = lat; location.lng = lng;
string liveryID = to_string(unit[L"liveryID"]);
spawnOptions.push_back({ unitType, location, "", liveryID });
log(username + " spawned a " + coalition + " " + unitType, true);
}
if (key.compare("spawnGroundUnits") == 0)
command = dynamic_cast<Command*>(new SpawnGroundUnits(coalition, spawnOptions, country, immediate));
else
command = dynamic_cast<Command*>(new SpawnNavyUnits(coalition, spawnOptions, country, immediate));
}
/************************/
else if (key.compare("attackUnit") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
unsigned int targetID = value[L"targetID"].as_integer();
Unit* unit = unitsManager->getGroupLeader(ID);
Unit* target = unitsManager->getUnit(targetID);
if (unit != nullptr && target != nullptr) {
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to attack unit " + target->getUnitName() + "(" + target->getName() + ")", true);
unit->setTargetID(targetID);
unit->setState(State::ATTACK);
}
}
/************************/
else if (key.compare("followUnit") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
unsigned int leaderID = value[L"targetID"].as_integer();
double offsetX = value[L"offsetX"].as_double();
double offsetY = value[L"offsetY"].as_double();
double offsetZ = value[L"offsetZ"].as_double();
Unit* unit = unitsManager->getGroupLeader(ID);
Unit* leader = unitsManager->getUnit(leaderID);
if (unit != nullptr && leader != nullptr) {
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to follow unit " + leader->getUnitName() + "(" + leader->getName() + ")", true);
unit->setFormationOffset(Offset(offsetX, offsetY, offsetZ));
unit->setLeaderID(leaderID);
unit->setState(State::FOLLOW);
}
}
/************************/
else if (key.compare("changeSpeed") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->changeSpeed(to_string(value[L"change"]));
log(username + " changed " + unit->getUnitName() + "(" + unit->getName() + ") speed: " + to_string(value[L"change"]), true);
}
}
/************************/
else if (key.compare("changeAltitude") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->changeAltitude(to_string(value[L"change"]));
log(username + " changed " + unit->getUnitName() + "(" + unit->getName() + ") altitude: " + to_string(value[L"change"]), true);
}
}
/************************/
else if (key.compare("setSpeed") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setDesiredSpeed(value[L"speed"].as_double());
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") speed: " + to_string(value[L"speed"].as_double()), true);
}
}
/************************/
else if (key.compare("setSpeedType") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setDesiredSpeedType(to_string(value[L"speedType"]));
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") speed type: " + to_string(value[L"speedType"]), true);
}
}
/************************/
else if (key.compare("setAltitude") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setDesiredAltitude(value[L"altitude"].as_double());
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") altitude: " + to_string(value[L"altitude"].as_double()), true);
}
}
/************************/
else if (key.compare("setAltitudeType") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setDesiredAltitudeType(to_string(value[L"altitudeType"]));
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") altitude type: " + to_string(value[L"altitudeType"]), true);
}
}
/************************/
else if (key.compare("cloneUnits") == 0)
{
vector<CloneOptions> cloneOptions;
bool deleteOriginal = value[L"deleteOriginal"].as_bool();
for (auto unit : value[L"units"].as_array()) {
unsigned int ID = unit[L"ID"].as_integer();
double lat = unit[L"location"][L"lat"].as_double();
double lng = unit[L"location"][L"lng"].as_double();
Coords location; location.lat = lat; location.lng = lng;
cloneOptions.push_back({ ID, location });
log(username + " cloning unit with ID " + to_string(ID), true);
}
command = dynamic_cast<Command*>(new Clone(cloneOptions, deleteOriginal));
}
/************************/
else if (key.compare("setROE") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unsigned char ROE = value[L"ROE"].as_number().to_uint32();
unit->setROE(ROE);
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") ROE to " + to_string(ROE), true);
}
}
/************************/
else if (key.compare("setReactionToThreat") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unsigned char reactionToThreat = value[L"reactionToThreat"].as_number().to_uint32();
unit->setReactionToThreat(reactionToThreat);
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") reaction to threat to " + to_string(reactionToThreat), true);
}
}
/************************/
else if (key.compare("setEmissionsCountermeasures") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unsigned char emissionsCountermeasures = value[L"emissionsCountermeasures"].as_number().to_uint32();
unit->setEmissionsCountermeasures(emissionsCountermeasures);
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") emissions and countermeasures to " + to_string(emissionsCountermeasures), true);
}
}
/************************/
else if (key.compare("landAt") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
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);
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to land", true);
}
}
/************************/
else if (key.compare("deleteUnit") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
bool explosion = value[L"explosion"].as_bool();
string explosionType = to_string(value[L"explosionType"]);
bool immediate = value[L"immediate"].as_bool();
Unit* unit = unitsManager->getUnit(ID);
if (unit != nullptr) {
unitsManager->deleteUnit(ID, explosion, explosionType, immediate);
log(username + " deleted unit " + unit->getUnitName() + "(" + unit->getName() + ")", true);
}
}
/************************/
else if (key.compare("refuel") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setState(State::REFUEL);
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to refuel", true);
}
}
/************************/
else if (key.compare("setAdvancedOptions") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
{
/* Advanced tasking */
unit->setIsActiveTanker(value[L"isActiveTanker"].as_bool());
unit->setIsActiveAWACS(value[L"isActiveAWACS"].as_bool());
/* TACAN Options */
DataTypes::TACAN TACAN;
TACAN.isOn = value[L"TACAN"][L"isOn"].as_bool();
TACAN.channel = static_cast<unsigned char>(value[L"TACAN"][L"channel"].as_number().to_uint32());
TACAN.XY = to_string(value[L"TACAN"][L"XY"]).at(0);
string callsign = to_string(value[L"TACAN"][L"callsign"]);
if (callsign.length() > 3)
callsign = callsign.substr(0, 3);
strcpy_s(TACAN.callsign, 4, callsign.c_str());
unit->setTACAN(TACAN);
/* Radio Options */
auto radio = value[L"radio"];
unit->setRadio({ radio[L"frequency"].as_number().to_uint32(),
static_cast<unsigned char>(radio[L"callsign"].as_number().to_uint32()),
static_cast<unsigned char>(radio[L"callsignNumber"].as_number().to_uint32())
});
/* General Settings */
auto generalSettings = value[L"generalSettings"];
unit->setGeneralSettings({ generalSettings[L"prohibitJettison"].as_bool(),
generalSettings[L"prohibitAA"].as_bool(),
generalSettings[L"prohibitAG"].as_bool(),
generalSettings[L"prohibitAfterburner"].as_bool(),
generalSettings[L"prohibitAirWpn"].as_bool(),
});
unit->resetActiveDestination();
log(username + " updated unit " + unit->getUnitName() + "(" + unit->getName() + ") advancedOptions", true);
}
}
/************************/
else if (key.compare("setFollowRoads") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
bool followRoads = value[L"followRoads"].as_bool();
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setFollowRoads(followRoads);
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") followRoads to: " + (followRoads ? "true" : "false"), true);
}
}
/************************/
else if (key.compare("setOnOff") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
bool onOff = value[L"onOff"].as_bool();
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setOnOff(onOff);
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") onOff to: " + (onOff? "true": "false"), true);
}
}
/************************/
else if (key.compare("explosion") == 0)
{
unsigned int intensity = value[L"intensity"].as_integer();
string explosionType = to_string(value[L"explosionType"]);
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
log("Adding explosion of type " + explosionType + " at (" + to_string(lat) + ", " + to_string(lng) + ")");
Coords loc; loc.lat = lat; loc.lng = lng;
command = dynamic_cast<Command*>(new Explosion(intensity, explosionType, loc));
}
/************************/
else if (key.compare("bombPoint") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(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* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setTargetPosition(loc);
unit->setState(State::BOMB_POINT);
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to bomb a point", true);
}
}
/************************/
else if (key.compare("carpetBomb") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(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* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setTargetPosition(loc);
unit->setState(State::CARPET_BOMB);
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to perform carpet bombing", true);
}
}
/************************/
/* TODO: this command does not appear to be working in DCS and has been disabled */
else if (key.compare("bombBuilding") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(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* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setTargetPosition(loc);
unit->setState(State::BOMB_BUILDING);
}
}
/************************/
else if (key.compare("fireAtArea") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(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* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setTargetPosition(loc);
unit->setState(State::FIRE_AT_AREA);
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to fire at area", true);
}
}
/************************/
else if (key.compare("simulateFireFight") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
double alt = value[L"altitude"].as_double();
Coords loc; loc.lat = lat; loc.lng = lng; loc.alt = alt;
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setTargetPosition(loc);
unit->setState(State::SIMULATE_FIRE_FIGHT);
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to simulate a fire fight", true);
}
}
/************************/
else if (key.compare("scenicAAA") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setState(State::SCENIC_AAA);
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to enter scenic AAA state", true);
}
}
/************************/
else if (key.compare("missOnPurpose") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unit->setState(State::MISS_ON_PURPOSE);
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to enter Miss On Purpose state", true);
}
}
/************************/
else if (key.compare("setOperateAs") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
unsigned char operateAs = value[L"operateAs"].as_number().to_uint32();
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setOperateAs(operateAs);
}
/************************/
else if (key.compare("landAtPoint") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(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* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
list<Coords> newPath;
newPath.push_back(loc);
unit->setActivePath(newPath);
unit->setState(State::LAND_AT_POINT);
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to land at point", true);
}
}
/************************/
else if (key.compare("setShotsScatter") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unsigned char shotsScatter = value[L"shotsScatter"].as_number().to_uint32();
unit->setShotsScatter(shotsScatter);
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") shots scatter to " + to_string(shotsScatter), true);
}
}
/************************/
else if (key.compare("setShotsIntensity") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unsigned char shotsIntensity = value[L"shotsIntensity"].as_number().to_uint32();
unit->setShotsIntensity(shotsIntensity);
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") shots intensity to " + to_string(shotsIntensity), true);
}
}
/************************/
else if (key.compare("setCommandModeOptions") == 0)
{
setCommandModeOptions(value);
log(username + " updated the Command Mode Options", true);
}
/************************/
else if (key.compare("reloadDatabases") == 0) {
unitsManager->loadDatabases();
}
/************************/
else
{
log("Unknown command: " + key);
}
if (command != nullptr)
{
appendCommand(command);
log("New command appended correctly to stack. Current server load: " + to_string(getLoad()));
answer[L"commandHash"] = json::value(to_wstring(command->getHash()));
}
}

View File

@@ -0,0 +1,47 @@
#include "scriptLoader.h"
#include "logger.h"
#include "luatools.h"
#include "dcstools.h"
#include "defines.h"
#include <algorithm>
extern string instancePath;
bool executeLuaScript(lua_State* L, string path)
{
replace(path.begin(), path.end(), '\\', '/');
// Encase the loading call in a procted call to catch any syntax errors
string str = "Olympus.protectedCall(dofile, \"" + path + "\")";
if (dostring_in(L, "server", str.c_str()) != 0)
{
log("Error registering " + path);
return false;
}
else
{
log(path + " registered successfully");
return true;
}
}
/* Executes the "OlympusCommand.lua" file to load in the "Server" Lua space all the Lua functions necessary to perform DCS commands (like moving units) */
void registerLuaFunctions(lua_State* L)
{
string modLocation;
if (dostring_in(L, "server", PROTECTED_CALL))
{
log("Error registering protectedCall");
}
else
{
log("protectedCall registered successfully");
}
executeLuaScript(L, instancePath + MIST_SCRIPT);
executeLuaScript(L, instancePath + OLYMPUS_COMMAND_SCRIPT);
executeLuaScript(L, instancePath + UNIT_PAYLOADS_SCRIPT);
executeLuaScript(L, instancePath + TEMPLATES_SCRIPT);
executeLuaScript(L, instancePath + MODS_SCRIPT);
}

345
backend/core/src/server.cpp Normal file
View File

@@ -0,0 +1,345 @@
#include "server.h"
#include "logger.h"
#include "defines.h"
#include "unitsManager.h"
#include "weaponsManager.h"
#include "scheduler.h"
#include "luatools.h"
#include <exception>
#include <stdexcept>
#include "base64.hpp"
#include <chrono>
using namespace std::chrono;
using namespace base64;
extern UnitsManager* unitsManager;
extern WeaponsManager* weaponsManager;
extern Scheduler* scheduler;
extern json::value missionData;
extern mutex mutexLock;
extern string sessionHash;
extern string instancePath;
void handle_eptr(std::exception_ptr eptr)
{
try {
if (eptr) {
std::rethrow_exception(eptr);
}
}
catch (const std::exception& e) {
log(e.what());
}
}
Server::Server(lua_State* L):
serverThread(nullptr),
runListener(true)
{
}
void Server::start(lua_State* L)
{
log("Starting RESTServer");
serverThread = new thread(&Server::task, this);
}
void Server::stop(lua_State* L)
{
log("Stopping RESTServer");
runListener = false;
if (serverThread != nullptr)
serverThread->join();
}
void Server::handle_options(http_request request)
{
http_response response(status_codes::OK);
response.headers().add(U("Allow"), U("GET, PUT, OPTIONS"));
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, PUT, OPTIONS"));
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type, Authorization"));
request.reply(response);
}
void Server::handle_get(http_request request)
{
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
http_response response(status_codes::OK);
string password = extractPassword(request);
if (password.compare(gameMasterPassword) == 0 || password.compare(blueCommanderPassword) == 0 || password.compare(redCommanderPassword) == 0)
{
std::exception_ptr eptr;
try {
auto answer = json::value::object();
auto path = uri::split_path(uri::decode(request.relative_uri().path()));
/* If present, extract the request reference time. This is used for updates, and it specifies the last time that request has been performed */
map<utility::string_t, utility::string_t> query = request.relative_uri().split_query(request.relative_uri().query());
unsigned long long time = 0;
if (query.find(L"time") != query.end())
{
try {
time = stoull((*(query.find(L"time"))).second);
}
catch (...) {
time = 0;
}
}
if (path.size() > 0)
{
string URI = to_string(path[0]);
/* Units data */
if (URI.compare(UNITS_URI) == 0)
{
unsigned long long updateTime = ms.count();
stringstream ss;
ss.write((char*)&updateTime, sizeof(updateTime));
unitsManager->getUnitData(ss, time);
response.set_body(concurrency::streams::bytestream::open_istream(ss.str()));
}
else if (URI.compare(WEAPONS_URI) == 0)
{
unsigned long long updateTime = ms.count();
stringstream ss;
ss.write((char*)&updateTime, sizeof(updateTime));
weaponsManager->getWeaponData(ss, time);
response.set_body(concurrency::streams::bytestream::open_istream(ss.str()));
}
else {
/* Logs data */
if (URI.compare(LOGS_URI) == 0)
{
auto logs = json::value::object();
getLogsJSON(logs, time);
answer[L"logs"] = logs;
}
/* Airbases data */
else if (URI.compare(AIRBASES_URI) == 0 && missionData.has_object_field(L"airbases"))
answer[L"airbases"] = missionData[L"airbases"];
/* Bullseyes data */
else if (URI.compare(BULLSEYE_URI) == 0 && missionData.has_object_field(L"bullseyes"))
answer[L"bullseyes"] = missionData[L"bullseyes"];
/* Mission data */
else if (URI.compare(MISSION_URI) == 0 && missionData.has_object_field(L"mission")) {
answer[L"mission"] = missionData[L"mission"];
answer[L"mission"][L"commandModeOptions"] = scheduler->getCommandModeOptions();
/* The active mode is determined by the inserted password*/
if (password.compare(gameMasterPassword) == 0)
answer[L"mission"][L"commandModeOptions"][L"commandMode"] = json::value(L"Game master");
else if (password.compare(blueCommanderPassword) == 0)
answer[L"mission"][L"commandModeOptions"][L"commandMode"] = json::value(L"Blue commander");
else if (password.compare(redCommanderPassword) == 0)
answer[L"mission"][L"commandModeOptions"][L"commandMode"] = json::value(L"Red commander");
else
answer[L"mission"][L"commandModeOptions"][L"commandMode"] = json::value(L"Observer");
}
else if (URI.compare(COMMANDS_URI) == 0 && query.find(L"commandHash") != query.end()) {
answer[L"commandExecuted"] = json::value(scheduler->isCommandExecuted(to_string(query[L"commandHash"])));
}
/* Common data */
answer[L"time"] = json::value::string(to_wstring(ms.count()));
answer[L"sessionHash"] = json::value::string(to_wstring(sessionHash));
answer[L"load"] = scheduler->getLoad();
answer[L"frameRate"] = scheduler->getFrameRate();
response.set_body(answer);
}
}
}
catch (...) {
eptr = std::current_exception(); // capture
}
handle_eptr(eptr);
}
else {
response = status_codes::Unauthorized;
}
response.headers().add(U("Allow"), U("GET, PUT, OPTIONS"));
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, PUT, OPTIONS"));
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type, Authorization"));
request.reply(response);
}
void Server::handle_request(http_request request, function<void(json::value const&, json::value&)> action)
{
http_response response(status_codes::OK);
//TODO: limit what a user can do depending on the password
string password = extractPassword(request);
if (password.compare(gameMasterPassword) == 0 || password.compare(blueCommanderPassword) == 0 || password.compare(redCommanderPassword) == 0)
{
auto answer = json::value::object();
request.extract_json().then([&answer, &action](pplx::task<json::value> task)
{
try
{
auto const& jvalue = task.get();
if (!jvalue.is_null())
action(jvalue, answer);
}
catch (http_exception const& e)
{
log(e.what());
}
}).wait();
response.set_body(answer);
}
else {
response = status_codes::Unauthorized;
}
response.headers().add(U("Allow"), U("GET, PUT, OPTIONS"));
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
response.headers().add(U("Access-Control-Allow-Methods"), U("GET, PUT, OPTIONS"));
response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type, Authorization"));
request.reply(response);
}
void Server::handle_put(http_request request)
{
string username = extractUsername(request);
handle_request(
request,
[username](json::value const& jvalue, json::value& answer)
{
/* Lock for thread safety */
lock_guard<mutex> guard(mutexLock);
for (auto const& e : jvalue.as_object())
{
auto key = e.first;
auto value = e.second;
std::exception_ptr eptr;
try {
scheduler->handleRequest(to_string(key), value, username, answer);
}
catch (...) {
eptr = std::current_exception(); // capture
}
handle_eptr(eptr);
}
});
}
string Server::extractUsername(http_request& request) {
if (request.headers().has(L"Authorization")) {
string authorization = to_string(request.headers().find(L"Authorization")->second);
string s = "Basic ";
string::size_type i = authorization.find(s);
if (i != std::string::npos)
authorization.erase(i, s.length());
else
return "";
string decoded = from_base64(authorization);
i = decoded.find(":");
if (i != string::npos && i <= decoded.length())
decoded.erase(i, decoded.length() - i);
else
return "";
return decoded;
}
else
return "";
}
string Server::extractPassword(http_request& request) {
if (request.headers().has(L"Authorization")) {
string authorization = to_string(request.headers().find(L"Authorization")->second);
string s = "Basic ";
string::size_type i = authorization.find(s);
if (i != std::string::npos)
authorization.erase(i, s.length());
else
return "";
string decoded = from_base64(authorization);
i = decoded.find(":");
if (i != string::npos && i+1 < decoded.length())
decoded.erase(0, i+1);
else
return "";
return decoded;
}
else
return "";
}
void Server::task()
{
string address = REST_ADDRESS;
string jsonLocation = instancePath + OLYMPUS_JSON_PATH;
log("Reading configuration from " + jsonLocation);
std::ifstream ifstream(jsonLocation);
std::stringstream ss;
ss << ifstream.rdbuf();
std::error_code errorCode;
json::value config = json::value::parse(ss.str(), errorCode);
if (config.is_object() && config.has_object_field(L"server") &&
config[L"server"].has_string_field(L"address") && config[L"server"].has_number_field(L"port"))
{
address = "http://" + to_string(config[L"server"][L"address"]) + ":" + to_string(config[L"server"][L"port"].as_number().to_int32());
log("Starting server on " + address);
}
else
log("Error reading configuration file. Starting server on " + address);
if (config.is_object() && config.has_object_field(L"authentication"))
{
if (config[L"authentication"].has_string_field(L"gameMasterPassword")) gameMasterPassword = to_string(config[L"authentication"][L"gameMasterPassword"]);
if (config[L"authentication"].has_string_field(L"blueCommanderPassword")) blueCommanderPassword = to_string(config[L"authentication"][L"blueCommanderPassword"]);
if (config[L"authentication"].has_string_field(L"redCommanderPassword")) redCommanderPassword = to_string(config[L"authentication"][L"redCommanderPassword"]);
}
else
log("Error reading configuration file. No password set.");
http_listener listener(to_wstring(address + "/" + REST_URI));
std::function<void(http_request)> handle_options = std::bind(&Server::handle_options, this, std::placeholders::_1);
std::function<void(http_request)> handle_get = std::bind(&Server::handle_get, this, std::placeholders::_1);
std::function<void(http_request)> handle_put = std::bind(&Server::handle_put, this, std::placeholders::_1);
listener.support(methods::OPTIONS, handle_options);
listener.support(methods::GET, handle_get);
listener.support(methods::PUT, handle_put);
try
{
listener.open()
.then([&listener]() {log("RESTServer starting to listen"); })
.wait();
while (runListener) { Sleep(1000); };
listener.close()
.then([&listener]() {log("RESTServer stopping connections"); })
.wait();
log("RESTServer stopped listening");
}
catch (exception const& e)
{
log(e.what());
}
}

810
backend/core/src/unit.cpp Normal file
View File

@@ -0,0 +1,810 @@
#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, unsigned int ID) :
ID(ID)
{
log("Creating unit with ID: " + to_string(ID));
}
Unit::~Unit()
{
}
void Unit::initialize(json::value json)
{
if (json.has_string_field(L"name"))
setName(to_string(json[L"name"]));
if (json.has_string_field(L"unitName"))
setUnitName(to_string(json[L"unitName"]));
if (json.has_string_field(L"groupName"))
setGroupName(to_string(json[L"groupName"]));
if (json.has_number_field(L"coalitionID"))
setCoalition(json[L"coalitionID"].as_number().to_int32());
//if (json.has_number_field(L"Country"))
// setCountry(json[L"Country"].as_number().to_int32());
/* All units which contain the name "Olympus" are automatically under AI control */
if (getUnitName().find("Olympus") != string::npos)
setControlled(true);
update(json, 0);
setDefaults();
}
void Unit::update(json::value json, double dt)
{
if (json.has_object_field(L"position"))
{
setPosition({
json[L"position"][L"lat"].as_number().to_double(),
json[L"position"][L"lng"].as_number().to_double(),
json[L"position"][L"alt"].as_number().to_double()
});
}
if (json.has_number_field(L"heading"))
setHeading(json[L"heading"].as_number().to_double());
if (json.has_number_field(L"track"))
setTrack(json[L"track"].as_number().to_double());
if (json.has_number_field(L"speed"))
setSpeed(json[L"speed"].as_number().to_double());
if (json.has_number_field(L"horizontalVelocity"))
setHorizontalVelocity(json[L"horizontalVelocity"].as_number().to_double());
if (json.has_number_field(L"verticalVelocity"))
setVerticalVelocity(json[L"verticalVelocity"].as_number().to_double());
if (json.has_boolean_field(L"isAlive"))
setAlive(json[L"isAlive"].as_bool());
if (json.has_boolean_field(L"isHuman"))
setHuman(json[L"isHuman"].as_bool());
if (json.has_number_field(L"fuel")) {
setFuel(short(json[L"fuel"].as_number().to_double() * 100));
}
if (json.has_object_field(L"ammo")) {
vector<DataTypes::Ammo> ammo;
for (auto const& el : json[L"ammo"].as_object()) {
DataTypes::Ammo ammoItem;
auto ammoJson = el.second;
if (ammoJson.has_number_field(L"count"))
ammoItem.quantity = ammoJson[L"count"].as_number().to_uint32();
if (ammoJson.has_object_field(L"desc")) {
if (ammoJson[L"desc"].has_string_field(L"displayName")) {
string name = to_string(ammoJson[L"desc"][L"displayName"].as_string());
name = name.substr(0, min(name.size(), sizeof(ammoItem.name) - 1));
strcpy_s(ammoItem.name, sizeof(ammoItem.name), name.c_str());
}
if (ammoJson[L"desc"].has_number_field(L"guidance"))
ammoItem.guidance = ammoJson[L"desc"][L"guidance"].as_number().to_uint32();
if (ammoJson[L"desc"].has_number_field(L"category"))
ammoItem.category = ammoJson[L"desc"][L"category"].as_number().to_uint32();
if (ammoJson[L"desc"].has_number_field(L"missileCategory"))
ammoItem.missileCategory = ammoJson[L"desc"][L"missileCategory"].as_number().to_uint32();
}
ammo.push_back(ammoItem);
}
setAmmo(ammo);
}
if (json.has_object_field(L"contacts")) {
vector<DataTypes::Contact> contacts;
for (auto const& el : json[L"contacts"].as_object()) {
DataTypes::Contact contactItem;
auto contactJson = el.second;
contactItem.ID = contactJson[L"object"][L"id_"].as_number().to_uint32();
string detectionMethod = to_string(contactJson[L"detectionMethod"]);
if (detectionMethod.compare("VISUAL") == 0) contactItem.detectionMethod = 1;
else if (detectionMethod.compare("OPTIC") == 0) contactItem.detectionMethod = 2;
else if (detectionMethod.compare("RADAR") == 0) contactItem.detectionMethod = 4;
else if (detectionMethod.compare("IRST") == 0) contactItem.detectionMethod = 8;
else if (detectionMethod.compare("RWR") == 0) contactItem.detectionMethod = 16;
else if (detectionMethod.compare("DLINK") == 0) contactItem.detectionMethod = 32;
contacts.push_back(contactItem);
}
setContacts(contacts);
}
if (json.has_boolean_field(L"hasTask"))
setHasTask(json[L"hasTask"].as_bool());
if (json.has_number_field(L"health"))
setHealth(static_cast<unsigned char>(json[L"health"].as_number().to_uint32()));
runAILoop();
}
void Unit::setDefaults(bool force)
{
}
void Unit::runAILoop() {
/* Set isLeader */
Unit* leader = nullptr;
setIsLeader(unitsManager->isUnitGroupLeader(this, leader));
/* If the unit is alive, controlled, is the leader of the group and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */
if (getAlive() && getControlled() && !getHuman() && getIsLeader()) {
if (getEnableTaskCheckFailed() && checkTaskFailed()) {
log(unitName + " has no task, switching to IDLE state");
setState(State::IDLE);
}
AIloop();
}
refreshLeaderData(lastLoopTime);
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
lastLoopTime = ms.count();
}
void Unit::refreshLeaderData(unsigned long long time) {
/* When units are in a group, most data comes from the group leader. If new data is available, align it from the leader */
if (!getIsLeader()) {
Unit* leader = unitsManager->getGroupLeader(this);
if (leader != nullptr) {
for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++)
{
if (leader->checkFreshness(datumIndex, time)) {
switch (datumIndex) {
case DataIndex::controlled: updateValue(controlled, leader->controlled, datumIndex); break;
case DataIndex::state: updateValue(state, leader->state, datumIndex); break;
case DataIndex::task: updateValue(task, leader->task, datumIndex); break;
case DataIndex::hasTask: updateValue(hasTask, leader->hasTask, datumIndex); break;
case DataIndex::isActiveTanker: updateValue(isActiveTanker, leader->isActiveTanker, datumIndex); break;
case DataIndex::isActiveAWACS: updateValue(isActiveAWACS, leader->isActiveAWACS, datumIndex); break;
case DataIndex::onOff: updateValue(onOff, leader->onOff, datumIndex); break;
case DataIndex::followRoads: updateValue(followRoads, leader->followRoads, datumIndex); break;
case DataIndex::desiredSpeed: updateValue(desiredSpeed, leader->desiredSpeed, datumIndex); break;
case DataIndex::desiredSpeedType: updateValue(desiredSpeedType, leader->desiredSpeedType, datumIndex); break;
case DataIndex::desiredAltitude: updateValue(desiredAltitude, leader->desiredAltitude, datumIndex); break;
case DataIndex::desiredAltitudeType: updateValue(desiredAltitudeType, leader->desiredAltitudeType, datumIndex); break;
case DataIndex::leaderID: updateValue(leaderID, leader->leaderID, datumIndex); break;
case DataIndex::formationOffset: updateValue(formationOffset, leader->formationOffset, datumIndex); break;
case DataIndex::targetID: updateValue(targetID, leader->targetID, datumIndex); break;
case DataIndex::targetPosition: updateValue(targetPosition, leader->targetPosition, datumIndex); break;
case DataIndex::ROE: updateValue(ROE, leader->ROE, datumIndex); break;
case DataIndex::reactionToThreat: updateValue(reactionToThreat, leader->reactionToThreat, datumIndex); break;
case DataIndex::emissionsCountermeasures: updateValue(emissionsCountermeasures, leader->emissionsCountermeasures, datumIndex); break;
case DataIndex::TACAN: updateValue(TACAN, leader->TACAN, datumIndex); break;
case DataIndex::radio: updateValue(radio, leader->radio, datumIndex); break;
case DataIndex::generalSettings: updateValue(generalSettings, leader->generalSettings, datumIndex); break;
case DataIndex::activePath: updateValue(activePath, leader->activePath, datumIndex); break;
case DataIndex::operateAs: updateValue(operateAs, leader->operateAs, datumIndex); break;
case DataIndex::shotsScatter: updateValue(shotsScatter, leader->shotsScatter, datumIndex); break;
case DataIndex::shotsIntensity: updateValue(shotsIntensity, leader->shotsIntensity, datumIndex); break;
}
}
}
}
}
}
bool Unit::checkFreshness(unsigned char datumIndex, unsigned long long time) {
auto it = updateTimeMap.find(datumIndex);
if (it == updateTimeMap.end())
return false;
else
return it->second > time;
}
bool Unit::hasFreshData(unsigned long long time) {
for (auto it : updateTimeMap)
if (it.second > time)
return true;
return false;
}
void Unit::getData(stringstream& ss, unsigned long long time)
{
/* When an update is requested, make sure data is refreshed */
if (time == 0)
refreshLeaderData(0);
const unsigned char endOfData = DataIndex::endOfData;
ss.write((const char*)&ID, sizeof(ID));
if (!alive && time == 0) {
unsigned char datumIndex = DataIndex::category;
appendString(ss, datumIndex, category);
datumIndex = DataIndex::alive;
appendNumeric(ss, datumIndex, alive);
}
else {
for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++)
{
if (checkFreshness(datumIndex, time)) {
switch (datumIndex) {
case DataIndex::category: appendString(ss, datumIndex, category); break;
case DataIndex::alive: appendNumeric(ss, datumIndex, alive); break;
case DataIndex::human: appendNumeric(ss, datumIndex, human); break;
case DataIndex::controlled: appendNumeric(ss, datumIndex, controlled); break;
case DataIndex::coalition: appendNumeric(ss, datumIndex, coalition); break;
case DataIndex::country: appendNumeric(ss, datumIndex, country); break;
case DataIndex::name: appendString(ss, datumIndex, name); break;
case DataIndex::unitName: appendString(ss, datumIndex, unitName); break;
case DataIndex::groupName: appendString(ss, datumIndex, groupName); break;
case DataIndex::state: appendNumeric(ss, datumIndex, state); break;
case DataIndex::task: appendString(ss, datumIndex, task); break;
case DataIndex::hasTask: appendNumeric(ss, datumIndex, hasTask); break;
case DataIndex::position: appendNumeric(ss, datumIndex, position); break;
case DataIndex::speed: appendNumeric(ss, datumIndex, speed); break;
case DataIndex::horizontalVelocity: appendNumeric(ss, datumIndex, horizontalVelocity); break;
case DataIndex::verticalVelocity: appendNumeric(ss, datumIndex, verticalVelocity); break;
case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break;
case DataIndex::track: appendNumeric(ss, datumIndex, track); break;
case DataIndex::isActiveTanker: appendNumeric(ss, datumIndex, isActiveTanker); break;
case DataIndex::isActiveAWACS: appendNumeric(ss, datumIndex, isActiveAWACS); break;
case DataIndex::onOff: appendNumeric(ss, datumIndex, onOff); break;
case DataIndex::followRoads: appendNumeric(ss, datumIndex, followRoads); break;
case DataIndex::fuel: appendNumeric(ss, datumIndex, fuel); break;
case DataIndex::desiredSpeed: appendNumeric(ss, datumIndex, desiredSpeed); break;
case DataIndex::desiredSpeedType: appendNumeric(ss, datumIndex, desiredSpeedType); break;
case DataIndex::desiredAltitude: appendNumeric(ss, datumIndex, desiredAltitude); break;
case DataIndex::desiredAltitudeType: appendNumeric(ss, datumIndex, desiredAltitudeType); break;
case DataIndex::leaderID: appendNumeric(ss, datumIndex, leaderID); break;
case DataIndex::formationOffset: appendNumeric(ss, datumIndex, formationOffset); break;
case DataIndex::targetID: appendNumeric(ss, datumIndex, targetID); break;
case DataIndex::targetPosition: appendNumeric(ss, datumIndex, targetPosition); break;
case DataIndex::ROE: appendNumeric(ss, datumIndex, ROE); break;
case DataIndex::reactionToThreat: appendNumeric(ss, datumIndex, reactionToThreat); break;
case DataIndex::emissionsCountermeasures: appendNumeric(ss, datumIndex, emissionsCountermeasures); break;
case DataIndex::TACAN: appendNumeric(ss, datumIndex, TACAN); break;
case DataIndex::radio: appendNumeric(ss, datumIndex, radio); break;
case DataIndex::generalSettings: appendNumeric(ss, datumIndex, generalSettings); break;
case DataIndex::ammo: appendVector(ss, datumIndex, ammo); break;
case DataIndex::contacts: appendVector(ss, datumIndex, contacts); break;
case DataIndex::activePath: appendList(ss, datumIndex, activePath); break;
case DataIndex::isLeader: appendNumeric(ss, datumIndex, isLeader); break;
case DataIndex::operateAs: appendNumeric(ss, datumIndex, operateAs); break;
case DataIndex::shotsScatter: appendNumeric(ss, datumIndex, shotsScatter); break;
case DataIndex::shotsIntensity: appendNumeric(ss, datumIndex, shotsIntensity); break;
case DataIndex::health: appendNumeric(ss, datumIndex, health); break;
}
}
}
}
ss.write((const char*)&endOfData, sizeof(endOfData));
}
void Unit::setAmmo(vector<DataTypes::Ammo> newValue)
{
if (ammo.size() == newValue.size()) {
bool equal = true;
for (int i = 0; i < ammo.size(); i++) {
if (ammo.at(i) != newValue.at(i))
{
equal = false;
break;
}
}
if (equal)
return;
}
ammo = newValue;
triggerUpdate(DataIndex::ammo);
}
void Unit::setContacts(vector<DataTypes::Contact> newValue)
{
if (contacts.size() == newValue.size()) {
bool equal = true;
for (int i = 0; i < contacts.size(); i++) {
if (contacts.at(i) != newValue.at(i))
{
equal = false;
break;
}
}
if (equal)
return;
}
contacts = newValue;
triggerUpdate(DataIndex::contacts);
}
void Unit::setActivePath(list<Coords> newPath)
{
activePath = newPath;
resetActiveDestination();
}
void Unit::clearActivePath()
{
list<Coords> newPath;
setActivePath(newPath);
}
void Unit::pushActivePathFront(Coords newActivePathFront)
{
list<Coords> path = activePath;
path.push_front(newActivePathFront);
setActivePath(path);
}
void Unit::pushActivePathBack(Coords newActivePathBack)
{
list<Coords> path = activePath;
path.push_back(newActivePathBack);
setActivePath(path);
}
void Unit::popActivePathFront()
{
list<Coords> path = activePath;
path.pop_front();
setActivePath(path);
}
string Unit::getTargetName()
{
if (isTargetAlive())
{
Unit* target = unitsManager->getUnit(targetID);
if (target != nullptr)
return target->getUnitName();
}
return "";
}
bool Unit::isTargetAlive()
{
if (targetID == NULL)
return false;
Unit* target = unitsManager->getUnit(targetID);
if (target != nullptr)
return target->alive;
else
return false;
}
string Unit::getLeaderName()
{
if (isLeaderAlive())
{
Unit* leader = unitsManager->getUnit(leaderID);
if (leader != nullptr)
return leader->getUnitName();
}
return "";
}
bool Unit::isLeaderAlive()
{
if (leaderID == NULL)
return false;
Unit* leader = unitsManager->getUnit(leaderID);
if (leader != nullptr)
return leader->alive;
else
return false;
}
void Unit::resetActiveDestination()
{
activeDestination = Coords(NULL);
}
void Unit::resetTask()
{
Command* command = dynamic_cast<Command*>(new ResetTask(groupName, [this]() { this->setHasTaskAssigned(false); }));
scheduler->appendCommand(command);
setHasTask(false);
resetTaskFailedCounter();
}
void Unit::setFormationOffset(Offset newFormationOffset)
{
formationOffset = newFormationOffset;
/* Apply the change */
setHasTask(false);
resetTaskFailedCounter();
AIloop();
triggerUpdate(DataIndex::formationOffset);
}
void Unit::setROE(unsigned char newROE, bool force)
{
if (ROE != newROE || force) {
ROE = newROE;
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ROE, static_cast<unsigned int>(ROE)));
scheduler->appendCommand(command);
triggerUpdate(DataIndex::ROE);
}
}
void Unit::setReactionToThreat(unsigned char newReactionToThreat, bool force)
{
if (reactionToThreat != newReactionToThreat || force) {
reactionToThreat = newReactionToThreat;
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::REACTION_ON_THREAT, static_cast<unsigned int>(reactionToThreat)));
scheduler->appendCommand(command);
triggerUpdate(DataIndex::reactionToThreat);
}
}
void Unit::setEmissionsCountermeasures(unsigned char newEmissionsCountermeasures, bool force)
{
if (emissionsCountermeasures != newEmissionsCountermeasures || force) {
emissionsCountermeasures = newEmissionsCountermeasures;
unsigned int radarEnum;
unsigned int flareEnum;
unsigned int ECMEnum;
if (emissionsCountermeasures == EmissionCountermeasure::SILENT)
{
radarEnum = RadarUse::NEVER;
flareEnum = FlareUse::NEVER;
ECMEnum = ECMUse::NEVER_USE;
}
else if (emissionsCountermeasures == EmissionCountermeasure::ATTACK)
{
radarEnum = RadarUse::FOR_ATTACK_ONLY;
flareEnum = FlareUse::AGAINST_FIRED_MISSILE;
ECMEnum = ECMUse::USE_IF_ONLY_LOCK_BY_RADAR;
}
else if (emissionsCountermeasures == EmissionCountermeasure::DEFEND)
{
radarEnum = RadarUse::FOR_SEARCH_IF_REQUIRED;
flareEnum = FlareUse::WHEN_FLYING_IN_SAM_WEZ;
ECMEnum = ECMUse::USE_IF_DETECTED_LOCK_BY_RADAR;
}
else if (emissionsCountermeasures == EmissionCountermeasure::FREE)
{
radarEnum = RadarUse::FOR_CONTINUOUS_SEARCH;
flareEnum = FlareUse::WHEN_FLYING_NEAR_ENEMIES;
ECMEnum = ECMUse::ALWAYS_USE;
}
else
return;
Command* command;
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::RADAR_USING, radarEnum));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::FLARE_USING, flareEnum));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ECM_USING, ECMEnum));
scheduler->appendCommand(command);
triggerUpdate(DataIndex::emissionsCountermeasures);
}
}
void Unit::landAt(Coords loc)
{
clearActivePath();
pushActivePathBack(loc);
setState(State::LAND);
}
void Unit::setIsActiveTanker(bool newIsActiveTanker)
{
if (isActiveTanker != newIsActiveTanker) {
isActiveTanker = newIsActiveTanker;
/* Apply the change */
setHasTask(false);
resetTaskFailedCounter();
AIloop();
triggerUpdate(DataIndex::isActiveTanker);
}
}
void Unit::setIsActiveAWACS(bool newIsActiveAWACS)
{
if (isActiveAWACS != newIsActiveAWACS) {
isActiveAWACS = newIsActiveAWACS;
/* Apply the change */
setHasTask(false);
resetTaskFailedCounter();
AIloop();
triggerUpdate(DataIndex::isActiveAWACS);
}
}
void Unit::setTACAN(DataTypes::TACAN newTACAN, bool force)
{
if (TACAN != newTACAN || force)
{
TACAN = newTACAN;
if (TACAN.isOn) {
std::ostringstream commandSS;
if (TACAN.channel < 0)
TACAN.channel = 0;
if (TACAN.channel > 126)
TACAN.channel = 126;
commandSS << "{"
<< "id = 'ActivateBeacon',"
<< "params = {"
<< "type = " << ((TACAN.XY == 'X' == 0) ? 4 : 5) << ","
<< "system = 3,"
<< "name = \"Olympus_TACAN\","
<< "callsign = \"" << TACAN.callsign << "\", "
<< "frequency = " << TACANChannelToFrequency(TACAN.channel, TACAN.XY) << ","
<< "}"
<< "}";
Command* command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
}
else {
std::ostringstream commandSS;
commandSS << "{"
<< "id = 'DeactivateBeacon',"
<< "params = {"
<< "}"
<< "}";
Command* command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
}
triggerUpdate(DataIndex::TACAN);
}
}
void Unit::setRadio(DataTypes::Radio newRadio, bool force)
{
if (radio != newRadio || force)
{
radio = newRadio;
std::ostringstream commandSS;
Command* command;
if (radio.frequency < 0)
radio.frequency = 0;
if (radio.frequency > 999000000)
radio.frequency = 999000000;
commandSS << "{"
<< "id = 'SetFrequency',"
<< "params = {"
<< "modulation = 0," // TODO Allow selection
<< "frequency = " << radio.frequency << ","
<< "}"
<< "}";
command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
// Clear the stringstream
commandSS.str(string(""));
commandSS << "{"
<< "id = 'SetCallsign',"
<< "params = {"
<< "callname = " << to_string(radio.callsign) << ","
<< "number = " << to_string(radio.callsignNumber) << ","
<< "}"
<< "}";
command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
triggerUpdate(DataIndex::radio);
}
}
void Unit::setGeneralSettings(DataTypes::GeneralSettings newGeneralSettings, bool force)
{
if (generalSettings != newGeneralSettings)
{
generalSettings = newGeneralSettings;
Command* command;
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::PROHIBIT_AA, generalSettings.prohibitAA));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::PROHIBIT_AG, generalSettings.prohibitAG));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::PROHIBIT_JETT, generalSettings.prohibitJettison));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::PROHIBIT_AB, generalSettings.prohibitAfterburner));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ENGAGE_AIR_WEAPONS, !generalSettings.prohibitAirWpn));
scheduler->appendCommand(command);
triggerUpdate(DataIndex::generalSettings);
}
}
void Unit::setDesiredSpeed(double newDesiredSpeed)
{
if (desiredSpeed != newDesiredSpeed) {
desiredSpeed = newDesiredSpeed;
/* Apply the change */
setHasTask(false);
resetTaskFailedCounter();
AIloop();
triggerUpdate(DataIndex::desiredSpeed);
}
}
void Unit::setDesiredAltitude(double newDesiredAltitude)
{
if (desiredAltitude != newDesiredAltitude) {
desiredAltitude = newDesiredAltitude;
/* Apply the change */
setHasTask(false);
resetTaskFailedCounter();
AIloop();
triggerUpdate(DataIndex::desiredAltitude);
}
}
void Unit::setDesiredSpeedType(string newDesiredSpeedType)
{
if (desiredSpeedType != (newDesiredSpeedType.compare("GS") == 0)) {
desiredSpeedType = newDesiredSpeedType.compare("GS") == 0;
/* Apply the change */
setHasTask(false);
resetTaskFailedCounter();
AIloop();
triggerUpdate(DataIndex::desiredSpeedType);
}
}
void Unit::setDesiredAltitudeType(string newDesiredAltitudeType)
{
if (desiredAltitudeType != (newDesiredAltitudeType.compare("AGL") == 0)) {
desiredAltitudeType = newDesiredAltitudeType.compare("AGL") == 0;
/* Apply the change */
setHasTask(false);
resetTaskFailedCounter();
AIloop();
triggerUpdate(DataIndex::desiredAltitudeType);
}
}
void Unit::goToDestination(string enrouteTask)
{
if (activeDestination != NULL)
{
Command* command = dynamic_cast<Command*>(new Move(groupName, activeDestination, getDesiredSpeed(), getDesiredSpeedType() ? "GS" : "CAS", getDesiredAltitude(), getDesiredAltitudeType() ? "AGL" : "ASL", enrouteTask, getCategory(), getFollowRoads(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
}
bool Unit::isDestinationReached(double threshold)
{
if (activeDestination != NULL)
{
/* Check if any unit in the group has reached the point */
for (auto const& p : unitsManager->getGroupMembers(groupName))
{
double dist = 0;
Geodesic::WGS84().Inverse(p->getPosition().lat, p->getPosition().lng, activeDestination.lat, activeDestination.lng, dist);
if (dist < threshold)
{
log(unitName + " destination reached");
return true;
}
else {
return false;
}
}
return false;
}
else
return true;
}
bool Unit::setActiveDestination()
{
if (activePath.size() > 0)
{
activeDestination = activePath.front();
log(unitName + " active destination set to queue front");
triggerUpdate(DataIndex::activePath);
return true;
}
else
{
activeDestination = Coords(0);
log(unitName + " active destination set to NULL");
triggerUpdate(DataIndex::activePath);
return false;
}
}
bool Unit::updateActivePath(bool looping)
{
if (activePath.size() > 0)
{
/* Push the next destination in the queue to the front */
if (looping)
pushActivePathBack(activePath.front());
popActivePathFront();
log(unitName + " active path front popped");
return true;
}
else {
return false;
}
}
void Unit::setHasTask(bool newValue) {
updateValue(hasTask, newValue, DataIndex::hasTask);
}
bool Unit::checkTaskFailed()
{
if (getHasTask())
return false;
else {
if (taskCheckCounter > 0)
taskCheckCounter -= hasTaskAssigned;
return taskCheckCounter == 0;
}
}
void Unit::resetTaskFailedCounter() {
taskCheckCounter = TASK_CHECK_INIT_VALUE;
}
void Unit::setHasTaskAssigned(bool newHasTaskAssigned) {
hasTaskAssigned = newHasTaskAssigned;
if (hasTaskAssigned)
log(unitName + " was assigned a new task");
else
log(unitName + " no task assigned");
}
void Unit::triggerUpdate(unsigned char datumIndex) {
updateTimeMap[datumIndex] = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
}

View File

@@ -0,0 +1,241 @@
#include "framework.h"
#include "unitsManager.h"
#include "logger.h"
#include "unit.h"
#include "aircraft.h"
#include "helicopter.h"
#include "groundunit.h"
#include "navyunit.h"
#include "weapon.h"
#include "commands.h"
#include "scheduler.h"
#include "defines.h"
#include <GeographicLib/Geodesic.hpp>
using namespace GeographicLib;
#include "base64.hpp"
using namespace base64;
extern Scheduler* scheduler;
UnitsManager::UnitsManager(lua_State* L)
{
LogInfo(L, "Units Manager constructor called successfully");
}
UnitsManager::~UnitsManager()
{
}
Unit* UnitsManager::getUnit(unsigned int ID)
{
if (units.find(ID) == units.end()) {
return nullptr;
}
else {
return units[ID];
}
}
bool UnitsManager::isUnitInGroup(Unit* unit)
{
if (unit != nullptr) {
string groupName = unit->getGroupName();
if (groupName.length() == 0) return false;
for (auto const& p : units)
{
if (p.second->getGroupName().compare(groupName) == 0 && p.second != unit && p.second->getAlive())
return true;
}
}
return false;
}
/* Returns true if unit is group leader. Else, returns false, and leader will be equal to the group leader */
bool UnitsManager::isUnitGroupLeader(Unit* unit, Unit*& leader)
{
if (unit != nullptr) {
leader = getGroupLeader(unit);
return leader == nullptr? false: unit == leader;
}
else
return false;
}
Unit* UnitsManager::getGroupLeader(Unit* unit)
{
if (unit != nullptr) {
string groupName = unit->getGroupName();
if (groupName.length() == 0) return nullptr;
/* Find the first alive unit that has the same groupName */
for (auto const& p : units)
{
if (p.second->getAlive() && p.second->getGroupName().compare(groupName) == 0)
return p.second;
}
}
return nullptr;
}
vector<Unit*> UnitsManager::getGroupMembers(string groupName)
{
vector<Unit*> members;
for (auto const& p : units)
{
if (p.second->getGroupName().compare(groupName) == 0)
members.push_back(p.second);
}
return members;
}
Unit* UnitsManager::getGroupLeader(unsigned int ID)
{
Unit* unit = getUnit(ID);
return getGroupLeader(unit);
}
void UnitsManager::update(json::value& json, double dt)
{
for (auto const& p : json.as_object())
{
unsigned int ID = std::stoi(p.first);
if (units.count(ID) == 0)
{
json::value value = p.second;
if (value.has_string_field(L"category")) {
string category = to_string(value[L"category"].as_string());
if (category.compare("Aircraft") == 0)
units[ID] = dynamic_cast<Unit*>(new Aircraft(p.second, ID));
else if (category.compare("Helicopter") == 0)
units[ID] = dynamic_cast<Unit*>(new Helicopter(p.second, ID));
else if (category.compare("GroundUnit") == 0)
units[ID] = dynamic_cast<Unit*>(new GroundUnit(p.second, ID));
else if (category.compare("NavyUnit") == 0)
units[ID] = dynamic_cast<Unit*>(new NavyUnit(p.second, ID));
/* Initialize the unit if creation was successfull */
if (units.count(ID) != 0) {
units[ID]->update(p.second, dt);
units[ID]->initialize(p.second);
}
}
}
else {
/* Update the unit if present*/
if (units.count(ID) != 0)
units[ID]->update(p.second, dt);
}
}
}
void UnitsManager::runAILoop() {
/* Run the AI Loop on all units */
for (auto const& unit : units)
unit.second->runAILoop();
}
void UnitsManager::getUnitData(stringstream &ss, unsigned long long time)
{
for (auto const& p : units)
p.second->getData(ss, time);
}
void UnitsManager::deleteUnit(unsigned int ID, bool explosion, string explosionType, bool immediate)
{
if (getUnit(ID) != nullptr)
{
Command* command = dynamic_cast<Command*>(new Delete(ID, explosion, explosionType, immediate));
scheduler->appendCommand(command);
}
}
Unit* UnitsManager::getClosestUnit(Unit* unit, unsigned char coalition, vector<string> categories, double &distance) {
Unit* closestUnit = nullptr;
distance = 0;
for (auto const& p : units) {
/* Check if the units category is of the correct type */
bool requestedCategory = false;
for (auto const& category : categories) {
if (p.second->getCategory().compare(category) == 0) {
requestedCategory = true;
break;
}
}
/* Check if the unit belongs to the desired coalition, is alive, and is of the category requested */
if (requestedCategory && p.second->getCoalition() == coalition && p.second->getAlive()) {
/* Compute the distance from the unit to the tested unit */
double dist;
double bearing1;
double bearing2;
Geodesic::WGS84().Inverse(unit->getPosition().lat, unit->getPosition().lng, p.second->getPosition().lat, p.second->getPosition().lng, dist, bearing1, bearing2);
double altDelta = unit->getPosition().alt - p.second->getPosition().alt;
/* If the closest unit has not been assigned yet, assign it to this unit */
if (closestUnit == nullptr)
{
closestUnit = p.second;
distance = sqrt(dist * dist + altDelta * altDelta);
}
else {
/* Check if the unit is closer than the one already selected */
if (dist < distance) {
closestUnit = p.second;
distance = sqrt(dist * dist + altDelta * altDelta);
}
}
}
}
return closestUnit;
}
map<Unit*, double> UnitsManager::getUnitsInRange(Unit* unit, unsigned char coalition, vector<string> categories, double range) {
map<Unit*, double> unitsInRange;
for (auto const& p : units) {
/* Check if the units category is of the correct type */
bool requestedCategory = false;
for (auto const& category : categories) {
if (p.second->getCategory().compare(category) == 0) {
requestedCategory = true;
break;
}
}
/* Check if the unit belongs to the desired coalition, is alive, and is of the category requested */
if (requestedCategory && p.second->getCoalition() == coalition && p.second->getAlive()) {
/* Compute the distance from the unit to the tested unit */
double dist;
double bearing1;
double bearing2;
Geodesic::WGS84().Inverse(unit->getPosition().lat, unit->getPosition().lng, p.second->getPosition().lat, p.second->getPosition().lng, dist, bearing1, bearing2);
if (dist <= range)
unitsInRange[p.second] = dist;
}
}
return unitsInRange;
}
void UnitsManager::acquireControl(unsigned int ID) {
Unit* leader = getGroupLeader(ID);
if (leader != nullptr) {
if (!leader->getControlled()) {
leader->setControlled(true);
leader->setDefaults(true);
}
}
}
void UnitsManager::loadDatabases() {
Aircraft::loadDatabase(AIRCRAFT_DATABASE_PATH);
Helicopter::loadDatabase(HELICOPTER_DATABASE_PATH);
GroundUnit::loadDatabase(GROUNDUNIT_DATABASE_PATH);
NavyUnit::loadDatabase(NAVYUNIT_DATABASE_PATH);
}

116
backend/core/src/weapon.cpp Normal file
View File

@@ -0,0 +1,116 @@
#include "weapon.h"
#include "utils.h"
#include "logger.h"
#include "commands.h"
#include "scheduler.h"
#include "defines.h"
#include <chrono>
using namespace std::chrono;
Weapon::Weapon(json::value json, unsigned int ID) :
ID(ID)
{
log("Creating weapon with ID: " + to_string(ID));
}
Weapon::~Weapon()
{
}
void Weapon::initialize(json::value json)
{
if (json.has_string_field(L"name"))
setName(to_string(json[L"name"]));
if (json.has_number_field(L"coalitionID"))
setCoalition(json[L"coalitionID"].as_number().to_int32());
update(json, 0);
}
void Weapon::update(json::value json, double dt)
{
if (json.has_object_field(L"position"))
{
setPosition({
json[L"position"][L"lat"].as_number().to_double(),
json[L"position"][L"lng"].as_number().to_double(),
json[L"position"][L"alt"].as_number().to_double()
});
}
if (json.has_number_field(L"heading"))
setHeading(json[L"heading"].as_number().to_double());
if (json.has_number_field(L"speed"))
setSpeed(json[L"speed"].as_number().to_double());
if (json.has_boolean_field(L"isAlive"))
setAlive(json[L"isAlive"].as_bool());
}
bool Weapon::checkFreshness(unsigned char datumIndex, unsigned long long time) {
auto it = updateTimeMap.find(datumIndex);
if (it == updateTimeMap.end())
return false;
else
return it->second > time;
}
bool Weapon::hasFreshData(unsigned long long time) {
for (auto it : updateTimeMap)
if (it.second > time)
return true;
return false;
}
void Weapon::getData(stringstream& ss, unsigned long long time)
{
const unsigned char endOfData = DataIndex::endOfData;
ss.write((const char*)&ID, sizeof(ID));
if (!alive && time == 0) {
unsigned char datumIndex = DataIndex::category;
appendString(ss, datumIndex, category);
datumIndex = DataIndex::alive;
appendNumeric(ss, datumIndex, alive);
}
else {
for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++)
{
if (checkFreshness(datumIndex, time)) {
switch (datumIndex) {
case DataIndex::category: appendString(ss, datumIndex, category); break;
case DataIndex::alive: appendNumeric(ss, datumIndex, alive); break;
case DataIndex::coalition: appendNumeric(ss, datumIndex, coalition); break;
case DataIndex::name: appendString(ss, datumIndex, name); break;
case DataIndex::position: appendNumeric(ss, datumIndex, position); break;
case DataIndex::speed: appendNumeric(ss, datumIndex, speed); break;
case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break;
}
}
}
}
ss.write((const char*)&endOfData, sizeof(endOfData));
}
void Weapon::triggerUpdate(unsigned char datumIndex) {
updateTimeMap[datumIndex] = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
}
/* Missile */
Missile::Missile(json::value json, unsigned int ID) : Weapon(json, ID)
{
log("New Missile created with ID: " + to_string(ID));
setCategory("Missile");
};
/* Bomb */
Bomb::Bomb(json::value json, unsigned int ID) : Weapon(json, ID)
{
log("New Bomb created with ID: " + to_string(ID));
setCategory("Bomb");
};

View File

@@ -0,0 +1,65 @@
#include "framework.h"
#include "weaponsManager.h"
#include "logger.h"
#include "weapon.h"
#include "scheduler.h"
#include "base64.hpp"
using namespace base64;
WeaponsManager::WeaponsManager(lua_State* L)
{
LogInfo(L, "Weapons Manager constructor called successfully");
}
WeaponsManager::~WeaponsManager()
{
}
Weapon* WeaponsManager::getWeapon(unsigned int ID)
{
if (weapons.find(ID) == weapons.end()) {
return nullptr;
}
else {
return weapons[ID];
}
}
void WeaponsManager::update(json::value& json, double dt)
{
for (auto const& p : json.as_object())
{
unsigned int ID = std::stoi(p.first);
if (weapons.count(ID) == 0)
{
json::value value = p.second;
if (value.has_string_field(L"category")) {
string category = to_string(value[L"category"].as_string());
if (category.compare("Missile") == 0)
weapons[ID] = dynamic_cast<Weapon*>(new Missile(p.second, ID));
else if (category.compare("Bomb") == 0)
weapons[ID] = dynamic_cast<Weapon*>(new Bomb(p.second, ID));
/* Initialize the weapon if creation was successfull */
if (weapons.count(ID) != 0) {
weapons[ID]->update(p.second, dt);
weapons[ID]->initialize(p.second);
}
}
}
else {
/* Update the weapon if present*/
if (weapons.count(ID) != 0)
weapons[ID]->update(p.second, dt);
}
}
}
void WeaponsManager::getWeaponData(stringstream& ss, unsigned long long time)
{
for (auto const& p : weapons)
p.second->getData(ss, time);
}

View File

@@ -0,0 +1,110 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Italian (Italy) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Italian (Italy) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// English (United Kingdom) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,0
PRODUCTVERSION 1,0,3,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "DCS Olympus"
VALUE "FileDescription", "DCS Olympus"
VALUE "FileVersion", "1.0.3.0"
VALUE "InternalName", "dcstools.dll"
VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "dcstools.dll"
VALUE "ProductName", "DCS Olympus"
VALUE "ProductVersion", "1.0.3.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United Kingdom) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<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\dcstools.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\dcstools.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\luatools\luatools.vcxproj">
<Project>{de139ec1-4f88-47d5-be73-f41915fe14a3}</Project>
</ProjectReference>
<ProjectReference Include="..\utils\utils.vcxproj">
<Project>{b85009ce-4a5c-4a5a-b85d-001b3a2651b2}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="dcstools.rc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{2b255368-39a0-431a-a6de-cc739ac70dc1}</ProjectGuid>
<RootNamespace>dcs</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<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|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\DCSOlympus.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\DCSOlympus.props" />
</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" />
<Import Project="..\DCSOlympus.props" />
</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" />
<Import Project="..\DCSOlympus.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>.\..\..\bin\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;DCS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;DCS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;DCS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<Version>{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}</Version>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;DCSTOOLS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>include;..\..\third-party\lua\include;..\shared\include;..\utils\include;..\luatools\include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>lua.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,35 @@
<?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>{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="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\dcstools.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\dcstools.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="dcstools.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,12 @@
#pragma once
#include "framework.h"
#include "luatools.h"
void DllExport LogInfo(lua_State* L, string message);
void DllExport LogWarning(lua_State* L, string message);
void DllExport LogError(lua_State* L, string message);
void DllExport Log(lua_State* L, string message, unsigned int level);
int DllExport dostring_in(lua_State* L, string target, string command);
void DllExport getAllUnits(lua_State* L, map<unsigned int, json::value>& unitJSONs);
unsigned int DllExport TACANChannelToFrequency(unsigned int channel, char XY);

View File

@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by dcstools.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,111 @@
#include "dcstools.h"
void LogInfo(lua_State* L, string message)
{
STACK_INIT;
lua_getglobal(L, "log");
lua_getfield(L, -1, "INFO");
int infoLevel = (int)lua_tointeger(L, -1);
STACK_POP(1);
STACK_CLEAN;
Log(L, message, infoLevel);
}
void LogWarning(lua_State* L, string message)
{
STACK_INIT;
lua_getglobal(L, "log");
lua_getfield(L, -1, "WARNING");
int warningLevel = (int)lua_tointeger(L, -1);
STACK_POP(1);
STACK_CLEAN;
Log(L, message, warningLevel);
}
void LogError(lua_State* L, string message)
{
STACK_INIT;
lua_getglobal(L, "log");
lua_getfield(L, -1, "ERROR");
int errorLevel = (int)lua_tointeger(L, -1);
STACK_POP(1);
STACK_CLEAN;
Log(L, message, errorLevel);
}
void Log(lua_State* L, string message, unsigned int level)
{
STACK_INIT;
lua_getglobal(L, "log");
lua_getfield(L, -1, "write");
lua_pushstring(L, "Olympus.dll");
lua_pushnumber(L, level);
lua_pushstring(L, message.c_str());
lua_pcall(L, 3, 0, 0);
STACK_CLEAN;
}
void getAllUnits(lua_State* L, map<unsigned int, json::value>& unitJSONs)
{
unsigned int res = 0;
STACK_INIT;
lua_getglobal(L, "Export");
lua_getfield(L, -1, "LoGetWorldObjects");
res = lua_pcall(L, 0, 1, 0);
if (res != 0)
{
LogError(L, "Error retrieving World Objects");
goto exit;
}
if (!lua_istable(L, 2))
{
LogError(L, "Error retrieving World Objects");
goto exit;
}
else
{
lua_pushnil(L);
while (lua_next(L, 2) != 0)
{
unsigned int ID = static_cast<unsigned int>(lua_tonumber(L, -2));
if (unitJSONs.find(ID) == unitJSONs.end())
unitJSONs[ID] = json::value::object();
luaTableToJSON(L, -1, unitJSONs[ID]);
STACK_POP(1)
}
}
exit:
STACK_CLEAN;
return;
}
int dostring_in(lua_State* L, string target, string command)
{
lua_getglobal(L, "net");
lua_getfield(L, -1, "dostring_in");
lua_pushstring(L, target.c_str());
lua_pushstring(L, command.c_str());
return lua_pcall(L, 2, 0, 0);
}
unsigned int TACANChannelToFrequency(unsigned int channel, char XY)
{
unsigned int basef = (XY == 'X' && channel > 63) || (XY == 'Y' && channel < 64) ? 1087 : 961;
return (basef + channel) * 1000000;
}

2579
backend/docs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
#pragma once
#include "framework.h"
void DllExport setLogDirectory(std::string m_dirPath);
void DllExport log(const std::string& sMessage, bool addToJSON = false);
void DllExport log(const std::wstring& sMessage, bool addToJSON = false);
void DllExport getLogsJSON(json::value& json, unsigned long long time);

View File

@@ -0,0 +1,32 @@
#pragma once
#include "framework.h"
#include "interface.h"
class Logger
{
public:
void log(const string& sMessage, bool addToJSON);
void log(const wstring& sMessage, bool addToJSON);
void toJSON(json::value& json, unsigned long long time);
void setDirectory(string newDirPath);
static Logger* GetLogger();
private:
Logger();
Logger(const Logger&) {}; // copy constructor is private
Logger& operator=(const Logger&) { return *this; }; // assignment operator is private
static const string m_sFileName;
static Logger* m_pThis;
static ofstream m_Logfile;
static std::map<unsigned long long, std::string> m_logs;
static string m_dirPath;
mutex mutexLock;
void Open();
void Close();
};

110
backend/logger/logger.rc Normal file
View File

@@ -0,0 +1,110 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Italian (Italy) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Italian (Italy) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// English (United Kingdom) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,0
PRODUCTVERSION 1,0,3,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "DCS Olympus"
VALUE "FileDescription", "DCS Olympus"
VALUE "FileVersion", "1.0.3.0"
VALUE "InternalName", "logger.dll"
VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "logger.dll"
VALUE "ProductName", "DCS Olympus"
VALUE "ProductVersion", "1.0.3.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United Kingdom) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<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\interface.cpp" />
<ClCompile Include="src\logger.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\interface.h" />
<ClInclude Include="include\logger.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\utils\utils.vcxproj">
<Project>{b85009ce-4a5c-4a5a-b85d-001b3a2651b2}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="logger.rc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{873ecabe-fcfe-4217-ac15-91959c3cf1c6}</ProjectGuid>
<RootNamespace>logger</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<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|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\DCSOlympus.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\DCSOlympus.props" />
</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" />
<Import Project="..\DCSOlympus.props" />
</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" />
<Import Project="..\DCSOlympus.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>.\..\..\bin\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;LOGGER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;LOGGER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;LOGGER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<Version>{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}</Version>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;LOGGER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>include;..\..\third-party\lua\include;..\shared\include;..\utils\include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,41 @@
<?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>{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="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\logger.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\interface.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\logger.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\interface.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="logger.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

14
backend/logger/resource.h Normal file
View File

@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by logger.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,25 @@
#include "framework.h"
#include "logger.h"
#include "interface.h"
#define LOGGER Logger::GetLogger()
void setLogDirectory(string m_dirPath)
{
LOGGER->setDirectory(m_dirPath);
}
void log(const string& message, bool addToJSON)
{
LOGGER->log(message, addToJSON);
}
void log(const wstring& message, bool addToJSON)
{
LOGGER->log(message, addToJSON);
}
void getLogsJSON(json::value& json, unsigned long long time)
{
LOGGER->toJSON(json, time);
}

View File

@@ -0,0 +1,82 @@
#include "logger.h"
#include "utils.h"
#include "defines.h"
#include <chrono>
using namespace std::chrono;
const string Logger::m_sFileName = LOG_NAME;
Logger* Logger::m_pThis = NULL;
ofstream Logger::m_Logfile;
std::map<unsigned long long, std::string> Logger::m_logs;
std::string Logger::m_dirPath;
Logger::Logger()
{
}
Logger* Logger::GetLogger()
{
if (m_pThis == NULL) {
m_pThis = new Logger();
}
return m_pThis;
}
void Logger::setDirectory(string newDirPath)
{
m_dirPath = newDirPath;
}
void Logger::Open()
{
try {
m_Logfile.open((m_dirPath + m_sFileName).c_str(), ios::out | ios::app);
}
catch (...) {
std::filesystem::path m_dirPath = std::filesystem::temp_directory_path();
m_Logfile.open((m_dirPath.string() + m_sFileName).c_str(), ios::out | ios::app);
}
}
void Logger::Close()
{
m_Logfile.close();
}
void Logger::toJSON(json::value& json, unsigned long long time)
{
lock_guard<mutex> guard(mutexLock);
/* Loop on the logs in reverse since we are usually only interested in the very last added logs */
auto itr = m_logs.end();
while (itr != m_logs.begin())
{
--itr;
if (itr->first < time) return;
json[to_wstring(itr->first)] = json::value::string(to_wstring(itr->second));
}
}
void Logger::log(const string& message, bool addToJSON)
{
lock_guard<mutex> guard(mutexLock);
Open();
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
m_Logfile << CurrentDateTime() << ":\t";
m_Logfile << message << "\n";
if (addToJSON)
m_logs[static_cast<unsigned long long>(ms.count())] = message;
Close();
}
void Logger::log(const wstring& message, bool addToJSON)
{
lock_guard<mutex> guard(mutexLock);
Open();
milliseconds ms = duration_cast<milliseconds>(system_clock::now().time_since_epoch());
m_Logfile << CurrentDateTime() << ":\t";
m_Logfile << to_string(message) << "\n";
if (addToJSON)
m_logs[static_cast<unsigned long long>(ms.count())] = to_string(message);
Close();
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "framework.h"
void DllExport stackUpdate(lua_State* L, int& stackDepth, int initialStack = 0);
void DllExport stackPop(lua_State* L, int popDepth = 1);
void DllExport stackClean(lua_State* L, int stackDepth);
void DllExport luaTableToJSON(lua_State* L, int index, json::value& json, bool logKeys = false);
void DllExport luaLogTableKeys(lua_State* L, int index);
#define STACK_UPDATE stackUpdate(L, stackDepth, initialStack);
#define STACK_INIT int stackDepth = 0; int initialStack = 0; stackUpdate(L, initialStack);
#define STACK_POP(X) stackPop(L, X); STACK_UPDATE;
#define STACK_CLEAN STACK_UPDATE; stackClean(L, stackDepth);

View File

@@ -0,0 +1,110 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Italian (Italy) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Italian (Italy) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// English (United Kingdom) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,0
PRODUCTVERSION 1,0,3,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "DCS Olympus"
VALUE "FileDescription", "DCS Olympus"
VALUE "FileVersion", "1.0.3.0"
VALUE "InternalName", "luatools.dll"
VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "luatools.dll"
VALUE "ProductName", "DCS Olympus"
VALUE "ProductVersion", "1.0.3.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United Kingdom) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,176 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{de139ec1-4f88-47d5-be73-f41915fe14a3}</ProjectGuid>
<RootNamespace>lua</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>luatools</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<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|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\DCSOlympus.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\DCSOlympus.props" />
</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" />
<Import Project="..\DCSOlympus.props" />
</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" />
<Import Project="..\DCSOlympus.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>.\..\..\bin\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;LUA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;LUA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;LUA_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<Version>{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}</Version>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;LUATOOLS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>include; ..\..\third-party\lua\include; ..\utils\include; ..\shared\include; ..\logger\include;</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>lua.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<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>
<ItemGroup>
<ClCompile Include="src\luatools.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\luatools.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="luatools.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,35 @@
<?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>{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="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\luatools.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\luatools.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="luatools.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by luatools.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,85 @@
#include "framework.h"
#include "luaTools.h"
#include "logger.h"
#include "utils.h"
void stackUpdate(lua_State* L, int& stackDepth, int initialStack)
{
stackDepth = lua_gettop(L) - initialStack;
}
void stackPop(lua_State* L, int popDepth)
{
lua_pop(L, popDepth);
}
void stackClean(lua_State* L, int stackDepth)
{
lua_pop(L, stackDepth);
}
void luaLogTableKeys(lua_State* L, int index)
{
if (lua_istable(L, index))
{
STACK_INIT;
lua_pushvalue(L, index);
lua_pushnil(L);
while (lua_next(L, -2))
{
lua_pushvalue(L, -2);
const char* key = lua_tostring(L, -1);
log(key);
lua_pop(L, 2);
}
lua_pop(L, 1);
STACK_CLEAN;
}
}
void luaTableToJSON(lua_State* L, int index, json::value& json, bool logKeys)
{
if (lua_istable(L, index))
{
STACK_INIT;
lua_pushvalue(L, index);
lua_pushnil(L);
while (lua_next(L, -2))
{
lua_pushvalue(L, -2);
const char* key = lua_tostring(L, -1);
if (logKeys)
{
log(key);
}
if (lua_istable(L, -2))
{
if (!json.has_object_field(to_wstring(key)))
json[to_wstring(key)] = json::value::object();
luaTableToJSON(L, -2, json[to_wstring(key)], logKeys);
}
else if (lua_isnumber(L, -2))
{
json[to_wstring(key)] = json::value::number(lua_tonumber(L, -2));
}
else if (lua_isboolean(L, -2))
{
json[to_wstring(key)] = json::value::boolean(lua_toboolean(L, -2));
}
else if (lua_isstring(L, -2)) // Keep last, lua_isstring only checks if it can be stringified (not if it actually IS a string)
{
json[to_wstring(key)] = json::value::string(to_wstring(lua_tostring(L, -2)));
}
lua_pop(L, 2);
}
lua_pop(L, 1);
STACK_CLEAN;
}
}

42
backend/olympus.sln Normal file
View 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

View 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>

110
backend/olympus/olympus.rc Normal file
View File

@@ -0,0 +1,110 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Italian (Italy) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Italian (Italy) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// English (United Kingdom) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,0
PRODUCTVERSION 1,0,3,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "DCS Olympus"
VALUE "FileDescription", "DCS Olympus"
VALUE "FileVersion", "1.0.3.0"
VALUE "InternalName", "olympus.dll"
VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "olympus.dll"
VALUE "ProductName", "DCS Olympus"
VALUE "ProductVersion", "1.0.3.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United Kingdom) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,130 @@
<?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="..\luatools\luatools.vcxproj">
<Project>{de139ec1-4f88-47d5-be73-f41915fe14a3}</Project>
</ProjectReference>
<ProjectReference Include="..\utils\utils.vcxproj">
<Project>{b85009ce-4a5c-4a5a-b85d-001b3a2651b2}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="olympus.rc" />
</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" />
<Import Project="..\DCSOlympus.props" />
</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" />
<Import Project="..\DCSOlympus.props" />
</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>
<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>
<Version>{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}</Version>
</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>
<DelayLoadDLLs>dcstools.dll;logger.dll;utils.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,22 @@
<?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>
<ItemGroup>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="olympus.rc" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by olympus.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,238 @@
#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, const char* path);
typedef int(__stdcall* f_coreDeinit)(lua_State* L);
typedef int(__stdcall* f_coreFrame)(lua_State* L);
typedef int(__stdcall* f_coreUnitsData)(lua_State* L);
typedef int(__stdcall* f_coreWeaponsData)(lua_State* L);
typedef int(__stdcall* f_coreMissionData)(lua_State* L);
f_coreInit coreInit = nullptr;
f_coreDeinit coreDeinit = nullptr;
f_coreFrame coreFrame = nullptr;
f_coreUnitsData coreUnitsData = nullptr;
f_coreWeaponsData coreWeaponsData = nullptr;
f_coreMissionData coreMissionData = nullptr;
string modPath;
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
std::string GetLastErrorAsString()
{
//Get the error message ID, if any.
DWORD errorMessageID = ::GetLastError();
if (errorMessageID == 0) {
return std::string(); //No error message has been recorded
}
LPSTR messageBuffer = nullptr;
//Ask Win32 to give us the string version of that message ID.
//The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
//Copy the error message into a std::string.
std::string message(messageBuffer, size);
//Free the Win32's string's buffer.
LocalFree(messageBuffer);
return message;
}
static int onSimulationStart(lua_State* L)
{
LogInfo(L, "Trying to load core.dll from " + modPath);
SetDllDirectoryA(modPath.c_str());
setLogDirectory(modPath);
log("onSimulationStart callback called successfully");
string dllLocation = modPath + "\\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 (!coreDeinit)
{
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;
}
coreUnitsData = (f_coreUnitsData)GetProcAddress(hGetProcIDDLL, "coreUnitsData");
if (!coreUnitsData)
{
LogError(L, "Error getting coreUnitsData ProcAddress from DLL");
goto error;
}
coreWeaponsData = (f_coreWeaponsData)GetProcAddress(hGetProcIDDLL, "coreWeaponsData");
if (!coreWeaponsData)
{
LogError(L, "Error getting coreWeaponsData ProcAddress from DLL");
goto error;
}
coreMissionData = (f_coreMissionData)GetProcAddress(hGetProcIDDLL, "coreMissionData");
if (!coreMissionData)
{
LogError(L, "Error getting coreMissionData ProcAddress from DLL");
goto error;
}
coreInit(L, modPath.c_str());
LogInfo(L, "Module loaded and started successfully.");
return 0;
error:
LogError(L, "Error while loading module: " + GetLastErrorAsString());
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;
coreUnitsData = nullptr;
coreWeaponsData = nullptr;
coreMissionData = nullptr;
}
hGetProcIDDLL = NULL;
return 0;
error:
LogError(L, "Error while unloading module: " + GetLastErrorAsString());
return 0;
}
static int setUnitsData(lua_State* L)
{
if (coreUnitsData)
{
coreUnitsData(L);
}
return 0;
}
static int setWeaponsData(lua_State* L)
{
if (coreWeaponsData)
{
coreWeaponsData(L);
}
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},
{"setUnitsData", setUnitsData },
{"setWeaponsData", setWeaponsData },
{"setMissionData", setMissionData },
{NULL, NULL}
};
extern "C" DllExport int luaopen_olympus(lua_State * L)
{
lua_getglobal(L, "require");
lua_pushstring(L, "lfs");
lua_pcall(L, 1, 1, 0);
lua_getfield(L, -1, "writedir");
lua_pcall(L, 0, 1, 0);
if (lua_isstring(L, -1)) {
modPath = string(lua_tostring(L, -1)) + "Mods\\Services\\Olympus\\bin\\";
SetDllDirectoryA(modPath.c_str());
LogInfo(L, "Instance location retrieved successfully");
}
else {
/* Log without using the helper dlls because we have not loaded them yet here */
lua_getglobal(L, "log");
lua_getfield(L, -1, "ERROR");
int errorLevel = (int)lua_tointeger(L, -1);
lua_getglobal(L, "log");
lua_getfield(L, -1, "write");
lua_pushstring(L, "Olympus.dll");
lua_pushnumber(L, errorLevel);
lua_pushstring(L, "An error has occurred while trying to retrieve Olympus's instance location");
lua_pcall(L, 3, 0, 0);
return 0;
}
LogInfo(L, "Loading .dlls from " + modPath);
luaL_register(L, "olympus", Map);
return 1;
}

View File

@@ -0,0 +1,28 @@
#pragma once
#define VERSION "{{OLYMPUS_VERSION_NUMBER}}.{{OLYMPUS_COMMIT_HASH}}"
#define LOG_NAME "..\\..\\..\\..\\Logs\\Olympus_log.txt"
#define REST_ADDRESS "http://localhost:3001"
#define REST_URI "olympus"
#define UNITS_URI "units"
#define WEAPONS_URI "weapons"
#define LOGS_URI "logs"
#define AIRBASES_URI "airbases"
#define BULLSEYE_URI "bullseyes"
#define MISSION_URI "mission"
#define COMMANDS_URI "commands"
#define FRAMERATE_TIME_INTERVAL 0.05
#define OLYMPUS_JSON_PATH "..\\..\\..\\..\\Config\\olympus.json"
#define AIRCRAFT_DATABASE_PATH "..\\databases\\units\\aircraftdatabase.json"
#define HELICOPTER_DATABASE_PATH "..\\databases\\units\\helicopterdatabase.json"
#define GROUNDUNIT_DATABASE_PATH "..\\databases\\units\\groundunitdatabase.json"
#define NAVYUNIT_DATABASE_PATH "..\\databases\\units\\navyunitdatabase.json"
#define MIST_SCRIPT "..\\Scripts\\mist.lua"
#define OLYMPUS_COMMAND_SCRIPT "..\\Scripts\\OlympusCommand.lua"
#define UNIT_PAYLOADS_SCRIPT "..\\Scripts\\unitPayloads.lua"
#define TEMPLATES_SCRIPT "..\\Scripts\\templates.lua"
#define MODS_SCRIPT "..\\Scripts\\mods.lua"

View File

@@ -0,0 +1,34 @@
#pragma once
#define DllExport __declspec( dllexport )
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
#include <iostream>
#include <string>
#include <time.h>
#include <chrono>
#include <string>
#include <map>
#include <list>
#include <fstream>
#include <iostream>
#include <cstdarg>
#include <filesystem>
#include <codecvt>
#include <cpprest/http_listener.h>
#include <cpprest/json.h>
#include <cpprest/streams.h>
#include <set>
using namespace std;
using namespace web;
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "luaconf.h"
#include "lauxlib.h"
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include "framework.h"
#pragma pack(push, 1)
struct Coords {
double lat = 0;
double lng = 0;
double alt = 0;
};
struct Offset {
double x = 0;
double y = 0;
double z = 0;
};
#pragma pack(pop)
// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
const DllExport std::string CurrentDateTime();
std::wstring DllExport to_wstring(const std::string& str);
std::string DllExport to_string(json::value& value);
std::string DllExport to_string(const std::wstring& wstr);
std::string DllExport random_string(size_t length);
bool DllExport operator== (const Coords& a, const Coords& b);
bool DllExport operator!= (const Coords& a, const Coords& b);
bool DllExport operator== (const Coords& a, const double& b);
bool DllExport operator!= (const Coords& a, const double& b);
bool DllExport operator== (const Offset& a, const Offset& b);
bool DllExport operator!= (const Offset& a, const Offset& b);
bool DllExport operator== (const Offset& a, const double& b);
bool DllExport operator!= (const Offset& a, const double& b);
double DllExport knotsToMs(const double knots);
double DllExport msToKnots(const double ms);
double DllExport ftToM(const double ft);
double DllExport mToFt(const double m);

14
backend/utils/resource.h Normal file
View File

@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by utils.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,87 @@
#include "framework.h"
#include "utils.h"
// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
const std::string CurrentDateTime()
{
time_t now = time(NULL);
struct tm tstruct;
char buf[80];
localtime_s(&tstruct, &now);
strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);
return buf;
}
std::wstring to_wstring(const std::string& str)
{
unsigned int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (unsigned int)str.size(), NULL, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (unsigned int)str.size(), &wstrTo[0], size_needed);
return wstrTo;
}
std::string to_string(json::value& value) {
return to_string(value.as_string());
}
std::string to_string(const std::wstring& wstr)
{
if (wstr.empty())
{
return "";
}
const auto size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr.at(0), (unsigned int)wstr.size(), nullptr, 0, nullptr, nullptr);
if (size_needed <= 0)
{
throw std::runtime_error("WideCharToMultiByte() failed: " + std::to_string(size_needed));
}
std::string result(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr.at(0), (unsigned int)wstr.size(), &result.at(0), size_needed, nullptr, nullptr);
return result;
}
std::string random_string(size_t length)
{
srand(static_cast<unsigned int>(time(NULL)));
auto randchar = []() -> char
{
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t max_index = (sizeof(charset) - 1);
return charset[rand() % max_index];
};
std::string str(length, 0);
std::generate_n(str.begin(), length, randchar);
return str;
}
bool operator== (const Coords& a, const Coords& b) { return a.lat == b.lat && a.lng == b.lng && a.alt == b.alt; }
bool operator!= (const Coords& a, const Coords& b) { return !(a == b); }
bool operator== (const Coords& a, const double& b) { return a.lat == b && a.lng == b && a.alt == b; }
bool operator!= (const Coords& a, const double& b) { return !(a == b); }
bool operator== (const Offset& a, const Offset& b) { return a.x == b.x && a.y == b.y && a.z == b.z; }
bool operator!= (const Offset& a, const Offset& b) { return !(a == b); }
bool operator== (const Offset& a, const double& b) { return a.x == b && a.y == b && a.z == b; }
bool operator!= (const Offset& a, const double& b) { return !(a == b); }
double knotsToMs(const double knots) {
return knots / 1.94384;
}
double msToKnots(const double ms) {
return ms * 1.94384;
}
double ftToM(const double ft) {
return ft * 0.3048;
}
double mToFt(const double m) {
return m / 0.3048;
}

110
backend/utils/utils.rc Normal file
View File

@@ -0,0 +1,110 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Italian (Italy) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ITA)
LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Italian (Italy) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// English (United Kingdom) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,3,0
PRODUCTVERSION 1,0,3,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "DCS Olympus"
VALUE "FileDescription", "DCS Olympus"
VALUE "FileVersion", "1.0.3.0"
VALUE "InternalName", "utils.dll"
VALUE "LegalCopyright", "Copyright (C) 2023"
VALUE "OriginalFilename", "utils.dll"
VALUE "ProductName", "TODO: <Product name>"
VALUE "ProductVersion", "1.0.3.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United Kingdom) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

173
backend/utils/utils.vcxproj Normal file
View File

@@ -0,0 +1,173 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\utils.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\utils.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="utils.rc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{b85009ce-4a5c-4a5a-b85d-001b3a2651b2}</ProjectGuid>
<RootNamespace>utils</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</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|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\DCSOlympus.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\DCSOlympus.props" />
</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" />
<Import Project="..\DCSOlympus.props" />
</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" />
<Import Project="..\DCSOlympus.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>.\..\..\bin\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>.\..\..\bin\$(Platform)\$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;UTILS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;UTILS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;UTILS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>include;..\..\third-party\lua\include;..\shared\include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
<AdditionalDependencies>lua.lib; $(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;UTILS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>include;..\..\third-party\lua\include;..\shared\include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>lua.lib; $(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\..\third-party\lua</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View 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="Source Files">
<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="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="utils.rc" />
</ItemGroup>
</Project>

7
backend/vcpkg.json Normal file
View File

@@ -0,0 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"dependencies": [
"cpprestsdk",
"geographiclib"
]
}