From 33b3fe08ba21431d65fc4fe9b680d00c64b39d46 Mon Sep 17 00:00:00 2001 From: AltF4 Date: Sun, 26 Dec 2021 10:26:14 -0700 Subject: [PATCH] Add support for bot input over EXI interface - Used for fast-forwarded inputs - Helpful when training AI - Only affects named-pipe input type --- Source/Core/Core/HW/EXI_DeviceSlippi.cpp | 34 ++++++ Source/Core/Core/HW/EXI_DeviceSlippi.h | 3 + Source/Core/Core/Slippi/SlippiPad.cpp | 6 + Source/Core/Core/Slippi/SlippiPad.h | 2 +- .../ControllerInterface.cpp | 38 ++++++ .../ControllerInterface/ControllerInterface.h | 2 + .../ControllerInterface/Pipes/Pipes.cpp | 110 +++++++++++++++++- .../ControllerInterface/Pipes/Pipes.h | 5 + 8 files changed, 198 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/HW/EXI_DeviceSlippi.cpp b/Source/Core/Core/HW/EXI_DeviceSlippi.cpp index 44177d5a1d..9f3f5536e9 100644 --- a/Source/Core/Core/HW/EXI_DeviceSlippi.cpp +++ b/Source/Core/Core/HW/EXI_DeviceSlippi.cpp @@ -33,6 +33,8 @@ //#include "Core/PatchEngine.h" #include "Core/PowerPC/PowerPC.h" +#include "InputCommon/ControllerInterface/ControllerInterface.h" + // Not clean but idk a better way atm #include "DolphinWX/Frame.h" #include "DolphinWX/Main.h" @@ -2944,6 +2946,35 @@ void CEXISlippi::prepareDelayResponse() } } +void CEXISlippi::prepareOverwriteInputs() +{ + m_read_queue.clear(); + // If blocking pipe input is configured, this will block until pipe input is sent for this frame + g_controller_interface.UpdateInput(); + std::map pads = g_controller_interface.GetSlippiPads(); + + // Insert the pads + for (int i = 1; i <= 4; i++) + { + if (pads.count(i-1) != 0) + { + // Do overwrite this port + m_read_queue.push_back(1); + for (int j = 0; j < SLIPPI_PAD_DATA_SIZE; j++) + { + m_read_queue.push_back(pads[i-1].padBuf[j]); + } + } + else + { + // Don't overwrite this port + m_read_queue.push_back(0); + appendWordToBuffer(&m_read_queue, 0); + appendWordToBuffer(&m_read_queue, 0); + } + } +} + void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize) { u8 *memPtr = Memory::GetPointer(_uAddr); @@ -3092,6 +3123,9 @@ void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize) case CMD_GET_DELAY: prepareDelayResponse(); break; + case CMD_OVERWRITE_INPUTS: + prepareOverwriteInputs(); + break; default: writeToFileAsync(&memPtr[bufLoc], payloadLen + 1, ""); m_slippiserver->write(&memPtr[bufLoc], payloadLen + 1); diff --git a/Source/Core/Core/HW/EXI_DeviceSlippi.h b/Source/Core/Core/HW/EXI_DeviceSlippi.h index 6ca2b5f9a9..dbb7565614 100644 --- a/Source/Core/Core/HW/EXI_DeviceSlippi.h +++ b/Source/Core/Core/HW/EXI_DeviceSlippi.h @@ -83,6 +83,7 @@ class CEXISlippi : public IEXIDevice CMD_GCT_LENGTH = 0xD3, CMD_GCT_LOAD = 0xD4, CMD_GET_DELAY = 0xD5, + CMD_OVERWRITE_INPUTS = 0xD6, CMD_PREMADE_TEXT_LENGTH = 0xE1, CMD_PREMADE_TEXT_LOAD = 0xE2, }; @@ -135,6 +136,7 @@ class CEXISlippi : public IEXIDevice {CMD_GCT_LENGTH, 0x0}, {CMD_GCT_LOAD, 0x4}, {CMD_GET_DELAY, 0x0}, + {CMD_OVERWRITE_INPUTS, 0x0}, {CMD_PREMADE_TEXT_LENGTH, 0x2}, {CMD_PREMADE_TEXT_LOAD, 0x2}, }; @@ -212,6 +214,7 @@ class CEXISlippi : public IEXIDevice void prepareGctLength(); void prepareGctLoad(u8 *payload); void prepareDelayResponse(); + void prepareOverwriteInputs(); void preparePremadeTextLength(u8 *payload); void preparePremadeTextLoad(u8 *payload); diff --git a/Source/Core/Core/Slippi/SlippiPad.cpp b/Source/Core/Core/Slippi/SlippiPad.cpp index 7310f00dda..018393724d 100644 --- a/Source/Core/Core/Slippi/SlippiPad.cpp +++ b/Source/Core/Core/Slippi/SlippiPad.cpp @@ -3,6 +3,12 @@ // TODO: Confirm the default and padding values are right static u8 emptyPad[SLIPPI_PAD_FULL_SIZE] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +SlippiPad::SlippiPad() +{ + this->frame = 0; + memcpy(this->padBuf, emptyPad, SLIPPI_PAD_FULL_SIZE); +} + SlippiPad::SlippiPad(int32_t frame) { this->frame = frame; diff --git a/Source/Core/Core/Slippi/SlippiPad.h b/Source/Core/Core/Slippi/SlippiPad.h index bd97acb033..eca33b2dfb 100644 --- a/Source/Core/Core/Slippi/SlippiPad.h +++ b/Source/Core/Core/Slippi/SlippiPad.h @@ -8,6 +8,7 @@ class SlippiPad { public: + SlippiPad(); SlippiPad(int32_t frame); SlippiPad(int32_t frame, u8* padBuf); SlippiPad(int32_t frame, u8 playerIdx, u8 *padBuf); @@ -17,4 +18,3 @@ class SlippiPad u8 playerIdx; u8 padBuf[SLIPPI_PAD_FULL_SIZE]; }; - diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp index f85e7a23d2..252d90e5dd 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp @@ -33,6 +33,10 @@ #include "InputCommon/ControllerInterface/Pipes/Pipes.h" #endif +#include "InputCommon/InputConfig.h" +#include "InputCommon/ControllerEmu.h" +#include "Core/HW/GCPad.h" + using namespace ciface::ExpressionParser; namespace @@ -237,6 +241,40 @@ void ControllerInterface::InvokeHotplugCallbacks() const callback(); } +std::map ControllerInterface::GetSlippiPads() +{ + std::map pads; + // Loop through all input devices + { + std::lock_guard lk(m_devices_mutex); + + for (u32 i = 0; i < m_devices.size(); i++) + { + std::shared_ptr d = m_devices[i]; + if (d->GetSource() == "Pipe") + { + ciface::Pipes::PipeDevice* x = (ciface::Pipes::PipeDevice*)d.get(); + + // Find which controller this device is attached to + for(int j = 0; j < 4; j++) + { + const auto device_type = SConfig::GetInstance().m_SIDevice[j]; + if (device_type == 6) //TODO + { + ciface::Core::DeviceQualifier device = Pad::GetConfig()->GetController(j)->default_device; + if (device.name == d->GetName()) + { + pads[j] = (x)->GetSlippiPad(); + } + } + } + } + } + } + + return pads; +} + // // InputReference :: State // diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h index 0e22a176de..6c1fa289e0 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.h @@ -10,6 +10,7 @@ #include #include +#include "Core/Slippi/SlippiPad.h" #include "Common/CommonTypes.h" #include "Common/Thread.h" #include "InputCommon/ControllerInterface/Device.h" @@ -127,6 +128,7 @@ class ControllerInterface : public ciface::Core::DeviceContainer void RegisterHotplugCallback(std::function callback); void InvokeHotplugCallbacks() const; + std::map GetSlippiPads(); private: std::vector> m_hotplug_callbacks; diff --git a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp index 980808880e..c3abd8af2b 100644 --- a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.cpp @@ -215,6 +215,31 @@ void PipeDevice::AddAxis(const std::string& name, double value) void PipeDevice::SetAxis(const std::string& entry, double value) { + if (entry.compare("MAIN X") == 0) + { + m_current_pad.padBuf[2] = u8 ((value * 255) + 128) % 256; + } + if (entry.compare("MAIN Y") == 0) + { + m_current_pad.padBuf[3] = u8 ((value * 255) + 128) % 256; + } + if (entry.compare("C X") == 0) + { + m_current_pad.padBuf[4] = u8 ((value * 255) + 128) % 256; + } + if (entry.compare("C Y") == 0) + { + m_current_pad.padBuf[5] = u8 ((value * 255) + 128) % 256; + } + if (entry.compare("L") == 0) + { + m_current_pad.padBuf[6] = u8 (value * 256); + } + if (entry.compare("R") == 0) + { + m_current_pad.padBuf[7] = u8 (value * 256); + } + value = MathUtil::Clamp(value, 0.0, 1.0); double hi = std::max(0.0, value - 0.5) * 2.0; double lo = (0.5 - std::min(0.5, value)) * 2.0; @@ -239,6 +264,7 @@ bool PipeDevice::ParseCommand(const std::string& command) return false; if (tokens[0] == "PRESS" || tokens[0] == "RELEASE") { + SetButtonState(tokens[1], tokens[0]); auto search = m_buttons.find(tokens[1]); if (search != m_buttons.end()) search->second->SetState(tokens[0] == "PRESS" ? 1.0 : 0.0); @@ -248,7 +274,7 @@ bool PipeDevice::ParseCommand(const std::string& command) if (tokens.size() == 3) { double value = StringToDouble(tokens[2]); - SetAxis(tokens[1], (value / 2.0) + 0.5); + SetAxis(tokens[1], value); } else if (tokens.size() == 4) { @@ -260,5 +286,87 @@ bool PipeDevice::ParseCommand(const std::string& command) } return false; } + +SlippiPad PipeDevice::GetSlippiPad() +{ + return m_current_pad; +} + +void PipeDevice::SetButtonState(const std::string& button, const std::string& press) +{ + u8 mask = 0x00; + int index = 0; + bool is_press = press == "PRESS"; + + if (button.compare("A") == 0) + { + mask = 0x01; + index = 0; + } + if (button.compare("B") == 0) + { + mask = 0x02; + index = 0; + } + if (button.compare("X") == 0) + { + mask = 0x04; + index = 0; + } + if (button.compare("Y") == 0) + { + mask = 0x08; + index = 0; + } + if (button.compare("L") == 0) + { + mask = 0x40; + index = 1; + } + if (button.compare("R") == 0) + { + mask = 0x20; + index = 1; + } + if (button.compare("START") == 0) + { + mask = 0x10; + index = 0; + } + if (button.compare("D_LEFT") == 0) + { + mask = 0x01; + index = 1; + } + if (button.compare("D_RIGHT") == 0) + { + mask = 0x02; + index = 1; + } + if (button.compare("D_DOWN") == 0) + { + mask = 0x04; + index = 1; + } + if (button.compare("D_UP") == 0) + { + mask = 0x08; + index = 1; + } + if (button.compare("Z") == 0) + { + mask = 0x10; + index = 1; + } + if (is_press) + { + m_current_pad.padBuf[index] |= mask; + } + else + { + m_current_pad.padBuf[index] &= ~(mask); + } +} + } } diff --git a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h index 4ced50789d..8e1d466085 100644 --- a/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h +++ b/Source/Core/InputCommon/ControllerInterface/Pipes/Pipes.h @@ -13,6 +13,8 @@ #include #endif +#include "Core/Slippi/SlippiPad.h" + extern bool g_needInputForFrame; namespace ciface @@ -47,6 +49,7 @@ class PipeDevice : public Core::Device void UpdateInput() override; std::string GetName() const override { return m_name; } std::string GetSource() const override { return "Pipe"; } + SlippiPad GetSlippiPad(); private: class PipeInput : public Input { @@ -64,12 +67,14 @@ class PipeDevice : public Core::Device bool ParseCommand(const std::string& command); void SetAxis(const std::string& entry, double value); s32 readFromPipe(PIPE_FD file_descriptor, char *in_buffer, size_t size); + void SetButtonState(const std::string& button, const std::string& press); const PIPE_FD m_fd; const std::string m_name; std::string m_buf; std::map m_buttons; std::map m_axes; + SlippiPad m_current_pad; }; } }