2022-02-27 03:15:00 +01:00
//=============================================================================//
//
// Purpose:
//
//=============================================================================//
# include "core/stdafx.h"
2022-03-22 01:59:02 +01:00
# include "tier0/fasttimer.h"
2022-04-09 16:16:40 +02:00
# include "tier1/cvar.h"
# include "tier1/cmd.h"
2022-03-22 01:59:02 +01:00
# include "mathlib/crc32.h"
2022-08-09 17:18:07 +02:00
# include "public/edict.h"
2022-08-23 21:32:12 +02:00
# include "filesystem/filesystem.h"
2022-02-27 03:15:00 +01:00
# include "game/server/ai_node.h"
# include "game/server/ai_network.h"
# include "game/server/ai_networkmanager.h"
2023-08-24 23:44:57 +02:00
# include <public/worldsize.h>
2022-02-27 03:15:00 +01:00
2022-03-22 17:18:29 +01:00
constexpr int AINET_SCRIPT_VERSION_NUMBER = 21 ;
constexpr int AINET_VERSION_NUMBER = 57 ;
2022-08-31 12:49:48 +02:00
constexpr int AINET_MIN_FILE_SIZE = 82 ;
2022-11-03 17:12:22 +01:00
constexpr const char * AINETWORK_EXT = " .ain " ;
constexpr const char * AINETWORK_PATH = " maps/graphs/ " ;
2022-02-27 03:15:00 +01:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CAI_NetworkBuilder : : BuildFile
Build AI node graph file from
in - memory structures and write
to disk to be loaded
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2022-03-22 01:59:02 +01:00
void CAI_NetworkBuilder : : SaveNetworkGraph ( CAI_Network * pNetwork )
2022-02-27 03:15:00 +01:00
{
2023-08-24 23:44:57 +02:00
//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;
//}
2022-11-14 01:01:28 +01:00
char szMeshPath [ MAX_PATH ] ;
char szGraphPath [ MAX_PATH ] ;
2022-03-22 01:59:02 +01:00
2023-05-01 22:51:31 +02:00
V_snprintf ( szMeshPath , sizeof ( szMeshPath ) , " %s%s_%s%s " , NAVMESH_PATH , g_ServerGlobalVariables - > m_pszMapName , S_HULL_TYPE [ E_HULL_TYPE : : LARGE ] , NAVMESH_EXT ) ;
2022-11-14 01:01:28 +01:00
V_snprintf ( szGraphPath , sizeof ( szGraphPath ) , " %s%s%s " , AINETWORK_PATH , g_ServerGlobalVariables - > m_pszMapName , AINETWORK_EXT ) ;
2022-03-22 01:59:02 +01:00
CFastTimer masterTimer ;
CFastTimer timer ;
2022-03-22 17:18:29 +01:00
// Build from memory.
2023-08-21 19:12:29 +02:00
Msg ( eDLL_T : : SERVER , " ++++--------------------------------------------------------------------------------------------------------------------------++++ \n " ) ;
Msg ( eDLL_T : : SERVER , " >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> AI NETWORK GRAPH FILE CONSTRUCTION STARTED <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< \n " ) ;
Msg ( eDLL_T : : SERVER , " ++++--------------------------------------------------------------------------------------------------------------------------++++ \n " ) ;
2022-03-22 01:59:02 +01:00
masterTimer . Start ( ) ;
timer . Start ( ) ;
2023-08-24 10:35:54 +02:00
FileSystem ( ) - > CreateDirHierarchy ( AINETWORK_PATH , " GAME " ) ;
2022-11-14 01:01:28 +01:00
FileHandle_t pAIGraph = FileSystem ( ) - > Open ( szGraphPath , " wb " , " GAME " ) ;
2022-08-23 21:32:12 +02:00
if ( ! pAIGraph )
{
2022-11-14 01:01:28 +01:00
Error ( eDLL_T : : SERVER , NO_ERROR , " %s - Unable to write to '%s' (read-only?) \n " , __FUNCTION__ , szGraphPath ) ;
2022-08-23 21:32:12 +02:00
return ;
}
2022-03-20 17:03:46 +01:00
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing header... \n " ) ;
DevMsg ( eDLL_T : : SERVER , " |-- AINet version: '%d' \n " , AINET_VERSION_NUMBER ) ;
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Write ( & AINET_VERSION_NUMBER , sizeof ( int ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Map version: '%d' \n " , g_ServerGlobalVariables - > m_nMapVersion ) ;
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Write ( & g_ServerGlobalVariables - > m_nMapVersion , sizeof ( int ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
2022-11-14 01:01:28 +01:00
FileHandle_t pNavMesh = FileSystem ( ) - > Open ( szMeshPath , " rb " , " GAME " ) ;
2023-08-24 23:44:57 +02:00
uint32_t nNavMeshCRC = NULL ;
2022-08-23 21:32:12 +02:00
if ( ! pNavMesh )
2022-03-22 01:59:02 +01:00
{
2023-08-24 10:35:54 +02:00
Warning ( eDLL_T : : SERVER , " %s - No %s NavMesh found. Unable to calculate CRC for AI Network \n " ,
__FUNCTION__ , S_HULL_TYPE [ E_HULL_TYPE : : LARGE ] ) ;
2022-03-22 01:59:02 +01:00
}
else
{
2023-08-09 14:43:54 +02:00
const ssize_t nLen = FileSystem ( ) - > Size ( pNavMesh ) ;
2023-06-26 22:34:24 +02:00
std : : unique_ptr < uint8_t [ ] > pBuf ( new uint8_t [ nLen ] ) ;
2022-08-23 21:32:12 +02:00
2023-06-26 22:34:24 +02:00
FileSystem ( ) - > Read ( pBuf . get ( ) , nLen , pNavMesh ) ;
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Close ( pNavMesh ) ;
2023-08-24 23:44:57 +02:00
nNavMeshCRC = crc32 : : update ( NULL , pBuf . get ( ) , nLen ) ;
2022-03-22 01:59:02 +01:00
}
2022-03-22 17:18:29 +01:00
// Large NavMesh CRC.
2023-08-24 23:44:57 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- NavMesh CRC: '0x%lX' \n " , nNavMeshCRC ) ;
FileSystem ( ) - > Write ( & nNavMeshCRC , sizeof ( uint32_t ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
2022-03-22 17:18:29 +01:00
// Path nodes.
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Node count: '%d' \n " , pNetwork - > m_iNumNodes ) ;
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Write ( & pNetwork - > m_iNumNodes , sizeof ( int ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-21 19:12:29 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing header. %lf seconds \n " , timer . GetDuration ( ) . GetSeconds ( ) ) ;
2022-03-22 01:59:02 +01:00
timer . Start ( ) ;
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing node positions... \n " ) ;
2022-08-23 21:32:12 +02:00
2022-03-24 02:08:27 +01:00
if ( pNetwork - > m_pAInode )
2022-03-20 17:03:46 +01:00
{
2023-08-24 10:35:54 +02:00
int totalLinkCount = 0 ;
2022-03-24 02:08:27 +01:00
for ( int i = 0 ; i < pNetwork - > m_iNumNodes ; i + + )
2022-03-20 17:03:46 +01:00
{
2023-08-24 10:35:54 +02:00
const CAI_Node * aiNode = pNetwork - > m_pAInode [ i ] ;
2023-08-27 00:56:38 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Copying node '#%d' from '0x%p' to '0x%zX' \n " , aiNode - > m_nIndex , aiNode , FileSystem ( ) - > Tell ( pAIGraph ) ) ;
2023-08-24 10:35:54 +02:00
2023-08-27 00:56:38 +02:00
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 ) ;
2023-08-24 10:35:54 +02:00
2023-08-27 00:56:38 +02:00
FileSystem ( ) - > Write ( & aiNode - > unk0 , sizeof ( char ) , pAIGraph ) ;
FileSystem ( ) - > Write ( & aiNode - > unk1 , sizeof ( int ) , pAIGraph ) ;
2022-03-24 02:08:27 +01:00
for ( int j = 0 ; j < MAX_HULLS ; j + + )
{
2023-08-27 00:56:38 +02:00
FileSystem ( ) - > Write ( & aiNode - > unk2 [ j ] , sizeof ( short ) , pAIGraph ) ;
2022-03-24 02:08:27 +01:00
}
2022-03-20 17:03:46 +01:00
2023-08-27 00:56:38 +02:00
FileSystem ( ) - > Write ( & aiNode - > unk3 , sizeof ( aiNode - > unk3 ) , pAIGraph ) ;
FileSystem ( ) - > Write ( & aiNode - > unk6 , sizeof ( short ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
2023-08-27 00:56:38 +02:00
// 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 ) ;
2022-03-20 17:03:46 +01:00
2023-08-24 10:35:54 +02:00
totalLinkCount + = aiNode - > m_nNumLinks ;
2022-03-24 02:08:27 +01:00
}
2023-08-24 10:35:54 +02:00
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 ;
2022-03-20 17:03:46 +01:00
}
2023-08-24 10:35:54 +02:00
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-21 19:12:29 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing node positions. %lf seconds \n " , timer . GetDuration ( ) . GetSeconds ( ) ) ;
2022-03-22 01:59:02 +01:00
timer . Start ( ) ;
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing links... \n " ) ;
DevMsg ( eDLL_T : : SERVER , " |-- Cached link count: '%d' \n " , pNetwork - > m_iNumLinks ) ;
2022-03-20 17:03:46 +01:00
2023-08-24 10:35:54 +02:00
int packedLinks = pNetwork - > m_iNumLinks / 2 ;
FileSystem ( ) - > Write ( & packedLinks , sizeof ( int ) , pAIGraph ) ;
2022-03-24 02:08:27 +01:00
if ( pNetwork - > m_pAInode )
2022-03-20 17:03:46 +01:00
{
2022-03-24 02:08:27 +01:00
for ( int i = 0 ; i < pNetwork - > m_iNumNodes ; i + + )
2022-03-20 17:03:46 +01:00
{
2023-08-24 10:35:54 +02:00
const CAI_Node * aiNode = pNetwork - > m_pAInode [ i ] ;
for ( int j = 0 ; j < aiNode - > m_nNumLinks ; j + + )
2022-03-22 01:59:02 +01:00
{
2023-08-24 10:35:54 +02:00
const CAI_NodeLink * nodeLink = aiNode - > links [ j ] ;
2022-03-24 02:08:27 +01:00
// Skip links that don't originate from current node.
2023-08-24 10:35:54 +02:00
if ( nodeLink - > m_iSrcID ! = aiNode - > m_nIndex )
2022-03-24 02:08:27 +01:00
{
continue ;
}
2023-08-27 00:56:38 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing link '%hd' => '%hd' to '0x%zX' \n " , nodeLink - > m_iSrcID , nodeLink - > m_iDestID , FileSystem ( ) - > Tell ( pAIGraph ) ) ;
2022-03-24 02:08:27 +01:00
2023-08-27 00:56:38 +02:00
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 ) ;
2022-03-22 01:59:02 +01:00
}
2022-03-20 17:03:46 +01:00
}
}
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-24 10:35:54 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing links. %lf seconds (%d links) \n " , timer . GetDuration ( ) . GetSeconds ( ) , pNetwork - > m_iNumLinks ) ;
2022-03-22 01:59:02 +01:00
timer . Start ( ) ;
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing hull data... \n " ) ;
2022-03-22 17:18:29 +01:00
// Don't know what this is, it's likely a block from tf1 that got deprecated? should just be 1 int per node.
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing '%d' bytes for node block at '0x%zX' \n " , pNetwork - > m_iNumNodes * sizeof ( uint32_t ) , FileSystem ( ) - > Tell ( pAIGraph ) ) ;
2022-03-22 17:18:29 +01:00
2022-08-11 11:07:45 +02:00
if ( pNetwork - > m_iNumNodes > 0 )
2022-03-22 17:18:29 +01:00
{
2023-06-26 22:34:24 +02:00
std : : unique_ptr < uint32 [ ] > unkNodeBlock ( new uint32_t [ pNetwork - > m_iNumNodes * sizeof ( uint32_t ) ] ) ;
2023-08-24 23:44:57 +02:00
memset ( unkNodeBlock . get ( ) , ' \0 ' , pNetwork - > m_iNumNodes * sizeof ( uint32_t ) ) ;
2022-08-23 21:32:12 +02:00
2023-06-26 22:34:24 +02:00
FileSystem ( ) - > Write ( unkNodeBlock . get ( ) , pNetwork - > m_iNumNodes * sizeof ( uint32_t ) , pAIGraph ) ;
2022-03-22 17:18:29 +01:00
}
// 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.
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing '%d' traversal nodes at '0x%zX' \n " , 0 , FileSystem ( ) - > Tell ( pAIGraph ) ) ;
2023-08-24 23:44:57 +02:00
2022-03-22 17:18:29 +01:00
short traverseNodeCount = 0 ; // Only write count since count=0 means we don't have to actually do anything here.
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Write ( & traverseNodeCount , sizeof ( short ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
2022-03-22 17:18:29 +01:00
// TODO: Ideally these should be actually dumped, but they're always 0 in r2 from what i can tell.
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing '%d' bytes for hull data block at '0x%zX' \n " , ( MAX_HULLS * 8 ) , FileSystem ( ) - > Tell ( pAIGraph ) ) ;
2022-07-20 21:06:19 +02:00
for ( int i = 0 ; i < ( MAX_HULLS * 8 ) ; i + + )
{
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Write ( " \0 " , sizeof ( char ) , pAIGraph ) ;
2022-07-20 21:06:19 +02:00
}
2022-03-20 17:03:46 +01:00
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-21 19:12:29 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing hull data. %lf seconds \n " , timer . GetDuration ( ) . GetSeconds ( ) ) ;
2022-03-22 01:59:02 +01:00
timer . Start ( ) ;
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing clusters... \n " ) ;
2022-03-22 01:59:02 +01:00
2023-08-24 23:44:57 +02:00
const int numClusters = g_pAIPathClusters - > Count ( ) ;
FileSystem ( ) - > Write ( & numClusters , sizeof ( int ) , pAIGraph ) ;
FOR_EACH_VEC ( * g_pAIPathClusters , i )
2022-03-20 17:03:46 +01:00
{
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing cluster '#%d' at '0x%zX' \n " , i , FileSystem ( ) - > Tell ( pAIGraph ) ) ;
2022-03-20 17:03:46 +01:00
2023-08-24 23:44:57 +02:00
const CAI_Cluster * pathClusters = ( * g_pAIPathClusters ) [ i ] ;
FileSystem ( ) - > Write ( & pathClusters - > m_nIndex , sizeof ( int ) , pAIGraph ) ;
FileSystem ( ) - > Write ( & pathClusters - > unk1 , sizeof ( char ) , pAIGraph ) ;
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 ) ;
2022-03-20 17:03:46 +01:00
2023-08-24 23:44:57 +02:00
const int unkVec0Size = pathClusters - > unkVec0 . Count ( ) ;
FileSystem ( ) - > Write ( & unkVec0Size , sizeof ( int ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
2023-08-24 23:44:57 +02:00
FOR_EACH_VEC ( pathClusters - > unkVec0 , j )
2022-03-20 17:03:46 +01:00
{
2023-08-24 23:44:57 +02:00
short unkShort = static_cast < short > ( pathClusters - > unkVec0 [ j ] ) ;
FileSystem ( ) - > Write ( & unkShort , sizeof ( short ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
}
2023-08-24 23:44:57 +02:00
const int unkVec1Size = pathClusters - > unkVec1 . Count ( ) ;
FileSystem ( ) - > Write ( & unkVec1Size , sizeof ( int ) , pAIGraph ) ;
FOR_EACH_VEC ( pathClusters - > unkVec1 , j )
2022-03-20 17:03:46 +01:00
{
2023-08-24 23:44:57 +02:00
short unkShort = static_cast < short > ( pathClusters - > unkVec0 [ j ] ) ;
FileSystem ( ) - > Write ( & unkShort , sizeof ( short ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
}
2023-08-24 23:44:57 +02:00
FileSystem ( ) - > Write ( & pathClusters - > unk5 , sizeof ( char ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
}
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-24 23:44:57 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing clusters. %lf seconds (%d clusters) \n " , timer . GetDuration ( ) . GetSeconds ( ) , numClusters ) ;
2022-03-22 01:59:02 +01:00
timer . Start ( ) ;
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing cluster links... \n " ) ;
2022-03-22 01:59:02 +01:00
2023-08-24 23:44:57 +02:00
const int numClusterLinks = g_pAIClusterLinks - > Count ( ) ;
FileSystem ( ) - > Write ( & numClusterLinks , sizeof ( int ) , pAIGraph ) ;
FOR_EACH_VEC ( * g_pAIClusterLinks , i )
2022-03-20 17:03:46 +01:00
{
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing cluster link '#%d' at '0x%zX' \n " , i , FileSystem ( ) - > Tell ( pAIGraph ) ) ;
2023-08-24 23:44:57 +02:00
// Disk and memory structs are literally identical here so just directly write.
const CAI_ClusterLink * clusterLink = ( * g_pAIClusterLinks ) [ i ] ;
2023-08-25 08:47:12 +02:00
FileSystem ( ) - > Write ( & clusterLink - > prevIndex_MAYBE , sizeof ( short ) , pAIGraph ) ;
FileSystem ( ) - > Write ( & clusterLink - > nextIndex_MAYBE , sizeof ( short ) , pAIGraph ) ;
FileSystem ( ) - > Write ( & clusterLink - > unk2 , sizeof ( int ) , pAIGraph ) ;
FileSystem ( ) - > Write ( & clusterLink - > flags , sizeof ( char ) , pAIGraph ) ;
FileSystem ( ) - > Write ( & clusterLink - > unk4 , sizeof ( char ) , pAIGraph ) ;
FileSystem ( ) - > Write ( & clusterLink - > unk5 , sizeof ( char ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
}
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-24 23:44:57 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing cluster links. %lf seconds (%d cluster links) \n " , timer . GetDuration ( ) . GetSeconds ( ) , numClusterLinks ) ;
2022-03-22 01:59:02 +01:00
// This is always set to '-1'. Likely a field for maintaining compatibility.
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Write ( & pNetwork - > unk5 , sizeof ( pNetwork - > unk5 ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
2022-03-22 17:18:29 +01:00
// AIN v57 and above only (not present in r1, static array in r2, pointer to dynamic array in r5).
2022-03-22 01:59:02 +01:00
timer . Start ( ) ;
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing script nodes... \n " ) ;
2022-03-22 01:59:02 +01:00
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Write ( & pNetwork - > m_iNumScriptNodes , sizeof ( pNetwork - > m_iNumScriptNodes ) , pAIGraph ) ;
2022-03-21 13:48:34 +01:00
for ( int i = 0 ; i < pNetwork - > m_iNumScriptNodes ; i + + )
{
2022-03-22 17:18:29 +01:00
// Disk and memory structs for script nodes are identical.
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing script node '#%d' at '0x%zX' \n " , i , FileSystem ( ) - > Tell ( pAIGraph ) ) ;
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Write ( & pNetwork - > m_ScriptNode [ i ] , sizeof ( CAI_ScriptNode ) , pAIGraph ) ;
2022-03-21 13:48:34 +01:00
}
2022-03-21 00:28:14 +01:00
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-21 19:12:29 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing script nodes. %lf seconds (%d nodes) \n " , timer . GetDuration ( ) . GetSeconds ( ) , pNetwork - > m_iNumScriptNodes ) ;
2022-03-22 01:59:02 +01:00
timer . Start ( ) ;
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing hint data... \n " ) ;
2022-03-22 01:59:02 +01:00
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Write ( & pNetwork - > m_iNumHints , sizeof ( pNetwork - > m_iNumHints ) , pAIGraph ) ;
2022-03-21 00:28:14 +01:00
for ( int i = 0 ; i < pNetwork - > m_iNumHints ; i + + )
2022-03-20 17:03:46 +01:00
{
2023-08-24 10:35:54 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing hint data '#%d' at '0x%zX' \n " , i , FileSystem ( ) - > Tell ( pAIGraph ) ) ;
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Write ( & pNetwork - > m_Hints [ i ] , sizeof ( pNetwork - > m_Hints [ i ] ) , pAIGraph ) ;
2022-03-20 17:03:46 +01:00
}
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-21 19:12:29 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing hint data. %lf seconds (%d hints) \n " , timer . GetDuration ( ) . GetSeconds ( ) , pNetwork - > m_iNumHints ) ;
2022-03-22 01:59:02 +01:00
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Close ( pAIGraph ) ;
2022-03-22 01:59:02 +01:00
masterTimer . End ( ) ;
2023-08-21 19:12:29 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing AI node graph. %lf seconds \n " , masterTimer . GetDuration ( ) . GetSeconds ( ) ) ;
Msg ( eDLL_T : : SERVER , " ++++--------------------------------------------------------------------------------------------------------------------------++++ \n " ) ;
Msg ( eDLL_T : : SERVER , " ++++--------------------------------------------------------------------------------------------------------------------------++++ \n " ) ;
2022-02-27 03:15:00 +01:00
}
2022-05-06 16:20:51 +02:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CAI_NetworkManager : : LoadNetworkGraph
Load network from the disk
and validate status
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void CAI_NetworkManager : : LoadNetworkGraph ( CAI_NetworkManager * pAINetworkManager , void * pBuffer , const char * szAIGraphFile )
2022-02-27 03:15:00 +01:00
{
2022-11-14 01:01:28 +01:00
bool bNavMeshAvailable = true ;
char szMeshPath [ MAX_PATH ] ;
char szGraphPath [ MAX_PATH ] ;
2022-05-06 16:20:51 +02:00
2022-11-14 01:01:28 +01:00
V_snprintf ( szMeshPath , sizeof ( szMeshPath ) , " %s%s_%s%s " , NAVMESH_PATH , g_ServerGlobalVariables - > m_pszMapName , S_HULL_TYPE [ E_HULL_TYPE : : LARGE ] , NAVMESH_EXT ) ;
V_snprintf ( szGraphPath , sizeof ( szGraphPath ) , " %s%s%s " , AINETWORK_PATH , g_ServerGlobalVariables - > m_pszMapName , AINETWORK_EXT ) ;
2022-05-06 16:20:51 +02:00
int nAiNetVersion = NULL ;
int nAiMapVersion = NULL ;
uint32_t nAiGraphHash = NULL ;
uint32_t nNavMeshHash = NULL ;
2022-11-14 01:01:28 +01:00
FileHandle_t pNavMesh = FileSystem ( ) - > Open ( szMeshPath , " rb " , " GAME " ) ;
2022-08-23 21:32:12 +02:00
if ( ! pNavMesh )
{
2022-11-03 17:12:22 +01:00
Warning ( eDLL_T : : SERVER , " %s - No %s NavMesh found. Unable to calculate CRC for AI Network \n " , __FUNCTION__ , S_HULL_TYPE [ E_HULL_TYPE : : LARGE ] ) ;
2022-08-23 21:32:12 +02:00
bNavMeshAvailable = false ;
}
else
{
2023-08-09 14:43:54 +02:00
const ssize_t nLen = FileSystem ( ) - > Size ( pNavMesh ) ;
2023-06-26 22:34:24 +02:00
std : : unique_ptr < uint8_t [ ] > pBuf ( new uint8_t [ nLen ] ) ;
2022-08-23 21:32:12 +02:00
2023-06-26 22:34:24 +02:00
FileSystem ( ) - > Read ( pBuf . get ( ) , nLen , pNavMesh ) ;
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Close ( pNavMesh ) ;
2023-06-26 22:34:24 +02:00
nNavMeshHash = crc32 : : update ( NULL , pBuf . get ( ) , nLen ) ;
2022-08-23 21:32:12 +02:00
}
2022-11-14 01:01:28 +01:00
FileHandle_t pAIGraph = FileSystem ( ) - > Open ( szGraphPath , " rb " , " GAME " ) ;
2022-08-23 21:32:12 +02:00
if ( ! pAIGraph )
{
2022-11-14 01:01:28 +01:00
Error ( eDLL_T : : SERVER , NO_ERROR , " %s - Unable to open '%s' (insufficient rights?) \n " , __FUNCTION__ , szGraphPath ) ;
2022-08-23 21:32:12 +02:00
LoadNetworkGraphEx ( pAINetworkManager , pBuffer , szAIGraphFile ) ;
2022-08-11 12:09:38 +02:00
2022-08-23 21:32:12 +02:00
return ;
}
2022-08-31 03:00:50 +02:00
if ( FileSystem ( ) - > Size ( pAIGraph ) > = AINET_MIN_FILE_SIZE )
2022-05-06 16:20:51 +02:00
{
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Read ( & nAiNetVersion , sizeof ( int ) , pAIGraph ) ;
FileSystem ( ) - > Read ( & nAiMapVersion , sizeof ( int ) , pAIGraph ) ;
FileSystem ( ) - > Read ( & nAiGraphHash , sizeof ( int ) , pAIGraph ) ;
2022-05-06 16:20:51 +02:00
if ( nAiNetVersion > AINET_VERSION_NUMBER )
{
2022-11-14 01:01:28 +01:00
Warning ( eDLL_T : : SERVER , " AI node graph '%s' is unsupported (net version: '%d' expected: '%d') \n " ,
szGraphPath , nAiNetVersion , AINET_VERSION_NUMBER ) ;
2022-05-06 16:20:51 +02:00
}
else if ( nAiMapVersion ! = g_ServerGlobalVariables - > m_nMapVersion )
{
2022-11-14 01:01:28 +01:00
Warning ( eDLL_T : : SERVER , " AI node graph '%s' is out of date (map version: '%d' expected: '%d') \n " ,
szGraphPath , nAiMapVersion , g_ServerGlobalVariables - > m_nMapVersion ) ;
2022-05-06 16:20:51 +02:00
}
2022-11-14 01:01:28 +01:00
else if ( bNavMeshAvailable & & nAiGraphHash ! = nNavMeshHash )
2022-05-06 16:20:51 +02:00
{
2023-05-01 22:51:31 +02:00
Warning ( eDLL_T : : SERVER , " AI node graph '%s' is out of date (checksum: '%x' expected: '%x') \n " ,
2022-11-14 01:01:28 +01:00
szGraphPath , nAiGraphHash , nNavMeshHash ) ;
2022-05-06 16:20:51 +02:00
}
}
2022-08-23 21:32:12 +02:00
else
{
2022-11-14 01:01:28 +01:00
Error ( eDLL_T : : SERVER , NO_ERROR , " %s - AI node graph '%s' is corrupt \n " , __FUNCTION__ , szGraphPath ) ;
2022-08-23 21:32:12 +02:00
}
FileSystem ( ) - > Close ( pAIGraph ) ;
LoadNetworkGraphEx ( pAINetworkManager , pBuffer , szAIGraphFile ) ;
}
2022-05-06 16:20:51 +02:00
2022-08-23 21:32:12 +02:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CAI_NetworkManager : : LoadNetworkGraphEx
Load network
( internal )
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void CAI_NetworkManager : : LoadNetworkGraphEx ( CAI_NetworkManager * pAINetworkManager , void * pBuffer , const char * szAIGraphFile )
{
2022-03-07 11:36:45 +01:00
# if defined (GAMEDLL_S0) || defined (GAMEDLL_S1)
2022-05-06 16:20:51 +02:00
CAI_NetworkManager__LoadNetworkGraph ( pAINetworkManager , pBuffer , szAIGraphFile , NULL ) ;
2022-03-07 11:36:45 +01:00
# elif defined (GAMEDLL_S2) || defined (GAMEDLL_S3)
2022-05-06 16:20:51 +02:00
CAI_NetworkManager__LoadNetworkGraph ( pAINetworkManager , pBuffer , szAIGraphFile ) ;
2022-03-07 11:36:45 +01:00
# endif
2022-02-27 03:15:00 +01:00
2022-04-03 03:10:48 +02:00
if ( ai_ainDumpOnLoad - > GetBool ( ) )
2022-02-27 03:15:00 +01:00
{
2023-08-21 19:12:29 +02:00
Msg ( eDLL_T : : SERVER , " Reparsing AI Network '%s' \n " , szAIGraphFile ) ;
2022-05-06 16:20:51 +02:00
CAI_NetworkBuilder : : SaveNetworkGraph ( * ( CAI_Network * * ) ( reinterpret_cast < char * > ( pAINetworkManager ) + AINETWORK_OFFSET ) ) ;
2022-02-27 03:15:00 +01:00
}
}
2022-05-06 16:20:51 +02:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CAI_NetworkBuilder : : Build
builds network in - memory
during level load
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void CAI_NetworkBuilder : : Build ( CAI_NetworkBuilder * pBuilder , CAI_Network * pAINetwork , void * a3 , int a4 )
2022-02-27 03:15:00 +01:00
{
2022-05-06 16:20:51 +02:00
CAI_NetworkBuilder__Build ( pBuilder , pAINetwork , a3 , a4 ) ;
CAI_NetworkBuilder : : SaveNetworkGraph ( pAINetwork ) ;
2022-02-27 03:15:00 +01:00
}
2023-01-25 02:26:52 +01:00
void VAI_NetworkManager : : Attach ( ) const
2022-02-27 03:15:00 +01:00
{
2022-05-06 16:20:51 +02:00
DetourAttach ( ( LPVOID * ) & CAI_NetworkManager__LoadNetworkGraph , & CAI_NetworkManager : : LoadNetworkGraph ) ;
DetourAttach ( ( LPVOID * ) & CAI_NetworkBuilder__Build , & CAI_NetworkBuilder : : Build ) ;
2022-02-27 03:15:00 +01:00
}
2023-01-25 02:26:52 +01:00
void VAI_NetworkManager : : Detach ( ) const
2022-02-27 03:15:00 +01:00
{
2022-05-06 16:20:51 +02:00
DetourDetach ( ( LPVOID * ) & CAI_NetworkManager__LoadNetworkGraph , & CAI_NetworkManager : : LoadNetworkGraph ) ;
DetourDetach ( ( LPVOID * ) & CAI_NetworkBuilder__Build , & CAI_NetworkBuilder : : Build ) ;
2022-02-27 03:15:00 +01:00
}