From 806390f62de1a5714424334c89203a9bf3240b96 Mon Sep 17 00:00:00 2001 From: Human Gamer <39096122+HumanGamer@users.noreply.github.com> Date: Tue, 9 Apr 2024 12:55:38 -0500 Subject: [PATCH] Attempts at reducing input lag --- engine/source/core/torqueConfig.h | 6 ++ engine/source/game/gameBase.cpp | 7 ++ engine/source/game/gameBase.h | 4 + engine/source/game/gameConnection.cpp | 5 ++ engine/source/game/gameConnection.h | 4 + engine/source/game/main.cpp | 21 +++++ engine/source/game/marble/marble.cpp | 112 +++++++++++++++++++++++++- engine/source/game/marble/marble.h | 4 + engine/source/game/moveManager.cpp | 48 +++++++++++ engine/source/sim/processList.cpp | 18 +++++ 10 files changed, 227 insertions(+), 2 deletions(-) diff --git a/engine/source/core/torqueConfig.h b/engine/source/core/torqueConfig.h index c5a7bdb4..e486a7ce 100644 --- a/engine/source/core/torqueConfig.h +++ b/engine/source/core/torqueConfig.h @@ -81,6 +81,12 @@ // Define me to allow switching physics systems in script //#define MB_PHYSICS_SWITCHABLE +/// Define me to disable input lag +//#define MB_DISABLE_INPUT_LAG + +// Define me to make client physics run every frame +//#define MB_CLIENT_PHYSICS_EVERY_FRAME + // Define me to use MBO physics (does nothing if MB_PHYSICS_SWITCHABLE is defined) //#define MBO_PHYSICS diff --git a/engine/source/game/gameBase.cpp b/engine/source/game/gameBase.cpp index 52555eec..eca581ef 100644 --- a/engine/source/game/gameBase.cpp +++ b/engine/source/game/gameBase.cpp @@ -282,6 +282,13 @@ void GameBase::processTick(const Move* move) #endif } +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME +void GameBase::processPhysicsTick(const Move *move, F32 dt) +{ + +} +#endif + void GameBase::interpolateTick(F32 delta) { } diff --git a/engine/source/game/gameBase.h b/engine/source/game/gameBase.h index 3ec9ebf8..7315a656 100644 --- a/engine/source/game/gameBase.h +++ b/engine/source/game/gameBase.h @@ -295,6 +295,10 @@ class GameBase : public SceneObject, public ProcessObject /// @param move Move event corresponding to this tick, or NULL. virtual void processTick(const Move* move); +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME + virtual void processPhysicsTick(const Move* move, F32 dt); +#endif + /// Interpolates between tick events. This takes place on the CLIENT ONLY. /// /// @param delta Time since last call to interpolate diff --git a/engine/source/game/gameConnection.cpp b/engine/source/game/gameConnection.cpp index 99a4f0e7..f22095b3 100644 --- a/engine/source/game/gameConnection.cpp +++ b/engine/source/game/gameConnection.cpp @@ -50,8 +50,13 @@ GameConnection::GameConnection() mLastClientMove = 0; mFirstMoveIndex = 0; mLastSentMove = 0; +#ifdef MB_DISABLE_INPUT_LAG + mTargetMoveListSize = 0; + mMaxMoveListSize = 1; +#else mTargetMoveListSize = 3; mMaxMoveListSize = 5; +#endif mDataBlockModifiedKey = 0; mMaxDataBlockModifiedKey = 0; diff --git a/engine/source/game/gameConnection.h b/engine/source/game/gameConnection.h index 0bd687db..cd279826 100644 --- a/engine/source/game/gameConnection.h +++ b/engine/source/game/gameConnection.h @@ -290,6 +290,10 @@ class GameConnection : public NetConnection void pushMove(const Move& mv); bool getNextMove(Move& curMove); + +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME + bool getNextMove2(Move& curMove); +#endif bool isBacklogged(); virtual U32 getMoveList(Move**, U32* numMoves); MoveList& getMoves() { return mMoveList; } diff --git a/engine/source/game/main.cpp b/engine/source/game/main.cpp index 5321448e..33005e70 100644 --- a/engine/source/game/main.cpp +++ b/engine/source/game/main.cpp @@ -70,6 +70,10 @@ #include "discord/DiscordGame.h" //#include "../discord/discordGameSDK.h" +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME +#include "game/gameConnection.h" +#endif + #ifndef BUILD_TOOLS DemoGame GameObject; DemoNetInterface GameNetInterface; @@ -757,6 +761,11 @@ void DemoGame::processConsoleEvent(ConsoleEvent* event) Sim::postCurrentEvent(Sim::getRootGroup(), new SimConsoleEvent(2, const_cast(argv), false)); } +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME +Move gFirstMove; +Move gNextMove; +#endif + /// Process a time event and update all sub-processes void DemoGame::processTimeEvent(TimeEvent* event) { @@ -779,6 +788,18 @@ void DemoGame::processTimeEvent(TimeEvent* event) bool tickPass; if (!gGamePaused) { +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME + gFirstMove = gNextMove = NullMove; + if (GameConnection::getConnectionToServer() != NULL) + { + GameConnection* gc = GameConnection::getConnectionToServer(); + if (gc) + { + gc->getNextMove2(gFirstMove); + gc->getNextMove2(gNextMove); + } + } +#endif PROFILE_START(ServerProcess); tickPass = serverProcess(timeDelta); PROFILE_END(); diff --git a/engine/source/game/marble/marble.cpp b/engine/source/game/marble/marble.cpp index 5d1ebee5..6fedda28 100644 --- a/engine/source/game/marble/marble.cpp +++ b/engine/source/game/marble/marble.cpp @@ -2030,7 +2030,10 @@ void Marble::processTick(const Move* move) { Parent::processTick(move); +#ifndef MB_CLIENT_PHYSICS_EVERY_FRAME clearMarbleAxis(); +#endif + if ((mMode & TimerMode) != 0) { U32 bonusTime = mMarbleBonusTime; @@ -2075,7 +2078,7 @@ void Marble::processTick(const Move* move) if (move) { dMemcpy(&delta.move, move, sizeof(delta.move)); - newMove = move; + newMove = move; } else newMove = &delta.move; @@ -2083,9 +2086,12 @@ void Marble::processTick(const Move* move) else newMove = &NullMove; +#ifndef MB_CLIENT_PHYSICS_EVERY_FRAME processMoveTriggers(newMove); +#endif processCameraMove(newMove); +#ifndef MB_CLIENT_PHYSICS_EVERY_FRAME Point3F startPos(mPosition.x, mPosition.y, mPosition.z); advancePhysics(newMove, TickMs); @@ -2124,7 +2130,7 @@ void Marble::processTick(const Move* move) { if (Marble::smEndPadId && Marble::smEndPadId != -1) Marble::smEndPad = dynamic_cast(Sim::findObject(Marble::smEndPadId)); - + if (Marble::smEndPad.isNull()) Marble::smEndPadId = 0; } @@ -2153,10 +2159,112 @@ void Marble::processTick(const Move* move) mSinglePrecision.mVelocity = mVelocity; mSinglePrecision.mOmega = mOmega; + mPosition = mSinglePrecision.mPosition; + mVelocity = mSinglePrecision.mVelocity; + mOmega = mSinglePrecision.mOmega; +#else + if (isServerObject()) + { + processPhysicsTick(move, TickSec); + } +#endif +} + +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME +void Marble::processPhysicsTick(const Move *move, F32 dt) +{ + clearMarbleAxis(); + + const Move* newMove; + if (mControllable) + { + if (move) + { + dMemcpy(&delta.move, move, sizeof(delta.move)); + newMove = move; + } + else + newMove = &delta.move; + } + else + newMove = &NullMove; + + processMoveTriggers(newMove); +// processCameraMove(newMove); + + Point3F startPos(mPosition.x, mPosition.y, mPosition.z); + + //advancePhysics(newMove, TickMs); + advancePhysics(newMove, (U32)(dt * 1000.0f)); + + Point3F endPos(mPosition.x, mPosition.y, mPosition.z); + + processItemsAndTriggers(startPos, endPos); + updatePowerups(); + + if (mPadPtr) + { + bool oldOnPad = mOnPad; + updatePadState(); +#ifdef MB_ULTRA_PREVIEWS + if (oldOnPad != mOnPad && !(isGhost() || gSPMode)) +#else + if (oldOnPad != mOnPad && !isGhost()) +#endif + { + const char* funcName = "onLeavePad"; + if (!oldOnPad) + funcName = "onEnterPad"; + Con::executef(mDataBlock, 2, funcName, scriptThis()); + } + } + +#ifdef MB_ULTRA_PREVIEWS + if (isGhost() || gSPMode) +#else + if (isGhost()) +#endif + { + if (getControllingClient()) + { + if (Marble::smEndPad.isNull() || Marble::smEndPad->getId() != Marble::smEndPadId) + { + if (Marble::smEndPadId && Marble::smEndPadId != -1) + Marble::smEndPad = dynamic_cast(Sim::findObject(Marble::smEndPadId)); + + if (Marble::smEndPad.isNull()) + Marble::smEndPadId = 0; + } + } + } + + if (mOmega.len() < 0.000001) + mOmega.set(0, 0, 0); + +#ifdef MBG_PHYSICS +#define MB_RESPAWN_TRIGGER_ID 0 +#else +#define MB_RESPAWN_TRIGGER_ID 2 +#endif + +#ifdef MB_ULTRA_PREVIEWS + if (!(isGhost() || gSPMode) && mOOB && newMove->trigger[MB_RESPAWN_TRIGGER_ID]) +#else + if (!isGhost() && mOOB && newMove->trigger[MB_RESPAWN_TRIGGER_ID]) +#endif + Con::executef(this, 1, "onOOBClick"); + + notifyCollision(); + + mSinglePrecision.mPosition = mPosition; + mSinglePrecision.mVelocity = mVelocity; + mSinglePrecision.mOmega = mOmega; + mPosition = mSinglePrecision.mPosition; mVelocity = mSinglePrecision.mVelocity; mOmega = mSinglePrecision.mOmega; } +#endif //---------------------------------------------------------------------------- diff --git a/engine/source/game/marble/marble.h b/engine/source/game/marble/marble.h index 13fc3bf6..de49bd2e 100644 --- a/engine/source/game/marble/marble.h +++ b/engine/source/game/marble/marble.h @@ -314,6 +314,10 @@ class Marble : public ShapeBase void setPowerUpId(U32 id, bool reset); virtual void processTick(const Move* move); +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME + virtual void processPhysicsTick(const Move* move, F32 dt); +#endif + // Marble Physics Point3D getVelocityD() const; void setVelocityD(const Point3D& vel); diff --git a/engine/source/game/moveManager.cpp b/engine/source/game/moveManager.cpp index d5f67856..e5ffee90 100644 --- a/engine/source/game/moveManager.cpp +++ b/engine/source/game/moveManager.cpp @@ -397,6 +397,54 @@ bool GameConnection::getNextMove(Move& curMove) return true; } +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME +bool GameConnection::getNextMove2(Move& curMove) +{ + if (mMoveList.size() > MaxMoveQueueSize) + return false; + + F32 pitchAdd = MoveManager::mPitchUpSpeed - MoveManager::mPitchDownSpeed; + F32 yawAdd = MoveManager::mYawLeftSpeed - MoveManager::mYawRightSpeed; + F32 rollAdd = MoveManager::mRollRightSpeed - MoveManager::mRollLeftSpeed; + + curMove.pitch = MoveManager::mPitch + pitchAdd; + curMove.yaw = MoveManager::mYaw + yawAdd; + curMove.roll = MoveManager::mRoll + rollAdd; + + //MoveManager::mPitch = 0; + //MoveManager::mYaw = 0; + //MoveManager::mRoll = 0; + + + curMove.x = MoveManager::mRightAction - MoveManager::mLeftAction + MoveManager::mXAxis_L; + curMove.y = MoveManager::mForwardAction - MoveManager::mBackwardAction + MoveManager::mYAxis_L; + curMove.z = MoveManager::mUpAction - MoveManager::mDownAction; + + curMove.freeLook = MoveManager::mFreeLook; + curMove.deviceIsKeyboardMouse = MoveManager::mDeviceIsKeyboardMouse; + curMove.autoCenterCamera = MoveManager::mAutoCenterCamera; + + for (U32 i = 0; i < MaxTriggerKeys; i++) + { + curMove.trigger[i] = false; + if (MoveManager::mTriggerCount[i] & 1) + curMove.trigger[i] = true; + else if (!(MoveManager::mPrevTriggerCount[i] & 1) && MoveManager::mPrevTriggerCount[i] != MoveManager::mTriggerCount[i]) + curMove.trigger[i] = true; + //MoveManager::mPrevTriggerCount[i] = MoveManager::mTriggerCount[i]; + } + + curMove.horizontalDeadZone = MoveManager::mHorizontalDeadZone; + curMove.verticalDeadZone = MoveManager::mVerticalDeadZone; + curMove.cameraAccelSpeed = MoveManager::mCameraAccelSpeed; + curMove.cameraSensitivityHorizontal = MoveManager::mCameraSensitivityHorizontal; + curMove.cameraSensitivityVertical = MoveManager::mCameraSensitivityVertical; + + curMove.clamp(); // clamp for net traffic + return true; +} +#endif + void GameConnection::pushMove(const Move& mv) { U32 id = mFirstMoveIndex + mMoveList.size(); diff --git a/engine/source/sim/processList.cpp b/engine/source/sim/processList.cpp index 51c81a05..05ed2e6c 100644 --- a/engine/source/sim/processList.cpp +++ b/engine/source/sim/processList.cpp @@ -254,6 +254,11 @@ bool ProcessList::advanceServerTime(SimTime timeDelta) //---------------------------------------------------------------------------- +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME +extern Move gFirstMove; +extern Move gNextMove; +#endif + bool ProcessList::advanceClientTime(SimTime timeDelta) { PROFILE_START(AdvanceClientTime); @@ -267,6 +272,11 @@ bool ProcessList::advanceClientTime(SimTime timeDelta) if (mDirty) orderList(); +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME + Move firstmove = gFirstMove; + Move nextmove = gNextMove; +#endif + SimTime targetTime = mLastTime + timeDelta; SimTime targetTick = targetTime - (targetTime & 0x1F); SimTime tickCount = (targetTick - mLastTick) >> TickShift; @@ -332,6 +342,14 @@ bool ProcessList::advanceClientTime(SimTime timeDelta) GameBase* gb = getGameBase(pobj); gb->advanceTime(dt); } + +#ifdef MB_CLIENT_PHYSICS_EVERY_FRAME + for (ProcessObject* pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next) + { + GameBase* gb = getGameBase(pobj); + gb->processPhysicsTick(&firstmove, dt); + } +#endif } else { mSkipAdvanceObjectsMs -= timeDelta;