diff --git a/r5dev/game/server/ai_networkmanager.cpp b/r5dev/game/server/ai_networkmanager.cpp index a1d165ee..826f649a 100644 --- a/r5dev/game/server/ai_networkmanager.cpp +++ b/r5dev/game/server/ai_networkmanager.cpp @@ -10,8 +10,8 @@ #include "tier1/cmd.h" #include "mathlib/crc32.h" #include "public/edict.h" -#include "public/utility/binstream.h" #include "public/utility/utility.h" +#include "filesystem/filesystem.h" #include "engine/host_state.h" #include "game/server/ai_node.h" #include "game/server/ai_network.h" @@ -19,6 +19,7 @@ constexpr int AINET_SCRIPT_VERSION_NUMBER = 21; constexpr int AINET_VERSION_NUMBER = 57; +constexpr int AINETWORK_MIN_SIZE = 82; /* ============================== @@ -31,8 +32,8 @@ CAI_NetworkBuilder::BuildFile */ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) { - const string svMeshDir = "maps\\navmesh\\"; - const string svGraphDir = "maps\\graphs\\"; + const string svMeshDir = "maps/navmesh/"; + const string svGraphDir = "maps/graphs/"; fs::path fsMeshPath(svMeshDir + g_pHostState->m_levelName + "_" + SHULL_SIZE[EHULL_SIZE::LARGE] + ".nm"); fs::path fsGraphPath(svGraphDir + g_pHostState->m_levelName + ".ain"); @@ -40,45 +41,54 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) CFastTimer masterTimer; CFastTimer timer; - CIOStream writer(fsGraphPath, CIOStream::Mode_t::WRITE); - - int nCalculatedLinkcount = 0; - // Build from memory. DevMsg(eDLL_T::SERVER, "++++--------------------------------------------------------------------------------------------------------------------------++++\n"); DevMsg(eDLL_T::SERVER, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> AI NETWORK GRAPH FILE CONSTRUCTION STARTED <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); DevMsg(eDLL_T::SERVER, "++++--------------------------------------------------------------------------------------------------------------------------++++\n"); - DevMsg(eDLL_T::SERVER, "+- Writing header...\n"); masterTimer.Start(); timer.Start(); - CreateDirectories(svGraphDir); + FileHandle_t pAIGraph = FileSystem()->Open(fsGraphPath.relative_path().u8string().c_str(), "wb", "GAME"); + if (!pAIGraph) + { + Error(eDLL_T::SERVER, false, "%s - Unable to write to '%s' (read-only?)\n", __FUNCTION__, fsGraphPath.relative_path().u8string().c_str()); + return; + } + DevMsg(eDLL_T::SERVER, "+- Writing header...\n"); DevMsg(eDLL_T::SERVER, " |-- AINet version: '%d'\n", AINET_VERSION_NUMBER); - writer.Write(&AINET_VERSION_NUMBER, sizeof(int)); + FileSystem()->Write(&AINET_VERSION_NUMBER, sizeof(int), pAIGraph); DevMsg(eDLL_T::SERVER, " |-- Map version: '%d'\n", g_ServerGlobalVariables->m_nMapVersion); - writer.Write(&g_ServerGlobalVariables->m_nMapVersion, sizeof(int)); + FileSystem()->Write(&g_ServerGlobalVariables->m_nMapVersion, sizeof(int), pAIGraph); - CIOStream reader(fsMeshPath, CIOStream::Mode_t::READ); + FileHandle_t pNavMesh = FileSystem()->Open(fsMeshPath.relative_path().u8string().c_str(), "rb", "GAME"); uint32_t nNavMeshHash = NULL; - if (reader.IsReadable()) + + if (!pNavMesh) { - nNavMeshHash = crc32::update(NULL, reader.GetData(), reader.GetSize()); + Warning(eDLL_T::SERVER, "%s - No %s NavMesh found. Unable to calculate CRC for AI Network.\n", __FUNCTION__, SHULL_SIZE[EHULL_SIZE::LARGE].c_str()); } else { - Warning(eDLL_T::SERVER, "%s - No %s NavMesh found. Unable to calculate CRC for AI Network.\n", __FUNCTION__, SHULL_SIZE[EHULL_SIZE::LARGE].c_str()); + uint32_t nLen = FileSystem()->Size(pNavMesh); + uint8_t* pBuf = MemAllocSingleton()->Alloc(nLen); + + FileSystem()->Read(pBuf, nLen, pNavMesh); + FileSystem()->Close(pNavMesh); + + nNavMeshHash = crc32::update(NULL, pBuf, nLen); + MemAllocSingleton()->Free(pBuf); } // Large NavMesh CRC. DevMsg(eDLL_T::SERVER, " |-- NavMesh CRC: '%lx'\n", nNavMeshHash); - writer.Write(&nNavMeshHash, sizeof(int)); + FileSystem()->Write(&nNavMeshHash, sizeof(uint32_t), pAIGraph); // Path nodes. DevMsg(eDLL_T::SERVER, " |-- Nodecount: '%d'\n", pNetwork->m_iNumNodes); - writer.Write(&pNetwork->m_iNumNodes, sizeof(int)); + FileSystem()->Write(&pNetwork->m_iNumNodes, sizeof(int), pAIGraph); timer.End(); DevMsg(eDLL_T::SERVER, "...done writing header. %lf seconds\n", timer.GetDuration().GetSeconds()); @@ -86,6 +96,8 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) timer.Start(); DevMsg(eDLL_T::SERVER, "+- Writing node positions...\n"); + int nCalculatedLinkcount = 0; + if (pNetwork->m_pAInode) { for (int i = 0; i < pNetwork->m_iNumNodes; i++) @@ -111,8 +123,8 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) memcpy(diskNode.unk6, pNetwork->m_pAInode[i]->unk10, sizeof(diskNode.unk6)); - DevMsg(eDLL_T::SERVER, " |-- Copying node '#%d' from '0x%p' to '0x%zX'\n", pNetwork->m_pAInode[i]->m_nIndex, reinterpret_cast(pNetwork->m_pAInode[i]), writer.GetPosition()); - writer.Write(&diskNode, sizeof(CAI_NodeDisk)); + DevMsg(eDLL_T::SERVER, " |-- Copying node '#%d' from '0x%p' to '0x%zX'\n", pNetwork->m_pAInode[i]->m_nIndex, reinterpret_cast(pNetwork->m_pAInode[i]), FileSystem()->Tell(pAIGraph)); + FileSystem()->Write(&diskNode, sizeof(CAI_NodeDisk), pAIGraph); nCalculatedLinkcount += pNetwork->m_pAInode[i]->m_nNumLinks; } @@ -135,7 +147,7 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) } } - writer.Write(&nCalculatedLinkcount, sizeof(int)); + FileSystem()->Write(&nCalculatedLinkcount, sizeof(int), pAIGraph); if (pNetwork->m_pAInode) { @@ -155,8 +167,8 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) diskLink.unk0 = pNetwork->m_pAInode[i]->links[j]->unk1; memcpy(diskLink.m_bHulls, pNetwork->m_pAInode[i]->links[j]->m_bHulls, sizeof(diskLink.m_bHulls)); - DevMsg(eDLL_T::SERVER, " |-- Writing link '%h' => '%h' to '0x%zX'\n", diskLink.m_iSrcID, diskLink.m_iDestID, writer.GetPosition()); - writer.Write(&diskLink, sizeof(CAI_NodeLinkDisk)); + DevMsg(eDLL_T::SERVER, " |-- Writing link '%h' => '%h' to '0x%zX'\n", diskLink.m_iSrcID, diskLink.m_iDestID, FileSystem()->Tell(pAIGraph)); + FileSystem()->Write(&diskLink, sizeof(CAI_NodeLinkDisk), pAIGraph); } } } @@ -167,27 +179,28 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) 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), writer.GetPosition()); + DevMsg(eDLL_T::SERVER, " |-- Writing '%d' bytes for node block at '0x%zX'\n", pNetwork->m_iNumNodes * sizeof(uint32_t), FileSystem()->Tell(pAIGraph)); if (pNetwork->m_iNumNodes > 0) { - uint32_t* unkNodeBlock = new uint32_t[pNetwork->m_iNumNodes]; + uint32_t* unkNodeBlock = MemAllocSingleton()->Alloc(pNetwork->m_iNumNodes * sizeof(uint32_t)); memset(&unkNodeBlock, '\0', pNetwork->m_iNumNodes * sizeof(uint32_t)); - writer.Write(&*unkNodeBlock, pNetwork->m_iNumNodes * sizeof(uint32_t)); - delete[] unkNodeBlock; + + FileSystem()->Write(&*unkNodeBlock, pNetwork->m_iNumNodes * sizeof(uint32_t), pAIGraph); + MemAllocSingleton()->Free(unkNodeBlock); } // 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, writer.GetPosition()); + 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. - writer.Write(&traverseNodeCount, sizeof(short)); + FileSystem()->Write(&traverseNodeCount, sizeof(short), pAIGraph); // 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, writer.GetPosition()); + DevMsg(eDLL_T::SERVER, " |-- Writing '%d' bytes for hull data block at '0x%zX'\n", MAX_HULLS * 8, FileSystem()->Tell(pAIGraph)); for (int i = 0; i < (MAX_HULLS * 8); i++) { - writer.Write('\0'); + FileSystem()->Write("\0", sizeof(char), pAIGraph); } timer.End(); @@ -196,34 +209,34 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) timer.Start(); DevMsg(eDLL_T::SERVER, "+- Writing clusters...\n"); - writer.Write(&*g_nAiNodeClusters, sizeof(*g_nAiNodeClusters)); + FileSystem()->Write(&*g_nAiNodeClusters, sizeof(*g_nAiNodeClusters), pAIGraph); for (int i = 0; i < *g_nAiNodeClusters; i++) { - DevMsg(eDLL_T::SERVER, " |-- Writing cluster '#%d' at '0x%zX'\n", i, writer.GetPosition()); + DevMsg(eDLL_T::SERVER, " |-- Writing cluster '#%d' at '0x%zX'\n", i, FileSystem()->Tell(pAIGraph)); AINodeClusters* nodeClusters = (*g_pppAiNodeClusters)[i]; - writer.Write(&nodeClusters->m_nIndex, sizeof(nodeClusters->m_nIndex)); - writer.Write(&nodeClusters->unk1, sizeof(nodeClusters->unk1)); + FileSystem()->Write(&nodeClusters->m_nIndex, sizeof(nodeClusters->m_nIndex), pAIGraph); + FileSystem()->Write(&nodeClusters->unk1, sizeof(nodeClusters->unk1), pAIGraph); - writer.Write(&nodeClusters->m_vOrigin.x, sizeof(nodeClusters->m_vOrigin.x)); - writer.Write(&nodeClusters->m_vOrigin.y, sizeof(nodeClusters->m_vOrigin.y)); - writer.Write(&nodeClusters->m_vOrigin.z, sizeof(nodeClusters->m_vOrigin.z)); + 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); - writer.Write(&nodeClusters->unkcount0, sizeof(nodeClusters->unkcount0)); + FileSystem()->Write(&nodeClusters->unkcount0, sizeof(nodeClusters->unkcount0), pAIGraph); for (int j = 0; j < nodeClusters->unkcount0; j++) { short unk2Short = static_cast(nodeClusters->unk2[j]); - writer.Write(&unk2Short, sizeof(unk2Short)); + FileSystem()->Write(&unk2Short, sizeof(unk2Short), pAIGraph); } - writer.Write(&nodeClusters->unkcount1, sizeof(nodeClusters->unkcount1)); + FileSystem()->Write(&nodeClusters->unkcount1, sizeof(nodeClusters->unkcount1), pAIGraph); for (int j = 0; j < nodeClusters->unkcount1; j++) { short unk3Short = static_cast(nodeClusters->unk3[j]); - writer.Write(&unk3Short, sizeof(unk3Short)); + FileSystem()->Write(&unk3Short, sizeof(unk3Short), pAIGraph); } - writer.Write(&nodeClusters->unk5, sizeof(nodeClusters->unk5)); + FileSystem()->Write(&nodeClusters->unk5, sizeof(nodeClusters->unk5), pAIGraph); } timer.End(); @@ -232,30 +245,30 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) timer.Start(); DevMsg(eDLL_T::SERVER, "+- Writing cluster links...\n"); - writer.Write(&*g_nAiNodeClusterLinks, sizeof(*g_nAiNodeClusterLinks)); + FileSystem()->Write(&*g_nAiNodeClusterLinks, sizeof(*g_nAiNodeClusterLinks), pAIGraph); for (int i = 0; i < *g_nAiNodeClusterLinks; 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, writer.GetPosition()); - writer.Write(&*g_pppAiNodeClusterLinks[i], sizeof(*(*g_pppAiNodeClusterLinks)[i])); + 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); } timer.End(); DevMsg(eDLL_T::SERVER, "...done writing cluster links. %lf seconds (%d cluster links)\n", timer.GetDuration().GetSeconds(), *g_nAiNodeClusterLinks); // This is always set to '-1'. Likely a field for maintaining compatibility. - writer.Write(&pNetwork->unk5, sizeof(pNetwork->unk5)); + FileSystem()->Write(&pNetwork->unk5, sizeof(pNetwork->unk5), pAIGraph); // 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"); - writer.Write(&pNetwork->m_iNumScriptNodes, sizeof(pNetwork->m_iNumScriptNodes)); + FileSystem()->Write(&pNetwork->m_iNumScriptNodes, sizeof(pNetwork->m_iNumScriptNodes), pAIGraph); 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, writer.GetPosition()); - writer.Write(&pNetwork->m_ScriptNode[i], sizeof(CAI_ScriptNode)); + 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); } timer.End(); @@ -264,16 +277,18 @@ void CAI_NetworkBuilder::SaveNetworkGraph(CAI_Network* pNetwork) timer.Start(); DevMsg(eDLL_T::SERVER, "+- Writing hint data...\n"); - writer.Write(&pNetwork->m_iNumHints, sizeof(pNetwork->m_iNumHints)); + FileSystem()->Write(&pNetwork->m_iNumHints, sizeof(pNetwork->m_iNumHints), pAIGraph); for (int i = 0; i < pNetwork->m_iNumHints; i++) { - DevMsg(eDLL_T::SERVER, " |-- Writing hint data '#%d' at '0x%zX'\n", i, writer.GetPosition()); - writer.Write(&pNetwork->m_Hints[i], sizeof(pNetwork->m_Hints[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); } timer.End(); DevMsg(eDLL_T::SERVER, "...done writing hint data. %lf seconds (%d hints)\n", timer.GetDuration().GetSeconds(), pNetwork->m_iNumHints); + FileSystem()->Close(pAIGraph); + masterTimer.End(); DevMsg(eDLL_T::SERVER, "...done writing AI node graph. %lf seconds\n", masterTimer.GetDuration().GetSeconds()); DevMsg(eDLL_T::SERVER, "++++--------------------------------------------------------------------------------------------------------------------------++++\n"); @@ -290,43 +305,66 @@ CAI_NetworkManager::LoadNetworkGraph */ void CAI_NetworkManager::LoadNetworkGraph(CAI_NetworkManager* pAINetworkManager, void* pBuffer, const char* szAIGraphFile) { - string svMeshDir = "maps\\navmesh\\"; - string svGraphDir = "maps\\graphs\\"; + string svMeshDir = "maps/navmesh/"; + string svGraphDir = "maps/graphs/"; fs::path fsMeshPath(svMeshDir + g_pHostState->m_levelName + "_" + SHULL_SIZE[EHULL_SIZE::LARGE] + ".nm"); fs::path fsGraphPath(svGraphDir + g_pHostState->m_levelName + ".ain"); int nAiNetVersion = NULL; int nAiMapVersion = NULL; + bool bNavMeshAvailable = true; uint32_t nAiGraphHash = NULL; uint32_t nNavMeshHash = NULL; - CIOStream iAIGraph(fsGraphPath, CIOStream::Mode_t::READ); - - if (iAIGraph.IsReadable()) + FileHandle_t pNavMesh = FileSystem()->Open(fsMeshPath.relative_path().u8string().c_str(), "rb", "GAME"); + if (!pNavMesh) { - iAIGraph.Read(nAiNetVersion); - iAIGraph.Read(nAiMapVersion); - iAIGraph.Read(nAiGraphHash); + Warning(eDLL_T::SERVER, "%s - No %s NavMesh found. Unable to calculate CRC for AI Network.\n", __FUNCTION__, SHULL_SIZE[EHULL_SIZE::LARGE].c_str()); + bNavMeshAvailable = false; + } + else + { + uint32_t nLen = FileSystem()->Size(pNavMesh); + uint8_t* pBuf = MemAllocSingleton()->Alloc(nLen); + + FileSystem()->Read(pBuf, nLen, pNavMesh); + FileSystem()->Close(pNavMesh); + + nNavMeshHash = crc32::update(NULL, pBuf, nLen); + MemAllocSingleton()->Free(pBuf); + } + + FileHandle_t pAIGraph = FileSystem()->Open(fsGraphPath.relative_path().u8string().c_str(), "rb", "GAME"); + if (!pAIGraph) + { + Error(eDLL_T::SERVER, false, "%s - Unable to open '%s' (insufficient rights?)\n", __FUNCTION__, + fsGraphPath.relative_path().u8string().c_str()); + LoadNetworkGraphEx(pAINetworkManager, pBuffer, szAIGraphFile); + + return; + } + if (FileSystem()->Size(pAIGraph) >= AINETWORK_MIN_SIZE) + { + FileSystem()->Read(&nAiNetVersion, sizeof(int), pAIGraph); + FileSystem()->Read(&nAiMapVersion, sizeof(int), pAIGraph); + FileSystem()->Read(&nAiGraphHash, sizeof(int), pAIGraph); if (nAiNetVersion > AINET_VERSION_NUMBER) { - Warning(eDLL_T::SERVER, "AI node graph '%s' deviates expectations (net version: '%d' expected: '%d')\n", + Warning(eDLL_T::SERVER, "AI node graph '%s' deviates expectations (net version: '%d' expected: '%d')\n", fsGraphPath.relative_path().u8string().c_str(), nAiNetVersion, AINET_VERSION_NUMBER); } else if (nAiMapVersion != g_ServerGlobalVariables->m_nMapVersion) { - Warning(eDLL_T::SERVER, "AI node graph '%s' is out of date (map version: '%d' expected: '%d')\n", + Warning(eDLL_T::SERVER, "AI node graph '%s' is out of date (map version: '%d' expected: '%d')\n", fsGraphPath.relative_path().u8string().c_str(), nAiMapVersion, g_ServerGlobalVariables->m_nMapVersion); } else { - CIOStream iNavMesh(fsMeshPath, CIOStream::Mode_t::READ); - - if (iNavMesh.IsReadable()) + if (bNavMeshAvailable) { - nNavMeshHash = crc32::update(NULL, iNavMesh.GetData(), iNavMesh.GetSize()); if (nNavMeshHash != nAiGraphHash) { Warning(eDLL_T::SERVER, "AI node graph '%s' is out of date (checksum: '0x%X' expected: '0x%X')\n", @@ -335,7 +373,26 @@ void CAI_NetworkManager::LoadNetworkGraph(CAI_NetworkManager* pAINetworkManager, } } } + else + { + Error(eDLL_T::SERVER, false, "%s - AI node graph '%s' is corrupt (LEN_BYTES < AINETWORK_MIN_SIZE)\n", __FUNCTION__, + fsGraphPath.relative_path().u8string().c_str()); + } + FileSystem()->Close(pAIGraph); + LoadNetworkGraphEx(pAINetworkManager, pBuffer, szAIGraphFile); +} + +/* +============================== +CAI_NetworkManager::LoadNetworkGraphEx + + Load network + (internal) +============================== +*/ +void CAI_NetworkManager::LoadNetworkGraphEx(CAI_NetworkManager* pAINetworkManager, void* pBuffer, const char* szAIGraphFile) +{ #if defined (GAMEDLL_S0) || defined (GAMEDLL_S1) CAI_NetworkManager__LoadNetworkGraph(pAINetworkManager, pBuffer, szAIGraphFile, NULL); #elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3) diff --git a/r5dev/game/server/ai_networkmanager.h b/r5dev/game/server/ai_networkmanager.h index f1d3279b..83ad21b2 100644 --- a/r5dev/game/server/ai_networkmanager.h +++ b/r5dev/game/server/ai_networkmanager.h @@ -60,6 +60,7 @@ class CAI_NetworkManager { public: static void LoadNetworkGraph(CAI_NetworkManager* pAINetworkManager, void* pBuffer, const char* szAIGraphFile); + static void LoadNetworkGraphEx(CAI_NetworkManager* pAINetworkManager, void* pBuffer, const char* szAIGraphFile); }; ///////////////////////////////////////////////////////////////////////////////