//----------------------------------------------------------------------------- // Purpose: Used at level change and round start to re-calculate which holiday is active //----------------------------------------------------------------------------- void UTIL_CalculateHolidays() { s_HolidaysActive.ClearAll(); CRTime::UpdateRealTime(); for ( int iHoliday = 0; iHoliday < kHolidayCount; iHoliday++ ) { if ( EconHolidays_IsHolidayActive( iHoliday, CRTime::RTime32TimeCur() ) ) { s_HolidaysActive.Set( iHoliday ); } } s_HolidaysCalculated = true; }
// Called during player movement to set up/restore after lag compensation void CLagCompensationManager::StartLagCompensation( CBasePlayer *player, CUserCmd *cmd ) { //DONT LAG COMP AGAIN THIS FRAME IF THERES ALREADY ONE IN PROGRESS //IF YOU'RE HITTING THIS THEN IT MEANS THERES A CODE BUG if ( m_pCurrentPlayer ) { Assert( m_pCurrentPlayer == NULL ); Warning( "Trying to start a new lag compensation session while one is already active!\n" ); return; } // sort out any changes to the AI indexing if ( m_bNeedsAIUpdate ) // to be called once per frame... must happen BEFORE lag compensation - {// if that happens, that is. if not its called at the end of the frame m_bNeedsAIUpdate = false; UpdateAIIndexes(); } // Assume no players or entities need to be restored m_RestorePlayer.ClearAll(); m_RestoreEntity.ClearAll(); m_bNeedToRestore = false; m_pCurrentPlayer = player; if ( !player->m_bLagCompensation // Player not wanting lag compensation || (gpGlobals->maxClients <= 1) // no lag compensation in single player || !sv_unlag.GetBool() // disabled by server admin || player->IsBot() // not for bots || player->IsObserver() // not for spectators ) return; // NOTE: Put this here so that it won't show up in single player mode. VPROF_BUDGET( "StartLagCompensation", VPROF_BUDGETGROUP_OTHER_NETWORKING ); Q_memset( m_RestoreData, 0, sizeof( m_RestoreData ) ); Q_memset( m_ChangeData, 0, sizeof( m_ChangeData ) ); Q_memset( m_EntityRestoreData, 0, sizeof( m_EntityRestoreData ) ); Q_memset( m_EntityChangeData, 0, sizeof( m_EntityChangeData ) ); // Get true latency // correct is the amout of time we have to correct game time float correct = 0.0f; INetChannelInfo *nci = engine->GetPlayerNetInfo( player->entindex() ); if ( nci ) { // add network latency correct+= nci->GetLatency( FLOW_OUTGOING ); } // calc number of view interpolation ticks - 1 int lerpTicks = TIME_TO_TICKS( player->m_fLerpTime ); // add view interpolation latency see C_BaseEntity::GetInterpolationAmount() correct += TICKS_TO_TIME( lerpTicks ); // check bouns [0,sv_maxunlag] correct = clamp( correct, 0.0f, sv_maxunlag.GetFloat() ); // correct tick send by player int targettick = cmd->tick_count - lerpTicks; // calc difference between tick send by player and our latency based tick float deltaTime = correct - TICKS_TO_TIME(gpGlobals->tickcount - targettick); if ( fabs( deltaTime ) > 0.2f ) { // difference between cmd time and latency is too big > 200ms, use time correction based on latency // DevMsg("StartLagCompensation: delta too big (%.3f)\n", deltaTime ); targettick = gpGlobals->tickcount - TIME_TO_TICKS( correct ); } // Iterate all active players const CBitVec<MAX_EDICTS> *pEntityTransmitBits = engine->GetEntityTransmitBitsForClient( player->entindex() - 1 ); for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBasePlayer *pPlayer = UTIL_PlayerByIndex( i ); if ( !pPlayer || player == pPlayer ) continue; // Custom checks for if things should lag compensate (based on things like what team the player is on). if ( !player->WantsLagCompensationOnEntity( pPlayer, cmd, pEntityTransmitBits ) ) continue; // Move other player back in time BacktrackPlayer( pPlayer, TICKS_TO_TIME( targettick ) ); } // also iterate all monsters CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); int nAIs = g_AI_Manager.NumAIs(); for ( int i = 0; i < nAIs; i++ ) { CAI_BaseNPC *pNPC = ppAIs[i]; // Custom checks for if things should lag compensate if ( !pNPC || !player->WantsLagCompensationOnEntity( pNPC, cmd, pEntityTransmitBits ) ) continue; // Move NPC back in time BacktrackEntity( pNPC, TICKS_TO_TIME( targettick ) ); } }
bool _ComputeRagdollBones( const ragdoll_t *pRagdoll, matrix3x4_t &parentTransform, matrix3x4_t *pBones, Vector *pPositions, QAngle *pAngles ) { matrix3x4_t inverted, output; #ifdef _DEBUG CBitVec<MAXSTUDIOBONES> vBonesComputed; vBonesComputed.ClearAll(); #endif for ( int i = 0; i < pRagdoll->listCount; ++i ) { const ragdollelement_t& element = pRagdoll->list[ i ]; // during restore if a model has changed since the file was saved, this could be NULL if ( !element.pObject ) return false; int const boneIndex = pRagdoll->boneIndex[ i ]; if ( boneIndex < 0 ) { AssertMsg( 0, "Replay: No mapping for ragdoll bone\n" ); return false; } // Get global transform and put it into the bone cache element.pObject->GetPositionMatrix( &pBones[ boneIndex ] ); // Ensure a fixed translation from the parent (no stretching) if ( element.parentIndex >= 0 && !pRagdoll->allowStretch ) { int parentIndex = pRagdoll->boneIndex[ element.parentIndex ]; #ifdef _DEBUG // Make sure we computed the parent already Assert( vBonesComputed.IsBitSet(parentIndex) ); #endif // overwrite the position from physics to force rigid attachment // NOTE: On the client we actually override this with the proper parent bone in each LOD Vector out; VectorTransform( element.originParentSpace, pBones[ parentIndex ], out ); MatrixSetColumn( out, 3, pBones[ boneIndex ] ); MatrixInvert( pBones[ parentIndex ], inverted ); } else if ( element.parentIndex == - 1 ) { // Decompose into parent space MatrixInvert( parentTransform, inverted ); } #ifdef _DEBUG vBonesComputed.Set( boneIndex, true ); #endif // Compute local transform and put into 'output' ConcatTransforms( inverted, pBones[ boneIndex ], output ); // Cache as Euler/position MatrixAngles( output, pAngles[ i ], pPositions[ i ] ); } return true; }
void CGroundLine::SetParameters( const Vector &vStart, const Vector &vEnd, const Vector &vStartColor, // Color values 0-1 const Vector &vEndColor, float alpha, float lineWidth ) { m_vStart = vStart; m_vEnd = vEnd; m_vStartColor = vStartColor; m_vEndColor = vEndColor; m_Alpha = alpha; m_LineWidth = lineWidth; Vector vTo( vEnd.x - vStart.x, vEnd.y - vStart.y, 0 ); float flXYLen = vTo.Length(); // Recalculate our segment list. unsigned int nSteps = (int)flXYLen / XY_PER_SEGMENT; nSteps = clamp( nSteps, 8, MAX_GROUNDLINE_SEGMENTS ) & ~1; unsigned int nMaxSteps = nSteps / 2; // First generate the sequence. We generate every other point here so it can insert fixup points to prevent // it from crossing world geometry. Vector pt[MAX_GROUNDLINE_SEGMENTS]; Vector vStep = (Vector(m_vEnd[0], m_vEnd[1], 0) - Vector(m_vStart[0], m_vStart[1], 0)) / (nMaxSteps-1); pt[0] = FindBestSurfacePoint(m_vStart); unsigned int i; for(i=1; i < nMaxSteps; i++) pt[i<<1] = FindBestSurfacePoint(pt[(i-1)<<1] + vStep); CBitVec<MAX_GROUNDLINE_SEGMENTS> pointsUsed; pointsUsed.ClearAll(); // Now try to make sure they don't intersect the geometry. for(i=0; i < nMaxSteps-1; i++) { Vector &a = pt[i<<1]; Vector &b = pt[(i+1)<<1]; trace_t trace; UTIL_TraceLine(a, b, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace); if(trace.fraction < 1) { int cIndex = (i<<1)+1; Vector &c = pt[cIndex]; // Ok, this line segment intersects the world. Do a binary search to try to find the // point of intersection. Vector hi, lo; if(a.z < b.z) { hi = b; lo = a; } else { hi = a; lo = b; } if(BinSearchSegments(lo, hi, Vector(lo[0],lo[1],hi[2]), 15, &c)) { pointsUsed.Set( cIndex ); } else if(BinSearchSegments(lo, hi, Vector(hi[0],hi[1],hi[2]+500), 15, &c)) { pointsUsed.Set( cIndex ); } } } // Export the points. m_nPoints = 0; for(i=0; i < nSteps; i++) { // Every other point is always active. if( pointsUsed.Get( i ) || !(i & 1) ) { m_Points[m_nPoints] = pt[i]; ++m_nPoints; } } }