summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/input_common/drivers/tas_input.cpp93
-rw-r--r--src/input_common/drivers/tas_input.h59
2 files changed, 82 insertions, 70 deletions
diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp
index 0e01fb0d9..2094c1feb 100644
--- a/src/input_common/drivers/tas_input.cpp
+++ b/src/input_common/drivers/tas_input.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6#include <regex>
7#include <fmt/format.h> 6#include <fmt/format.h>
8 7
9#include "common/fs/file.h" 8#include "common/fs/file.h"
@@ -15,7 +14,7 @@
15 14
16namespace InputCommon::TasInput { 15namespace InputCommon::TasInput {
17 16
18enum TasAxes : u8 { 17enum class Tas::TasAxis : u8 {
19 StickX, 18 StickX,
20 StickY, 19 StickY,
21 SubstickX, 20 SubstickX,
@@ -66,7 +65,7 @@ Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engi
66 65
67Tas::~Tas() { 66Tas::~Tas() {
68 Stop(); 67 Stop();
69}; 68}
70 69
71void Tas::LoadTasFiles() { 70void Tas::LoadTasFiles() {
72 script_length = 0; 71 script_length = 0;
@@ -79,43 +78,43 @@ void Tas::LoadTasFiles() {
79} 78}
80 79
81void Tas::LoadTasFile(size_t player_index, size_t file_index) { 80void Tas::LoadTasFile(size_t player_index, size_t file_index) {
82 if (!commands[player_index].empty()) { 81 commands[player_index].clear();
83 commands[player_index].clear(); 82
84 }
85 std::string file = Common::FS::ReadStringFromFile( 83 std::string file = Common::FS::ReadStringFromFile(
86 Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / 84 Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) /
87 fmt::format("script{}-{}.txt", file_index, player_index + 1), 85 fmt::format("script{}-{}.txt", file_index, player_index + 1),
88 Common::FS::FileType::BinaryFile); 86 Common::FS::FileType::BinaryFile);
89 std::stringstream command_line(file); 87 std::istringstream command_line(file);
90 std::string line; 88 std::string line;
91 int frame_no = 0; 89 int frame_no = 0;
92 while (std::getline(command_line, line, '\n')) { 90 while (std::getline(command_line, line, '\n')) {
93 if (line.empty()) { 91 if (line.empty()) {
94 continue; 92 continue;
95 } 93 }
96 std::smatch m;
97 94
98 std::stringstream linestream(line); 95 std::vector<std::string> seg_list;
99 std::string segment; 96 {
100 std::vector<std::string> seglist; 97 std::istringstream line_stream(line);
101 98 std::string segment;
102 while (std::getline(linestream, segment, ' ')) { 99 while (std::getline(line_stream, segment, ' ')) {
103 seglist.push_back(segment); 100 seg_list.push_back(std::move(segment));
101 }
104 } 102 }
105 103
106 if (seglist.size() < 4) { 104 if (seg_list.size() < 4) {
107 continue; 105 continue;
108 } 106 }
109 107
110 while (frame_no < std::stoi(seglist.at(0))) { 108 const auto num_frames = std::stoi(seg_list[0]);
111 commands[player_index].push_back({}); 109 while (frame_no < num_frames) {
110 commands[player_index].emplace_back();
112 frame_no++; 111 frame_no++;
113 } 112 }
114 113
115 TASCommand command = { 114 TASCommand command = {
116 .buttons = ReadCommandButtons(seglist.at(1)), 115 .buttons = ReadCommandButtons(seg_list[1]),
117 .l_axis = ReadCommandAxis(seglist.at(2)), 116 .l_axis = ReadCommandAxis(seg_list[2]),
118 .r_axis = ReadCommandAxis(seglist.at(3)), 117 .r_axis = ReadCommandAxis(seg_list[3]),
119 }; 118 };
120 commands[player_index].push_back(command); 119 commands[player_index].push_back(command);
121 frame_no++; 120 frame_no++;
@@ -123,16 +122,17 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) {
123 LOG_INFO(Input, "TAS file loaded! {} frames", frame_no); 122 LOG_INFO(Input, "TAS file loaded! {} frames", frame_no);
124} 123}
125 124
126void Tas::WriteTasFile(std::u8string file_name) { 125void Tas::WriteTasFile(std::u8string_view file_name) {
127 std::string output_text; 126 std::string output_text;
128 for (size_t frame = 0; frame < record_commands.size(); frame++) { 127 for (size_t frame = 0; frame < record_commands.size(); frame++) {
129 const TASCommand& line = record_commands[frame]; 128 const TASCommand& line = record_commands[frame];
130 output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons), 129 output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons),
131 WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis)); 130 WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis));
132 } 131 }
133 const auto bytes_written = Common::FS::WriteStringToFile( 132
134 Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name, 133 const auto tas_file_name = Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name;
135 Common::FS::FileType::TextFile, output_text); 134 const auto bytes_written =
135 Common::FS::WriteStringToFile(tas_file_name, Common::FS::FileType::TextFile, output_text);
136 if (bytes_written == output_text.size()) { 136 if (bytes_written == output_text.size()) {
137 LOG_INFO(Input, "TAS file written to file!"); 137 LOG_INFO(Input, "TAS file written to file!");
138 } else { 138 } else {
@@ -205,10 +205,10 @@ void Tas::UpdateThread() {
205 const int button = static_cast<int>(i); 205 const int button = static_cast<int>(i);
206 SetButton(identifier, button, button_status); 206 SetButton(identifier, button, button_status);
207 } 207 }
208 SetAxis(identifier, TasAxes::StickX, command.l_axis.x); 208 SetTasAxis(identifier, TasAxis::StickX, command.l_axis.x);
209 SetAxis(identifier, TasAxes::StickY, command.l_axis.y); 209 SetTasAxis(identifier, TasAxis::StickY, command.l_axis.y);
210 SetAxis(identifier, TasAxes::SubstickX, command.r_axis.x); 210 SetTasAxis(identifier, TasAxis::SubstickX, command.r_axis.x);
211 SetAxis(identifier, TasAxes::SubstickY, command.r_axis.y); 211 SetTasAxis(identifier, TasAxis::SubstickY, command.r_axis.y);
212 } 212 }
213 } else { 213 } else {
214 is_running = Settings::values.tas_loop.GetValue(); 214 is_running = Settings::values.tas_loop.GetValue();
@@ -224,27 +224,28 @@ void Tas::ClearInput() {
224} 224}
225 225
226TasAnalog Tas::ReadCommandAxis(const std::string& line) const { 226TasAnalog Tas::ReadCommandAxis(const std::string& line) const {
227 std::stringstream linestream(line); 227 std::vector<std::string> seg_list;
228 std::string segment; 228 {
229 std::vector<std::string> seglist; 229 std::istringstream line_stream(line);
230 230 std::string segment;
231 while (std::getline(linestream, segment, ';')) { 231 while (std::getline(line_stream, segment, ';')) {
232 seglist.push_back(segment); 232 seg_list.push_back(std::move(segment));
233 }
233 } 234 }
234 235
235 const float x = std::stof(seglist.at(0)) / 32767.0f; 236 const float x = std::stof(seg_list.at(0)) / 32767.0f;
236 const float y = std::stof(seglist.at(1)) / 32767.0f; 237 const float y = std::stof(seg_list.at(1)) / 32767.0f;
237 238
238 return {x, y}; 239 return {x, y};
239} 240}
240 241
241u64 Tas::ReadCommandButtons(const std::string& data) const { 242u64 Tas::ReadCommandButtons(const std::string& line) const {
242 std::stringstream button_text(data); 243 std::istringstream button_text(line);
243 std::string line; 244 std::string button_line;
244 u64 buttons = 0; 245 u64 buttons = 0;
245 while (std::getline(button_text, line, ';')) { 246 while (std::getline(button_text, button_line, ';')) {
246 for (auto [text, tas_button] : text_to_tas_button) { 247 for (const auto& [text, tas_button] : text_to_tas_button) {
247 if (text == line) { 248 if (text == button_line) {
248 buttons |= static_cast<u64>(tas_button); 249 buttons |= static_cast<u64>(tas_button);
249 break; 250 break;
250 } 251 }
@@ -254,8 +255,8 @@ u64 Tas::ReadCommandButtons(const std::string& data) const {
254} 255}
255 256
256std::string Tas::WriteCommandButtons(u64 buttons) const { 257std::string Tas::WriteCommandButtons(u64 buttons) const {
257 std::string returns = ""; 258 std::string returns;
258 for (auto [text_button, tas_button] : text_to_tas_button) { 259 for (const auto& [text_button, tas_button] : text_to_tas_button) {
259 if ((buttons & static_cast<u64>(tas_button)) != 0) { 260 if ((buttons & static_cast<u64>(tas_button)) != 0) {
260 returns += fmt::format("{};", text_button); 261 returns += fmt::format("{};", text_button);
261 } 262 }
@@ -267,6 +268,10 @@ std::string Tas::WriteCommandAxis(TasAnalog analog) const {
267 return fmt::format("{};{}", analog.x * 32767, analog.y * 32767); 268 return fmt::format("{};{}", analog.x * 32767, analog.y * 32767);
268} 269}
269 270
271void Tas::SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value) {
272 SetAxis(identifier, static_cast<int>(axis), value);
273}
274
270void Tas::StartStop() { 275void Tas::StartStop() {
271 if (!Settings::values.tas_enable) { 276 if (!Settings::values.tas_enable) {
272 return; 277 return;
diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h
index c95a130fc..3996fe3a8 100644
--- a/src/input_common/drivers/tas_input.h
+++ b/src/input_common/drivers/tas_input.h
@@ -5,11 +5,11 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <string>
9#include <vector>
8 10
9#include "common/common_types.h" 11#include "common/common_types.h"
10#include "common/settings_input.h"
11#include "input_common/input_engine.h" 12#include "input_common/input_engine.h"
12#include "input_common/main.h"
13 13
14/* 14/*
15To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below 15To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below
@@ -88,39 +88,39 @@ public:
88 88
89 /** 89 /**
90 * Changes the input status that will be stored in each frame 90 * Changes the input status that will be stored in each frame
91 * @param buttons: bitfield with the status of the buttons 91 * @param buttons Bitfield with the status of the buttons
92 * @param left_axis: value of the left axis 92 * @param left_axis Value of the left axis
93 * @param right_axis: value of the right axis 93 * @param right_axis Value of the right axis
94 */ 94 */
95 void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis); 95 void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis);
96 96
97 // Main loop that records or executes input 97 // Main loop that records or executes input
98 void UpdateThread(); 98 void UpdateThread();
99 99
100 // Sets the flag to start or stop the TAS command excecution and swaps controllers profiles 100 // Sets the flag to start or stop the TAS command execution and swaps controllers profiles
101 void StartStop(); 101 void StartStop();
102 102
103 // Stop the TAS and reverts any controller profile 103 // Stop the TAS and reverts any controller profile
104 void Stop(); 104 void Stop();
105 105
106 // Sets the flag to reload the file and start from the begining in the next update 106 // Sets the flag to reload the file and start from the beginning in the next update
107 void Reset(); 107 void Reset();
108 108
109 /** 109 /**
110 * Sets the flag to enable or disable recording of inputs 110 * Sets the flag to enable or disable recording of inputs
111 * @return Returns true if the current recording status is enabled 111 * @returns true if the current recording status is enabled
112 */ 112 */
113 bool Record(); 113 bool Record();
114 114
115 /** 115 /**
116 * Saves contents of record_commands on a file 116 * Saves contents of record_commands on a file
117 * @param overwrite_file: Indicates if player 1 should be overwritten 117 * @param overwrite_file Indicates if player 1 should be overwritten
118 */ 118 */
119 void SaveRecording(bool overwrite_file); 119 void SaveRecording(bool overwrite_file);
120 120
121 /** 121 /**
122 * Returns the current status values of TAS playback/recording 122 * Returns the current status values of TAS playback/recording
123 * @return Tuple of 123 * @returns A Tuple of
124 * TasState indicating the current state out of Running ; 124 * TasState indicating the current state out of Running ;
125 * Current playback progress ; 125 * Current playback progress ;
126 * Total length of script file currently loaded or being recorded 126 * Total length of script file currently loaded or being recorded
@@ -128,6 +128,8 @@ public:
128 std::tuple<TasState, size_t, size_t> GetStatus() const; 128 std::tuple<TasState, size_t, size_t> GetStatus() const;
129 129
130private: 130private:
131 enum class TasAxis : u8;
132
131 struct TASCommand { 133 struct TASCommand {
132 u64 buttons{}; 134 u64 buttons{};
133 TasAnalog l_axis{}; 135 TasAnalog l_axis{};
@@ -137,29 +139,31 @@ private:
137 /// Loads TAS files from all players 139 /// Loads TAS files from all players
138 void LoadTasFiles(); 140 void LoadTasFiles();
139 141
140 /** Loads TAS file from the specified player 142 /**
141 * @param player_index: player number to save the script 143 * Loads TAS file from the specified player
142 * @param file_index: script number of the file 144 * @param player_index Player number to save the script
145 * @param file_index Script number of the file
143 */ 146 */
144 void LoadTasFile(size_t player_index, size_t file_index); 147 void LoadTasFile(size_t player_index, size_t file_index);
145 148
146 /** Writes a TAS file from the recorded commands 149 /**
147 * @param file_name: name of the file to be written 150 * Writes a TAS file from the recorded commands
151 * @param file_name Name of the file to be written
148 */ 152 */
149 void WriteTasFile(std::u8string file_name); 153 void WriteTasFile(std::u8string_view file_name);
150 154
151 /** 155 /**
152 * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 156 * Parses a string containing the axis values. X and Y have a range from -32767 to 32767
153 * @param line: string containing axis values with the following format "x;y" 157 * @param line String containing axis values with the following format "x;y"
154 * @return Returns a TAS analog object with axis values with range from -1.0 to 1.0 158 * @returns A TAS analog object with axis values with range from -1.0 to 1.0
155 */ 159 */
156 TasAnalog ReadCommandAxis(const std::string& line) const; 160 TasAnalog ReadCommandAxis(const std::string& line) const;
157 161
158 /** 162 /**
159 * Parses a string containing the button values. Each button is represented by it's text format 163 * Parses a string containing the button values. Each button is represented by it's text format
160 * specified in text_to_tas_button array 164 * specified in text_to_tas_button array
161 * @param line: string containing button name with the following format "a;b;c;d..." 165 * @param line string containing button name with the following format "a;b;c;d..."
162 * @return Returns a u64 with each bit representing the status of a button 166 * @returns A u64 with each bit representing the status of a button
163 */ 167 */
164 u64 ReadCommandButtons(const std::string& line) const; 168 u64 ReadCommandButtons(const std::string& line) const;
165 169
@@ -170,17 +174,20 @@ private:
170 174
171 /** 175 /**
172 * Converts an u64 containing the button status into the text equivalent 176 * Converts an u64 containing the button status into the text equivalent
173 * @param buttons: bitfield with the status of the buttons 177 * @param buttons Bitfield with the status of the buttons
174 * @return Returns a string with the name of the buttons to be written to the file 178 * @returns A string with the name of the buttons to be written to the file
175 */ 179 */
176 std::string WriteCommandButtons(u64 buttons) const; 180 std::string WriteCommandButtons(u64 buttons) const;
177 181
178 /** 182 /**
179 * Converts an TAS analog object containing the axis status into the text equivalent 183 * Converts an TAS analog object containing the axis status into the text equivalent
180 * @param data: value of the axis 184 * @param analog Value of the axis
181 * @return A string with the value of the axis to be written to the file 185 * @returns A string with the value of the axis to be written to the file
182 */ 186 */
183 std::string WriteCommandAxis(TasAnalog data) const; 187 std::string WriteCommandAxis(TasAnalog analog) const;
188
189 /// Sets an axis for a particular pad to the given value.
190 void SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value);
184 191
185 size_t script_length{0}; 192 size_t script_length{0};
186 bool is_recording{false}; 193 bool is_recording{false};