From c126b0718ca4ffff463c4462ca38f61019df4acf Mon Sep 17 00:00:00 2001 From: Lioncash <mathew1800@gmail.com> Date: Mon, 13 Dec 2021 10:41:30 -0500 Subject: [PATCH 01/10] tas_input: Make TasAxes enum an enum class Prevents these values from potentially clashing with anything in other headers. --- src/input_common/drivers/tas_input.cpp | 14 +++++++++----- src/input_common/drivers/tas_input.h | 5 +++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 0e01fb0d9..1a38616b4 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -15,7 +15,7 @@ namespace InputCommon::TasInput { -enum TasAxes : u8 { +enum class Tas::TasAxis : u8 { StickX, StickY, SubstickX, @@ -205,10 +205,10 @@ void Tas::UpdateThread() { const int button = static_cast<int>(i); SetButton(identifier, button, button_status); } - SetAxis(identifier, TasAxes::StickX, command.l_axis.x); - SetAxis(identifier, TasAxes::StickY, command.l_axis.y); - SetAxis(identifier, TasAxes::SubstickX, command.r_axis.x); - SetAxis(identifier, TasAxes::SubstickY, command.r_axis.y); + SetTasAxis(identifier, TasAxis::StickX, command.l_axis.x); + SetTasAxis(identifier, TasAxis::StickY, command.l_axis.y); + SetTasAxis(identifier, TasAxis::SubstickX, command.r_axis.x); + SetTasAxis(identifier, TasAxis::SubstickY, command.r_axis.y); } } else { is_running = Settings::values.tas_loop.GetValue(); @@ -267,6 +267,10 @@ std::string Tas::WriteCommandAxis(TasAnalog analog) const { return fmt::format("{};{}", analog.x * 32767, analog.y * 32767); } +void Tas::SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value) { + SetAxis(identifier, static_cast<int>(axis), value); +} + void Tas::StartStop() { if (!Settings::values.tas_enable) { return; diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index c95a130fc..c44c39da9 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -128,6 +128,8 @@ public: std::tuple<TasState, size_t, size_t> GetStatus() const; private: + enum class TasAxis : u8; + struct TASCommand { u64 buttons{}; TasAnalog l_axis{}; @@ -182,6 +184,9 @@ private: */ std::string WriteCommandAxis(TasAnalog data) const; + /// Sets an axis for a particular pad to the given value. + void SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value); + size_t script_length{0}; bool is_recording{false}; bool is_running{false}; From d52ad96ce348656b2ea7de8b8a85badfa86d2860 Mon Sep 17 00:00:00 2001 From: Lioncash <mathew1800@gmail.com> Date: Mon, 13 Dec 2021 10:49:06 -0500 Subject: [PATCH 02/10] tas_input: Amend -Wdocumentation warnings Parameters shouldn't have the colon by their name. --- src/input_common/drivers/tas_input.cpp | 10 +++--- src/input_common/drivers/tas_input.h | 48 ++++++++++++++------------ 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 1a38616b4..19d8ccae3 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -238,13 +238,13 @@ TasAnalog Tas::ReadCommandAxis(const std::string& line) const { return {x, y}; } -u64 Tas::ReadCommandButtons(const std::string& data) const { - std::stringstream button_text(data); - std::string line; +u64 Tas::ReadCommandButtons(const std::string& line) const { + std::stringstream button_text(line); + std::string button_line; u64 buttons = 0; - while (std::getline(button_text, line, ';')) { + while (std::getline(button_text, button_line, ';')) { for (auto [text, tas_button] : text_to_tas_button) { - if (text == line) { + if (text == button_line) { buttons |= static_cast<u64>(tas_button); break; } diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index c44c39da9..7c2c4a21b 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -88,39 +88,39 @@ public: /** * Changes the input status that will be stored in each frame - * @param buttons: bitfield with the status of the buttons - * @param left_axis: value of the left axis - * @param right_axis: value of the right axis + * @param buttons Bitfield with the status of the buttons + * @param left_axis Value of the left axis + * @param right_axis Value of the right axis */ void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis); // Main loop that records or executes input void UpdateThread(); - // Sets the flag to start or stop the TAS command excecution and swaps controllers profiles + // Sets the flag to start or stop the TAS command execution and swaps controllers profiles void StartStop(); - // Stop the TAS and reverts any controller profile + // Stop the TAS and reverts any controller profile void Stop(); - // Sets the flag to reload the file and start from the begining in the next update + // Sets the flag to reload the file and start from the beginning in the next update void Reset(); /** * Sets the flag to enable or disable recording of inputs - * @return Returns true if the current recording status is enabled + * @returns true if the current recording status is enabled */ bool Record(); /** * Saves contents of record_commands on a file - * @param overwrite_file: Indicates if player 1 should be overwritten + * @param overwrite_file Indicates if player 1 should be overwritten */ void SaveRecording(bool overwrite_file); /** * Returns the current status values of TAS playback/recording - * @return Tuple of + * @returns A Tuple of * TasState indicating the current state out of Running ; * Current playback progress ; * Total length of script file currently loaded or being recorded @@ -139,29 +139,31 @@ private: /// Loads TAS files from all players void LoadTasFiles(); - /** Loads TAS file from the specified player - * @param player_index: player number to save the script - * @param file_index: script number of the file + /** + * Loads TAS file from the specified player + * @param player_index Player number to save the script + * @param file_index Script number of the file */ void LoadTasFile(size_t player_index, size_t file_index); - /** Writes a TAS file from the recorded commands - * @param file_name: name of the file to be written + /** + * Writes a TAS file from the recorded commands + * @param file_name Name of the file to be written */ void WriteTasFile(std::u8string file_name); /** * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 - * @param line: string containing axis values with the following format "x;y" - * @return Returns a TAS analog object with axis values with range from -1.0 to 1.0 + * @param line String containing axis values with the following format "x;y" + * @returns A TAS analog object with axis values with range from -1.0 to 1.0 */ TasAnalog ReadCommandAxis(const std::string& line) const; /** * Parses a string containing the button values. Each button is represented by it's text format * specified in text_to_tas_button array - * @param line: string containing button name with the following format "a;b;c;d..." - * @return Returns a u64 with each bit representing the status of a button + * @param line string containing button name with the following format "a;b;c;d..." + * @returns A u64 with each bit representing the status of a button */ u64 ReadCommandButtons(const std::string& line) const; @@ -172,17 +174,17 @@ private: /** * Converts an u64 containing the button status into the text equivalent - * @param buttons: bitfield with the status of the buttons - * @return Returns a string with the name of the buttons to be written to the file + * @param buttons Bitfield with the status of the buttons + * @returns A string with the name of the buttons to be written to the file */ std::string WriteCommandButtons(u64 buttons) const; /** * Converts an TAS analog object containing the axis status into the text equivalent - * @param data: value of the axis - * @return A string with the value of the axis to be written to the file + * @param analog Value of the axis + * @returns A string with the value of the axis to be written to the file */ - std::string WriteCommandAxis(TasAnalog data) const; + std::string WriteCommandAxis(TasAnalog analog) const; /// Sets an axis for a particular pad to the given value. void SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value); From 37a8e2a67eae239b13f10ac56bc42932e9a25b25 Mon Sep 17 00:00:00 2001 From: Lioncash <mathew1800@gmail.com> Date: Mon, 13 Dec 2021 10:50:22 -0500 Subject: [PATCH 03/10] tas_input: Remove unused std::smatch variable This also means we can get rid of the dependency on <regex> --- src/input_common/drivers/tas_input.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 19d8ccae3..0a504c484 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include <cstring> -#include <regex> #include <fmt/format.h> #include "common/fs/file.h" @@ -93,7 +92,6 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { if (line.empty()) { continue; } - std::smatch m; std::stringstream linestream(line); std::string segment; From 6be730bdcdf875655973b1a39576e6933fd93eab Mon Sep 17 00:00:00 2001 From: Lioncash <mathew1800@gmail.com> Date: Mon, 13 Dec 2021 10:54:05 -0500 Subject: [PATCH 04/10] tas_input: Use u8string_view instead of u8string Same behavior, but without the potential for extra allocations. --- src/input_common/drivers/tas_input.cpp | 11 ++++++----- src/input_common/drivers/tas_input.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 0a504c484..3fdd3649b 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -121,16 +121,17 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { LOG_INFO(Input, "TAS file loaded! {} frames", frame_no); } -void Tas::WriteTasFile(std::u8string file_name) { +void Tas::WriteTasFile(std::u8string_view file_name) { std::string output_text; for (size_t frame = 0; frame < record_commands.size(); frame++) { const TASCommand& line = record_commands[frame]; output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons), WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis)); } - const auto bytes_written = Common::FS::WriteStringToFile( - Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name, - Common::FS::FileType::TextFile, output_text); + + const auto tas_file_name = Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name; + const auto bytes_written = + Common::FS::WriteStringToFile(tas_file_name, Common::FS::FileType::TextFile, output_text); if (bytes_written == output_text.size()) { LOG_INFO(Input, "TAS file written to file!"); } else { @@ -252,7 +253,7 @@ u64 Tas::ReadCommandButtons(const std::string& line) const { } std::string Tas::WriteCommandButtons(u64 buttons) const { - std::string returns = ""; + std::string returns; for (auto [text_button, tas_button] : text_to_tas_button) { if ((buttons & static_cast<u64>(tas_button)) != 0) { returns += fmt::format("{};", text_button); diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 7c2c4a21b..68970dcec 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -150,7 +150,7 @@ private: * Writes a TAS file from the recorded commands * @param file_name Name of the file to be written */ - void WriteTasFile(std::u8string file_name); + void WriteTasFile(std::u8string_view file_name); /** * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 From a515ede2af822a337b95ed0b3987a197664d5180 Mon Sep 17 00:00:00 2001 From: Lioncash <mathew1800@gmail.com> Date: Mon, 13 Dec 2021 10:57:51 -0500 Subject: [PATCH 05/10] tas_input: Use istringstream over stringstream This is only using the input facilities, so we don't need to use the fully-fleged stringstream. --- src/input_common/drivers/tas_input.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 3fdd3649b..a7d3d0b47 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -85,7 +85,7 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / fmt::format("script{}-{}.txt", file_index, player_index + 1), Common::FS::FileType::BinaryFile); - std::stringstream command_line(file); + std::istringstream command_line(file); std::string line; int frame_no = 0; while (std::getline(command_line, line, '\n')) { @@ -93,7 +93,7 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { continue; } - std::stringstream linestream(line); + std::istringstream linestream(line); std::string segment; std::vector<std::string> seglist; From 26ef76213c81b6c2dc8eeeae11e9586f22a76011 Mon Sep 17 00:00:00 2001 From: Lioncash <mathew1800@gmail.com> Date: Mon, 13 Dec 2021 11:07:26 -0500 Subject: [PATCH 06/10] tas_input: std::move strings into vector While we're in the same area, we can also avoid performing std::stoi in a loop when it only needs to be performed once. --- src/input_common/drivers/tas_input.cpp | 45 ++++++++++++++------------ 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index a7d3d0b47..d14a43b9e 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -93,27 +93,29 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { continue; } - std::istringstream linestream(line); - std::string segment; - std::vector<std::string> seglist; - - while (std::getline(linestream, segment, ' ')) { - seglist.push_back(segment); + std::vector<std::string> seg_list; + { + std::istringstream line_stream(line); + std::string segment; + while (std::getline(line_stream, segment, ' ')) { + seg_list.push_back(std::move(segment)); + } } - if (seglist.size() < 4) { + if (seg_list.size() < 4) { continue; } - while (frame_no < std::stoi(seglist.at(0))) { - commands[player_index].push_back({}); + const auto num_frames = std::stoi(seg_list[0]); + while (frame_no < num_frames) { + commands[player_index].emplace_back(); frame_no++; } TASCommand command = { - .buttons = ReadCommandButtons(seglist.at(1)), - .l_axis = ReadCommandAxis(seglist.at(2)), - .r_axis = ReadCommandAxis(seglist.at(3)), + .buttons = ReadCommandButtons(seg_list[1]), + .l_axis = ReadCommandAxis(seg_list[2]), + .r_axis = ReadCommandAxis(seg_list[3]), }; commands[player_index].push_back(command); frame_no++; @@ -223,22 +225,23 @@ void Tas::ClearInput() { } TasAnalog Tas::ReadCommandAxis(const std::string& line) const { - std::stringstream linestream(line); - std::string segment; - std::vector<std::string> seglist; - - while (std::getline(linestream, segment, ';')) { - seglist.push_back(segment); + std::vector<std::string> seg_list; + { + std::istringstream line_stream(line); + std::string segment; + while (std::getline(line_stream, segment, ';')) { + seg_list.push_back(std::move(segment)); + } } - const float x = std::stof(seglist.at(0)) / 32767.0f; - const float y = std::stof(seglist.at(1)) / 32767.0f; + const float x = std::stof(seg_list.at(0)) / 32767.0f; + const float y = std::stof(seg_list.at(1)) / 32767.0f; return {x, y}; } u64 Tas::ReadCommandButtons(const std::string& line) const { - std::stringstream button_text(line); + std::istringstream button_text(line); std::string button_line; u64 buttons = 0; while (std::getline(button_text, button_line, ';')) { From db9320e7541430dc487e85f40912725bd5b66c8a Mon Sep 17 00:00:00 2001 From: Lioncash <mathew1800@gmail.com> Date: Mon, 13 Dec 2021 11:10:56 -0500 Subject: [PATCH 07/10] tas_input: Remove unnecessary includes Gets rid of indirect includes and includes only what the interface needs. --- src/input_common/drivers/tas_input.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 68970dcec..3996fe3a8 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -5,11 +5,11 @@ #pragma once #include <array> +#include <string> +#include <vector> #include "common/common_types.h" -#include "common/settings_input.h" #include "input_common/input_engine.h" -#include "input_common/main.h" /* To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below From ddda6ae776e0fab22a3cf70a9f4f5a87df86fda8 Mon Sep 17 00:00:00 2001 From: Lioncash <mathew1800@gmail.com> Date: Mon, 13 Dec 2021 11:19:24 -0500 Subject: [PATCH 08/10] tas_input: Execute clear() even if empty clear() when empty is simply a no-op, so we can get rid of the check here and let the stdlib do it for us. --- src/input_common/drivers/tas_input.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index d14a43b9e..bd4e411c9 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -78,9 +78,8 @@ void Tas::LoadTasFiles() { } void Tas::LoadTasFile(size_t player_index, size_t file_index) { - if (!commands[player_index].empty()) { - commands[player_index].clear(); - } + commands[player_index].clear(); + std::string file = Common::FS::ReadStringFromFile( Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / fmt::format("script{}-{}.txt", file_index, player_index + 1), From 734fb180bb42d361f05d1fab02323de5095e2d8d Mon Sep 17 00:00:00 2001 From: Lioncash <mathew1800@gmail.com> Date: Mon, 13 Dec 2021 11:20:23 -0500 Subject: [PATCH 09/10] tas_input: Remove unnecessary semicolon Resolves a -Wextra-semi warning --- src/input_common/drivers/tas_input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index bd4e411c9..1617ba1d4 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -65,7 +65,7 @@ Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engi Tas::~Tas() { Stop(); -}; +} void Tas::LoadTasFiles() { script_length = 0; From 54ca48e8b772453814d2e4d49a4ba29a1b46b32d Mon Sep 17 00:00:00 2001 From: Lioncash <mathew1800@gmail.com> Date: Mon, 13 Dec 2021 11:36:48 -0500 Subject: [PATCH 10/10] tas_input: Avoid minor copies in Read/WriteCommandButtons() We don't need to copy the whole pair --- src/input_common/drivers/tas_input.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 1617ba1d4..2094c1feb 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -244,7 +244,7 @@ u64 Tas::ReadCommandButtons(const std::string& line) const { std::string button_line; u64 buttons = 0; while (std::getline(button_text, button_line, ';')) { - for (auto [text, tas_button] : text_to_tas_button) { + for (const auto& [text, tas_button] : text_to_tas_button) { if (text == button_line) { buttons |= static_cast<u64>(tas_button); break; @@ -256,7 +256,7 @@ u64 Tas::ReadCommandButtons(const std::string& line) const { std::string Tas::WriteCommandButtons(u64 buttons) const { std::string returns; - for (auto [text_button, tas_button] : text_to_tas_button) { + for (const auto& [text_button, tas_button] : text_to_tas_button) { if ((buttons & static_cast<u64>(tas_button)) != 0) { returns += fmt::format("{};", text_button); }