28 Feb 2018

This commit is contained in:
g-cont 2018-02-28 00:00:00 +03:00 committed by Alibek Omarov
parent 64609ae475
commit 6441d5bfa2
25 changed files with 580 additions and 518 deletions

View File

@ -248,7 +248,7 @@ typedef struct render_interface_s
// handle decals which hit mod_studio or mod_sprite
void (*R_StudioDecalShoot)( int decalTexture, struct cl_entity_s *ent, const float *start, const float *pos, int flags, modelstate_t *state );
// prepare studio decals for save
int (*R_CreateStudioDecalList)( decallist_t *pList, int count, qboolean changelevel );
int (*R_CreateStudioDecalList)( decallist_t *pList, int count );
// clear decals by engine request (e.g. for demo recording or vid_restart)
void (*R_ClearStudioDecals)( void );
// grab r_speeds message

View File

@ -839,7 +839,7 @@ int pfnCheckGameDll( void )
{
void *hInst;
if( SV_Active( )) return true;
if( SV_Initialized( )) return true;
if(( hInst = Com_LoadLibrary( GI->game_dll, true )) != NULL )
{

View File

@ -2353,7 +2353,6 @@ void CL_InitLocal( void )
bottomcolor = Cvar_Get( "bottomcolor", "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "player bottom color" );
cl_lw = Cvar_Get( "cl_lw", "1", FCVAR_ARCHIVE|FCVAR_USERINFO, "enable client weapon predicting" );
Cvar_Get( "cl_lc", "1", FCVAR_ARCHIVE|FCVAR_USERINFO, "enable lag compensation" );
Cvar_Get( "msg", "0", FCVAR_USERINFO|FCVAR_ARCHIVE, "message filter for server notifications" );
Cvar_Get( "password", "", FCVAR_USERINFO, "server password" );
Cvar_Get( "team", "", FCVAR_USERINFO, "player team" );
Cvar_Get( "skin", "", FCVAR_USERINFO, "player skin" );
@ -2388,6 +2387,7 @@ void CL_InitLocal( void )
Cmd_AddCommand ("drop", NULL, "drop current/specified item or weapon" );
Cmd_AddCommand ("gametitle", NULL, "show game logo" );
Cmd_AddCommand ("god", NULL, "enable godmode" );
Cmd_AddCommand ("fly", NULL, "enable fly mode" );
Cmd_AddCommand ("fov", NULL, "set client field of view" );
Cmd_AddCommand ("log", NULL, "logging server events" );

View File

@ -737,46 +737,67 @@ CL_ParseServerData
*/
void CL_ParseServerData( sizebuf_t *msg )
{
string gamefolder;
int i, servercount, checksum;
int playernum, maxclients;
char gamefolder[MAX_QPATH];
qboolean background;
int i;
MsgDev( D_NOTE, "Serverdata packet received.\n" );
cls.demowaiting = false; // server is changed
clgame.load_sequence++; // now all hud sprites are invalid
// wipe the client_t struct
if( !cls.changelevel && !cls.changedemo )
CL_ClearState ();
cls.state = ca_connected;
clgame.load_sequence++; // now all hud sprites are invalid
cls.signon = 0; // reset signon state
// Re-init hud video, especially if we changed game directories
clgame.dllFuncs.pfnVidInit();
// parse protocol version number
i = MSG_ReadLong( msg );
cls.serverProtocol = i;
cls.serverProtocol = MSG_ReadLong( msg );
if( i != PROTOCOL_VERSION )
Host_Error( "Server use invalid protocol (%i should be %i)\n", i, PROTOCOL_VERSION );
if( cls.serverProtocol != PROTOCOL_VERSION )
Host_Error( "Server use invalid protocol (%i should be %i)\n", cls.serverProtocol, PROTOCOL_VERSION );
cl.servercount = MSG_ReadLong( msg );
cl.checksum = MSG_ReadLong( msg );
cl.playernum = MSG_ReadByte( msg );
cl.maxclients = MSG_ReadByte( msg );
servercount = MSG_ReadLong( msg );
checksum = MSG_ReadLong( msg );
playernum = MSG_ReadByte( msg );
maxclients = MSG_ReadByte( msg );
clgame.maxEntities = MSG_ReadWord( msg );
clgame.maxEntities = bound( 600, clgame.maxEntities, MAX_EDICTS );
clgame.maxModels = MSG_ReadWord( msg );
Q_strncpy( clgame.mapname, MSG_ReadString( msg ), MAX_STRING );
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), MAX_STRING );
background = MSG_ReadOneBit( msg );
cls.changelevel = MSG_ReadOneBit( msg );
Q_strncpy( gamefolder, MSG_ReadString( msg ), MAX_STRING );
host.features = (uint)MSG_ReadLong( msg );
if( clgame.maxModels > MAX_MODELS )
MsgDev( D_WARN, "server model limit is above client model limit %i > %i\n", clgame.maxModels, MAX_MODELS );
if( cls.changelevel && cls.demoplayback )
cls.changedemo = true;
// wipe the client_t struct
CL_ClearState ();
// fill the client struct
cl.servercount = servercount;
cl.checksum = checksum;
cl.playernum = playernum;
cl.maxclients = maxclients;
// set the background state
if( cls.demoplayback && ( cls.demonum != -1 ))
{
host.mouse_visible = false;
cl.background = true;
}
else cl.background = background;
if( cls.changedemo )
SCR_BeginLoadingPlaque( cl.background );
if( Con_FixedFont( ))
{
// seperate the printfs so the server message can have a color
@ -805,15 +826,6 @@ void CL_ParseServerData( sizebuf_t *msg )
}
else Cvar_Reset( "r_decals" );
// set the background state
if( cls.demoplayback && ( cls.demonum != -1 ))
{
// re-init mouse
host.mouse_visible = false;
cl.background = true;
}
else cl.background = background;
if( cl.background ) // tell the game parts about background state
Cvar_FullSet( "cl_background", "1", FCVAR_READ_ONLY );
else Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
@ -829,13 +841,11 @@ void CL_ParseServerData( sizebuf_t *msg )
else if( !cls.demoplayback )
Key_SetKeyDest( key_menu );
cl.viewentity = cl.playernum + 1; // always keep viewent an actual
// will be changed later
cl.viewentity = cl.playernum + 1;
gameui.globals->maxClients = cl.maxclients;
Q_strncpy( gameui.globals->maptitle, clgame.maptitle, sizeof( gameui.globals->maptitle ));
if( !cls.changelevel && !cls.changedemo )
CL_InitEdicts (); // re-arrange edicts
CL_InitEdicts (); // re-arrange edicts
// get splash name
if( cls.demoplayback && ( cls.demonum != -1 ))
@ -2204,14 +2214,13 @@ ACTION MESSAGES
=====================
CL_ParseServerMessage
INTERNAL RESOURCE
dispatch messages
=====================
*/
void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
{
char *s;
int i, cmd, param1, param2;
size_t bufStart, playerbytes;
int cmd, param1, param2;
cls_message_debug.parsing = true; // begin parsing
starting_count = MSG_GetNumBytesRead( msg ); // updates each frame
@ -2304,18 +2313,10 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
CL_ParseServerTime( msg );
break;
case svc_print:
i = MSG_ReadByte( msg );
MsgDev( D_INFO, "^5%s", MSG_ReadString( msg ));
if( i == PRINT_CHAT )
{
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
S_StartLocalSound( "misc/talk.wav", VOL_NORM, false );
else S_StartLocalSound( "common/menu2.wav", VOL_NORM, false );
}
break;
case svc_stufftext:
s = MSG_ReadString( msg );
Cbuf_AddText( s );
Cbuf_AddText( MSG_ReadString( msg ));
break;
case svc_setangle:
CL_ParseSetAngle( msg );

View File

@ -1138,7 +1138,7 @@ static int DecalDepthCompare( const void *a, const void *b )
// Input : *pList -
// Output : int
//-----------------------------------------------------------------------------
int R_CreateDecalList( decallist_t *pList, qboolean changelevel )
int R_CreateDecalList( decallist_t *pList )
{
int total = 0;
int i, depth;
@ -1151,7 +1151,7 @@ int R_CreateDecalList( decallist_t *pList, qboolean changelevel )
decal_t *pdecals;
// decal is in use and is not a custom decal
if( decal->psurface == NULL || ( decal->flags & FDECAL_DONTSAVE ))
if( decal->psurface == NULL || FBitSet( decal->flags, FDECAL_DONTSAVE ))
continue;
// compute depth
@ -1177,7 +1177,7 @@ int R_CreateDecalList( decallist_t *pList, qboolean changelevel )
if( clgame.drawFuncs.R_CreateStudioDecalList )
{
total += clgame.drawFuncs.R_CreateStudioDecalList( pList, total, changelevel );
total += clgame.drawFuncs.R_CreateStudioDecalList( pList, total );
}
}

View File

@ -344,16 +344,10 @@ COM_AddAppDirectoryToSearchPath
*/
void COM_AddAppDirectoryToSearchPath( const char *pszBaseDir, const char *appName )
{
string dir;
if( !pszBaseDir || !appName )
{
MsgDev( D_ERROR, "COM_AddDirectorySearchPath: bad directory or appname\n" );
if( !COM_CheckString( pszBaseDir ))
return;
}
Q_snprintf( dir, sizeof( dir ), "%s/%s", pszBaseDir, appName );
FS_AddGameDirectory( dir, FS_GAMEDIR_PATH );
FS_AddGameDirectory( pszBaseDir, FS_GAMEDIR_PATH );
}
/*

View File

@ -289,15 +289,6 @@ typedef enum
RD_PACKET
} rdtype_t;
// game print level
typedef enum
{
PRINT_LOW, // pickup messages
PRINT_MEDIUM, // death messages
PRINT_HIGH, // critical messages
PRINT_CHAT, // chat messages
} messagelevel_t;
#include "net_ws.h"
typedef struct host_redirect_s
@ -766,7 +757,7 @@ float pfnTime( void );
*/
#define Z_Malloc( size ) Mem_Alloc( host.mempool, size )
#define Z_Realloc( ptr, size ) Mem_Realloc( host.mempool, ptr, size )
#define Z_Free( ptr ) if( ptr ) Mem_Free( ptr )
#define Z_Free( ptr ) if( ptr != NULL ) Mem_Free( ptr )
//
// crclib.c
@ -853,9 +844,7 @@ qboolean CL_IsInConsole( void );
qboolean CL_IsThirdPerson( void );
qboolean CL_IsIntermission( void );
qboolean CL_Initialized( void );
qboolean CL_IsTimeDemo( void );
char *CL_Userinfo( void );
float CL_GetLerpFrac( void );
void CL_CharEvent( int key );
qboolean CL_DisableVisibility( void );
int CL_PointContents( const vec3_t point );
@ -868,15 +857,13 @@ struct pmtrace_s *PM_TraceLine( float *start, float *end, int flags, int usehull
void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch );
void SV_StartMusic( const char *curtrack, const char *looptrack, long position );
void SV_CreateDecal( struct sizebuf_s *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
void SV_CreateStudioDecal( struct sizebuf_s *msg, const float *origin, const float *start, int decalIndex, int entityIndex, int modelIndex,
int flags, struct modelstate_s *state );
void SV_CreateStudioDecal( struct sizebuf_s *bf, const float *v0, const float *v1, int decal, int ent, int model, int flags, struct modelstate_s *s );
void Log_Printf( const char *fmt, ... );
struct sizebuf_s *SV_GetReliableDatagram( void );
void SV_BroadcastCommand( const char *fmt, ... );
void SV_ChangeLevel( qboolean loadfromsavedgame, const char *mapname, const char *start );
qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
void SV_BroadcastPrintf( struct sv_client_s *ignore, int level, char *fmt, ... );
int R_CreateDecalList( struct decallist_s *pList, qboolean changelevel );
void SV_BroadcastPrintf( struct sv_client_s *ignore, char *fmt, ... );
int R_CreateDecalList( struct decallist_s *pList );
void R_DecalRemoveAll( int texture );
void R_ClearAllDecals( void );
void R_ClearStaticEntities( void );
@ -884,8 +871,6 @@ qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *posi
struct cl_entity_s *CL_GetEntityByIndex( int index );
struct player_info_s *CL_GetPlayerInfo( int playerIndex );
void CL_ServerCommand( qboolean reliable, char *fmt, ... );
void SV_ActivateServer( void );
void SV_DeactivateServer( void );
const char *CL_MsgInfo( int cmd );
void SV_DrawDebugTriangles( void );
void SV_DrawOrthoTriangles( void );
@ -895,19 +880,22 @@ void CL_ExtraUpdate( void );
int CL_GetMaxClients( void );
int SV_GetMaxClients( void );
qboolean CL_IsRecordDemo( void );
qboolean CL_IsTimeDemo( void );
qboolean CL_IsPlaybackDemo( void );
qboolean CL_IsBackgroundDemo( void );
qboolean CL_IsBackgroundMap( void );
qboolean SV_Initialized( void );
qboolean CL_LoadProgs( const char *name );
qboolean SV_GetComment( const char *savename, char *comment );
qboolean SV_NewGame( const char *mapName, qboolean loadGame );
void SV_ClipPMoveToEntity( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
void CL_ClipPMoveToEntity( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
void CL_Particle( const vec3_t origin, int color, float life, int zpos, int zvel ); // debug thing
void SV_LevelInit( const char *pMapName, char const *pOldLevel, char const *pLandmarkName, qboolean loadGame );
qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean background );
void SV_SysError( const char *error_string );
qboolean SV_LoadGame( const char *pName );
void SV_ShutdownGame( void );
void SV_ExecLoadLevel( void );
void SV_ExecLoadGame( void );
void SV_ExecChangeLevel( void );
void SV_ClearSaveDir( void );
void SV_InitGameProgs( void );
void SV_FreeGameProgs( void );

View File

@ -79,12 +79,12 @@ static qboolean Cvar_UpdateInfo( convar_t *var, const char *value, qboolean noti
if( FBitSet( var->flags, FCVAR_PROTECTED ))
{
Log_Printf( "Server cvar \"%s\" = \"%s\"\n", var->name, "***PROTECTED***" );
SV_BroadcastPrintf( NULL, PRINT_HIGH, "\"%s\" changed to \"%s\"\n", var->name, "***PROTECTED***" );
SV_BroadcastPrintf( NULL, "\"%s\" changed to \"%s\"\n", var->name, "***PROTECTED***" );
}
else
{
Log_Printf( "Server cvar \"%s\" = \"%s\"\n", var->name, value );
SV_BroadcastPrintf( NULL, PRINT_HIGH, "\"%s\" changed to \"%s\"\n", var->name, value );
SV_BroadcastPrintf( NULL, "\"%s\" changed to \"%s\"\n", var->name, value );
}
}
}

View File

@ -59,7 +59,7 @@ int Host_CompareFileTime( long ft1, long ft2 )
void Host_ShutdownServer( void )
{
if( !SV_Active( )) return;
if( !SV_Initialized( )) return;
Q_strncpy( host.finalmsg, "Server was killed", MAX_STRING );
SV_Shutdown( false );
}
@ -106,7 +106,7 @@ void Host_EndGame( qboolean abort, const char *message, ... )
MsgDev( D_INFO, "Host_EndGame: %s\n", string );
if( SV_Active( ))
if( SV_Initialized( ))
{
Q_snprintf( host.finalmsg, sizeof( host.finalmsg ), "Host_EndGame: %s", string );
SV_Shutdown( false );
@ -442,7 +442,7 @@ void Host_RestartDecals( void )
// g-cont. add space for studiodecals if present
host.decalList = (decallist_t *)Z_Malloc( sizeof( decallist_t ) * MAX_RENDER_DECALS * 2 );
host.numdecals = R_CreateDecalList( host.decalList, false );
host.numdecals = R_CreateDecalList( host.decalList );
// remove decals from map
R_ClearAllDecals();

View File

@ -14,29 +14,20 @@ GNU General Public License for more details.
*/
#include "common.h"
#include "netchan.h"
#include "protocol.h"
#include "mod_local.h"
#include "mathlib.h"
#include "input.h"
#include "features.h"
#include "render_api.h" // decallist_t
void COM_InitHostState( void )
{
memset( GameState, 0, sizeof( game_status_t ));
GameState->curstate = STATE_RUNFRAME;
GameState->nextstate = STATE_RUNFRAME;
}
static void HostState_SetState( host_state_t newState, qboolean clearNext )
static void Host_SetState( host_state_t newState, qboolean clearNext )
{
if( clearNext )
GameState->nextstate = newState;
GameState->curstate = newState;
}
static void HostState_SetNextState( host_state_t nextState )
static void Host_SetNextState( host_state_t nextState )
{
ASSERT( GameState->curstate == STATE_RUNFRAME );
GameState->nextstate = nextState;
@ -44,8 +35,11 @@ static void HostState_SetNextState( host_state_t nextState )
void COM_NewGame( char const *pMapName )
{
if( GameState->nextstate != STATE_RUNFRAME )
return;
Q_strncpy( GameState->levelName, pMapName, sizeof( GameState->levelName ));
HostState_SetNextState( STATE_LOAD_LEVEL );
Host_SetNextState( STATE_LOAD_LEVEL );
GameState->backgroundMap = false;
GameState->landmarkName[0] = 0;
@ -54,8 +48,11 @@ void COM_NewGame( char const *pMapName )
void COM_LoadLevel( char const *pMapName, qboolean background )
{
if( GameState->nextstate != STATE_RUNFRAME )
return;
Q_strncpy( GameState->levelName, pMapName, sizeof( GameState->levelName ));
HostState_SetNextState( STATE_LOAD_LEVEL );
Host_SetNextState( STATE_LOAD_LEVEL );
GameState->backgroundMap = background;
GameState->landmarkName[0] = 0;
@ -64,8 +61,11 @@ void COM_LoadLevel( char const *pMapName, qboolean background )
void COM_LoadGame( char const *pMapName )
{
if( GameState->nextstate != STATE_RUNFRAME )
return;
Q_strncpy( GameState->levelName, pMapName, sizeof( GameState->levelName ));
HostState_SetNextState( STATE_LOAD_GAME );
Host_SetNextState( STATE_LOAD_GAME );
GameState->backgroundMap = false;
GameState->newGame = false;
GameState->loadGame = true;
@ -73,6 +73,9 @@ void COM_LoadGame( char const *pMapName )
void COM_ChangeLevel( char const *pNewLevel, char const *pLandmarkName )
{
if( GameState->nextstate != STATE_RUNFRAME )
return;
Q_strncpy( GameState->levelName, pNewLevel, sizeof( GameState->levelName ));
if( COM_CheckString( pLandmarkName ))
@ -86,68 +89,27 @@ void COM_ChangeLevel( char const *pNewLevel, char const *pLandmarkName )
GameState->loadGame = false;
}
HostState_SetNextState( STATE_CHANGELEVEL );
Host_SetNextState( STATE_CHANGELEVEL );
GameState->newGame = false;
}
void HostState_LoadLevel( void )
void Host_ShutdownGame( void )
{
if( SV_SpawnServer( GameState->levelName, NULL, GameState->backgroundMap ))
{
SV_LevelInit( GameState->levelName, NULL, NULL, false );
SV_ActivateServer ();
}
HostState_SetState( STATE_RUNFRAME, true );
}
void HostState_LoadGame( void )
{
if( SV_SpawnServer( GameState->levelName, NULL, false ))
{
SV_LevelInit( GameState->levelName, NULL, NULL, true );
SV_ActivateServer ();
}
HostState_SetState( STATE_RUNFRAME, true );
}
void HostState_ChangeLevel( void )
{
SV_ChangeLevel( GameState->loadGame, GameState->levelName, GameState->landmarkName );
HostState_SetState( STATE_RUNFRAME, true );
}
void HostState_ShutdownGame( void )
{
if( !GameState->loadGame )
SV_ClearSaveDir();
S_StopBackgroundTrack();
if( GameState->newGame )
{
Host_EndGame( false, DEFAULT_ENDGAME_MESSAGE );
}
else
{
S_StopAllSounds( true );
SV_DeactivateServer();
}
SV_ShutdownGame();
switch( GameState->nextstate )
{
case STATE_LOAD_GAME:
case STATE_LOAD_LEVEL:
HostState_SetState( GameState->nextstate, true );
Host_SetState( GameState->nextstate, true );
break;
default:
HostState_SetState( STATE_RUNFRAME, true );
Host_SetState( STATE_RUNFRAME, true );
break;
}
}
void HostState_Run( float time )
void Host_RunFrame( float time )
{
// engine main frame
Host_Frame( time );
@ -161,14 +123,14 @@ void HostState_Run( float time )
SCR_BeginLoadingPlaque( GameState->backgroundMap );
// intentionally fallthrough
case STATE_GAME_SHUTDOWN:
HostState_SetState( STATE_GAME_SHUTDOWN, false );
Host_SetState( STATE_GAME_SHUTDOWN, false );
break;
case STATE_CHANGELEVEL:
SCR_BeginLoadingPlaque( false );
HostState_SetState( GameState->nextstate, true );
Host_SetState( GameState->nextstate, true );
break;
default:
HostState_SetState( STATE_RUNFRAME, true );
Host_SetState( STATE_RUNFRAME, true );
break;
}
}
@ -185,19 +147,22 @@ void COM_Frame( float time )
switch( GameState->curstate )
{
case STATE_LOAD_LEVEL:
HostState_LoadLevel();
SV_ExecLoadLevel();
Host_SetState( STATE_RUNFRAME, true );
break;
case STATE_LOAD_GAME:
HostState_LoadGame();
SV_ExecLoadGame();
Host_SetState( STATE_RUNFRAME, true );
break;
case STATE_CHANGELEVEL:
HostState_ChangeLevel();
SV_ExecChangeLevel();
Host_SetState( STATE_RUNFRAME, true );
break;
case STATE_RUNFRAME:
HostState_Run( time );
Host_RunFrame( time );
break;
case STATE_GAME_SHUTDOWN:
HostState_ShutdownGame();
Host_ShutdownGame();
break;
}

View File

@ -107,7 +107,6 @@ static void Mod_FreeModel( model_t *mod )
if( !mod || !mod->name[0] )
return;
Msg( "release %s\n", mod->name );
Mod_FreeUserData( mod );
// select the properly unloader
@ -479,8 +478,6 @@ void Mod_FreeUnused( void )
model_t *mod;
int i;
Msg( "Mod_FreeUnused()\n" );
for( i = 0, mod = mod_known; i < mod_numknown; i++, mod++ )
{
if( mod->needload == NL_UNREFERENCED )

View File

@ -96,6 +96,12 @@ sizebuf_t net_message;
byte *net_mempool;
byte net_message_buffer[NET_MAX_MESSAGE];
const char *ns_strings[NS_COUNT] =
{
"Client",
"Server",
};
/*
===============
Netchan_Init
@ -714,7 +720,7 @@ void Netchan_CheckForCompletion( netchan_t *chan, int stream, int intotalbuffers
if( c == intotalbuffers )
{
chan->incomingready[stream] = true;
MsgDev( D_NOTE, "\nincoming is complete %i bytes waiting\n", size );
MsgDev( D_NOTE, "\n%s: incoming is complete %i bytes waiting\n", ns_strings[chan->sock], size );
}
}

View File

@ -142,7 +142,7 @@ typedef struct physics_interface_s
// called through save\restore process
void (*pfnCreateEntitiesInTransitionList)( SAVERESTOREDATA*, int levelMask );
// called through save\restore process
void (*pfnCreateEntitiesInRestoreList)( SAVERESTOREDATA*, int createPlayers );
void (*pfnCreateEntitiesInRestoreList)( SAVERESTOREDATA* );
// allocate custom string (e.g. using user implementation of stringtable, not engine strings)
string_t (*pfnAllocString)( const char *szValue );
// make custom string (e.g. using user implementation of stringtable, not engine strings)

View File

@ -246,8 +246,6 @@ typedef struct sv_client_s
edict_t *edict; // EDICT_NUM(clientnum+1)
edict_t *pViewEntity; // svc_setview member
int messagelevel; // for filtering printed messages
edict_t *viewentity[MAX_VIEWENTS]; // list of portal cameras in player PVS
int num_viewents; // num of portal cameras that can merge PVS
@ -485,10 +483,11 @@ void Master_Packet( void );
//
// sv_init.c
//
void SV_ActivateServer( void );
void SV_LevelInit( const char *pMapName, char const *pOldLevel, char const *pLandmarkName, qboolean loadGame );
void SV_ActivateServer( int runPhysics );
qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background );
model_t *SV_ModelHandle( int modelindex );
void SV_DeactivateServer( void );
char *SV_EntityScript( void );
//
// sv_phys.c
@ -519,8 +518,8 @@ void SV_WaterMove( edict_t *ent );
// sv_send.c
//
void SV_SendClientMessages( void );
void SV_ClientPrintf( sv_client_t *cl, int level, char *fmt, ... );
void SV_BroadcastPrintf( sv_client_t *ignore, int level, char *fmt, ... );
void SV_ClientPrintf( sv_client_t *cl, char *fmt, ... );
void SV_BroadcastPrintf( sv_client_t *ignore, char *fmt, ... );
void SV_BroadcastCommand( const char *fmt, ... );
//
@ -536,6 +535,7 @@ const char *SV_GetClientIDString( sv_client_t *cl );
void SV_FullClientUpdate( sv_client_t *cl, sizebuf_t *msg );
void SV_FullUpdateMovevars( sv_client_t *cl, sizebuf_t *msg );
void SV_GetPlayerStats( sv_client_t *cl, int *ping, int *packet_loss );
void SV_SendServerdata( sizebuf_t *msg, sv_client_t *cl );
qboolean SV_ClientConnect( edict_t *ent, char *userinfo );
void SV_ClientThink( sv_client_t *cl, usercmd_t *cmd );
void SV_ExecuteClientMessage( sv_client_t *cl, sizebuf_t *msg );
@ -543,6 +543,7 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg );
edict_t *SV_FakeConnect( const char *netname );
void SV_ExecuteClientCommand( sv_client_t *cl, char *s );
void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed );
void SV_BuildReconnect( sizebuf_t *msg );
qboolean SV_IsPlayerIndex( int idx );
int SV_CalcPing( sv_client_t *cl );
void SV_InitClientMove( void );
@ -572,9 +573,9 @@ int SV_TransferConsistencyInfo( void );
//
// sv_frame.c
//
void SV_InactivateClients( void );
void SV_WriteFrameToClient( sv_client_t *client, sizebuf_t *msg );
void SV_BuildClientFrame( sv_client_t *client );
void SV_InactivateClients( void );
void SV_SendMessagesToAll( void );
void SV_SkipUpdates( void );
@ -625,7 +626,7 @@ char *SV_Localinfo( void );
_inline edict_t *SV_EDICT_NUM( int n, const char * file, const int line )
{
if((n >= 0) && (n < svgame.globals->maxEntities))
if((n >= 0) && (n < GI->max_edicts))
return svgame.edicts + n;
Host_Error( "SV_EDICT_NUM: bad number %i (called at %s:%i)\n", n, file, line );
return NULL;
@ -645,10 +646,12 @@ void SV_ServerLog_f( sv_client_t *cl );
void SV_ClearSaveDir( void );
void SV_SaveGame( const char *pName );
qboolean SV_LoadGame( const char *pName );
int SV_LoadGameState( char const *level, qboolean createPlayers );
int SV_LoadGameState( char const *level, qboolean changelevel );
void SV_ChangeLevel( qboolean loadfromsavedgame, const char *mapname, const char *start );
void SV_LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName );
const char *SV_GetLatestSave( void );
void SV_InitSaveRestore( void );
void SV_ClearGameState( void );
//
// sv_pmove.c

View File

@ -535,10 +535,7 @@ qboolean SV_ClientConnect( edict_t *ent, char *userinfo )
char *pszName, *pszAddress;
char szRejectReason[MAX_INFO_STRING];
// make sure we start with known default
if( !sv.loadgame ) ent->v.flags = 0;
szRejectReason[0] = '\0';
pszName = Info_ValueForKey( userinfo, "name" );
pszAddress = Info_ValueForKey( userinfo, "ip" );
@ -642,7 +639,6 @@ void SV_FlushRedirect( netadr_t adr, int dest, char *buf )
case RD_CLIENT:
if( !svs.currentPlayer ) return; // client not set
MSG_BeginServerCmd( &svs.currentPlayer->netchan.message, svc_print );
MSG_WriteByte( &svs.currentPlayer->netchan.message, PRINT_HIGH );
MSG_WriteString( &svs.currentPlayer->netchan.message, buf );
break;
case RD_NONE:
@ -1204,35 +1200,7 @@ void SV_PutClientInServer( sv_client_t *cl )
MSG_Init( &msg, "Spawn", msg_buf, sizeof( msg_buf ));
if( !sv.loadgame )
{
if( Q_atoi( Info_ValueForKey( cl->userinfo, "hltv" )))
SetBits( cl->flags, FCL_HLTV_PROXY );
if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
SetBits( ent->v.flags, FL_PROXY );
else ent->v.flags = 0;
ent->v.netname = MAKE_STRING( cl->name );
ent->v.colormap = NUM_FOR_EDICT( ent ); // ???
// fisrt entering
svgame.globals->time = sv.time;
svgame.dllFuncs.pfnClientPutInServer( ent );
if( sv.background ) // don't attack player in background mode
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;
}
}
else
if( sv.loadgame )
{
// NOTE: we needs to setup angles on restore here
if( ent->v.fixangle == 1 )
@ -1275,6 +1243,37 @@ void SV_PutClientInServer( sv_client_t *cl )
if( sv.viewentity > 0 && sv.viewentity < GI->max_edicts )
cl->pViewEntity = EDICT_NUM( sv.viewentity );
else cl->pViewEntity = NULL;
sv.loadgame = false;
sv.paused = false;
}
else
{
if( Q_atoi( Info_ValueForKey( cl->userinfo, "hltv" )))
SetBits( cl->flags, FCL_HLTV_PROXY );
if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
SetBits( ent->v.flags, FL_PROXY );
else ent->v.flags = 0;
ent->v.netname = MAKE_STRING( cl->name );
ent->v.colormap = NUM_FOR_EDICT( ent ); // ???
// fisrt entering
svgame.globals->time = sv.time;
svgame.dllFuncs.pfnClientPutInServer( ent );
if( sv.background ) // don't attack player in background mode
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;
}
}
// enable dev-mode to prevent crash cheat-protecting from Invasion mod
@ -1314,11 +1313,6 @@ void SV_PutClientInServer( sv_client_t *cl )
Netchan_CreateFragments( &cl->netchan, &msg );
Netchan_FragSend( &cl->netchan );
}
// clear any temp states
sv.changelevel = false;
sv.loadgame = false;
sv.paused = false;
}
/*
@ -1351,13 +1345,27 @@ void SV_TogglePause( const char *msg )
sv.paused ^= 1;
if( msg ) SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s", msg );
if( COM_CheckString( msg ))
SV_BroadcastPrintf( NULL, "%s", msg );
// send notification to all clients
MSG_BeginServerCmd( &sv.reliable_datagram, svc_setpause );
MSG_WriteOneBit( &sv.reliable_datagram, sv.paused );
}
/*
================
SV_SendReconnect
Tell all the clients that the server is changing levels
================
*/
void SV_BuildReconnect( sizebuf_t *msg )
{
MSG_BeginServerCmd( msg, svc_stufftext );
MSG_WriteString( msg, "reconnect\n" );
}
/*
==================
SV_WriteDeltaDescriptionToClient
@ -1389,20 +1397,30 @@ This will be sent on the initial connection and upon each server load.
*/
void SV_SendServerdata( sizebuf_t *msg, sv_client_t *cl )
{
string message;
int i;
// Only send this message to developer console, or multiplayer clients.
if(( host.developer ) || ( svs.maxclients > 1 ))
{
MSG_BeginServerCmd( msg, svc_print );
Q_snprintf( message, sizeof( message ), "%c\nBUILD %d SERVER (%i CRC)\nServer # %i\n", 2, Q_buildnum(), 0, svs.spawncount );
MSG_WriteString( msg, message );
}
// send the serverdata
MSG_BeginServerCmd( msg, svc_serverdata );
MSG_WriteLong( msg, PROTOCOL_VERSION );
MSG_WriteLong( msg, svs.spawncount );
MSG_WriteLong( msg, sv.worldmapCRC );
MSG_WriteByte( msg, cl - svs.clients );
MSG_WriteByte( msg, svgame.globals->maxClients );
MSG_WriteWord( msg, svgame.globals->maxEntities );
MSG_WriteByte( msg, svs.maxclients );
MSG_WriteWord( msg, GI->max_edicts );
MSG_WriteWord( msg, MAX_MODELS );
MSG_WriteString( msg, sv.name );
MSG_WriteString( msg, STRING( EDICT_NUM( 0 )->v.message )); // Map Message
MSG_WriteString( msg, STRING( svgame.edicts->v.message )); // Map Message
MSG_WriteOneBit( msg, sv.background ); // tell client about background map
MSG_WriteOneBit( msg, svgame.globals->changelevel );
MSG_WriteString( msg, GI->gamefolder );
MSG_WriteLong( msg, host.features );
@ -1418,6 +1436,21 @@ void SV_SendServerdata( sizebuf_t *msg, sv_client_t *cl )
// now client know delta and can reading encoded messages
SV_FullUpdateMovevars( cl, msg );
// send the user messages registration
for( i = 1; i < MAX_USER_MESSAGES && svgame.msg[i].name[0]; i++ )
SV_SendUserReg( msg, &svgame.msg[i] );
for( i = 0; i < MAX_LIGHTSTYLES; i++ )
{
if( !sv.lightstyles[i].pattern[0] )
continue; // unused style
MSG_BeginServerCmd( msg, svc_lightstyle );
MSG_WriteByte( msg, i ); // stylenum
MSG_WriteString( msg, sv.lightstyles[i].pattern );
MSG_WriteFloat( msg, sv.lightstyles[i].time );
}
}
/*
@ -1453,21 +1486,6 @@ void SV_New_f( sv_client_t *cl )
// send the serverdata
SV_SendServerdata( &msg, cl );
// send the user messages registration
for( i = 1; i < MAX_USER_MESSAGES && svgame.msg[i].name[0]; i++ )
SV_SendUserReg( &msg, &svgame.msg[i] );
for( i = 0; i < MAX_LIGHTSTYLES; i++ )
{
if( !sv.lightstyles[i].pattern[0] )
continue; // unused style
MSG_BeginServerCmd( &msg, svc_lightstyle );
MSG_WriteByte( &msg, i ); // stylenum
MSG_WriteString( &msg, sv.lightstyles[i].pattern );
MSG_WriteFloat( &msg, sv.lightstyles[i].time );
}
// server info string
MSG_BeginServerCmd( &msg, svc_stufftext );
MSG_WriteString( &msg, va( "fullserverinfo \"%s\"\n", SV_Serverinfo( )));
@ -1662,13 +1680,13 @@ void SV_Pause_f( sv_client_t *cl )
if( !sv_pausable->value )
{
SV_ClientPrintf( cl, PRINT_HIGH, "Pause not allowed.\n" );
SV_ClientPrintf( cl, "Pause not allowed.\n" );
return;
}
if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
{
SV_ClientPrintf( cl, PRINT_HIGH, "Spectators can not pause.\n" );
SV_ClientPrintf( cl, "Spectators can not pause.\n" );
return;
}
@ -1753,19 +1771,18 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
if( Q_strlen( val ))
cl->netchan.rate = bound( MIN_RATE, Q_atoi( val ), MAX_RATE );
else cl->netchan.rate = DEFAULT_RATE;
// msg command
val = Info_ValueForKey( cl->userinfo, "msg" );
if( Q_strlen( val )) cl->messagelevel = Q_atoi( val );
// movement prediction
if( Q_atoi( Info_ValueForKey( cl->userinfo, "cl_nopred" )))
ClearBits( cl->flags, FCL_PREDICT_MOVEMENT );
else SetBits( cl->flags, FCL_PREDICT_MOVEMENT );
// lag compensation
if( Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lc" )))
SetBits( cl->flags, FCL_LAG_COMPENSATION );
else ClearBits( cl->flags, FCL_LAG_COMPENSATION );
// weapon perdiction
if( Q_atoi( Info_ValueForKey( cl->userinfo, "cl_lw" )))
SetBits( cl->flags, FCL_LOCAL_WEAPONS );
else ClearBits( cl->flags, FCL_LOCAL_WEAPONS );
@ -1830,13 +1847,37 @@ static void SV_Noclip_f( sv_client_t *cl )
if( pEntity->v.movetype != MOVETYPE_NOCLIP )
{
SV_ClientPrintf( cl, "noclip ON\n" );
pEntity->v.movetype = MOVETYPE_NOCLIP;
SV_ClientPrintf( cl, PRINT_HIGH, "noclip ON\n" );
}
else
{
SV_ClientPrintf( cl, "noclip OFF\n" );
pEntity->v.movetype = MOVETYPE_WALK;
}
}
/*
==================
SV_Fly_f
==================
*/
static void SV_Fly_f( sv_client_t *cl )
{
edict_t *pEntity = cl->edict;
if( !Cvar_VariableInteger( "sv_cheats" ) || sv.background )
return;
if( pEntity->v.movetype != MOVETYPE_FLY )
{
SV_ClientPrintf( cl, "flymode ON\n" );
pEntity->v.movetype = MOVETYPE_FLY;
}
else
{
SV_ClientPrintf( cl, "flymode OFF\n" );
pEntity->v.movetype = MOVETYPE_WALK;
SV_ClientPrintf( cl, PRINT_HIGH, "noclip OFF\n" );
}
}
@ -1855,8 +1896,8 @@ static void SV_Godmode_f( sv_client_t *cl )
pEntity->v.flags = pEntity->v.flags ^ FL_GODMODE;
if( !FBitSet( pEntity->v.flags, FL_GODMODE ))
SV_ClientPrintf( cl, PRINT_HIGH, "godmode OFF\n" );
else SV_ClientPrintf( cl, PRINT_HIGH, "godmode ON\n" );
SV_ClientPrintf( cl, "godmode OFF\n" );
else SV_ClientPrintf( cl, "godmode ON\n" );
}
/*
@ -1874,8 +1915,8 @@ static void SV_Notarget_f( sv_client_t *cl )
pEntity->v.flags = pEntity->v.flags ^ FL_NOTARGET;
if( !FBitSet( pEntity->v.flags, FL_NOTARGET ))
SV_ClientPrintf( cl, PRINT_HIGH, "notarget OFF\n" );
else SV_ClientPrintf( cl, PRINT_HIGH, "notarget ON\n" );
SV_ClientPrintf( cl, "notarget OFF\n" );
else SV_ClientPrintf( cl, "notarget ON\n" );
}
/*
@ -2013,7 +2054,7 @@ void SV_Spawn_f( sv_client_t *cl )
{
MSG_BeginServerCmd( &sv.reliable_datagram, svc_setpause );
MSG_WriteByte( &sv.reliable_datagram, sv.paused );
SV_ClientPrintf( cl, PRINT_HIGH, "Server is paused.\n" );
SV_ClientPrintf( cl, "Server is paused.\n" );
}
}
@ -2037,6 +2078,7 @@ void SV_Begin_f( sv_client_t *cl )
ucmd_t ucmds[] =
{
{ "new", SV_New_f },
{ "fly", SV_Fly_f },
{ "god", SV_Godmode_f },
{ "begin", SV_Begin_f },
{ "spawn", SV_Spawn_f },
@ -2278,7 +2320,7 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
cl->packet_loss = packet_loss;
// check for pause or frozen
if( sv.paused || sv.loadgame || sv.background || !CL_IsInGame() || SV_PlayerIsFrozen( player ))
if( sv.paused || !CL_IsInGame() || SV_PlayerIsFrozen( player ))
{
for( i = 0; i < numcmds; i++ )
{
@ -2288,7 +2330,7 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
cmds[i].upmove = 0;
cmds[i].buttons = 0;
if( SV_PlayerIsFrozen( player ) || sv.background )
if( SV_PlayerIsFrozen( player ))
cmds[i].impulse = 0;
VectorCopy( cmds[i].viewangles, player->v.v_angle );

View File

@ -23,12 +23,12 @@ SV_ClientPrintf
Sends text across to be displayed if the level passes
=================
*/
void SV_ClientPrintf( sv_client_t *cl, int level, char *fmt, ... )
void SV_ClientPrintf( sv_client_t *cl, char *fmt, ... )
{
char string[MAX_SYSPATH];
va_list argptr;
if( level < cl->messagelevel || FBitSet( cl->flags, FCL_FAKECLIENT ))
if( FBitSet( cl->flags, FCL_FAKECLIENT ))
return;
va_start( argptr, fmt );
@ -36,7 +36,6 @@ void SV_ClientPrintf( sv_client_t *cl, int level, char *fmt, ... )
va_end( argptr );
MSG_BeginServerCmd( &cl->netchan.message, svc_print );
MSG_WriteByte( &cl->netchan.message, level );
MSG_WriteString( &cl->netchan.message, string );
}
@ -47,7 +46,7 @@ SV_BroadcastPrintf
Sends text to all active clients
=================
*/
void SV_BroadcastPrintf( sv_client_t *ignore, int level, char *fmt, ... )
void SV_BroadcastPrintf( sv_client_t *ignore, char *fmt, ... )
{
char string[MAX_SYSPATH];
va_list argptr;
@ -66,16 +65,17 @@ void SV_BroadcastPrintf( sv_client_t *ignore, int level, char *fmt, ... )
for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ )
{
if( level < cl->messagelevel || FBitSet( cl->flags, FCL_FAKECLIENT ))
if( FBitSet( cl->flags, FCL_FAKECLIENT ))
continue;
if( cl == ignore || cl->state != cs_spawned )
continue;
MSG_BeginServerCmd( &cl->netchan.message, svc_print );
MSG_WriteByte( &cl->netchan.message, level );
MSG_WriteString( &cl->netchan.message, string );
}
MsgDev( D_REPORT, string );
}
/*
@ -235,12 +235,7 @@ void SV_Map_f( void )
if( !SV_ValidateMap( mapname, true ))
return;
// changing singleplayer to multiplayer or back. refresh the player count
if( FBitSet( sv_maxclients->flags, FCVAR_CHANGED ))
Host_ShutdownServer();
Cvar_DirectSet( sv_hostmap, mapname );
COM_LoadLevel( mapname, false );
}
@ -261,7 +256,7 @@ void SV_MapBackground_f( void )
return;
}
if( sv.state == ss_active && !sv.background )
if( SV_Active() && !sv.background )
{
MsgDev( D_ERROR, "can't set background map while game is active\n" );
return;
@ -274,14 +269,10 @@ void SV_MapBackground_f( void )
if( !SV_ValidateMap( mapname, false ))
return;
Q_strncpy( host.finalmsg, "", MAX_STRING );
SV_Shutdown( true );
NET_Config( false ); // close network sockets
// reset all multiplayer cvars
// background map is always run as singleplayer
Cvar_FullSet( "maxplayers", "1", FCVAR_LATCH );
Cvar_SetValue( "deathmatch", 0 );
Cvar_SetValue( "coop", 0 );
Cvar_FullSet( "deathmatch", "0", FCVAR_LATCH );
Cvar_FullSet( "coop", "0", FCVAR_LATCH );
COM_LoadLevel( mapname, true );
}
@ -512,10 +503,17 @@ void SV_ChangeLevel_f( void )
}
if( sv.background )
{
COM_LoadLevel( mapname, false );
else if( c == 2 )
COM_ChangeLevel( Cmd_Argv( 1 ), NULL );
else COM_ChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
}
else
{
// g-cont: inactivate clients to avoid fired "trigger_changelevel" multiple times
SV_InactivateClients ();
if( c == 2 ) COM_ChangeLevel( Cmd_Argv( 1 ), NULL );
else COM_ChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
}
}
/*
@ -570,8 +568,8 @@ void SV_Kick_f( void )
}
Log_Printf( "Kick: \"%s<%i>\" was kicked\n", svs.currentPlayer->name, svs.currentPlayer->userid );
SV_BroadcastPrintf( svs.currentPlayer, PRINT_HIGH, "%s was kicked\n", svs.currentPlayer->name );
SV_ClientPrintf( svs.currentPlayer, PRINT_HIGH, "You were kicked from the game\n" );
SV_BroadcastPrintf( svs.currentPlayer, "%s was kicked\n", svs.currentPlayer->name );
SV_ClientPrintf( svs.currentPlayer, "You were kicked from the game\n" );
SV_DropClient( svs.currentPlayer );
}
@ -589,7 +587,7 @@ void SV_Kill_f( void )
if( svs.currentPlayer->edict->v.health <= 0.0f )
{
SV_ClientPrintf( svs.currentPlayer, PRINT_HIGH, "Can't suicide - already dead!\n");
SV_ClientPrintf( svs.currentPlayer, "Can't suicide - already dead!\n");
return;
}
@ -678,9 +676,7 @@ SV_ConSay_f
*/
void SV_ConSay_f( void )
{
char *p, text[MAX_SYSPATH];
sv_client_t *client;
int i;
char *p, text[MAX_SYSPATH];
if( Cmd_Argc() < 2 ) return;
@ -700,14 +696,7 @@ void SV_ConSay_f( void )
}
Q_strncat( text, p, MAX_SYSPATH );
for( i = 0, client = svs.clients; i < svs.maxclients; i++, client++ )
{
if( client->state != cs_spawned )
continue;
SV_ClientPrintf( client, PRINT_CHAT, "%s\n", text );
}
SV_BroadcastPrintf( NULL, "%s\n", text );
Log_Printf( "Server say: \"%s\"\n", p );
}
@ -849,8 +838,8 @@ void SV_PlayersOnly_f( void )
sv.hostflags = sv.hostflags ^ SVF_PLAYERSONLY;
if( !FBitSet( sv.hostflags, SVF_PLAYERSONLY ))
SV_BroadcastPrintf( NULL, PRINT_HIGH, "Resume server physic\n" );
else SV_BroadcastPrintf( NULL, PRINT_HIGH, "Freeze server physic\n" );
SV_BroadcastPrintf( NULL, "Resume game physic\n" );
else SV_BroadcastPrintf( NULL, "Freeze game physic\n" );
}
/*
@ -871,8 +860,8 @@ void SV_EdictUsage_f( void )
active = pfnNumberOfEntities();
Msg( "%5i edicts is used\n", active );
Msg( "%5i edicts is free\n", svgame.globals->maxEntities - active );
Msg( "%5i total\n", svgame.globals->maxEntities );
Msg( "%5i edicts is free\n", GI->max_edicts - active );
Msg( "%5i total\n", GI->max_edicts );
}
/*
@ -937,7 +926,6 @@ 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( "killsave", SV_DeleteSave_f, "delete a saved game file and saveshot" );
}
}
@ -961,17 +949,18 @@ void SV_InitOperatorCommands( void )
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" );
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 )
{
Cmd_AddCommand( "say", SV_ConSay_f, "send a chat message to everyone on the server" );
Cmd_AddCommand( "killserver", SV_KillServer_f, "shutdown current server" );
}
}
@ -998,6 +987,7 @@ void SV_KillOperatorCommands( void )
Cmd_RemoveCommand( "entpatch" );
Cmd_RemoveCommand( "edict_usage" );
Cmd_RemoveCommand( "entity_info" );
Cmd_RemoveCommand( "shutdownserver" );
if( host.type == HOST_NORMAL )
{
@ -1009,6 +999,5 @@ void SV_KillOperatorCommands( void )
else if( host.type == HOST_DEDICATED )
{
Cmd_RemoveCommand( "say" );
Cmd_RemoveCommand( "killserver" );
}
}

View File

@ -177,8 +177,8 @@ void SV_ParseConsistencyResponse( sv_client_t *cl, sizebuf_t *msg )
dropmessage[0] = 0;
if( svgame.dllFuncs.pfnInconsistentFile( cl->edict, sv.resources[badresindex - 1].szFileName, dropmessage ))
{
if( Q_strlen( dropmessage ) > 0 )
SV_ClientPrintf( cl, PRINT_HIGH, dropmessage );
if( COM_CheckString( dropmessage ))
SV_ClientPrintf( cl, dropmessage );
SV_DropClient( cl );
}
}

View File

@ -862,7 +862,7 @@ void SV_SendClientMessages( void )
{
MSG_Clear( &cl->netchan.message );
MSG_Clear( &cl->datagram );
SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s overflowed\n", cl->name );
SV_BroadcastPrintf( NULL, "%s overflowed\n", cl->name );
MsgDev( D_WARN, "reliable overflow for %s\n", cl->name );
SV_DropClient( cl );
SetBits( cl->flags, FCL_SEND_NET_MESSAGE );

View File

@ -838,7 +838,7 @@ edict_t *SV_AllocEdict( void )
edict_t *pEdict;
int i;
for( i = svgame.globals->maxClients + 1; i < svgame.numEntities; i++ )
for( i = svs.maxclients + 1; i < svgame.numEntities; i++ )
{
pEdict = EDICT_NUM( i );
// the first couple seconds of server time can involve a lot of
@ -850,8 +850,8 @@ edict_t *SV_AllocEdict( void )
}
}
if( i >= svgame.globals->maxEntities )
Sys_Error( "ED_AllocEdict: no free edicts (max is %d)\n", svgame.globals->maxEntities );
if( i >= GI->max_edicts )
Sys_Error( "ED_AllocEdict: no free edicts (max is %d)\n", GI->max_edicts );
svgame.numEntities++;
pEdict = EDICT_NUM( i );
@ -1389,15 +1389,15 @@ int SV_CheckClientPVS( int check, qboolean bMergePVS )
edict_t *ent = NULL;
// cycle to the next one
check = bound( 1, check, svgame.globals->maxClients );
check = bound( 1, check, svs.maxclients );
if( check == svgame.globals->maxClients )
if( check == svs.maxclients )
i = 1; // reset cycle
else i = check + 1;
for( ;; i++ )
{
if( i == ( svgame.globals->maxClients + 1 ))
if( i == ( svs.maxclients + 1 ))
i = 1;
ent = EDICT_NUM( i );
@ -1580,7 +1580,7 @@ void pfnRemoveEntity( edict_t* e )
}
// never free client or world entity
if( NUM_FOR_EDICT( e ) < ( svgame.globals->maxClients + 1 ))
if( NUM_FOR_EDICT( e ) < ( svs.maxclients + 1 ))
{
MsgDev( D_ERROR, "SV_RemoveEntity: can't delete %s\n", (e == EDICT_NUM( 0 )) ? "world" : "client" );
return;
@ -3243,10 +3243,8 @@ void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg )
switch( ptype )
{
case print_console:
SV_ClientPrintf( client, PRINT_HIGH, "%s", szMsg );
break;
case print_chat:
SV_ClientPrintf( client, PRINT_CHAT, "%s", szMsg );
SV_ClientPrintf( client, "%s", szMsg );
break;
case print_center:
MSG_BeginServerCmd( &client->netchan.message, svc_centerprint );
@ -3263,9 +3261,7 @@ pfnServerPrint
*/
void pfnServerPrint( const char *szMsg )
{
// while loading in-progress we can sending message only for local client
if( sv.state != ss_active ) MsgDev( D_INFO, "%s", szMsg );
else SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s", szMsg );
SV_BroadcastPrintf( NULL, "%s", szMsg );
}
/*
@ -3489,8 +3485,6 @@ void pfnRunPlayerMove( edict_t *pClient, const float *v_angle, float fmove, floa
usercmd_t cmd;
uint seed;
if( sv.paused ) return;
if(( cl = SV_ClientFromEdict( pClient, true )) == NULL )
{
MsgDev( D_ERROR, "SV_ClientThink: fakeclient is not spawned!\n" );
@ -4926,10 +4920,10 @@ 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 ) * svgame.globals->maxEntities );
svgame.numEntities = svgame.globals->maxClients + 1; // clients + world
svgame.edicts = Mem_Alloc( svgame.mempool, sizeof( edict_t ) * GI->max_edicts );
svgame.numEntities = svs.maxclients + 1; // clients + world
for( i = 0, e = svgame.edicts; i < svgame.globals->maxEntities; i++, e++ )
for( i = 0, e = svgame.edicts; i < GI->max_edicts; i++, e++ )
e->free = true; // mark all edicts as freed
// clear user messages

View File

@ -477,12 +477,11 @@ void SV_FreeOldEntities( void )
int i;
// at end of frame kill all entities which supposed to it
for( i = svgame.globals->maxClients + 1; i < svgame.numEntities; i++ )
for( i = svs.maxclients + 1; i < svgame.numEntities; i++ )
{
ent = EDICT_NUM( i );
if( ent->free ) continue;
if( ent->v.flags & FL_KILLME )
if( !ent->free && FBitSet( ent->v.flags, FL_KILLME ))
SV_FreeEdict( ent );
}
@ -497,39 +496,48 @@ SV_ActivateServer
activate server on changed map, run physics
================
*/
void SV_ActivateServer( void )
void SV_ActivateServer( int runPhysics )
{
int i, numFrames;
int i, numFrames;
byte msg_buf[MAX_INIT_MSG];
sizebuf_t msg;
sv_client_t *cl;
if( !svs.initialized )
return;
// Activate the DLL server code
svgame.dllFuncs.pfnServerActivate( svgame.edicts, svgame.numEntities, svgame.globals->maxClients );
MSG_Init( &msg, "NewServer", msg_buf, sizeof( msg_buf ));
if( sv.loadgame || svgame.globals->changelevel )
{
sv.frametime = bound( 0.001, sv_changetime.value, 0.1 );
numFrames = 1;
}
else if( svs.maxclients <= 1 )
// always clearing newunit variable
Cvar_SetValue( "sv_newunit", 0 );
// relese all intermediate entities
SV_FreeOldEntities ();
// Activate the DLL server code
svgame.globals->time = sv.time;
svgame.dllFuncs.pfnServerActivate( svgame.edicts, svgame.numEntities, svs.maxclients );
// parse user-specified resources
SV_CreateGenericResources();
sv.state = ss_active;
if( runPhysics )
{
sv.frametime = bound( 0.1, sv_spawntime.value, 0.8 );
numFrames = 2;
numFrames = (svs.maxclients <= 1) ? 2 : 8;
}
else
{
sv.frametime = 0.1f;
numFrames = 8;
sv.frametime = bound( 0.001, sv_changetime.value, 0.1 );
numFrames = 0;
}
// run some frames to allow everything to settle
for( i = 0; i < numFrames; i++ )
SV_Physics();
// parse user-specified resources
SV_CreateGenericResources();
// create a baseline for more efficient communications
SV_CreateBaseline();
@ -540,18 +548,26 @@ void SV_ActivateServer( void )
sv.num_consistency = SV_TransferConsistencyInfo();
// send serverinfo to all connected clients
for( i = 0; i < svs.maxclients; i++ )
for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ )
{
if( svs.clients[i].state >= cs_connected )
{
Netchan_Clear( &svs.clients[i].netchan );
svs.clients[i].delta_sequence = -1;
}
if( cl->state < cs_connected )
continue;
Netchan_Clear( &cl->netchan );
cl->delta_sequence = -1;
if( svs.maxclients <= 1 )
SV_SendServerdata( &msg, cl );
else SV_BuildReconnect( &cl->netchan.message );
Netchan_CreateFragments( &cl->netchan, &msg );
Netchan_FragSend( &cl->netchan );
MSG_Clear( &msg );
}
// invoke to refresh all movevars
memset( &svgame.oldmovevars, 0, sizeof( movevars_t ));
svgame.globals->changelevel = false; // changelevel ends here
svgame.globals->changelevel = false;
// setup hostflags
sv.hostflags = 0;
@ -559,9 +575,9 @@ void SV_ActivateServer( void )
HPAK_FlushHostQueue();
// tell what kind of server has been started.
if( svgame.globals->maxClients > 1 )
if( svs.maxclients > 1 )
{
MsgDev( D_INFO, "%i player server started\n", svgame.globals->maxClients );
MsgDev( D_INFO, "%i player server started\n", svs.maxclients );
}
else
{
@ -574,11 +590,7 @@ void SV_ActivateServer( void )
if( host.type == HOST_DEDICATED )
Mod_FreeUnused ();
sv.state = ss_active;
host.movevars_changed = true;
sv.changelevel = false;
sv.paused = false;
Host_SetServerState( sv.state );
MsgDev( D_INFO, "level loaded at %.2f sec\n", Sys_DoubleTime() - svs.timestart );
@ -629,65 +641,12 @@ void SV_DeactivateServer( void )
svgame.globals->maxEntities = GI->max_edicts;
svgame.globals->maxClients = svs.maxclients;
svgame.numEntities = svgame.globals->maxClients + 1; // clients + world
svgame.numEntities = svs.maxclients + 1; // clients + world
svgame.globals->startspot = 0;
svgame.globals->mapname = 0;
// clear states
sv.changelevel = false;
sv.background = false;
sv.loadgame = false;
sv.state = ss_dead;
}
/*
================
SV_LevelInit
Spawn all entities
================
*/
void SV_LevelInit( const char *pMapName, char const *pOldLevel, char const *pLandmarkName, qboolean loadGame )
{
if( !svs.initialized )
return;
if( loadGame )
{
if( !SV_LoadGameState( pMapName, 1 ))
{
SV_SpawnEntities( pMapName, SV_EntityScript( ));
}
if( pOldLevel )
{
SV_LoadAdjacentEnts( pOldLevel, pLandmarkName );
}
if( sv_newunit.value )
{
SV_ClearSaveDir();
}
}
else
{
svgame.dllFuncs.pfnResetGlobalState();
SV_SpawnEntities( pMapName, SV_EntityScript( ));
svgame.globals->frametime = 0.0f;
if( sv_newunit.value )
{
SV_ClearSaveDir();
}
}
// always clearing newunit variable
Cvar_SetValue( "sv_newunit", 0 );
// relese all intermediate entities
SV_FreeOldEntities ();
}
/*
==============
SV_InitGame
@ -695,34 +654,100 @@ SV_InitGame
A brand new game has been started
==============
*/
void SV_InitGame( void )
qboolean SV_InitGame( void )
{
edict_t *ent;
int i, load = sv.loadgame;
if( svs.initialized )
return true; // already initialized ?
// first initialize?
if( !SV_LoadProgs( GI->game_dll ))
{
// cause any connected clients to reconnect
Q_strncpy( host.finalmsg, "Server restarted", MAX_STRING );
SV_Shutdown( true );
MsgDev( D_ERROR, "SV_InitGame: can't initialize %s\n", GI->game_dll );
return false; // failed to loading server.dll
}
// alloc baseline slots
svs.baselines = Z_Malloc( sizeof( entity_state_t ) * GI->max_edicts );
// client frames will be allocated in SV_ClientConnect
svs.initialized = true;
return true;
}
/*
==============
SV_ShutdownGame
prepare to close server
==============
*/
void SV_ShutdownGame( void )
{
if( !GameState->loadGame )
SV_ClearGameState();
S_StopBackgroundTrack();
if( GameState->newGame )
{
Host_EndGame( false, DEFAULT_ENDGAME_MESSAGE );
}
else
{
// init game after host error
if( !svgame.hInstance )
{
if( !SV_LoadProgs( GI->game_dll ))
{
MsgDev( D_ERROR, "SV_InitGame: can't initialize %s\n", GI->game_dll );
return; // can't loading
}
}
S_StopAllSounds( true );
SV_DeactivateServer();
}
}
// make sure the client is down
CL_Drop();
/*
================
SV_AllocClientFrames
allocate delta-compression frames for each client
================
*/
void SV_AllocClientFrames( void )
{
sv_client_t *cl;
int i;
for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ )
{
cl->frames = Z_Realloc( cl->frames, SV_UPDATE_BACKUP * sizeof( client_frame_t ));
}
}
/*
================
SV_SetupClients
determine the game type and prepare clients
================
*/
void SV_SetupClients( void )
{
qboolean changed_maxclients = false;
// check if clients count was really changed
if( svs.maxclients != (int)sv_maxclients->value )
changed_maxclients = true;
svs.maxclients = sv_maxclients->value; // copy the actual value from cvar
if( svs.maxclients == 1 )
{
if( deathmatch.value )
{
changed_maxclients = true;
svs.maxclients = 8;
}
else if( coop.value )
{
changed_maxclients = true;
svs.maxclients = 4;
}
}
svs.maxclients = sv_maxclients->value; // copy the actual value from cvar
if( !changed_maxclients ) return; // nothing to change
// dedicated servers are can't be single player and are usually DM
if( host.type == HOST_DEDICATED )
@ -741,13 +766,10 @@ void SV_InitGame( void )
SV_UPDATE_BACKUP = ( svs.maxclients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
svgame.globals->maxClients = svs.maxclients;
svs.clients = Z_Malloc( sizeof( sv_client_t ) * svs.maxclients );
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_Malloc( sizeof( entity_state_t ) * svs.num_client_entities );
svs.baselines = Z_Malloc( sizeof( entity_state_t ) * GI->max_edicts );
if( !load ) MsgDev( D_INFO, "%s alloced by server packet entities\n", Q_memprint( sizeof( entity_state_t ) * svs.num_client_entities ));
// client frames will be allocated in SV_DirectConnect
svs.packet_entities = Z_Realloc( svs.packet_entities, sizeof( entity_state_t ) * svs.num_client_entities );
MsgDev( D_INFO, "%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 ));
@ -755,24 +777,11 @@ void SV_InitGame( void )
// copy gamemode into svgame.globals
svgame.globals->deathmatch = deathmatch.value;
svgame.globals->coop = coop.value;
svgame.numEntities = svs.maxclients + 1; // clients + world
// heartbeats will always be sent to the id master
svs.last_heartbeat = MAX_HEARTBEAT; // send immediately
// set client fields on player ents
for( i = 0; i < svgame.globals->maxClients; i++ )
{
// setup all the clients
ent = EDICT_NUM( i + 1 );
svs.clients[i].edict = ent;
SV_InitEdict( ent );
}
// get actual movevars
SV_UpdateMovevars( true );
svgame.numEntities = svgame.globals->maxClients + 1; // clients + world
svs.initialized = true;
ClearBits( sv_maxclients->flags, FCVAR_CHANGED );
ClearBits( deathmatch.flags, FCVAR_CHANGED );
ClearBits( coop.flags, FCVAR_CHANGED );
}
/*
@ -786,28 +795,18 @@ clients along with it.
qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean background )
{
int i, current_skill;
qboolean loadgame, paused;
qboolean changelevel;
edict_t *ent;
// save state
loadgame = sv.loadgame;
changelevel = sv.changelevel;
paused = sv.paused;
if( sv.state == ss_dead )
SV_InitGame(); // the game is just starting
NET_Config(( svs.maxclients > 1 )); // init network stuff
ClearBits( sv_maxclients->flags, FCVAR_CHANGED );
if( !svs.initialized )
if( !SV_InitGame( ))
return false;
Log_Open();
Log_Printf( "Loading map \"%s\"\n", mapname );
Log_PrintServerVars();
svgame.globals->changelevel = false; // will be restored later if needed
SV_SetupClients();
SV_AllocClientFrames();
svs.timestart = Sys_DoubleTime();
svs.spawncount++; // any partially connected client will be restarted
@ -824,13 +823,8 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
Host_SetServerState( sv.state );
memset( &sv, 0, sizeof( sv )); // wipe the entire per-level structure
// restore state
sv.paused = paused;
sv.loadgame = loadgame;
sv.time = svgame.globals->time = 1.0f; // server spawn time it's always 1.0 second
sv.background = background;
sv.changelevel = changelevel;
sv.time = 1.0f; // server spawn time it's always 1.0 second
svgame.globals->time = sv.time;
// initialize buffers
MSG_Init( &sv.signon, "Signon", sv.signon_buf, sizeof( sv.signon_buf ));
@ -839,19 +833,10 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
MSG_Init( &sv.reliable_datagram, "Reliable Datagram", sv.reliable_datagram_buf, sizeof( sv.reliable_datagram_buf ));
MSG_Init( &sv.spec_datagram, "Spectator Datagram", sv.spectator_buf, sizeof( sv.spectator_buf ));
// leave slots at start for clients only
for( i = 0; i < svs.maxclients; i++ )
{
// needs to reconnect
if( svs.clients[i].state > cs_connected )
svs.clients[i].state = cs_connected;
}
// make cvars consistant
if( coop.value ) Cvar_SetValue( "deathmatch", 0 );
current_skill = Q_rint( skill.value );
current_skill = bound( 0, current_skill, 3 );
Cvar_SetValue( "skill", (float)current_skill );
if( sv.background )
@ -885,11 +870,29 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
SetBits( sv.model_precache_flags[i+1], RES_FATALIFMISSING );
}
// leave slots at start for clients only
for( i = 0; i < svs.maxclients; i++ )
{
// needs to reconnect
if( svs.clients[i].state > cs_connected )
svs.clients[i].state = cs_connected;
ent = EDICT_NUM( i + 1 );
svs.clients[i].edict = ent;
SV_InitEdict( ent );
}
// heartbeats will always be sent to the id master
svs.last_heartbeat = MAX_HEARTBEAT; // send immediately
// precache and static commands can be issued during map initialization
sv.state = ss_loading;
Host_SetServerState( sv.state );
// get actual movevars
SV_UpdateMovevars( true );
// clear physics interaction links
SV_ClearWorld();
@ -897,6 +900,11 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
}
qboolean SV_Active( void )
{
return (sv.state != ss_dead);
}
qboolean SV_Initialized( void )
{
return svs.initialized;
}
@ -920,4 +928,50 @@ void SV_FreeGameProgs( void )
// unload progs (free cvars and commands)
SV_UnloadProgs();
}
/*
================
SV_ExecLoadLevel
State machine exec new map
================
*/
void SV_ExecLoadLevel( void )
{
if( SV_SpawnServer( GameState->levelName, NULL, GameState->backgroundMap ))
{
SV_SpawnEntities( GameState->levelName, SV_EntityScript( ));
SV_ActivateServer( true );
}
}
/*
================
SV_ExecLoadGame
State machine exec load saved game
================
*/
void SV_ExecLoadGame( void )
{
if( SV_SpawnServer( GameState->levelName, NULL, false ))
{
if( !SV_LoadGameState( GameState->levelName, false ))
SV_SpawnEntities( GameState->levelName, SV_EntityScript( ));
sv.loadgame = sv.paused = true; // pause until all clients connect
SV_ActivateServer( false );
}
}
/*
================
SV_ExecChangeLevel
State machine exec changelevel path
================
*/
void SV_ExecChangeLevel( void )
{
SV_ChangeLevel( GameState->loadGame, GameState->levelName, GameState->landmarkName );
}

View File

@ -166,11 +166,11 @@ void SV_ServerLog_f( sv_client_t *cl )
if( Cmd_Argc() != 2 )
{
SV_ClientPrintf( cl, PRINT_HIGH, "usage: log < on|off >\n" );
SV_ClientPrintf( cl, "usage: log < on|off >\n" );
if( svs.log.active )
SV_ClientPrintf( cl, PRINT_HIGH, "currently logging\n" );
else SV_ClientPrintf( cl, PRINT_HIGH, "not currently logging\n" );
SV_ClientPrintf( cl, "currently logging\n" );
else SV_ClientPrintf( cl, "not currently logging\n" );
return;
}
@ -186,6 +186,6 @@ void SV_ServerLog_f( sv_client_t *cl )
}
else
{
SV_ClientPrintf( cl, PRINT_HIGH, "log: unknown parameter %s\n", Cmd_Argv( 1 ));
SV_ClientPrintf( cl, "log: unknown parameter %s\n", Cmd_Argv( 1 ));
}
}

View File

@ -59,8 +59,8 @@ CVAR_DEFINE_AUTO( mapcyclefile, "mapcycle.txt", 0, "name of multiplayer map cycl
CVAR_DEFINE_AUTO( motdfile, "motd.txt", 0, "name of 'message of the day' file" );
CVAR_DEFINE_AUTO( logsdir, "logs", 0, "place to store multiplayer logs" );
CVAR_DEFINE_AUTO( bannedcfgfile, "banned.cfg", 0, "name of list of banned users" );
CVAR_DEFINE_AUTO( deathmatch, "0", 0, "deathmatch mode in multiplayer game" );
CVAR_DEFINE_AUTO( coop, "0", 0, "cooperative mode in multiplayer game" );
CVAR_DEFINE_AUTO( deathmatch, "0", FCVAR_LATCH, "deathmatch mode in multiplayer game" );
CVAR_DEFINE_AUTO( coop, "0", FCVAR_LATCH, "cooperative mode in multiplayer game" );
CVAR_DEFINE_AUTO( teamplay, "0", 0, "team mode in multiplayer game" );
CVAR_DEFINE_AUTO( skill, "1", 0, "skill level in singleplayer game" );
CVAR_DEFINE_AUTO( temp1, "0", 0, "temporary cvar that used by some mods" );
@ -418,7 +418,7 @@ void SV_CheckTimeouts( void )
{
if( !NET_IsLocalAddress( cl->netchan.remote_address ))
{
SV_BroadcastPrintf( NULL, PRINT_HIGH, "%s timed out\n", cl->name );
SV_BroadcastPrintf( NULL, "%s timed out\n", cl->name );
SV_DropClient( cl );
cl->state = cs_free; // don't bother with zombie state
}
@ -825,14 +825,13 @@ void SV_FinalMessage( char *message, qboolean reconnect )
MSG_Init( &msg, "FinalMessage", msg_buf, sizeof( msg_buf ));
MSG_BeginServerCmd( &msg, svc_print );
MSG_WriteByte( &msg, PRINT_HIGH );
MSG_WriteString( &msg, va( "%s\n", message ));
if( reconnect )
{
MSG_BeginServerCmd( &msg, svc_changing );
if( sv.loadgame || svs.maxclients > 1 || sv.changelevel )
if( svs.maxclients > 1 || sv.changelevel )
MSG_WriteOneBit( &msg, 1 ); // changelevel
else MSG_WriteOneBit( &msg, 0 );
}
@ -852,6 +851,29 @@ void SV_FinalMessage( char *message, qboolean reconnect )
Netchan_Transmit( &cl->netchan, MSG_GetNumBytesWritten( &msg ), MSG_GetData( &msg ));
}
void SV_FreeClients( void )
{
if( svs.maxclients != 0 )
{
// free server static data
if( svs.clients )
{
Z_Free( svs.clients );
svs.clients = NULL;
}
if( svs.packet_entities )
{
Z_Free( svs.packet_entities );
svs.packet_entities = NULL;
svs.num_client_entities = 0;
svs.next_client_entities = 0;
}
svs.maxclients = 0;
}
}
/*
================
SV_Shutdown
@ -863,7 +885,7 @@ before Sys_Quit or Sys_Error
void SV_Shutdown( qboolean reconnect )
{
// already freed
if( !SV_Active( )) return;
if( !SV_Initialized( )) return;
// rcon will be disconnected
SV_EndRedirect();
@ -882,31 +904,18 @@ void SV_Shutdown( qboolean reconnect )
// free current level
memset( &sv, 0, sizeof( sv ));
Host_SetServerState( sv.state );
Host_SetServerState( ss_dead );
SV_FreeClients();
Log_Printf( "Server shutdown\n" );
Log_Close();
// free server static data
if( svs.clients )
{
Z_Free( svs.clients );
svs.clients = NULL;
}
if( svs.baselines )
{
Z_Free( svs.baselines );
svs.baselines = NULL;
}
if( svs.packet_entities )
{
Z_Free( svs.packet_entities );
svs.packet_entities = NULL;
svs.num_client_entities = 0;
svs.next_client_entities = 0;
}
svs.initialized = false;
}

View File

@ -80,7 +80,7 @@ void SV_CheckAllEnts( void )
nextcheck = Sys_DoubleTime() + 5.0;
// check edicts errors
for( i = svgame.globals->maxClients + 1; i < svgame.numEntities; i++ )
for( i = svs.maxclients + 1; i < svgame.numEntities; i++ )
{
e = EDICT_NUM( i );
@ -896,7 +896,7 @@ static edict_t *SV_PushMove( edict_t *pusher, float movetime )
sv_pushed_t *p, *pushed_p;
edict_t *check;
if( svgame.globals->changelevel || VectorIsNull( pusher->v.velocity ))
if( VectorIsNull( pusher->v.velocity ))
{
pusher->v.ltime += movetime;
return NULL;
@ -1014,7 +1014,7 @@ static edict_t *SV_PushRotate( edict_t *pusher, float movetime )
vec3_t org, org2, temp;
edict_t *check;
if( svgame.globals->changelevel || VectorIsNull( pusher->v.avelocity ))
if( VectorIsNull( pusher->v.avelocity ))
{
pusher->v.ltime += movetime;
return NULL;
@ -1800,7 +1800,7 @@ void SV_Physics( void )
if( !SV_IsValidEdict( ent ))
continue;
if( i > 0 && i <= svgame.globals->maxClients )
if( i > 0 && i <= svs.maxclients )
continue;
SV_Physics_Entity( ent );

View File

@ -32,6 +32,9 @@ void SV_ClearPhysEnts( void )
qboolean SV_PlayerIsFrozen( edict_t *pClient )
{
if( sv.background )
return true; // always freeze client on background
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
return false;

View File

@ -1060,7 +1060,7 @@ SV_SaveClientState
write out the list of premanent decals for this level
=============
*/
void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level, int changelevel )
{
string name;
file_t *pFile;
@ -1094,7 +1094,7 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
// g-cont. add space for studiodecals if present
decalList = (decallist_t *)Z_Malloc( sizeof( decallist_t ) * MAX_RENDER_DECALS * 2 );
decalCount = R_CreateDecalList( decalList, svgame.globals->changelevel );
decalCount = R_CreateDecalList( decalList );
// DECALS SECTION
sections.offsets[LUMP_DECALS_OFFSET] = FS_Tell( pFile );
@ -1175,7 +1175,7 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
}
// DYNAMIC SOUNDS SECTION (don't go across transition)
if( !svgame.globals->changelevel && ( soundCount = S_GetCurrentDynamicSounds( soundInfo, MAX_CHANNELS )) != 0 )
if( !changelevel && ( soundCount = S_GetCurrentDynamicSounds( soundInfo, MAX_CHANNELS )) != 0 )
{
sections.offsets[LUMP_SOUNDS_OFFSET] = FS_Tell( pFile );
FS_Write( pFile, &soundCount, sizeof( int ));
@ -1205,7 +1205,7 @@ void SV_SaveClientState( SAVERESTOREDATA *pSaveData, const char *level )
}
// BACKGROUND MUSIC SECTION (don't go across transition)
if( !svgame.globals->changelevel && S_StreamGetCurrentState( curtrack, looptrack, &position ))
if( !changelevel && S_StreamGetCurrentState( curtrack, looptrack, &position ))
{
byte nameSize;
@ -1440,7 +1440,7 @@ SV_SaveGameState
save current game state
=============
*/
SAVERESTOREDATA *SV_SaveGameState( void )
SAVERESTOREDATA *SV_SaveGameState( int changelevel )
{
SaveFileSectionsInfo_t sectionsInfo;
SaveFileSections_t sections;
@ -1528,12 +1528,12 @@ SAVERESTOREDATA *SV_SaveGameState( void )
SV_EntityPatchWrite( pSaveData, sv.name );
SV_SaveClientState( pSaveData, sv.name );
SV_SaveClientState( pSaveData, sv.name, changelevel );
return pSaveData;
}
int SV_LoadGameState( char const *level, qboolean createPlayers )
int SV_LoadGameState( char const *level, qboolean changelevel )
{
SAVE_HEADER header;
SAVERESTOREDATA *pSaveData;
@ -1578,7 +1578,7 @@ int SV_LoadGameState( char const *level, qboolean createPlayers )
// create entity list
if( svgame.physFuncs.pfnCreateEntitiesInRestoreList != NULL )
{
svgame.physFuncs.pfnCreateEntitiesInRestoreList( pSaveData, createPlayers );
svgame.physFuncs.pfnCreateEntitiesInRestoreList( pSaveData );
}
else
{
@ -1586,7 +1586,7 @@ int SV_LoadGameState( char const *level, qboolean createPlayers )
{
pEntInfo = &pSaveData->pTable[i];
if( pEntInfo->classname != 0 && pEntInfo->size && !( pEntInfo->flags & FENTTABLE_REMOVED ))
if( pEntInfo->classname != 0 && pEntInfo->size && !FBitSet( pEntInfo->flags, FENTTABLE_REMOVED ))
{
if( pEntInfo->id == 0 ) // worldspawn
{
@ -1597,11 +1597,11 @@ int SV_LoadGameState( char const *level, qboolean createPlayers )
SV_InitEdict( pent );
pent = SV_CreateNamedEntity( pent, pEntInfo->classname );
}
else if(( pEntInfo->id > 0 ) && ( pEntInfo->id < svgame.globals->maxClients + 1 ))
else if(( pEntInfo->id > 0 ) && ( pEntInfo->id < svs.maxclients + 1 ))
{
edict_t *ed;
if(!( pEntInfo->flags & FENTTABLE_PLAYER ))
if( !FBitSet( pEntInfo->flags, FENTTABLE_PLAYER ))
{
MsgDev( D_WARN, "ENTITY IS NOT A PLAYER: %d\n", i );
Assert( 0 );
@ -1609,9 +1609,9 @@ int SV_LoadGameState( char const *level, qboolean createPlayers )
ed = EDICT_NUM( pEntInfo->id );
if( ed && createPlayers )
if( ed != NULL )
{
Assert( ed->free == false );
ASSERT( ed->free == false );
// create the player
pent = SV_CreateNamedEntity( ed, pEntInfo->classname );
}
@ -1653,7 +1653,7 @@ int SV_LoadGameState( char const *level, qboolean createPlayers )
pent = pSaveData->pTable[bound( 0, (word)header.viewentity, pSaveData->tableCount )].pent;
// don't go camera across the levels
if( SV_IsValidEdict( pent ) && !svgame.globals->changelevel )
if( SV_IsValidEdict( pent ) && !changelevel )
sv.viewentity = NUM_FOR_EDICT( pent );
else sv.viewentity = 0;
@ -1670,6 +1670,21 @@ int SV_LoadGameState( char const *level, qboolean createPlayers )
return 1;
}
/*
=============
SV_ClearGameState
clear current game state
=============
*/
void SV_ClearGameState( void )
{
SV_ClearSaveDir();
if( svgame.dllFuncs.pfnResetGlobalState != NULL )
svgame.dllFuncs.pfnResetGlobalState();
}
// ripped out from the hl.dll
edict_t *SV_FindGlobalEntity( string_t classname, string_t globalname )
{
@ -1715,7 +1730,7 @@ int SV_CreateEntityTransitionList( SAVERESTOREDATA *pSaveData, int levelMask )
active = (pEntInfo->flags & levelMask) ? 1 : 0;
// spawn players
if(( pEntInfo->id > 0 ) && ( pEntInfo->id < svgame.globals->maxClients + 1 ))
if(( pEntInfo->id > 0 ) && ( pEntInfo->id < svs.maxclients + 1 ))
{
edict_t *ed = EDICT_NUM( pEntInfo->id );
@ -1942,11 +1957,9 @@ void SV_ChangeLevel( qboolean loadfromsavedgame, const char *mapname, const char
svgame.globals->changelevel = true;
// save the current level's state
pSaveData = SV_SaveGameState();
sv.loadgame = true;
pSaveData = SV_SaveGameState( true );
}
SV_InactivateClients ();
SV_DeactivateServer ();
if( !SV_SpawnServer( level, startspot, false ))
@ -1954,20 +1967,24 @@ void SV_ChangeLevel( qboolean loadfromsavedgame, const char *mapname, const char
if( loadfromsavedgame )
{
// Finish saving gamestate
// finish saving gamestate
SV_SaveFinish( pSaveData );
svgame.globals->changelevel = true;
SV_LevelInit( level, oldlevel, startspot, true );
sv.paused = true; // pause until all clients connect
sv.loadgame = true;
if( !SV_LoadGameState( level, true ))
SV_SpawnEntities( level, SV_EntityScript( ));
SV_LoadAdjacentEnts( oldlevel, startspot );
sv.loadgame = sv.paused = true; // pause until all clients connect
if( sv_newunit.value )
SV_ClearSaveDir();
SV_ActivateServer( false );
}
else
{
SV_LevelInit( level, NULL, NULL, false );
// classic quake changelevel
SV_SpawnEntities( level, SV_EntityScript( ));
SV_ActivateServer( true );
}
SV_ActivateServer ();
}
int SV_SaveGameSlot( const char *pSaveName, const char *pSaveComment )
@ -1979,7 +1996,7 @@ int SV_SaveGameSlot( const char *pSaveName, const char *pSaveComment )
int i, tag, tokenSize;
file_t *pFile;
pSaveData = SV_SaveGameState();
pSaveData = SV_SaveGameState( false );
if( !pSaveData ) return 0;
SV_SaveFinish( pSaveData );
@ -2127,9 +2144,7 @@ qboolean SV_LoadGame( const char *pPath )
if( !FS_FileExists( pPath, true ))
return false;
SV_ClearSaveDir();
SV_InitGameProgs();
if( !svgame.hInstance )
return false;
@ -2137,6 +2152,8 @@ qboolean SV_LoadGame( const char *pPath )
if( pFile )
{
SV_ClearGameState();
if( SV_SaveReadHeader( pFile, &gameHeader ))
{
SV_DirectoryExtract( pFile, gameHeader.mapCount );