mirror of
https://github.com/ncblakely/GiantsTools
synced 2024-12-22 07:17:22 +01:00
Serialization of navmesh and build settings.
This commit is contained in:
parent
7874502ca2
commit
23d3136e3f
21
External/json/LICENSE.MIT
vendored
Normal file
21
External/json/LICENSE.MIT
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2021 Niels Lohmann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
25597
External/json/json.hpp
vendored
Normal file
25597
External/json/json.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -308,6 +308,7 @@ Global
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|x86.ActiveCfg = Release|Any CPU
|
||||
{2AFB71CA-8313-472E-B242-0517343764B4}.ReleaseBeta|x86.Build.0 = Release|Any CPU
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|x64.Build.0 = Debug|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
@ -319,6 +320,7 @@ Global
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|x86.ActiveCfg = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.DebugBeta|x86.Build.0 = Debug|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|x64.ActiveCfg = Release|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|x64.Build.0 = Release|x64
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.Release|x86.ActiveCfg = Release|Win32
|
||||
@ -330,6 +332,7 @@ Global
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|x86.ActiveCfg = Release|Win32
|
||||
{8AEE9CFF-0E24-498F-B60A-627A7F4A727D}.ReleaseBeta|x86.Build.0 = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x64.Build.0 = Debug|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
@ -341,6 +344,7 @@ Global
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|x86.ActiveCfg = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.DebugBeta|x86.Build.0 = Debug|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x64.ActiveCfg = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x64.Build.0 = Release|x64
|
||||
{CA9C0938-3ADA-4C73-A89A-E9447ABCE101}.Release|x86.ActiveCfg = Release|Win32
|
||||
|
@ -3,10 +3,13 @@
|
||||
#include "NavMeshGenerator.h"
|
||||
#include "RecastContext.h"
|
||||
|
||||
using namespace std::filesystem;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::filesystem::path inputPath;
|
||||
std::filesystem::path outputPath;
|
||||
path inputPath;
|
||||
path outputPath;
|
||||
path outputPath2;
|
||||
bool enableLogging = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
@ -19,21 +22,27 @@ int main(int argc, char** argv)
|
||||
{
|
||||
outputPath = argv[++i];
|
||||
}
|
||||
else if (!_stricmp(argv[i], "--output2"))
|
||||
{
|
||||
outputPath2 = argv[++i];
|
||||
}
|
||||
else if (!_stricmp(argv[i], "--enableLogging"))
|
||||
{
|
||||
enableLogging = true;
|
||||
}
|
||||
}
|
||||
|
||||
InputGeom* geom = new InputGeom();
|
||||
geom->load(nullptr, inputPath.string());
|
||||
const auto context = std::make_shared<RecastContext>(enableLogging);
|
||||
|
||||
auto geom = std::make_shared<InputGeom>();
|
||||
geom->load(context.get(), inputPath.string());
|
||||
|
||||
if (outputPath.empty())
|
||||
{
|
||||
printf("Warning: no output path set, no file will be generated.\n");
|
||||
}
|
||||
|
||||
const auto context = std::make_shared<RecastContext>(enableLogging);
|
||||
|
||||
NavMeshGenerator generator(geom, context);
|
||||
bool success = generator.BuildNavMesh();
|
||||
|
||||
@ -45,5 +54,17 @@ int main(int argc, char** argv)
|
||||
if (!outputPath.empty())
|
||||
{
|
||||
generator.Serialize(outputPath);
|
||||
|
||||
if (!outputPath2.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
copy_file(outputPath, outputPath2);
|
||||
}
|
||||
catch (const filesystem_error& ex)
|
||||
{
|
||||
printf("Unable to copy output file to secondary path: %s.\n", ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,34 @@
|
||||
#include "Recast.h"
|
||||
#include "RecastContext.h"
|
||||
|
||||
NavMeshGenerator::NavMeshGenerator(InputGeom* geom, std::shared_ptr<RecastContext> context)
|
||||
using namespace nlohmann;
|
||||
using namespace std::filesystem;
|
||||
|
||||
inline unsigned int nextPow2(unsigned int v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return v;
|
||||
}
|
||||
|
||||
inline unsigned int ilog2(unsigned int v)
|
||||
{
|
||||
unsigned int r;
|
||||
unsigned int shift;
|
||||
r = (v > 0xffff) << 4; v >>= r;
|
||||
shift = (v > 0xff) << 3; v >>= shift; r |= shift;
|
||||
shift = (v > 0xf) << 2; v >>= shift; r |= shift;
|
||||
shift = (v > 0x3) << 1; v >>= shift; r |= shift;
|
||||
r |= (v >> 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
NavMeshGenerator::NavMeshGenerator(std::shared_ptr<InputGeom> geom, std::shared_ptr<RecastContext> context)
|
||||
: m_geom(geom),
|
||||
m_navMeshQuery(dtAllocNavMeshQuery()),
|
||||
m_navMesh(dtAllocNavMesh()),
|
||||
@ -36,6 +63,8 @@ void NavMeshGenerator::Cleanup()
|
||||
|
||||
bool NavMeshGenerator::BuildNavMesh()
|
||||
{
|
||||
CalculateTileSize();
|
||||
|
||||
dtNavMeshParams params{};
|
||||
rcVcopy(params.orig, m_geom->getNavMeshBoundsMin());
|
||||
params.tileWidth = m_tileSize * m_cellSize;
|
||||
@ -60,6 +89,27 @@ bool NavMeshGenerator::BuildNavMesh()
|
||||
return true;
|
||||
}
|
||||
|
||||
void NavMeshGenerator::CalculateTileSize()
|
||||
{
|
||||
const float* bmin = m_geom->getNavMeshBoundsMin();
|
||||
const float* bmax = m_geom->getNavMeshBoundsMax();
|
||||
|
||||
int gw = 0, gh = 0;
|
||||
rcCalcGridSize(bmin, bmax, m_cellSize, &gw, &gh);
|
||||
const int ts = (int)m_tileSize;
|
||||
const int tw = (gw + ts - 1) / ts;
|
||||
const int th = (gh + ts - 1) / ts;
|
||||
const float tcs = m_tileSize * m_cellSize;
|
||||
|
||||
// Max tiles and max polys affect how the tile IDs are caculated.
|
||||
// There are 22 bits available for identifying a tile and a polygon.
|
||||
int tileBits = rcMin((int)ilog2(nextPow2(tw * th)), 14);
|
||||
if (tileBits > 14) tileBits = 14;
|
||||
int polyBits = 22 - tileBits;
|
||||
m_maxTiles = 1 << tileBits;
|
||||
m_maxPolysPerTile = 1 << polyBits;
|
||||
}
|
||||
|
||||
void NavMeshGenerator::BuildAllTiles()
|
||||
{
|
||||
const float* bmin = m_geom->getNavMeshBoundsMin();
|
||||
@ -485,13 +535,14 @@ unsigned char* NavMeshGenerator::BuildTileMesh(const int tx, const int ty, const
|
||||
return navData;
|
||||
}
|
||||
|
||||
void NavMeshGenerator::Serialize(const std::filesystem::path& path) const
|
||||
bool NavMeshGenerator::Serialize(const std::filesystem::path& path, bool saveStatistics)
|
||||
{
|
||||
if (!m_navMesh) return;
|
||||
if (!m_navMesh)
|
||||
return false;
|
||||
|
||||
FILE* fp = fopen(path.string().c_str(), "wb");
|
||||
if (!fp)
|
||||
return;
|
||||
return false;
|
||||
|
||||
// Store header.
|
||||
NavMeshSetHeader header;
|
||||
@ -524,4 +575,49 @@ void NavMeshGenerator::Serialize(const std::filesystem::path& path) const
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (saveStatistics)
|
||||
{
|
||||
std::filesystem::path statsPath = path;
|
||||
statsPath = statsPath.replace_extension(".navstats");
|
||||
WriteStatistics(statsPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NavMeshGenerator::WriteStatistics(const std::filesystem::path& path)
|
||||
{
|
||||
std::ofstream outputFile(path);
|
||||
if (!outputFile.is_open())
|
||||
return false;
|
||||
|
||||
njson json;
|
||||
json["m_cellSize"] = m_cellSize;
|
||||
json["m_cellHeight"] = m_cellHeight;
|
||||
json["m_agentHeight"] = m_agentHeight;
|
||||
json["m_agentRadius"] = m_agentRadius;
|
||||
json["m_agentMaxClimb"] = m_agentMaxClimb;
|
||||
json["m_agentMaxSlope"] = m_agentMaxSlope;
|
||||
json["m_regionMinSize"] = m_regionMinSize;
|
||||
json["m_regionMergeSize"] = m_regionMergeSize;
|
||||
json["m_edgeMaxLen"] = m_edgeMaxLen;
|
||||
json["m_edgeMaxError"] = m_edgeMaxError;
|
||||
json["m_vertsPerPoly"] = m_vertsPerPoly;
|
||||
json["m_detailSampleDist"] = m_detailSampleDist;
|
||||
json["m_detailSampleMaxError"] = m_detailSampleMaxError;
|
||||
json["m_partitionType"] = m_partitionType;
|
||||
json["m_filterLowHangingObstacles"] = m_filterLowHangingObstacles;
|
||||
json["m_filterLedgeSpans"] = m_filterLedgeSpans;
|
||||
json["m_filterWalkableLowHeightSpans"] = m_filterWalkableLowHeightSpans;
|
||||
json["m_maxTiles"] = m_maxTiles;
|
||||
json["m_maxPolysPerTile"] = m_maxPolysPerTile;
|
||||
json["m_tileSize"] = m_tileSize;
|
||||
json["m_tileCol"] = m_tileCol;
|
||||
json["m_tileMemUsage"] = m_tileMemUsage;
|
||||
json["m_tileBuildTime"] = m_tileBuildTime;
|
||||
json["m_tileTriCount"] = m_tileTriCount;
|
||||
|
||||
outputFile << std::setw(4) << json;
|
||||
return true;
|
||||
}
|
@ -15,23 +15,24 @@
|
||||
class NavMeshGenerator
|
||||
{
|
||||
public:
|
||||
NavMeshGenerator(InputGeom* geom, std::shared_ptr<RecastContext> context);
|
||||
NavMeshGenerator(std::shared_ptr<InputGeom> geom, std::shared_ptr<RecastContext> context);
|
||||
virtual ~NavMeshGenerator();
|
||||
|
||||
bool BuildNavMesh();
|
||||
void Serialize(const std::filesystem::path& path) const;
|
||||
bool Serialize(const std::filesystem::path& path, bool saveStatistics = true);
|
||||
private:
|
||||
void BuildAllTiles();
|
||||
void CalculateTileSize();
|
||||
void Cleanup();
|
||||
bool WriteStatistics(const std::filesystem::path& path);
|
||||
|
||||
unsigned char* BuildTileMesh(const int tx, const int ty, const float* bmin, const float* bmax, int& dataSize);
|
||||
|
||||
std::unique_ptr<InputGeom> m_geom;
|
||||
std::shared_ptr<InputGeom> m_geom;
|
||||
std::unique_ptr<dtNavMesh, NavMeshDeleter> m_navMesh;
|
||||
std::unique_ptr<dtNavMeshQuery, NavMeshQueryDeleter> m_navMeshQuery;
|
||||
std::shared_ptr<rcContext> m_ctx;
|
||||
|
||||
|
||||
unsigned char* m_triareas{};
|
||||
rcHeightfield* m_solid{};
|
||||
rcCompactHeightfield* m_chf{};
|
||||
@ -46,7 +47,7 @@ private:
|
||||
float m_agentHeight = 2.0f;
|
||||
float m_agentRadius = 0.6f;
|
||||
float m_agentMaxClimb = 0.9f;
|
||||
float m_agentMaxSlope = 50.0f; //45.0f;
|
||||
float m_agentMaxSlope = 60.0f; // Sample: 45.0f
|
||||
float m_regionMinSize = 8;
|
||||
float m_regionMergeSize = 20;
|
||||
float m_edgeMaxLen = 12.0f;
|
||||
@ -65,7 +66,7 @@ private:
|
||||
// Tile configuration
|
||||
int m_maxTiles = 0;
|
||||
int m_maxPolysPerTile = 0;
|
||||
float m_tileSize = 32;
|
||||
float m_tileSize = 96; //Sample: 32
|
||||
|
||||
unsigned int m_tileCol{};
|
||||
float m_lastBuiltTileBmin[3]{};
|
||||
|
@ -1,18 +1,6 @@
|
||||
<?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>
|
||||
<Filter Include="Recast">
|
||||
<UniqueIdentifier>{82f0fd75-bb9d-4e6c-849a-71f66d5a8f0a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@ -52,7 +40,7 @@
|
||||
<Filter Include="Recast\Recast\Include">
|
||||
<UniqueIdentifier>{54fffb89-f106-45f9-9a78-119f59e17fed}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Framework">
|
||||
<Filter Include="Framework">
|
||||
<UniqueIdentifier>{c5ca75e6-1ec9-4c06-a733-4323f130f5c4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
@ -129,30 +117,22 @@
|
||||
<ClCompile Include="..\External\recastnavigation\Recast\Source\RecastRegion.cpp">
|
||||
<Filter>Recast\Recast\Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NavMeshGenerator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RecastContext.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Framework\ChunkyTriMesh.cpp">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
<Filter>Framework</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Framework\InputGeom.cpp">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
<Filter>Framework</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Framework\MeshLoaderObj.cpp">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
<Filter>Framework</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Framework\PerfTimer.cpp">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
<Filter>Framework</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="NavMeshGenerator.cpp" />
|
||||
<ClCompile Include="pch.cpp" />
|
||||
<ClCompile Include="RecastContext.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\External\recastnavigation\DebugUtils\Include\DebugDraw.h">
|
||||
@ -209,35 +189,27 @@
|
||||
<ClInclude Include="..\External\recastnavigation\Recast\Include\RecastAssert.h">
|
||||
<Filter>Recast\Recast\Include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NavMeshGenerator.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NavMeshUtil.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RecastContext.h">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\ChunkyTriMesh.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
<Filter>Framework</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\InputGeom.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
<Filter>Framework</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\MeshLoaderObj.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
<Filter>Framework</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\PerfTimer.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
<Filter>Framework</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\Sample.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
<Filter>Framework</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Framework\SampleInterfaces.h">
|
||||
<Filter>Source Files\Framework</Filter>
|
||||
<Filter>Framework</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NavMeshGenerator.h" />
|
||||
<ClInclude Include="NavMeshUtil.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="RecastContext.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -23,6 +23,7 @@ struct NavMeshQueryDeleter
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// Serialization logic
|
||||
// Note: identical to Recast's demo app so it can be loaded by it
|
||||
struct NavMeshSetHeader
|
||||
{
|
||||
int magic;
|
||||
|
@ -1,3 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
// STL
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
// External libraries
|
||||
#include "../External/json/json.hpp"
|
||||
using njson = nlohmann::json;
|
||||
|
Loading…
Reference in New Issue
Block a user