From 35ad8554a58d6b3971116f589ad85df6e2abe162 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Fri, 18 Mar 2022 03:14:07 +0100 Subject: [PATCH] Somewhat correct working navmesh The reachability table needs to be figured out still. The issue should be very small, but at the moment I do not have time for it. The pointer to the table, and table pointers to data is correct, however, not a single poly is ever getting marked as 'reachable' (0xffffffff). This could be either within recast itself (see build_link_table() and set_reachable() functions), or the way the engine parses the data. The function that determines whether poly is reachable is located at '0x140F448E0' --- r5dev/core/init.cpp | 6 ++ r5dev/game/server/ai_utility.cpp | 37 +++++++ r5dev/game/server/ai_utility.h | 4 + r5dev/game/server/detour_impl.h | 33 +++++++ r5dev/naveditor/Sample.cpp | 97 ++++++++++++++++--- .../recast/Detour/Include/DetourNavMesh.h | 6 +- .../recast/Detour/Source/DetourNavMesh.cpp | 3 +- r5dev/tier0/IConVar.cpp | 3 +- r5dev/tier0/cvar.cpp | 2 + r5dev/tier0/cvar.h | 1 + r5dev/vproj/dedicated.vcxproj | 7 +- r5dev/vproj/dedicated.vcxproj.filters | 9 ++ r5dev/vproj/gamesdk.vcxproj | 7 +- r5dev/vproj/gamesdk.vcxproj.filters | 9 ++ 14 files changed, 200 insertions(+), 24 deletions(-) create mode 100644 r5dev/game/server/ai_utility.cpp create mode 100644 r5dev/game/server/ai_utility.h create mode 100644 r5dev/game/server/detour_impl.h diff --git a/r5dev/core/init.cpp b/r5dev/core/init.cpp index fcf184a5..71b861e1 100644 --- a/r5dev/core/init.cpp +++ b/r5dev/core/init.cpp @@ -66,6 +66,8 @@ #include "game/server/ai_node.h" #include "game/server/ai_network.h" #include "game/server/ai_networkmanager.h" +#include "game/server/ai_utility.h" +#include "game/server/detour_impl.h" #include "game/server/fairfight_impl.h" #include "game/server/gameinterface.h" #include "public/include/edict.h" @@ -146,7 +148,9 @@ void Systems_Init() #ifndef DEDICATED HCVideoMode_Common_Attach(); + //DebugOverlays_Attach(); #endif // !DEDICATED + CAI_Utility_Attach(); // Patch instructions RuntimePtc_Init(); @@ -235,7 +239,9 @@ void Systems_Shutdown() #ifndef DEDICATED HCVideoMode_Common_Detach(); + //DebugOverlays_Detach(); #endif // !DEDICATED + CAI_Utility_Detach(); // Commit the transaction DetourTransactionCommit(); diff --git a/r5dev/game/server/ai_utility.cpp b/r5dev/game/server/ai_utility.cpp new file mode 100644 index 00000000..13121e21 --- /dev/null +++ b/r5dev/game/server/ai_utility.cpp @@ -0,0 +1,37 @@ +//=============================================================================// +// +// Purpose: AI system utility +// +//=============================================================================// + +#include "core/stdafx.h" +#include "tier0/cvar.h" +#include "game/server/detour_impl.h" + +//----------------------------------------------------------------------------- +// Purpose: determines whether target poly is reachable from current agent poly +// input : *this - +// poly_1 - +// poly_2 - +// hull_type - +// Output : true if reachable, false otherwise +//----------------------------------------------------------------------------- +bool hdtNavMesh__isPolyReachable(dtNavMesh* thisptr, dtPolyRef poly_1, dtPolyRef poly_2, int hull_type) +{ + if (navmesh_always_reachable->GetBool()) + { + return true; + } + return dtNavMesh__isPolyReachable(thisptr, poly_1, poly_2, hull_type); +} + +/////////////////////////////////////////////////////////////////////////////// +void CAI_Utility_Attach() +{ + DetourAttach((LPVOID*)&dtNavMesh__isPolyReachable, &hdtNavMesh__isPolyReachable); +} + +void CAI_Utility_Detach() +{ + DetourDetach((LPVOID*)&dtNavMesh__isPolyReachable, &hdtNavMesh__isPolyReachable); +} \ No newline at end of file diff --git a/r5dev/game/server/ai_utility.h b/r5dev/game/server/ai_utility.h new file mode 100644 index 00000000..763dd12d --- /dev/null +++ b/r5dev/game/server/ai_utility.h @@ -0,0 +1,4 @@ +#pragma once + +void CAI_Utility_Attach(); +void CAI_Utility_Detach(); \ No newline at end of file diff --git a/r5dev/game/server/detour_impl.h b/r5dev/game/server/detour_impl.h new file mode 100644 index 00000000..a1d207a6 --- /dev/null +++ b/r5dev/game/server/detour_impl.h @@ -0,0 +1,33 @@ +#pragma once +#include "thirdparty/recast/detour/include/detourstatus.h" +#include "thirdparty/recast/detour/include/detournavmesh.h" + +namespace +{ + //------------------------------------------------------------------------- + // RUNTIME: DETOUR + //------------------------------------------------------------------------- + ADDRESS p_dtNavMesh__Init = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x4C\x89\x44\x24\x00\x53\x41\x56\x48\x81\xEC\x00\x00\x00\x00\x0F\x10\x11", "xxxx?xxxxxx????xxx"); + dtStatus (*dtNavMesh__Init)(dtNavMesh* thisptr, unsigned char* data, int flags) = (dtStatus(*)(dtNavMesh*, unsigned char*, int))p_dtNavMesh__Init.GetPtr(); /*4C 89 44 24 ? 53 41 56 48 81 EC ? ? ? ? 0F 10 11*/ + + ADDRESS p_dtNavMesh__addTile = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x44\x89\x4C\x24\x00\x41\x55", "xxxx?xx");/*44 89 4C 24 ? 41 55*/ + dtStatus(*dtNavMesh__addTile)(dtNavMesh* thisptr, unsigned char* data, dtMeshHeader* header, int datasize, int flags, dtTileRef lastRef) = (dtStatus(*)(dtNavMesh*, unsigned char*, dtMeshHeader*, int, int, dtTileRef))p_dtNavMesh__addTile.GetPtr(); + + ADDRESS p_dtNavMesh__isPolyReachable = g_mGameDll.FindPatternSIMD((std::uint8_t*)"\x48\x89\x6C\x24\x00\x48\x89\x74\x24\x00\x48\x89\x7C\x24\x00\x41\x56\x49\x63\xF1", "xxxx?xxxx?xxxx?xxxxx"); /*48 89 6C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 56 49 63 F1*/ + bool(*dtNavMesh__isPolyReachable)(dtNavMesh* thisptr, dtPolyRef poly_1, dtPolyRef poly_2, int hull_type) = (bool(*)(dtNavMesh*, dtPolyRef, dtPolyRef, int))p_dtNavMesh__isPolyReachable.GetPtr(); +} + +/////////////////////////////////////////////////////////////////////////////// +class HRecast : public IDetour +{ + virtual void debugp() + { + std::cout << "| FUN: dtNavMesh::Init : 0x" << std::hex << std::uppercase << p_dtNavMesh__Init.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: dtNavMesh::addTile : 0x" << std::hex << std::uppercase << p_dtNavMesh__addTile.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "| FUN: dtNavMesh::isPolyReachable : 0x" << std::hex << std::uppercase << p_dtNavMesh__isPolyReachable.GetPtr() << std::setw(npad) << " |" << std::endl; + std::cout << "+----------------------------------------------------------------+" << std::endl; + } +}; +/////////////////////////////////////////////////////////////////////////////// + +REGISTER(HRecast); diff --git a/r5dev/naveditor/Sample.cpp b/r5dev/naveditor/Sample.cpp index e8ba0ea6..cbcc9ae4 100644 --- a/r5dev/naveditor/Sample.cpp +++ b/r5dev/naveditor/Sample.cpp @@ -656,13 +656,8 @@ void Sample::saveAll(std::string path, dtNavMesh* mesh) header.numTiles++; } memcpy(&header.params, mesh->getParams(), sizeof(dtNavMeshParams)); - - link_table_data link_data; - build_link_table(mesh, link_data); - int table_size = ((link_data.set_count + 31) / 32) * link_data.set_count * 32; - header.params.disjoint_poly_group_count = link_data.set_count; - header.params.reachability_table_count = m_count_reachability_tables; - header.params.reachability_table_size = table_size; + header.params.disjoint_poly_group_count = 3; + header.params.reachability_table_size = ((header.params.disjoint_poly_group_count + 31) / 32) * header.params.disjoint_poly_group_count * 32; if (*is_tf2)unpatch_headertf2(header); fwrite(&header, sizeof(NavMeshSetHeader), 1, fp); @@ -683,15 +678,85 @@ void Sample::saveAll(std::string path, dtNavMesh* mesh) if (*is_tf2)patch_tiletf2(const_cast(tile)); } - //still dont know what this thing is... - int header_sth = 0; - for (int i = 0; i < link_data.set_count; i++) - fwrite(&header_sth, sizeof(int), 1, fp); + int header_sth[3] = { 0,0,0 }; + fwrite(header_sth, sizeof(int), 3, fp); + unsigned int reachability[32 * 3]; + for (int i = 0; i < 32 * 3; i++) + reachability[i] = 0xffffffff; - std::vector reachability(table_size, 0); - for (int i = 0; i < link_data.set_count; i++) - set_reachable(reachability, link_data.set_count, i, i, true); for (int i = 0; i < header.params.reachability_table_count; i++) - fwrite(reachability.data(), sizeof(int), (table_size / 4), fp); + fwrite(reachability, sizeof(int), (header.params.reachability_table_size / 4), fp); fclose(fp); -} \ No newline at end of file +} + +//void Sample::saveAll(std::string path, dtNavMesh* mesh) +//{ +// if (!mesh) return; +// +// std::filesystem::path p = "..\\maps\\navmesh\\"; +// +// if (std::filesystem::is_directory(p)) +// { +// path.insert(0, p.string()); +// } +// +// char buffer[256]; +// sprintf(buffer, "%s_%s.nm", path.c_str(), m_navmesh_name); +// +// FILE* fp = fopen(buffer, "wb"); +// if (!fp) +// return; +// +// // Store header. +// NavMeshSetHeader header; +// header.magic = NAVMESHSET_MAGIC; +// header.version = NAVMESHSET_VERSION; +// header.numTiles = 0; +// +// for (int i = 0; i < mesh->getMaxTiles(); ++i) +// { +// dtMeshTile* tile = mesh->getTile(i); +// if (!tile || !tile->header || !tile->dataSize) continue; +// header.numTiles++; +// } +// memcpy(&header.params, mesh->getParams(), sizeof(dtNavMeshParams)); +// header.params.disjoint_poly_group_count = 3; +// +// link_table_data link_data; +// build_link_table(mesh, link_data); +// int table_size = ((link_data.set_count + 31) / 32) * link_data.set_count * 32; +// header.params.disjoint_poly_group_count = link_data.set_count; +// header.params.reachability_table_count = m_count_reachability_tables; +// header.params.reachability_table_size = table_size; +// +// if (*is_tf2)unpatch_headertf2(header); +// fwrite(&header, sizeof(NavMeshSetHeader), 1, fp); +// +// // Store tiles. +// for (int i = 0; i < mesh->getMaxTiles(); ++i) +// { +// dtMeshTile* tile = mesh->getTile(i); +// if (!tile || !tile->header || !tile->dataSize) continue; +// +// NavMeshTileHeader tileHeader; +// tileHeader.tileRef = mesh->getTileRef(tile); +// tileHeader.dataSize = tile->dataSize; +// fwrite(&tileHeader, sizeof(tileHeader), 1, fp); +// +// if (*is_tf2)unpatch_tiletf2(const_cast(tile)); +// fwrite(tile->data, tile->dataSize, 1, fp); +// if (*is_tf2)patch_tiletf2(const_cast(tile)); +// } +// +// //still dont know what this thing is... +// int header_sth = 0; +// for (int i = 0; i < link_data.set_count; i++) +// fwrite(&header_sth, sizeof(int), 1, fp); +// +// std::vector reachability(table_size, 0); +// for (int i = 0; i < link_data.set_count; i++) +// set_reachable(reachability, link_data.set_count, i, i, true); +// for (int i = 0; i < header.params.reachability_table_count; i++) +// fwrite(reachability.data(), sizeof(int), (table_size / 4), fp); +// fclose(fp); +//} \ No newline at end of file diff --git a/r5dev/thirdparty/recast/Detour/Include/DetourNavMesh.h b/r5dev/thirdparty/recast/Detour/Include/DetourNavMesh.h index 132c5600..aec4fe87 100644 --- a/r5dev/thirdparty/recast/Detour/Include/DetourNavMesh.h +++ b/r5dev/thirdparty/recast/Detour/Include/DetourNavMesh.h @@ -19,8 +19,11 @@ #ifndef DETOURNAVMESH_H #define DETOURNAVMESH_H +// Only use types for function prototypes +#ifndef GAMESDK #include "Detour/Include/DetourAlloc.h" #include "Detour/Include/DetourStatus.h" +#endif // !GAMESDK // Undefine (or define in a build cofnig) the following line to use 64bit polyref. // Generally not needed, useful for very large worlds. @@ -176,7 +179,7 @@ struct dtPoly unsigned short link_table_idx; //IDK but looks filled unsigned short unk; //IDK but looks filled - int unk1; //!TODO: debug this if you ever find where this gets used in the engine.. + unsigned int unk1; //!TODO: debug this if you ever find where this gets used in the engine.. float org[3]; // Seems to be used for AIN file generation (build from large navmesh). /// Sets the user defined area id. [Limit: < #DT_MAX_AREAS] @@ -695,7 +698,6 @@ private: unsigned int m_saltBits; ///< Number of salt bits in the tile ID. unsigned int m_tileBits; ///< Number of tile bits in the tile ID. unsigned int m_polyBits; ///< Number of poly bits in the tile ID. - int unk1 = -1; ///< Unknown. #endif friend class dtNavMeshQuery; }; diff --git a/r5dev/thirdparty/recast/Detour/Source/DetourNavMesh.cpp b/r5dev/thirdparty/recast/Detour/Source/DetourNavMesh.cpp index d85974c2..dee4ec99 100644 --- a/r5dev/thirdparty/recast/Detour/Source/DetourNavMesh.cpp +++ b/r5dev/thirdparty/recast/Detour/Source/DetourNavMesh.cpp @@ -225,7 +225,6 @@ dtStatus dtNavMesh::init(const dtNavMeshParams* params) { memcpy(&m_params, params, sizeof(dtNavMeshParams)); dtVcopy(m_orig, params->orig); - unk0 = params->orig[2]; m_tileWidth = params->tileWidth; m_tileHeight = params->tileHeight; @@ -252,6 +251,8 @@ dtStatus dtNavMesh::init(const dtNavMeshParams* params) m_nextFree = &m_tiles[i]; } + unk0 = dtIlog2(dtNextPow2((unsigned int)params[1].orig[0])); + // Init ID generator values. #ifndef DT_POLYREF64 m_tileBits = dtIlog2(dtNextPow2((unsigned int)params->maxTiles)); diff --git a/r5dev/tier0/IConVar.cpp b/r5dev/tier0/IConVar.cpp index ba874e94..26048b12 100644 --- a/r5dev/tier0/IConVar.cpp +++ b/r5dev/tier0/IConVar.cpp @@ -55,7 +55,8 @@ void ConVar::Init(void) const rcon_password = new ConVar("rcon_password", "" , FCVAR_SERVER_CANNOT_QUERY | FCVAR_DONTRECORD | FCVAR_RELEASE, "Remote server access password (rcon is disabled if empty).", false, 0.f, false, 0.f, nullptr, nullptr); //------------------------------------------------------------------------- // SERVER | - ai_dumpAINfileFromLoad = new ConVar("ai_dumpAINfileFromLoad" , "0", FCVAR_DEVELOPMENTONLY, "Dumps AIN data from node graphs loaded from the disk on load.", false, 0.f, false, 0.f, nullptr, nullptr); + ai_dumpAINfileFromLoad = new ConVar("ai_dumpAINfileFromLoad" , "0", FCVAR_DEVELOPMENTONLY, "Dumps AIN data from node graphs loaded from the disk on load.", false, 0.f, false, 0.f, nullptr, nullptr); + navmesh_always_reachable = new ConVar("navmesh_always_reachable" , "1", FCVAR_DEVELOPMENTONLY, "Marks poly from agent to target on navmesh as reachable regardless of table data ( !slower! ).", false, 0.f, false, 0.f, nullptr, nullptr); // !TODO: Default to '0' once the reachability table gets properly parsed. sv_showconnecting = new ConVar("sv_showconnecting" , "1", FCVAR_RELEASE, "Logs information about the connecting client to the console.", false, 0.f, false, 0.f, nullptr, nullptr); sv_pylonvisibility = new ConVar("sv_pylonvisibility", "0", FCVAR_RELEASE, "Determines the visiblity to the Pylon Master Server, 0 = Not visible, 1 = Visible, 2 = Hidden !TODO: not implemented yet.", false, 0.f, false, 0.f, nullptr, nullptr); diff --git a/r5dev/tier0/cvar.cpp b/r5dev/tier0/cvar.cpp index 9b0b853c..b649b9a8 100644 --- a/r5dev/tier0/cvar.cpp +++ b/r5dev/tier0/cvar.cpp @@ -15,6 +15,8 @@ ConVar* rcon_password = nullptr; //----------------------------------------------------------------------------- // SERVER | ConVar* ai_dumpAINfileFromLoad = nullptr; +ConVar* navmesh_always_reachable = nullptr; + ConVar* sv_showconnecting = nullptr; ConVar* sv_pylonvisibility = nullptr; diff --git a/r5dev/tier0/cvar.h b/r5dev/tier0/cvar.h index e9f1761e..90200411 100644 --- a/r5dev/tier0/cvar.h +++ b/r5dev/tier0/cvar.h @@ -27,6 +27,7 @@ extern ConVar* rcon_password; //------------------------------------------------------------------------- // SERVER | extern ConVar* ai_dumpAINfileFromLoad; +extern ConVar* navmesh_always_reachable; extern ConVar* sv_showconnecting; extern ConVar* sv_pylonvisibility; #ifdef DEDICATED diff --git a/r5dev/vproj/dedicated.vcxproj b/r5dev/vproj/dedicated.vcxproj index c9ef7635..beb0bef5 100644 --- a/r5dev/vproj/dedicated.vcxproj +++ b/r5dev/vproj/dedicated.vcxproj @@ -65,7 +65,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - /D DEDICATED /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) + /D GAMESDK /D DEDICATED /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) Use core\stdafx.h stdcpp17 @@ -94,7 +94,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - /D DEDICATED /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) + /D GAMESDK /D DEDICATED /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) Use core\stdafx.h stdcpp17 @@ -158,6 +158,8 @@ + + @@ -368,6 +370,7 @@ + diff --git a/r5dev/vproj/dedicated.vcxproj.filters b/r5dev/vproj/dedicated.vcxproj.filters index c24a460c..f1a90b75 100644 --- a/r5dev/vproj/dedicated.vcxproj.filters +++ b/r5dev/vproj/dedicated.vcxproj.filters @@ -786,6 +786,12 @@ sdk\engine + + sdk\game\server + + + sdk\game\server + @@ -977,6 +983,9 @@ sdk\engine + + sdk\game\server + diff --git a/r5dev/vproj/gamesdk.vcxproj b/r5dev/vproj/gamesdk.vcxproj index d714f9aa..454e8db5 100644 --- a/r5dev/vproj/gamesdk.vcxproj +++ b/r5dev/vproj/gamesdk.vcxproj @@ -45,6 +45,7 @@ + @@ -142,6 +143,8 @@ + + @@ -422,7 +425,7 @@ stdcpp17 stdc17 - /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) + /D GAMESDK /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) Windows @@ -462,7 +465,7 @@ true - /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) + /D GAMESDK /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions) Windows diff --git a/r5dev/vproj/gamesdk.vcxproj.filters b/r5dev/vproj/gamesdk.vcxproj.filters index 0ea3e491..40816054 100644 --- a/r5dev/vproj/gamesdk.vcxproj.filters +++ b/r5dev/vproj/gamesdk.vcxproj.filters @@ -393,6 +393,9 @@ sdk\materialsystem + + sdk\game\server + @@ -1130,6 +1133,12 @@ sdk\engine + + sdk\game\server + + + sdk\game\server +