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 ;
2023-08-29 23:48:41 +02:00
constexpr int AINET_MINIMUM_SIZE = 82 ; // The file is at least this large when all required fields are written
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
{
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 " ) ;
2022-03-20 17:03:46 +01:00
2023-08-29 23:48:41 +02:00
// Must be computed at this point.
Assert ( ( * g_ppAINetworkManager ) - > IsRuntimeCRCCalculated ( ) ) ;
2022-03-22 01:59:02 +01:00
2022-03-22 17:18:29 +01:00
// Large NavMesh CRC.
2023-08-28 20:01:45 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- AINet version: '%d' \n " , AINET_VERSION_NUMBER ) ;
DevMsg ( eDLL_T : : SERVER , " |-- Map version: '%d' \n " , g_ServerGlobalVariables - > m_nMapVersion ) ;
2023-08-29 23:48:41 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Runtime CRC: '0x%lX' \n " , ( * g_ppAINetworkManager ) - > GetRuntimeCRC ( ) ) ;
2022-03-20 17:03:46 +01:00
2023-08-28 20:01:45 +02:00
CUtlBuffer buf ;
// ---------------------------
// Save the version numbers
// ---------------------------
buf . PutInt ( AINET_VERSION_NUMBER ) ;
buf . PutInt ( g_ServerGlobalVariables - > m_nMapVersion ) ;
2023-08-29 23:48:41 +02:00
buf . PutInt ( ( * g_ppAINetworkManager ) - > GetRuntimeCRC ( ) ) ;
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-28 02:44:39 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing path nodes... \n " ) ;
2022-08-23 21:32:12 +02:00
2023-08-28 20:01:45 +02:00
// -------------------------------
// Dump all the nodes to the file
// -------------------------------
buf . PutInt ( pNetwork - > NumPathNodes ( ) ) ;
int totalNumLinks = 0 ;
2023-08-24 10:35:54 +02:00
2023-08-28 20:01:45 +02:00
for ( int node = 0 ; node < pNetwork - > NumPathNodes ( ) ; node + + )
{
const CAI_Node * aiNode = pNetwork - > GetPathNode ( node ) ;
2022-03-20 17:03:46 +01:00
2023-08-28 23:17:03 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing node '#%d' at '0x%zX' \n " , aiNode - > m_iID , buf . TellPut ( ) ) ;
2023-08-27 00:56:38 +02:00
2023-08-28 23:17:03 +02:00
buf . Put ( & aiNode - > m_vOrigin , sizeof ( Vector3D ) ) ;
2023-08-28 20:01:45 +02:00
buf . PutFloat ( aiNode - > GetYaw ( ) ) ;
2023-08-28 23:17:03 +02:00
buf . Put ( & aiNode - > m_flVOffset , sizeof ( aiNode - > m_flVOffset ) ) ;
2023-08-28 20:01:45 +02:00
buf . PutChar ( ( char ) aiNode - > GetType ( ) ) ;
buf . PutInt ( aiNode - > GetInfo ( ) ) ;
2022-03-20 17:03:46 +01:00
2023-08-28 20:01:45 +02:00
for ( int j = 0 ; j < MAX_HULLS ; j + + )
{
buf . PutShort ( ( short ) aiNode - > unk2 [ j ] ) ;
2022-03-24 02:08:27 +01:00
}
2023-08-24 10:35:54 +02:00
2023-08-28 23:17:03 +02:00
buf . Put ( & aiNode - > unk3 , sizeof ( aiNode - > unk3 ) ) ;
2023-08-28 20:01:45 +02:00
buf . PutShort ( aiNode - > unk6 ) ;
buf . PutShort ( aiNode - > unk9 ) ; // Always -1;
2023-08-28 23:17:03 +02:00
buf . Put ( & aiNode - > unk11 , sizeof ( aiNode - > unk11 ) ) ;
2023-08-28 20:01:45 +02:00
totalNumLinks + = aiNode - > NumLinks ( ) ;
2022-03-20 17:03:46 +01:00
}
2023-08-24 10:35:54 +02:00
2023-08-28 20:01:45 +02:00
pNetwork - > m_iNumLinks = totalNumLinks ;
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-28 02:44:39 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing path nodes. %lf seconds (%d nodes) \n " , timer . GetDuration ( ) . GetSeconds ( ) , pNetwork - > m_iNumNodes ) ;
2022-03-22 01:59:02 +01:00
timer . Start ( ) ;
2023-08-28 02:44:39 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing node links... \n " ) ;
2023-08-28 23:17:03 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Cached node link count: '%d' \n " , totalNumLinks ) ;
2022-03-20 17:03:46 +01:00
2023-08-28 20:01:45 +02:00
// -------------------------------
// Dump all the links to the file
// -------------------------------
2023-08-28 23:17:03 +02:00
int packedLinks = totalNumLinks / 2 ;
2023-08-28 20:01:45 +02:00
buf . PutInt ( packedLinks ) ;
2022-03-24 02:08:27 +01:00
2023-08-28 20:01:45 +02:00
for ( int node = 0 ; node < pNetwork - > NumPathNodes ( ) ; node + + )
2022-03-20 17:03:46 +01:00
{
2023-08-28 20:01:45 +02:00
const CAI_Node * aiNode = pNetwork - > GetPathNode ( node ) ;
for ( int link = 0 ; link < aiNode - > NumLinks ( ) ; link + + )
2022-03-20 17:03:46 +01:00
{
2023-08-28 20:01:45 +02:00
const CAI_NodeLink * nodeLink = aiNode - > GetLinkByIndex ( link ) ;
2023-08-24 10:35:54 +02:00
2023-08-28 20:01:45 +02:00
// Skip links that don't originate from current node.
if ( nodeLink - > m_iSrcID = = aiNode - > m_iID )
2022-03-22 01:59:02 +01:00
{
2023-08-28 23:17:03 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing link (%hd <--> %hd) at '0x%zX' \n " , nodeLink - > m_iSrcID , nodeLink - > m_iDestID , buf . TellPut ( ) ) ;
2023-08-24 10:35:54 +02:00
2023-08-28 20:01:45 +02:00
buf . PutShort ( nodeLink - > m_iSrcID ) ;
buf . PutShort ( nodeLink - > m_iDestID ) ;
2022-03-24 02:08:27 +01:00
2023-08-28 20:01:45 +02:00
buf . PutChar ( nodeLink - > unk1 ) ;
buf . Put ( nodeLink - > m_iAcceptedMoveTypes , sizeof ( nodeLink - > m_iAcceptedMoveTypes ) ) ;
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-28 02:44:39 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing node links. %lf seconds (%d links) \n " , timer . GetDuration ( ) . GetSeconds ( ) , pNetwork - > m_iNumLinks ) ;
2022-03-22 01:59:02 +01:00
timer . Start ( ) ;
2023-08-29 23:48:41 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing wc lookup table... \n " ) ;
2023-08-28 20:01:45 +02:00
// -------------------------------
2023-08-29 23:48:41 +02:00
// Dump the WC lookup table
2023-08-28 20:01:45 +02:00
// -------------------------------
CUtlMap < int , int > wcIDs ;
SetDefLessFunc ( wcIDs ) ;
bool bCheckForProblems = false ;
const CAI_NetworkEditTools * const pEditOps = ( * g_ppAINetworkManager ) - > GetEditOps ( ) ;
2022-03-22 17:18:29 +01:00
2023-08-28 20:01:45 +02:00
for ( int node = 0 ; node < pNetwork - > m_iNumNodes ; node + + )
2022-03-22 17:18:29 +01:00
{
2023-08-28 20:01:45 +02:00
const int nIndex = pEditOps - > m_pNodeIndexTable [ node ] ;
const int iPreviousNodeBinding = wcIDs . Find ( nIndex ) ;
2022-08-23 21:32:12 +02:00
2023-08-28 20:01:45 +02:00
if ( iPreviousNodeBinding ! = wcIDs . InvalidIndex ( ) )
{
if ( ! bCheckForProblems )
{
DevWarning ( eDLL_T : : SERVER , " ******* MAP CONTAINS DUPLICATE HAMMER NODE IDS! CHECK FOR PROBLEMS IN HAMMER TO CORRECT ******* \n " ) ;
bCheckForProblems = true ;
}
DevWarning ( eDLL_T : : SERVER , " AI node %d is associated with Hammer node %d, but %d is already bound to node %d \n " ,
node , nIndex , nIndex , wcIDs [ ( unsigned short ) nIndex ] ) ;
}
else
{
wcIDs . Insert ( nIndex , node ) ;
}
DevMsg ( eDLL_T : : SERVER , " |-- Writing Hammer node (%d <--> %d) at '0x%zX' \n " , nIndex , wcIDs . Element ( ( unsigned short ) nIndex ) , buf . TellPut ( ) ) ;
buf . PutInt ( nIndex ) ;
2022-03-22 17:18:29 +01:00
}
2023-08-28 20:01:45 +02:00
timer . End ( ) ;
2023-08-29 23:48:41 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing wc lookup table. %lf seconds (%d indices) \n " , timer . GetDuration ( ) . GetSeconds ( ) , wcIDs . Count ( ) ) ;
2023-08-28 20:01:45 +02:00
timer . Start ( ) ;
DevMsg ( eDLL_T : : SERVER , " +- Writing traverse ex nodes... \n " ) ;
2023-08-28 23:17:03 +02:00
// -------------------------------
2023-08-29 23:48:41 +02:00
// Dump the traverse ex nodes
2023-08-28 23:17:03 +02:00
// -------------------------------
2023-08-28 20:01:45 +02:00
const int traverseExNodeCount = g_pAITraverseNodes - > Count ( ) ;
buf . PutShort ( ( short ) traverseExNodeCount ) ;
2023-08-24 23:44:57 +02:00
2023-08-28 20:01:45 +02:00
FOR_EACH_VEC ( * g_pAITraverseNodes , i )
{
DevMsg ( eDLL_T : : SERVER , " |-- Writing traverse ex node '%d' at '0x%zX' \n " , i , buf . TellPut ( ) ) ;
const CAI_TraverseNode & traverseExNode = ( * g_pAITraverseNodes ) [ i ] ;
buf . Put ( & traverseExNode . m_Quat , sizeof ( Quaternion ) ) ;
buf . PutInt ( traverseExNode . m_Index_MAYBE ) ;
}
timer . End ( ) ;
Msg ( eDLL_T : : SERVER , " ...done writing traverse ex nodes. %lf seconds (%d nodes) \n " , timer . GetDuration ( ) . GetSeconds ( ) , traverseExNodeCount ) ;
2022-03-20 17:03:46 +01:00
2023-08-28 23:17:03 +02:00
2023-08-28 20:01:45 +02:00
timer . Start ( ) ;
2023-08-28 23:17:03 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing hull data blocks... \n " ) ;
// -------------------------------
2023-08-29 23:48:41 +02:00
// Dump the hull data blocks
2023-08-28 23:17:03 +02:00
// -------------------------------
// Pointer to numZones counter, incremented up and until
// the last counter field for the hull data block.
int * countPtr = & pNetwork - > m_iNumZones ;
for ( int i = 0 ; i < MAX_HULLS ; i + + , countPtr + + )
2022-07-20 21:06:19 +02:00
{
2023-08-28 23:17:03 +02:00
const CAI_HullData & hullData = pNetwork - > m_HullData [ i ] ;
const int bufferSize = sizeof ( int ) * hullData . unk1 ;
buf . PutInt ( * countPtr ) ;
buf . PutShort ( hullData . m_Count ) ;
buf . PutShort ( hullData . unk1 ) ;
buf . Put ( hullData . pBuffer , bufferSize ) ;
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-28 23:17:03 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing hull data blocks. %lf seconds (%d blocks) \n " , timer . GetDuration ( ) . GetSeconds ( ) , MAX_HULLS ) ;
2022-03-22 01:59:02 +01:00
timer . Start ( ) ;
2023-08-28 02:44:39 +02:00
DevMsg ( eDLL_T : : SERVER , " +- Writing path clusters... \n " ) ;
2022-03-22 01:59:02 +01:00
2023-08-28 23:17:03 +02:00
// -------------------------------
2023-08-29 23:48:41 +02:00
// Dump the path clusters
2023-08-28 23:17:03 +02:00
// -------------------------------
2023-08-24 23:44:57 +02:00
const int numClusters = g_pAIPathClusters - > Count ( ) ;
2023-08-28 20:01:45 +02:00
buf . PutInt ( numClusters ) ;
2023-08-24 23:44:57 +02:00
FOR_EACH_VEC ( * g_pAIPathClusters , i )
2022-03-20 17:03:46 +01:00
{
2023-08-28 20:01:45 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing cluster '#%d' at '0x%zX' \n " , i , buf . TellPut ( ) ) ;
2022-03-20 17:03:46 +01:00
2023-08-24 23:44:57 +02:00
const CAI_Cluster * pathClusters = ( * g_pAIPathClusters ) [ i ] ;
2023-08-28 20:01:45 +02:00
buf . PutInt ( pathClusters - > m_nIndex ) ;
buf . PutChar ( pathClusters - > unk1 ) ;
2023-08-24 23:44:57 +02:00
2023-08-28 20:01:45 +02:00
buf . PutFloat ( pathClusters - > GetOrigin ( ) . x ) ;
buf . PutFloat ( pathClusters - > GetOrigin ( ) . y ) ;
buf . PutFloat ( pathClusters - > GetOrigin ( ) . z ) ;
2022-03-20 17:03:46 +01:00
2023-08-24 23:44:57 +02:00
const int unkVec0Size = pathClusters - > unkVec0 . Count ( ) ;
2023-08-28 20:01:45 +02:00
buf . PutInt ( unkVec0Size ) ;
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 ] ) ;
2023-08-28 20:01:45 +02:00
buf . PutShort ( unkShort ) ;
2022-03-20 17:03:46 +01:00
}
2023-08-24 23:44:57 +02:00
const int unkVec1Size = pathClusters - > unkVec1 . Count ( ) ;
2023-08-28 20:01:45 +02:00
buf . PutInt ( unkVec1Size ) ;
2023-08-24 23:44:57 +02:00
FOR_EACH_VEC ( pathClusters - > unkVec1 , j )
2022-03-20 17:03:46 +01:00
{
2023-08-27 11:38:02 +02:00
short unkShort = static_cast < short > ( pathClusters - > unkVec1 [ j ] ) ;
2023-08-28 20:01:45 +02:00
buf . PutShort ( unkShort ) ;
2022-03-20 17:03:46 +01:00
}
2023-08-28 20:01:45 +02:00
buf . PutChar ( pathClusters - > unk5 ) ;
2022-03-20 17:03:46 +01:00
}
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-28 02:44:39 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing path 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-28 23:17:03 +02:00
// -------------------------------
2023-08-29 23:48:41 +02:00
// Dump the cluster links
2023-08-28 23:17:03 +02:00
// -------------------------------
2023-08-24 23:44:57 +02:00
const int numClusterLinks = g_pAIClusterLinks - > Count ( ) ;
2023-08-28 20:01:45 +02:00
buf . PutInt ( numClusterLinks ) ;
2023-08-24 23:44:57 +02:00
FOR_EACH_VEC ( * g_pAIClusterLinks , i )
2022-03-20 17:03:46 +01:00
{
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
2023-08-28 23:17:03 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing link (%hd <--> %hd) at '0x%zX' \n " , clusterLink - > m_iSrcID , clusterLink - > m_iDestID , buf . TellPut ( ) ) ;
2023-08-28 20:01:45 +02:00
buf . PutShort ( clusterLink - > m_iSrcID ) ;
buf . PutShort ( clusterLink - > m_iDestID ) ;
2023-08-25 08:47:12 +02:00
2023-08-28 20:01:45 +02:00
buf . PutInt ( clusterLink - > unk2 ) ;
buf . PutChar ( clusterLink - > flags ) ;
2023-08-25 08:47:12 +02:00
2023-08-28 20:01:45 +02:00
buf . PutChar ( clusterLink - > unkFlags4 ) ;
buf . PutChar ( clusterLink - > unkFlags5 ) ;
2022-03-20 17:03:46 +01:00
}
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-28 02:44:39 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing cluster links. %lf seconds (%d 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.
2023-08-28 20:01:45 +02:00
buf . PutInt ( pNetwork - > unk5 ) ;
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
2023-08-28 23:17:03 +02:00
// -------------------------------
2023-08-29 23:48:41 +02:00
// Dump all the script nodes
2023-08-28 23:17:03 +02:00
// -------------------------------
const int numScriptNodes = pNetwork - > m_iNumScriptNodes ;
buf . PutInt ( numScriptNodes ) ;
for ( int node = 0 ; node < numScriptNodes ; node + + )
2022-03-21 13:48:34 +01:00
{
2022-03-22 17:18:29 +01:00
// Disk and memory structs for script nodes are identical.
2023-08-28 23:17:03 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing script node '#%d' at '0x%zX' \n " , node , buf . TellPut ( ) ) ;
buf . Put ( & pNetwork - > m_ScriptNode [ node ] , sizeof ( CAI_ScriptNode ) ) ;
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-28 23:17:03 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing script nodes. %lf seconds (%d nodes) \n " , timer . GetDuration ( ) . GetSeconds ( ) , numScriptNodes ) ;
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
2023-08-28 23:17:03 +02:00
// -------------------------------
2023-08-29 23:48:41 +02:00
// Dump the hint data
2023-08-28 23:17:03 +02:00
// -------------------------------
const int numHinst = pNetwork - > m_iNumHints ;
buf . PutInt ( numHinst ) ;
for ( int hint = 0 ; hint < numHinst ; hint + + )
2022-03-20 17:03:46 +01:00
{
2023-08-28 23:17:03 +02:00
DevMsg ( eDLL_T : : SERVER , " |-- Writing hint data '#%d' at '0x%zX' \n " , hint , buf . TellPut ( ) ) ;
buf . PutShort ( pNetwork - > m_Hints [ hint ] ) ;
2022-03-20 17:03:46 +01:00
}
2022-03-22 01:59:02 +01:00
timer . End ( ) ;
2023-08-28 23:17:03 +02:00
Msg ( eDLL_T : : SERVER , " ...done writing hint data. %lf seconds (%d hints) \n " , timer . GetDuration ( ) . GetSeconds ( ) , numHinst ) ;
2022-03-22 01:59:02 +01:00
2023-08-29 23:48:41 +02:00
timer . Start ( ) ;
DevMsg ( eDLL_T : : SERVER , " +- Calculating navmesh crc... \n " ) ;
// -------------------------------
// Dump NavMesh CRC
// -------------------------------
FileHandle_t pNavMesh = FileSystem ( ) - > Open ( szMeshPath , " rb " , " GAME " ) ;
uint32_t nNavMeshCRC = NULL ;
if ( ! pNavMesh )
{
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 ] ) ;
}
else
{
const ssize_t nLen = FileSystem ( ) - > Size ( pNavMesh ) ;
std : : unique_ptr < uint8_t [ ] > pBuf ( new uint8_t [ nLen ] ) ;
FileSystem ( ) - > Read ( pBuf . get ( ) , nLen , pNavMesh ) ;
FileSystem ( ) - > Close ( pNavMesh ) ;
nNavMeshCRC = crc32 : : update ( NULL , pBuf . get ( ) , nLen ) ;
}
// Note: the NavMesh checksum is written at the END of the file
// to maintain compatibility with r1 and r2 AIN's.
DevMsg ( eDLL_T : : SERVER , " |-- Writing navmesh crc '%x' at '0x%zX' \n " , nNavMeshCRC , buf . TellPut ( ) ) ;
buf . PutInt ( nNavMeshCRC ) ;
timer . End ( ) ;
Msg ( eDLL_T : : SERVER , " ...done calculating navmesh crc. %lf seconds (%x) \n " , timer . GetDuration ( ) . GetSeconds ( ) , nNavMeshCRC ) ;
// Write the entire buffer to the disk.
2023-08-28 20:01:45 +02:00
FileSystem ( ) - > Write ( buf . Base ( ) , buf . TellPut ( ) , pAIGraph ) ;
2022-08-23 21:32:12 +02:00
FileSystem ( ) - > Close ( pAIGraph ) ;
2022-03-22 01:59:02 +01:00
masterTimer . End ( ) ;
2023-08-29 23:48:41 +02:00
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
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2023-08-28 20:01:45 +02:00
void CAI_NetworkManager : : LoadNetworkGraph ( CAI_NetworkManager * pManager , CUtlBuffer * 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 ;
2023-08-29 23:48:41 +02:00
uint32_t nAiGraphCRC = NULL ; // AIN CRC from AIN file.
uint32_t nAiNavMeshCRC = NULL ; // NavMesh CRC from AIN file.
uint32_t nNavMeshCRC = NULL ; // NavMesh CRC from local NM file.
uint32_t nAiRuntimeCRC = pManager - > GetRuntimeCRC ( ) ;
2022-05-06 16:20:51 +02:00
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-08-29 23:48:41 +02:00
nNavMeshCRC = crc32 : : update ( NULL , pBuf . get ( ) , nLen ) ;
2022-08-23 21:32:12 +02:00
}
2023-08-29 00:33:12 +02:00
const ssize_t nFileSize = pBuffer - > TellPut ( ) ;
const ssize_t nOldOffset = pBuffer - > TellGet ( ) ;
2022-08-11 12:09:38 +02:00
2023-08-29 00:33:12 +02:00
// Seek to the start of the buffer so we can validate the header.
pBuffer - > SeekGet ( CUtlBuffer : : SEEK_HEAD , 0 ) ;
2022-08-31 03:00:50 +02:00
2023-08-29 23:48:41 +02:00
// If we have a NavMesh, then the minimum size is
// 'AINET_MINIMUM_SIZE' + CRC32 as the AIN needs
// a NavMesh checksum field for validation.
const int nMinimumFileSize = bNavMeshAvailable
? AINET_MINIMUM_SIZE + sizeof ( nNavMeshCRC )
: AINET_MINIMUM_SIZE ;
if ( nFileSize > = nMinimumFileSize )
2022-05-06 16:20:51 +02:00
{
2023-08-29 00:33:12 +02:00
nAiNetVersion = pBuffer - > GetInt ( ) ;
nAiMapVersion = pBuffer - > GetInt ( ) ;
2023-08-29 23:48:41 +02:00
nAiGraphCRC = pBuffer - > GetInt ( ) ;
2022-05-06 16:20:51 +02:00
2023-08-29 23:48:41 +02:00
// Too old; build with a different game???
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
}
2023-08-29 23:48:41 +02:00
// AIN file was build with a different version of the map, therefore,
// the path node positions might be invalid.
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
}
2023-08-29 23:48:41 +02:00
// Data checksum is now what the runtime expects.
else if ( nAiGraphCRC ! = nAiRuntimeCRC )
{
Warning ( eDLL_T : : SERVER , " AI node graph '%s' is out of date (ain checksum: '%x' expected: '%x') \n " ,
szGraphPath , nAiGraphCRC , nAiRuntimeCRC ) ;
}
else if ( bNavMeshAvailable )
2022-05-06 16:20:51 +02:00
{
2023-08-29 23:48:41 +02:00
// Seek to the end of the file, minus the size of the CRC field.
// The NavMesh CRC is written at the end of the file to maintain
// compatibility with r1 and r2 AIN files.
pBuffer - > SeekGet ( CUtlBuffer : : SEEK_HEAD , nFileSize - sizeof ( nAiNavMeshCRC ) ) ;
nAiNavMeshCRC = pBuffer - > GetInt ( ) ;
// The AIN file was build with a different NavMesh, therefore,
// the script node positions might be incorrect.
if ( nAiNavMeshCRC ! = nNavMeshCRC )
{
Warning ( eDLL_T : : SERVER , " AI node graph '%s' is out of date (nav checksum: '%x' expected: '%x') \n " ,
szGraphPath , nAiGraphCRC , nNavMeshCRC ) ;
}
2022-05-06 16:20:51 +02:00
}
}
2022-08-23 21:32:12 +02:00
else
{
2023-08-29 23:48:41 +02:00
Error ( eDLL_T : : SERVER , NO_ERROR , " %s - AI node graph '%s' appears truncated \n " , __FUNCTION__ , szGraphPath ) ;
2022-08-23 21:32:12 +02:00
}
2023-08-29 00:33:12 +02:00
// Recover old buffer position before we call LoadNetworkGraph.
pBuffer - > SeekGet ( CUtlBuffer : : SEEK_HEAD , nOldOffset ) ;
2023-08-27 11:36:58 +02:00
LoadNetworkGraphEx ( pManager , pBuffer , szAIGraphFile ) ;
2022-08-23 21:32:12 +02:00
}
2022-05-06 16:20:51 +02:00
2022-08-23 21:32:12 +02:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CAI_NetworkManager : : LoadNetworkGraphEx
Load network
( internal )
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2023-08-28 20:01:45 +02:00
void CAI_NetworkManager : : LoadNetworkGraphEx ( CAI_NetworkManager * pManager , CUtlBuffer * pBuffer , const char * szAIGraphFile )
2022-08-23 21:32:12 +02:00
{
2023-08-27 11:36:58 +02:00
CAI_NetworkManager__LoadNetworkGraph ( pManager , pBuffer , szAIGraphFile ) ;
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-27 11:36:58 +02:00
Msg ( eDLL_T : : SERVER , " Dumping AI Network '%s' \n " , szAIGraphFile ) ;
CAI_NetworkBuilder : : SaveNetworkGraph ( pManager - > m_pNetwork ) ;
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
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2023-08-27 11:36:58 +02:00
void CAI_NetworkBuilder : : Build ( CAI_NetworkBuilder * pBuilder , CAI_Network * pAINetwork )
2022-02-27 03:15:00 +01:00
{
2023-08-27 11:36:58 +02:00
CAI_NetworkBuilder__Build ( pBuilder , pAINetwork ) ;
2022-05-06 16:20:51 +02:00
CAI_NetworkBuilder : : SaveNetworkGraph ( pAINetwork ) ;
2022-02-27 03:15:00 +01:00
}
2023-11-26 13:21:20 +01:00
void VAI_NetworkManager : : Detour ( const bool bAttach ) const
2022-02-27 03:15:00 +01:00
{
2023-11-26 13:21:20 +01:00
DetourSetup ( & CAI_NetworkManager__LoadNetworkGraph , & CAI_NetworkManager : : LoadNetworkGraph , bAttach ) ;
DetourSetup ( & CAI_NetworkBuilder__Build , & CAI_NetworkBuilder : : Build , bAttach ) ;
2022-02-27 03:15:00 +01:00
}