aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2022-02-16 16:53:36 +0000
committerBobTheBob <32057864+BobTheBob9@users.noreply.github.com>2022-02-16 16:53:36 +0000
commit1a7b41cc722c05eb97006d29e124c17559c45324 (patch)
tree7e8798125360b8f58ba4f549fce018358c2fa7ad
parent37212a4d0cb59929af6366b48d0a8cc110f06912 (diff)
downloadNorthstarLauncher-1a7b41cc722c05eb97006d29e124c17559c45324.tar.gz
NorthstarLauncher-1a7b41cc722c05eb97006d29e124c17559c45324.zip
functional ain dumping
-rw-r--r--NorthstarDedicatedTest/buildainfile.cpp186
1 files changed, 162 insertions, 24 deletions
diff --git a/NorthstarDedicatedTest/buildainfile.cpp b/NorthstarDedicatedTest/buildainfile.cpp
index b4277128..7962a70e 100644
--- a/NorthstarDedicatedTest/buildainfile.cpp
+++ b/NorthstarDedicatedTest/buildainfile.cpp
@@ -3,6 +3,9 @@
#include "convar.h"
#include "hookutils.h"
#include <fstream>
+#include <filesystem>
+
+namespace fs = std::filesystem;
const int AINET_VERSION_NUMBER = 57;
const int AINET_SCRIPT_VERSION_NUMBER = 21;
@@ -21,7 +24,7 @@ struct CAI_NodeLink
int64_t flags;
};
-#pragma pack(push, 1)
+#pragma pack (push, 1)
struct CAI_NodeLinkDisk
{
short srcId;
@@ -51,8 +54,8 @@ struct CAI_Node
CAI_NodeLink** links;
char unk5[16];
int linkcount;
- int unk11; // bad name lmao
- short unk6; // should match up to unk4 on disk
+ 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
@@ -60,7 +63,7 @@ struct CAI_Node
};
// the way CAI_Nodes are represented in on-disk ain files
-#pragma pack(push, 1)
+#pragma pack (push, 1)
struct CAI_NodeDisk
{
float x;
@@ -78,6 +81,54 @@ struct CAI_NodeDisk
char unk6[8];
}; // total size of 68 bytes
+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;
+
+ short* unk2; // maps to unk5 on disk;
+ char pad1[12]; // pad to +48
+ int unkcount0; // maps to unkcount0 on disk
+
+ char pad2[4]; // pad to +56
+ short* unk3;
+ char pad3[16]; // pad to +80
+ int unkcount1;
+
+ char pad4[132];
+ char unk5;
+};
+
+int* pUnkStruct0Count;
+UnkNodeStruct0*** pppUnkNodeStruct0s;
+
+struct UnkLinkStruct1
+{
+ short unk0;
+ short unk1;
+ int unk2;
+ char unk3;
+ char unk4;
+ char unk5;
+};
+
+int* pUnkLinkStruct1Count;
+UnkLinkStruct1*** pppUnkStruct1s;
+
+struct CAI_ScriptNode
+{
+ float x;
+ float y;
+ float z;
+ uint64_t scriptdata;
+};
+
struct CAI_Network
{
// +0
@@ -89,38 +140,52 @@ struct CAI_Network
// +136
int zonecount;
// +140
- char unk2[24];
+ char unk2[16];
+ // +156
+ int unk5; // unk8 on disk
+ // +160
+ char unk6[4];
// +164
int hintcount;
// +168
- char unk3[4000];
+ short hints[2000]; // these probably aren't actually hints, but there's 1 of them per hint so idk
// +4168
int scriptnodecount;
// +4172
- char unk4[80000];
+ CAI_ScriptNode scriptnodes[4000];
// +84172
int nodecount;
// +84176
CAI_Node** nodes;
};
+char** pUnkServerMapversionGlobal;
+char* pMapName;
+
ConVar* Cvar_ns_ai_dumpAINfileFromLoad;
void DumpAINInfo(CAI_Network* aiNetwork)
{
+ fs::path writePath("r2/maps/graphs");
+ writePath /= pMapName;
+ writePath += ".ain";
+
// dump from memory
- spdlog::info("writing .ain to file....");
+ spdlog::info("writing ain file {}", writePath.string());
spdlog::info("");
spdlog::info("");
spdlog::info("");
spdlog::info("");
spdlog::info("");
- std::ofstream writeStream("dumped_ain.ain", std::ofstream::binary);
+ std::ofstream writeStream(writePath, std::ofstream::binary);
spdlog::info("writing ainet version: {}", AINET_VERSION_NUMBER);
writeStream.write((char*)&AINET_VERSION_NUMBER, sizeof(int));
- spdlog::info("writing map version: {}", MAP_VERSION_TEMP); // temp
- writeStream.write((char*)&MAP_VERSION_TEMP, 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));
@@ -150,8 +215,7 @@ void DumpAINInfo(CAI_Network* aiNetwork)
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
+ 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());
@@ -160,6 +224,7 @@ void DumpAINInfo(CAI_Network* aiNetwork)
calculatedLinkcount += aiNetwork->nodes[i]->linkcount;
}
+ // links
spdlog::info("linkcount: {}", aiNetwork->linkcount);
spdlog::info("calculated total linkcount: {}", calculatedLinkcount);
@@ -170,7 +235,7 @@ void DumpAINInfo(CAI_Network* aiNetwork)
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));
@@ -194,21 +259,88 @@ void DumpAINInfo(CAI_Network* aiNetwork)
}
}
- // don't know what this is, it's likely a block from tf1 that got deprecated?
+ // 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;
- spdlog::info("hintcount: {}", aiNetwork->hintcount);
- spdlog::info("scriptnodecount: {}", aiNetwork->scriptnodecount);
- spdlog::info("zonecount: {}", aiNetwork->zonecount);
+ // 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 i = 0; i < nodeStruct->unkcount0; i++)
+ writeStream.write((char*)&nodeStruct->unk2[i], sizeof(nodeStruct->unk2[i]));
+
+ writeStream.write((char*)&nodeStruct->unkcount1, sizeof(nodeStruct->unkcount1));
+ for (int i = 0; i < nodeStruct->unkcount1; i++)
+ writeStream.write((char*)&nodeStruct->unk3[i], sizeof(nodeStruct->unk3[i]));
+
+ 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();
}
-typedef void (*CAI_NetworkBuilder__BuildType)(void* builder, CAI_Network* aiNetwork, void* unknown);
+typedef void(*CAI_NetworkBuilder__BuildType)(void* builder, CAI_Network* aiNetwork, void* unknown);
CAI_NetworkBuilder__BuildType CAI_NetworkBuilder__Build;
void CAI_NetworkBuilder__BuildHook(void* builder, CAI_Network* aiNetwork, void* unknown)
@@ -218,7 +350,7 @@ void CAI_NetworkBuilder__BuildHook(void* builder, CAI_Network* aiNetwork, void*
DumpAINInfo(aiNetwork);
}
-typedef void (*LoadAINFileType)(void* aimanager, void* buf, const char* filename);
+typedef void(*LoadAINFileType)(void* aimanager, void* buf, const char* filename);
LoadAINFileType LoadAINFile;
void LoadAINFileHook(void* aimanager, void* buf, const char* filename)
@@ -234,14 +366,20 @@ void LoadAINFileHook(void* aimanager, void* buf, const char* filename)
void InitialiseBuildAINFileHooks(HMODULE baseAddress)
{
- Cvar_ns_ai_dumpAINfileFromLoad = RegisterConVar(
- "ns_ai_dumpAINfileFromLoad", "0", FCVAR_NONE, "For debugging: whether we should dump ain data for ains loaded from disk");
+ Cvar_ns_ai_dumpAINfileFromLoad = RegisterConVar("ns_ai_dumpAINfileFromLoad", "0", FCVAR_NONE, "For debugging: whether we should dump ain data for ains loaded from disk");
HookEnabler hook;
- ENABLER_CREATEHOOK(
- hook, (char*)baseAddress + 0x385E20, &CAI_NetworkBuilder__BuildHook, reinterpret_cast<LPVOID*>(&CAI_NetworkBuilder__Build));
+ ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x385E20, &CAI_NetworkBuilder__BuildHook, reinterpret_cast<LPVOID*>(&CAI_NetworkBuilder__Build));
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x3933A0, &LoadAINFileHook, reinterpret_cast<LPVOID*>(&LoadAINFile));
+ pUnkStruct0Count = (int*)((char*)baseAddress + 0x1063BF8);
+ pppUnkNodeStruct0s = (UnkNodeStruct0***)((char*)baseAddress + 0x1063BE0);
+
+ pUnkLinkStruct1Count = (int*)((char*)baseAddress + 0x1063AA8);
+ pppUnkStruct1s = (UnkLinkStruct1***)((char*)baseAddress + 0x1063A90);
+ pUnkServerMapversionGlobal = (char**)((char*)baseAddress + 0xBFBE08);
+ pMapName = (char*)baseAddress + 0x1053370;
+
// remove a check that prevents a logging function in link generation from working
// due to the sheer amount of logging this is a massive perf hit to generation, but spewlog_enable 0 exists so whatever
{