diff --git a/r5dev/game/server/ai_network.cpp b/r5dev/game/server/ai_network.cpp index 51e05058..b5e051cf 100644 --- a/r5dev/game/server/ai_network.cpp +++ b/r5dev/game/server/ai_network.cpp @@ -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 { diff --git a/r5dev/game/server/ai_network.h b/r5dev/game/server/ai_network.h index 51d25919..419016f1 100644 --- a/r5dev/game/server/ai_network.h +++ b/r5dev/game/server/ai_network.h @@ -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(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(); + + 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(); + p_CAI_Network__DebugConnectMsg = g_GameDll.FindPatternSIMD("4C 89 4C 24 ?? 48 83 EC 18"); - v_CAI_Network__DebugConnectMsg = p_CAI_Network__DebugConnectMsg.RCast(); /*4C 89 4C 24 ?? 48 83 EC 18*/ + v_CAI_Network__DebugConnectMsg = p_CAI_Network__DebugConnectMsg.RCast(); } virtual void GetVar(void) const { diff --git a/r5dev/game/server/ai_networkmanager.cpp b/r5dev/game/server/ai_networkmanager.cpp index d9506983..cea28593 100644 --- a/r5dev/game/server/ai_networkmanager.cpp +++ b/r5dev/game/server/ai_networkmanager.cpp @@ -14,6 +14,7 @@ #include "game/server/ai_node.h" #include "game/server/ai_network.h" #include "game/server/ai_networkmanager.h" +#include 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 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(nodeClusters->unk2[j]); - FileSystem()->Write(&unk2Short, sizeof(unk2Short), pAIGraph); + short unkShort = static_cast(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(nodeClusters->unk3[j]); - FileSystem()->Write(&unk3Short, sizeof(unk3Short), pAIGraph); + short unkShort = static_cast(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); diff --git a/r5dev/game/server/ai_networkmanager.h b/r5dev/game/server/ai_networkmanager.h index 214464c9..72959830 100644 --- a/r5dev/game/server/ai_networkmanager.h +++ b/r5dev/game/server/ai_networkmanager.h @@ -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* g_pAIPathClusters = nullptr; +inline CUtlVector* 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(g_nAiNodeClusters)); - LogVarAdr("g_pAiNodeClusters", reinterpret_cast(g_pppAiNodeClusters)); - LogVarAdr("g_nAiNodeClusterLinks", reinterpret_cast(g_nAiNodeClusterLinks)); - LogVarAdr("g_pAiNodeClusterLinks", reinterpret_cast(g_pppAiNodeClusterLinks)); + LogVarAdr("g_AIPathClusters< CAI_Cluster* >", reinterpret_cast(g_pAIPathClusters)); + LogVarAdr("g_AIClusterLinks< CAI_ClusterLink* >", reinterpret_cast(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(); - g_pppAiNodeClusters = g_GameDll.FindPatternSIMD("F3 0F 10 52 ?? 4C 8B CA") - .FindPatternSelf("48 8B 35", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast(); - 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(); - g_pppAiNodeClusterLinks = g_GameDll.FindPatternSIMD("F3 0F 10 52 ?? 4C 8B CA") - .FindPatternSelf("4C 8B 1D", 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*>(); } 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 83f2cc9e..61a92cce 100644 --- a/r5dev/game/server/ai_node.h +++ b/r5dev/game/server/ai_node.h @@ -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 unkVec0; + CUtlVector 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); \ No newline at end of file