Fix AIN building bugs

Fixed writing of:
- Path nodes
- Node links
- Path clusters
- Cluster links

The previous globals 'g_pppAiNodeClusters' and 'g_pppAiNodeClusterLinks' were of type CUtlVector. These have been retyped and renamed accordingly.

Also mapped the CAI_Cluster class out slightly more.
Rebuild of path clusters and cluster links are still not correct; parsing a file in from r2, results in a different file on the disk, at the very offset the clusters are being written in (one field is off, this will be investigated soon).
This commit is contained in:
Kawe Mazidjatari 2023-08-24 23:44:57 +02:00
parent c21747c4c6
commit 52bc73abb0
5 changed files with 160 additions and 63 deletions

View File

@ -123,6 +123,28 @@ CAI_Node** CAI_Network::GetPathNodes(void) const
return m_pAInode;
}
//-----------------------------------------------------------------------------
// Purpose: adds a path node
// Input : *origin -
// jaw -
// Output : CAI_Node*
//-----------------------------------------------------------------------------
CAI_Node* CAI_Network::AddPathNode(const Vector3D* origin, const float jaw)
{
return v_CAI_Network__AddPathNode(this, origin, jaw);
}
//-----------------------------------------------------------------------------
// Purpose: creates a node link
// Input : srcID -
// destID -
// Output : CAI_NodeLink*
//-----------------------------------------------------------------------------
CAI_NodeLink* CAI_Network::CreateNodeLink(int srcID, int destID)
{
return v_CAI_Network__CreateNodeLink(this, srcID, destID);
}
//-----------------------------------------------------------------------------
void VAI_Network::Attach() const
{

View File

@ -19,8 +19,12 @@ public:
short GetHint(int nIndex) const;
CAI_ScriptNode* GetScriptNodes(void) const;
CAI_Node* AddPathNode(const Vector3D* origin, const float jaw);
CAI_Node** GetPathNodes(void) const;
CAI_NodeLink* CreateNodeLink(int srcID, int destID);
public:
void* m_pVTable; // <-- 'this'.
@ -45,6 +49,12 @@ public:
};
inline CAI_Network** g_pAINetwork = nullptr;
inline CMemory p_CAI_Network__AddPathNode;
inline CAI_Node*(*v_CAI_Network__AddPathNode)(CAI_Network* pNetwork, const Vector3D* origin, float yaw);
inline CMemory p_CAI_Network__CreateNodeLink;
inline CAI_NodeLink* (*v_CAI_Network__CreateNodeLink)(CAI_Network* pNetwork, int srcID, int destID);
inline CMemory p_CAI_Network__DebugConnectMsg;
inline void(*v_CAI_Network__DebugConnectMsg)(int node1, int node2, const char* pszformat, ...);
@ -53,13 +63,21 @@ class VAI_Network : public IDetour
{
virtual void GetAdr(void) const
{
LogFunAdr("CAI_Network::AddPathNode", p_CAI_Network__AddPathNode.GetPtr());
LogFunAdr("CAI_Network::CreateNodeLink", p_CAI_Network__CreateNodeLink.GetPtr());
LogFunAdr("CAI_Network::DebugConnectMsg", p_CAI_Network__DebugConnectMsg.GetPtr());
LogVarAdr("g_pAINetwork", reinterpret_cast<uintptr_t>(g_pAINetwork));
}
virtual void GetFun(void) const
{
p_CAI_Network__AddPathNode = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 48 8B B9 ?? ?? ?? ?? 48 8B F2 0F 29 74 24 ??");
v_CAI_Network__AddPathNode = p_CAI_Network__AddPathNode.RCast<CAI_Node*(*)(CAI_Network*, const Vector3D*, float)>();
p_CAI_Network__CreateNodeLink = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 55 57 41 56 48 83 EC 20 49 63 E8");
v_CAI_Network__CreateNodeLink = p_CAI_Network__CreateNodeLink.RCast<CAI_NodeLink* (*)(CAI_Network*, int, int)>();
p_CAI_Network__DebugConnectMsg = g_GameDll.FindPatternSIMD("4C 89 4C 24 ?? 48 83 EC 18");
v_CAI_Network__DebugConnectMsg = p_CAI_Network__DebugConnectMsg.RCast<void (*)(int, int, const char*, ...)>(); /*4C 89 4C 24 ?? 48 83 EC 18*/
v_CAI_Network__DebugConnectMsg = p_CAI_Network__DebugConnectMsg.RCast<void (*)(int, int, const char*, ...)>();
}
virtual void GetVar(void) const
{

View File

@ -14,6 +14,7 @@
#include "game/server/ai_node.h"
#include "game/server/ai_network.h"
#include "game/server/ai_networkmanager.h"
#include <public/worldsize.h>
constexpr int AINET_SCRIPT_VERSION_NUMBER = 21;
constexpr int AINET_VERSION_NUMBER = 57;
@ -32,6 +33,47 @@ CAI_NetworkBuilder::BuildFile
*/
void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork)
{
//int test = 0;
//while (pNetwork->m_iNumNodes < 8000)
//{
// Vector3D origin;
// origin.Init(
// RandomFloat(0.0f, MAX_COORD_FLOAT),
// RandomFloat(0.0f, MAX_COORD_FLOAT),
// RandomFloat(0.0f, MAX_COORD_FLOAT));
// /*CAI_Node* pNode = */pNetwork->AddPathNode(&origin, RandomFloat(-180, 180));
// if (test > 0)
// pNetwork->CreateNodeLink(test-1, test);
// CAI_NodeCluster* cluster = new CAI_NodeCluster();
// memset(cluster, '\0', sizeof(CAI_NodeCluster));
// origin.Init(
// RandomFloat(0.0f, MAX_COORD_FLOAT),
// RandomFloat(0.0f, MAX_COORD_FLOAT),
// RandomFloat(0.0f, MAX_COORD_FLOAT));
// cluster->m_nIndex = test;
// cluster->m_vOrigin = origin;
// g_pAINodeClusters->AddToTail(cluster);
// CAI_NodeClusterLink* clusterLink = new CAI_NodeClusterLink();
// memset(clusterLink, '\0', sizeof(CAI_NodeClusterLink));
// clusterLink->prevIndex_MAYBE = (short)test;
// clusterLink->nextIndex_MAYBE = (short)test + 1;
// clusterLink->flags = 4;
// g_pAINodeClusterLinks->AddToTail(clusterLink);
// ++test;
//}
char szMeshPath[MAX_PATH];
char szGraphPath[MAX_PATH];
@ -65,7 +107,7 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork)
FileSystem()->Write(&g_ServerGlobalVariables->m_nMapVersion, sizeof(int), pAIGraph);
FileHandle_t pNavMesh = FileSystem()->Open(szMeshPath, "rb", "GAME");
uint32_t nNavMeshHash = NULL;
uint32_t nNavMeshCRC = NULL;
if (!pNavMesh)
{
@ -80,12 +122,12 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork)
FileSystem()->Read(pBuf.get(), nLen, pNavMesh);
FileSystem()->Close(pNavMesh);
nNavMeshHash = crc32::update(NULL, pBuf.get(), nLen);
nNavMeshCRC = crc32::update(NULL, pBuf.get(), nLen);
}
// Large NavMesh CRC.
DevMsg(eDLL_T::SERVER, " |-- NavMesh CRC: '0x%lX'\n", nNavMeshHash);
FileSystem()->Write(&nNavMeshHash, sizeof(uint32_t), pAIGraph);
DevMsg(eDLL_T::SERVER, " |-- NavMesh CRC: '0x%lX'\n", nNavMeshCRC);
FileSystem()->Write(&nNavMeshCRC, sizeof(uint32_t), pAIGraph);
// Path nodes.
DevMsg(eDLL_T::SERVER, " |-- Node count: '%d'\n", pNetwork->m_iNumNodes);
@ -177,7 +219,7 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork)
diskLink.m_bHulls[k] = nodeLink->m_bHulls[k];
}
DevMsg(eDLL_T::SERVER, " |-- Writing link '%h' => '%h' to '0x%zX'\n", diskLink.m_iSrcID, diskLink.m_iDestID, FileSystem()->Tell(pAIGraph));
DevMsg(eDLL_T::SERVER, " |-- Writing link '%hd' => '%hd' to '0x%zX'\n", diskLink.m_iSrcID, diskLink.m_iDestID, FileSystem()->Tell(pAIGraph));
FileSystem()->Write(&diskLink, sizeof(CAI_NodeLinkDisk), pAIGraph);
}
}
@ -194,7 +236,7 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork)
if (pNetwork->m_iNumNodes > 0)
{
std::unique_ptr<uint32[]> unkNodeBlock(new uint32_t[pNetwork->m_iNumNodes * sizeof(uint32_t)]);
memset(&unkNodeBlock, '\0', pNetwork->m_iNumNodes * sizeof(uint32_t));
memset(unkNodeBlock.get(), '\0', pNetwork->m_iNumNodes * sizeof(uint32_t));
FileSystem()->Write(unkNodeBlock.get(), pNetwork->m_iNumNodes * sizeof(uint32_t), pAIGraph);
}
@ -202,6 +244,7 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork)
// TODO: This is traverse nodes i think? these aren't used in r2 ains so we can get away with just writing count=0 and skipping
// but ideally should actually dump these.
DevMsg(eDLL_T::SERVER, " |-- Writing '%d' traversal nodes at '0x%zX'\n", 0, FileSystem()->Tell(pAIGraph));
short traverseNodeCount = 0; // Only write count since count=0 means we don't have to actually do anything here.
FileSystem()->Write(&traverseNodeCount, sizeof(short), pAIGraph);
@ -218,52 +261,63 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork)
timer.Start();
DevMsg(eDLL_T::SERVER, "+- Writing clusters...\n");
FileSystem()->Write(&*g_nAiNodeClusters, sizeof(*g_nAiNodeClusters), pAIGraph);
for (int i = 0; i < *g_nAiNodeClusters; i++)
const int numClusters = g_pAIPathClusters->Count();
FileSystem()->Write(&numClusters, sizeof(int), pAIGraph);
FOR_EACH_VEC(*g_pAIPathClusters, i)
{
DevMsg(eDLL_T::SERVER, " |-- Writing cluster '#%d' at '0x%zX'\n", i, FileSystem()->Tell(pAIGraph));
AINodeClusters* nodeClusters = (*g_pppAiNodeClusters)[i];
FileSystem()->Write(&nodeClusters->m_nIndex, sizeof(nodeClusters->m_nIndex), pAIGraph);
FileSystem()->Write(&nodeClusters->unk1, sizeof(nodeClusters->unk1), pAIGraph);
const CAI_Cluster* pathClusters = (*g_pAIPathClusters)[i];
FileSystem()->Write(&nodeClusters->m_vOrigin.x, sizeof(nodeClusters->m_vOrigin.x), pAIGraph);
FileSystem()->Write(&nodeClusters->m_vOrigin.y, sizeof(nodeClusters->m_vOrigin.y), pAIGraph);
FileSystem()->Write(&nodeClusters->m_vOrigin.z, sizeof(nodeClusters->m_vOrigin.z), pAIGraph);
FileSystem()->Write(&pathClusters->m_nIndex, sizeof(int), pAIGraph);
FileSystem()->Write(&pathClusters->unk1, sizeof(char), pAIGraph);
FileSystem()->Write(&nodeClusters->unkcount0, sizeof(nodeClusters->unkcount0), pAIGraph);
for (int j = 0; j < nodeClusters->unkcount0; j++)
FileSystem()->Write(&pathClusters->m_vOrigin.x, sizeof(vec_t), pAIGraph);
FileSystem()->Write(&pathClusters->m_vOrigin.y, sizeof(vec_t), pAIGraph);
FileSystem()->Write(&pathClusters->m_vOrigin.z, sizeof(vec_t), pAIGraph);
const int unkVec0Size = pathClusters->unkVec0.Count();
FileSystem()->Write(&unkVec0Size, sizeof(int), pAIGraph);
FOR_EACH_VEC(pathClusters->unkVec0, j)
{
short unk2Short = static_cast<short>(nodeClusters->unk2[j]);
FileSystem()->Write(&unk2Short, sizeof(unk2Short), pAIGraph);
short unkShort = static_cast<short>(pathClusters->unkVec0[j]);
FileSystem()->Write(&unkShort, sizeof(short), pAIGraph);
}
FileSystem()->Write(&nodeClusters->unkcount1, sizeof(nodeClusters->unkcount1), pAIGraph);
for (int j = 0; j < nodeClusters->unkcount1; j++)
const int unkVec1Size = pathClusters->unkVec1.Count();
FileSystem()->Write(&unkVec1Size, sizeof(int), pAIGraph);
FOR_EACH_VEC(pathClusters->unkVec1, j)
{
short unk3Short = static_cast<short>(nodeClusters->unk3[j]);
FileSystem()->Write(&unk3Short, sizeof(unk3Short), pAIGraph);
short unkShort = static_cast<short>(pathClusters->unkVec0[j]);
FileSystem()->Write(&unkShort, sizeof(short), pAIGraph);
}
FileSystem()->Write(&nodeClusters->unk5, sizeof(nodeClusters->unk5), pAIGraph);
FileSystem()->Write(&pathClusters->unk5, sizeof(char), pAIGraph);
}
timer.End();
Msg(eDLL_T::SERVER, "...done writing clusters. %lf seconds (%d clusters)\n", timer.GetDuration().GetSeconds(), *g_nAiNodeClusters);
Msg(eDLL_T::SERVER, "...done writing clusters. %lf seconds (%d clusters)\n", timer.GetDuration().GetSeconds(), numClusters);
timer.Start();
DevMsg(eDLL_T::SERVER, "+- Writing cluster links...\n");
FileSystem()->Write(&*g_nAiNodeClusterLinks, sizeof(*g_nAiNodeClusterLinks), pAIGraph);
for (int i = 0; i < *g_nAiNodeClusterLinks; i++)
const int numClusterLinks = g_pAIClusterLinks->Count();
FileSystem()->Write(&numClusterLinks, sizeof(int), pAIGraph);
FOR_EACH_VEC(*g_pAIClusterLinks, i)
{
// Disk and memory structs are literally identical here so just directly write.
DevMsg(eDLL_T::SERVER, " |-- Writing cluster link '#%d' at '0x%zX'\n", i, FileSystem()->Tell(pAIGraph));
FileSystem()->Write(&*g_pppAiNodeClusterLinks[i], sizeof(*(*g_pppAiNodeClusterLinks)[i]), pAIGraph);
// Disk and memory structs are literally identical here so just directly write.
const CAI_ClusterLink* clusterLink = (*g_pAIClusterLinks)[i];
FileSystem()->Write(clusterLink, sizeof(CAI_ClusterLink), pAIGraph);
}
timer.End();
Msg(eDLL_T::SERVER, "...done writing cluster links. %lf seconds (%d cluster links)\n", timer.GetDuration().GetSeconds(), *g_nAiNodeClusterLinks);
Msg(eDLL_T::SERVER, "...done writing cluster links. %lf seconds (%d cluster links)\n", timer.GetDuration().GetSeconds(), numClusterLinks);
// This is always set to '-1'. Likely a field for maintaining compatibility.
FileSystem()->Write(&pNetwork->unk5, sizeof(pNetwork->unk5), pAIGraph);

