Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/engine/shared/config_variables_bestclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ MACRO_CONFIG_INT(BcPrevInpMousesensSmallSens, bc_prev_inp_mousesens_small_sens,
MACRO_CONFIG_INT(BcToggleSmallSens, bc_toggle_small_sens, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Use toggle mode for small sens bind")

// Inputs
MACRO_CONFIG_INT(BcInputDebounce, bc_input_debounce, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Preserve button presses shorter than one simulation tick")
MACRO_CONFIG_INT(BcInputs, bc_inputs, 0, 0, 6, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Input prediction mode (0 = off, 1 = fast, 2 = best, 3 = saiko, 4 = delta, 5 = f, 6 = cloud)")
MACRO_CONFIG_INT(BcBestInputAmount, bc_best_input_amount, 0, 0, 1000, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Best input prediction amount in 0.01 ticks")
MACRO_CONFIG_INT(BcBestInputSmoothing, bc_best_input_smoothing, 0, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Best input smoothing amount (0-100%)")
Expand Down
6 changes: 5 additions & 1 deletion src/game/client/components/bestclient/menus_bestclient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2976,7 +2976,7 @@ void CMenus::RenderSettingsBestClientGameplay(CUIRect MainView)
const float InputsExpandedTargetHeight = (MarginSmall + LineSize) + InputsModeFieldsHeight;
const float InputsExpandedHeight = BC_MODULE_REVEAL(InputsEnabled, InputsExpandedTargetHeight, Client()->RenderFrameTime());
const float InputsHeaderHeight = LineSize + MarginSmall + LineSize;
const float InputsFooterLines = g_Config.m_ClSubTickAiming ? 2.0f : 3.0f;
const float InputsFooterLines = g_Config.m_ClSubTickAiming ? 3.0f : 4.0f;
const float InputsBlockHeight = InputsHeaderHeight + InputsExpandedHeight + InputsFooterLines * (MarginSmall + LineSize);

CUIRect InputsBlock;
Expand Down Expand Up @@ -3176,6 +3176,10 @@ void CMenus::RenderSettingsBestClientGameplay(CUIRect MainView)
InputsBlock.HSplitTop(LineSize, &Content, &InputsBlock);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_BcAutoMargin, BcLocalize("Auto margin"), &g_Config.m_BcAutoMargin, &Content, LineSize);

InputsBlock.HSplitTop(MarginSmall, nullptr, &InputsBlock);
InputsBlock.HSplitTop(LineSize, &Content, &InputsBlock);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_BcInputDebounce, BcLocalize("Input Debounce"), &g_Config.m_BcInputDebounce, &Content, LineSize);

LeftColumn.HSplitTop(MarginBetweenViews, nullptr, &LeftColumn);

const bool SnapTapBlocked = GameClient()->m_SnapTap.IsBlockedByCommunity();
Expand Down
72 changes: 57 additions & 15 deletions src/game/client/components/controls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ void CControls::OnReset()

void CControls::ResetInput(int Dummy)
{
m_aInputDebounce[Dummy] = {};
m_aLastData[Dummy].m_Direction = 0;
// simulate releasing the fire button
if((m_aLastData[Dummy].m_Fire & 1) != 0)
Expand All @@ -69,6 +70,7 @@ struct CInputState
{
CControls *m_pControls;
int *m_apVariables[NUM_DUMMIES];
int m_Input;
};

void CControls::ConKeyInputState(IConsole::IResult *pResult, void *pUserData)
Expand All @@ -78,7 +80,22 @@ void CControls::ConKeyInputState(IConsole::IResult *pResult, void *pUserData)
if(pState->m_pControls->GameClient()->m_GameInfo.m_BugDDRaceInput && pState->m_pControls->GameClient()->m_Snap.m_SpecInfo.m_Active)
return;

*pState->m_apVariables[g_Config.m_ClDummy] = pResult->GetInteger(0);
int *pVariable = pState->m_apVariables[g_Config.m_ClDummy];
const int Value = pResult->GetInteger(0);
if(!Value && *pVariable && g_Config.m_BcInputDebounce && pState->m_Input >= 0)
pState->m_pControls->InputDebounce(g_Config.m_ClDummy, pState->m_Input);
*pVariable = Value;
}

void CControls::InputDebounce(int Dummy, int Input)
{
switch(Input)
{
case INPUT_LEFT: if(m_aLastData[Dummy].m_Direction != -1) m_aInputDebounce[Dummy].m_Direction = -1; break;
case INPUT_RIGHT: if(m_aLastData[Dummy].m_Direction != 1) m_aInputDebounce[Dummy].m_Direction = 1; break;
case INPUT_JUMP: m_aInputDebounce[Dummy].m_Jump = m_aLastData[Dummy].m_Jump ? -1 : 1; break;
case INPUT_HOOK: m_aInputDebounce[Dummy].m_Hook = m_aLastData[Dummy].m_Hook ? -1 : 1; break;
}
}

void CControls::ConKeyInputCounter(IConsole::IResult *pResult, void *pUserData)
Expand All @@ -89,10 +106,10 @@ void CControls::ConKeyInputCounter(IConsole::IResult *pResult, void *pUserData)
return;

int *pVariable = pState->m_apVariables[g_Config.m_ClDummy];
if(((*pVariable) & 1) != pResult->GetInteger(0))
const bool Pressed = pResult->GetInteger(0) != 0;
if(((*pVariable) & 1) != Pressed)
(*pVariable)++;
*pVariable &= INPUT_STATE_MASK;
// bestclient
if(pVariable == &pState->m_pControls->m_aInputData[g_Config.m_ClDummy].m_Fire)
pState->m_pControls->GameClient()->m_BestClient.OnGoresFireInput(pResult->GetInteger(0));
// bestclient
Expand Down Expand Up @@ -125,27 +142,27 @@ void CControls::OnConsoleInit()
{
// game commands
{
static CInputState s_State = {this, {&m_aInputDirectionLeft[0], &m_aInputDirectionLeft[1]}};
static CInputState s_State = {this, {&m_aInputDirectionLeft[0], &m_aInputDirectionLeft[1]}, INPUT_LEFT};
Console()->Register("+left", "", CFGFLAG_CLIENT, ConKeyInputState, &s_State, "Move left");
}
{
static CInputState s_State = {this, {&m_aInputDirectionRight[0], &m_aInputDirectionRight[1]}};
static CInputState s_State = {this, {&m_aInputDirectionRight[0], &m_aInputDirectionRight[1]}, INPUT_RIGHT};
Console()->Register("+right", "", CFGFLAG_CLIENT, ConKeyInputState, &s_State, "Move right");
}
{
static CInputState s_State = {this, {&m_aInputData[0].m_Jump, &m_aInputData[1].m_Jump}};
static CInputState s_State = {this, {&m_aInputData[0].m_Jump, &m_aInputData[1].m_Jump}, INPUT_JUMP};
Console()->Register("+jump", "", CFGFLAG_CLIENT, ConKeyInputState, &s_State, "Jump");
}
{
static CInputState s_State = {this, {&m_aInputData[0].m_Hook, &m_aInputData[1].m_Hook}};
static CInputState s_State = {this, {&m_aInputData[0].m_Hook, &m_aInputData[1].m_Hook}, INPUT_HOOK};
Console()->Register("+hook", "", CFGFLAG_CLIENT, ConKeyInputState, &s_State, "Hook");
}
{
static CInputState s_State = {this, {&m_aInputData[0].m_Fire, &m_aInputData[1].m_Fire}};
static CInputState s_State = {this, {&m_aInputData[0].m_Fire, &m_aInputData[1].m_Fire}, -1};
Console()->Register("+fire", "", CFGFLAG_CLIENT, ConKeyInputCounter, &s_State, "Fire");
}
{
static CInputState s_State = {this, {&m_aShowHookColl[0], &m_aShowHookColl[1]}};
static CInputState s_State = {this, {&m_aShowHookColl[0], &m_aShowHookColl[1]}, -1};
Console()->Register("+showhookcoll", "", CFGFLAG_CLIENT, ConKeyInputState, &s_State, "Show Hook Collision");
}

Expand Down Expand Up @@ -194,6 +211,9 @@ void CControls::OnMessage(int Msg, void *pRawMsg)

int CControls::SnapInput(int *pData)
{
const int UnlatchedJump = m_aInputData[g_Config.m_ClDummy].m_Jump;
const int UnlatchedHook = m_aInputData[g_Config.m_ClDummy].m_Hook;

// bestclient
GameClient()->m_BestClient.UpdateGoresMode();
// bestclient
Expand Down Expand Up @@ -252,7 +272,6 @@ int CControls::SnapInput(int *pData)
ResetInput(g_Config.m_ClDummy);

mem_copy(pData, &m_aInputData[g_Config.m_ClDummy], sizeof(m_aInputData[0]));

// set the target anyway though so that we can keep seeing our surroundings,
// even if chat or menu are activated
vec2 Pos = GameClient()->m_Controls.m_aMousePos[g_Config.m_ClDummy];
Expand Down Expand Up @@ -303,6 +322,13 @@ int CControls::SnapInput(int *pData)
const bool LeftPressed = m_aInputDirectionLeft[g_Config.m_ClDummy] != 0;
const bool RightPressed = m_aInputDirectionRight[g_Config.m_ClDummy] != 0;
m_aInputData[g_Config.m_ClDummy].m_Direction = GameClient()->m_SnapTap.ResolveMovementDirection(g_Config.m_ClDummy, LeftPressed, RightPressed, true);
const CInputDebounceState &DebounceState = m_aInputDebounce[g_Config.m_ClDummy];
if(m_aInputData[g_Config.m_ClDummy].m_Direction == 0 && DebounceState.m_Direction)
m_aInputData[g_Config.m_ClDummy].m_Direction = DebounceState.m_Direction;
if(DebounceState.m_Jump)
m_aInputData[g_Config.m_ClDummy].m_Jump = DebounceState.m_Jump > 0;
if(DebounceState.m_Hook)
m_aInputData[g_Config.m_ClDummy].m_Hook = DebounceState.m_Hook > 0;
// bestclient

// dummy copy moves
Expand Down Expand Up @@ -380,10 +406,22 @@ int CControls::SnapInput(int *pData)
m_aLastData[g_Config.m_ClDummy] = m_aInputData[g_Config.m_ClDummy];

if(!Send)
{
if(m_aInputDebounce[g_Config.m_ClDummy].m_Jump)
m_aInputData[g_Config.m_ClDummy].m_Jump = UnlatchedJump;
if(m_aInputDebounce[g_Config.m_ClDummy].m_Hook)
m_aInputData[g_Config.m_ClDummy].m_Hook = UnlatchedHook;
m_aInputDebounce[g_Config.m_ClDummy] = {};
return 0;
}

m_LastSendTime = time_get();
mem_copy(pData, &m_aInputData[g_Config.m_ClDummy], sizeof(m_aInputData[0]));
if(m_aInputDebounce[g_Config.m_ClDummy].m_Jump)
m_aInputData[g_Config.m_ClDummy].m_Jump = UnlatchedJump;
if(m_aInputDebounce[g_Config.m_ClDummy].m_Hook)
m_aInputData[g_Config.m_ClDummy].m_Hook = UnlatchedHook;
m_aInputDebounce[g_Config.m_ClDummy] = {};
return sizeof(m_aInputData[0]);
}

Expand Down Expand Up @@ -540,6 +578,10 @@ bool CControls::CheckNewInput()
const bool LeftPressed = m_aInputDirectionLeft[g_Config.m_ClDummy] != 0;
const bool RightPressed = m_aInputDirectionRight[g_Config.m_ClDummy] != 0;
TestInput.m_Direction = GameClient()->m_SnapTap.ResolveMovementDirection(g_Config.m_ClDummy, LeftPressed, RightPressed, false);
const CInputDebounceState &DebounceState = m_aInputDebounce[g_Config.m_ClDummy];
if(TestInput.m_Direction == 0 && DebounceState.m_Direction) TestInput.m_Direction = DebounceState.m_Direction;
if(DebounceState.m_Jump) TestInput.m_Jump = DebounceState.m_Jump > 0;
if(DebounceState.m_Hook) TestInput.m_Hook = DebounceState.m_Hook > 0;

bool NewInput = false;
if(m_aFastInput[g_Config.m_ClDummy].m_Direction != TestInput.m_Direction)
Expand All @@ -564,7 +606,6 @@ bool CControls::CheckNewInput()
}

m_aFastInput[g_Config.m_ClDummy] = TestInput;

return NewInput;
}
// bestclient
Expand All @@ -579,6 +620,10 @@ bool CControls::CheckNewInput()
const bool LeftPressed = m_aInputDirectionLeft[Dummy] != 0;
const bool RightPressed = m_aInputDirectionRight[Dummy] != 0;
TestInput.m_Direction = GameClient()->m_SnapTap.ResolveMovementDirection(Dummy, LeftPressed, RightPressed, false);
const CInputDebounceState &DebounceState = m_aInputDebounce[Dummy];
if(TestInput.m_Direction == 0 && DebounceState.m_Direction) TestInput.m_Direction = DebounceState.m_Direction;
if(DebounceState.m_Jump) TestInput.m_Jump = DebounceState.m_Jump > 0;
if(DebounceState.m_Hook) TestInput.m_Hook = DebounceState.m_Hook > 0;
// bestclient
}

Expand Down Expand Up @@ -638,8 +683,5 @@ bool CControls::CheckNewInput()
m_aFastInput[Dummy] = TestInput;
}

if(NewInput[0] || NewInput[1])
return true;
else
return false;
return NewInput[0] || NewInput[1];
}
22 changes: 22 additions & 0 deletions src/game/client/components/controls.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,29 @@ class CControls : public CComponent
void ResetInput(int Dummy);
bool CheckNewInput();

// bestclient
void InputDebounce(int Dummy, int Input);
struct CInputDebounceState
{
int m_Direction = 0;
int m_Jump = 0;
int m_Hook = 0;
};
CInputDebounceState m_aInputDebounce[NUM_DUMMIES];

// bestclient

private:
// bestclient
enum
{
INPUT_LEFT,
INPUT_RIGHT,
INPUT_JUMP,
INPUT_HOOK,
};
// bestclient

static void ConKeyInputState(IConsole::IResult *pResult, void *pUserData);
static void ConKeyInputCounter(IConsole::IResult *pResult, void *pUserData);
static void ConKeyInputSet(IConsole::IResult *pResult, void *pUserData);
Expand Down
5 changes: 4 additions & 1 deletion src/game/client/gameclient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6365,7 +6365,10 @@ void CGameClient::StoreSave(const char *pTeamMembers, const char *pGeneratedCode
bool CGameClient::CheckNewInput()
{
if(IsCloudInputMode()) // bestclient
return m_CloudInput.CheckNewInput(m_Controls); // bestclient
{
const bool NewInput = m_CloudInput.CheckNewInput(m_Controls);
return NewInput;
}
return m_Controls.CheckNewInput();
}

Expand Down