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'
This commit is contained in:
Kawe Mazidjatari 2022-03-18 03:14:07 +01:00
parent 9f24bc01b0
commit 35ad8554a5
14 changed files with 200 additions and 24 deletions

View File

@ -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();

View File

@ -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);
}

View File

@ -0,0 +1,4 @@
#pragma once
void CAI_Utility_Attach();
void CAI_Utility_Detach();

View File

@ -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);

View File

@ -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<dtMeshTile*>(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<int> 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);
}
}
//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<dtMeshTile*>(tile));
// fwrite(tile->data, tile->dataSize, 1, fp);
// if (*is_tf2)patch_tiletf2(const_cast<dtMeshTile*>(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<int> 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);
//}

View File

@ -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;
};

View File

@ -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));

View File

@ -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);

View File

@ -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;

View File

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

View File

@ -65,7 +65,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/D DEDICATED /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>/D GAMESDK /D DEDICATED /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>core\stdafx.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -94,7 +94,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/D DEDICATED /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>/D GAMESDK /D DEDICATED /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>core\stdafx.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
@ -158,6 +158,8 @@
<ClInclude Include="..\game\server\ai_network.h" />
<ClInclude Include="..\game\server\ai_networkmanager.h" />
<ClInclude Include="..\game\server\ai_node.h" />
<ClInclude Include="..\game\server\ai_utility.h" />
<ClInclude Include="..\game\server\detour_impl.h" />
<ClInclude Include="..\game\server\fairfight_impl.h" />
<ClInclude Include="..\game\server\gameinterface.h" />
<ClInclude Include="..\launcher\IApplication.h" />
@ -368,6 +370,7 @@
<ClCompile Include="..\engine\sys_engine.cpp" />
<ClCompile Include="..\engine\sys_utils.cpp" />
<ClCompile Include="..\game\server\ai_networkmanager.cpp" />
<ClCompile Include="..\game\server\ai_utility.cpp" />
<ClCompile Include="..\game\server\gameinterface.cpp" />
<ClCompile Include="..\launcher\IApplication.cpp" />
<ClCompile Include="..\launcher\prx.cpp" />

View File

@ -786,6 +786,12 @@
<ClInclude Include="..\engine\gl_matsysiface.h">
<Filter>sdk\engine</Filter>
</ClInclude>
<ClInclude Include="..\game\server\detour_impl.h">
<Filter>sdk\game\server</Filter>
</ClInclude>
<ClInclude Include="..\game\server\ai_utility.h">
<Filter>sdk\game\server</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\client\IVEngineClient.cpp">
@ -977,6 +983,9 @@
<ClCompile Include="..\engine\modelloader.cpp">
<Filter>sdk\engine</Filter>
</ClCompile>
<ClCompile Include="..\game\server\ai_utility.cpp">
<Filter>sdk\game\server</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\Dedicated.def" />

View File

@ -45,6 +45,7 @@
<ClCompile Include="..\gameui\IConsole.cpp" />
<ClCompile Include="..\gameui\IBrowser.cpp" />
<ClCompile Include="..\game\server\ai_networkmanager.cpp" />
<ClCompile Include="..\game\server\ai_utility.cpp" />
<ClCompile Include="..\game\server\gameinterface.cpp" />
<ClCompile Include="..\inputsystem\inputsystem.cpp" />
<ClCompile Include="..\launcher\IApplication.cpp" />
@ -142,6 +143,8 @@
<ClInclude Include="..\game\server\ai_network.h" />
<ClInclude Include="..\game\server\ai_networkmanager.h" />
<ClInclude Include="..\game\server\ai_node.h" />
<ClInclude Include="..\game\server\ai_utility.h" />
<ClInclude Include="..\game\server\detour_impl.h" />
<ClInclude Include="..\game\server\fairfight_impl.h" />
<ClInclude Include="..\game\server\gameinterface.h" />
<ClInclude Include="..\inputsystem\ButtonCode.h" />
@ -422,7 +425,7 @@
</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C>
<AdditionalOptions>/D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>/D GAMESDK /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -462,7 +465,7 @@
<CreateHotpatchableImage>
</CreateHotpatchableImage>
<WholeProgramOptimization>true</WholeProgramOptimization>
<AdditionalOptions>/D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions>/D GAMESDK /D _CRT_SECURE_NO_WARNINGS %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>

View File

@ -393,6 +393,9 @@
<ClCompile Include="..\materialsystem\materialsystem.cpp">
<Filter>sdk\materialsystem</Filter>
</ClCompile>
<ClCompile Include="..\game\server\ai_utility.cpp">
<Filter>sdk\game\server</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\client\cdll_engine_int.h">
@ -1130,6 +1133,12 @@
<ClInclude Include="..\engine\gl_matsysiface.h">
<Filter>sdk\engine</Filter>
</ClInclude>
<ClInclude Include="..\game\server\detour_impl.h">
<Filter>sdk\game\server</Filter>
</ClInclude>
<ClInclude Include="..\game\server\ai_utility.h">
<Filter>sdk\game\server</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="..\shared\resource\lockedserver.png">