diff --git a/src/game/g_active.c b/src/game/g_active.c index df50af2..a882986 100644 --- a/src/game/g_active.c +++ b/src/game/g_active.c @@ -913,7 +913,7 @@ void SendPendingPredictableEvents( playerState_t *ps ) G_UnlaggedStore Called on every server frame. Stores position data for the client at that - into client->unlaggedHist[] and the time into level.unlaggedTimes[]. + into client->pers.unlaggedHist and the time into level.unlaggedTimes. This data is used by G_UnlaggedCalc() ============== */ @@ -923,18 +923,20 @@ void G_UnlaggedStore( void ) gentity_t *ent; unlagged_t *save; - if( !g_unlagged.integer ) + if( !g_unlagged.integer || !level.unlaggedMarkers ) return; level.unlaggedIndex++; - if( level.unlaggedIndex >= MAX_UNLAGGED_MARKERS ) + if( level.unlaggedIndex >= level.unlaggedMarkers ) level.unlaggedIndex = 0; + assert( level.unlaggedTimes ); level.unlaggedTimes[ level.unlaggedIndex ] = level.time; for( i = 0; i < level.maxclients; i++ ) { ent = &g_entities[ i ]; - save = &ent->client->unlaggedHist[ level.unlaggedIndex ]; + assert( ent->client->pers.unlaggedHist ); + save = &ent->client->pers.unlaggedHist[ level.unlaggedIndex ]; save->used = qfalse; if( !ent->r.linked || !( ent->r.contents & CONTENTS_BODY ) ) continue; @@ -951,7 +953,7 @@ void G_UnlaggedStore( void ) ============== G_UnlaggedClear - Mark all unlaggedHist[] markers for this client invalid. Useful for + Mark all unlaggedHist markers for this client invalid. Useful for preventing teleporting and death. ============== */ @@ -959,8 +961,12 @@ void G_UnlaggedClear( gentity_t *ent ) { int i; - for( i = 0; i < MAX_UNLAGGED_MARKERS; i++ ) - ent->client->unlaggedHist[ i ].used = qfalse; + if( !g_unlagged.integer || !level.unlaggedMarkers ) + return; + + assert( ent->client->pers.unlaggedHist ); + for( i = 0; i < level.unlaggedMarkers; i++ ) + ent->client->pers.unlaggedHist[ i ].used = qfalse; } /* @@ -980,7 +986,7 @@ void G_UnlaggedCalc( int time, gentity_t *rewindEnt ) int frameMsec = 0; float lerp = 0.5f; - if( !g_unlagged.integer ) + if( !g_unlagged.integer || !level.unlaggedMarkers ) return; // clear any calculated values from a previous run @@ -990,15 +996,16 @@ void G_UnlaggedCalc( int time, gentity_t *rewindEnt ) ent->client->unlaggedCalc.used = qfalse; } - for( i = 0; i < MAX_UNLAGGED_MARKERS; i++ ) + assert( level.unlaggedTimes ); + for( i = 0; i < level.unlaggedMarkers; i++ ) { if( level.unlaggedTimes[ startIndex ] <= time ) break; stopIndex = startIndex; if( --startIndex < 0 ) - startIndex = MAX_UNLAGGED_MARKERS - 1; + startIndex = level.unlaggedMarkers - 1; } - if( i == MAX_UNLAGGED_MARKERS ) + if( i == level.unlaggedMarkers ) { // if we searched all markers and the oldest one still isn't old enough // just use the oldest marker with no lerping @@ -1021,6 +1028,7 @@ void G_UnlaggedCalc( int time, gentity_t *rewindEnt ) for( i = 0; i < level.maxclients; i++ ) { ent = &g_entities[ i ]; + assert( ent->client->pers.unlaggedHist ); if( ent == rewindEnt ) continue; if( !ent->r.linked || !( ent->r.contents & CONTENTS_BODY ) ) @@ -1029,20 +1037,20 @@ void G_UnlaggedCalc( int time, gentity_t *rewindEnt ) continue; //if( ent->client->ps.stats[ STAT_STATE ] & SS_GRABBED ) // continue; - if( !ent->client->unlaggedHist[ startIndex ].used ) + if( !ent->client->pers.unlaggedHist[ startIndex ].used ) continue; - if( !ent->client->unlaggedHist[ stopIndex ].used ) + if( !ent->client->pers.unlaggedHist[ stopIndex ].used ) continue; // between two unlagged markers - VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].mins, - ent->client->unlaggedHist[ stopIndex ].mins, + VectorLerp( lerp, ent->client->pers.unlaggedHist[ startIndex ].mins, + ent->client->pers.unlaggedHist[ stopIndex ].mins, ent->client->unlaggedCalc.mins ); - VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].maxs, - ent->client->unlaggedHist[ stopIndex ].maxs, + VectorLerp( lerp, ent->client->pers.unlaggedHist[ startIndex ].maxs, + ent->client->pers.unlaggedHist[ stopIndex ].maxs, ent->client->unlaggedCalc.maxs ); - VectorLerp( lerp, ent->client->unlaggedHist[ startIndex ].origin, - ent->client->unlaggedHist[ stopIndex ].origin, + VectorLerp( lerp, ent->client->pers.unlaggedHist[ startIndex ].origin, + ent->client->pers.unlaggedHist[ stopIndex ].origin, ent->client->unlaggedCalc.origin ); ent->client->unlaggedCalc.used = qtrue; @@ -1061,7 +1069,7 @@ void G_UnlaggedOff( void ) int i = 0; gentity_t *ent; - if( !g_unlagged.integer ) + if( !g_unlagged.integer || !level.unlaggedMarkers ) return; for( i = 0; i < level.maxclients; i++ ) @@ -1097,11 +1105,16 @@ void G_UnlaggedOn( gentity_t *attacker, vec3_t muzzle, float range ) gentity_t *ent; unlagged_t *calc; - if( !g_unlagged.integer ) + if( !g_unlagged.integer || !level.unlaggedMarkers ) return; if( !attacker->client->pers.useUnlagged ) return; + +#if 0 + if( attacker->client->ps.ping > g_unlagged.integer ) // don't unlag a higher ping than g_unlagged + return; +#endif for( i = 0; i < level.maxclients; i++ ) { @@ -1168,10 +1181,14 @@ static void G_UnlaggedDetectCollisions( gentity_t *ent ) float r1, r2; float range; - if( !g_unlagged.integer ) + if( !g_unlagged.integer || !level.unlaggedMarkers ) return; if( !ent->client->pers.useUnlagged ) return; +#if 0 + if( ent->client->ps.ping > g_unlagged.integer ) // don't unlag a higher ping than g_unlagged + return; +#endif calc = &ent->client->unlaggedCalc; diff --git a/src/game/g_client.c b/src/game/g_client.c index b5dd53d..60a53f2 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -1220,17 +1220,20 @@ restarts. */ char *ClientConnect( int clientNum, qboolean firstTime ) { - char *value; - gclient_t *client; - char userinfo[ MAX_INFO_STRING ]; - gentity_t *ent; - char reason[ MAX_STRING_CHARS ] = {""}; - int i; + char *value; + gclient_t *client; + char userinfo[ MAX_INFO_STRING ]; + gentity_t *ent; + char reason[ MAX_STRING_CHARS ] = {""}; + int i; + unlagged_t *unlaggedHist; ent = &g_entities[ clientNum ]; client = &level.clients[ clientNum ]; ent->client = client; + unlaggedHist = client->pers.unlaggedHist; memset( client, 0, sizeof( *client ) ); + client->pers.unlaggedHist = unlaggedHist; trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) ); value = Info_ValueForKey( userinfo, "cl_guid" ); diff --git a/src/game/g_local.h b/src/game/g_local.h index d999965..22325c8 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -293,6 +293,13 @@ typedef struct connectionRecord_s int ptrCode; } connectionRecord_t; +typedef struct unlagged_s { + vec3_t origin; + vec3_t mins; + vec3_t maxs; + qboolean used; +} unlagged_t; + // client data that stays across multiple respawns, but is cleared // on each level change or team change at ClientBegin() typedef struct @@ -342,17 +349,11 @@ typedef struct qboolean denyBuild; int adminLevel; char voice[ MAX_VOICE_NAME_LEN ]; + qboolean useUnlagged; + unlagged_t *unlaggedHist; } clientPersistant_t; -#define MAX_UNLAGGED_MARKERS 10 -typedef struct unlagged_s { - vec3_t origin; - vec3_t mins; - vec3_t maxs; - qboolean used; -} unlagged_t; - // this structure is cleared on each ClientSpawn(), // except for 'client->pers' and 'client->sess' struct gclient_s @@ -436,7 +437,6 @@ struct gclient_s int lastFlameBall; // s.number of the last flame ball fired - unlagged_t unlaggedHist[ MAX_UNLAGGED_MARKERS ]; unlagged_t unlaggedBackup; unlagged_t unlaggedCalc; int unlaggedTime; @@ -641,8 +641,9 @@ typedef struct qboolean alienTeamLocked; qboolean humanTeamLocked; - int unlaggedIndex; - int unlaggedTimes[ MAX_UNLAGGED_MARKERS ]; + int unlaggedIndex; + int *unlaggedTimes; + int unlaggedMarkers; char layout[ MAX_QPATH ]; diff --git a/src/game/g_main.c b/src/game/g_main.c index 1cd6ff8..b691676 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -244,7 +244,7 @@ static cvarTable_t gameCvarTable[ ] = { &g_alienStage2Threshold, "g_alienStage2Threshold", DEFAULT_ALIEN_STAGE2_THRESH, 0, 0, qfalse }, { &g_alienStage3Threshold, "g_alienStage3Threshold", DEFAULT_ALIEN_STAGE3_THRESH, 0, 0, qfalse }, - { &g_unlagged, "g_unlagged", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse }, + { &g_unlagged, "g_unlagged", "500", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qfalse }, { &g_disabledEquipment, "g_disabledEquipment", "", CVAR_ROM, 0, qfalse }, { &g_disabledClasses, "g_disabledClasses", "", CVAR_ROM, 0, qfalse }, @@ -2440,6 +2440,7 @@ void CheckCvars( void ) static int lastMarkDeconModCount = -1; static int lastSDTimeModCount = -1; static int lastNumZones = 0; + static int lastFPS = 0, lastUnlagged = 0; if( g_password.modificationCount != lastPasswordModCount ) { @@ -2496,6 +2497,47 @@ void CheckCvars( void ) lastNumZones = g_humanRepeaterMaxZones.integer; } + // If the frame rate or maximum unlagged ping changes, we need new arrays of unlagged histories + if( trap_Cvar_VariableIntegerValue( "sv_fps" ) != lastFPS || g_unlagged.integer != lastUnlagged ) + { + int i; + int unlagged = g_unlagged.integer; + + level.unlaggedIndex = 0; + + if( unlagged < 0 ) + unlagged = 0; + if( unlagged > 9999 ) // make sure it's not set insanely high and uses too much memory + unlagged = 9999; + + level.unlaggedMarkers = (int) ceil( (double) unlagged * (double) ( trap_Cvar_VariableIntegerValue( "sv_fps" ) ) / 1000.0 ); + level.unlaggedMarkers++; // unlagged keeps a marker for "now" + + trap_Cvar_Set( "g_unlagged", va( "%d", ( level.unlaggedMarkers - 1 ) * trap_Cvar_VariableIntegerValue( "sv_fps" ) ) ); // set g_unlagged to the value actually being used + + for( i = 0; i < level.maxclients; i++ ) + { + gclient_t *client = &level.clients[ i ]; + + if( client->pers.unlaggedHist ) + BG_Free( client->pers.unlaggedHist ); + if( unlagged ) + client->pers.unlaggedHist = BG_Alloc( level.unlaggedMarkers * sizeof( unlagged_t ) ); + else + client->pers.unlaggedHist = NULL; + } + + if( level.unlaggedTimes ) + BG_Free( level.unlaggedTimes ); + if( unlagged ) + level.unlaggedTimes = BG_Alloc( level.unlaggedMarkers * sizeof( int ) ); + else + level.unlaggedTimes = NULL; + + lastFPS = trap_Cvar_VariableIntegerValue( "sv_fps" ); + lastUnlagged = unlagged; + } + level.frameMsec = trap_Milliseconds( ); }