summaryrefslogtreecommitdiff
path: root/src/input_common/tas/tas_input.h
diff options
context:
space:
mode:
authorGravatar MonsterDruide12021-06-18 16:15:42 +0200
committerGravatar MonsterDruide12021-09-18 23:22:00 +0200
commitb42c3ce21db249d5e3bc04b4f73202e757da317c (patch)
treec5ccf9e311d2a675b0e2afff3d85ed4654047b5e /src/input_common/tas/tas_input.h
parentMerge pull request #7020 from Moonlacer/remove_audio_stretching (diff)
downloadyuzu-b42c3ce21db249d5e3bc04b4f73202e757da317c.tar.gz
yuzu-b42c3ce21db249d5e3bc04b4f73202e757da317c.tar.xz
yuzu-b42c3ce21db249d5e3bc04b4f73202e757da317c.zip
input_common/tas: Base playback & recording system
The base playback system supports up to 8 controllers (specified by `PLAYER_NUMBER` in `tas_input.h`), which all change their inputs simulataneously when `TAS::UpdateThread` is called. The recording system uses the controller debugger to read the state of the first controller and forwards that data to the TASing system for recording. Currently, this process sadly is not frame-perfect and pixel-accurate. Co-authored-by: Naii-the-Baf <sfabian200@gmail.com> Co-authored-by: Narr-the-Reg <juangerman-13@hotmail.com>
Diffstat (limited to 'src/input_common/tas/tas_input.h')
-rw-r--r--src/input_common/tas/tas_input.h163
1 files changed, 163 insertions, 0 deletions
diff --git a/src/input_common/tas/tas_input.h b/src/input_common/tas/tas_input.h
new file mode 100644
index 000000000..0a152a04f
--- /dev/null
+++ b/src/input_common/tas/tas_input.h
@@ -0,0 +1,163 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <mutex>
9#include <thread>
10
11#include "common/common_types.h"
12#include "core/frontend/input.h"
13#include "input_common/main.h"
14
15#define PLAYER_NUMBER 8
16
17namespace TasInput {
18
19using TasAnalog = std::tuple<float, float>;
20
21enum class TasButton : u32 {
22 BUTTON_A = 0x000001,
23 BUTTON_B = 0x000002,
24 BUTTON_X = 0x000004,
25 BUTTON_Y = 0x000008,
26 STICK_L = 0x000010,
27 STICK_R = 0x000020,
28 TRIGGER_L = 0x000040,
29 TRIGGER_R = 0x000080,
30 TRIGGER_ZL = 0x000100,
31 TRIGGER_ZR = 0x000200,
32 BUTTON_PLUS = 0x000400,
33 BUTTON_MINUS = 0x000800,
34 BUTTON_LEFT = 0x001000,
35 BUTTON_UP = 0x002000,
36 BUTTON_RIGHT = 0x004000,
37 BUTTON_DOWN = 0x008000,
38 BUTTON_SL = 0x010000,
39 BUTTON_SR = 0x020000,
40 BUTTON_HOME = 0x040000,
41 BUTTON_CAPTURE = 0x080000,
42};
43
44static 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
67enum class TasAxes : u8 {
68 StickX,
69 StickY,
70 SubstickX,
71 SubstickY,
72 Undefined,
73};
74
75struct TasData {
76 u32 buttons{};
77 std::array<float, 4> axis{};
78};
79
80class Tas {
81public:
82 Tas();
83 ~Tas();
84
85 static std::string buttonsToString(u32 button) {
86 std::string returns;
87 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_A)) != 0)
88 returns += ", A";
89 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_B)) != 0)
90 returns += ", B";
91 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_X)) != 0)
92 returns += ", X";
93 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_Y)) != 0)
94 returns += ", Y";
95 if ((button & static_cast<u32>(TasInput::TasButton::STICK_L)) != 0)
96 returns += ", STICK_L";
97 if ((button & static_cast<u32>(TasInput::TasButton::STICK_R)) != 0)
98 returns += ", STICK_R";
99 if ((button & static_cast<u32>(TasInput::TasButton::TRIGGER_L)) != 0)
100 returns += ", TRIGGER_L";
101 if ((button & static_cast<u32>(TasInput::TasButton::TRIGGER_R)) != 0)
102 returns += ", TRIGGER_R";
103 if ((button & static_cast<u32>(TasInput::TasButton::TRIGGER_ZL)) != 0)
104 returns += ", TRIGGER_ZL";
105 if ((button & static_cast<u32>(TasInput::TasButton::TRIGGER_ZR)) != 0)
106 returns += ", TRIGGER_ZR";
107 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_PLUS)) != 0)
108 returns += ", PLUS";
109 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_MINUS)) != 0)
110 returns += ", MINUS";
111 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_LEFT)) != 0)
112 returns += ", LEFT";
113 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_UP)) != 0)
114 returns += ", UP";
115 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_RIGHT)) != 0)
116 returns += ", RIGHT";
117 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_DOWN)) != 0)
118 returns += ", DOWN";
119 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_SL)) != 0)
120 returns += ", SL";
121 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_SR)) != 0)
122 returns += ", SR";
123 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_HOME)) != 0)
124 returns += ", HOME";
125 if ((button & static_cast<u32>(TasInput::TasButton::BUTTON_CAPTURE)) != 0)
126 returns += ", CAPTURE";
127 return returns.length() != 0 ? returns.substr(2) : "";
128 }
129
130 void RefreshTasFile();
131 void LoadTasFiles();
132 void RecordInput(u32 buttons, std::array<std::pair<float, float>, 2> axes);
133 void UpdateThread();
134 std::string GetStatusDescription();
135
136 InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const;
137 InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const;
138 [[nodiscard]] const TasData& GetTasState(std::size_t pad) const;
139
140private:
141 struct TASCommand {
142 u32 buttons{};
143 TasAnalog l_axis{};
144 TasAnalog r_axis{};
145 };
146 void LoadTasFile(int playerIndex);
147 void WriteTasFile();
148 TasAnalog ReadCommandAxis(const std::string line) const;
149 u32 ReadCommandButtons(const std::string line) const;
150 std::string WriteCommandButtons(u32 data) const;
151 std::string WriteCommandAxis(TasAnalog data) const;
152 std::pair<float, float> flipY(std::pair<float, float> old) const;
153
154 size_t scriptLength{0};
155 std::array<TasData, PLAYER_NUMBER> tas_data;
156 bool update_thread_running{true};
157 bool refresh_tas_fle{false};
158 std::array<std::vector<TASCommand>, PLAYER_NUMBER> newCommands{};
159 std::vector<TASCommand> recordCommands{};
160 std::size_t current_command{0};
161 TASCommand lastInput{}; // only used for recording
162};
163} // namespace TasInput