diff options
| author | 2021-06-18 16:32:46 +0200 | |
|---|---|---|
| committer | 2021-09-18 23:22:20 +0200 | |
| commit | 4297d2fea2228ff4afe2a7c244fb8b3f1a97491a (patch) | |
| tree | 25a1ce3a2d41bf9e066c7a57a441be65e282f16f /src/input_common/tas/tas_input.h | |
| parent | main: TAS Playback state label (diff) | |
| download | yuzu-4297d2fea2228ff4afe2a7c244fb8b3f1a97491a.tar.gz yuzu-4297d2fea2228ff4afe2a7c244fb8b3f1a97491a.tar.xz yuzu-4297d2fea2228ff4afe2a7c244fb8b3f1a97491a.zip | |
core: Hacky TAS syncing & load pausing
To keep the TAS inputs synced to the game speed even through lag spikes and loading zones, deeper access is required.
First, the `TAS::UpdateThread` has to be executed exactly once per frame. This is done by connecting it to the service method the game calls to pass parameters to the GPU: `Service::VI::QueueBuffer`.
Second, the loading time of new subareas and/or kingdoms (SMO) can vary. To counteract that, the `CPU_BOOST_MODE` can be detected: In the `APM`-interface, the call to enabling/disabling the boost mode can be caught and forwarded to the TASing system, which can pause the script execution if neccessary and enabled in the settings.
Diffstat (limited to 'src/input_common/tas/tas_input.h')
| -rw-r--r-- | src/input_common/tas/tas_input.h | 58 |
1 files changed, 20 insertions, 38 deletions
diff --git a/src/input_common/tas/tas_input.h b/src/input_common/tas/tas_input.h index 0a152a04f..8ee70bcaf 100644 --- a/src/input_common/tas/tas_input.h +++ b/src/input_common/tas/tas_input.h | |||
| @@ -12,11 +12,17 @@ | |||
| 12 | #include "core/frontend/input.h" | 12 | #include "core/frontend/input.h" |
| 13 | #include "input_common/main.h" | 13 | #include "input_common/main.h" |
| 14 | 14 | ||
| 15 | #define PLAYER_NUMBER 8 | ||
| 16 | |||
| 17 | namespace TasInput { | 15 | namespace TasInput { |
| 18 | 16 | ||
| 19 | using TasAnalog = std::tuple<float, float>; | 17 | constexpr int PLAYER_NUMBER = 8; |
| 18 | |||
| 19 | using TasAnalog = std::pair<float, float>; | ||
| 20 | |||
| 21 | enum class TasState { | ||
| 22 | RUNNING, | ||
| 23 | RECORDING, | ||
| 24 | STOPPED, | ||
| 25 | }; | ||
| 20 | 26 | ||
| 21 | enum class TasButton : u32 { | 27 | enum class TasButton : u32 { |
| 22 | BUTTON_A = 0x000001, | 28 | BUTTON_A = 0x000001, |
| @@ -41,29 +47,6 @@ enum class TasButton : u32 { | |||
| 41 | BUTTON_CAPTURE = 0x080000, | 47 | BUTTON_CAPTURE = 0x080000, |
| 42 | }; | 48 | }; |
| 43 | 49 | ||
| 44 | static const std::array<std::pair<std::string, TasButton>, 20> text_to_tas_button = { | ||
| 45 | std::pair{"KEY_A", TasButton::BUTTON_A}, | ||
| 46 | {"KEY_B", TasButton::BUTTON_B}, | ||
| 47 | {"KEY_X", TasButton::BUTTON_X}, | ||
| 48 | {"KEY_Y", TasButton::BUTTON_Y}, | ||
| 49 | {"KEY_LSTICK", TasButton::STICK_L}, | ||
| 50 | {"KEY_RSTICK", TasButton::STICK_R}, | ||
| 51 | {"KEY_L", TasButton::TRIGGER_L}, | ||
| 52 | {"KEY_R", TasButton::TRIGGER_R}, | ||
| 53 | {"KEY_PLUS", TasButton::BUTTON_PLUS}, | ||
| 54 | {"KEY_MINUS", TasButton::BUTTON_MINUS}, | ||
| 55 | {"KEY_DLEFT", TasButton::BUTTON_LEFT}, | ||
| 56 | {"KEY_DUP", TasButton::BUTTON_UP}, | ||
| 57 | {"KEY_DRIGHT", TasButton::BUTTON_RIGHT}, | ||
| 58 | {"KEY_DDOWN", TasButton::BUTTON_DOWN}, | ||
| 59 | {"KEY_SL", TasButton::BUTTON_SL}, | ||
| 60 | {"KEY_SR", TasButton::BUTTON_SR}, | ||
| 61 | {"KEY_CAPTURE", TasButton::BUTTON_CAPTURE}, | ||
| 62 | {"KEY_HOME", TasButton::BUTTON_HOME}, | ||
| 63 | {"KEY_ZL", TasButton::TRIGGER_ZL}, | ||
| 64 | {"KEY_ZR", TasButton::TRIGGER_ZR}, | ||
| 65 | }; | ||
| 66 | |||
| 67 | enum class TasAxes : u8 { | 50 | enum class TasAxes : u8 { |
| 68 | StickX, | 51 | StickX, |
| 69 | StickY, | 52 | StickY, |
| @@ -82,7 +65,7 @@ public: | |||
| 82 | Tas(); | 65 | Tas(); |
| 83 | ~Tas(); | 66 | ~Tas(); |
| 84 | 67 | ||
| 85 | static std::string buttonsToString(u32 button) { | 68 | static std::string ButtonsToString(u32 button) { |
| 86 | std::string returns; | 69 | std::string returns; |
| 87 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_A)) != 0) | 70 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_A)) != 0) |
| 88 | returns += ", A"; | 71 | returns += ", A"; |
| @@ -124,14 +107,14 @@ public: | |||
| 124 | returns += ", HOME"; | 107 | returns += ", HOME"; |
| 125 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_CAPTURE)) != 0) | 108 | if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_CAPTURE)) != 0) |
| 126 | returns += ", CAPTURE"; | 109 | returns += ", CAPTURE"; |
| 127 | return returns.length() != 0 ? returns.substr(2) : ""; | 110 | return returns.empty() ? "" : returns.substr(2); |
| 128 | } | 111 | } |
| 129 | 112 | ||
| 130 | void RefreshTasFile(); | 113 | void RefreshTasFile(); |
| 131 | void LoadTasFiles(); | 114 | void LoadTasFiles(); |
| 132 | void RecordInput(u32 buttons, std::array<std::pair<float, float>, 2> axes); | 115 | void RecordInput(u32 buttons, const std::array<std::pair<float, float>, 2>& axes); |
| 133 | void UpdateThread(); | 116 | void UpdateThread(); |
| 134 | std::string GetStatusDescription(); | 117 | std::tuple<TasState, size_t, size_t> GetStatus(); |
| 135 | 118 | ||
| 136 | InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const; | 119 | InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const; |
| 137 | InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const; | 120 | InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const; |
| @@ -143,21 +126,20 @@ private: | |||
| 143 | TasAnalog l_axis{}; | 126 | TasAnalog l_axis{}; |
| 144 | TasAnalog r_axis{}; | 127 | TasAnalog r_axis{}; |
| 145 | }; | 128 | }; |
| 146 | void LoadTasFile(int playerIndex); | 129 | void LoadTasFile(size_t player_index); |
| 147 | void WriteTasFile(); | 130 | void WriteTasFile(); |
| 148 | TasAnalog ReadCommandAxis(const std::string line) const; | 131 | TasAnalog ReadCommandAxis(const std::string& line) const; |
| 149 | u32 ReadCommandButtons(const std::string line) const; | 132 | u32 ReadCommandButtons(const std::string& line) const; |
| 150 | std::string WriteCommandButtons(u32 data) const; | 133 | std::string WriteCommandButtons(u32 data) const; |
| 151 | std::string WriteCommandAxis(TasAnalog data) const; | 134 | std::string WriteCommandAxis(TasAnalog data) const; |
| 152 | std::pair<float, float> flipY(std::pair<float, float> old) const; | ||
| 153 | 135 | ||
| 154 | size_t scriptLength{0}; | 136 | size_t script_length{0}; |
| 155 | std::array<TasData, PLAYER_NUMBER> tas_data; | 137 | std::array<TasData, PLAYER_NUMBER> tas_data; |
| 156 | bool update_thread_running{true}; | 138 | bool update_thread_running{true}; |
| 157 | bool refresh_tas_fle{false}; | 139 | bool refresh_tas_fle{false}; |
| 158 | std::array<std::vector<TASCommand>, PLAYER_NUMBER> newCommands{}; | 140 | std::array<std::vector<TASCommand>, PLAYER_NUMBER> commands{}; |
| 159 | std::vector<TASCommand> recordCommands{}; | 141 | std::vector<TASCommand> record_commands{}; |
| 160 | std::size_t current_command{0}; | 142 | std::size_t current_command{0}; |
| 161 | TASCommand lastInput{}; // only used for recording | 143 | TASCommand last_input{}; // only used for recording |
| 162 | }; | 144 | }; |
| 163 | } // namespace TasInput | 145 | } // namespace TasInput |