From 4cfc4e78ecd16ffc636300d72d451a8bf6536cca Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sat, 29 May 2021 00:41:52 -0700 Subject: [PATCH] Initial CControllerRecorder imp (very WIP) --- Runtime/Input/CControllerRecorder.cpp | 50 +++++++++++++++++++++++++++ Runtime/Input/CControllerRecorder.hpp | 28 +++++++++++++++ Runtime/Input/CFinalInput.cpp | 47 +++++++++++++++++++++++++ Runtime/Input/CFinalInput.hpp | 1 + Runtime/Input/CInputGenerator.cpp | 8 +++-- Runtime/Input/CInputGenerator.hpp | 5 ++- Runtime/Input/CMakeLists.txt | 19 +++++----- 7 files changed, 145 insertions(+), 13 deletions(-) create mode 100644 Runtime/Input/CControllerRecorder.cpp create mode 100644 Runtime/Input/CControllerRecorder.hpp diff --git a/Runtime/Input/CControllerRecorder.cpp b/Runtime/Input/CControllerRecorder.cpp new file mode 100644 index 000000000..50f105bdc --- /dev/null +++ b/Runtime/Input/CControllerRecorder.cpp @@ -0,0 +1,50 @@ +#include "Runtime/Input/CControllerRecorder.hpp" + +#include "Runtime/Graphics/CGraphics.hpp" +#include "Runtime/CArchitectureQueue.hpp" +#include "Runtime/CArchitectureMessage.hpp" + +namespace metaforce { +bool CControllerRecorder::ProcessInput(const CFinalInput& in, s32 frame, CArchitectureQueue& queue) { + if (m_mode == EMode::Record) { + m_finalInputs[frame] = in; + return false; + } else { + SetMode(EMode::Record); + } + if (m_mode == EMode::Play && m_finalInputs.find(frame) != m_finalInputs.end()) { + queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, m_finalInputs[frame])); + return true; + } + + return false; +} + +void CControllerRecorder::SetMode(EMode mode) { + EMode oldMode = m_mode; + m_mode = mode; + if (m_mode == EMode::Record && oldMode != EMode::Record) { + m_initialState = *g_GameState; + } else if (oldMode == EMode::Record && m_mode == EMode::None) { + //auto w = athena::io::FileWriter("/home/antidote/Documents/test.inp"); + //PutTo(w); + } else if (oldMode == EMode::None && m_mode == EMode::Play) { + m_oldGameStatePtr = g_GameState; + g_GameState = &m_initialState; + } else if (oldMode == EMode::Play && m_mode == EMode::None) { + } +} + +void CControllerRecorder::PutTo(COutputStream& out) { + out.writeUint32Big(1); // Version + m_initialState.WriteBackupBuf(); + auto& buf = m_initialState.BackupBuf(); + out.writeUint32Big(buf.size()); + out.writeBytes(buf.data(), buf.size()); + out.writeUint32Big(m_finalInputs.size()); + for (auto pair : m_finalInputs) { + out.writeUint32Big(pair.first); + pair.second.PutTo(out); + } +} +} diff --git a/Runtime/Input/CControllerRecorder.hpp b/Runtime/Input/CControllerRecorder.hpp new file mode 100644 index 000000000..bb60daaea --- /dev/null +++ b/Runtime/Input/CControllerRecorder.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "Runtime/Input/CFinalInput.hpp" +#include "Runtime/CGameState.hpp" + +namespace metaforce { +class CArchitectureQueue; +class CControllerRecorder { +public: + enum class EMode { + None, + Record, + Play + }; +private: + std::map m_finalInputs; // frame -> input + EMode m_mode = EMode::None; + CGameState m_initialState; + const CGameState* m_oldGameStatePtr = nullptr; +public: + CControllerRecorder() = default; + + bool ProcessInput(const CFinalInput& in, s32 frame, CArchitectureQueue& queue); + void SetMode(EMode mode); + void PutTo(COutputStream& out); +}; + +} // namespace metaforce diff --git a/Runtime/Input/CFinalInput.cpp b/Runtime/Input/CFinalInput.cpp index 944e240d8..9e4e824a9 100644 --- a/Runtime/Input/CFinalInput.cpp +++ b/Runtime/Input/CFinalInput.cpp @@ -162,4 +162,51 @@ CFinalInput CFinalInput::ScaleAnalogueSticks(float leftDiv, float rightDiv) cons ret.m_rightMul = 1.f / rightDiv; return ret; } + +void CFinalInput::PutTo(COutputStream& out) { + out.writeFloatBig(x0_dt); + out.writeFloatBig(x4_controllerIdx); + out.writeFloatBig(x8_anaLeftX); + out.writeFloatBig(xc_anaLeftY); + out.writeFloatBig(x10_anaRightX); + out.writeFloatBig(x14_anaRightY); + out.writeFloatBig(x18_anaLeftTrigger); + out.writeFloatBig(x1c_anaRightTrigger); + out.writeBool(x20_enableAnaLeftXP); + out.writeBool(x20_enableAnaLeftNegXP); + out.writeBool(x21_enableAnaLeftYP); + out.writeBool(x21_enableAnaLeftNegYP); + out.writeBool(x22_enableAnaRightXP); + out.writeBool(x22_enableAnaRightNegXP); + out.writeBool(x23_enableAnaRightYP); + out.writeBool(x23_enableAnaRightNegYP); + out.writeBool(x24_anaLeftTriggerP); + out.writeBool(x28_anaRightTriggerP); + out.writeBool(x2c_b24_A); + out.writeBool(x2c_b25_B); + out.writeBool(x2c_b26_X); + out.writeBool(x2c_b27_Y); + out.writeBool(x2c_b28_Z); + out.writeBool(x2c_b29_L); + out.writeBool(x2c_b30_R); + out.writeBool(x2c_b31_DPUp); + out.writeBool(x2d_b24_DPRight); + out.writeBool(x2d_b25_DPDown); + out.writeBool(x2d_b26_DPLeft); + out.writeBool(x2d_b27_Start); + out.writeBool(x2d_b28_PA); + out.writeBool(x2d_b29_PB); + out.writeBool(x2d_b30_PX); + out.writeBool(x2d_b31_PY); + out.writeBool(x2e_b25_PL); + out.writeBool(x2e_b26_PR); + out.writeBool(x2e_b27_PDPUp); + out.writeBool(x2e_b28_PDPRight); + out.writeBool(x2e_b29_PDPDown); + out.writeBool(x2e_b30_PDPLeft); + out.writeBool(x2e_b31_PStart); + out.writeBytes(m_PCharKeys.data(), m_PCharKeys.size() - 1); + out.writeBytes(m_PSpecialKeys.data(), m_PSpecialKeys.size() - 1); + out.writeBytes(m_PMouseButtons.data(), m_PMouseButtons.size() - 1); +} } // namespace metaforce diff --git a/Runtime/Input/CFinalInput.hpp b/Runtime/Input/CFinalInput.hpp index 43e20d852..ff63f0517 100644 --- a/Runtime/Input/CFinalInput.hpp +++ b/Runtime/Input/CFinalInput.hpp @@ -171,6 +171,7 @@ struct CFinalInput { float AMouseButton(boo::EMouseButton k) const { return DMouseButton(k) ? 1.f : 0.f; } const std::optional& GetKBM() const { return m_kbm; } + void PutTo(COutputStream& out); }; } // namespace metaforce diff --git a/Runtime/Input/CInputGenerator.cpp b/Runtime/Input/CInputGenerator.cpp index 495e2b774..d514899c0 100644 --- a/Runtime/Input/CInputGenerator.cpp +++ b/Runtime/Input/CInputGenerator.cpp @@ -28,13 +28,15 @@ void CInputGenerator::Update(float dt, CArchitectureQueue& queue) { input |= kbInput; kbUsed = true; } - queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, input)); + if (!m_recorder.ProcessInput(input, CGraphics::GetFrameCounter(), queue)) { + queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, input)); + } } } /* Send straight keyboard input if no first controller present */ - if (!kbUsed) + if (!kbUsed && !m_recorder.ProcessInput(kbInput, CGraphics::GetFrameCounter(), queue)) { queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, kbInput)); + } } - } // namespace metaforce diff --git a/Runtime/Input/CInputGenerator.hpp b/Runtime/Input/CInputGenerator.hpp index c8445c5f9..08c394c9d 100644 --- a/Runtime/Input/CInputGenerator.hpp +++ b/Runtime/Input/CInputGenerator.hpp @@ -5,6 +5,8 @@ #include #include "Runtime/Input/CFinalInput.hpp" + +#include "Runtime/Input/CControllerRecorder.hpp" #include "Runtime/Input/CKeyboardMouseController.hpp" #include @@ -33,7 +35,7 @@ class CInputGenerator : public boo::DeviceFinder { } bool m_firstFrame = true; - + CControllerRecorder m_recorder; public: CInputGenerator(float leftDiv, float rightDiv) : boo::DeviceFinder({dev_typeid(DolphinSmashAdapter)}), m_leftDiv(leftDiv), m_rightDiv(rightDiv) {} @@ -180,6 +182,7 @@ public: /* This is where the game thread enters */ void Update(float dt, CArchitectureQueue& queue); + void SetRecordMode(CControllerRecorder::EMode mode) { m_recorder.SetMode(mode); }; }; } // namespace metaforce diff --git a/Runtime/Input/CMakeLists.txt b/Runtime/Input/CMakeLists.txt index 260c262e8..9be235b16 100644 --- a/Runtime/Input/CMakeLists.txt +++ b/Runtime/Input/CMakeLists.txt @@ -1,12 +1,13 @@ set(INPUT_SOURCES - IController.hpp - CKeyboardMouseController.hpp - ControlMapper.hpp ControlMapper.cpp - CInputGenerator.hpp CInputGenerator.cpp - CFinalInput.hpp CFinalInput.cpp - CRumbleManager.hpp CRumbleManager.cpp - CRumbleGenerator.hpp CRumbleGenerator.cpp - CRumbleVoice.hpp CRumbleVoice.cpp - RumbleFxTable.hpp RumbleFxTable.cpp) + IController.hpp + CKeyboardMouseController.hpp + ControlMapper.hpp ControlMapper.cpp + CInputGenerator.hpp CInputGenerator.cpp + CFinalInput.hpp CFinalInput.cpp + CRumbleManager.hpp CRumbleManager.cpp + CRumbleGenerator.hpp CRumbleGenerator.cpp + CRumbleVoice.hpp CRumbleVoice.cpp + RumbleFxTable.hpp RumbleFxTable.cpp + CControllerRecorder.hpp CControllerRecorder.cpp) runtime_add_list(Input INPUT_SOURCES)