[579] Add simulated input lag option (#1438)

* [579] Add simulated input lag option

* Continue to clear buffer when inputs are blocked

* Changes from feedback
This commit is contained in:
Garrett Cox 2022-09-19 21:49:13 -05:00 committed by GitHub
parent 55e79cd9d2
commit f712068a17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 49 additions and 29 deletions

View File

@ -80,6 +80,7 @@ namespace Ship {
if (backend->GetGuid() == "Auto") { if (backend->GetGuid() == "Auto") {
for (const auto& device : physicalDevices) { for (const auto& device : physicalDevices) {
if(shouldBlockGameInput && device->GetGuid() != "Keyboard") { if(shouldBlockGameInput && device->GetGuid() != "Keyboard") {
device->Read(nullptr, i);
continue; continue;
} }
device->Read(&pad[i], i); device->Read(&pad[i], i);
@ -87,6 +88,7 @@ namespace Ship {
continue; continue;
} }
if(shouldBlockGameInput && backend->GetGuid() != "Keyboard") { if(shouldBlockGameInput && backend->GetGuid() != "Keyboard") {
backend->Read(nullptr, i);
continue; continue;
} }
backend->Read(&pad[i], i); backend->Read(&pad[i], i);

View File

@ -1,6 +1,7 @@
#include "Controller.h" #include "Controller.h"
#include <memory> #include <memory>
#include <algorithm> #include <algorithm>
#include "Cvar.h"
#if __APPLE__ #if __APPLE__
#include <SDL_events.h> #include <SDL_events.h>
#else #else
@ -21,58 +22,67 @@ namespace Ship {
void Controller::Read(OSContPad* pad, int32_t virtualSlot) { void Controller::Read(OSContPad* pad, int32_t virtualSlot) {
ReadFromSource(virtualSlot); ReadFromSource(virtualSlot);
OSContPad padToBuffer = { 0 };
#ifndef __WIIU__ #ifndef __WIIU__
SDL_PumpEvents(); SDL_PumpEvents();
#endif #endif
// Button Inputs // Button Inputs
pad->button |= getPressedButtons(virtualSlot) & 0xFFFF; padToBuffer.button |= getPressedButtons(virtualSlot) & 0xFFFF;
// Stick Inputs // Stick Inputs
if (getLeftStickX(virtualSlot) == 0) { if (getLeftStickX(virtualSlot) == 0) {
if (getPressedButtons(virtualSlot) & BTN_STICKLEFT) { if (getPressedButtons(virtualSlot) & BTN_STICKLEFT) {
pad->stick_x = -128; padToBuffer.stick_x = -128;
} else if (getPressedButtons(virtualSlot) & BTN_STICKRIGHT) { } else if (getPressedButtons(virtualSlot) & BTN_STICKRIGHT) {
pad->stick_x = 127; padToBuffer.stick_x = 127;
} }
} else { } else {
pad->stick_x = getLeftStickX(virtualSlot); padToBuffer.stick_x = getLeftStickX(virtualSlot);
} }
if (getLeftStickY(virtualSlot) == 0) { if (getLeftStickY(virtualSlot) == 0) {
if (getPressedButtons(virtualSlot) & BTN_STICKDOWN) { if (getPressedButtons(virtualSlot) & BTN_STICKDOWN) {
pad->stick_y = -128; padToBuffer.stick_y = -128;
} else if (getPressedButtons(virtualSlot) & BTN_STICKUP) { } else if (getPressedButtons(virtualSlot) & BTN_STICKUP) {
pad->stick_y = 127; padToBuffer.stick_y = 127;
} }
} else { } else {
pad->stick_y = getLeftStickY(virtualSlot); padToBuffer.stick_y = getLeftStickY(virtualSlot);
} }
// Stick Inputs // Stick Inputs
if (getRightStickX(virtualSlot) == 0) { if (getRightStickX(virtualSlot) == 0) {
if (getPressedButtons(virtualSlot) & BTN_VSTICKLEFT) { if (getPressedButtons(virtualSlot) & BTN_VSTICKLEFT) {
pad->right_stick_x = -128; padToBuffer.right_stick_x = -128;
} else if (getPressedButtons(virtualSlot) & BTN_VSTICKRIGHT) { } else if (getPressedButtons(virtualSlot) & BTN_VSTICKRIGHT) {
pad->right_stick_x = 127; padToBuffer.right_stick_x = 127;
} }
} else { } else {
pad->right_stick_x = getRightStickX(virtualSlot); padToBuffer.right_stick_x = getRightStickX(virtualSlot);
} }
if (getRightStickY(virtualSlot) == 0) { if (getRightStickY(virtualSlot) == 0) {
if (getPressedButtons(virtualSlot) & BTN_VSTICKDOWN) { if (getPressedButtons(virtualSlot) & BTN_VSTICKDOWN) {
pad->right_stick_y = -128; padToBuffer.right_stick_y = -128;
} else if (getPressedButtons(virtualSlot) & BTN_VSTICKUP) { } else if (getPressedButtons(virtualSlot) & BTN_VSTICKUP) {
pad->right_stick_y = 127; padToBuffer.right_stick_y = 127;
} }
} else { } else {
pad->right_stick_y = getRightStickY(virtualSlot); padToBuffer.right_stick_y = getRightStickY(virtualSlot);
} }
// Gyro // Gyro
pad->gyro_x = getGyroX(virtualSlot); padToBuffer.gyro_x = getGyroX(virtualSlot);
pad->gyro_y = getGyroY(virtualSlot); padToBuffer.gyro_y = getGyroY(virtualSlot);
padBuffer.push_front(padToBuffer);
*pad = padBuffer[std::min(padBuffer.size(), (size_t)CVar_GetS32("gSimulatedInputLag", 0))];
while (padBuffer.size() > 6) {
padBuffer.pop_back();
}
} }
void Controller::SetButtonMapping(int32_t virtualSlot, int32_t n64Button, int32_t dwScancode) { void Controller::SetButtonMapping(int32_t virtualSlot, int32_t n64Button, int32_t dwScancode) {

View File

@ -4,6 +4,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <cstdint> #include <cstdint>
#include <queue>
#include "UltraController.h" #include "UltraController.h"
#include "ControllerAttachment.h" #include "ControllerAttachment.h"
#include <unordered_map> #include <unordered_map>
@ -84,5 +85,6 @@ namespace Ship {
std::unordered_map<int32_t, std::shared_ptr<DeviceProfile>> profiles; std::unordered_map<int32_t, std::shared_ptr<DeviceProfile>> profiles;
std::unordered_map<int32_t, std::shared_ptr<Buttons>> ButtonData = {}; std::unordered_map<int32_t, std::shared_ptr<Buttons>> ButtonData = {};
std::deque<OSContPad> padBuffer;
}; };
} }

View File

@ -504,6 +504,11 @@ namespace GameMenuBar {
UIWidgets::EnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false); UIWidgets::EnhancementSliderFloat("Input Scale: %.1f", "##Input", "gInputScale", 1.0f, 3.0f, "", 1.0f, false);
UIWidgets::Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting"); UIWidgets::Tooltip("Sets the on screen size of the displayed inputs from the Show Inputs setting");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
UIWidgets::Spacer(0);
ImGui::PushItemWidth(ImGui::GetWindowSize().x - 20.0f);
UIWidgets::EnhancementSliderInt("Simulated Input Lag: %d frames", "##SimulatedInputLag", "gSimulatedInputLag", 0, 6, "", 0, false);
UIWidgets::Tooltip("Buffers your inputs to be executed a specified amount of frames later");
ImGui::PopItemWidth();
ImGui::EndMenu(); ImGui::EndMenu();
} }

View File

@ -483,10 +483,7 @@ static void RunFrame()
Graph_StartFrame(); Graph_StartFrame();
// TODO: Workaround for rumble being too long. Implement os thread functions.
for (int i = 0; i < 3; i++) {
PadMgr_ThreadEntry(&gPadMgr); PadMgr_ThreadEntry(&gPadMgr);
}
Graph_Update(&runFrameContext.gfxCtx, runFrameContext.gameState); Graph_Update(&runFrameContext.gfxCtx, runFrameContext.gameState);
ticksB = GetPerfCounter(); ticksB = GetPerfCounter();

View File

@ -331,6 +331,9 @@ void PadMgr_HandleRetraceMsg(PadMgr* padMgr) {
} }
padMgr->validCtrlrsMask = mask; padMgr->validCtrlrsMask = mask;
// TODO: Workaround for rumble being too long. Implement os thread functions.
// Game logic runs at 20hz but input thread runs at 60 hertz, so we call this 3 times
for (i = 0; i < 3; i++) {
/* if (gFaultStruct.msgId) { /* if (gFaultStruct.msgId) {
PadMgr_RumbleStop(padMgr); PadMgr_RumbleStop(padMgr);
} else */ if (padMgr->rumbleOffFrames > 0) { } else */ if (padMgr->rumbleOffFrames > 0) {
@ -342,6 +345,7 @@ void PadMgr_HandleRetraceMsg(PadMgr* padMgr) {
PadMgr_RumbleControl(padMgr); PadMgr_RumbleControl(padMgr);
--padMgr->rumbleOnFrames; --padMgr->rumbleOnFrames;
} }
}
} }
void PadMgr_HandlePreNMI(PadMgr* padMgr) { void PadMgr_HandlePreNMI(PadMgr* padMgr) {