View File

@ -27,10 +27,8 @@ inline void*(*CAI_NetworkManager__LoadNetworkGraph)(void* thisptr, void* pBuffer
inline CMemory p_CAI_NetworkBuilder__Build;
inline void*(*CAI_NetworkBuilder__Build)(void* thisptr, CAI_Network* pNetwork, void* a3, int a4);
inline int * g_nAiNodeClusters = nullptr;
inline AINodeClusters *** g_pppAiNodeClusters = nullptr;
inline int * g_nAiNodeClusterLinks = nullptr;
inline AINodeClusterLinks*** g_pppAiNodeClusterLinks = nullptr;
inline CUtlVector<CAI_Cluster*>* g_pAIPathClusters = nullptr;
inline CUtlVector<CAI_ClusterLink*>* g_pAIClusterLinks = nullptr;
//-----------------------------------------------------------------------------
// CAI_NetworkBuilder
@ -68,10 +66,8 @@ class VAI_NetworkManager : public IDetour
LogFunAdr("CAI_NetworkManager::LoadNetworkGraph", p_CAI_NetworkManager__LoadNetworkGraph.GetPtr());
LogFunAdr("CAI_NetworkManager::ShouldRebuild", p_CAI_NetworkManager__ShouldRebuild.GetPtr());
LogFunAdr("CAI_NetworkBuilder::Build", p_CAI_NetworkBuilder__Build.GetPtr());
LogVarAdr("g_nAiNodeClusters", reinterpret_cast<uintptr_t>(g_nAiNodeClusters));
LogVarAdr("g_pAiNodeClusters", reinterpret_cast<uintptr_t>(g_pppAiNodeClusters));
LogVarAdr("g_nAiNodeClusterLinks", reinterpret_cast<uintptr_t>(g_nAiNodeClusterLinks));
LogVarAdr("g_pAiNodeClusterLinks", reinterpret_cast<uintptr_t>(g_pppAiNodeClusterLinks));
LogVarAdr("g_AIPathClusters< CAI_Cluster* >", reinterpret_cast<uintptr_t>(g_pAIPathClusters));
LogVarAdr("g_AIClusterLinks< CAI_ClusterLink* >", reinterpret_cast<uintptr_t>(g_pAIClusterLinks));
}
virtual void GetFun(void) const
{
@ -93,14 +89,10 @@ class VAI_NetworkManager : public IDetour
}
virtual void GetVar(void) const
{
g_nAiNodeClusters = g_GameDll.FindPatternSIMD("4C 0F BF 12")
.FindPatternSelf("83 3D", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x2, 0x7).RCast<int*>();
g_pppAiNodeClusters = g_GameDll.FindPatternSIMD("F3 0F 10 52 ?? 4C 8B CA")
.FindPatternSelf("48 8B 35", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast<AINodeClusters***>();
g_nAiNodeClusterLinks = g_GameDll.FindPatternSIMD("49 FF C0 48 83 C2 04 4D 3B C2 7C D4")
.FindPatternSelf("8B 3D", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x2, 0x6).RCast<int*>();
g_pppAiNodeClusterLinks = g_GameDll.FindPatternSIMD("F3 0F 10 52 ?? 4C 8B CA")
.FindPatternSelf("4C 8B 1D", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast<AINodeClusterLinks***>();
g_pAIPathClusters = g_GameDll.FindPatternSIMD("F3 0F 10 52 ?? 4C 8B CA")
.FindPatternSelf("48 8B 35", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast<CUtlVector<CAI_Cluster*>*>();
g_pAIClusterLinks = g_GameDll.FindPatternSIMD("F3 0F 10 52 ?? 4C 8B CA")
.FindPatternSelf("4C 8B 1D", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast<CUtlVector<CAI_ClusterLink*>*>();
}
virtual void GetCon(void) const { }
virtual void Attach(void) const;

View File

@ -94,37 +94,48 @@ struct CAI_ScriptNode
Vector3D m_vOrigin;
uint64_t scriptdata;
};
#pragma pack(pop)
struct AINodeClusters
//=============================================================================
// >> CAI_Cluster
//=============================================================================
struct CAI_Cluster
{
int m_nIndex;
char unk0;
char unk1; // Maps to unk1 on disk
char pad0[2]; // Padding to +8
char unk1; // Maps to unk1 on disk
Vector3D m_vOrigin;
char unkC; // idk, might be a 4 bytes type or just padding.
char pad5[4];
int* unk2; // Maps to unk5 on disk;
char pad1[16]; // Pad to +48
int unkcount0; // Maps to unkcount0 on disk
// These are utlvectors in engine, but its
// unknown what they do yet.
CUtlVector<int> unkVec0;
CUtlVector<int> unkVec1;
char pad2[4]; // Pad to +56
int* unk3;
char pad3[16]; // Pad to +80
int unkcount1;
// This is an array of floats that is indexed
// into by teamNum at [r5apex_ds.exe + EC84DC];
// Seems to be used along with the cvar:
// 'ai_path_dangerous_cluster_min_time'.
float clusterTime[MAX_TEAMS];
char pad4[132];
float field_0250;
float field_0254;
float field_0258;
char unk5;
};
static_assert(sizeof(CAI_Cluster) == 608);
struct AINodeClusterLinks
//=============================================================================
// >> CAI_ClusterLink
//=============================================================================
struct CAI_ClusterLink
{
short unk0;
short unk1;
short prevIndex_MAYBE;
short nextIndex_MAYBE;
int unk2;
char unk3;
char flags;
char unk4;
char unk5;
};
#pragma pack(pop)
static_assert(sizeof(CAI_ClusterLink) == 12);