From 8db81823be1bfcb7b1486c0a7064a71e2209dfff Mon Sep 17 00:00:00 2001 From: Jannis Date: Thu, 1 Feb 2024 21:04:37 +0100 Subject: [PATCH] more tweaks and work on the export tool, finished terrain export --- .../AmeisenNavigation.Exporter.vcxproj | 27 +- ...AmeisenNavigation.Exporter.vcxproj.filters | 27 ++ .../src/Dbc/DbcFile.hpp | 45 +++ AmeisenNavigation.Exporter/src/Main.cpp | 115 +++++--- AmeisenNavigation.Exporter/src/Main.hpp | 21 +- .../src/Mpq/FileSort.hpp | 73 +++++ .../src/Mpq/MpqManager.hpp | 118 ++++++++ AmeisenNavigation.Exporter/src/Utils/Tri.hpp | 23 ++ .../src/Utils/Vector3.hpp | 32 +++ AmeisenNavigation.Exporter/src/Wow/Adt.hpp | 262 ++++++++++++++++++ .../src/Wow/LiquidType.hpp | 9 + AmeisenNavigation.Exporter/src/Wow/Mver.hpp | 8 + AmeisenNavigation.Exporter/src/Wow/Wdt.hpp | 44 +++ AmeisenNavigation.Server/src/Main.cpp | 21 ++ AmeisenNavigation.Server/src/Main.hpp | 18 +- AmeisenNavigation.Tester/MainWindow.xaml | 21 +- AmeisenNavigation.Tester/MainWindow.xaml.cs | 98 ++++++- AmeisenNavigation/AmeisenNavigation.vcxproj | 2 + .../AmeisenNavigation.vcxproj.filters | 2 + AmeisenNavigation/src/AmeisenNavigation.cpp | 89 +++--- AmeisenNavigation/src/AmeisenNavigation.hpp | 21 +- .../src/Clients/AmeisenNavClient.hpp | 77 +++-- AmeisenNavigation/src/Clients/ClientState.hpp | 11 + .../src/Clients/QueryFilterProvider.hpp | 109 ++++++++ AmeisenNavigation/src/Utils/Path.hpp | 48 ++++ AmeisenNavigation/src/Utils/VectorUtils.hpp | 10 +- dep/StormLib/lib/Win32/StormLibDUS.lib | Bin 0 -> 2409554 bytes dep/StormLib/lib/Win32/StormLibRUS.lib | Bin 3001862 -> 3001862 bytes dep/StormLib/lib/x64/StormLibRUS.lib | Bin 3546646 -> 3546646 bytes 29 files changed, 1195 insertions(+), 136 deletions(-) create mode 100644 AmeisenNavigation.Exporter/src/Dbc/DbcFile.hpp create mode 100644 AmeisenNavigation.Exporter/src/Mpq/FileSort.hpp create mode 100644 AmeisenNavigation.Exporter/src/Mpq/MpqManager.hpp create mode 100644 AmeisenNavigation.Exporter/src/Utils/Tri.hpp create mode 100644 AmeisenNavigation.Exporter/src/Utils/Vector3.hpp create mode 100644 AmeisenNavigation.Exporter/src/Wow/Adt.hpp create mode 100644 AmeisenNavigation.Exporter/src/Wow/LiquidType.hpp create mode 100644 AmeisenNavigation.Exporter/src/Wow/Mver.hpp create mode 100644 AmeisenNavigation.Exporter/src/Wow/Wdt.hpp create mode 100644 AmeisenNavigation/src/Clients/ClientState.hpp create mode 100644 AmeisenNavigation/src/Clients/QueryFilterProvider.hpp create mode 100644 dep/StormLib/lib/Win32/StormLibDUS.lib diff --git a/AmeisenNavigation.Exporter/AmeisenNavigation.Exporter.vcxproj b/AmeisenNavigation.Exporter/AmeisenNavigation.Exporter.vcxproj index 37f7bbb..bc1623b 100644 --- a/AmeisenNavigation.Exporter/AmeisenNavigation.Exporter.vcxproj +++ b/AmeisenNavigation.Exporter/AmeisenNavigation.Exporter.vcxproj @@ -101,13 +101,14 @@ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpplatest - stdc17 + Default true + MultiThreadedDebugDLL Console true - StormLibRUS.lib;%(AdditionalDependencies) + StormLibDUS.lib;%(AdditionalDependencies) @@ -119,8 +120,10 @@ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpplatest - stdc17 + Default true + MaxSpeed + MultiThreadedDLL Console @@ -137,13 +140,14 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpplatest - stdc17 + Default true + MultiThreadedDebugDLL Console true - StormLibRUS.lib;%(AdditionalDependencies) + StormLibDUS.lib;%(AdditionalDependencies) @@ -155,8 +159,10 @@ NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpplatest - stdc17 + Default true + MaxSpeed + MultiThreadedDLL Console @@ -170,7 +176,16 @@ + + + + + + + + + diff --git a/AmeisenNavigation.Exporter/AmeisenNavigation.Exporter.vcxproj.filters b/AmeisenNavigation.Exporter/AmeisenNavigation.Exporter.vcxproj.filters index b5ab3a5..1d197e4 100644 --- a/AmeisenNavigation.Exporter/AmeisenNavigation.Exporter.vcxproj.filters +++ b/AmeisenNavigation.Exporter/AmeisenNavigation.Exporter.vcxproj.filters @@ -23,5 +23,32 @@ Headerdateien + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + + + Headerdateien + \ No newline at end of file diff --git a/AmeisenNavigation.Exporter/src/Dbc/DbcFile.hpp b/AmeisenNavigation.Exporter/src/Dbc/DbcFile.hpp new file mode 100644 index 0000000..dce525c --- /dev/null +++ b/AmeisenNavigation.Exporter/src/Dbc/DbcFile.hpp @@ -0,0 +1,45 @@ +#pragma once + +struct DbcHeader +{ + char magic[4]; + unsigned int recordCount; + unsigned int fieldCount; + unsigned int recordSize; + unsigned int stringTableSize; +}; + +class DbcFile +{ + unsigned char* Data; + +public: + DbcFile(unsigned char* data) noexcept + : Data(data) + {} + + ~DbcFile() noexcept + { + if (Data) free(Data); + } + + inline DbcHeader* GetHeader() const noexcept { return reinterpret_cast(Data); } + constexpr inline unsigned char* GetData() const noexcept { return Data + sizeof(DbcHeader); } + + inline unsigned int GetRecordCount() const noexcept { return GetHeader()->recordCount; } + inline unsigned int GetFieldCount() const noexcept { return GetHeader()->fieldCount; } + inline unsigned int GetRecordSize() const noexcept { return GetHeader()->recordSize; } + inline unsigned int GetStringTableSize() const noexcept { return GetHeader()->stringTableSize; } + inline unsigned char* GetStringTable() const noexcept { return GetData() + (GetRecordSize() * GetRecordCount()); } + + template + constexpr inline T Read(unsigned int id, unsigned int field) noexcept + { + return *((T*)(GetData() + (id * GetRecordSize() + (field * 4)))); + } + + inline const char* ReadString(unsigned int id, unsigned int field) noexcept + { + return reinterpret_cast(GetStringTable() + Read(id, field)); + } +}; diff --git a/AmeisenNavigation.Exporter/src/Main.cpp b/AmeisenNavigation.Exporter/src/Main.cpp index e1be7d5..47057cc 100644 --- a/AmeisenNavigation.Exporter/src/Main.cpp +++ b/AmeisenNavigation.Exporter/src/Main.cpp @@ -1,62 +1,107 @@ #include "Main.hpp" -int main() +int main() noexcept { - const std::string mpqFilter{ ".mpq" }; - std::vector mpqFiles{}; - std::vector> dbcFiles{}; + MpqManager mpqManager(GAME_DIR); - for (const auto& entry : std::filesystem::recursive_directory_iterator("C:\\Spiele\\World of Warcraft 3.3.5a\\Data\\")) + unsigned char* mapDbcData = nullptr; + unsigned int mapDbcSize = 0; + std::vector> maps; + + if (mpqManager.GetFileContent("DBFilesClient\\Map.dbc", mapDbcData, mapDbcSize)) { - if (entry.is_regular_file()) - { - const auto& path = entry.path(); - const auto& ext = path.extension().string(); + DbcFile mapDbc(mapDbcData); - if (std::equal(mpqFilter.begin(), mpqFilter.end(), ext.begin(), [](char a, char b) { return std::tolower(a) == std::tolower(b); })) - { - mpqFiles.push_back(path); - } + for (unsigned int i = 0u; i < mapDbc.GetRecordCount(); ++i) + { + maps.push_back(std::make_pair(mapDbc.Read(i, 0u), mapDbc.ReadString(i, 1u))); } } - std::sort(mpqFiles.begin(), mpqFiles.end(), NaturalCompare); + unsigned char* liquidTypeDbcData = nullptr; + unsigned int liquidTypeDbcSize = 0; + std::unordered_map liquidTypes; - for (const auto& mpqFile : mpqFiles) + if (mpqManager.GetFileContent("DBFilesClient\\LiquidType.dbc", liquidTypeDbcData, liquidTypeDbcSize)) { - std::cout << mpqFile << std::endl; - continue; + DbcFile liquidTypeDbc(liquidTypeDbcData); - if (void* mpq; SFileOpenArchive(mpqFile.c_str(), 0, MPQ_OPEN_READ_ONLY, &mpq)) + for (unsigned int i = 0u; i < liquidTypeDbc.GetRecordCount(); ++i) { - SFILE_FIND_DATA findData{}; - void* fileFind = SFileFindFirstFile(mpq, "*.dbc", &findData, nullptr); + liquidTypes[liquidTypeDbc.Read(i, 0u)] = static_cast(liquidTypeDbc.Read(i, 3u)); + } + } + + // #pragma omp parallel for schedule(dynamic) + for (int mapIndex = 0; mapIndex < 1; ++mapIndex) // maps.size() + { + const auto& [id, name] = maps[mapIndex]; + const auto mapsPath = std::format("World\\Maps\\{}\\{}", name, name); + + const auto wdtPath = std::format("{}.wdt", mapsPath); + unsigned char* wdtData = nullptr; + unsigned int wdtSize = 0; + + if (mpqManager.GetFileContent(wdtPath.c_str(), wdtData, wdtSize)) + { + Wdt wdt(wdtData); + + std::vector verts; + std::vector tris; - while (fileFind) + for (int i = 0; i < 1; ++i) // WDT_MAP_SIZE * WDT_MAP_SIZE { - dbcFiles.push_back(std::make_pair(findData, mpqFile)); + const auto x = 48; // i % WDT_MAP_SIZE; + const auto y = 32; // i / WDT_MAP_SIZE; - if (!SFileFindNextFile(fileFind, &findData)) + if (wdt.Main()->adt[x][y].exists) { - break; + const auto adtPath = std::format("{}_{}_{}.adt", mapsPath, y, x); + unsigned char* adtData = nullptr; + unsigned int adtSize = 0; + + std::cout << "[Maps] " << name << ": ADT(" << x << ", " << y << ") " << adtPath << std::endl; + + if (mpqManager.GetFileContent(adtPath.c_str(), adtData, adtSize)) + { + Adt adt(adtData); + + for (int a = 0; a < ADT_CELLS_PER_GRID * ADT_CELLS_PER_GRID; ++a) + { + const int cx = a / ADT_CELLS_PER_GRID; + const int cy = a % ADT_CELLS_PER_GRID; + + adt.GetTerrainVertsAndTris(cx, cy, verts, tris); + adt.GetLiquidVertsAndTris(cx, cy, verts, tris); + } + } } } - SFileFindClose(fileFind); - SFileCloseArchive(mpq); - } - else - { - std::cerr << "-> Failed to open MPQ file: " << mpqFile << std::endl; + ExportDebugObjFile(verts, tris); } } - std::sort(dbcFiles.begin(), dbcFiles.end(), [](const auto& a, const auto& b) { return a.second > b.second; }); + return 0; +} - for (const auto& dbcFile : dbcFiles) +void ExportDebugObjFile(const std::vector& vertexes, const std::vector& tris) noexcept +{ + std::cout << "Exporting OBJ file" << std::endl; + std::fstream objFstream; + objFstream << std::fixed << std::showpoint; + objFstream << std::setprecision(8); + objFstream.open("C:\\Users\\Jannis\\source\\repos\\recastnavigation\\RecastDemo\\Bin\\Meshes\\debug.obj", std::fstream::out); + + for (const auto& v3 : vertexes) { - std::cout << dbcFile.first.szPlainName << std::endl; + objFstream << "v " << v3.y << " " << v3.z << " " << v3.x << "\n"; } - return 0; -} \ No newline at end of file + for (const auto& tri : tris) + { + objFstream << "f " << tri.a << " " << tri.b << " " << tri.c << "\n"; + } + + objFstream.close(); +} diff --git a/AmeisenNavigation.Exporter/src/Main.hpp b/AmeisenNavigation.Exporter/src/Main.hpp index 496a2a3..d7e5efe 100644 --- a/AmeisenNavigation.Exporter/src/Main.hpp +++ b/AmeisenNavigation.Exporter/src/Main.hpp @@ -1,17 +1,20 @@ #pragma once -#include #include +#include +#include #include +#include #include -#define STORMLIB_NO_AUTO_LINK -#include +#include "Utils/Vector3.hpp" +#include "Utils/Tri.hpp" +#include "Dbc/DbcFile.hpp" +#include "Mpq/MpqManager.hpp" +#include "Wow/Adt.hpp" +#include "Wow/LiquidType.hpp" +#include "Wow/Wdt.hpp" -#include -#pragma comment(lib, "Shlwapi.lib") +constexpr auto GAME_DIR = "C:\\Spiele\\World of Warcraft 3.3.5a\\Data\\"; -inline auto NaturalCompare(const std::filesystem::path& path1, const std::filesystem::path& path2) -{ - return StrCmpLogicalW(path1.wstring().c_str(), path2.wstring().c_str()); -} +void ExportDebugObjFile(const std::vector& vertexes, const std::vector& tris) noexcept; diff --git a/AmeisenNavigation.Exporter/src/Mpq/FileSort.hpp b/AmeisenNavigation.Exporter/src/Mpq/FileSort.hpp new file mode 100644 index 0000000..0f2aa11 --- /dev/null +++ b/AmeisenNavigation.Exporter/src/Mpq/FileSort.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include +#include + +inline std::pair ExtractNumber(const std::wstring& s) +{ + std::wstring prefix; + int number = 0; + bool foundDigit = false; + + for (const wchar_t& c : s) + { + if (std::iswdigit(c)) + { + prefix += L' '; + foundDigit = true; + number = number * 10 + (c - L'0'); + } + else + { + if (foundDigit) + { + break; + } + + prefix += c; + } + } + + return { prefix, number }; +} + +inline int GetPathDepth(const std::filesystem::path& path, int depth = 0) +{ + if (path.has_parent_path()) + { + const auto parent = path.parent_path(); + + if (parent != path) + { + return GetPathDepth(parent, depth + 1); + } + } + + return depth; +} + +/// +/// Try to sort the MPQ files in the order wow loads them. +/// +inline bool NaturalCompare(const std::filesystem::directory_entry& a, const std::filesystem::directory_entry& b) +{ + if (GetPathDepth(a.path()) > GetPathDepth(b.path())) + { + return true; + } + + auto [prefixA, numberA] = ExtractNumber(a.path().filename().wstring()); + auto [prefixB, numberB] = ExtractNumber(b.path().filename().wstring()); + + if (numberA == 0 && numberB != 0) + { + return true; + } + + if (prefixA != prefixB) + { + return prefixA < prefixB; + } + + return numberA < numberB; +} diff --git a/AmeisenNavigation.Exporter/src/Mpq/MpqManager.hpp b/AmeisenNavigation.Exporter/src/Mpq/MpqManager.hpp new file mode 100644 index 0000000..94bdf29 --- /dev/null +++ b/AmeisenNavigation.Exporter/src/Mpq/MpqManager.hpp @@ -0,0 +1,118 @@ +#pragma once + +#include +#include +#include + +#define STORMLIB_NO_AUTO_LINK +#include + +#include "FileSort.hpp" + +class MpqManager +{ + const char* GameDir; + std::vector Mpqs; + +public: + MpqManager(const char* gameDir) noexcept + : GameDir(gameDir), + Mpqs() + { + const std::string mpqFilter{ ".mpq" }; + + std::vector mpqFiles; + + for (const auto& p : std::filesystem::recursive_directory_iterator(gameDir)) + { + if (p.is_regular_file()) + { + const auto& ext = p.path().extension().string(); + + if (std::ranges::equal(mpqFilter, ext, [](char a, char b) { return std::tolower(a) == std::tolower(b); })) + { + mpqFiles.emplace_back(p); + } + } + } + + std::ranges::sort(mpqFiles, NaturalCompare); + Mpqs.resize(mpqFiles.size()); + +#pragma omp parallel for schedule(dynamic) + for (int i = 0; i < mpqFiles.size(); ++i) + { + const auto& path = mpqFiles[i].path(); + + if (void* mpq; SFileOpenArchive(path.c_str(), 0, MPQ_OPEN_READ_ONLY, &mpq)) + { +#pragma omp critical + { + std::cout << "[MPQManager] (" << i << ") Loaded: 0x" << std::hex << mpq << std::dec << " " << path.filename() << std::endl; + } + + Mpqs[i] = mpq; + } + } + } + + ~MpqManager() noexcept + { + for (void* mpq : Mpqs) + { + SFileCloseArchive(mpq); + } + } + + inline bool GetFile(const char* name, SFILE_FIND_DATA& resultFindData, void*& mpqHanle) noexcept + { + bool result = false; + SFILE_FIND_DATA findData{ 0 }; + + for (void* mpq : Mpqs) + { + if (void* fileFind = SFileFindFirstFile(mpq, name, &findData, nullptr)) + { + do + { + resultFindData = findData; + mpqHanle = mpq; + result = true; + } while (SFileFindNextFile(fileFind, &findData)); + + SFileFindClose(fileFind); + } + } + + return result; + } + + inline bool GetFileContent(const char* name, unsigned char*& buffer, unsigned int& bufferSize) noexcept + { + void* mpq{}; + SFILE_FIND_DATA findData{}; + + if (GetFile(name, findData, mpq)) + { + if (HANDLE hFile{}; SFileOpenFileEx(mpq, findData.cFileName, 0, &hFile)) + { + bufferSize = findData.dwFileSize; + + if (bufferSize > 0) + { + buffer = new unsigned char[bufferSize]; + + if (SFileReadFile(hFile, buffer, bufferSize, 0, 0)) + { + SFileCloseFile(hFile); + return true; + } + } + + SFileCloseFile(hFile); + } + } + + return false; + } +}; diff --git a/AmeisenNavigation.Exporter/src/Utils/Tri.hpp b/AmeisenNavigation.Exporter/src/Utils/Tri.hpp new file mode 100644 index 0000000..e692945 --- /dev/null +++ b/AmeisenNavigation.Exporter/src/Utils/Tri.hpp @@ -0,0 +1,23 @@ +#pragma once + +struct Tri +{ + union + { + struct + { + int a; + int b; + int c; + }; + int points[3]; + }; + + Tri() noexcept + : points{ 0, 0, 0 } + {} + + Tri(int a, int b, int c) noexcept + : points{ a, b, c } + {} +}; diff --git a/AmeisenNavigation.Exporter/src/Utils/Vector3.hpp b/AmeisenNavigation.Exporter/src/Utils/Vector3.hpp new file mode 100644 index 0000000..2a852a4 --- /dev/null +++ b/AmeisenNavigation.Exporter/src/Utils/Vector3.hpp @@ -0,0 +1,32 @@ +#pragma once + +#pragma once + +struct Vector3 +{ + union + { + struct + { + float x; + float y; + float z; + }; + float pos[3]; + }; + + Vector3() noexcept + : pos{ 0.0f, 0.0f, 0.0f } + {} + + Vector3(float* position) noexcept + : pos{ position[0], position[1], position[2] } + {} + + Vector3(float x, float y, float z) noexcept + : pos{ x, y, z } + {} + + constexpr inline operator float* () noexcept { return pos; } + constexpr inline operator const float* () const noexcept { return pos; } +}; diff --git a/AmeisenNavigation.Exporter/src/Wow/Adt.hpp b/AmeisenNavigation.Exporter/src/Wow/Adt.hpp new file mode 100644 index 0000000..22e7a96 --- /dev/null +++ b/AmeisenNavigation.Exporter/src/Wow/Adt.hpp @@ -0,0 +1,262 @@ +#pragma once + +#include "Mver.hpp" + +constexpr auto TILESIZE = 533.33333f; +constexpr auto CHUNKSIZE = TILESIZE / 16.0f; +constexpr auto UNITSIZE = CHUNKSIZE / 8.0f; +constexpr auto HALFUNITSIZE = UNITSIZE / 2.0f; + +constexpr auto ADT_CELLS_PER_GRID = 16; +constexpr auto ADT_CELL_SIZE = 8; +constexpr auto ADT_GRID_SIZE = ADT_CELLS_PER_GRID * ADT_CELL_SIZE; + +struct MCIN +{ + unsigned char magic[4]; + unsigned int size; + + struct + { + unsigned int offsetMcnk; + unsigned int size; + unsigned int flags; + unsigned int asyncId; + } cells[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; +}; + +enum class AdtLiquidVertexFormat : unsigned short +{ + HeightDepth = 0, + HeightTextureCoord = 1, + Depth = 2, +}; + +struct AdtLiquid +{ + unsigned short type; + AdtLiquidVertexFormat vertexFormat; + float minHeightLevel; + float maxHeightLevel; + unsigned char offsetX; + unsigned char offsetY; + unsigned char width; + unsigned char height; + unsigned int offsetExistsBitmap; + unsigned int offsetVertexData; +}; + +struct AdtLiquidAttributes +{ + unsigned long long fishable; + unsigned long long deep; +}; + +class MH2O +{ +public: + unsigned char magic[4]; + unsigned int size; + + struct + { + unsigned int offsetInstances; + unsigned int used; + unsigned int offsetAttributes; + } liquid[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; + + inline AdtLiquid* GetInstance(unsigned int x, unsigned int y) noexcept + { + if (liquid[x][y].used && liquid[x][y].offsetInstances) + { + return reinterpret_cast(reinterpret_cast(this) + 8 + liquid[x][y].offsetInstances); + } + + return nullptr; + } + + inline AdtLiquidAttributes* GetAttributes(unsigned int x, unsigned int y) noexcept + { + if (liquid[x][y].used) + { + if (liquid[x][y].offsetAttributes) + { + return reinterpret_cast(reinterpret_cast(this) + 8 + liquid[x][y].offsetAttributes); + } + + static AdtLiquidAttributes all{ 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF }; + return &all; + } + + return nullptr; + } + + inline unsigned long long GetExistsBitmap(AdtLiquid* h) noexcept + { + return h->offsetExistsBitmap ? *reinterpret_cast(reinterpret_cast(this) + 8 + h->offsetExistsBitmap) + : 0xFFFFFFFFFFFFFFFFuLL; + } +}; + +struct MCVT +{ + unsigned char magic[4]; + unsigned int size; + float heightMap[(9 * 9) + (8 * 8)]; +}; + +struct MCNK +{ + unsigned char magic[4]; + unsigned int size; + unsigned int flags; + unsigned int ix; + unsigned int iy; + unsigned int nLayers; + unsigned int nDoodadRefs; + unsigned int offsMcvt; + unsigned int offsMcnr; + unsigned int offsMcly; + unsigned int offsMcrf; + unsigned int offsMcal; + unsigned int sizeMcal; + unsigned int offsMcsh; + unsigned int sizeMcsh; + unsigned int areaid; + unsigned int nMapObjRefs; + unsigned int holes; + unsigned short s[2]; + unsigned int data[3]; + unsigned int predTex; + unsigned int nEffectDoodad; + unsigned int offsMCcse; + unsigned int nSndEmitters; + unsigned int offsMclq; + unsigned int sizeMclq; + float x; + float y; + float z; + unsigned int offsMccv; + unsigned int props; + unsigned int effectId; +}; + +struct MHDR +{ + unsigned char magic[4]; + unsigned int size; + unsigned int flags; + unsigned int offsetMcin; + unsigned int offsetMtex; + unsigned int offsetMmdx; + unsigned int offsetMmid; + unsigned int offsetMwmo; + unsigned int offsetMwid; + unsigned int offsetMddf; + unsigned int offsetModf; + unsigned int offsetMfbo; + unsigned int offsetMh2o; + unsigned int data[5]; +}; + +class Adt +{ + unsigned char* Data; + +public: + + Adt(unsigned char* data) noexcept + : Data(data) + {} + + ~Adt() noexcept + { + if (Data) free(Data); + } + + inline MVER* Mver() noexcept { return reinterpret_cast(Data); }; + inline MHDR* Mhdr() noexcept { return reinterpret_cast(Data + sizeof(MVER)); }; + + inline MCIN* Mcin() noexcept + { + unsigned int offset = Mhdr()->offsetMcin; + return offset ? reinterpret_cast(Data + sizeof(MVER) + 8 + offset) : nullptr; + }; + + inline MH2O* Mh2o() noexcept + { + unsigned int offset = Mhdr()->offsetMh2o; + return offset ? reinterpret_cast(Data + sizeof(MVER) + 8 + offset) : nullptr; + }; + + inline MCNK* Mcnk(unsigned int x, unsigned int y) noexcept + { + unsigned int offset = Mcin()->cells[x][y].offsetMcnk; + return offset ? reinterpret_cast(Data + offset) : nullptr; + }; + + inline MCVT* Mcvt(MCNK* mcnk) noexcept + { + unsigned int offset = mcnk->offsMcvt; + return offset ? reinterpret_cast(reinterpret_cast(mcnk) + offset) : nullptr; + }; + + inline void GetTerrainVertsAndTris(unsigned int x, unsigned int y, std::vector& vertexes, std::vector& tris) noexcept + { + if (MCNK* mcnk = Mcnk(x, y)) + { + // heightMap index, 0 - 144 + int mcvtIndex = 0; + + for (int j = 0; j < 17; ++j) // 17 total row count (9 + 8) + { + // how many units are in this row (this alternates 9, 8, 9, 8, ..., 9) + const int unitCount = j % 2 ? 8 : 9; + + for (int i = 0; i < unitCount; ++i) + { + // chunk offset - unit offset + Vector3 v3{ mcnk->x - (j * HALFUNITSIZE), mcnk->y - (i * UNITSIZE), mcnk->z }; + + // add the heightMap offset if there is one + if (MCVT* mcvt = Mcvt(mcnk)) + { + v3.z += mcvt->heightMap[mcvtIndex]; + } + + mcvtIndex++; + + vertexes.emplace_back(v3); + + if (unitCount == 8) + { + // shift the inner row by HALFUNITSIZE + v3.y -= HALFUNITSIZE; + + // check for holes in the inner grid, if there is no hole, generate tris + if (!mcnk->holes || !((mcnk->holes & 0x0000FFFFu) & ((1 << (i / 2)) << ((j / 4) << 2)))) + { + int vertexCount = vertexes.size(); + tris.emplace_back(Tri{ vertexCount - 9, vertexCount, vertexCount - 8 }); // Top + tris.emplace_back(Tri{ vertexCount + 9, vertexCount, vertexCount + 8 }); // Bottom + tris.emplace_back(Tri{ vertexCount - 8, vertexCount, vertexCount + 9 }); // Right + tris.emplace_back(Tri{ vertexCount + 8, vertexCount, vertexCount - 9 }); // Left + } + } + } + } + } + } + + inline void GetLiquidVertsAndTris(unsigned int x, unsigned int y, std::vector& vertexes, std::vector& tris) noexcept + { + if (MH2O* mh2o = Mh2o()) + { + if (AdtLiquid* liquid = mh2o->GetInstance(x, y)) + { + AdtLiquidAttributes* attributes = mh2o->GetAttributes(x, y); + unsigned long long existBitmap = mh2o->GetExistsBitmap(liquid); + } + } + } +}; diff --git a/AmeisenNavigation.Exporter/src/Wow/LiquidType.hpp b/AmeisenNavigation.Exporter/src/Wow/LiquidType.hpp new file mode 100644 index 0000000..d58659c --- /dev/null +++ b/AmeisenNavigation.Exporter/src/Wow/LiquidType.hpp @@ -0,0 +1,9 @@ +#pragma once + +enum class LiquidType : char +{ + WATER = 0, + OCEAN = 1, + MAGMA = 2, + SLIME = 3 +}; diff --git a/AmeisenNavigation.Exporter/src/Wow/Mver.hpp b/AmeisenNavigation.Exporter/src/Wow/Mver.hpp new file mode 100644 index 0000000..92f0752 --- /dev/null +++ b/AmeisenNavigation.Exporter/src/Wow/Mver.hpp @@ -0,0 +1,8 @@ +#pragma once + +struct MVER +{ + unsigned char magic[4]; + unsigned int size; + unsigned int version; +}; diff --git a/AmeisenNavigation.Exporter/src/Wow/Wdt.hpp b/AmeisenNavigation.Exporter/src/Wow/Wdt.hpp new file mode 100644 index 0000000..75c67f0 --- /dev/null +++ b/AmeisenNavigation.Exporter/src/Wow/Wdt.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "Mver.hpp" + +constexpr auto WDT_MAP_SIZE = 64; + +struct MPHD +{ + unsigned char magic[4]; + unsigned int size; + unsigned int data[8]; +}; + +struct MAIN +{ + unsigned char magic[4]; + unsigned int size; + + struct AdtData + { + unsigned int exists; + unsigned int data; + } adt[64][64]; +}; + +class Wdt +{ + unsigned char* Data; + +public: + + Wdt(unsigned char* data) noexcept + : Data(data) + {} + + ~Wdt() noexcept + { + if (Data) free(Data); + } + + inline MVER* Mver() noexcept { return reinterpret_cast(Data); }; + inline MPHD* Mphd() noexcept { return reinterpret_cast(Data + sizeof(MVER)); }; + inline MAIN* Main() noexcept { return reinterpret_cast(Data + sizeof(MVER) + sizeof(MPHD)); }; +}; diff --git a/AmeisenNavigation.Server/src/Main.cpp b/AmeisenNavigation.Server/src/Main.cpp index 49087f3..a37a507 100644 --- a/AmeisenNavigation.Server/src/Main.cpp +++ b/AmeisenNavigation.Server/src/Main.cpp @@ -100,6 +100,8 @@ int __cdecl main(int argc, const char* argv[]) Server->AddCallback(static_cast(MessageType::EXPLORE_POLY), ExplorePolyCallback); + Server->AddCallback(static_cast(MessageType::CONFIGURE_FILTER), ConfigureFilterCallback); + LogS("Starting server on: ", Config->ip, ":", std::to_string(Config->port)); Server->Run(); @@ -277,3 +279,22 @@ void ExplorePolyCallback(ClientHandler* handler, char type, const void* data, in path.pointCount = 0; pathMisc.pointCount = 0; } + +void ConfigureFilterCallback(ClientHandler* handler, char type, const void* data, int size) noexcept +{ + bool result = true; + const ConfigureFilterData request = *reinterpret_cast(data); + + AmeisenNavClient* client = Nav->GetClient(handler->GetId()); + client->ResetQueryFilter(); + + const FilterConfig* filterConfigs = &request.firstFilterConfig; + + for (size_t i = 0; i < request.filterConfigCount; ++i) + { + client->ConfigureQueryFilter(filterConfigs[i].areaId, filterConfigs[i].cost); + } + + client->UpdateQueryFilter(request.state); + handler->SendData(type, &result, sizeof(bool)); +} diff --git a/AmeisenNavigation.Server/src/Main.hpp b/AmeisenNavigation.Server/src/Main.hpp index a80a3dc..3963e2a 100644 --- a/AmeisenNavigation.Server/src/Main.hpp +++ b/AmeisenNavigation.Server/src/Main.hpp @@ -11,7 +11,7 @@ #include #include -constexpr auto AMEISENNAV_VERSION = "1.8.3.2"; +constexpr auto AMEISENNAV_VERSION = "1.8.4.0"; enum class MessageType { @@ -22,6 +22,7 @@ enum class MessageType CAST_RAY, // Cast a movement ray to test for obstacles RANDOM_PATH, // Generate a straight path where the nodes get offsetted by a random value EXPLORE_POLY, // Generate a route to explore the polygon (W.I.P) + CONFIGURE_FILTER, // Cpnfigure the clients dtQueryFilter area costs }; enum class PathType @@ -79,6 +80,19 @@ struct ExplorePolyData Vector3 firstPolyPoint; }; +struct FilterConfig +{ + char areaId; + float cost; +}; + +struct ConfigureFilterData +{ + ClientState state; + int filterConfigCount; + FilterConfig firstFilterConfig; +}; + inline AnTcpServer* Server = nullptr; inline AmeisenNavigation* Nav = nullptr; inline AmeisenNavConfig* Config = nullptr; @@ -101,6 +115,8 @@ void RandomPointAroundCallback(ClientHandler* handler, char type, const void* da void ExplorePolyCallback(ClientHandler* handler, char type, const void* data, int size) noexcept; +void ConfigureFilterCallback(ClientHandler* handler, char type, const void* data, int size) noexcept; + inline void HandlePathFlagsAndSendData(ClientHandler* handler, int mapId, int flags, Path& path, Path& smoothPath, char type, PathType pathType) noexcept { Path* pathToSend = &path; diff --git a/AmeisenNavigation.Tester/MainWindow.xaml b/AmeisenNavigation.Tester/MainWindow.xaml index cac3dd3..2d5ce85 100644 --- a/AmeisenNavigation.Tester/MainWindow.xaml +++ b/AmeisenNavigation.Tester/MainWindow.xaml @@ -7,10 +7,10 @@ mc:Ignorable="d" Title="AmeisenNavigation Tester" Height="450" Width="900" MinHeight="450" MinWidth="900" Loaded="Window_Loaded"> -