diff options
Diffstat (limited to 'NorthstarDLL/buildainfile.cpp')
-rw-r--r-- | NorthstarDLL/buildainfile.cpp | 796 |
1 files changed, 398 insertions, 398 deletions
diff --git a/NorthstarDLL/buildainfile.cpp b/NorthstarDLL/buildainfile.cpp index c91aa30e..b759db66 100644 --- a/NorthstarDLL/buildainfile.cpp +++ b/NorthstarDLL/buildainfile.cpp @@ -1,398 +1,398 @@ -#include "pch.h"
-#include "convar.h"
-#include "hoststate.h"
-#include "r2engine.h"
-
-#include <fstream>
-#include <filesystem>
-
-AUTOHOOK_INIT()
-
-namespace fs = std::filesystem;
-
-const int AINET_VERSION_NUMBER = 57;
-const int AINET_SCRIPT_VERSION_NUMBER = 21;
-const int PLACEHOLDER_CRC = 0;
-const int MAX_HULLS = 5;
-
-#pragma pack(push, 1)
-struct CAI_NodeLink
-{
- short srcId;
- short destId;
- bool hulls[MAX_HULLS];
- char unk0;
- char unk1; // maps => unk0 on disk
- char unk2[5];
- int64_t flags;
-};
-#pragma pack(pop)
-
-#pragma pack(push, 1)
-struct CAI_NodeLinkDisk
-{
- short srcId;
- short destId;
- char unk0;
- bool hulls[MAX_HULLS];
-};
-#pragma pack(pop)
-
-#pragma pack(push, 1)
-struct CAI_Node
-{
- int index; // not present on disk
- float x;
- float y;
- float z;
- float hulls[MAX_HULLS];
- float yaw;
-
- 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 and death wish
- char unk3[MAX_HULLS]; // hell on earth, should map to unk3 on disk
- char pad[3]; // aligns next bytes
- float unk4[MAX_HULLS]; // i have no fucking clue, calculated using some kind of demon hell function float magic
-
- CAI_NodeLink** links;
- char unk5[16];
- int linkcount;
- int unk11; // bad name lmao
- 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
-};
-#pragma pack(pop)
-
-// the way CAI_Nodes are represented in on-disk ain files
-#pragma pack(push, 1)
-struct CAI_NodeDisk
-{
- float x;
- float y;
- float z;
- float yaw;
- float hulls[MAX_HULLS];
-
- char unk0;
- int unk1;
- short unk2[MAX_HULLS];
- char unk3[MAX_HULLS];
- short unk4;
- short unk5;
- char unk6[8];
-}; // total size of 68 bytes
-#pragma pack(pop)
-
-#pragma pack(push, 1)
-struct UnkNodeStruct0
-{
- int index;
- char unk0;
- char unk1; // maps to unk1 on disk
- char pad0[2]; // padding to +8
-
- float x;
- float y;
- float z;
-
- char pad5[4];
- int* unk2; // maps to unk5 on disk;
- char pad1[16]; // pad to +48
- int unkcount0; // maps to unkcount0 on disk
-
- char pad2[4]; // pad to +56
- int* unk3;
- char pad3[16]; // pad to +80
- int unkcount1;
-
- char pad4[132];
- char unk5;
-};
-#pragma pack(pop)
-
-int* pUnkStruct0Count;
-UnkNodeStruct0*** pppUnkNodeStruct0s;
-
-#pragma pack(push, 1)
-struct UnkLinkStruct1
-{
- short unk0;
- short unk1;
- int unk2;
- char unk3;
- char unk4;
- char unk5;
-};
-#pragma pack(pop)
-
-int* pUnkLinkStruct1Count;
-UnkLinkStruct1*** pppUnkStruct1s;
-
-#pragma pack(push, 1)
-struct CAI_ScriptNode
-{
- float x;
- float y;
- float z;
- uint64_t scriptdata;
-};
-#pragma pack(pop)
-
-#pragma pack(push, 1)
-struct CAI_Network
-{
- // +0
- char unk0[8];
- // +8
- int linkcount; // this is uninitialised and never set on ain build, fun!
- // +12
- char unk1[124];
- // +136
- int zonecount;
- // +140
- char unk2[16];
- // +156
- int unk5; // unk8 on disk
- // +160
- char unk6[4];
- // +164
- int hintcount;
- // +168
- short hints[2000]; // these probably aren't actually hints, but there's 1 of them per hint so idk
- // +4168
- int scriptnodecount;
- // +4172
- CAI_ScriptNode scriptnodes[4000];
- // +84172
- int nodecount;
- // +84176
- CAI_Node** nodes;
-};
-#pragma pack(pop)
-
-char** pUnkServerMapversionGlobal;
-
-ConVar* Cvar_ns_ai_dumpAINfileFromLoad;
-
-void DumpAINInfo(CAI_Network* aiNetwork)
-{
- fs::path writePath(fmt::format("{}/maps/graphs", "r2"));
- writePath /= R2::g_pHostState->m_levelName;
- writePath += ".ain";
-
- // dump from memory
- spdlog::info("writing ain file {}", writePath.string());
- spdlog::info("");
- spdlog::info("");
- spdlog::info("");
- spdlog::info("");
- spdlog::info("");
-
- std::ofstream writeStream(writePath, std::ofstream::binary);
- spdlog::info("writing ainet version: {}", AINET_VERSION_NUMBER);
- writeStream.write((char*)&AINET_VERSION_NUMBER, sizeof(int));
-
- // could probably be cleaner but whatever
- int mapVersion = *(int*)(*pUnkServerMapversionGlobal + 104);
- spdlog::info("writing map version: {}", mapVersion); // temp
- writeStream.write((char*)&mapVersion, sizeof(int));
- spdlog::info("writing placeholder crc: {}", PLACEHOLDER_CRC);
- writeStream.write((char*)&PLACEHOLDER_CRC, sizeof(int));
-
- int calculatedLinkcount = 0;
-
- // path nodes
- spdlog::info("writing nodecount: {}", aiNetwork->nodecount);
- writeStream.write((char*)&aiNetwork->nodecount, sizeof(int));
-
- for (int i = 0; i < aiNetwork->nodecount; i++)
- {
- // construct on-disk node struct
- CAI_NodeDisk diskNode;
- diskNode.x = aiNetwork->nodes[i]->x;
- diskNode.y = aiNetwork->nodes[i]->y;
- diskNode.z = aiNetwork->nodes[i]->z;
- diskNode.yaw = aiNetwork->nodes[i]->yaw;
- memcpy(diskNode.hulls, aiNetwork->nodes[i]->hulls, sizeof(diskNode.hulls));
- diskNode.unk0 = (char)aiNetwork->nodes[i]->unk0;
- diskNode.unk1 = aiNetwork->nodes[i]->unk1;
-
- for (int j = 0; j < MAX_HULLS; j++)
- {
- diskNode.unk2[j] = (short)aiNetwork->nodes[i]->unk2[j];
- spdlog::info((short)aiNetwork->nodes[i]->unk2[j]);
- }
-
- memcpy(diskNode.unk3, aiNetwork->nodes[i]->unk3, sizeof(diskNode.unk3));
- diskNode.unk4 = aiNetwork->nodes[i]->unk6;
- diskNode.unk5 =
- -1; // aiNetwork->nodes[i]->unk8; // this field is wrong, however, it's always -1 in vanilla navmeshes anyway, so no biggie
- memcpy(diskNode.unk6, aiNetwork->nodes[i]->unk10, sizeof(diskNode.unk6));
-
- spdlog::info("writing node {} from {} to {:x}", aiNetwork->nodes[i]->index, (void*)aiNetwork->nodes[i], writeStream.tellp());
- writeStream.write((char*)&diskNode, sizeof(CAI_NodeDisk));
-
- calculatedLinkcount += aiNetwork->nodes[i]->linkcount;
- }
-
- // links
- spdlog::info("linkcount: {}", aiNetwork->linkcount);
- spdlog::info("calculated total linkcount: {}", calculatedLinkcount);
-
- calculatedLinkcount /= 2;
- if (Cvar_ns_ai_dumpAINfileFromLoad->GetBool())
- {
- if (aiNetwork->linkcount == calculatedLinkcount)
- spdlog::info("caculated linkcount is normal!");
- else
- spdlog::warn("calculated linkcount has weird value! this is expected on build!");
- }
-
- spdlog::info("writing linkcount: {}", calculatedLinkcount);
- writeStream.write((char*)&calculatedLinkcount, sizeof(int));
-
- for (int i = 0; i < aiNetwork->nodecount; i++)
- {
- for (int j = 0; j < aiNetwork->nodes[i]->linkcount; j++)
- {
- // skip links that don't originate from current node
- if (aiNetwork->nodes[i]->links[j]->srcId != aiNetwork->nodes[i]->index)
- continue;
-
- CAI_NodeLinkDisk diskLink;
- diskLink.srcId = aiNetwork->nodes[i]->links[j]->srcId;
- diskLink.destId = aiNetwork->nodes[i]->links[j]->destId;
- diskLink.unk0 = aiNetwork->nodes[i]->links[j]->unk1;
- memcpy(diskLink.hulls, aiNetwork->nodes[i]->links[j]->hulls, sizeof(diskLink.hulls));
-
- spdlog::info("writing link {} => {} to {:x}", diskLink.srcId, diskLink.destId, writeStream.tellp());
- writeStream.write((char*)&diskLink, sizeof(CAI_NodeLinkDisk));
- }
- }
-
- // don't know what this is, it's likely a block from tf1 that got deprecated? should just be 1 int per node
- spdlog::info("writing {:x} bytes for unknown block at {:x}", aiNetwork->nodecount * sizeof(uint32_t), writeStream.tellp());
- uint32_t* unkNodeBlock = new uint32_t[aiNetwork->nodecount];
- memset(unkNodeBlock, 0, aiNetwork->nodecount * sizeof(uint32_t));
- writeStream.write((char*)unkNodeBlock, aiNetwork->nodecount * sizeof(uint32_t));
- delete[] unkNodeBlock;
-
- // TODO: this is traverse nodes i think? these aren't used in tf2 ains so we can get away with just writing count=0 and skipping
- // but ideally should actually dump these
- spdlog::info("writing {} traversal nodes at {:x}...", 0, writeStream.tellp());
- short traverseNodeCount = 0;
- writeStream.write((char*)&traverseNodeCount, sizeof(short));
- // only write count since count=0 means we don't have to actually do anything here
-
- // TODO: ideally these should be actually dumped, but they're always 0 in tf2 from what i can tell
- spdlog::info("writing {} bytes for unknown hull block at {:x}", MAX_HULLS * 8, writeStream.tellp());
- char* unkHullBlock = new char[MAX_HULLS * 8];
- memset(unkHullBlock, 0, MAX_HULLS * 8);
- writeStream.write(unkHullBlock, MAX_HULLS * 8);
- delete[] unkHullBlock;
-
- // unknown struct that's seemingly node-related
- spdlog::info("writing {} unknown node structs at {:x}", *pUnkStruct0Count, writeStream.tellp());
- writeStream.write((char*)pUnkStruct0Count, sizeof(*pUnkStruct0Count));
- for (int i = 0; i < *pUnkStruct0Count; i++)
- {
- spdlog::info("writing unknown node struct {} at {:x}", i, writeStream.tellp());
- UnkNodeStruct0* nodeStruct = (*pppUnkNodeStruct0s)[i];
-
- writeStream.write((char*)&nodeStruct->index, sizeof(nodeStruct->index));
- writeStream.write((char*)&nodeStruct->unk1, sizeof(nodeStruct->unk1));
-
- writeStream.write((char*)&nodeStruct->x, sizeof(nodeStruct->x));
- writeStream.write((char*)&nodeStruct->y, sizeof(nodeStruct->y));
- writeStream.write((char*)&nodeStruct->z, sizeof(nodeStruct->z));
-
- writeStream.write((char*)&nodeStruct->unkcount0, sizeof(nodeStruct->unkcount0));
- for (int j = 0; j < nodeStruct->unkcount0; j++)
- {
- short unk2Short = (short)nodeStruct->unk2[j];
- writeStream.write((char*)&unk2Short, sizeof(unk2Short));
- }
-
- writeStream.write((char*)&nodeStruct->unkcount1, sizeof(nodeStruct->unkcount1));
- for (int j = 0; j < nodeStruct->unkcount1; j++)
- {
- short unk3Short = (short)nodeStruct->unk3[j];
- writeStream.write((char*)&unk3Short, sizeof(unk3Short));
- }
-
- writeStream.write((char*)&nodeStruct->unk5, sizeof(nodeStruct->unk5));
- }
-
- // unknown struct that's seemingly link-related
- spdlog::info("writing {} unknown link structs at {:x}", *pUnkLinkStruct1Count, writeStream.tellp());
- writeStream.write((char*)pUnkLinkStruct1Count, sizeof(*pUnkLinkStruct1Count));
- for (int i = 0; i < *pUnkLinkStruct1Count; i++)
- {
- // disk and memory structs are literally identical here so just directly write
- spdlog::info("writing unknown link struct {} at {:x}", i, writeStream.tellp());
- writeStream.write((char*)(*pppUnkStruct1s)[i], sizeof(*(*pppUnkStruct1s)[i]));
- }
-
- // some weird int idk what this is used for
- writeStream.write((char*)&aiNetwork->unk5, sizeof(aiNetwork->unk5));
-
- // tf2-exclusive stuff past this point, i.e. ain v57 only
- spdlog::info("writing {} script nodes at {:x}", aiNetwork->scriptnodecount, writeStream.tellp());
- writeStream.write((char*)&aiNetwork->scriptnodecount, sizeof(aiNetwork->scriptnodecount));
- for (int i = 0; i < aiNetwork->scriptnodecount; i++)
- {
- // disk and memory structs are literally identical here so just directly write
- spdlog::info("writing script node {} at {:x}", i, writeStream.tellp());
- writeStream.write((char*)&aiNetwork->scriptnodes[i], sizeof(aiNetwork->scriptnodes[i]));
- }
-
- spdlog::info("writing {} hints at {:x}", aiNetwork->hintcount, writeStream.tellp());
- writeStream.write((char*)&aiNetwork->hintcount, sizeof(aiNetwork->hintcount));
- for (int i = 0; i < aiNetwork->hintcount; i++)
- {
- spdlog::info("writing hint data {} at {:x}", i, writeStream.tellp());
- writeStream.write((char*)&aiNetwork->hints[i], sizeof(aiNetwork->hints[i]));
- }
-
- writeStream.close();
-}
-
-AUTOHOOK(CAI_NetworkBuilder__Build, server.dll + 0x385E20,
-void,, (void* builder, CAI_Network* aiNetwork, void* unknown))
-{
- CAI_NetworkBuilder__Build(builder, aiNetwork, unknown);
-
- DumpAINInfo(aiNetwork);
-}
-
-AUTOHOOK(LoadAINFile, server.dll + 0x3933A0,
-void,, (void* aimanager, void* buf, const char* filename))
-{
- LoadAINFile(aimanager, buf, filename);
-
- if (Cvar_ns_ai_dumpAINfileFromLoad->GetBool())
- {
- spdlog::info("running DumpAINInfo for loaded file {}", filename);
- DumpAINInfo(*(CAI_Network**)((char*)aimanager + 2536));
- }
-}
-
-ON_DLL_LOAD("server.dll", BuildAINFile, (CModule module))
-{
- AUTOHOOK_DISPATCH()
-
- Cvar_ns_ai_dumpAINfileFromLoad = new ConVar(
- "ns_ai_dumpAINfileFromLoad", "0", FCVAR_NONE, "For debugging: whether we should dump ain data for ains loaded from disk");
-
- pUnkStruct0Count = module.Offset(0x1063BF8).As<int*>();
- pppUnkNodeStruct0s = module.Offset(0x1063BE0).As<UnkNodeStruct0***>();
- pUnkLinkStruct1Count = module.Offset(0x1063AA8).As<int*>();
- pppUnkStruct1s = module.Offset(0x1063A90).As<UnkLinkStruct1***>();
- pUnkServerMapversionGlobal = module.Offset(0xBFBE08).As<char**>();
-}
\ No newline at end of file +#include "pch.h" +#include "convar.h" +#include "hoststate.h" +#include "r2engine.h" + +#include <fstream> +#include <filesystem> + +AUTOHOOK_INIT() + +namespace fs = std::filesystem; + +const int AINET_VERSION_NUMBER = 57; +const int AINET_SCRIPT_VERSION_NUMBER = 21; +const int PLACEHOLDER_CRC = 0; +const int MAX_HULLS = 5; + +#pragma pack(push, 1) +struct CAI_NodeLink +{ + short srcId; + short destId; + bool hulls[MAX_HULLS]; + char unk0; + char unk1; // maps => unk0 on disk + char unk2[5]; + int64_t flags; +}; +#pragma pack(pop) + +#pragma pack(push, 1) +struct CAI_NodeLinkDisk +{ + short srcId; + short destId; + char unk0; + bool hulls[MAX_HULLS]; +}; +#pragma pack(pop) + +#pragma pack(push, 1) +struct CAI_Node +{ + int index; // not present on disk + float x; + float y; + float z; + float hulls[MAX_HULLS]; + float yaw; + + 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 and death wish + char unk3[MAX_HULLS]; // hell on earth, should map to unk3 on disk + char pad[3]; // aligns next bytes + float unk4[MAX_HULLS]; // i have no fucking clue, calculated using some kind of demon hell function float magic + + CAI_NodeLink** links; + char unk5[16]; + int linkcount; + int unk11; // bad name lmao + 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 +}; +#pragma pack(pop) + +// the way CAI_Nodes are represented in on-disk ain files +#pragma pack(push, 1) +struct CAI_NodeDisk +{ + float x; + float y; + float z; + float yaw; + float hulls[MAX_HULLS]; + + char unk0; + int unk1; + short unk2[MAX_HULLS]; + char unk3[MAX_HULLS]; + short unk4; + short unk5; + char unk6[8]; +}; // total size of 68 bytes +#pragma pack(pop) + +#pragma pack(push, 1) +struct UnkNodeStruct0 +{ + int index; + char unk0; + char unk1; // maps to unk1 on disk + char pad0[2]; // padding to +8 + + float x; + float y; + float z; + + char pad5[4]; + int* unk2; // maps to unk5 on disk; + char pad1[16]; // pad to +48 + int unkcount0; // maps to unkcount0 on disk + + char pad2[4]; // pad to +56 + int* unk3; + char pad3[16]; // pad to +80 + int unkcount1; + + char pad4[132]; + char unk5; +}; +#pragma pack(pop) + +int* pUnkStruct0Count; +UnkNodeStruct0*** pppUnkNodeStruct0s; + +#pragma pack(push, 1) +struct UnkLinkStruct1 +{ + short unk0; + short unk1; + int unk2; + char unk3; + char unk4; + char unk5; +}; +#pragma pack(pop) + +int* pUnkLinkStruct1Count; +UnkLinkStruct1*** pppUnkStruct1s; + +#pragma pack(push, 1) +struct CAI_ScriptNode +{ + float x; + float y; + float z; + uint64_t scriptdata; +}; +#pragma pack(pop) + +#pragma pack(push, 1) +struct CAI_Network +{ + // +0 + char unk0[8]; + // +8 + int linkcount; // this is uninitialised and never set on ain build, fun! + // +12 + char unk1[124]; + // +136 + int zonecount; + // +140 + char unk2[16]; + // +156 + int unk5; // unk8 on disk + // +160 + char unk6[4]; + // +164 + int hintcount; + // +168 + short hints[2000]; // these probably aren't actually hints, but there's 1 of them per hint so idk + // +4168 + int scriptnodecount; + // +4172 + CAI_ScriptNode scriptnodes[4000]; + // +84172 + int nodecount; + // +84176 + CAI_Node** nodes; +}; +#pragma pack(pop) + +char** pUnkServerMapversionGlobal; + +ConVar* Cvar_ns_ai_dumpAINfileFromLoad; + +void DumpAINInfo(CAI_Network* aiNetwork) +{ + fs::path writePath(fmt::format("{}/maps/graphs", "r2")); + writePath /= R2::g_pHostState->m_levelName; + writePath += ".ain"; + + // dump from memory + spdlog::info("writing ain file {}", writePath.string()); + spdlog::info(""); + spdlog::info(""); + spdlog::info(""); + spdlog::info(""); + spdlog::info(""); + + std::ofstream writeStream(writePath, std::ofstream::binary); + spdlog::info("writing ainet version: {}", AINET_VERSION_NUMBER); + writeStream.write((char*)&AINET_VERSION_NUMBER, sizeof(int)); + + // could probably be cleaner but whatever + int mapVersion = *(int*)(*pUnkServerMapversionGlobal + 104); + spdlog::info("writing map version: {}", mapVersion); // temp + writeStream.write((char*)&mapVersion, sizeof(int)); + spdlog::info("writing placeholder crc: {}", PLACEHOLDER_CRC); + writeStream.write((char*)&PLACEHOLDER_CRC, sizeof(int)); + + int calculatedLinkcount = 0; + + // path nodes + spdlog::info("writing nodecount: {}", aiNetwork->nodecount); + writeStream.write((char*)&aiNetwork->nodecount, sizeof(int)); + + for (int i = 0; i < aiNetwork->nodecount; i++) + { + // construct on-disk node struct + CAI_NodeDisk diskNode; + diskNode.x = aiNetwork->nodes[i]->x; + diskNode.y = aiNetwork->nodes[i]->y; + diskNode.z = aiNetwork->nodes[i]->z; + diskNode.yaw = aiNetwork->nodes[i]->yaw; + memcpy(diskNode.hulls, aiNetwork->nodes[i]->hulls, sizeof(diskNode.hulls)); + diskNode.unk0 = (char)aiNetwork->nodes[i]->unk0; + diskNode.unk1 = aiNetwork->nodes[i]->unk1; + + for (int j = 0; j < MAX_HULLS; j++) + { + diskNode.unk2[j] = (short)aiNetwork->nodes[i]->unk2[j]; + spdlog::info((short)aiNetwork->nodes[i]->unk2[j]); + } + + memcpy(diskNode.unk3, aiNetwork->nodes[i]->unk3, sizeof(diskNode.unk3)); + diskNode.unk4 = aiNetwork->nodes[i]->unk6; + diskNode.unk5 = + -1; // aiNetwork->nodes[i]->unk8; // this field is wrong, however, it's always -1 in vanilla navmeshes anyway, so no biggie + memcpy(diskNode.unk6, aiNetwork->nodes[i]->unk10, sizeof(diskNode.unk6)); + + spdlog::info("writing node {} from {} to {:x}", aiNetwork->nodes[i]->index, (void*)aiNetwork->nodes[i], writeStream.tellp()); + writeStream.write((char*)&diskNode, sizeof(CAI_NodeDisk)); + + calculatedLinkcount += aiNetwork->nodes[i]->linkcount; + } + + // links + spdlog::info("linkcount: {}", aiNetwork->linkcount); + spdlog::info("calculated total linkcount: {}", calculatedLinkcount); + + calculatedLinkcount /= 2; + if (Cvar_ns_ai_dumpAINfileFromLoad->GetBool()) + { + if (aiNetwork->linkcount == calculatedLinkcount) + spdlog::info("caculated linkcount is normal!"); + else + spdlog::warn("calculated linkcount has weird value! this is expected on build!"); + } + + spdlog::info("writing linkcount: {}", calculatedLinkcount); + writeStream.write((char*)&calculatedLinkcount, sizeof(int)); + + for (int i = 0; i < aiNetwork->nodecount; i++) + { + for (int j = 0; j < aiNetwork->nodes[i]->linkcount; j++) + { + // skip links that don't originate from current node + if (aiNetwork->nodes[i]->links[j]->srcId != aiNetwork->nodes[i]->index) + continue; + + CAI_NodeLinkDisk diskLink; + diskLink.srcId = aiNetwork->nodes[i]->links[j]->srcId; + diskLink.destId = aiNetwork->nodes[i]->links[j]->destId; + diskLink.unk0 = aiNetwork->nodes[i]->links[j]->unk1; + memcpy(diskLink.hulls, aiNetwork->nodes[i]->links[j]->hulls, sizeof(diskLink.hulls)); + + spdlog::info("writing link {} => {} to {:x}", diskLink.srcId, diskLink.destId, writeStream.tellp()); + writeStream.write((char*)&diskLink, sizeof(CAI_NodeLinkDisk)); + } + } + + // don't know what this is, it's likely a block from tf1 that got deprecated? should just be 1 int per node + spdlog::info("writing {:x} bytes for unknown block at {:x}", aiNetwork->nodecount * sizeof(uint32_t), writeStream.tellp()); + uint32_t* unkNodeBlock = new uint32_t[aiNetwork->nodecount]; + memset(unkNodeBlock, 0, aiNetwork->nodecount * sizeof(uint32_t)); + writeStream.write((char*)unkNodeBlock, aiNetwork->nodecount * sizeof(uint32_t)); + delete[] unkNodeBlock; + + // TODO: this is traverse nodes i think? these aren't used in tf2 ains so we can get away with just writing count=0 and skipping + // but ideally should actually dump these + spdlog::info("writing {} traversal nodes at {:x}...", 0, writeStream.tellp()); + short traverseNodeCount = 0; + writeStream.write((char*)&traverseNodeCount, sizeof(short)); + // only write count since count=0 means we don't have to actually do anything here + + // TODO: ideally these should be actually dumped, but they're always 0 in tf2 from what i can tell + spdlog::info("writing {} bytes for unknown hull block at {:x}", MAX_HULLS * 8, writeStream.tellp()); + char* unkHullBlock = new char[MAX_HULLS * 8]; + memset(unkHullBlock, 0, MAX_HULLS * 8); + writeStream.write(unkHullBlock, MAX_HULLS * 8); + delete[] unkHullBlock; + + // unknown struct that's seemingly node-related + spdlog::info("writing {} unknown node structs at {:x}", *pUnkStruct0Count, writeStream.tellp()); + writeStream.write((char*)pUnkStruct0Count, sizeof(*pUnkStruct0Count)); + for (int i = 0; i < *pUnkStruct0Count; i++) + { + spdlog::info("writing unknown node struct {} at {:x}", i, writeStream.tellp()); + UnkNodeStruct0* nodeStruct = (*pppUnkNodeStruct0s)[i]; + + writeStream.write((char*)&nodeStruct->index, sizeof(nodeStruct->index)); + writeStream.write((char*)&nodeStruct->unk1, sizeof(nodeStruct->unk1)); + + writeStream.write((char*)&nodeStruct->x, sizeof(nodeStruct->x)); + writeStream.write((char*)&nodeStruct->y, sizeof(nodeStruct->y)); + writeStream.write((char*)&nodeStruct->z, sizeof(nodeStruct->z)); + + writeStream.write((char*)&nodeStruct->unkcount0, sizeof(nodeStruct->unkcount0)); + for (int j = 0; j < nodeStruct->unkcount0; j++) + { + short unk2Short = (short)nodeStruct->unk2[j]; + writeStream.write((char*)&unk2Short, sizeof(unk2Short)); + } + + writeStream.write((char*)&nodeStruct->unkcount1, sizeof(nodeStruct->unkcount1)); + for (int j = 0; j < nodeStruct->unkcount1; j++) + { + short unk3Short = (short)nodeStruct->unk3[j]; + writeStream.write((char*)&unk3Short, sizeof(unk3Short)); + } + + writeStream.write((char*)&nodeStruct->unk5, sizeof(nodeStruct->unk5)); + } + + // unknown struct that's seemingly link-related + spdlog::info("writing {} unknown link structs at {:x}", *pUnkLinkStruct1Count, writeStream.tellp()); + writeStream.write((char*)pUnkLinkStruct1Count, sizeof(*pUnkLinkStruct1Count)); + for (int i = 0; i < *pUnkLinkStruct1Count; i++) + { + // disk and memory structs are literally identical here so just directly write + spdlog::info("writing unknown link struct {} at {:x}", i, writeStream.tellp()); + writeStream.write((char*)(*pppUnkStruct1s)[i], sizeof(*(*pppUnkStruct1s)[i])); + } + + // some weird int idk what this is used for + writeStream.write((char*)&aiNetwork->unk5, sizeof(aiNetwork->unk5)); + + // tf2-exclusive stuff past this point, i.e. ain v57 only + spdlog::info("writing {} script nodes at {:x}", aiNetwork->scriptnodecount, writeStream.tellp()); + writeStream.write((char*)&aiNetwork->scriptnodecount, sizeof(aiNetwork->scriptnodecount)); + for (int i = 0; i < aiNetwork->scriptnodecount; i++) + { + // disk and memory structs are literally identical here so just directly write + spdlog::info("writing script node {} at {:x}", i, writeStream.tellp()); + writeStream.write((char*)&aiNetwork->scriptnodes[i], sizeof(aiNetwork->scriptnodes[i])); + } + + spdlog::info("writing {} hints at {:x}", aiNetwork->hintcount, writeStream.tellp()); + writeStream.write((char*)&aiNetwork->hintcount, sizeof(aiNetwork->hintcount)); + for (int i = 0; i < aiNetwork->hintcount; i++) + { + spdlog::info("writing hint data {} at {:x}", i, writeStream.tellp()); + writeStream.write((char*)&aiNetwork->hints[i], sizeof(aiNetwork->hints[i])); + } + + writeStream.close(); +} + +AUTOHOOK(CAI_NetworkBuilder__Build, server.dll + 0x385E20, +void,, (void* builder, CAI_Network* aiNetwork, void* unknown)) +{ + CAI_NetworkBuilder__Build(builder, aiNetwork, unknown); + + DumpAINInfo(aiNetwork); +} + +AUTOHOOK(LoadAINFile, server.dll + 0x3933A0, +void,, (void* aimanager, void* buf, const char* filename)) +{ + LoadAINFile(aimanager, buf, filename); + + if (Cvar_ns_ai_dumpAINfileFromLoad->GetBool()) + { + spdlog::info("running DumpAINInfo for loaded file {}", filename); + DumpAINInfo(*(CAI_Network**)((char*)aimanager + 2536)); + } +} + +ON_DLL_LOAD("server.dll", BuildAINFile, (CModule module)) +{ + AUTOHOOK_DISPATCH() + + Cvar_ns_ai_dumpAINfileFromLoad = new ConVar( + "ns_ai_dumpAINfileFromLoad", "0", FCVAR_NONE, "For debugging: whether we should dump ain data for ains loaded from disk"); + + pUnkStruct0Count = module.Offset(0x1063BF8).As<int*>(); + pppUnkNodeStruct0s = module.Offset(0x1063BE0).As<UnkNodeStruct0***>(); + pUnkLinkStruct1Count = module.Offset(0x1063AA8).As<int*>(); + pppUnkStruct1s = module.Offset(0x1063A90).As<UnkLinkStruct1***>(); + pUnkServerMapversionGlobal = module.Offset(0xBFBE08).As<char**>(); +} |