From 25e5ea0c833e791c169b0bb4c686239ba9cacb30 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 28 Aug 2023 20:01:45 +0200 Subject: [PATCH] CAI_NetworkBuilder::SaveNetworkGraph() rewrite - Use CUtlBuffer instead to construct the data. - Dump traverse ex nodes as well (CAI_TraverseNode). --- r5dev/game/server/ai_network.cpp | 26 ++- r5dev/game/server/ai_network.h | 12 +- r5dev/game/server/ai_networkmanager.cpp | 244 ++++++++++++++---------- r5dev/game/server/ai_networkmanager.h | 33 +++- r5dev/game/server/ai_node.h | 110 +++++++---- r5dev/game/shared/ai_utility_shared.cpp | 2 +- 6 files changed, 263 insertions(+), 164 deletions(-) diff --git a/r5dev/game/server/ai_network.cpp b/r5dev/game/server/ai_network.cpp index b5e051cf..c47519ea 100644 --- a/r5dev/game/server/ai_network.cpp +++ b/r5dev/game/server/ai_network.cpp @@ -54,7 +54,7 @@ void* CAI_Network::GetVTable(void) const // Purpose: gets the number of node links // Output : int //----------------------------------------------------------------------------- -int CAI_Network::GetNumLinks(void) const +int CAI_Network::NumLinks(void) const { return m_iNumLinks; } @@ -63,7 +63,7 @@ int CAI_Network::GetNumLinks(void) const // Purpose: gets the number of zones // Output : int //----------------------------------------------------------------------------- -int CAI_Network::GetNumZones(void) const +int CAI_Network::NumZones(void) const { return m_iNumZones; } @@ -72,7 +72,7 @@ int CAI_Network::GetNumZones(void) const // Purpose: gets the number of hints // Output : int //----------------------------------------------------------------------------- -int CAI_Network::GetNumHints(void) const +int CAI_Network::NumHints(void) const { return m_iNumHints; } @@ -81,16 +81,16 @@ int CAI_Network::GetNumHints(void) const // Purpose: gets the number of script nodes // Output : int //----------------------------------------------------------------------------- -int CAI_Network::GetNumScriptNodes(void) const +int CAI_Network::NumScriptNodes(void) const { return m_iNumScriptNodes; } //----------------------------------------------------------------------------- // Purpose: gets the path nodes -// Output : int64_t +// Output : int //----------------------------------------------------------------------------- -int64_t CAI_Network::GetNumPathNodes(void) const +int CAI_Network::NumPathNodes(void) const { return m_iNumNodes; } @@ -115,12 +115,20 @@ CAI_ScriptNode* CAI_Network::GetScriptNodes(void) const } //----------------------------------------------------------------------------- -// Purpose: gets the pointer to path nodes +// Purpose: gets the pointer to path node +// Input : id - // Output : CAI_Node** //----------------------------------------------------------------------------- -CAI_Node** CAI_Network::GetPathNodes(void) const +CAI_Node* CAI_Network::GetPathNode(int id) const { - return m_pAInode; + if (id >= 0 && + id < m_iNumNodes) + { + return m_pAInode[id]; + } + + Assert(0); + return NULL; } //----------------------------------------------------------------------------- diff --git a/r5dev/game/server/ai_network.h b/r5dev/game/server/ai_network.h index 419016f1..e7810176 100644 --- a/r5dev/game/server/ai_network.h +++ b/r5dev/game/server/ai_network.h @@ -11,17 +11,17 @@ class CAI_Network public: static void DebugConnectMsg(int node1, int node2, const char* pszFormat, ...); void* GetVTable(void) const; - int GetNumLinks(void) const; - int GetNumZones(void) const; - int GetNumHints(void) const; - int GetNumScriptNodes(void) const; - int64_t GetNumPathNodes(void) const; + int NumLinks(void) const; + int NumZones(void) const; + int NumHints(void) const; + int NumScriptNodes(void) const; + int NumPathNodes(void) const; 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_Node* GetPathNode(int id) const; CAI_NodeLink* CreateNodeLink(int srcID, int destID); diff --git a/r5dev/game/server/ai_networkmanager.cpp b/r5dev/game/server/ai_networkmanager.cpp index 8036eca8..8c859bfa 100644 --- a/r5dev/game/server/ai_networkmanager.cpp +++ b/r5dev/game/server/ai_networkmanager.cpp @@ -59,11 +59,6 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) } DevMsg(eDLL_T::SERVER, "+- Writing header...\n"); - DevMsg(eDLL_T::SERVER, " |-- AINet version: '%d'\n", AINET_VERSION_NUMBER); - FileSystem()->Write(&AINET_VERSION_NUMBER, sizeof(int), pAIGraph); - - DevMsg(eDLL_T::SERVER, " |-- Map version: '%d'\n", g_ServerGlobalVariables->m_nMapVersion); - FileSystem()->Write(&g_ServerGlobalVariables->m_nMapVersion, sizeof(int), pAIGraph); FileHandle_t pNavMesh = FileSystem()->Open(szMeshPath, "rb", "GAME"); uint32_t nNavMeshCRC = NULL; @@ -85,12 +80,18 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) } // Large NavMesh CRC. + DevMsg(eDLL_T::SERVER, " |-- AINet version: '%d'\n", AINET_VERSION_NUMBER); + DevMsg(eDLL_T::SERVER, " |-- Map version: '%d'\n", g_ServerGlobalVariables->m_nMapVersion); 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); - FileSystem()->Write(&pNetwork->m_iNumNodes, sizeof(int), pAIGraph); + CUtlBuffer buf; + + // --------------------------- + // Save the version numbers + // --------------------------- + buf.PutInt(AINET_VERSION_NUMBER); + buf.PutInt(g_ServerGlobalVariables->m_nMapVersion); + buf.PutInt(nNavMeshCRC); timer.End(); Msg(eDLL_T::SERVER, "...done writing header. %lf seconds\n", timer.GetDuration().GetSeconds()); @@ -98,49 +99,42 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) timer.Start(); DevMsg(eDLL_T::SERVER, "+- Writing path nodes...\n"); - if (pNetwork->m_pAInode) + // ------------------------------- + // Dump all the nodes to the file + // ------------------------------- + buf.PutInt(pNetwork->NumPathNodes()); + int totalNumLinks = 0; + + for (int node = 0; node < pNetwork->NumPathNodes(); node++) { - int totalLinkCount = 0; + const CAI_Node* aiNode = pNetwork->GetPathNode(node); - for (int i = 0; i < pNetwork->m_iNumNodes; i++) + DevMsg(eDLL_T::SERVER, " |-- Copying node '#%d' from '0x%p' to '0x%zX'\n", aiNode->m_iID, aiNode, buf.TellPut()); + + buf.PutFloat(aiNode->GetOrigin().x); + buf.PutFloat(aiNode->GetOrigin().y); + buf.PutFloat(aiNode->GetOrigin().z); + + buf.PutFloat(aiNode->GetYaw()); + buf.Put(aiNode->m_flVOffset, sizeof(aiNode->m_flVOffset)); + buf.PutChar((char)aiNode->GetType()); + buf.PutInt(aiNode->GetInfo()); + + for (int j = 0; j < MAX_HULLS; j++) { - const CAI_Node* aiNode = pNetwork->m_pAInode[i]; - - DevMsg(eDLL_T::SERVER, " |-- Copying node '#%d' from '0x%p' to '0x%zX'\n", aiNode->m_nIndex, aiNode, FileSystem()->Tell(pAIGraph)); - - FileSystem()->Write(&aiNode->m_vOrigin, sizeof(Vector3D), pAIGraph); - FileSystem()->Write(&aiNode->m_flYaw, sizeof(float), pAIGraph); - FileSystem()->Write(&aiNode->m_fHulls, sizeof(aiNode->m_fHulls), pAIGraph); - - FileSystem()->Write(&aiNode->unk0, sizeof(char), pAIGraph); - FileSystem()->Write(&aiNode->unk1, sizeof(int), pAIGraph); - - for (int j = 0; j < MAX_HULLS; j++) - { - FileSystem()->Write(&aiNode->unk2[j], sizeof(short), pAIGraph); - } - - FileSystem()->Write(&aiNode->unk3, sizeof(aiNode->unk3), pAIGraph); - FileSystem()->Write(&aiNode->unk6, sizeof(short), pAIGraph); - - // aiNetwork->nodes[i]->unk8; // This field is wrong, however it's always -1 in original navmeshes anyway. - short unk8 = -1; - - FileSystem()->Write(&unk8/*aiNode->unk8*/, sizeof(short), pAIGraph); - FileSystem()->Write(&aiNode->unk10, sizeof(aiNode->unk10), pAIGraph); - - totalLinkCount += aiNode->m_nNumLinks; + buf.PutShort((short)aiNode->unk2[j]); } - pNetwork->m_iNumLinks = totalLinkCount; - } - else - { - // No links, this has to be initialized as the engine doesn't do it - // during build. - pNetwork->m_iNumLinks = 0; + buf.Put(aiNode->unk3, sizeof(aiNode->unk3)); + buf.PutShort(aiNode->unk6); + buf.PutShort(aiNode->unk9); // Always -1; + buf.Put(aiNode->unk11, sizeof(aiNode->unk11)); + + totalNumLinks += aiNode->NumLinks(); } + pNetwork->m_iNumLinks = totalNumLinks; + timer.End(); Msg(eDLL_T::SERVER, "...done writing path nodes. %lf seconds (%d nodes)\n", timer.GetDuration().GetSeconds(), pNetwork->m_iNumNodes); @@ -148,31 +142,30 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) DevMsg(eDLL_T::SERVER, "+- Writing node links...\n"); DevMsg(eDLL_T::SERVER, " |-- Cached node link count: '%d'\n", pNetwork->m_iNumLinks); + // ------------------------------- + // Dump all the links to the file + // ------------------------------- int packedLinks = pNetwork->m_iNumLinks / 2; - FileSystem()->Write(&packedLinks, sizeof(int), pAIGraph); + buf.PutInt(packedLinks); - if (pNetwork->m_pAInode) + for (int node = 0; node < pNetwork->NumPathNodes(); node++) { - for (int i = 0; i < pNetwork->m_iNumNodes; i++) + const CAI_Node* aiNode = pNetwork->GetPathNode(node); + + for (int link = 0; link < aiNode->NumLinks(); link++) { - const CAI_Node* aiNode = pNetwork->m_pAInode[i]; + const CAI_NodeLink* nodeLink = aiNode->GetLinkByIndex(link); - for (int j = 0; j < aiNode->m_nNumLinks; j++) + // Skip links that don't originate from current node. + if (nodeLink->m_iSrcID == aiNode->m_iID) { - const CAI_NodeLink* nodeLink = aiNode->links[j]; + DevMsg(eDLL_T::SERVER, " |-- Writing link (%hd <--> %hd) to '0x%zX'\n", nodeLink->m_iSrcID, nodeLink->m_iDestID, buf.TellPut()); - // Skip links that don't originate from current node. - if (nodeLink->m_iSrcID != aiNode->m_nIndex) - { - continue; - } + buf.PutShort(nodeLink->m_iSrcID); + buf.PutShort(nodeLink->m_iDestID); - DevMsg(eDLL_T::SERVER, " |-- Writing link '%hd' => '%hd' to '0x%zX'\n", nodeLink->m_iSrcID, nodeLink->m_iDestID, FileSystem()->Tell(pAIGraph)); - - FileSystem()->Write(&nodeLink->m_iSrcID, sizeof(short), pAIGraph); - FileSystem()->Write(&nodeLink->m_iDestID, sizeof(short), pAIGraph); - FileSystem()->Write(&nodeLink->unk1, sizeof(char), pAIGraph); - FileSystem()->Write(&nodeLink->m_bHulls, sizeof(nodeLink->m_bHulls), pAIGraph); + buf.PutChar(nodeLink->unk1); + buf.Put(nodeLink->m_iAcceptedMoveTypes, sizeof(nodeLink->m_iAcceptedMoveTypes)); } } } @@ -181,30 +174,68 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) Msg(eDLL_T::SERVER, "...done writing node links. %lf seconds (%d links)\n", timer.GetDuration().GetSeconds(), pNetwork->m_iNumLinks); timer.Start(); - DevMsg(eDLL_T::SERVER, "+- Writing hull data...\n"); - // Don't know what this is, it's likely a block from tf1 that got deprecated? should just be 1 int per node. - DevMsg(eDLL_T::SERVER, " |-- Writing '%d' bytes for node block at '0x%zX'\n", pNetwork->m_iNumNodes * sizeof(uint32_t), FileSystem()->Tell(pAIGraph)); + DevMsg(eDLL_T::SERVER, "+- Writing WC lookup table...\n"); - if (pNetwork->m_iNumNodes > 0) + // ------------------------------- + // Dump WC lookup table + // ------------------------------- + CUtlMap wcIDs; + SetDefLessFunc(wcIDs); + bool bCheckForProblems = false; + + const CAI_NetworkEditTools* const pEditOps = (*g_ppAINetworkManager)->GetEditOps(); + + for (int node = 0; node < pNetwork->m_iNumNodes; node++) { - std::unique_ptr unkNodeBlock(new uint32_t[pNetwork->m_iNumNodes * sizeof(uint32_t)]); - memset(unkNodeBlock.get(), '\0', pNetwork->m_iNumNodes * sizeof(uint32_t)); + const int nIndex = pEditOps->m_pNodeIndexTable[node]; + const int iPreviousNodeBinding = wcIDs.Find(nIndex); - FileSystem()->Write(unkNodeBlock.get(), pNetwork->m_iNumNodes * sizeof(uint32_t), pAIGraph); + if (iPreviousNodeBinding != wcIDs.InvalidIndex()) + { + if (!bCheckForProblems) + { + DevWarning(eDLL_T::SERVER, "******* MAP CONTAINS DUPLICATE HAMMER NODE IDS! CHECK FOR PROBLEMS IN HAMMER TO CORRECT *******\n"); + bCheckForProblems = true; + } + DevWarning(eDLL_T::SERVER, " AI node %d is associated with Hammer node %d, but %d is already bound to node %d\n", + node, nIndex, nIndex, wcIDs[(unsigned short)nIndex]); + } + else + { + wcIDs.Insert(nIndex, node); + } + + DevMsg(eDLL_T::SERVER, " |-- Writing Hammer node (%d <--> %d) at '0x%zX'\n", nIndex, wcIDs.Element((unsigned short)nIndex), buf.TellPut()); + buf.PutInt(nIndex); } - // 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' traverse ex nodes at '0x%zX'\n", 0, FileSystem()->Tell(pAIGraph)); + timer.End(); + Msg(eDLL_T::SERVER, "...done writing hammer nodes. %lf seconds (%d indices)\n", timer.GetDuration().GetSeconds(), wcIDs.Count()); - short traverseExNodeCount = 0; // Only write count since count=0 means we don't have to actually do anything here. - FileSystem()->Write(&traverseExNodeCount, sizeof(short), pAIGraph); + timer.Start(); + DevMsg(eDLL_T::SERVER, "+- Writing traverse ex nodes...\n"); + + const int traverseExNodeCount = g_pAITraverseNodes->Count(); + buf.PutShort((short)traverseExNodeCount); + + FOR_EACH_VEC(*g_pAITraverseNodes, i) + { + DevMsg(eDLL_T::SERVER, " |-- Writing traverse ex node '%d' at '0x%zX'\n", i, buf.TellPut()); + + const CAI_TraverseNode& traverseExNode = (*g_pAITraverseNodes)[i]; + buf.Put(&traverseExNode.m_Quat, sizeof(Quaternion)); + buf.PutInt(traverseExNode.m_Index_MAYBE); + } + + timer.End(); + Msg(eDLL_T::SERVER, "...done writing traverse ex nodes. %lf seconds (%d nodes)\n", timer.GetDuration().GetSeconds(), traverseExNodeCount); // TODO: Ideally these should be actually dumped, but they're always 0 in r2 from what i can tell. - DevMsg(eDLL_T::SERVER, " |-- Writing '%d' bytes for hull data block at '0x%zX'\n", (MAX_HULLS * 8), FileSystem()->Tell(pAIGraph)); + timer.Start(); + DevMsg(eDLL_T::SERVER, " |-- Writing '%d' bytes for hull data block at '0x%zX'\n", (MAX_HULLS * 8), buf.TellPut()); for (int i = 0; i < (MAX_HULLS * 8); i++) { - FileSystem()->Write("\0", sizeof(char), pAIGraph); + buf.PutChar('\0'); } timer.End(); @@ -214,40 +245,40 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) DevMsg(eDLL_T::SERVER, "+- Writing path clusters...\n"); const int numClusters = g_pAIPathClusters->Count(); - FileSystem()->Write(&numClusters, sizeof(int), pAIGraph); + buf.PutInt(numClusters); FOR_EACH_VEC(*g_pAIPathClusters, i) { - DevMsg(eDLL_T::SERVER, " |-- Writing cluster '#%d' at '0x%zX'\n", i, FileSystem()->Tell(pAIGraph)); + DevMsg(eDLL_T::SERVER, " |-- Writing cluster '#%d' at '0x%zX'\n", i, buf.TellPut()); const CAI_Cluster* pathClusters = (*g_pAIPathClusters)[i]; - FileSystem()->Write(&pathClusters->m_nIndex, sizeof(int), pAIGraph); - FileSystem()->Write(&pathClusters->unk1, sizeof(char), pAIGraph); + buf.PutInt(pathClusters->m_nIndex); + buf.PutChar(pathClusters->unk1); - 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); + buf.PutFloat(pathClusters->GetOrigin().x); + buf.PutFloat(pathClusters->GetOrigin().y); + buf.PutFloat(pathClusters->GetOrigin().z); const int unkVec0Size = pathClusters->unkVec0.Count(); - FileSystem()->Write(&unkVec0Size, sizeof(int), pAIGraph); + buf.PutInt(unkVec0Size); FOR_EACH_VEC(pathClusters->unkVec0, j) { short unkShort = static_cast(pathClusters->unkVec0[j]); - FileSystem()->Write(&unkShort, sizeof(short), pAIGraph); + buf.PutShort(unkShort); } const int unkVec1Size = pathClusters->unkVec1.Count(); - FileSystem()->Write(&unkVec1Size, sizeof(int), pAIGraph); + buf.PutInt(unkVec1Size); FOR_EACH_VEC(pathClusters->unkVec1, j) { short unkShort = static_cast(pathClusters->unkVec1[j]); - FileSystem()->Write(&unkShort, sizeof(short), pAIGraph); + buf.PutShort(unkShort); } - FileSystem()->Write(&pathClusters->unk5, sizeof(char), pAIGraph); + buf.PutChar(pathClusters->unk5); } timer.End(); @@ -257,41 +288,41 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) DevMsg(eDLL_T::SERVER, "+- Writing cluster links...\n"); const int numClusterLinks = g_pAIClusterLinks->Count(); - FileSystem()->Write(&numClusterLinks, sizeof(int), pAIGraph); + buf.PutInt(numClusterLinks); FOR_EACH_VEC(*g_pAIClusterLinks, i) { - DevMsg(eDLL_T::SERVER, " |-- Writing link '#%d' at '0x%zX'\n", i, FileSystem()->Tell(pAIGraph)); - // Disk and memory structs are literally identical here so just directly write. const CAI_ClusterLink* clusterLink = (*g_pAIClusterLinks)[i]; - FileSystem()->Write(&clusterLink->prevIndex_MAYBE, sizeof(short), pAIGraph); - FileSystem()->Write(&clusterLink->nextIndex_MAYBE, sizeof(short), pAIGraph); + DevMsg(eDLL_T::SERVER, " |-- Writing link (%hd <--> %hd) to '0x%zX'\n", clusterLink->m_iSrcID, clusterLink->m_iDestID, buf.TellPut()); - FileSystem()->Write(&clusterLink->unk2, sizeof(int), pAIGraph); - FileSystem()->Write(&clusterLink->flags, sizeof(char), pAIGraph); + buf.PutShort(clusterLink->m_iSrcID); + buf.PutShort(clusterLink->m_iDestID); - FileSystem()->Write(&clusterLink->unk4, sizeof(char), pAIGraph); - FileSystem()->Write(&clusterLink->unk5, sizeof(char), pAIGraph); + buf.PutInt(clusterLink->unk2); + buf.PutChar(clusterLink->flags); + + buf.PutChar(clusterLink->unkFlags4); + buf.PutChar(clusterLink->unkFlags5); } timer.End(); Msg(eDLL_T::SERVER, "...done writing cluster links. %lf seconds (%d 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); + buf.PutInt(pNetwork->unk5); // AIN v57 and above only (not present in r1, static array in r2, pointer to dynamic array in r5). timer.Start(); DevMsg(eDLL_T::SERVER, "+- Writing script nodes...\n"); - FileSystem()->Write(&pNetwork->m_iNumScriptNodes, sizeof(pNetwork->m_iNumScriptNodes), pAIGraph); + buf.PutInt(pNetwork->m_iNumScriptNodes); for (int i = 0; i < pNetwork->m_iNumScriptNodes; i++) { // Disk and memory structs for script nodes are identical. - DevMsg(eDLL_T::SERVER, " |-- Writing script node '#%d' at '0x%zX'\n", i, FileSystem()->Tell(pAIGraph)); - FileSystem()->Write(&pNetwork->m_ScriptNode[i], sizeof(CAI_ScriptNode), pAIGraph); + DevMsg(eDLL_T::SERVER, " |-- Writing script node '#%d' at '0x%zX'\n", i, buf.TellPut()); + buf.Put(&pNetwork->m_ScriptNode[i], sizeof(CAI_ScriptNode)); } timer.End(); @@ -300,16 +331,17 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) timer.Start(); DevMsg(eDLL_T::SERVER, "+- Writing hint data...\n"); - FileSystem()->Write(&pNetwork->m_iNumHints, sizeof(pNetwork->m_iNumHints), pAIGraph); + buf.PutInt(pNetwork->m_iNumHints); for (int i = 0; i < pNetwork->m_iNumHints; i++) { - DevMsg(eDLL_T::SERVER, " |-- Writing hint data '#%d' at '0x%zX'\n", i, FileSystem()->Tell(pAIGraph)); - FileSystem()->Write(&pNetwork->m_Hints[i], sizeof(pNetwork->m_Hints[i]), pAIGraph); + DevMsg(eDLL_T::SERVER, " |-- Writing hint data '#%d' at '0x%zX'\n", i, buf.TellPut()); + buf.PutShort(pNetwork->m_Hints[i]); } timer.End(); Msg(eDLL_T::SERVER, "...done writing hint data. %lf seconds (%d hints)\n", timer.GetDuration().GetSeconds(), pNetwork->m_iNumHints); + FileSystem()->Write(buf.Base(), buf.TellPut(), pAIGraph); FileSystem()->Close(pAIGraph); masterTimer.End(); @@ -326,7 +358,7 @@ CAI_NetworkManager::LoadNetworkGraph and validate status ============================== */ -void CAI_NetworkManager::LoadNetworkGraph(CAI_NetworkManager* pManager, void* pBuffer, const char* szAIGraphFile) +void CAI_NetworkManager::LoadNetworkGraph(CAI_NetworkManager* pManager, CUtlBuffer* pBuffer, const char* szAIGraphFile) { bool bNavMeshAvailable = true; @@ -407,7 +439,7 @@ CAI_NetworkManager::LoadNetworkGraphEx (internal) ============================== */ -void CAI_NetworkManager::LoadNetworkGraphEx(CAI_NetworkManager* pManager, void* pBuffer, const char* szAIGraphFile) +void CAI_NetworkManager::LoadNetworkGraphEx(CAI_NetworkManager* pManager, CUtlBuffer* pBuffer, const char* szAIGraphFile) { #if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) CAI_NetworkManager__LoadNetworkGraph(pManager, pBuffer, szAIGraphFile); diff --git a/r5dev/game/server/ai_networkmanager.h b/r5dev/game/server/ai_networkmanager.h index 0380a9c7..8504d996 100644 --- a/r5dev/game/server/ai_networkmanager.h +++ b/r5dev/game/server/ai_networkmanager.h @@ -15,21 +15,27 @@ class CAI_NetworkBuilder; class CAI_NetworkManager; /* ==== CAI_NETWORKMANAGER ============================================================================================================================================== */ +inline CMemory p_CAI_NetworkManager__InitializeAINetworks = nullptr; +inline void (*CAI_NetworkManager__InitializeAINetworks)(void); // Static + inline CMemory p_CAI_NetworkManager__DelayedInit = nullptr; inline void (*CAI_NetworkManager__DelayedInit)(CAI_NetworkManager* thisptr, CAI_Network* pNetwork); #if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) inline CMemory p_CAI_NetworkManager__LoadNetworkGraph = nullptr; -inline void (*CAI_NetworkManager__LoadNetworkGraph)(CAI_NetworkManager* thisptr, void* pBuffer, const char* pszFileName); +inline void (*CAI_NetworkManager__LoadNetworkGraph)(CAI_NetworkManager* thisptr, CUtlBuffer* pBuffer, const char* pszFileName); #elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) inline CMemory p_CAI_NetworkManager__LoadNetworkGraph = nullptr; -inline void (*CAI_NetworkManager__LoadNetworkGraph)(CAI_NetworkManager* thisptr, void* pBuffer, const char* pszFileName); +inline void (*CAI_NetworkManager__LoadNetworkGraph)(CAI_NetworkManager* thisptr, CUtlBuffer* pBuffer, const char* pszFileName); #endif /* ==== CAI_NETWORKBUILDER ============================================================================================================================================== */ inline CMemory p_CAI_NetworkBuilder__Build; inline void (*CAI_NetworkBuilder__Build)(CAI_NetworkBuilder* thisptr, CAI_Network* pNetwork); +inline CAI_NetworkManager** g_ppAINetworkManager = nullptr; + inline CUtlVector* g_pAIPathClusters = nullptr; inline CUtlVector* g_pAIClusterLinks = nullptr; +inline CUtlVector* g_pAITraverseNodes = nullptr; //----------------------------------------------------------------------------- // CAI_NetworkEditTools @@ -53,7 +59,7 @@ public: // Debugging Tools //----------------- int m_debugNetOverlays; - CAI_Node** m_pNodes; // either nodes or node links. + int* m_pNodeIndexTable; //----------------- // Network pointers @@ -92,8 +98,11 @@ public: class CAI_NetworkManager : public CBaseEntity { public: - static void LoadNetworkGraph(CAI_NetworkManager* pAINetworkManager, void* pBuffer, const char* szAIGraphFile); - static void LoadNetworkGraphEx(CAI_NetworkManager* pAINetworkManager, void* pBuffer, const char* szAIGraphFile); + static void LoadNetworkGraph(CAI_NetworkManager* pAINetworkManager, CUtlBuffer* pBuffer, const char* szAIGraphFile); + static void LoadNetworkGraphEx(CAI_NetworkManager* pAINetworkManager, CUtlBuffer* pBuffer, const char* szAIGraphFile); + + CAI_NetworkEditTools* GetEditOps() { return m_pEditOps; } + CAI_Network* GetNetwork() { /*Assert(!m_ThreadedBuild.pBuildingNetwork);*/ return m_pNetwork; } private: // !TODO[ AMOS ]: If found, change to ptr and hook up to engine! @@ -118,21 +127,27 @@ class VAI_NetworkManager : public IDetour { virtual void GetAdr(void) const { + LogFunAdr("CAI_NetworkManager::InitializeAINetworks", p_CAI_NetworkManager__InitializeAINetworks.GetPtr()); LogFunAdr("CAI_NetworkManager::LoadNetworkGraph", p_CAI_NetworkManager__LoadNetworkGraph.GetPtr()); LogFunAdr("CAI_NetworkManager::DelayedInit", p_CAI_NetworkManager__DelayedInit.GetPtr()); LogFunAdr("CAI_NetworkBuilder::Build", p_CAI_NetworkBuilder__Build.GetPtr()); + LogVarAdr("g_pAINetworkManager", reinterpret_cast(g_ppAINetworkManager)); LogVarAdr("g_AIPathClusters< CAI_Cluster* >", reinterpret_cast(g_pAIPathClusters)); LogVarAdr("g_AIClusterLinks< CAI_ClusterLink* >", reinterpret_cast(g_pAIClusterLinks)); + LogVarAdr("g_AITraverseNodes< CAI_TraverseNode >", reinterpret_cast(g_pAITraverseNodes)); } virtual void GetFun(void) const { + p_CAI_NetworkManager__InitializeAINetworks = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 4C 89 74 24 ?? 55 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? E8 ?? ?? ?? ??"); + CAI_NetworkManager__InitializeAINetworks = p_CAI_NetworkManager__InitializeAINetworks.RCast(); + p_CAI_NetworkManager__DelayedInit = g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 48 8B D9 48 8B 0D ?? ?? ?? ?? 8B 41 6C"); #if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) p_CAI_NetworkManager__LoadNetworkGraph = g_GameDll.FindPatternSIMD("4C 89 44 24 ?? 48 89 4C 24 ?? 55 53 57 41 54 41 55 41 56"); - CAI_NetworkManager__LoadNetworkGraph = p_CAI_NetworkManager__LoadNetworkGraph.RCast(); + CAI_NetworkManager__LoadNetworkGraph = p_CAI_NetworkManager__LoadNetworkGraph.RCast(); #elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) p_CAI_NetworkManager__LoadNetworkGraph = g_GameDll.FindPatternSIMD("4C 89 44 24 ?? 48 89 4C 24 ?? 55 53 56 57 41 54 41 55 41 56 41 57 48 8D 6C 24 ?? 48 81 EC ?? ?? ?? ?? 48 8B FA"); - CAI_NetworkManager__LoadNetworkGraph = p_CAI_NetworkManager__LoadNetworkGraph.RCast(); + CAI_NetworkManager__LoadNetworkGraph = p_CAI_NetworkManager__LoadNetworkGraph.RCast(); #endif #if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) p_CAI_NetworkBuilder__Build = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 4C 24 ?? 57 41 54 41 55 41 56 41 57 48 83 EC 30 48 63 BA ?? ?? ?? ??"); @@ -144,10 +159,14 @@ class VAI_NetworkManager : public IDetour } virtual void GetVar(void) const { + g_ppAINetworkManager = p_CAI_NetworkManager__InitializeAINetworks.FindPattern("48 89 05", CMemory::Direction::DOWN) + .ResolveRelativeAddressSelf(0x3, 0x7).RCast(); g_pAIPathClusters = g_GameDll.FindPatternSIMD("F3 0F 10 52 ?? 4C 8B CA") .FindPatternSelf("48 8B 35", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast*>(); g_pAIClusterLinks = g_GameDll.FindPatternSIMD("F3 0F 10 52 ?? 4C 8B CA") .FindPatternSelf("4C 8B 1D", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast*>(); + g_pAITraverseNodes = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 55 56 57 41 54 41 56 48 8B EC 48 81 EC ?? ?? ?? ??").OffsetSelf(0x2EF) + .FindPatternSelf("48 8B 05", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast*>(); } virtual void GetCon(void) const { } virtual void Attach(void) const; diff --git a/r5dev/game/server/ai_node.h b/r5dev/game/server/ai_node.h index f8d40619..3dfb987a 100644 --- a/r5dev/game/server/ai_node.h +++ b/r5dev/game/server/ai_node.h @@ -10,6 +10,19 @@ constexpr int MAX_HULLS = 5; constexpr int NOT_CACHED = -2; // Returned if data not in cache constexpr int NO_NODE = -1; // Returned when no node meets the qualification +//========================================================= +// >> The type of node +//========================================================= +enum NodeType_e // !TODO: unconfirmed for r1/r2/r5. +{ + NODE_ANY, // Used to specify any type of node (for search) + NODE_DELETED, // Used in wc_edit mode to remove nodes during runtime + NODE_GROUND, + NODE_AIR, + NODE_CLIMB, + NODE_WATER +}; + //============================================================================= // >> CAI_NodeLink //============================================================================= @@ -17,7 +30,7 @@ struct CAI_NodeLink { short m_iSrcID; short m_iDestID; - bool m_bHulls[MAX_HULLS]; + byte m_iAcceptedMoveTypes[MAX_HULLS]; byte m_LinkInfo; char unk1; // maps => unk0 on disk char unk2[5]; @@ -27,15 +40,31 @@ struct CAI_NodeLink //============================================================================= // >> CAI_Node //============================================================================= -struct CAI_Node +class CAI_Node { - int m_nIndex; // Not present on disk - Vector3D m_vOrigin; - float m_fHulls[MAX_HULLS]; - float m_flYaw; +public: + const Vector3D& GetOrigin() const { return m_vOrigin; } + Vector3D& AccessOrigin() { return m_vOrigin; } + float GetYaw() const { return m_flYaw; } + + int NumLinks() const { return m_Links.Count(); } + void ClearLinks() { m_Links.Purge(); } + CAI_NodeLink* GetLinkByIndex(int i) const { return m_Links[i]; } + + NodeType_e SetType(NodeType_e type) { return (m_eNodeType = type); } + NodeType_e GetType() const { return m_eNodeType; } + + int SetInfo(int info) { return m_eNodeInfo = info; } + int GetInfo() const { return m_eNodeInfo; } + + int m_iID; // ID for this node + Vector3D m_vOrigin; // location of this node in space + float m_flVOffset[MAX_HULLS]; // vertical offset for each hull type, assuming ground node, 0 otherwise + float m_flYaw; // NPC on this node should face this yaw to face the hint, or climb a ladder + + NodeType_e m_eNodeType; // The type of node; always 2 in buildainfile. + int m_eNodeInfo; // bits that tell us more about this nodes - int unk0; // Always 2 in buildainfile, maps directly to unk0 in disk struct - int unk1; // Maps directly to unk1 in disk struct int unk2[MAX_HULLS]; // Maps directly to unk2 in disk struct, despite being ints rather than shorts // View server.dll+393672 for context @@ -43,36 +72,24 @@ struct CAI_Node char pad[3]; // Aligns next bytes float unk4[MAX_HULLS]; // I have no clue, calculated using some kind float function magic - CAI_NodeLink** links; - void* unkBuf0; - void* unkBuf1; - int m_nNumLinks; - int unk11; // Bad name lmao + CUtlVector m_Links; short unk6; // Should match up to unk4 on disk char unk7[16]; // Padding until next bit - short unk8; // Should match up to unk5 on disk - char unk9[8]; // Padding until next bit - char unk10[8]; // Should match up to unk6 on disk -}; - -//============================================================================= -// >> CAI_ScriptNode -//============================================================================= -struct CAI_ScriptNode -{ - Vector3D m_vOrigin; - - // Might be wrong; seems to be used for clamping. - // See [r5apex_ds + 0xF28A6E] - int m_nMin; - int m_nMax; + short unk8; + short unk9; // Should match up to unk5 on disk + char unk10[6]; // Padding until next bit + char unk11[8]; // Should match up to unk6 on disk }; //============================================================================= // >> CAI_Cluster //============================================================================= -struct CAI_Cluster +class CAI_Cluster { +public: + const Vector3D& GetOrigin() const { return m_vOrigin; } + Vector3D& AccessOrigin() { return m_vOrigin; } + int m_nIndex; char unk0; char unk1; // Maps to unk1 on disk @@ -103,11 +120,34 @@ static_assert(sizeof(CAI_Cluster) == 608); //============================================================================= struct CAI_ClusterLink { - short prevIndex_MAYBE; - short nextIndex_MAYBE; + short m_iSrcID; + short m_iDestID; int unk2; char flags; - char unk4; - char unk5; + char unkFlags4; + char unkFlags5; +}; +static_assert(sizeof(CAI_ClusterLink) == 12); + +//============================================================================= +// >> CAI_ScriptNode +//============================================================================= +struct CAI_TraverseNode +{ + Quaternion m_Quat; + int m_Index_MAYBE; +}; +static_assert(sizeof(CAI_TraverseNode) == 20); + +//============================================================================= +// >> CAI_ScriptNode +//============================================================================= +struct CAI_ScriptNode +{ + Vector3D m_vOrigin; + + // Might be wrong; seems to be used for clamping. + // See [r5apex_ds + 0xF28A6E] + int m_nMin; + int m_nMax; }; -static_assert(sizeof(CAI_ClusterLink) == 12); \ No newline at end of file diff --git a/r5dev/game/shared/ai_utility_shared.cpp b/r5dev/game/shared/ai_utility_shared.cpp index b34fb073..4ca2d373 100644 --- a/r5dev/game/shared/ai_utility_shared.cpp +++ b/r5dev/game/shared/ai_utility_shared.cpp @@ -55,7 +55,7 @@ void CAI_Utility::DrawAIScriptNetwork(const CAI_Network* pNetwork) const OverlayBox_t::Transforms vTransforms; std::unordered_set uLinkSet; - for (int i = ai_script_nodes_draw->GetInt(), ns = pNetwork->GetNumScriptNodes(); i < ns; i++) + for (int i = ai_script_nodes_draw->GetInt(), ns = pNetwork->NumScriptNodes(); i < ns; i++) { if (nNodeRange && i > nNodeRange) break;