mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-09 13:51:45 +08:00
Merge branch 'master' into resource
This commit is contained in:
@@ -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
|
||||
//
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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( ));
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -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] );
|
||||
}
|
||||
|
||||
@@ -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++ )
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user