//=============================================================================// // // Purpose: // //=============================================================================// #include "engine/host.h" #include "clientstate.h" #include "cl_splitscreen.h" #include "cl_main.h" #include "engine/net.h" #include "cdll_engine_int.h" static float s_lastMovementCall = 0.0; static float s_LastFrameTime = 0.0; //----------------------------------------------------------------------------- // Purpose: run client's movement frame //----------------------------------------------------------------------------- void H_CL_Move() { CClientState* cl = GetBaseLocalClient(); if (!cl->IsConnected()) return; if (!v_Host_ShouldRun()) return; int commandTick = -1; if (cl->m_CurrFrameSnapshot) commandTick = cl->m_CurrFrameSnapshot->m_TickUpdate.m_nCommandTick; bool sendPacket = true; CNetChan* chan = cl->m_NetChannel; // Only perform clamping and packeting if the timescale value is default, // else the timescale change won't be handled in the player's movement. const float hostTimeScale = host_timescale->GetFloat(); const bool isTimeScaleDefault = hostTimeScale == 1.0; const float minFrameTime = usercmd_frametime_min->GetFloat(); const float maxFrameTime = usercmd_frametime_max->GetFloat(); const float netTime = float(*g_pNetTime); if (cl->m_flNextCmdTime <= (maxFrameTime * 0.5f) + netTime) sendPacket = chan->CanPacket(); else if (cl->m_nOutgoingCommandNr - (commandTick+1) < MAX_BACKUP_COMMANDS || isTimeScaleDefault) sendPacket = false; const bool isActive = cl->IsActive(); if (isActive) { const float movementCallTime = float(Plat_FloatTime()); const int outCommandNr = cl->m_nOutgoingCommandNr; const bool isPaused = cl->IsPaused(); const int nextCommandNr = isPaused ? outCommandNr : outCommandNr+1; FOR_EACH_SPLITSCREEN_PLAYER(i) { if (g_pSplitScreenMgr->IsDisconnecting(i)) continue; float frameTime = 0.0f; if (cl_move_use_dt->GetBool()) { float timeScale; float deltaTime; if (isPaused) { timeScale = 1.0f; frameTime = movementCallTime - s_lastMovementCall; deltaTime = frameTime; } else { timeScale = hostTimeScale; frameTime = cl->m_flFrameTime + s_LastFrameTime; deltaTime = frameTime / timeScale; } // Clamp the frame time to the maximum. if (deltaTime > maxFrameTime) frameTime = timeScale * maxFrameTime; // Drop this frame if delta time is below the minimum. const bool dropFrame = (isTimeScaleDefault && deltaTime < minFrameTime); // This check originally was 'time < 0.0049999999', but // that caused problems when the framerate was above 190. if (dropFrame) { s_LastFrameTime = frameTime; return; } s_LastFrameTime = 0.0; } //else if (isPaused) // // This hlClient virtual call just returns false. // Create and store usercmd structure. g_pHLClient->CreateMove(nextCommandNr, frameTime, !isPaused); cl->m_nOutgoingCommandNr = nextCommandNr; } CL_RunPrediction(); if (sendPacket) CL_SendMove(); else chan->SetChoked(); // Choke the packet... s_lastMovementCall = movementCallTime; } if (sendPacket) { if (isActive) { CLC_ClientTick tickMsg(cl->m_nDeltaTick, cl->m_nStringTableAckTick); chan->SendNetMsg(tickMsg, false, false); } chan->SendDatagram(nullptr); // Use full update rate when active. float delta = netTime - float(cl->m_flNextCmdTime); float maxDelta = fminf(fmaxf(delta, 0.0f), minFrameTime); cl->m_flNextCmdTime = double(minFrameTime + netTime - maxDelta); } } void VCL_Main::Attach() const { DetourAttach(&CL_Move, &H_CL_Move); } void VCL_Main::Detach() const { DetourDetach(&CL_Move, &H_CL_Move); }