Merge branch 'master' into resource

This commit is contained in:
mittorn
2019-01-30 13:38:36 +00:00
committed by GitHub
222 changed files with 13798 additions and 8154 deletions

View File

@@ -113,24 +113,6 @@ typedef struct
file_t *file;
} server_log_t;
// like as entity_state_t in Quake
typedef struct
{
char model[MAX_QPATH]; // name of static-entity model for right precache
vec3_t origin;
vec3_t angles;
short sequence;
short frame;
short colormap;
byte skin; // can't set contents! only real skin!
byte body;
float scale;
byte rendermode;
byte renderamt;
color24 rendercolor;
byte renderfx;
} sv_static_entity_t;
typedef struct server_s
{
sv_state_t state; // precache commands are only valid during load
@@ -159,8 +141,6 @@ typedef struct server_s
char event_precache[MAX_EVENTS][MAX_QPATH];
byte model_precache_flags[MAX_MODELS];
model_t *models[MAX_MODELS];
sv_static_entity_t static_entities[MAX_STATIC_ENTITIES];
int num_static_entities;
// run local lightstyles to let SV_LightPoint grab the actual information
@@ -386,6 +366,7 @@ typedef struct
int next_client_entities; // next client_entity to use
entity_state_t *packet_entities; // [num_client_entities]
entity_state_t *baselines; // [GI->max_edicts]
entity_state_t *static_entities; // [MAX_STATIC_ENTITIES];
double last_heartbeat;
challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
@@ -406,6 +387,7 @@ extern convar_t sv_unlagpush;
extern convar_t sv_unlagsamples;
extern convar_t rcon_password;
extern convar_t sv_instancedbaseline;
extern convar_t sv_background_freeze;
extern convar_t sv_minupdaterate;
extern convar_t sv_maxupdaterate;
extern convar_t sv_downloadurl;
@@ -575,6 +557,7 @@ void SV_RequestMissingResources( void );
// sv_frame.c
//
void SV_InactivateClients( void );
int SV_FindBestBaselineForStatic( int index, entity_state_t **baseline, entity_state_t *to );
void SV_WriteFrameToClient( sv_client_t *client, sizebuf_t *msg );
void SV_BuildClientFrame( sv_client_t *client );
void SV_SendMessagesToAll( void );
@@ -599,7 +582,8 @@ void SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word eventindex,
float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 );
void SV_PlaybackReliableEvent( sizebuf_t *msg, word eventindex, float delay, event_args_t *args );
int SV_BuildSoundMsg( sizebuf_t *msg, edict_t *ent, int chan, const char *sample, int vol, float attn, int flags, int pitch, const vec3_t pos );
int SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t absmax );
qboolean SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t absmax );
void SV_QueueChangeLevel( const char *level, const char *landname );
void SV_WriteEntityPatch( const char *filename );
float SV_AngleMod( float ideal, float current, float speed );
void SV_SpawnEntities( const char *mapname );
@@ -608,11 +592,16 @@ edict_t* SV_CreateNamedEntity( edict_t *ent, string_t className );
string_t SV_AllocString( const char *szValue );
string_t SV_MakeString( const char *szValue );
const char *SV_GetString( string_t iString );
void SV_SetStringArrayMode( qboolean dynamic );
void SV_EmptyStringPool( void );
#ifdef XASH_64BIT
void SV_PrintStr64Stats_f( void );
#endif
sv_client_t *SV_ClientFromEdict( const edict_t *pEdict, qboolean spawned_only );
int SV_MapIsValid( const char *filename, const char *spawn_entity, const char *landmark_name );
void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch );
void SV_CreateStaticEntity( struct sizebuf_s *msg, sv_static_entity_t *ent );
edict_t *SV_FindGlobalEntity( string_t classname, string_t globalname );
qboolean SV_CreateStaticEntity( struct sizebuf_s *msg, int index );
void SV_SendUserReg( sizebuf_t *msg, sv_user_message_t *user );
edict_t* pfnPEntityOfEntIndex( int iEntIndex );
int pfnIndexOfEdict( const edict_t *pEdict );
@@ -621,6 +610,7 @@ void SV_UpdateBaseVelocity( edict_t *ent );
byte *pfnSetFatPVS( const float *org );
byte *pfnSetFatPAS( const float *org );
int pfnPrecacheModel( const char *s );
int pfnModelIndex( const char *m );
void pfnRemoveEntity( edict_t* e );
void SV_RestartAmbientSounds( void );
void SV_RestartDecals( void );
@@ -628,7 +618,6 @@ void SV_RestartStaticEnts( void );
int pfnGetCurrentPlayer( void );
edict_t *SV_EdictNum( int n );
char *SV_Localinfo( void );
//
// sv_log.c
//

View File

