14 Aug 2016

This commit is contained in:
g-cont 2016-08-14 00:00:00 +03:00 committed by Alibek Omarov
parent f0da5370cf
commit e9889b21ca
36 changed files with 846 additions and 333 deletions

View File

@ -476,12 +476,22 @@ void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, floa
else VectorCopy( angles, args.angles );
if( !origin || VectorIsNull( origin ))
VectorCopy( cl.frame.client.origin, args.origin );
{
if( CL_IsPredicted( )) VectorCopy( cl.predicted.origin, args.origin );
else VectorCopy( cl.frame.client.origin, args.origin );
}
else VectorCopy( origin, args.origin );
VectorCopy( cl.frame.client.velocity, args.velocity );
args.ducking = (cl.frame.playerstate[cl.playernum].usehull == 1);
// args.ducking = cl.frame.client.bInDuck;
if( CL_IsPredicted( ))
{
VectorCopy( cl.predicted.velocity, args.velocity );
args.ducking = (cl.predicted.usehull == 1);
}
else
{
VectorCopy( cl.frame.client.velocity, args.velocity );
args.ducking = cl.frame.client.bInDuck;
}
args.fparam1 = fparam1;
args.fparam2 = fparam2;

View File

@ -123,7 +123,7 @@ qboolean CL_FindInterpolationUpdates( cl_entity_t *ent, float targettime, positi
int CL_InterpolateModel( cl_entity_t *e )
{
position_history_t *ph0, *ph1;
position_history_t *ph0 = NULL, *ph1 = NULL;
vec3_t origin, angles, delta;
float t, t1, t2, frac;
int i;
@ -131,13 +131,15 @@ int CL_InterpolateModel( cl_entity_t *e )
VectorCopy( e->curstate.origin, e->origin );
VectorCopy( e->curstate.angles, e->angles );
if( e->model == NULL || cl.maxclients <= 1 )
if( !e->model || ( e->model->name[0] == '*' && !cl_bmodelinterp->integer ) || RP_LOCALCLIENT( e ) || cl.maxclients <= 1 )
return 1;
if( cl.predicted.moving && cl.predicted.onground == e->index )
return 1;
t = cl.time - cl_interp->value;
if( !CL_FindInterpolationUpdates( e, t, &ph0, &ph1, NULL ))
return 0;
CL_FindInterpolationUpdates( e, t, &ph0, &ph1, NULL );
if( ph0 == NULL || ph1 == NULL )
return 0;
@ -193,6 +195,36 @@ int CL_InterpolateModel( cl_entity_t *e )
return 1;
}
void CL_InterpolateMovingEntity( cl_entity_t *ent )
{
float d, f = 0.0f;
int i;
// don't do it if the goalstarttime hasn't updated in a while.
// NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit
// was increased to 1.0 s., which is 2x the max lag we are accounting for.
if(( cl.time < ent->curstate.animtime + 1.0f ) && ( ent->curstate.animtime != ent->latched.prevanimtime ))
f = ( cl.time - ent->curstate.animtime ) / ( ent->curstate.animtime - ent->latched.prevanimtime );
f = f - 1.0f;
ent->origin[0] += ( ent->origin[0] - ent->latched.prevorigin[0] ) * f;
ent->origin[1] += ( ent->origin[1] - ent->latched.prevorigin[1] ) * f;
ent->origin[2] += ( ent->origin[2] - ent->latched.prevorigin[2] ) * f;
for( i = 0; i < 3; i++ )
{
float ang1, ang2;
ang1 = ent->angles[i];
ang2 = ent->latched.prevangles[i];
d = ang1 - ang2;
if( d > 180.0f ) d -= 360.0f;
else if( d < -180.0f ) d += 360.0f;
ent->angles[i] += d * f;
}
}
void CL_UpdateEntityFields( cl_entity_t *ent )
{
// parametric rockets code
@ -218,7 +250,11 @@ void CL_UpdateEntityFields( cl_entity_t *ent )
ent->angles[PITCH] = -ent->angles[PITCH] / 3.0f;
// make me lerp
if( ent->model && ent->model->type == mod_brush && ent->curstate.animtime != 0.0f )
if( ent->index == cl.predicted.onground && cl.predicted.moving )
{
CL_InterpolateMovingEntity( ent );
}
else if( ent->model && ent->model->type == mod_brush && ent->curstate.animtime != 0.0f)
{
float d, f = 0.0f;
int i;
@ -324,7 +360,7 @@ void CL_UpdateEntityFields( cl_entity_t *ent )
}
}
// move code from StudioSetupTransform here
// moved code from StudioSetupTransform here
if( host.features & ENGINE_COMPUTE_STUDIO_LERP )
{
ent->origin[0] += ( ent->curstate.origin[0] - ent->latched.prevorigin[0] ) * f;
@ -516,10 +552,6 @@ void CL_WeaponAnim( int iAnim, int body )
cl.weaponstarttime = 0;
cl.weaponsequence = iAnim;
if( Host_IsLocalClient() || cl_predict->value || !cl_lw->value )
view->curstate.modelindex = cl.frame.client.viewmodel;
else view->curstate.modelindex = cl.predicted_viewmodel;
// anim is changed. update latchedvars
if( iAnim != view->curstate.sequence )
{
@ -749,6 +781,8 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t
/*
=================
CL_FlushEntityPacket
Read and ignore whole entity packet.
=================
*/
void CL_FlushEntityPacket( sizebuf_t *msg )
@ -756,7 +790,6 @@ void CL_FlushEntityPacket( sizebuf_t *msg )
int newnum;
entity_state_t from, to;
MsgDev( D_INFO, "FlushEntityPacket()\n" );
Q_memset( &from, 0, sizeof( from ));
cl.frames[cl.parsecountmod].valid = false;
@ -1003,23 +1036,34 @@ CL_SetIdealPitch
void CL_SetIdealPitch( void )
{
float angleval, sinval, cosval;
vec3_t top, bottom;
float z[MAX_FORWARD];
float z[MAX_FORWARD], view_z;
vec3_t top, bottom, origin;
int i, j;
int step, dir, steps;
pmtrace_t tr;
if( !( cl.frame.client.flags & FL_ONGROUND ))
return;
if( CL_IsPredicted( ))
{
VectorCopy( cl.predicted.origin, origin );
view_z = cl.predicted.viewofs[2];
}
else
{
VectorCopy( cl.frame.client.origin, origin );
view_z = cl.frame.client.view_ofs[2];
}
angleval = cl.frame.playerstate[cl.playernum].angles[YAW] * M_PI2 / 360.0f;
SinCos( angleval, &sinval, &cosval );
for( i = 0; i < MAX_FORWARD; i++ )
{
top[0] = cl.frame.client.origin[0] + cosval * (i + 3.0f) * 12.0f;
top[1] = cl.frame.client.origin[1] + sinval * (i + 3.0f) * 12.0f;
top[2] = cl.frame.client.origin[2] + cl.frame.client.view_ofs[2];
top[0] = origin[0] + cosval * (i + 3.0f) * 12.0f;
top[1] = origin[1] + sinval * (i + 3.0f) * 12.0f;
top[2] = origin[2] + view_z;
bottom[0] = top[0];
bottom[1] = top[1];

View File

@ -1226,7 +1226,8 @@ HSPRITE pfnSPR_LoadExt( const char *szPicName, uint texFlags )
// load new model
if( CL_LoadHudSprite( name, &clgame.sprites[i], false, texFlags ))
{
clgame.sprites[i].needload = clgame.load_sequence;
if( i < ( MAX_IMAGES - 1 ))
clgame.sprites[i].needload = clgame.load_sequence;
return i;
}
return 0;
@ -2217,6 +2218,8 @@ pfnLocalPlayerDucking
*/
int pfnLocalPlayerDucking( void )
{
if( CL_IsPredicted( ))
return (cl.predicted.usehull == 1);
return cl.frame.client.bInDuck;
}
@ -2232,7 +2235,7 @@ void pfnLocalPlayerViewheight( float *view_ofs )
if( !view_ofs ) return;
if( CL_IsPredicted( ))
VectorCopy( cl.predicted_viewofs, view_ofs );
VectorCopy( cl.predicted.viewofs, view_ofs );
else VectorCopy( cl.frame.client.view_ofs, view_ofs );
}
@ -2283,94 +2286,6 @@ physent_t *pfnGetPhysent( int idx )
return NULL;
}
/*
=============
pfnSetUpPlayerPrediction
FIXME: finalize
=============
*/
void pfnSetUpPlayerPrediction( int dopred, int bIncludeLocalClient )
{
#if 0
entity_state_t *playerstate = cl.frames[cl.parsecountmod].playerstate;
predicted_player_t *player = cls.predicted_players;
cl_entity_t *clent;
int j, v12;
for( j = 0; j < MAX_CLIENTS; j++, player++, playerstate++ )
{
player->active = false;
if( playerstate->messagenum != cl.parsecount )
continue; // not present this frame
if( !playerstate->modelindex )
continue;
// special for EF_NODRAW and local client?
if(( playerstate->effects & EF_NODRAW ) && !bIncludeLocalClient )
{
// don't include local player?
if( cl.playernum != j )
{
player->active = true;
player->movetype = playerstate->movetype;
player->solid = playerstate->solid;
player->usehull = playerstate->usehull;
clent = CL_EDICT_NUM( j + 1 );
// CL_ComputePlayerOrigin( v9 );
VectorCopy( clent->origin, player->origin );
VectorCopy( clent->angles, player->angles );
}
else continue;
}
else
{
if( cl.playernum == j )
continue;
player->active = true;
player->movetype = playerstate->movetype;
player->solid = playerstate->solid;
player->usehull = playerstate->usehull;
v12 = 17080 * cl.parsecountmod + 340 * j;
player->origin[0] = cl.frames[0].playerstate[0].origin[0] + v12;
player->origin[1] = cl.frames[0].playerstate[0].origin[1] + v12;
player->origin[2] = cl.frames[0].playerstate[0].origin[2] + v12;
player->angles[0] = cl.frames[0].playerstate[0].angles[0] + v12;
player->angles[1] = cl.frames[0].playerstate[0].angles[1] + v12;
player->angles[2] = cl.frames[0].playerstate[0].angles[2] + v12;
}
}
#endif
}
/*
=============
pfnPushPMStates
=============
*/
void pfnPushPMStates( void )
{
clgame.oldcount = clgame.pmove->numphysent;
}
/*
=============
pfnPopPMStates
=============
*/
void pfnPopPMStates( void )
{
clgame.pmove->numphysent = clgame.oldcount;
}
/*
=============
pfnSetTraceHull
@ -2612,7 +2527,7 @@ const char *PlayerInfo_ValueForKey( int playerNum, const char *key )
if(( playerNum > cl.maxclients ) || ( playerNum < 1 ))
return NULL;
if(( cl.players[playerNum-1].name == NULL ) || (*(cl.players[playerNum-1].name) == 0 ))
if( !cl.players[playerNum-1].name[0] )
return NULL;
return Info_ValueForKey( cl.players[playerNum-1].userinfo, key );
@ -3351,7 +3266,8 @@ TriForParams
*/
void TriFogParams( float flDensity, int iFogSkybox )
{
// TODO: implement
RI.fogDensity = flDensity;
RI.fogCustom = iFogSkybox;
}
/*
@ -3787,9 +3703,9 @@ static event_api_t gEventApi =
pfnLocalPlayerBounds,
pfnIndexFromTrace,
pfnGetPhysent,
pfnSetUpPlayerPrediction,
pfnPushPMStates,
pfnPopPMStates,
CL_SetUpPlayerPrediction,
CL_PushPMStates,
CL_PopPMStates,
CL_SetSolidPlayers,
CL_SetTraceHull,
CL_PlayerTrace,

View File

@ -30,7 +30,8 @@ GNU General Public License for more details.
convar_t *rcon_client_password;
convar_t *rcon_address;
convar_t *cl_smooth;
convar_t *cl_nosmooth;
convar_t *cl_smoothtime;
convar_t *cl_timeout;
convar_t *cl_predict;
convar_t *cl_showfps;
@ -38,6 +39,7 @@ convar_t *cl_nodelta;
convar_t *cl_crosshair;
convar_t *cl_cmdbackup;
convar_t *cl_showerror;
convar_t *cl_bmodelinterp;
convar_t *cl_draw_particles;
convar_t *cl_lightstyle_lerping;
convar_t *cl_idealpitchscale;
@ -305,27 +307,22 @@ void CL_CreateCmd( void )
Q_memset( &cmd, 0, sizeof( cmd ));
// build list of all solid entities per next frame (exclude clients)
CL_SetSolidEntities ();
CL_SetSolidPlayers ( cl.playernum );
CL_SetSolidEntities();
CL_PushPMStates();
CL_SetSolidPlayers( cl.playernum );
VectorCopy( cl.refdef.cl_viewangles, angles );
VectorCopy( cl.frame.client.origin, cl.data.origin );
VectorCopy( cl.refdef.cl_viewangles, cl.data.viewangles );
cl.data.iWeaponBits = cl.frame.client.weapons;
if( cl.scr_fov < 1.0f || cl.scr_fov > 179.0f )
cl.scr_fov = 90.0f; // reset to default
cl.data.fov = cl.scr_fov;
clgame.dllFuncs.pfnUpdateClientData( &cl.data, cl.time );
// grab changes
VectorCopy( cl.data.viewangles, cl.refdef.cl_viewangles );
cl.frame.client.weapons = cl.data.iWeaponBits;
cl.scr_fov = cl.data.fov;
if( cl.scr_fov < 1.0f || cl.scr_fov > 179.0f )
cl.scr_fov = 90.0f; // reset to default
if( clgame.dllFuncs.pfnUpdateClientData( &cl.data, cl.time ))
{
// grab changes if successful
VectorCopy( cl.data.viewangles, cl.refdef.cl_viewangles );
cl.scr_fov = cl.data.fov;
}
// allways dump the first ten messages,
// because it may contain leftover inputs
@ -337,6 +334,8 @@ void CL_CreateCmd( void )
cl.refdef.cmd = &cl.commands[cls.netchan.outgoing_sequence & CL_UPDATE_MASK].cmd;
*cl.refdef.cmd = cmd;
}
CL_PopPMStates();
return;
}
@ -354,6 +353,7 @@ void CL_CreateCmd( void )
active = ( cls.state == ca_active && !cl.refdef.paused && !cls.demoplayback );
clgame.dllFuncs.CL_CreateMove( cl.time - cl.oldtime, &pcmd->cmd, active );
CL_PopPMStates();
R_LightForPoint( cl.frame.client.origin, &color, false, false, 128.0f );
pcmd->cmd.lightlevel = (color.r + color.g + color.b) / 3;
@ -523,7 +523,6 @@ void CL_WritePacket( void )
for( i = numcmds - 1; i >= 0; i-- )
{
cmdnumber = ( cls.netchan.outgoing_sequence - i ) & CL_UPDATE_MASK;
if( i == 0 ) cl.commands[cmdnumber].processedfuncs = true; // only last cmd allow to run funcs
to = cmdnumber;
CL_WriteUsercmd( &buf, from, to );
@ -722,7 +721,7 @@ void CL_Connect_f( void )
return;
}
Q_strncpy( server, Cmd_Argv( 1 ), sizeof( cls.servername ));
Q_strncpy( server, Cmd_Argv( 1 ), sizeof( server ));
if( Host_ServerState())
{
@ -950,7 +949,7 @@ CL_InternetServers_f
void CL_InternetServers_f( void )
{
netadr_t adr;
char fullquery[512] = "\x31\xFF" "0.0.0.0:0\0" "\\gamedir\\";
char fullquery[512] = "1\xFF" "0.0.0.0:0\0" "\\gamedir\\";
MsgDev( D_INFO, "Scanning for servers on the internet area...\n" );
NET_Config( true ); // allow remote
@ -958,9 +957,9 @@ void CL_InternetServers_f( void )
if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ) )
MsgDev( D_INFO, "Can't resolve adr: %s\n", MASTERSERVER_ADR );
Q_strcpy( &fullquery[21], GI->gamedir );
Q_strcpy( &fullquery[22], GI->gamedir );
NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamedir ) + 22, fullquery, adr );
NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamedir ) + 23, fullquery, adr );
}
/*
@ -1074,9 +1073,10 @@ Handle a reply from a info
*/
void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
{
char *s;
char *s = BF_ReadString( msg );
s = BF_ReadString( msg );
// more info about servers
MsgDev( D_INFO, "Server: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( s, "gamedir" ));
UI_AddServerToList( from, s );
}
@ -1395,26 +1395,21 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
// dropped the connection but it is still getting packets from us
CL_Disconnect();
}
else if( msg->pData[0] == 0xFF && msg->pData[1] == 0xFF && msg->pData[2] == 0xFF && msg->pData[3] == 0xFF && msg->pData[4] == 0x66 && msg->pData[5] == 0x0A )
else if( !Q_strcmp( c, "f" ))
{
dataoffset = 6;
while( 1 )
// serverlist got from masterserver
while( !msg->bOverflow )
{
servadr.type = NA_IP;
Q_memcpy( servadr.ip, &msg->pData[dataoffset], sizeof(servadr.ip));
servadr.port = *(word *)&msg->pData[dataoffset + 4];
// 4 bytes for IP
BF_ReadBytes( msg, servadr.ip, sizeof( servadr.ip ));
// 2 bytes for Port
servadr.port = BF_ReadShort( msg );
if( !servadr.port )
break;
MsgDev( D_INFO, "Found server: %s\n", NET_AdrToString( servadr ));
if( !servadr.port ) break;
NET_Config( true ); // allow remote
Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION );
dataoffset += 6;
}
}
else if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
@ -1670,13 +1665,15 @@ void CL_InitLocal( void )
rate = Cvar_Get( "rate", "25000", CVAR_USERINFO|CVAR_ARCHIVE, "player network rate" );
hltv = Cvar_Get( "hltv", "0", CVAR_USERINFO|CVAR_LATCH, "HLTV mode" );
cl_showfps = Cvar_Get( "cl_showfps", "1", CVAR_ARCHIVE, "show client fps" );
cl_smooth = Cvar_Get ("cl_smooth", "0", CVAR_ARCHIVE, "smooth up stair climbing and interpolate position in multiplayer" );
cl_nosmooth = Cvar_Get( "cl_nosmooth", "0", CVAR_ARCHIVE, "disable smooth up stair climbing and interpolate position in multiplayer" );
cl_smoothtime = Cvar_Get( "cl_smoothtime", "0.1", CVAR_ARCHIVE, "time to smooth up" );
cl_cmdbackup = Cvar_Get( "cl_cmdbackup", "10", CVAR_ARCHIVE, "how many additional history commands are sent" );
cl_cmdrate = Cvar_Get( "cl_cmdrate", "30", CVAR_ARCHIVE, "Max number of command packets sent to server per second" );
cl_draw_particles = Cvar_Get( "cl_draw_particles", "1", CVAR_ARCHIVE, "Disable any particle effects" );
cl_draw_beams = Cvar_Get( "cl_draw_beams", "1", CVAR_ARCHIVE, "Disable view beams" );
cl_lightstyle_lerping = Cvar_Get( "cl_lightstyle_lerping", "0", CVAR_ARCHIVE, "enables animated light lerping (perfomance option)" );
cl_showerror = Cvar_Get( "cl_showerror", "0", CVAR_ARCHIVE, "show prediction error" );
cl_bmodelinterp = Cvar_Get( "cl_bmodelinterp", "1", CVAR_ARCHIVE, "enable bmodel interpolation" );
Cvar_Get( "hud_scale", "0", CVAR_ARCHIVE|CVAR_LATCH, "scale hud at current resolution" );
Cvar_Get( "skin", "", CVAR_USERINFO, "player skin" ); // XDM 3.3 want this cvar

View File

@ -29,6 +29,120 @@ void CL_ClearPhysEnts( void )
clgame.pmove->numphysent = 0;
}
/*
=============
CL_PushPMStates
=============
*/
void CL_PushPMStates( void )
{
if( clgame.pushed )
{
MsgDev( D_ERROR, "PushPMStates called with pushed stack\n");
}
else
{
clgame.oldphyscount = clgame.pmove->numphysent;
clgame.oldviscount = clgame.pmove->numvisent;
clgame.pushed = true;
}
}
/*
=============
CL_PopPMStates
=============
*/
void CL_PopPMStates( void )
{
if( clgame.pushed )
{
clgame.pmove->numphysent = clgame.oldphyscount;
clgame.pmove->numvisent = clgame.oldviscount;
clgame.pushed = false;
}
else
{
MsgDev( D_ERROR, "PopPMStates called without stack\n");
}
}
/*
=============
CL_ComputePlayerOrigin
FIXME: implement
=============
*/
void CL_ComputePlayerOrigin( cl_entity_t *clent )
{
}
/*
=============
CL_SetUpPlayerPrediction
=============
*/
void CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient )
{
entity_state_t *state;
predicted_player_t *player;
cl_entity_t *clent;
int i;
for( i = 0; i < MAX_CLIENTS; i++ )
{
state = &cl.frames[cl.parsecountmod].playerstate[i];
player = &cls.predicted_players[i];
player->active = false;
if( state->messagenum != cl.parsecount )
continue; // not present this frame
if( !state->modelindex )
continue;
clent = CL_GetEntityByIndex( i + 1 );
// special for EF_NODRAW and local client?
if(( state->effects & EF_NODRAW ) && !bIncludeLocalClient )
{
// don't include local player?
if( cl.playernum == i )
continue;
player->active = true;
player->movetype = state->movetype;
player->solid = state->solid;
player->usehull = state->usehull;
CL_ComputePlayerOrigin( clent );
VectorCopy( clent->origin, player->origin );
VectorCopy( clent->angles, player->angles );
}
else
{
player->active = true;
player->movetype = state->movetype;
player->solid = state->solid;
player->usehull = state->usehull;
// don't rewrite origin and angles of local client
if( cl.playernum == i )
continue;
VectorCopy( state->origin, player->origin );
VectorCopy( state->angles, player->angles );
}
}
}
void CL_ClipPMoveToEntity( physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, pmtrace_t *tr )
{
ASSERT( tr != NULL );
@ -211,25 +325,32 @@ pmove must be setup with world and solid entity hulls before calling
*/
void CL_SetSolidPlayers( int playernum )
{
int j;
extern vec3_t player_mins;
extern vec3_t player_maxs;
entity_state_t *state;
cl_entity_t *ent;
physent_t *pe;
int i;
if( !cl_solid_players->integer )
return;
for( j = 0; j < cl.maxclients; j++ )
for( i = 0; i < cl.maxclients; i++ )
{
// the player object never gets added
if( j == playernum ) continue;
if( i == playernum ) continue;
ent = CL_GetEntityByIndex( j + 1 );
ent = CL_GetEntityByIndex( i + 1 );
if( !ent || !ent->player )
continue; // not present this frame
state = cl.frames[cl.parsecountmod].playerstate + i;
if( state->effects & EF_NODRAW )
continue; // skip invisible
if( !state->solid )
continue; // not solid
pe = &clgame.pmove->physents[clgame.pmove->numphysent];
if( CL_CopyEntityToPhysEnt( pe, ent ))
clgame.pmove->numphysent++;
@ -858,6 +979,10 @@ void CL_RunUsercmd( local_state_t *from, local_state_t *to, usercmd_t *u, qboole
// copy results back to client
CL_FinishPMove( clgame.pmove, to );
cl.predicted.lastground = clgame.pmove->onground;
if( cl.predicted.lastground > 0 && cl.predicted.lastground < clgame.pmove->numphysent )
cl.predicted.lastground = clgame.pmove->physents[cl.predicted.lastground].info;
clgame.dllFuncs.pfnPostRunCmd( from, to, &cmd, runfuncs, *time, random_seed );
*time += (double)cmd.msec / 1000.0;
}
@ -879,26 +1004,30 @@ void CL_CheckPredictionError( void )
frame = ( cls.netchan.incoming_acknowledged ) & CL_UPDATE_MASK;
// compare what the server returned with what we had predicted it to be
VectorSubtract( cl.frame.playerstate[cl.playernum].origin, cl.predicted_origins[frame], delta );
VectorSubtract( cl.frame.playerstate[cl.playernum].origin, cl.predicted.origins[frame], delta );
maxspd = ( clgame.movevars.maxvelocity * host.frametime );
len = VectorLength( delta );
// save the prediction error for interpolation
if(( cl.frame.client.flags & EF_NOINTERP ) || len > maxspd )
// if(( cl.frame.client.flags & EF_NOINTERP ) || len > maxspd )
if( len > 64.0f )
{
// a teleport or something or gamepaused
VectorClear( cl.prediction_error );
VectorClear( cl.predicted.error );
}
else
{
if( cl_showerror->value && len > 0.5f )
MsgDev( D_ERROR, "prediction error on %i: %g\n", cl.parsecount, len );
VectorCopy( cl.frame.playerstate[cl.playernum].origin, cl.predicted_origins[frame] );
VectorCopy( cl.frame.playerstate[cl.playernum].origin, cl.predicted.origins[frame] );
// save for error itnerpolation
VectorCopy( delta, cl.prediction_error );
// save for error interpolation
VectorCopy( delta, cl.predicted.error );
if(( len > 0.25f ) && ( cl.maxclients > 1 ))
cl.predicted.correction_time = cl_smoothtime->value;
}
}
@ -913,7 +1042,9 @@ void CL_PostRunCmd( usercmd_t *ucmd, int random_seed )
{
local_state_t from, to;
memcpy( from.weapondata, cl.frame.weapondata, sizeof( from.weapondata ));
Q_memset( &from, 0, sizeof( local_state_t ));
Q_memset( &to, 0, sizeof( local_state_t ));
Q_memcpy( from.weapondata, cl.frame.weapondata, sizeof( from.weapondata ));
from.playerstate = cl.frame.playerstate[cl.playernum];
from.client = cl.frame.client;
to = from;
@ -921,6 +1052,35 @@ void CL_PostRunCmd( usercmd_t *ucmd, int random_seed )
clgame.dllFuncs.pfnPostRunCmd( &from, &to, ucmd, true, cl.time, random_seed );
}
/*
=================
CL_FakeUsercmd
Runs client weapons prediction code
=================
*/
void CL_FakeUsercmd( local_state_t *from, local_state_t *to, usercmd_t *u, qboolean runfuncs, double *pfElapsed, unsigned int random_seed )
{
usercmd_t cmd;
local_state_t temp;
usercmd_t split;
while( u->msec > 50 )
{
split = *u;
split.msec /= 2;
CL_FakeUsercmd( from, &temp, &split, runfuncs, pfElapsed, random_seed );
from = &temp;
u = &split;
}
cmd = *u;
*to = *from;
clgame.dllFuncs.pfnPostRunCmd( from, to, &cmd, runfuncs, *pfElapsed, random_seed );
*pfElapsed += cmd.msec / 1000.0;
}
/*
=================
CL_PredictMovement
@ -949,15 +1109,62 @@ void CL_PredictMovement( void )
if( !CL_IsInGame( )) return;
CL_SetUpPlayerPrediction( false, false );
// unpredicted pure angled values converted into axis
AngleVectors( cl.refdef.cl_viewangles, cl.refdef.forward, cl.refdef.right, cl.refdef.up );
ASSERT( cl.refdef.cmd != NULL );
if( !CL_IsPredicted( ))
{
// run commands even if client predicting is disabled - client expected it
CL_PostRunCmd( cl.refdef.cmd, cls.lastoutgoingcommand );
{
// fake prediction code
// we need to perform cl_lw prediction while cl_predict is disabled
// because cl_lw is enabled by default in Half-Life
if( !cl_lw->integer )
{
cl.predicted.viewmodel = cl.frame.client.viewmodel;
return;
}
ack = cls.netchan.incoming_acknowledged;
outgoing_command = cls.netchan.outgoing_sequence;
from = &cl.predict[cl.parsecountmod];
from->playerstate = cl.frame.playerstate[cl.playernum];
from->client = cl.frame.client;
Q_memcpy( from->weapondata, cl.frame.weapondata, sizeof( from->weapondata ));
time = cl.frame.time;
while( 1 )
{
// we've run too far forward
if( frame >= ( CL_UPDATE_BACKUP - 1 ))
break;
// Incoming_acknowledged is the last usercmd the server acknowledged having acted upon
current_command = ack + frame;
current_command_mod = current_command & CL_UPDATE_MASK;
// we've caught up to the current command.
if( current_command >= outgoing_command )
break;
to = &cl.predict[( cl.parsecountmod + frame ) & CL_UPDATE_MASK];
CL_FakeUsercmd( from, to, &cl.commands[current_command_mod].cmd,
!cl.commands[current_command_mod].processedfuncs,
&time, cls.netchan.incoming_acknowledged + frame );
cl.commands[current_command_mod].processedfuncs = true;
from = to;
frame++;
}
if( to )
cl.predicted.viewmodel = to->client.viewmodel;
return;
}
@ -965,7 +1172,7 @@ void CL_PredictMovement( void )
outgoing_command = cls.netchan.outgoing_sequence;
from = &cl.predict[cl.parsecountmod];
memcpy( from->weapondata, cl.frame.weapondata, sizeof( from->weapondata ));
Q_memcpy( from->weapondata, cl.frame.weapondata, sizeof( from->weapondata ));
from->playerstate = cl.frame.playerstate[cl.playernum];
from->client = cl.frame.client;
@ -996,7 +1203,7 @@ void CL_PredictMovement( void )
cl.commands[current_command_mod].processedfuncs = true;
// save for debug checking
VectorCopy( to->playerstate.origin, cl.predicted_origins[current_command_mod] );
VectorCopy( to->playerstate.origin, cl.predicted.origins[current_command_mod] );
from = to;
frame++;
@ -1004,15 +1211,109 @@ void CL_PredictMovement( void )
if( to )
{
VectorCopy( to->playerstate.origin, cl.predicted_origin );
VectorCopy( to->client.velocity, cl.predicted_velocity );
VectorCopy( to->client.view_ofs, cl.predicted_viewofs );
VectorCopy( to->client.punchangle, cl.predicted_punchangle );
float t0 = cl.commands[( cl.parsecountmod + frame - 1) & CL_UPDATE_MASK].senttime;
float t1 = cl.commands[( cl.parsecountmod + frame ) & CL_UPDATE_MASK].senttime;
float t;
cl.predicted_viewmodel = to->client.viewmodel;
cl.scr_fov = to->client.fov;
if( t0 == t1 )
{
t = 0.0f;
}
else
{
t = (host.realtime - t0) / (t1 - t0);
t = bound( 0.0f, t, 1.0f );
}
if( cl.scr_fov < 1.0f || cl.scr_fov > 179.0f )
cl.scr_fov = 90.0f;
// was teleported
if( fabs( to->playerstate.origin[0] - from->playerstate.origin[0] ) > 128.0f ||
fabs( to->playerstate.origin[1] - from->playerstate.origin[1] ) > 128.0f ||
fabs( to->playerstate.origin[2] - from->playerstate.origin[2] ) > 128.0f )
{
VectorCopy( to->playerstate.origin, cl.predicted.origin );
VectorCopy( to->client.velocity, cl.predicted.velocity );
VectorCopy( to->client.punchangle, cl.predicted.punchangle );
VectorCopy( to->client.view_ofs, cl.predicted.viewofs );
}
else
{
vec3_t delta_origin, delta_punch, delta_vel;
VectorSubtract( to->playerstate.origin, from->playerstate.origin, delta_origin );
VectorSubtract( to->client.velocity, from->client.velocity, delta_vel );
VectorSubtract( to->client.punchangle, from->client.punchangle, delta_punch );
VectorMA( from->playerstate.origin, t, delta_origin, cl.predicted.origin );
VectorMA( from->client.velocity, t, delta_vel, cl.predicted.velocity );
VectorMA( from->client.punchangle, t, delta_punch, cl.predicted.punchangle );
if( from->playerstate.usehull == to->playerstate.usehull )
{
vec3_t delta_viewofs;
VectorSubtract( to->client.view_ofs, from->client.view_ofs, delta_viewofs );
VectorMA( from->client.view_ofs, t, delta_viewofs, cl.predicted.viewofs );
}
}
cl.predicted.waterlevel = to->client.waterlevel;
cl.predicted.viewmodel = to->client.viewmodel;
cl.predicted.usehull = to->playerstate.usehull;
if( to->client.flags & FL_ONGROUND )
{
cl_entity_t *ent = CL_GetEntityByIndex( cl.predicted.lastground );
cl.predicted.onground = cl.predicted.lastground;
cl.predicted.moving = 0;
if( ent )
{
vec3_t delta;
delta[0] = ent->curstate.origin[0] - ent->prevstate.origin[0];
delta[1] = ent->curstate.origin[1] - ent->prevstate.origin[1];
delta[2] = 0.0f;
if( VectorLength( delta ) > 0.0f )
{
cl.predicted.correction_time = 0;
cl.predicted.moving = 1;
}
}
}
else
{
cl.predicted.onground = -1;
cl.predicted.moving = 0;
}
if ( cl.predicted.correction_time > 0.0 && !cl_nosmooth->value && cl_smoothtime->value )
{
float d;
int i;
cl.predicted.correction_time = cl.predicted.correction_time - host.frametime;
if( cl_smoothtime->value <= 0 )
Cvar_SetFloat( "cl_smoothtime", 0.1 );
if( cl.predicted.correction_time < 0 )
cl.predicted.correction_time = 0;
if( cl_smoothtime->value <= cl.predicted.correction_time )
cl.predicted.correction_time = cl_smoothtime->value;
d = cl.predicted.correction_time / cl_smoothtime->value;
for( i = 0; i < 3; i++ )
{
cl.predicted.origin[i] = cl.predicted.lastorigin[i] + ( cl.predicted.origin[i] - cl.predicted.lastorigin[i] ) * (1.0 - d);
}
}
VectorCopy( cl.predicted.origin, cl.predicted.lastorigin );
CL_SetIdealPitch();
}
CL_CheckPredictionError();
}

View File

@ -527,7 +527,7 @@ void CL_Bubbles( const vec3_t mins, const vec3_t maxs, float height, int modelIn
pTemp->x = origin[0];
pTemp->y = origin[1];
angle = Com_RandomLong( -M_PI, M_PI );
angle = Com_RandomFloat( -M_PI, M_PI );
SinCos( angle, &sine, &cosine );
zspeed = Com_RandomLong( 80, 140 );
@ -572,7 +572,7 @@ void CL_BubbleTrail( const vec3_t start, const vec3_t end, float flWaterZ, int m
pTemp->x = origin[0];
pTemp->y = origin[1];
angle = Com_RandomLong( -M_PI, M_PI );
angle = Com_RandomFloat( -M_PI, M_PI );
zspeed = Com_RandomLong( 80, 140 );
VectorSet( pTemp->entity.baseline.origin, speed * cos( angle ), speed * sin( angle ), zspeed );
@ -2653,7 +2653,7 @@ int CL_DecalIndexFromName( const char *name )
return 0;
// look through the loaded sprite name list for SpriteName
for( i = 0; i < MAX_DECALS && host.draw_decals[i+1][0]; i++ )
for( i = 0; i < (MAX_DECALS - 1) && host.draw_decals[i+1][0]; i++ )
{
if( !Q_stricmp( name, host.draw_decals[i+1] ))
return i+1;

View File

@ -36,14 +36,14 @@ void V_SetupRefDef( void )
clent = CL_GetLocalPlayer ();
clgame.entities->curstate.scale = clgame.movevars.waveHeight;
clgame.viewent.curstate.modelindex = cl.frame.client.viewmodel;
if( cl_lw->value ) clgame.viewent.curstate.modelindex = cl.predicted.viewmodel;
else clgame.viewent.curstate.modelindex = cl.frame.client.viewmodel;
clgame.viewent.model = Mod_Handle( clgame.viewent.curstate.modelindex );
clgame.viewent.curstate.number = cl.playernum + 1;
clgame.viewent.curstate.entityType = ET_NORMAL;
clgame.viewent.index = cl.playernum + 1;
cl.refdef.movevars = &clgame.movevars;
cl.refdef.onground = ( cl.frame.client.flags & FL_ONGROUND ) ? 1 : 0;
cl.refdef.health = cl.frame.client.health;
cl.refdef.playernum = cl.playernum;
cl.refdef.max_entities = clgame.maxEntities;
@ -51,12 +51,11 @@ void V_SetupRefDef( void )
cl.refdef.time = cl.time;
cl.refdef.frametime = cl.time - cl.oldtime;
cl.refdef.demoplayback = cls.demoplayback;
cl.refdef.smoothing = cl_smooth->integer;
cl.refdef.viewsize = scr_viewsize->integer;
cl.refdef.waterlevel = cl.frame.client.waterlevel;
cl.refdef.onlyClientDraw = 0; // reset clientdraw
cl.refdef.hardware = true; // always true
cl.refdef.spectator = (clent->curstate.spectator != 0);
cl.refdef.smoothing = false; // old stuff to smooth multiplayer view
cl.refdef.nextView = 0;
SCR_AddDirtyPoint( 0, 0 );
@ -81,8 +80,7 @@ void V_SetupRefDef( void )
cl.refdef.viewport[0] = (scr_width->integer - cl.refdef.viewport[2]) / 2;
cl.refdef.viewport[1] = (scr_height->integer - sb_lines - cl.refdef.viewport[3]) / 2;
if( cl.scr_fov < 1.0f || cl.scr_fov > 179.0f )
cl.scr_fov = 90.0f;
cl.scr_fov = bound( 1.0f, cl.scr_fov, 179.0f );
// calc FOV
cl.refdef.fov_x = cl.scr_fov; // this is a final fov value
@ -94,11 +92,12 @@ void V_SetupRefDef( void )
if( CL_IsPredicted( ) && !cl.refdef.demoplayback )
{
VectorMA( cl.predicted_origin, -cl.lerpBack, cl.prediction_error, cl.refdef.simorg );
VectorCopy( cl.predicted_origin, cl.refdef.simorg );
VectorCopy( cl.predicted_velocity, cl.refdef.simvel );
VectorCopy( cl.predicted_viewofs, cl.refdef.viewheight );
VectorCopy( cl.predicted_punchangle, cl.refdef.punchangle );
VectorCopy( cl.predicted.origin, cl.refdef.simorg );
VectorCopy( cl.predicted.velocity, cl.refdef.simvel );
VectorCopy( cl.predicted.viewofs, cl.refdef.viewheight );
VectorCopy( cl.predicted.punchangle, cl.refdef.punchangle );
cl.refdef.onground = ( cl.predicted.onground == -1 ) ? false : true;
cl.refdef.waterlevel = cl.predicted.waterlevel;
}
else
{
@ -106,6 +105,8 @@ void V_SetupRefDef( void )
VectorCopy( cl.frame.client.view_ofs, cl.refdef.viewheight );
VectorCopy( cl.frame.client.velocity, cl.refdef.simvel );
VectorCopy( cl.frame.client.punchangle, cl.refdef.punchangle );
cl.refdef.onground = (cl.frame.client.flags & FL_ONGROUND) ? 1 : 0;
cl.refdef.waterlevel = cl.frame.client.waterlevel;
}
}

View File

@ -87,6 +87,24 @@ extern int CL_UPDATE_BACKUP;
#define INVALID_HANDLE 0xFFFF // for XashXT cache system
typedef struct
{
vec3_t origin; // generated by CL_PredictMovement
vec3_t viewofs;
vec3_t velocity;
vec3_t punchangle;
vec3_t origins[CMD_BACKUP];
vec3_t error;
vec3_t lastorigin;
double correction_time;
int viewmodel;
int onground;
int waterlevel;
int usehull;
int moving;
int lastground;
} cl_predicted_data_t; // data we got from prediction system
// the client_t structure is wiped completely at every
// server map change
typedef struct
@ -140,12 +158,7 @@ typedef struct
event_state_t events;
// predicting stuff
vec3_t predicted_origin; // generated by CL_PredictMovement
vec3_t predicted_viewofs;
vec3_t predicted_velocity;
vec3_t predicted_punchangle;
vec3_t predicted_origins[CMD_BACKUP];
vec3_t prediction_error;
cl_predicted_data_t predicted; // generated from CL_PredictMovement
// server state information
int playernum;
@ -166,7 +179,6 @@ typedef struct
// weapon predict stuff
float scr_fov;
int predicted_viewmodel;
float weaponstarttime;
int weaponsequence;
} client_t;
@ -357,8 +369,10 @@ typedef struct
movevars_t oldmovevars;
playermove_t *pmove; // pmove state
int old_trace_hull; // used by PM_Push\Pop state
int oldcount; // used by PM_Push\Pop state
int old_trace_hull; // used by PM_Push\Pop state
qboolean pushed; // used by PM_Push\Pop state
int oldviscount; // used by PM_Push\Pop state
int oldphyscount; // used by PM_Push\Pop state
vec3_t player_mins[MAX_MAP_HULLS]; // 4 hulls allowed
vec3_t player_maxs[MAX_MAP_HULLS]; // 4 hulls allowed
@ -518,13 +532,14 @@ extern menu_static_t menu;
// cvars
//
extern convar_t *cl_predict;
extern convar_t *cl_smooth;
extern convar_t *cl_showfps;
extern convar_t *cl_envshot_size;
extern convar_t *cl_timeout;
extern convar_t *cl_nodelta;
extern convar_t *cl_interp;
extern convar_t *cl_showerror;
extern convar_t *cl_nosmooth;
extern convar_t *cl_smoothtime;
extern convar_t *cl_crosshair;
extern convar_t *cl_testlights;
extern convar_t *cl_solid_players;
@ -534,6 +549,7 @@ extern convar_t *cl_lightstyle_lerping;
extern convar_t *cl_draw_particles;
extern convar_t *cl_levelshot_name;
extern convar_t *cl_draw_beams;
extern convar_t *cl_bmodelinterp;
extern convar_t *cl_lw; // local weapons
extern convar_t *scr_centertime;
extern convar_t *scr_viewsize;
@ -712,6 +728,9 @@ cl_entity_t *CL_GetWaterEntity( const float *rgflPos );
void CL_SetupPMove( playermove_t *pmove, local_state_t *from, usercmd_t *ucmd, qboolean runfuncs, double time );
pmtrace_t CL_TraceLine( vec3_t start, vec3_t end, int flags );
void CL_ClearPhysEnts( void );
void CL_PushPMStates( void );
void CL_PopPMStates( void );
void CL_SetUpPlayerPrediction( int dopred, int bIncludeLocalClient );
//
// cl_studio.c
@ -727,6 +746,7 @@ void CL_UpdateStudioVars( cl_entity_t *ent, entity_state_t *newstate, qboolean n
qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, float *pradius );
void CL_UpdateEntityFields( cl_entity_t *ent );
qboolean CL_IsPlayerIndex( int idx );
void CL_SetIdealPitch( void );
//
// cl_remap.c

View File

@ -1232,7 +1232,11 @@ void R_DecalRemoveAll( int textureIndex )
{
pdecal = &gDecalPool[i];
if( !textureIndex || pdecal->texture == textureIndex )
// don't remove permanent decals
if( pdecal->flags & FDECAL_PERMANENT )
continue;
if( !textureIndex || ( pdecal->texture == textureIndex ))
R_DecalUnlink( pdecal );
}
}

View File

@ -1191,5 +1191,6 @@ BOOL ( WINAPI * pwglRealizeLayerPalette)(HDC, int, BOOL);
BOOL ( WINAPI * pwglSwapLayerBuffers)(HDC, UINT);
BOOL ( WINAPI * pwglSwapIntervalEXT)( int interval );
HGLRC ( WINAPI * pwglCreateContextAttribsARB)( HDC hDC, HGLRC hShareContext, const int *attribList );
const char *( WINAPI * pwglGetExtensionsStringEXT)( void );
#endif//GL_EXPORT_H

View File

@ -492,6 +492,7 @@ void R_NewMap( void );
enum
{
GL_OPENGL_110 = 0, // base
GL_WGL_EXTENSIONS,
GL_WGL_SWAPCONTROL,
GL_WGL_PROCADDRESS,
GL_HARDWARE_GAMMA_CONTROL,
@ -548,6 +549,7 @@ typedef struct
// list of supported extensions
const char *extensions_string;
const char *wgl_extensions_string;
byte extension[GL_EXTCOUNT];
int max_texture_units;

View File

@ -370,16 +370,16 @@ int R_ComputeFxBlend( cl_entity_t *e )
break;
}
if( e->model->type != mod_brush )
if( e->model && e->model->type != mod_brush )
{
// NOTE: never pass sprites with rendercolor '0 0 0' it's a stupid Valve Hammer Editor bug
if( !e->curstate.rendercolor.r && !e->curstate.rendercolor.g && !e->curstate.rendercolor.b )
e->curstate.rendercolor.r = e->curstate.rendercolor.g = e->curstate.rendercolor.b = 255;
}
// apply scale to studiomodels and sprites only
if( e->model && e->model->type != mod_brush && !e->curstate.scale )
e->curstate.scale = 1.0f;
// apply scale to studiomodels and sprites only
if( !e->curstate.scale )
e->curstate.scale = 1.0f;
}
blend = bound( 0, blend, 255 );

View File

@ -843,20 +843,64 @@ void CL_BloodStream( const vec3_t org, const vec3_t dir, int pcolor, int speed )
{
particle_t *p;
int i, j;
float arc;
for( i = 0; i < speed * 20; i++ )
for( arc = 0.05f, i = 0; i < 100; i++, arc -= 0.005f )
{
p = CL_AllocParticle( NULL );
if( !p ) return;
p->die += 2.0f;
p->type = pt_vox_grav;
p->color = pcolor + Com_RandomLong( 0, 9 );
VectorCopy( org, p->org );
VectorCopy( dir, p->vel );
p->vel[2] -= arc;
arc -= 0.005f;
VectorScale( p->vel, speed, p->vel );
}
for( arc = 0.075f, i = 0; i < speed / 2; i++, arc -= 0.005f )
{
float num;
p = CL_AllocParticle( NULL );
if( !p ) return;
p->die += Com_RandomFloat( 0.2f, 0.8f );
p->type = pt_vox_grav;
p->color = pcolor;
p->die += 3.0f;
p->color = pcolor + Com_RandomLong( 0, 9 );
p->type = pt_vox_slowgrav;
for( j = 0; j < 3; j++ )
VectorCopy( org, p->org );
VectorCopy( dir, p->vel );
p->vel[2] -= arc;
num = Com_RandomFloat( 0.0f, 1.0f );
num = 1.7f * num * (int)(num * speed);
VectorScale( p->vel, num, p->vel );
for( j = 0; j < 2; j++ )
{
p->org[j] = org[j];
p->vel[j] = dir[j] * speed;
p = CL_AllocParticle( NULL );
if( !p ) return;
p->die += 3.0f;
p->color = pcolor + Com_RandomLong( 0, 9 );
p->type = pt_vox_slowgrav;
p->org[0] = org[0] + Com_RandomFloat( -1.0f, 1.0f );
p->org[1] = org[1] + Com_RandomFloat( -1.0f, 1.0f );
p->org[2] = org[2] + Com_RandomFloat( -1.0f, 1.0f );
VectorCopy( dir, p->vel );
p->vel[2] -= arc;
VectorScale( p->vel, num, p->vel );
}
}
}

View File

@ -3302,9 +3302,6 @@ void R_RunViewmodelEvents( void )
if( !Mod_Extradata( clgame.viewent.model ))
return;
if( cl_lw->value && cl.frame.client.viewmodel != cl.predicted_viewmodel )
return;
RI.currententity = &clgame.viewent;
RI.currentmodel = RI.currententity->model;
if( !RI.currentmodel ) return;
@ -3339,9 +3336,6 @@ void R_DrawViewModel( void )
if( !Mod_Extradata( clgame.viewent.model ))
return;
if( cl_lw->value && cl.frame.client.viewmodel != cl.predicted_viewmodel )
return;
RI.currententity = &clgame.viewent;
RI.currentmodel = RI.currententity->model;
if( !RI.currentmodel ) return;

View File

@ -27,11 +27,6 @@ GNU General Public License for more details.
#define WINDOW_EX_STYLE (0)
#define WINDOW_NAME "Xash Window" // Half-Life
#ifdef WIN32
// Enable NVIDIA High Performance Graphics while using Integrated Graphics.
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
#endif
convar_t *renderinfo;
convar_t *gl_allow_software;
convar_t *gl_extensions;
@ -465,6 +460,12 @@ static dllfunc_t wglswapintervalfuncs[] =
{ NULL, NULL }
};
static dllfunc_t wglgetextensionsstring[] =
{
{ "wglGetExtensionsStringEXT" , (void **)&pwglGetExtensionsStringEXT },
{ NULL, NULL }
};
dll_info_t opengl_dll = { "opengl32.dll", wgl_funcs, true };
/*
@ -530,6 +531,7 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
{
const dllfunc_t *func;
convar_t *parm;
const char *extensions_string;
MsgDev( D_NOTE, "GL_CheckExtension: %s ", name );
@ -547,7 +549,12 @@ void GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char *cv
GL_SetExtension( r_ext, 1 );
}
if(( name[2] == '_' || name[3] == '_' ) && !Q_strstr( glConfig.extensions_string, name ))
extensions_string = glConfig.extensions_string;
if( name[0] == 'W' && name[1] == 'G' && name[2] == 'L' && glConfig.wgl_extensions_string != NULL )
extensions_string = glConfig.wgl_extensions_string;
if(( name[2] == '_' || name[3] == '_' ) && !Q_strstr( extensions_string, name ))
{
GL_SetExtension( r_ext, false ); // update render info
MsgDev( D_NOTE, "- ^1failed\n" );
@ -1577,8 +1584,13 @@ void R_RenderInfo_f( void )
// don't spam about extensions
if( host.developer >= 4 )
{
Msg( "GL_EXTENSIONS: %s\n", glConfig.extensions_string );
if( glConfig.wgl_extensions_string != NULL )
Msg( "\nWGL_EXTENSIONS: %s\n", glConfig.wgl_extensions_string );
}
Msg( "GL_MAX_TEXTURE_SIZE: %i\n", glConfig.max_2d_texture_size );
if( GL_Support( GL_ARB_MULTITEXTURE ))
@ -1705,6 +1717,13 @@ void GL_InitExtensions( void )
glConfig.extensions_string = pglGetString( GL_EXTENSIONS );
MsgDev( D_INFO, "Video: %s\n", glConfig.renderer_string );
// windows-specific extensions
GL_CheckExtension( "WGL Extensions String", wglgetextensionsstring, NULL, GL_WGL_EXTENSIONS );
if( pwglGetExtensionsStringEXT != NULL )
glConfig.wgl_extensions_string = pwglGetExtensionsStringEXT();
else glConfig.wgl_extensions_string = NULL;
// initalize until base opengl functions loaded
GL_CheckExtension( "WGL_EXT_swap_control", wglswapintervalfuncs, NULL, GL_WGL_SWAPCONTROL );

View File

@ -828,7 +828,7 @@ void CheckNewDspPresets( void )
if( dsp_off->value != 0.0f )
return;
if( cl.frame.client.waterlevel > 2 )
if( s_listener.waterlevel > 2 )
idsp_room = roomwater_type->value;
else idsp_room = room_type->value;

View File

@ -355,20 +355,8 @@ already playing.
channel_t *SND_PickStaticChannel( int entnum, sfx_t *sfx, const vec3_t pos )
{
channel_t *ch = NULL;
int i, dupe = 0;
#if 0
// TODO: remove this code when predicting is will be done
// check for duplicate sounds
for( i = 0; i < total_channels; i++ )
{
if( channels[i].sfx == sfx && VectorCompare( channels[i].origin, pos ))
dupe++;
}
int i;
// check for duplicated static channels (same origin and same sfx)
if( dupe > MAX_DUPLICATED_CHANNELS )
return NULL;
#endif
// check for replacement sound, or find the best one to replace
for( i = MAX_DYNAMIC_CHANNELS; i < total_channels; i++ )
{

View File

@ -46,7 +46,7 @@ void VGUI_EnableTexture( qboolean enable );
void VGUI_CreateTexture( int id, int width, int height );
void VGUI_UploadTexture( int id, const char *buffer, int width, int height );
void VGUI_UploadTextureBlock( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight );
long VGUI_SurfaceWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
LONG VGUI_SurfaceWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr );
void VGUI_GetTextureSizes( int *width, int *height );
int VGUI_GenerateTexture( void );

View File

@ -228,7 +228,7 @@ KeyCode VGUI_MapKey( int keyCode )
}
}
long VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
LONG VGUI_SurfaceWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
SurfaceBase *surface = NULL;
CEnginePanel *panel = NULL;

View File

@ -48,6 +48,6 @@ int Q_buildnum( void )
return b;
#else
return 3387;
return 3477;
#endif
}

View File

@ -304,8 +304,8 @@ qboolean Cmd_GetMusicList( const char *s, char *completedname, int length )
{
const char *ext = FS_FileExtension( t->filenames[i] );
if( !Q_stricmp( ext, "wav" ) || !Q_stricmp( ext, "mp3" ));
else continue;
if( Q_stricmp( ext, "wav" ) && Q_stricmp( ext, "mp3" ))
continue;
FS_FileBase( t->filenames[i], matchbuf );
Msg( "%16s\n", matchbuf );
@ -568,7 +568,7 @@ Cmd_GetTexturemodes
Prints or complete sound filename
=====================================
*/
qboolean Cmd_GetTexturemodes( const char *s, char *completedname, int length )
qboolean Cmd_GetTextureModes( const char *s, char *completedname, int length )
{
int i, numtexturemodes;
string texturemodes[6]; // keep an actual ( sizeof( gl_texturemode) / sizeof( gl_texturemode[0] ))
@ -584,7 +584,7 @@ qboolean Cmd_GetTexturemodes( const char *s, char *completedname, int length )
"GL_NEAREST_MIPMAP_NEAREST",
};
// compare gamelist with current keyword
// compare texture filtering mode list with current keyword
for( i = 0, numtexturemodes = 0; i < 6; i++ )
{
if(( *s == '*' ) || !Q_strnicmp( gl_texturemode[i], s, Q_strlen( s )))
@ -592,7 +592,7 @@ qboolean Cmd_GetTexturemodes( const char *s, char *completedname, int length )
}
if( !numtexturemodes ) return false;
Q_strncpy( matchbuf, gl_texturemode[0], MAX_STRING );
Q_strncpy( matchbuf, texturemodes[0], MAX_STRING );
if( completedname && length ) Q_strncpy( completedname, matchbuf, length );
if( numtexturemodes == 1 ) return true;
@ -665,6 +665,63 @@ qboolean Cmd_GetGamesList( const char *s, char *completedname, int length )
return true;
}
/*
=====================================
Cmd_GetCDList
Prints or complete CD command name
=====================================
*/
qboolean Cmd_GetCDList( const char *s, char *completedname, int length )
{
int i, numcdcommands;
string cdcommands[8];
string matchbuf;
const char *cd_command[] =
{
"info",
"loop",
"off",
"on",
"pause",
"play",
"resume",
"stop",
};
// compare CD command list with current keyword
for( i = 0, numcdcommands = 0; i < 8; i++ )
{
if(( *s == '*' ) || !Q_strnicmp( cd_command[i], s, Q_strlen( s )))
Q_strcpy( cdcommands[numcdcommands++], cd_command[i] );
}
if( !numcdcommands ) return false;
Q_strncpy( matchbuf, cdcommands[0], MAX_STRING );
if( completedname && length ) Q_strncpy( completedname, matchbuf, length );
if( numcdcommands == 1 ) return true;
for( i = 0; i < numcdcommands; i++ )
{
Q_strncpy( matchbuf, cdcommands[i], MAX_STRING );
Msg( "%16s\n", matchbuf );
}
Msg( "\n^3 %i commands found.\n", numcdcommands );
// cut shortestMatch to the amount common with s
if( completedname && length )
{
for( i = 0; matchbuf[i]; i++ )
{
if( Q_tolower( completedname[i] ) != Q_tolower( matchbuf[i] ))
completedname[i] = 0;
}
}
return true;
}
qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
{
byte buf[MAX_SYSPATH];
@ -815,7 +872,7 @@ qboolean Cmd_CheckMapsList( qboolean fRefresh )
autocomplete_list_t cmd_list[] =
{
{ "gl_texturemode", Cmd_GetTexturemodes },
{ "gl_texturemode", Cmd_GetTextureModes },
{ "map_background", Cmd_GetMapList },
{ "changelevel", Cmd_GetMapList },
{ "playdemo", Cmd_GetDemoList, },
@ -832,6 +889,7 @@ autocomplete_list_t cmd_list[] =
{ "load", Cmd_GetSavesList },
{ "play", Cmd_GetSoundList },
{ "map", Cmd_GetMapList },
{ "cd", Cmd_GetCDList },
{ NULL }, // termiantor
};

View File

@ -755,12 +755,6 @@ void Con_Print( const char *txt )
if( txt[l] <= ' ')
break;
}
#if 0
// g-cont. experiment from SDLash3D
// word wrap
if( l != con.linewidth && ( con.x + l >= con.linewidth ))
Con_Linefeed();
#endif
txt++;
switch( c )

View File

@ -462,6 +462,8 @@ void Image_PaletteHueReplace( byte *palSrc, int newHue, int start, int end )
maxcol = max( max( r, g ), b ) / 255.0f;
mincol = min( min( r, g ), b ) / 255.0f;
if( maxcol == 0 ) continue;
val = maxcol;
sat = (maxcol - mincol) / maxcol;
@ -567,7 +569,7 @@ qboolean Image_Copy8bitRGBA( const byte *in, byte *out, int pixels )
// check for color
for( i = 0; i < 256; i++ )
{
col = (rgba_t *)image.d_currentpal[i];
col = (rgba_t *)&image.d_currentpal[i];
if( col[0] != col[1] || col[1] != col[2] )
{
image.flags |= IMAGE_HAS_COLOR;
@ -1114,7 +1116,7 @@ byte *Image_FloodInternal( const byte *indata, int inwidth, int inheight, int ou
{
if( x < inwidth )
*out++ = *in++;
else *out++;
else out++;
}
}
}

View File

@ -435,7 +435,7 @@ IN_WndProc
main window procedure
====================
*/
long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam )
LONG IN_WndProc( HWND hWnd, UINT uMsg, UINT wParam, LONG lParam )
{
int i, temp = 0;
qboolean fActivate;

View File

@ -45,7 +45,7 @@ void IN_MouseEvent( int mstate );
void IN_ActivateMouse( qboolean force );
void IN_DeactivateMouse( void );
void IN_ToggleClientMouse( int newstate, int oldstate );
long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam );
LONG IN_WndProc( HWND hWnd, UINT uMsg, UINT wParam, LONG lParam );
void IN_SetCursor( HICON hCursor );
#endif//INPUT_H

View File

@ -63,7 +63,7 @@ GNU General Public License for more details.
#define PORT_MASTER 27010
#define PORT_CLIENT 27005
#define PORT_SERVER 27015
#define MULTIPLAYER_BACKUP 64 // how many data slots to use when in multiplayer (must be power of 2)
#define MULTIPLAYER_BACKUP 128 // how many data slots to use when in multiplayer (must be power of 2)
#define SINGLEPLAYER_BACKUP 16 // same for single player
/*

View File

@ -76,7 +76,8 @@ static void FindNextChunk( const char *name )
iff_dataPtr += 4;
iff_chunkLen = GetLittleLong();
if( iff_chunkLen < 0 )
// limit chunk size to 1 mb
if( iff_chunkLen < 0 || iff_chunkLen > ( 1024 * 1024 ))
{
iff_dataPtr = NULL;
return;

View File

@ -165,9 +165,16 @@ static const char *Mem_CheckFilename( const char *filename )
int i;
if( !out ) return dummy;
for( i = 0; i < 128; i++, out++ )
if( out == '\0' ) break; // valid name
if( i == 128 ) return dummy;
{
if( *out == '\0' )
break; // valid name
}
if( i == 128 )
return dummy;
return filename;
}

View File

@ -447,6 +447,7 @@ void SV_RemoteCommand( netadr_t from, sizebuf_t *msg );
void SV_PrepWorldFrame( void );
void SV_ProcessFile( sv_client_t *cl, char *filename );
void SV_SendResourceList( sv_client_t *cl );
void SV_AddToMaster( netadr_t from, sizebuf_t *msg );
void Master_Add( void );
void Master_Heartbeat( void );
void Master_Packet( void );

View File

@ -548,7 +548,7 @@ char *SV_StatusString( void )
cl = &svs.clients[i];
if( cl->state == cs_connected || cl->state == cs_spawned )
{
Q_sprintf( player, "%i %i \"%s\"\n", (int)cl->edict->v.frags, cl->ping, cl->name );
Q_sprintf( player, "%i %i \"%s\"\n", (int)cl->edict->v.frags, (int)cl->ping, cl->name );
playerLength = Q_strlen( player );
if( statusLength + playerLength >= sizeof( status ))
break; // can't hold any more
@ -642,7 +642,7 @@ void SV_Info( netadr_t from )
int version;
// ignore in single player
if( sv_maxclients->integer == 1 )
if( sv_maxclients->integer == 1 || !svs.initialized )
return;
version = Q_atoi( Cmd_Argv( 1 ));
@ -660,9 +660,9 @@ void SV_Info( netadr_t from )
Info_SetValueForKey( string, "host", hostname->string );
Info_SetValueForKey( string, "map", sv.name );
Info_SetValueForKey( string, "dm", va( "%i", svgame.globals->deathmatch ));
Info_SetValueForKey( string, "team", va( "%i", svgame.globals->teamplay ));
Info_SetValueForKey( string, "coop", va( "%i", svgame.globals->coop ));
Info_SetValueForKey( string, "dm", va( "%i", (int)svgame.globals->deathmatch ));
Info_SetValueForKey( string, "team", va( "%i", (int)svgame.globals->teamplay ));
Info_SetValueForKey( string, "coop", va( "%i", (int)svgame.globals->coop ));
Info_SetValueForKey( string, "numcl", va( "%i", count ));
Info_SetValueForKey( string, "maxcl", va( "%i", sv_maxclients->integer ));
Info_SetValueForKey( string, "gamedir", GI->gamefolder );
@ -685,7 +685,7 @@ void SV_BuildNetAnswer( netadr_t from )
int i, count = 0;
// ignore in single player
if( sv_maxclients->integer == 1 )
if( sv_maxclients->integer == 1 || !svs.initialized )
return;
version = Q_atoi( Cmd_Argv( 1 ));
@ -716,7 +716,7 @@ void SV_BuildNetAnswer( netadr_t from )
{
edict_t *ed = svs.clients[i].edict;
float time = host.realtime - svs.clients[i].lastconnect;
Q_strncat( string, va( "%c\\%s\\%i\\%f\\", count, svs.clients[i].name, ed->v.frags, time ), sizeof( string ));
Q_strncat( string, va( "%c\\%s\\%i\\%f\\", count, svs.clients[i].name, (int)ed->v.frags, time ), sizeof( string ));
count++;
}
}
@ -1802,6 +1802,14 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
val = Info_ValueForKey( cl->userinfo, "name" );
}
if( !Q_strlen( temp1 ) )
{
Info_SetValueForKey( cl->userinfo, "name", "unnamed" );
val = Info_ValueForKey( cl->userinfo, "name" );
Q_strncpy( temp2, "unnamed", sizeof( temp2 ));
Q_strncpy( temp1, "unnamed", sizeof( temp1 ));
}
// check to see if another user by the same name exists
while( 1 )
{
@ -1871,6 +1879,14 @@ void SV_UserinfoChanged( sv_client_t *cl, const char *userinfo )
}
else cl->modelindex = 0;
// force reset player model to "player"
if( cl->modelindex == 0 )
{
Info_SetValueForKey( cl->userinfo, "model", "player" );
Mod_RegisterModel( "models/player.mdl", SV_ModelIndex( "models/player.mdl" ));
SV_SetModel( ent, "models/player.mdl" );
}
// call prog code to allow overrides
svgame.dllFuncs.pfnClientUserInfoChanged( cl->edict, cl->userinfo );
ent->v.netname = MAKE_STRING( cl->name );
@ -2038,6 +2054,70 @@ void SV_ExecuteClientCommand( sv_client_t *cl, char *s )
}
}
/*
==================
SV_TSourceEngineQuery
==================
*/
void SV_TSourceEngineQuery( netadr_t from )
{
// A2S_INFO
char answer[1024] = "";
int count = 0, bots = 0, index;
sizebuf_t buf;
if( svs.clients )
{
for( index = 0; index < sv_maxclients->integer; index++ )
{
if( svs.clients[index].state >= cs_connected )
{
if( svs.clients[index].fakeclient )
bots++;
else count++;
}
}
}
BF_Init( &buf, "TSourceEngineQuery", answer, sizeof( answer ));
BF_WriteByte( &buf, 'm' );
BF_WriteString( &buf, NET_AdrToString( net_local ) );
BF_WriteString( &buf, hostname->string );
BF_WriteString( &buf, sv.name );
BF_WriteString( &buf, GI->gamefolder );
BF_WriteString( &buf, GI->title );
BF_WriteByte( &buf, count );
BF_WriteByte( &buf, sv_maxclients->integer );
BF_WriteByte( &buf, PROTOCOL_VERSION );
BF_WriteByte( &buf, host.type == HOST_DEDICATED ? 'D' : 'L');
BF_WriteByte( &buf, 'W' );
if( Q_stricmp( GI->gamedir, "valve" ))
{
BF_WriteByte( &buf, 1 ); // mod
BF_WriteString( &buf, GI->game_url );
BF_WriteString( &buf, GI->update_url );
BF_WriteByte( &buf, 0 );
BF_WriteLong( &buf, (long)GI->version );
BF_WriteLong( &buf, GI->size );
if( GI->gamemode == 2 )
BF_WriteByte( &buf, 1 ); // multiplayer_only
else BF_WriteByte( &buf, 0 );
if( Q_strstr( GI->game_dll, "hl." ))
BF_WriteByte( &buf, 0 ); // Half-Life DLL
else BF_WriteByte( &buf, 1 ); // Own DLL
}
else BF_WriteByte( &buf, 0 ); // Half-Life
BF_WriteByte( &buf, GI->secure ); // unsecure
BF_WriteByte( &buf, bots );
NET_SendPacket( NS_SERVER, BF_GetNumBytesWritten( &buf ), BF_GetData( &buf ), from );
}
/*
=================
SV_ConnectionlessPacket
@ -2053,9 +2133,6 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
char *args;
char *c, buf[MAX_SYSPATH];
int len = sizeof( buf );
uint challenge;
int index, count = 0;
char query[512], ostype = 'w';
BF_Clear( msg );
BF_ReadLong( msg );// skip the -1 marker
@ -2074,46 +2151,9 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
else if( !Q_strcmp( c, "connect" )) SV_DirectConnect( from );
else if( !Q_strcmp( c, "rcon" )) SV_RemoteCommand( from, msg );
else if( !Q_strcmp( c, "netinfo" )) SV_BuildNetAnswer( from );
else if( msg->pData[0] == 0xFF && msg->pData[1] == 0xFF && msg->pData[2] == 0xFF && msg->pData[3] == 0xFF && msg->pData[4] == 0x73 && msg->pData[5] == 0x0A )
{
Q_memcpy(&challenge, &msg->pData[6], sizeof(int));
for( index = 0; index < sv_maxclients->integer; index++ )
{
if( svs.clients[index].state >= cs_connected )
count++;
}
Q_snprintf( query, sizeof( query ),
"0\n"
"\\protocol\\%d" // protocol version
"\\challenge\\%u" // challenge number that got after FF FF FF FF 73 0A
"\\players\\%d" // current player number
"\\max\\%d" // max_players
"\\bots\\0" // bot number?
"\\gamedir\\%s" // gamedir. _xash appended, because Xash3D is not compatible with GS in multiplayer
"\\map\\%s" // current map
"\\type\\d" // server type
"\\password\\0" // is password set
"\\os\\%c" // server OS?
"\\secure\\0" // server anti-cheat? VAC?
"\\lan\\0" // is LAN server?
"\\version\\%f" // server version
"\\region\\255" // server region
"\\product\\%s\n", // product? Where is the difference with gamedir?
PROTOCOL_VERSION,
challenge,
count,
sv_maxclients->integer,
GI->gamefolder,
sv.name,
ostype,
XASH_VERSION,
GI->gamefolder
);
NET_SendPacket( NS_SERVER, Q_strlen( query ), query, from );
}
else if( !Q_strcmp( c, "s")) SV_AddToMaster( from, msg );
else if( !Q_strcmp( c, "T" "Source" )) SV_TSourceEngineQuery( from );
else if( !Q_strcmp( c, "i" )) NET_SendPacket( NS_SERVER, 5, "\xFF\xFF\xFF\xFFj", from ); // A2A_PING
else if( svgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
{
// user out of band message (must be handled in CL_ConnectionlessPacket)
@ -2143,7 +2183,6 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
usercmd_t cmds[32], *to;
edict_t *player;
numbackup = 2;
player = cl->edict;
frame = &cl->frames[cl->netchan.incoming_acknowledged & SV_UPDATE_MASK];

View File

@ -561,6 +561,16 @@ void SV_WriteEntitiesToClient( sv_client_t *cl, sizebuf_t *msg )
// copy the entity states out
frame->num_entities = 0;
// It will break all connected clients, but it takes more than one week to overflow it
if(( (uint)svs.next_client_entities ) + frame_ents.num_entities >= 0x7FFFFFFE )
{
// just reset counter
svs.next_client_entities = 0;
// delta is broken now, cannot keep connected clients
SV_FinalMessage( "Server is running to long, reconnecting!", true );
}
frame->first_entity = svs.next_client_entities;
for( i = 0; i < frame_ents.num_entities; i++ )
@ -569,10 +579,6 @@ void SV_WriteEntitiesToClient( sv_client_t *cl, sizebuf_t *msg )
state = &svs.packet_entities[svs.next_client_entities % svs.num_client_entities];
*state = frame_ents.entities[i];
svs.next_client_entities++;
// this should never hit, map should always be restarted first in SV_Frame
if( svs.next_client_entities >= 0x7FFFFFFE )
Host_Error( "svs.next_client_entities wrapped\n" );
frame->num_entities++;
}
@ -601,6 +607,7 @@ void SV_SendClientDatagram( sv_client_t *cl )
svs.currentPlayer = cl;
svs.currentPlayerNum = (cl - svs.clients);
Q_memset( msg_buf, 0, NET_MAX_PAYLOAD );
BF_Init( &msg, "Datagram", msg_buf, sizeof( msg_buf ));
// always send servertime at new frame

View File

@ -3185,7 +3185,7 @@ void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg )
if( sv.state != ss_active )
{
// send message into console during loading
MsgDev( D_INFO, szMsg );
MsgDev( D_INFO, "%s\n", szMsg );
return;
}
@ -3198,7 +3198,7 @@ void pfnClientPrintf( edict_t* pEdict, PRINT_TYPE ptype, const char *szMsg )
switch( ptype )
{
case print_console:
if( client->fakeclient ) MsgDev( D_INFO, szMsg );
if( client->fakeclient ) MsgDev( D_INFO, "%s", szMsg );
else SV_ClientPrintf( client, PRINT_HIGH, "%s", szMsg );
break;
case print_chat:
@ -3222,7 +3222,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, szMsg );
if( sv.state != ss_active ) MsgDev( D_INFO, "%s", szMsg );
else SV_BroadcastPrintf( PRINT_HIGH, "%s", szMsg );
}
@ -4362,15 +4362,16 @@ pfnCheckParm
*/
static int pfnCheckParm( char *parm, char **ppnext )
{
static char str[64];
int i = Sys_CheckParm( parm );
if( Sys_GetParmFromCmdLine( parm, str ))
if( ppnext != NULL )
{
// get the pointer on cmdline param
if( ppnext ) *ppnext = str;
return 1;
if( i > 0 && i < host.argc - 1 )
*ppnext = (char*)host.argv[i + 1];
else *ppnext = NULL;
}
return 0;
return i;
}
// engine callbacks

View File

@ -403,6 +403,9 @@ void SV_DeactivateServer( void )
svgame.dllFuncs.pfnServerDeactivate();
if( sv_maxclients->integer > 32 )
Cvar_SetFloat( "maxplayers", 32.0f );
for( i = 0; i < sv_maxclients->integer; i++ )
{
// release client frames
@ -677,7 +680,7 @@ void SV_InitGame( void )
// copy gamemode into svgame.globals
svgame.globals->deathmatch = Cvar_VariableInteger( "deathmatch" );
svgame.globals->teamplay = Cvar_VariableInteger( "teamplay" );
svgame.globals->coop = Cvar_VariableInteger( "coop" );
svgame.globals->coop = ( sv_maxclients->integer > 1 ) ? Cvar_VariableInteger( "coop" ) : 0;
// heartbeats will always be sent to the id master
svs.last_heartbeat = MAX_HEARTBEAT; // send immediately

View File

@ -320,7 +320,8 @@ SV_ReadPackets
void SV_ReadPackets( void )
{
sv_client_t *cl;
int i, qport, curSize;
int i, qport;
size_t curSize;
while( NET_GetPacket( NS_SERVER, &net_from, net_message_buffer, &curSize ))
{
@ -548,7 +549,12 @@ Host_ServerFrame
void Host_ServerFrame( void )
{
// if server is not active, do nothing
if( !svs.initialized ) return;
if( !svs.initialized )
{
// but allow rcon
SV_ReadPackets ();
return;
}
svgame.globals->frametime = host.frametime;
@ -599,7 +605,7 @@ void Master_Add( void )
if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ))
MsgDev( D_INFO, "Can't resolve adr: %s\n", MASTERSERVER_ADR );
NET_SendPacket( NS_SERVER, 1, "q", adr );
NET_SendPacket( NS_SERVER, 2, "q\xFF", adr );
}
/*
@ -646,6 +652,54 @@ void Master_Shutdown( void )
NET_SendPacket( NS_SERVER, 2, "\x62\x0A", adr );
}
/*
=================
SV_AddToMaster
A server info answer to master server.
Master will validate challenge and this server to public list
=================
*/
void SV_AddToMaster( netadr_t from, sizebuf_t *msg )
{
uint challenge;
char s[MAX_INFO_STRING] = "0\n"; // skip 2 bytes of header
int clients = 0, bots = 0, index;
if( svs.clients )
{
for( index = 0; index < sv_maxclients->integer; index++ )
{
if( svs.clients[index].state >= cs_connected )
{
if( svs.clients[index].fakeclient )
bots++;
else clients++;
}
}
}
challenge = BF_ReadUBitLong( msg, sizeof( uint ) << 3 );
Info_SetValueForKey( s, "protocol", va( "%d", PROTOCOL_VERSION ) ); // protocol version
Info_SetValueForKey( s, "challenge", va( "%u", challenge ) ); // challenge number
Info_SetValueForKey( s, "players", va( "%d", clients ) ); // current player number, without bots
Info_SetValueForKey( s, "max", sv_maxclients->string ); // max_players
Info_SetValueForKey( s, "bots", va( "%d", bots ) ); // bot count
Info_SetValueForKey( s, "gamedir", GI->gamedir ); // gamedir
Info_SetValueForKey( s, "map", sv.name ); // current map
Info_SetValueForKey( s, "type", (host.type == HOST_DEDICATED) ? "d" : "l" ); // dedicated or local
Info_SetValueForKey( s, "password", "0" ); // is password set
Info_SetValueForKey( s, "os", "w" ); // Windows
Info_SetValueForKey( s, "secure", "0" ); // server anti-cheat
Info_SetValueForKey( s, "lan", "0" ); // LAN servers doesn't send info to master
Info_SetValueForKey( s, "version", va( "%g", XASH_VERSION )); // server region. 255 -- all regions
Info_SetValueForKey( s, "region", "255" ); // server region. 255 -- all regions
Info_SetValueForKey( s, "product", GI->gamefolder ); // product? Where is the difference with gamedir?
NET_SendPacket( NS_SERVER, Q_strlen( s ), s, from );
}
//============================================================================
/*

View File

@ -540,7 +540,7 @@ void SV_FindTouchedLeafs( edict_t *ent, mnode_t *node, int *headnode )
int sides, leafnum;
mleaf_t *leaf;
if( node->contents == CONTENTS_SOLID )
if( !node || node->contents == CONTENTS_SOLID )
return;
// add an efrag if the node is a leaf

View File

@ -17,6 +17,11 @@ GNU General Public License for more details.
#define GAME_PATH "valve" // default dir to start from
#ifdef WIN32
// enable NVIDIA High Performance Graphics while using Integrated Graphics.
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
#endif
typedef void (*pfnChangeGame)( const char *progname );
typedef int (*pfnInit)( const char *progname, int bChangeGame, pfnChangeGame func );
typedef void (*pfnShutdown)( void );