@@ -118,7 +118,7 @@ void SV_RejectConnection( netadr_t from, char *fmt, ... )
Q_vsnprintf( text, sizeof( text ), fmt, argptr );
va_end( argptr );
MsgDev( D_REPORT, "%s connection refused. Reason: %s\n", NET_AdrToString( from ), text );
Con_Reportf( "%s connection refused. Reason: %s\n", NET_AdrToString( from ), text );
Netchan_OutOfBandPrint( NS_SERVER, from, "print\n^1Server was reject the connection:^7 %s", text );
Netchan_OutOfBandPrint( NS_SERVER, from, "disconnect\n" );
}
@@ -331,7 +331,7 @@ void SV_ConnectClient( netadr_t from )
}
else
{
MsgDev( D_INFO, "%s:reconnect\n", NET_AdrToString( from ));
Con_Reportf( S_NOTE "%s:reconnect\n", NET_AdrToString( from ));
}
// find a client slot
@@ -343,7 +343,7 @@ void SV_ConnectClient( netadr_t from )
newcl->edict = EDICT_NUM( (newcl - svs.clients) + 1 );
newcl->challenge = challenge; // save challenge for checksumming
if( newcl->frames ) Mem_Free( newcl->frames );
newcl->frames = (client_frame_t *)Z_Malloc( sizeof( client_frame_t ) * SV_UPDATE_BACKUP );
newcl->frames = (client_frame_t *)Z_Calloc( sizeof( client_frame_t ) * SV_UPDATE_BACKUP );
newcl->userid = g_userid++; // create unique userid
newcl->state = cs_connected;
@@ -855,7 +855,7 @@ void SV_RemoteCommand( netadr_t from, sizebuf_t *msg )
char remaining[1024];
int i;
MsgDev( D_INFO, "Rcon from %s:\n%s\n", NET_AdrToString( from ), MSG_GetData( msg ) + 4 );
Con_Printf( "Rcon from %s:\n%s\n", NET_AdrToString( from ), MSG_GetData( msg ) + 4 );
Log_Printf( "Rcon: \"%s\" from \"%s\"\n", MSG_GetData( msg ) + 4, NET_AdrToString( from ));
SV_BeginRedirect( from, RD_PACKET, outputbuf, sizeof( outputbuf ) - 16, SV_FlushRedirect );
@@ -869,7 +869,7 @@ void SV_RemoteCommand( netadr_t from, sizebuf_t *msg )
}
Cmd_ExecuteString( remaining );
}
else MsgDev( D_ERROR, "Bad rcon_password.\n" );
else Con_Printf( S_ERROR "Bad rcon_password.\n" );
SV_EndRedirect();
}
@@ -1229,19 +1229,20 @@ void SV_PutClientInServer( sv_client_t *cl )
SetBits( ent->v.flags, FL_GODMODE|FL_NOTARGET );
cl->pViewEntity = NULL; // reset pViewEntity
if( svgame.globals->cdAudioTrack )
{
MSG_BeginServerCmd( &msg, svc_stufftext );
MSG_WriteString( &msg, va( "cd loop %3d\n", svgame.globals->cdAudioTrack ));
svgame.globals->cdAudioTrack = 0;
}
}
if( svgame.globals->cdAudioTrack )
{
MSG_BeginServerCmd( &msg, svc_stufftext );
MSG_WriteString( &msg, va( "cd loop %3d\n", svgame.globals->cdAudioTrack ));
svgame.globals->cdAudioTrack = 0;
}
#ifdef HACKS_RELATED_HLMODS
// enable dev-mode to prevent crash cheat-protecting from Invasion mod
if( FBitSet( ent->v.flags, FL_GODMODE|FL_NOTARGET ) && !Q_stricmp( GI->gamefolder, "invasion" ))
SV_ExecuteClientCommand( cl, "test\n" );
#endif
// refresh the userinfo and movevars
// NOTE: because movevars can be changed during the connection process
SetBits( cl->flags, FCL_RESEND_USERINFO|FCL_RESEND_MOVEVARS );
@@ -1727,6 +1728,9 @@ static qboolean SV_Godmode_f( sv_client_t *cl )
return true;
pEntity->v.flags = pEntity->v.flags ^ FL_GODMODE;
if( pEntity->v.takedamage == DAMAGE_AIM )
pEntity->v.takedamage = DAMAGE_NO;
else pEntity->v.takedamage = DAMAGE_AIM;
if( !FBitSet( pEntity->v.flags, FL_GODMODE ))
SV_ClientPrintf( cl, "godmode OFF\n" );
@@ -1996,7 +2000,7 @@ void SV_ExecuteClientCommand( sv_client_t *cl, char *s )
{
if( !u->func( cl ))
Con_Printf( "'%s' is not valid from the console\n", u->name );
else MsgDev( D_NOTE, "ucmd->%s()\n", u->name );
else Con_Reportf( "ucmd->%s()\n", u->name );
break;
}
}
@@ -2066,7 +2070,7 @@ void SV_TSourceEngineQuery( netadr_t from )
MSG_WriteString( &buf, GI->game_url );
MSG_WriteString( &buf, GI->update_url );
MSG_WriteByte( &buf, 0 );
MSG_WriteLong( &buf, (long)GI->version );
MSG_WriteLong( &buf, (int)GI->version );
MSG_WriteLong( &buf, GI->size );
if( GI->gamemode == 2 )
@@ -2109,7 +2113,7 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
Cmd_TokenizeString( args );
pcmd = Cmd_Argv( 0 );
Con_DPrintf( "SV_ConnectionlessPacket: %s : %s\n", NET_AdrToString( from ), pcmd );
Con_Reportf( "SV_ConnectionlessPacket: %s : %s\n", NET_AdrToString( from ), pcmd );
if( !Q_strcmp( pcmd, "ping" )) SV_Ping( from );
else if( !Q_strcmp( pcmd, "ack" )) SV_Ack( from );
@@ -2127,7 +2131,7 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
// user out of band message (must be handled in CL_ConnectionlessPacket)
if( len > 0 ) Netchan_OutOfBand( NS_SERVER, from, len, buf );
}
else MsgDev( D_ERROR, "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
else Con_DPrintf( S_ERROR "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
}
/*
@@ -2171,7 +2175,7 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
if( totalcmds < 0 || totalcmds >= CMD_MASK )
{
MsgDev( D_ERROR, "SV_ParseClientMove: %s sending too many commands %i\n", cl->name, totalcmds );
Con_Reportf( S_ERROR "SV_ParseClientMove: %s sending too many commands %i\n", cl->name, totalcmds );
SV_DropClient( cl, false );
return;
}
@@ -2194,12 +2198,16 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
if( checksum2 != checksum1 )
{
MsgDev( D_ERROR, "SV_UserMove: failed command checksum for %s (%d != %d)\n", cl->name, checksum2, checksum1 );
Con_Reportf( S_ERROR "SV_UserMove: failed command checksum for %s (%d != %d)\n", cl->name, checksum2, checksum1 );
return;
}
cl->packet_loss = packet_loss;
// freeze player for some reasons if loadgame was executed
if( GameState->loadGame )
return;
// check for pause or frozen
if( sv.paused || !CL_IsInGame() || SV_PlayerIsFrozen( player ))
{
@@ -2284,7 +2292,7 @@ void SV_ParseResourceList( sv_client_t *cl, sizebuf_t *msg )
for( i = 0; i < total; i++ )
{
resource = Z_Malloc( sizeof( resource_t ) );
resource = Z_Calloc( sizeof( resource_t ) );
Q_strncpy( resource->szFileName, MSG_ReadString( msg ), sizeof( resource->szFileName ));
resource->type = MSG_ReadByte( msg );
resource->nIndex = MSG_ReadShort( msg );
@@ -2306,13 +2314,12 @@ void SV_ParseResourceList( sv_client_t *cl, sizebuf_t *msg )
SV_AddToResourceList( resource, &cl->resourcesneeded );
}
if( sv_allow_upload.value )
MsgDev( D_REPORT, "Verifying and uploading resources...\n" );
totalsize = COM_SizeofResourceList( &cl->resourcesneeded, &ri );
if( totalsize != 0 && sv_allow_upload.value )
{
Con_DPrintf( "Verifying and uploading resources...\n" );
if( totalsize != 0 )
{
Con_DPrintf( "Custom resources total %.2fK\n", totalsize / 1024.0 );
@@ -2346,7 +2353,7 @@ void SV_ParseResourceList( sv_client_t *cl, sizebuf_t *msg )
SV_ClearResourceList( &cl->resourcesonhand );
return;
}
MsgDev( D_REPORT, "resources to request: %s\n", Q_memprint( totalsize ));
Con_DPrintf( "resources to request: %s\n", Q_memprint( totalsize ));
}
cl->upstate = us_processing;
@@ -2366,7 +2373,7 @@ void SV_ParseCvarValue( sv_client_t *cl, sizebuf_t *msg )
if( svgame.dllFuncs2.pfnCvarValue != NULL )
svgame.dllFuncs2.pfnCvarValue( cl->edict, value );
MsgDev( D_REPORT, "Cvar query response: name:%s, value:%s\n", cl->name, value );
Con_Reportf( "Cvar query response: name:%s, value:%s\n", cl->name, value );
}
/*
@@ -2386,7 +2393,7 @@ void SV_ParseCvarValue2( sv_client_t *cl, sizebuf_t *msg )
if( svgame.dllFuncs2.pfnCvarValue2 != NULL )
svgame.dllFuncs2.pfnCvarValue2( cl->edict, requestID, name, value );
MsgDev( D_REPORT, "Cvar query response: name:%s, request ID %d, cvar:%s, value:%s\n", cl->name, requestID, name, value );
Con_Reportf( "Cvar query response: name:%s, request ID %d, cvar:%s, value:%s\n", cl->name, requestID, name, value );
}
/*
@@ -2400,7 +2407,6 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
{
qboolean move_issued = false;
client_frame_t *frame;
char *s;
int c;
ASSERT( cl->frames != NULL );
@@ -2426,7 +2432,7 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
{
if( MSG_CheckOverflow( msg ))
{
MsgDev( D_ERROR, "SV_ReadClientMessage: clc_bad\n" );
Con_DPrintf( S_ERROR "incoming overflow for %s\n", cl->name );
SV_DropClient( cl, false );
return;
}
@@ -2450,10 +2456,9 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
SV_ParseClientMove( cl, msg );
break;
case clc_stringcmd:
s = MSG_ReadString( msg );
// malicious users may try using too many string commands
SV_ExecuteClientCommand( cl, s );
if( cl->state == cs_zombie ) return; // disconnect command
SV_ExecuteClientCommand( cl, MSG_ReadString( msg ));
if( cl->state == cs_zombie )
return; // disconnect command
break;
case clc_resourcelist:
SV_ParseResourceList( cl, msg );
@@ -2468,7 +2473,7 @@ void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg )
SV_ParseCvarValue2( cl, msg );
break;
default:
MsgDev( D_ERROR, "clc_bad\n" );
Con_DPrintf( S_ERROR "%s: clc_bad\n", cl->name );
SV_DropClient( cl, false );
return;
}

View File

@@ -75,7 +75,7 @@ void SV_BroadcastPrintf( sv_client_t *ignore, char *fmt, ... )
if( Host_IsDedicated() )
{
// echo to console
Con_DPrintf( string );
Con_DPrintf( "%s", string );
}
}
@@ -248,7 +248,8 @@ void SV_MapBackground_f( void )
if( SV_Active() && !sv.background )
{
MsgDev( D_ERROR, "can't set background map while game is active\n" );
if( GameState->nextstate == STATE_RUNFRAME )
Con_Printf( S_ERROR "can't set background map while game is active\n" );
return;
}
@@ -267,6 +268,57 @@ void SV_MapBackground_f( void )
COM_LoadLevel( mapname, true );
}
/*
==================
SV_NextMap_f
Change map for next in alpha-bethical ordering
For development work
==================
*/
void SV_NextMap_f( void )
{
char nextmap[MAX_QPATH];
int i, next;
search_t *t;
t = FS_Search( "maps/*.bsp", true, true ); // only in gamedir
if( !t )
{
Con_Printf( "next map can't be found\n" );
return;
}
for( i = 0; i < t->numfilenames; i++ )
{
const char *ext = COM_FileExtension( t->filenames[i] );
if( Q_stricmp( ext, "bsp" ))
continue;
COM_FileBase( t->filenames[i], nextmap );
if( Q_stricmp( sv_hostmap->string, nextmap ))
continue;
next = ( i + 1 ) % t->numfilenames;
COM_FileBase( t->filenames[next], nextmap );
Cvar_DirectSet( sv_hostmap, nextmap );
// found current point, check for valid
if( SV_ValidateMap( nextmap, true ))
{
// found and valid
COM_LoadLevel( nextmap, false );
Mem_Free( t );
return;
}
// jump to next map
}
Con_Printf( "failed to load next map\n" );
Mem_Free( t );
}
/*
==============
SV_NewGame_f
@@ -315,7 +367,7 @@ SV_Load_f
*/
void SV_Load_f( void )
{
string path;
char path[MAX_QPATH];
if( Cmd_Argc() != 2 )
{
@@ -439,6 +491,42 @@ void SV_Reload_f( void )
COM_LoadLevel( sv_hostmap->string, false );
}
/*
==================
SV_ChangeLevel_f
classic change level
==================
*/
void SV_ChangeLevel_f( void )
{
if( Cmd_Argc() != 2 )
{
Con_Printf( S_USAGE "changelevel <mapname>\n" );
return;
}
SV_QueueChangeLevel( Cmd_Argv( 1 ), NULL );
}
/*
==================
SV_ChangeLevel2_f
smooth change level
==================
*/
void SV_ChangeLevel2_f( void )
{
if( Cmd_Argc() != 3 )
{
Con_Printf( S_USAGE "changelevel2 <mapname> <landmark>\n" );
return;
}
SV_QueueChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
}
/*
==================
SV_Kick_f
@@ -800,6 +888,9 @@ void SV_InitHostCommands( void )
Cmd_AddCommand( "map_background", SV_MapBackground_f, "set background map" );
Cmd_AddCommand( "load", SV_Load_f, "load a saved game file" );
Cmd_AddCommand( "loadquick", SV_QuickLoad_f, "load a quick-saved game file" );
Cmd_AddCommand( "reload", SV_Reload_f, "continue from latest save or restart level" );
Cmd_AddCommand( "killsave", SV_DeleteSave_f, "delete a saved game file and saveshot" );
Cmd_AddCommand( "nextmap", SV_NextMap_f, "load next level" );
}
}
@@ -818,18 +909,18 @@ void SV_InitOperatorCommands( void )
Cmd_AddCommand( "clientinfo", SV_ClientInfo_f, "print user infostring (player num required)" );
Cmd_AddCommand( "playersonly", SV_PlayersOnly_f, "freezes time, except for players" );
Cmd_AddCommand( "restart", SV_Restart_f, "restarting current level" );
Cmd_AddCommand( "reload", SV_Reload_f, "continue from latest save or restart level" );
Cmd_AddCommand( "entpatch", SV_EntPatch_f, "write entity patch to allow external editing" );
Cmd_AddCommand( "edict_usage", SV_EdictUsage_f, "show info about edicts usage" );
Cmd_AddCommand( "entity_info", SV_EntityInfo_f, "show more info about edicts" );
Cmd_AddCommand( "shutdownserver", SV_KillServer_f, "shutdown current server" );
Cmd_AddCommand( "changelevel", SV_ChangeLevel_f, "change level" );
Cmd_AddCommand( "changelevel2", SV_ChangeLevel2_f, "smooth change level" );
if( host.type == HOST_NORMAL )
{
Cmd_AddCommand( "save", SV_Save_f, "save the game to a file" );
Cmd_AddCommand( "savequick", SV_QuickSave_f, "save the game to the quicksave" );
Cmd_AddCommand( "autosave", SV_AutoSave_f, "save the game to 'autosave' file" );
Cmd_AddCommand( "killsave", SV_DeleteSave_f, "delete a saved game file and saveshot" );
}
else if( host.type == HOST_DEDICATED )
{
@@ -852,17 +943,17 @@ void SV_KillOperatorCommands( void )
Cmd_RemoveCommand( "clientinfo" );
Cmd_RemoveCommand( "playersonly" );
Cmd_RemoveCommand( "restart" );
Cmd_RemoveCommand( "reload" );
Cmd_RemoveCommand( "entpatch" );
Cmd_RemoveCommand( "edict_usage" );
Cmd_RemoveCommand( "entity_info" );
Cmd_RemoveCommand( "shutdownserver" );
Cmd_RemoveCommand( "changelevel" );
Cmd_RemoveCommand( "changelevel2" );
if( host.type == HOST_NORMAL )
{
Cmd_RemoveCommand( "save" );
Cmd_RemoveCommand( "savequick" );
Cmd_RemoveCommand( "killsave" );
Cmd_RemoveCommand( "autosave" );
}
else if( host.type == HOST_DEDICATED )

View File

@@ -313,7 +313,7 @@ void SV_MoveToOnHandList( sv_client_t *cl, resource_t *pResource )
{
if( !pResource )
{
MsgDev( D_REPORT, "Null resource passed to SV_MoveToOnHandList\n" );
Con_Reportf( "Null resource passed to SV_MoveToOnHandList\n" );
return;
}
@@ -325,7 +325,7 @@ void SV_AddToResourceList( resource_t *pResource, resource_t *pList )
{
if( pResource->pPrev != NULL || pResource->pNext != NULL )
{
MsgDev( D_ERROR, "Resource already linked\n" );
Con_Reportf( S_ERROR "Resource already linked\n" );
return;
}
@@ -524,7 +524,7 @@ void SV_BatchUploadRequest( sv_client_t *cl )
}
else
{
MsgDev( D_ERROR, "Non customization in upload queue!\n" );
Con_Reportf( S_ERROR "Non customization in upload queue!\n" );
SV_MoveToOnHandList( cl, p );
}
}

View File

@@ -138,7 +138,7 @@ static void SV_AddEntitiesToPacket( edict_t *pViewEnt, edict_t *pClient, client_
}
// if we are full, silently discard entities
if( ents->num_entities < MAX_VISIBLE_PACKET )
if( ents->num_entities < ( MAX_VISIBLE_PACKET - 1 ))
{
ents->num_entities++; // entity accepted
c_fullsend++; // debug counter
@@ -172,6 +172,13 @@ Encode a client frame onto the network channel
=============================================================================
*/
/*
=============
SV_FindBestBaseline
trying to deltas with previous entities
=============
*/
int SV_FindBestBaseline( sv_client_t *cl, int index, entity_state_t **baseline, entity_state_t *to, client_frame_t *frame, qboolean player )
{
int bestBitCount;
@@ -205,6 +212,43 @@ int SV_FindBestBaseline( sv_client_t *cl, int index, entity_state_t **baseline,
return index - bestfound;
}
/*
=============
SV_FindBestBaselineForStatic
trying to deltas with previous static entities
=============
*/
int SV_FindBestBaselineForStatic( int index, entity_state_t **baseline, entity_state_t *to )
{
int bestBitCount;
int i, bitCount;
int bestfound, j;
bestBitCount = j = Delta_TestBaseline( *baseline, to, false, sv.time );
bestfound = index;
// lookup backward for previous 64 states and try to interpret current delta as baseline
for( i = index - 1; bestBitCount > 0 && i >= 0 && ( index - i ) < ( MAX_CUSTOM_BASELINES - 1 ); i-- )
{
// don't worry about underflow in circular buffer
entity_state_t *test = &svs.static_entities[i];
bitCount = Delta_TestBaseline( test, to, false, sv.time );
if( bitCount < bestBitCount )
{
bestBitCount = bitCount;
bestfound = i;
}
}
// using delta from previous entity as baseline for current
if( index != bestfound )
*baseline = &svs.static_entities[bestfound];
return index - bestfound;
}
/*
=============
SV_EmitPacketEntities
@@ -685,7 +729,7 @@ void SV_SendClientDatagram( sv_client_t *cl )
{
if( MSG_GetNumBytesWritten( &cl->datagram ) < MSG_GetNumBytesLeft( &msg ))
MSG_WriteBits( &msg, MSG_GetData( &cl->datagram ), MSG_GetNumBitsWritten( &cl->datagram ));
else MsgDev( D_WARN, "Ignoring unreliable datagram for %s, would overflow on msg\n", cl->name );
else Con_DPrintf( S_WARN "Ignoring unreliable datagram for %s, would overflow on msg\n", cl->name );
}
MSG_Clear( &cl->datagram );
@@ -747,14 +791,14 @@ void SV_UpdateToReliableMessages( void )
// clear the server datagram if it overflowed.
if( MSG_CheckOverflow( &sv.datagram ))
{
MsgDev( D_ERROR, "sv.datagram overflowed!\n" );
Con_DPrintf( S_ERROR "sv.datagram overflowed!\n" );
MSG_Clear( &sv.datagram );
}
// clear the server datagram if it overflowed.
if( MSG_CheckOverflow( &sv.spec_datagram ))
{
MsgDev( D_ERROR, "sv.spec_datagram overflowed!\n" );
Con_DPrintf( S_ERROR "sv.spec_datagram overflowed!\n" );
MSG_Clear( &sv.spec_datagram );
}
@@ -779,7 +823,7 @@ void SV_UpdateToReliableMessages( void )
}
else
{
MsgDev( D_WARN, "Ignoring unreliable datagram for %s, would overflow\n", cl->name );
Con_DPrintf( S_WARN "Ignoring unreliable datagram for %s, would overflow\n", cl->name );
}
if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
@@ -790,7 +834,7 @@ void SV_UpdateToReliableMessages( void )
}
else
{
MsgDev( D_WARN, "Ignoring spectator datagram for %s, would overflow\n", cl->name );
Con_DPrintf( S_WARN "Ignoring spectator datagram for %s, would overflow\n", cl->name );
}
}
}
@@ -845,7 +889,7 @@ void SV_SendClientMessages( void )
MSG_Clear( &cl->netchan.message );
MSG_Clear( &cl->datagram );
SV_BroadcastPrintf( NULL, "%s overflowed\n", cl->name );
MsgDev( D_WARN, "reliable overflow for %s\n", cl->name );
Con_DPrintf( S_ERROR "reliable overflow for %s\n", cl->name );
SV_DropClient( cl, false );
SetBits( cl->flags, FCL_SEND_NET_MESSAGE );
cl->netchan.cleartime = 0.0; // don't choke this message
@@ -962,6 +1006,12 @@ void SV_InactivateClients( void )
COM_ClearCustomizationList( &cl->customdata, false );
memset( cl->physinfo, 0, MAX_PHYSINFO_STRING );
// NOTE: many mods sending messages that must be applied on a next level
// e.g. CryOfFear sending HideHud and PlayMp3 that affected after map change
if( svgame.globals->changelevel )
continue;
MSG_Clear( &cl->netchan.message );
MSG_Clear( &cl->datagram );
}

View File

@@ -497,39 +497,47 @@ SV_CreateStaticEntity
NOTE: static entities only accepted when game is loading
=======================
*/
void SV_CreateStaticEntity( sizebuf_t *msg, sv_static_entity_t *ent )
qboolean SV_CreateStaticEntity( sizebuf_t *msg, int index )
{
int index;
entity_state_t nullstate, *baseline;
entity_state_t *state;
int offset;
if( index >= ( MAX_STATIC_ENTITIES - 1 ))
{
if( !sv.static_ents_overflow )
{
Con_Printf( S_WARN "MAX_STATIC_ENTITIES limit exceeded (%d)\n", MAX_STATIC_ENTITIES );
sv.static_ents_overflow = true;
}
sv.ignored_static_ents++; // continue overflowed entities
return false;
}
// this can happens if serialized map contain too many static entities...
if( MSG_GetNumBytesLeft( msg ) < 35 )
if( MSG_GetNumBytesLeft( msg ) < 50 )
{
sv.ignored_static_ents++;
return;
return false;
}
index = SV_ModelIndex( ent->model );
state = &svs.static_entities[index]; // allocate a new one
memset( &nullstate, 0, sizeof( nullstate ));
baseline = &nullstate;
// restore modelindex from modelname (already precached)
state->modelindex = pfnModelIndex( STRING( state->messagenum ));
state->entityType = ENTITY_NORMAL; // select delta-encode
state->number = 0;
// trying to compress with previous delta's
offset = SV_FindBestBaselineForStatic( index, &baseline, state );
MSG_BeginServerCmd( msg, svc_spawnstatic );
MSG_WriteShort( msg, index );
MSG_WriteWord( msg, ent->sequence );
MSG_WriteWord( msg, ent->frame );
MSG_WriteWord( msg, ent->colormap );
MSG_WriteByte( msg, ent->skin );
MSG_WriteByte( msg, ent->body );
MSG_WriteCoord( msg, ent->scale );
MSG_WriteVec3Coord( msg, ent->origin );
MSG_WriteVec3Angles( msg, ent->angles );
MSG_WriteByte( msg, ent->rendermode );
MSG_WriteDeltaEntity( baseline, state, msg, true, DELTA_STATIC, sv.time, offset );
if( ent->rendermode != kRenderNormal )
{
MSG_WriteByte( msg, ent->renderamt );
MSG_WriteByte( msg, ent->rendercolor.r );
MSG_WriteByte( msg, ent->rendercolor.g );
MSG_WriteByte( msg, ent->rendercolor.b );
MSG_WriteByte( msg, ent->renderfx );
}
return true;
}
/*
@@ -541,18 +549,14 @@ Write all the static ents into demo
*/
void SV_RestartStaticEnts( void )
{
sv_static_entity_t *clent;
int i;
int i;
// remove all the static entities on the client
R_ClearStaticEntities();
// resend them again
for( i = 0; i < sv.num_static_entities; i++ )
{
clent = &sv.static_entities[i];
SV_CreateStaticEntity( &sv.reliable_datagram, clent );
}
SV_CreateStaticEntity( &sv.reliable_datagram, i );
}
/*
@@ -567,7 +571,7 @@ void SV_RestartAmbientSounds( void )
soundlist_t soundInfo[256];
string curtrack, looptrack;
int i, nSounds;
long position;
int position;
if( !SV_Active( )) return;
@@ -611,7 +615,7 @@ void SV_RestartDecals( void )
if( !SV_Active( )) return;
// g-cont. add space for studiodecals if present
host.decalList = (decallist_t *)Z_Malloc( sizeof( decallist_t ) * MAX_RENDER_DECALS * 2 );
host.decalList = (decallist_t *)Z_Calloc( sizeof( decallist_t ) * MAX_RENDER_DECALS * 2 );
host.numdecals = R_CreateDecalList( host.decalList );
// remove decals from map
@@ -649,13 +653,98 @@ SV_BoxInPVS
check brush boxes in fat pvs
==============
*/
int SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t absmax )
qboolean SV_BoxInPVS( const vec3_t org, const vec3_t absmin, const vec3_t absmax )
{
if( !Mod_BoxVisible( absmin, absmax, Mod_GetPVSForPoint( org )))
return false;
return true;
}
/*
=============
SV_ChangeLevel
Issue changing level
=============
*/
void SV_QueueChangeLevel( const char *level, const char *landname )
{
int flags, smooth = false;
char mapname[MAX_QPATH];
char *spawn_entity;
// hold mapname to other place
Q_strncpy( mapname, level, sizeof( mapname ));
COM_StripExtension( mapname );
if( COM_CheckString( landname ))
smooth = true;
// determine spawn entity classname
if( svs.maxclients == 1 )
spawn_entity = GI->sp_entity;
else spawn_entity = GI->mp_entity;
flags = SV_MapIsValid( mapname, spawn_entity, landname );
if( FBitSet( flags, MAP_INVALID_VERSION ))
{
Con_Printf( S_ERROR "changelevel: %s is invalid or not supported\n", mapname );
return;
}
if( !FBitSet( flags, MAP_IS_EXIST ))
{
Con_Printf( S_ERROR "changelevel: map %s doesn't exist\n", mapname );
return;
}
if( smooth && !FBitSet( flags, MAP_HAS_LANDMARK ))
{
if( sv_validate_changelevel->value )
{
// NOTE: we find valid map but specified landmark it's doesn't exist
// run simple changelevel like in q1, throw warning
Con_Printf( S_WARN "changelevel: %s doesn't contain landmark [%s]. smooth transition was disabled\n", mapname, landname );
smooth = false;
}
}
if( svs.maxclients > 1 )
smooth = false; // multiplayer doesn't support smooth transition
if( smooth && !Q_stricmp( sv.name, level ))
{
Con_Printf( S_ERROR "can't changelevel with same map. Ignored.\n" );
return;
}
if( !smooth && !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
{
if( sv_validate_changelevel->value )
{
Con_Printf( S_ERROR "changelevel: %s doesn't have a valid spawnpoint. Ignored.\n", mapname );
return;
}
}
// bad changelevel position invoke enables in one-way transition
if( sv.framecount < 15 )
{
if( sv_validate_changelevel->value )
{
Con_Printf( S_WARN "an infinite changelevel was detected and will be disabled until a next save\\restore\n" );
return; // lock with svs.spawncount here
}
}
SV_SkipUpdates ();
// changelevel will be executed on a next frame
if( smooth ) COM_ChangeLevel( mapname, landname, sv.background ); // Smoothed Half-Life changelevel
else COM_ChangeLevel( mapname, NULL, sv.background ); // Classic Quake changlevel
}
/*
==============
SV_WriteEntityPatch
@@ -694,7 +783,7 @@ void SV_WriteEntityPatch( const char *filename )
char *entities = NULL;
FS_Seek( f, lumpofs, SEEK_SET );
entities = (char *)Z_Malloc( lumplen + 1 );
entities = (char *)Z_Calloc( lumplen + 1 );
FS_Read( f, entities, lumplen );
FS_WriteFile( va( "maps/%s.ent", filename ), entities, lumplen );
Con_Printf( "Write 'maps/%s.ent'\n", filename );
@@ -762,7 +851,7 @@ static char *SV_ReadEntityScript( const char *filename, int *flags )
if( !ents && lumplen >= 32 )
{
FS_Seek( f, lumpofs, SEEK_SET );
ents = Z_Malloc( lumplen + 1 );
ents = Z_Calloc( lumplen + 1 );
FS_Read( f, ents, lumplen );
}
FS_Close( f ); // all done
@@ -1192,24 +1281,29 @@ pfnSetModel
*/
void pfnSetModel( edict_t *e, const char *m )
{
char name[MAX_QPATH];
model_t *mod;
int i;
if( !SV_IsValidEdict( e ))
return;
if( COM_CheckString( m ))
if( *m == '\\' || *m == '/' ) m++;
Q_strncpy( name, m, sizeof( name ));
COM_FixSlashes( name );
if( COM_CheckString( name ))
{
// check to see if model was properly precached
for( i = 1; i < MAX_MODELS && sv.model_precache[i][0]; i++ )
{
if( !Q_stricmp( sv.model_precache[i], m ))
if( !Q_stricmp( sv.model_precache[i], name ))
break;
}
if( i == MAX_MODELS )
{
Con_Printf( S_ERROR "no precache: %s\n", m );
Con_Printf( S_ERROR "no precache: %s\n", name );
return;
}
}
@@ -1221,7 +1315,7 @@ void pfnSetModel( edict_t *e, const char *m )
return;
}
if( COM_CheckString( m ))
if( COM_CheckString( name ))
{
e->v.model = MAKE_STRING( sv.model_precache[i] );
e->v.modelindex = i;
@@ -1248,18 +1342,23 @@ pfnModelIndex
*/
int pfnModelIndex( const char *m )
{
char name[MAX_QPATH];
int i;
if( !COM_CheckString( m ))
return 0;
if( *m == '\\' || *m == '/' ) m++;
Q_strncpy( name, m, sizeof( name ));
COM_FixSlashes( name );
for( i = 1; i < MAX_MODELS && sv.model_precache[i][0]; i++ )
{
if( !Q_stricmp( sv.model_precache[i], m ))
if( !Q_stricmp( sv.model_precache[i], name ))
return i;
}
Con_Printf( S_ERROR "no precache: %s\n", m );
Con_Printf( S_ERROR "no precache: %s\n", name );
return 0;
}
@@ -1300,11 +1399,8 @@ pfnChangeLevel
*/
void pfnChangeLevel( const char *level, const char *landmark )
{
int flags, smooth = false;
static uint last_spawncount = 0;
char mapname[MAX_QPATH];
char landname[MAX_QPATH];
char *spawn_entity;
char *text;
if( !COM_CheckString( level ) || sv.state != ss_active )
@@ -1314,12 +1410,9 @@ void pfnChangeLevel( const char *level, const char *landmark )
if( svs.spawncount == last_spawncount )
return;
last_spawncount = svs.spawncount;
// hold mapname to other place
Q_strncpy( mapname, level, sizeof( mapname ));
COM_StripExtension( mapname );
landname[0] ='\0';
#ifdef HACKS_RELATED_HLMODS
// g-cont. some level-designers wrote landmark name with space
// and Cmd_TokenizeString separating all the after space as next argument
// emulate this bug for compatibility
@@ -1328,73 +1421,12 @@ void pfnChangeLevel( const char *level, const char *landmark )
text = (char *)landname;
while( *landmark && ((byte)*landmark) != ' ' )
*text++ = *landmark++;
smooth = true;
*text = '\0';
}
// determine spawn entity classname
if( svs.maxclients == 1 )
spawn_entity = GI->sp_entity;
else spawn_entity = GI->mp_entity;
flags = SV_MapIsValid( mapname, spawn_entity, landname );
if( FBitSet( flags, MAP_INVALID_VERSION ))
{
Con_Printf( S_ERROR "changelevel: %s is invalid or not supported\n", mapname );
return;
}
if( !FBitSet( flags, MAP_IS_EXIST ))
{
Con_Printf( S_ERROR "changelevel: map %s doesn't exist\n", mapname );
return;
}
if( smooth && !FBitSet( flags, MAP_HAS_LANDMARK ))
{
if( sv_validate_changelevel->value )
{
// NOTE: we find valid map but specified landmark it's doesn't exist
// run simple changelevel like in q1, throw warning
Con_Printf( S_WARN "changelevel: %s doesn't contain landmark [%s]. smooth transition was disabled\n", mapname, landname );
smooth = false;
}
}
if( svs.maxclients > 1 )
smooth = false; // multiplayer doesn't support smooth transition
if( smooth && !Q_stricmp( sv.name, level ))
{
Con_Printf( S_ERROR "can't changelevel with same map. Ignored.\n" );
return;
}
if( !smooth && !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
{
if( sv_validate_changelevel->value )
{
Con_Printf( S_ERROR "changelevel: %s doesn't have a valid spawnpoint. Ignored.\n", mapname );
return;
}
}
// bad changelevel position invoke enables in one-way transition
if( sv.framecount < 15 )
{
if( sv_validate_changelevel->value )
{
Con_Printf( S_WARN "an infinite changelevel was detected and will be disabled until a next save\\restore\n" );
return; // lock with svs.spawncount here
}
}
SV_SkipUpdates ();
// changelevel will be executed on a next frame
if( smooth ) COM_ChangeLevel( mapname, landname, sv.background ); // Smoothed Half-Life changelevel
else COM_ChangeLevel( mapname, NULL, sv.background ); // Classic Quake changlevel
#else
Q_strncpy( landname, landmark, sizeof( landname ));
#endif
SV_QueueChangeLevel( level, landname );
}
/*
@@ -1832,42 +1864,18 @@ move entity to client
*/
static void pfnMakeStatic( edict_t *ent )
{
sv_static_entity_t *clent;
entity_state_t *state;
if( !SV_IsValidEdict( ent ))
return;
if( sv.num_static_entities >= MAX_STATIC_ENTITIES )
{
if( !sv.static_ents_overflow )
{
Con_Printf( S_WARN "MAX_STATIC_ENTITIES limit exceeded (%d)\n", MAX_STATIC_ENTITIES );
sv.static_ents_overflow = true;
}
sv.ignored_static_ents++; // continue overflowed entities
return;
}
// fill the entity state
state = &svs.static_entities[sv.num_static_entities]; // allocate a new one
svgame.dllFuncs.pfnCreateBaseline( false, NUM_FOR_EDICT( ent ), state, ent, 0, vec3_origin, vec3_origin );
state->messagenum = ent->v.model; // member modelname
clent = &sv.static_entities[sv.num_static_entities++];
Q_strncpy( clent->model, STRING( ent->v.model ), sizeof( clent->model ));
VectorCopy( ent->v.origin, clent->origin );
VectorCopy( ent->v.angles, clent->angles );
clent->sequence = ent->v.sequence;
clent->frame = ent->v.frame * 128;
clent->colormap = ent->v.colormap;
clent->skin = ent->v.skin;
clent->body = ent->v.body;
clent->scale = ent->v.scale;
clent->rendermode = ent->v.rendermode;
clent->renderamt = ent->v.renderamt;
clent->rendercolor.r = ent->v.rendercolor[0];
clent->rendercolor.g = ent->v.rendercolor[1];
clent->rendercolor.b = ent->v.rendercolor[2];
clent->renderfx = ent->v.renderfx;
SV_CreateStaticEntity( &sv.signon, clent );
if( SV_CreateStaticEntity( &sv.signon, sv.num_static_entities ))
sv.num_static_entities++;
// remove at end of the frame
SetBits( ent->v.flags, FL_KILLME );
@@ -1983,38 +1991,44 @@ int SV_BuildSoundMsg( sizebuf_t *msg, edict_t *ent, int chan, const char *sample
if( vol < 0 || vol > 255 )
{
Con_Printf( S_ERROR "SV_StartSound: volume = %i\n", vol );
Con_Reportf( S_ERROR "SV_StartSound: volume = %i\n", vol );
vol = bound( 0, vol, 255 );
}
if( attn < 0.0f || attn > 4.0f )
{
Con_Printf( S_ERROR "SV_StartSound: attenuation %g must be in range 0-4\n", attn );
Con_Reportf( S_ERROR "SV_StartSound: attenuation %g must be in range 0-4\n", attn );
attn = bound( 0.0f, attn, 4.0f );
}
if( chan < 0 || chan > 7 )
{
Con_Printf( S_ERROR "SV_StartSound: channel must be in range 0-7\n" );
Con_Reportf( S_ERROR "SV_StartSound: channel must be in range 0-7\n" );
chan = bound( 0, chan, 7 );
}
if( pitch < 0 || pitch > 255 )
{
Con_Printf( S_ERROR "SV_StartSound: pitch = %i\n", pitch );
Con_Reportf( S_ERROR "SV_StartSound: pitch = %i\n", pitch );
pitch = bound( 0, pitch, 255 );
}
if( !COM_CheckString( sample ))
{
Con_Printf( S_ERROR "SV_StartSound: passed NULL sample\n" );
Con_Reportf( S_ERROR "SV_StartSound: passed NULL sample\n" );
return 0;
}
if( sample[0] == '!' && Q_isdigit( sample + 1 ))
{
SetBits( flags, SND_SENTENCE );
sound_idx = Q_atoi( sample + 1 );
if( sound_idx >= MAX_SOUNDS )
{
SetBits( flags, SND_SENTENCE|SND_SEQUENCE );
sound_idx -= MAX_SOUNDS;
}
else SetBits( flags, SND_SENTENCE );
}
else if( sample[0] == '#' && Q_isdigit( sample + 1 ))
{
@@ -2023,6 +2037,9 @@ int SV_BuildSoundMsg( sizebuf_t *msg, edict_t *ent, int chan, const char *sample
}
else
{
// TESTTEST
if( *sample == '*' ) chan = CHAN_AUTO;
// precache_sound can be used twice: cache sounds when loading
// and return sound index when server is active
sound_idx = SV_SoundIndex( sample );
@@ -2091,7 +2108,7 @@ void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float
msg_dest = MSG_ALL;
else if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
msg_dest = MSG_ALL;
else msg_dest = MSG_PAS_R;
else msg_dest = (svs.maxclients <= 1 ) ? MSG_ALL : MSG_PAS_R;
// always sending stop sound command
if( FBitSet( flags, SND_STOP ))
@@ -2112,7 +2129,7 @@ pfnEmitAmbientSound
*/
void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *sample, float vol, float attn, int flags, int pitch )
{
int msg_dest = MSG_PAS_R;
int msg_dest;
if( sv.state == ss_loading )
SetBits( flags, SND_SPAWNING );
@@ -2135,7 +2152,7 @@ SV_StartMusic
=================
*/
void SV_StartMusic( const char *curtrack, const char *looptrack, long position )
void SV_StartMusic( const char *curtrack, const char *looptrack, int position )
{
MSG_BeginServerCmd( &sv.multicast, svc_stufftext );
MSG_WriteString( &sv.multicast, va( "music \"%s\" \"%s\" %li\n", curtrack, looptrack, position ));
@@ -2395,7 +2412,7 @@ void pfnServerExecute( void )
Cbuf_Execute();
if( host.sv_cvars_restored > 0 )
Con_DPrintf( "server executing ^2config.cfg^7 (%i cvars)\n", host.sv_cvars_restored );
Con_Reportf( "server executing ^2config.cfg^7 (%i cvars)\n", host.sv_cvars_restored );
host.apply_game_config = false;
svgame.config_executed = true;
@@ -2927,7 +2944,7 @@ void *pfnPvAllocEntPrivateData( edict_t *pEdict, long cb )
if( cb > 0 )
{
// a poke646 have memory corrupt in somewhere - this is trashed last sixteen bytes :(
pEdict->pvPrivateData = Mem_Alloc( svgame.mempool, (cb + 15) & ~15 );
pEdict->pvPrivateData = Mem_Calloc( svgame.mempool, (cb + 15) & ~15 );
}
return pEdict->pvPrivateData;
@@ -2947,41 +2964,248 @@ void *pfnPvEntPrivateData( edict_t *pEdict )
return NULL;
}
#ifdef XASH_64BIT
static struct str64_s
{
size_t maxstringarray;
qboolean allowdup;
char *staticstringarray;
char *pstringarray;
char *pstringarraystatic;
char *pstringbase;
char *poldstringbase;
char *plast;
qboolean dynamic;
size_t maxalloc;
size_t numdups;
size_t numoverflows;
size_t totalalloc;
} str64;
#endif
/*
==================
SV_EmptyStringPool
Free strings on server stop. Reset string pointer on 64 bits
==================
*/
void SV_EmptyStringPool( void )
{
#ifdef XASH_64BIT
if( str64.dynamic ) // switch only after array fill (more space for multiplayer games)
str64.pstringbase = str64.pstringarray;
else
{
str64.pstringbase = str64.poldstringbase = str64.pstringarraystatic;
str64.plast = str64.pstringbase + 1;
}
#else
Mem_EmptyPool( svgame.stringspool );
#endif
}
/*
===============
SV_SetStringArrayMode
use different arrays on 64 bit platforms
set dynamic after complete server spawn
this helps not to lose strings that belongs to static game part
===============
*/
void SV_SetStringArrayMode( qboolean dynamic )
{
#ifdef XASH_64BIT
Con_Reportf( "SV_SetStringArrayMode(%d) %d\n", dynamic, str64.dynamic );
if( dynamic == str64.dynamic )
return;
str64.dynamic = dynamic;
SV_EmptyStringPool();
#endif
}
#ifdef XASH_64BIT
#ifndef _WIN32
#define USE_MMAP
#include <sys/mman.h>
#endif
#endif
/*
==================
SV_AllocStringPool
alloc string pool on 32bit platforms
alloc string array near the server library on 64bit platforms if possible
alloc string array somewhere if not (MAKE_STRING will not work. Always call ALLOC_STRING instead, or crash)
this case need patched game dll with MAKE_STRING checking ptrdiff size
==================
*/
void SV_AllocStringPool( void )
{
#ifdef XASH_64BIT
void *ptr = NULL;
string lenstr;
Con_Reportf( "SV_AllocStringPool()\n" );
if( Sys_GetParmFromCmdLine( "-str64alloc", lenstr ) )
{
str64.maxstringarray = Q_atoi( lenstr );
if( str64.maxstringarray < 1024 || str64.maxstringarray >= INT_MAX )
str64.maxstringarray = 65536;
}
else str64.maxstringarray = 65536;
if( Sys_CheckParm( "-str64dup" ) )
str64.allowdup = true;
#ifdef USE_MMAP
{
size_t pagesize = sysconf( _SC_PAGESIZE );
int arrlen = (str64.maxstringarray * 2) & ~(pagesize - 1);
void *base = svgame.dllFuncs.pfnGameInit;
void *start = svgame.hInstance - arrlen;
while( start - base > INT_MIN )
{
void *mapptr = mmap((void*)((unsigned long)start & ~(pagesize - 1)), arrlen, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0 );
if( mapptr && mapptr != (void*)-1 && mapptr - base > INT_MIN && mapptr - base < INT_MAX )
{
ptr = mapptr;
break;
}
if( mapptr ) munmap( mapptr, arrlen );
start -= arrlen;
}
if( !ptr )
{
start = base;
while( start - base < INT_MAX )
{
void *mapptr = mmap((void*)((unsigned long)start & ~(pagesize - 1)), arrlen, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0 );
if( mapptr && mapptr != (void*)-1 && mapptr - base > INT_MIN && mapptr - base < INT_MAX )
{
ptr = mapptr;
break;
}
if( mapptr ) munmap( mapptr, arrlen );
start += arrlen;
}
}
if( ptr )
{
Con_Reportf( "SV_AllocStringPool: Allocated string array near the server library: %p %p\n", base, ptr );
}
else
{
Con_Reportf( "SV_AllocStringPool: Failed to allocate string array near the server library!\n" );
ptr = str64.staticstringarray = Mem_Calloc(host.mempool, str64.maxstringarray * 2);
}
}
#else
ptr = str64.staticstringarray = Mem_Calloc(host.mempool, str64.maxstringarray * 2);
#endif
str64.pstringarray = ptr;
str64.pstringarraystatic = ptr + str64.maxstringarray;
str64.pstringbase = str64.poldstringbase = ptr;
str64.plast = ptr + 1;
svgame.globals->pStringBase = ptr;
#else
svgame.stringspool = Mem_AllocPool( "Server Strings" );
svgame.globals->pStringBase = "";
#endif
}
void SV_FreeStringPool( void )
{
#ifdef XASH_64BIT
Con_Reportf( "SV_FreeStringPool()\n" );
if( str64.pstringarray != str64.staticstringarray )
munmap( str64.pstringarray, (str64.maxstringarray * 2) & ~(sysconf( _SC_PAGESIZE ) - 1) );
else
Mem_Free( str64.staticstringarray );
#else
Mem_FreePool( &svgame.stringspool );
#endif
}
/*
=============
SV_AllocString
allocate new engine string
on 64bit platforms find in array string if deduplication enabled (default)
if not found, add to array
use -str64dup to disable deduplication, -str64alloc to set array size
=============
*/
string_t SV_AllocString( const char *szString )
string_t GAME_EXPORT SV_AllocString( const char *szValue )
{
char *out, *out_p;
int i, l;
const char *newString = NULL;
if( svgame.physFuncs.pfnAllocString != NULL )
return svgame.physFuncs.pfnAllocString( szString );
return svgame.physFuncs.pfnAllocString( szValue );
#ifdef XASH_64BIT
int cmp = 1;
if( !COM_CheckString( szString ))
return 0;
if( !str64.allowdup )
for( newString = str64.poldstringbase + 1; newString < str64.plast && ( cmp = Q_strcmp( newString, szValue ) ); newString += Q_strlen( newString ) + 1 );
l = Q_strlen( szString ) + 1;
out = out_p = Mem_Alloc( svgame.stringspool, l );
for( i = 0; i < l; i++ )
if( cmp )
{
if( szString[i] == '\\' && i < l - 1 )
{
i++;
if( szString[i] == 'n')
*out_p++ = '\n';
else *out_p++ = '\\';
}
else *out_p++ = szString[i];
}
uint len = Q_strlen( szValue );
return out - svgame.globals->pStringBase;
}
if( str64.plast - str64.poldstringbase + len + 2 > str64.maxstringarray )
{
str64.plast = str64.pstringbase + 1;
str64.poldstringbase = str64.pstringbase;
str64.numoverflows++;
}
//MsgDev( D_NOTE, "SV_AllocString: %ld %s\n", str64.plast - svgame.globals->pStringBase, szValue );
memcpy( str64.plast, szValue, len + 1 );
str64.totalalloc += len + 1;
newString = str64.plast;
str64.plast += len + 1;
}
else
str64.numdups++;
//MsgDev( D_NOTE, "SV_AllocString: dup %ld %s\n", newString - svgame.globals->pStringBase, szValue );
if( newString - str64.pstringarray > str64.maxalloc )
str64.maxalloc = newString - str64.pstringarray;
return newString - svgame.globals->pStringBase;
#else
newString = _copystring( svgame.stringspool, szValue, __FILE__, __LINE__ );
return newString - svgame.globals->pStringBase;
#endif
}
#ifdef XASH_64BIT
void SV_PrintStr64Stats_f( void )
{
Msg( "====================\n" );
Msg( "64 bit string pool statistics\n" );
Msg( "====================\n" );
Msg( "string array size: %lu\n", str64.maxstringarray );
Msg( "total alloc %lu\n", str64.totalalloc );
Msg( "maximum array usage: %lu\n", str64.maxalloc );
Msg( "overflow counter: %lu\n", str64.numoverflows );
Msg( "dup string counter: %lu\n", str64.numdups );
}
#endif
/*
=============
@@ -2994,9 +3218,18 @@ string_t SV_MakeString( const char *szValue )
{
if( svgame.physFuncs.pfnMakeString != NULL )
return svgame.physFuncs.pfnMakeString( szValue );
#ifdef XASH_64BIT
{
long long ptrdiff = szValue - svgame.globals->pStringBase;
if( ptrdiff > INT_MAX || ptrdiff < INT_MIN )
return SV_AllocString(szValue);
else
return (int)ptrdiff;
}
#else
return szValue - svgame.globals->pStringBase;
}
#endif
}
/*
=============
@@ -3405,7 +3638,7 @@ OBSOLETE, UNUSED
*/
uint pfnGetPlayerWONId( edict_t *e )
{
return -1;
return (uint)-1;
}
/*
@@ -3435,10 +3668,7 @@ void pfnFadeClientVolume( const edict_t *pEdict, int fadePercent, int fadeOutSec
sv_client_t *cl;
if(( cl = SV_ClientFromEdict( pEdict, true )) == NULL )
{
MsgDev( D_ERROR, "SV_FadeClientVolume: client is not spawned!\n" );
return;
}
if( FBitSet( cl->flags, FCL_FAKECLIENT ))
return;
@@ -4099,7 +4329,7 @@ void pfnEndSection( const char *pszSection )
{
if( !Q_stricmp( "oem_end_credits", pszSection ))
Host_Credits ();
else Cbuf_AddText( va( "endgame \"%s\"\n", pszSection ));
else Cbuf_AddText( "\ndisconnect\n" );
}
/*
@@ -4589,7 +4819,7 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
COM_ParseVector( &pstart, origin, 3 );
Mem_Free( pkvd[i].szValue ); // release old value, so we don't need these
copystring( va( "%g %g %g", origin[0], origin[1], origin[2] - 16.0f ));
pkvd[i].szValue = copystring( va( "%g %g %g", origin[0], origin[1], origin[2] - 16.0f ));
}
#endif
if( !Q_strcmp( pkvd[i].szKeyName, "light" ))
@@ -4605,8 +4835,11 @@ qboolean SV_ParseEdict( char **pfile, edict_t *ent )
}
// no reason to keep this data
Mem_Free( pkvd[i].szKeyName );
Mem_Free( pkvd[i].szValue );
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szKeyName ))
Mem_Free( pkvd[i].szKeyName );
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szValue ))
Mem_Free( pkvd[i].szValue );
}
if( classname )
@@ -4728,7 +4961,7 @@ void SV_UnloadProgs( void )
Delta_Shutdown ();
Mod_ClearUserData ();
Mem_FreePool( &svgame.stringspool );
SV_FreeStringPool();
if( svgame.dllFuncs2.pfnGameShutdown != NULL )
svgame.dllFuncs2.pfnGameShutdown ();
@@ -4738,6 +4971,7 @@ void SV_UnloadProgs( void )
Cvar_FullSet( "sv_background", "0", FCVAR_READ_ONLY );
// free entity baselines
Z_Free( svs.static_entities );
Z_Free( svs.baselines );
svs.baselines = NULL;
@@ -4840,7 +5074,7 @@ qboolean SV_LoadProgs( const char *name )
return false;
}
}
else Con_DPrintf( "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
else Con_Reportf( "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
}
else if( !GetEntityAPI( &svgame.dllFuncs, version ))
{
@@ -4865,15 +5099,16 @@ qboolean SV_LoadProgs( const char *name )
svgame.globals->maxEntities = GI->max_edicts;
svgame.globals->maxClients = svs.maxclients;
svgame.edicts = Mem_Alloc( svgame.mempool, sizeof( edict_t ) * GI->max_edicts );
svs.baselines = Z_Malloc( sizeof( entity_state_t ) * GI->max_edicts );
svgame.edicts = Mem_Calloc( svgame.mempool, sizeof( edict_t ) * GI->max_edicts );
svs.static_entities = Z_Calloc( sizeof( entity_state_t ) * MAX_STATIC_ENTITIES );
svs.baselines = Z_Calloc( sizeof( entity_state_t ) * GI->max_edicts );
svgame.numEntities = svs.maxclients + 1; // clients + world
for( i = 0, e = svgame.edicts; i < GI->max_edicts; i++, e++ )
e->free = true; // mark all edicts as freed
Cvar_FullSet( "host_gameloaded", "1", FCVAR_READ_ONLY );
svgame.stringspool = Mem_AllocPool( "Server Strings" );
SV_AllocStringPool();
// fire once
Con_Printf( "Dll loaded for game ^2\"%s\"\n", svgame.dllFuncs.pfnGetGameDescription( ));

View File

@@ -387,7 +387,7 @@ void SV_CreateBaseline( void )
{
entity_state_t nullstate, *base;
int playermodel;
qboolean player;
int delta_type;
int entnum;
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
@@ -405,13 +405,13 @@ void SV_CreateBaseline( void )
if( entnum != 0 && entnum <= svs.maxclients )
{
player = true;
delta_type = DELTA_PLAYER;
}
else
{
if( !pEdict->v.modelindex )
continue; // invisible
player = false;
delta_type = DELTA_ENTITY;
}
// take current state as baseline
@@ -424,7 +424,7 @@ void SV_CreateBaseline( void )
base->entityType = ENTITY_BEAM;
else base->entityType = ENTITY_NORMAL;
svgame.dllFuncs.pfnCreateBaseline( player, entnum, base, pEdict, playermodel, host.player_mins[0], host.player_maxs[0] );
svgame.dllFuncs.pfnCreateBaseline( delta_type, entnum, base, pEdict, playermodel, host.player_mins[0], host.player_maxs[0] );
sv.last_valid_baseline = entnum;
}
@@ -443,19 +443,19 @@ void SV_CreateBaseline( void )
if( entnum != 0 && entnum <= svs.maxclients )
{
player = true;
delta_type = DELTA_PLAYER;
}
else
{
if( !pEdict->v.modelindex )
continue; // invisible
player = false;
delta_type = DELTA_ENTITY;
}
// take current state as baseline
base = &svs.baselines[entnum];
MSG_WriteDeltaEntity( &nullstate, base, &sv.signon, true, player, 1.0f, 0 );
MSG_WriteDeltaEntity( &nullstate, base, &sv.signon, true, delta_type, 1.0f, 0 );
}
MSG_WriteUBitLong( &sv.signon, LAST_EDICT, MAX_ENTITY_BITS ); // end of baselines
@@ -464,7 +464,7 @@ void SV_CreateBaseline( void )
for( entnum = 0; entnum < sv.num_instanced; entnum++ )
{
base = &sv.instanced[entnum].baseline;
MSG_WriteDeltaEntity( &nullstate, base, &sv.signon, true, false, 1.0f, 0 );
MSG_WriteDeltaEntity( &nullstate, base, &sv.signon, true, DELTA_ENTITY, 1.0f, 0 );
}
}
@@ -522,6 +522,8 @@ void SV_ActivateServer( int runPhysics )
svgame.globals->time = sv.time;
svgame.dllFuncs.pfnServerActivate( svgame.edicts, svgame.numEntities, svs.maxclients );
SV_SetStringArrayMode( true );
// parse user-specified resources
SV_CreateGenericResources();
@@ -624,7 +626,7 @@ void SV_DeactivateServer( void )
SV_ClearPhysEnts ();
Mem_EmptyPool( svgame.stringspool );
SV_EmptyStringPool();
for( i = 0; i < svs.maxclients; i++ )
{
@@ -681,6 +683,7 @@ void SV_ShutdownGame( void )
SV_FinalMessage( "", true );
S_StopBackgroundTrack();
CL_StopPlayback(); // stop demo too
if( GameState->newGame )
{
@@ -735,7 +738,7 @@ void SV_SetupClients( void )
svs.clients = Z_Realloc( svs.clients, sizeof( sv_client_t ) * svs.maxclients );
svs.num_client_entities = svs.maxclients * SV_UPDATE_BACKUP * NUM_PACKET_ENTITIES;
svs.packet_entities = Z_Realloc( svs.packet_entities, sizeof( entity_state_t ) * svs.num_client_entities );
Con_DPrintf( "%s alloced by server packet entities\n", Q_memprint( sizeof( entity_state_t ) * svs.num_client_entities ));
Con_Reportf( "%s alloced by server packet entities\n", Q_memprint( sizeof( entity_state_t ) * svs.num_client_entities ));
// init network stuff
NET_Config(( svs.maxclients > 1 ));
@@ -793,6 +796,7 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
MSG_Init( &sv.spec_datagram, "Spectator Datagram", sv.spectator_buf, sizeof( sv.spectator_buf ));
// clearing all the baselines
memset( svs.static_entities, 0, sizeof( entity_state_t ) * MAX_STATIC_ENTITIES );
memset( svs.baselines, 0, sizeof( entity_state_t ) * GI->max_edicts );
// make cvars consistant
@@ -920,6 +924,7 @@ State machine exec new map
*/
void SV_ExecLoadLevel( void )
{
SV_SetStringArrayMode( false );
if( SV_SpawnServer( GameState->levelName, NULL, GameState->backgroundMap ))
{
SV_SpawnEntities( GameState->levelName );

View File

@@ -92,6 +92,7 @@ CVAR_DEFINE_AUTO( sv_skyvec_x, "0", FCVAR_MOVEVARS|FCVAR_UNLOGGED, "skylight dir
CVAR_DEFINE_AUTO( sv_skyvec_y, "0", FCVAR_MOVEVARS|FCVAR_UNLOGGED, "skylight direction by y-axis" );
CVAR_DEFINE_AUTO( sv_skyvec_z, "0", FCVAR_MOVEVARS|FCVAR_UNLOGGED, "skylight direction by z-axis" );
CVAR_DEFINE_AUTO( sv_wateralpha, "1", FCVAR_MOVEVARS|FCVAR_UNLOGGED, "world surfaces water transparency factor. 1.0 - solid, 0.0 - fully transparent" );
CVAR_DEFINE_AUTO( sv_background_freeze, "1", FCVAR_ARCHIVE, "freeze player movement on background maps (e.g. to prevent falling)" );
CVAR_DEFINE_AUTO( showtriggers, "0", FCVAR_LATCH, "debug cvar shows triggers" );
CVAR_DEFINE_AUTO( sv_airmove, "1", FCVAR_SERVER, "obsolete, compatibility issues" );
CVAR_DEFINE_AUTO( sv_version, "", FCVAR_READ_ONLY, "engine version string" );
@@ -158,7 +159,7 @@ void SV_UpdateMovevars( qboolean initialize )
if( sv_zmax.value < 256.0f ) Cvar_SetValue( "sv_zmax", 256.0f );
// clamp it right
if( host.features & ENGINE_WRITE_LARGE_COORD )
if( FBitSet( host.features, ENGINE_WRITE_LARGE_COORD ))
{
if( sv_zmax.value > 131070.0f )
Cvar_SetValue( "sv_zmax", 131070.0f );
@@ -513,6 +514,9 @@ void SV_PrepWorldFrame( void )
ClearBits( ent->v.effects, EF_MUZZLEFLASH|EF_NOINTERP );
}
if( svgame.physFuncs.pfnPrepWorldFrame != NULL )
svgame.physFuncs.pfnPrepWorldFrame();
}
/*
@@ -600,7 +604,7 @@ void Host_ServerFrame( void )
// if server is not active, do nothing
if( !svs.initialized ) return;
if( sv.simulating || sv.state != ss_active )
if( sv_fps.value != 0.0f && ( sv.simulating || sv.state != ss_active ))
sv.time_residual += host.frametime;
if( sv_fps.value == 0.0f )
@@ -649,9 +653,8 @@ void Master_Add( void )
NET_Config( true ); // allow remote
if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ))
MsgDev( D_INFO, "Can't resolve adr: %s\n", MASTERSERVER_ADR );
NET_SendPacket( NS_SERVER, 2, "q\xFF", adr );
Con_Printf( "can't resolve adr: %s\n", MASTERSERVER_ADR );
else NET_SendPacket( NS_SERVER, 2, "q\xFF", adr );
}
/*
@@ -693,9 +696,8 @@ void Master_Shutdown( void )
NET_Config( true ); // allow remote
if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ))
MsgDev( D_INFO, "Can't resolve addr: %s\n", MASTERSERVER_ADR );
NET_SendPacket( NS_SERVER, 2, "\x62\x0A", adr );
Con_Printf( "can't resolve addr: %s\n", MASTERSERVER_ADR );
else NET_SendPacket( NS_SERVER, 2, "\x62\x0A", adr );
}
/*
@@ -848,6 +850,7 @@ void SV_Init( void )
Cvar_RegisterVariable (&violence_hgibs);
Cvar_RegisterVariable (&mp_logecho);
Cvar_RegisterVariable (&mp_logfile);
Cvar_RegisterVariable (&sv_background_freeze);
// when we in developer-mode automatically turn cheats on
if( host_developer.value ) Cvar_SetValue( "sv_cheats", 1.0f );
@@ -856,6 +859,7 @@ void SV_Init( void )
Q_snprintf( versionString, sizeof( versionString ), "%s: %s-%s(%s-%s),%i,%i",
XASH_ENGINE_NAME, XASH_VERSION, Q_buildcommit(), Q_buildos(), Q_buildarch(), PROTOCOL_VERSION, Q_buildnum() );
Cvar_FullSet( "sv_version", versionString, FCVAR_READ_ONLY );
SV_ClearGameState (); // delete all temporary *.hl files

View File

@@ -74,8 +74,8 @@ realcheck:
stop[2] = start[2] - 2.0f * svgame.movevars.stepsize;
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_MoveNoEnts( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent );
else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, monsterClip );
trace = SV_MoveNoEnts( start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent );
else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, monsterClip );
if( trace.fraction == 1.0f )
return false;
@@ -91,8 +91,8 @@ realcheck:
start[1] = stop[1] = y ? maxs[1] : mins[1];
if( iMode == WALKMOVE_WORLDONLY )
trace = SV_MoveNoEnts( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent );
else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, monsterClip );
trace = SV_MoveNoEnts( start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent );
else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, monsterClip );
if( trace.fraction != 1.0f && trace.endpos[2] > bottom )
bottom = trace.endpos[2];

View File

@@ -782,6 +782,7 @@ Does not change the entities velocity at all
trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apush, int *blocked, float flDamage )
{
trace_t trace;
qboolean monsterBlock;
qboolean monsterClip;
int type;
vec3_t end;
@@ -814,11 +815,15 @@ trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apush, int
SV_LinkEdict( ent, true );
if( ent->v.movetype == MOVETYPE_WALK || ent->v.movetype == MOVETYPE_STEP || ent->v.movetype == MOVETYPE_PUSHSTEP )
monsterBlock = true;
else monsterBlock = false;
if( blocked )
{
// more accuracy blocking code
if( flDamage <= 0.0f )
*blocked = !VectorCompare( ent->v.origin, end ); // can't move full distance
if( monsterBlock )
*blocked = !VectorCompareEpsilon( ent->v.origin, end, ON_EPSILON ); // can't move full distance
else *blocked = true;
}
@@ -866,9 +871,8 @@ static qboolean SV_CanBlock( edict_t *ent )
if( ent->v.solid == SOLID_NOT || ent->v.solid == SOLID_TRIGGER )
{
// clear bounds for deadbody
ent->v.mins[0] = ent->v.mins[1] = 0.0f;
ent->v.maxs[0] = ent->v.maxs[1] = 0.0f;
ent->v.maxs[2] = ent->v.mins[2];
ent->v.mins[0] = ent->v.mins[1] = 0;
VectorCopy( ent->v.mins, ent->v.maxs );
return false;
}
@@ -938,7 +942,7 @@ static edict_t *SV_PushMove( edict_t *pusher, float movetime )
if( block ) continue;
// if the entity is standing on the pusher, it will definately be moved
if( !(( check->v.flags & FL_ONGROUND ) && check->v.groundentity == pusher ))
if( !( FBitSet( check->v.flags, FL_ONGROUND ) && check->v.groundentity == pusher ))
{
if( check->v.absmin[0] >= maxs[0]
|| check->v.absmin[1] >= maxs[1]
@@ -1945,7 +1949,7 @@ static char **pfnGetFilesList( const char *pattern, int *numFiles, int gamediron
static void *pfnMem_Alloc( size_t cb, const char *filename, const int fileline )
{
return _Mem_Alloc( svgame.mempool, cb, filename, fileline );
return _Mem_Alloc( svgame.mempool, cb, true, filename, fileline );
}
static void pfnMem_Free( void *mem, const char *filename, const int fileline )
@@ -1981,7 +1985,7 @@ const byte *pfnLoadImagePixels( const char *filename, int *width, int *height )
if( !pic ) return NULL;
buffer = Mem_Alloc( svgame.mempool, pic->size );
buffer = Mem_Malloc( svgame.mempool, pic->size );
if( buffer ) memcpy( buffer, pic->buffer, pic->size );
if( width ) *width = pic->width;
if( height ) *height = pic->height;
@@ -2029,7 +2033,7 @@ static server_physics_api_t gPhysicsAPI =
pfnPointContents,
SV_MoveNormal,
SV_MoveNoEnts,
SV_BoxInPVS,
(void*)SV_BoxInPVS,
pfnWriteBytes,
Mod_CheckLump,
Mod_ReadLump,
@@ -2055,7 +2059,7 @@ qboolean SV_InitPhysicsAPI( void )
{
if( pPhysIface( SV_PHYSICS_INTERFACE_VERSION, &gPhysicsAPI, &svgame.physFuncs ))
{
MsgDev( D_REPORT, "SV_LoadProgs: ^2initailized extended PhysicAPI ^7ver. %i\n", SV_PHYSICS_INTERFACE_VERSION );
Con_Reportf( "SV_LoadProgs: ^2initailized extended PhysicAPI ^7ver. %i\n", SV_PHYSICS_INTERFACE_VERSION );
if( svgame.physFuncs.SV_CheckFeatures != NULL )
{

View File

@@ -32,6 +32,9 @@ void SV_ClearPhysEnts( void )
qboolean SV_PlayerIsFrozen( edict_t *pClient )
{
if( sv_background_freeze.value && sv.background )
return true;
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
return false;
@@ -344,7 +347,7 @@ static void pfnParticle( const float *origin, int color, float life, int zpos, i
if( !origin )
{
MsgDev( D_ERROR, "SV_StartParticle: NULL origin. Ignored\n" );
Con_Reportf( S_ERROR "SV_StartParticle: NULL origin. Ignored\n" );
return;
}
@@ -375,10 +378,7 @@ static void pfnStuckTouch( int hitent, pmtrace_t *tr )
}
if( svgame.pmove->numtouch >= MAX_PHYSENTS )
{
MsgDev( D_ERROR, "PM_StuckTouch: MAX_TOUCHENTS limit exceeded\n" );
return;
}
VectorCopy( svgame.pmove->velocity, tr->deltavelocity );
tr->ent = hitent;
@@ -590,7 +590,7 @@ void SV_InitClientMove( void )
for( i = 0; i < MAX_MAP_HULLS; i++ )
{
if( svgame.dllFuncs.pfnGetHullBounds( i, host.player_mins[i], host.player_maxs[i] ))
MsgDev( D_NOTE, "SV: hull%i, player_mins: %g %g %g, player_maxs: %g %g %g\n", i,
Con_Reportf( "SV: hull%i, player_mins: %g %g %g, player_maxs: %g %g %g\n", i,
host.player_mins[i][0], host.player_mins[i][1], host.player_mins[i][2],
host.player_maxs[i][0], host.player_maxs[i][1], host.player_maxs[i][2] );
}

View File

@@ -30,7 +30,7 @@ half-life implementation of saverestore system
#define SAVEFILE_HEADER (('V'<<24)+('L'<<16)+('A'<<8)+'V') // little-endian "VALV"
#define SAVEGAME_HEADER (('V'<<24)+('A'<<16)+('S'<<8)+'J') // little-endian "JSAV"
#define SAVEGAME_VERSION 0x0071 // Version 0.71 GoldSrc compatible
#define CLIENT_SAVEGAME_VERSION 0x0065 // Version 0.65
#define CLIENT_SAVEGAME_VERSION 0x0067 // Version 0.67
#define SAVE_HEAPSIZE 0x400000 // reserve 4Mb for now
#define SAVE_HASHSTRINGS 0xFFF // 4095 unique strings
@@ -160,19 +160,40 @@ static TYPEDESCRIPTION gDecalEntry[] =
static TYPEDESCRIPTION gStaticEntry[] =
{
DEFINE_ARRAY( sv_static_entity_t, model, FIELD_CHARACTER, 64 ),
DEFINE_FIELD( sv_static_entity_t, origin, FIELD_VECTOR ),
DEFINE_FIELD( sv_static_entity_t, angles, FIELD_VECTOR ),
DEFINE_FIELD( sv_static_entity_t, sequence, FIELD_SHORT ),
DEFINE_FIELD( sv_static_entity_t, frame, FIELD_SHORT ),
DEFINE_FIELD( sv_static_entity_t, colormap, FIELD_SHORT ),
DEFINE_FIELD( sv_static_entity_t, skin, FIELD_CHARACTER ),
DEFINE_FIELD( sv_static_entity_t, body, FIELD_CHARACTER ),
DEFINE_FIELD( sv_static_entity_t, scale, FIELD_FLOAT ),
DEFINE_FIELD( sv_static_entity_t, rendermode, FIELD_CHARACTER ),
DEFINE_FIELD( sv_static_entity_t, renderamt, FIELD_CHARACTER ),
DEFINE_ARRAY( sv_static_entity_t, rendercolor, FIELD_CHARACTER, sizeof( color24 )),
DEFINE_FIELD( sv_static_entity_t, renderfx, FIELD_CHARACTER ),
DEFINE_FIELD( entity_state_t, messagenum, FIELD_MODELNAME ), // HACKHACK: store model into messagenum
DEFINE_FIELD( entity_state_t, origin, FIELD_VECTOR ),
DEFINE_FIELD( entity_state_t, angles, FIELD_VECTOR ),
DEFINE_FIELD( entity_state_t, sequence, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, frame, FIELD_FLOAT ),
DEFINE_FIELD( entity_state_t, colormap, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, skin, FIELD_SHORT ),
DEFINE_FIELD( entity_state_t, body, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, scale, FIELD_FLOAT ),
DEFINE_FIELD( entity_state_t, effects, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, framerate, FIELD_FLOAT ),
DEFINE_FIELD( entity_state_t, mins, FIELD_VECTOR ),
DEFINE_FIELD( entity_state_t, maxs, FIELD_VECTOR ),
DEFINE_FIELD( entity_state_t, rendermode, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, renderamt, FIELD_FLOAT ),
DEFINE_ARRAY( entity_state_t, rendercolor, FIELD_CHARACTER, sizeof( color24 )),
DEFINE_FIELD( entity_state_t, renderfx, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, controller, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, blending, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, solid, FIELD_SHORT ),
DEFINE_FIELD( entity_state_t, animtime, FIELD_TIME ),
DEFINE_FIELD( entity_state_t, movetype, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, vuser1, FIELD_VECTOR ),
DEFINE_FIELD( entity_state_t, vuser2, FIELD_VECTOR ),
DEFINE_FIELD( entity_state_t, vuser3, FIELD_VECTOR ),
DEFINE_FIELD( entity_state_t, vuser4, FIELD_VECTOR ),
DEFINE_FIELD( entity_state_t, iuser1, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, iuser2, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, iuser3, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, iuser4, FIELD_INTEGER ),
DEFINE_FIELD( entity_state_t, fuser1, FIELD_FLOAT ),
DEFINE_FIELD( entity_state_t, fuser2, FIELD_FLOAT ),
DEFINE_FIELD( entity_state_t, fuser3, FIELD_FLOAT ),
DEFINE_FIELD( entity_state_t, fuser4, FIELD_FLOAT ),
};
static TYPEDESCRIPTION gSoundEntry[] =
@@ -266,7 +287,7 @@ static void InitEntityTable( SAVERESTOREDATA *pSaveData, int entityCount )
ENTITYTABLE *pTable;
int i;
pSaveData->pTable = Mem_Alloc( host.mempool, sizeof( ENTITYTABLE ) * entityCount );
pSaveData->pTable = Mem_Calloc( host.mempool, sizeof( ENTITYTABLE ) * entityCount );
pSaveData->tableCount = entityCount;
// setup entitytable
@@ -401,7 +422,7 @@ static int IsValidSave( void )
}
// ignore autosave during background
if( sv.background )
if( sv.background || UI_CreditsActive( ))
return 0;
if( svgame.physFuncs.SV_AllowSaveGame != NULL )
@@ -518,9 +539,6 @@ static qboolean SaveGetName( int lastnum, char *filename )
{
int a, b, c;
if( !COM_CheckString( filename ))
return false;
if( lastnum < 0 || lastnum > 999 )
return false;
@@ -604,8 +622,8 @@ static SAVERESTOREDATA *SaveInit( int size, int tokenCount )
{
SAVERESTOREDATA *pSaveData;
pSaveData = Mem_Alloc( host.mempool, sizeof( SAVERESTOREDATA ) + size );
pSaveData->pTokens = (char **)Mem_Alloc( host.mempool, tokenCount * sizeof( char* ));
pSaveData = Mem_Calloc( host.mempool, sizeof( SAVERESTOREDATA ) + size );
pSaveData->pTokens = (char **)Mem_Calloc( host.mempool, tokenCount * sizeof( char* ));
pSaveData->tokenCount = tokenCount;
pSaveData->pBaseData = (char *)(pSaveData + 1); // skip the save structure);
@@ -643,7 +661,7 @@ static void SaveClear( SAVERESTOREDATA *pSaveData )
/*
=============
SaveInit
SaveFinish
release global save-restore buffer
=============
@@ -1108,7 +1126,7 @@ static void SaveClientState( SAVERESTOREDATA *pSaveData, const char *level, int
memset( &header, 0, sizeof( header ));
// g-cont. add space for studiodecals if present
decalList = (decallist_t *)Z_Malloc( sizeof( decallist_t ) * MAX_RENDER_DECALS * 2 );
decalList = (decallist_t *)Z_Calloc( sizeof( decallist_t ) * MAX_RENDER_DECALS * 2 );
// initialize client header
header.decalCount = R_CreateDecalList( decalList );
@@ -1147,7 +1165,7 @@ static void SaveClientState( SAVERESTOREDATA *pSaveData, const char *level, int
// write client entities
for( i = 0; i < header.entityCount; i++ )
svgame.dllFuncs.pfnSaveWriteFields( pSaveData, "STATICENTITY", &sv.static_entities[i], gStaticEntry, ARRAYSIZE( gStaticEntry ));
svgame.dllFuncs.pfnSaveWriteFields( pSaveData, "STATICENTITY", &svs.static_entities[i], gStaticEntry, ARRAYSIZE( gStaticEntry ));
// write sounds
for( i = 0; i < header.soundCount; i++ )
@@ -1190,7 +1208,6 @@ static void LoadClientState( SAVERESTOREDATA *pSaveData, const char *level, qboo
int i, size, id, version;
sv_client_t *cl = svs.clients;
char name[MAX_QPATH];
sv_static_entity_t staticEntry;
soundlist_t soundEntry;
decallist_t decalEntry;
SAVE_CLIENT header;
@@ -1250,22 +1267,19 @@ static void LoadClientState( SAVERESTOREDATA *pSaveData, const char *level, qboo
// clear old entities
if( !adjacent )
{
memset( sv.static_entities, 0, sizeof( sv.static_entities ));
memset( svs.static_entities, 0, sizeof( entity_state_t ) * MAX_STATIC_ENTITIES );
sv.num_static_entities = 0;
}
// restore client entities
for( i = 0; i < header.entityCount; i++ )
{
svgame.dllFuncs.pfnSaveReadFields( pSaveData, "STATICENTITY", &staticEntry, gStaticEntry, ARRAYSIZE( gStaticEntry ));
id = sv.num_static_entities;
svgame.dllFuncs.pfnSaveReadFields( pSaveData, "STATICENTITY", &svs.static_entities[id], gStaticEntry, ARRAYSIZE( gStaticEntry ));
if( adjacent ) continue; // static entities won't loading from adjacent levels
if( i >= MAX_STATIC_ENTITIES )
continue; // silently overflowed
SV_CreateStaticEntity( &sv.signon, &staticEntry );
sv.static_entities[i] = staticEntry;
sv.num_static_entities++;
if( SV_CreateStaticEntity( &sv.signon, id ))
sv.num_static_entities++;
}
// restore sounds
@@ -1560,7 +1574,7 @@ static int LoadGameState( char const *level, qboolean changelevel )
if( pent != NULL )
{
if( svgame.dllFuncs.pfnRestore( pent, pSaveData, false ) < 0 )
if( svgame.dllFuncs.pfnRestore( pent, pSaveData, 0 ) < 0 )
{
SetBits( pent->v.flags, FL_KILLME );
pTable->pent = NULL;
@@ -1775,7 +1789,7 @@ static int CreateEntityTransitionList( SAVERESTOREDATA *pSaveData, int levelMask
}
else
{
Con_DPrintf( "Transferring %s (%d)\n", STRING( pTable->classname ), NUM_FOR_EDICT( pent ));
Con_Reportf( "Transferring %s (%d)\n", STRING( pTable->classname ), NUM_FOR_EDICT( pent ));
if( svgame.dllFuncs.pfnRestore( pent, pSaveData, 0 ) < 0 )
{
@@ -1787,7 +1801,7 @@ static int CreateEntityTransitionList( SAVERESTOREDATA *pSaveData, int levelMask
{
// this can happen during normal processing - PVS is just a guess,
// some map areas won't exist in the new map
Con_DPrintf( "Suppressing %s\n", STRING( pTable->classname ));
Con_Reportf( "Suppressing %s\n", STRING( pTable->classname ));
SetBits( pent->v.flags, FL_KILLME );
}
else
@@ -1999,6 +2013,9 @@ qboolean SV_LoadGame( const char *pPath )
if( Host_IsDedicated() )
return false;
if( UI_CreditsActive( ))
return false;
if( !COM_CheckString( pPath ))
return false;
@@ -2116,7 +2133,7 @@ used for reload game after player death
const char *SV_GetLatestSave( void )
{
static char savename[MAX_QPATH];
long newest = 0, ft;
int newest = 0, ft;
int i, found = 0;
search_t *t;
@@ -2224,14 +2241,14 @@ int SV_GetSaveComment( const char *savename, char *comment )
return 0;
}
pSaveData = (char *)Mem_Alloc( host.mempool, size );
pSaveData = (char *)Mem_Malloc( host.mempool, size );
FS_Read( f, pSaveData, size );
pData = pSaveData;
// allocate a table for the strings, and parse the table
if( tokenSize > 0 )
{
pTokenList = Mem_Alloc( host.mempool, tokenCount * sizeof( char* ));
pTokenList = Mem_Calloc( host.mempool, tokenCount * sizeof( char* ));
// make sure the token strings pointed to by the pToken hashtable.
for( i = 0; i < tokenCount; i++ )

View File

@@ -28,7 +28,8 @@ typedef struct moveclip_s
edict_t *passedict;
trace_t trace;
int type; // move type
int flags; // trace flags
qboolean ignoretrans;
qboolean monsterclip;
} moveclip_t;
/*
@@ -820,18 +821,18 @@ returns true if the entity is in solid currently
*/
qboolean SV_TestEntityPosition( edict_t *ent, edict_t *blocker )
{
trace_t trace;
qboolean monsterClip = FBitSet( ent->v.flags, FL_MONSTERCLIP ) ? true : false;
trace_t trace;
if( ent->v.flags & (FL_CLIENT|FL_FAKECLIENT))
if( FBitSet( ent->v.flags, FL_CLIENT|FL_FAKECLIENT ))
{
// to avoid falling through tracktrain update client mins\maxs here
if( ent->v.flags & FL_DUCKING )
if( FBitSet( ent->v.flags, FL_DUCKING ))
SV_SetMinMaxSize( ent, svgame.pmove->player_mins[1], svgame.pmove->player_maxs[1], true );
else SV_SetMinMaxSize( ent, svgame.pmove->player_mins[0], svgame.pmove->player_maxs[0], true );
}
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL|FMOVE_SIMPLEBOX, ent, monsterClip );
trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent, monsterClip );
if( SV_IsValidEdict( blocker ) && SV_IsValidEdict( trace.ent ))
{
@@ -839,6 +840,7 @@ qboolean SV_TestEntityPosition( edict_t *ent, edict_t *blocker )
return trace.startsolid;
return false;
}
return trace.startsolid;
}
@@ -1159,18 +1161,15 @@ static qboolean SV_ClipToEntity( edict_t *touch, moveclip_t *clip )
if( svgame.dllFuncs2.pfnShouldCollide )
{
if( !svgame.dllFuncs2.pfnShouldCollide( touch, clip->passedict ))
return true; // originally this was 'return' but is completely wrong!
return true;
}
// monsterclip filter (solid custom is a static or dynamic bodies)
if( touch->v.solid == SOLID_BSP || touch->v.solid == SOLID_CUSTOM )
{
if( FBitSet( touch->v.flags, FL_MONSTERCLIP ))
{
// func_monsterclip works only with monsters that have same flag!
if( !FBitSet( clip->flags, FMOVE_MONSTERCLIP ))
return true;
}
// func_monsterclip works only with monsters that have same flag!
if( FBitSet( touch->v.flags, FL_MONSTERCLIP ) && !clip->monsterclip )
return true;
}
else
{
@@ -1181,7 +1180,7 @@ static qboolean SV_ClipToEntity( edict_t *touch, moveclip_t *clip )
mod = SV_ModelHandle( touch->v.modelindex );
if( mod && mod->type == mod_brush && FBitSet( clip->flags, FMOVE_IGNORE_GLASS ))
if( mod && mod->type == mod_brush && clip->ignoretrans )
{
// we ignore brushes with rendermode != kRenderNormal and without FL_WORLDBRUSH set
if( touch->v.rendermode != kRenderNormal && !FBitSet( touch->v.flags, FL_WORLDBRUSH ))
@@ -1226,7 +1225,7 @@ static qboolean SV_ClipToEntity( edict_t *touch, moveclip_t *clip )
if( touch->v.solid == SOLID_CUSTOM )
SV_CustomClipMoveToEntity( touch, clip->start, clip->mins, clip->maxs, clip->end, &trace );
else if( touch->v.flags & FL_MONSTER )
else if( FBitSet( touch->v.flags, FL_MONSTER ))
SV_ClipMoveToEntity( touch, clip->start, clip->mins2, clip->maxs2, clip->end, &trace );
else SV_ClipMoveToEntity( touch, clip->start, clip->mins, clip->maxs, clip->end, &trace );
@@ -1363,13 +1362,14 @@ trace_t SV_Move( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end,
clip.start = start;
clip.end = trace_endpos;
clip.type = (type & 0xFF);
clip.flags = (type & 0xFF00);
clip.ignoretrans = type >> 8;
clip.monsterclip = false;
clip.passedict = (e) ? e : EDICT_NUM( 0 );
clip.mins = mins;
clip.maxs = maxs;
if( monsterclip && !FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
SetBits( clip.flags, FMOVE_MONSTERCLIP );
clip.monsterclip = true;
if( clip.type == MOVE_MISSILE )
{
@@ -1422,7 +1422,8 @@ trace_t SV_MoveNoEnts( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_
clip.start = start;
clip.end = trace_endpos;
clip.type = (type & 0xFF);
clip.flags = (type & 0xFF00);
clip.ignoretrans = type >> 8;
clip.monsterclip = false;
clip.passedict = (e) ? e : EDICT_NUM( 0 );
clip.mins = mins;
clip.maxs = maxs;