Merge pull request #7576 from lioncash/tasenum

tas_input: Minor cleanup
master
bunnei 2021-12-13 14:47:24 +07:00 committed by GitHub
commit 7276aaf907
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 70 deletions

@ -3,7 +3,6 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <cstring> #include <cstring>
#include <regex>
#include <fmt/format.h> #include <fmt/format.h>
#include "common/fs/file.h" #include "common/fs/file.h"
@ -15,7 +14,7 @@
namespace InputCommon::TasInput { namespace InputCommon::TasInput {
enum TasAxes : u8 { enum class Tas::TasAxis : u8 {
StickX, StickX,
StickY, StickY,
SubstickX, SubstickX,
@ -66,7 +65,7 @@ Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engi
Tas::~Tas() { Tas::~Tas() {
Stop(); Stop();
}; }
void Tas::LoadTasFiles() { void Tas::LoadTasFiles() {
script_length = 0; script_length = 0;
@ -79,43 +78,43 @@ void Tas::LoadTasFiles() {
} }
void Tas::LoadTasFile(size_t player_index, size_t file_index) { 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( std::string file = Common::FS::ReadStringFromFile(
Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) /
fmt::format("script{}-{}.txt", file_index, player_index + 1), fmt::format("script{}-{}.txt", file_index, player_index + 1),
Common::FS::FileType::BinaryFile); Common::FS::FileType::BinaryFile);
std::stringstream command_line(file); std::istringstream command_line(file);
std::string line; std::string line;
int frame_no = 0; int frame_no = 0;
while (std::getline(command_line, line, '\n')) { while (std::getline(command_line, line, '\n')) {
if (line.empty()) { if (line.empty()) {
continue; continue;
} }
std::smatch m;
std::stringstream linestream(line); std::vector<std::string> seg_list;
{
std::istringstream line_stream(line);
std::string segment; std::string segment;
std::vector<std::string> seglist; while (std::getline(line_stream, segment, ' ')) {
seg_list.push_back(std::move(segment));
while (std::getline(linestream, segment, ' ')) { }
seglist.push_back(segment);
} }
if (seglist.size() < 4) { if (seg_list.size() < 4) {
continue; continue;
} }
while (frame_no < std::stoi(seglist.at(0))) { const auto num_frames = std::stoi(seg_list[0]);
commands[player_index].push_back({}); while (frame_no < num_frames) {
commands[player_index].emplace_back();
frame_no++; frame_no++;
} }
TASCommand command = { TASCommand command = {
.buttons = ReadCommandButtons(seglist.at(1)), .buttons = ReadCommandButtons(seg_list[1]),
.l_axis = ReadCommandAxis(seglist.at(2)), .l_axis = ReadCommandAxis(seg_list[2]),
.r_axis = ReadCommandAxis(seglist.at(3)), .r_axis = ReadCommandAxis(seg_list[3]),
}; };
commands[player_index].push_back(command); commands[player_index].push_back(command);
frame_no++; frame_no++;
@ -123,16 +122,17 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) {
LOG_INFO(Input, "TAS file loaded! {} frames", frame_no); 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; std::string output_text;
for (size_t frame = 0; frame < record_commands.size(); frame++) { for (size_t frame = 0; frame < record_commands.size(); frame++) {
const TASCommand& line = record_commands[frame]; const TASCommand& line = record_commands[frame];
output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons), output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons),
WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis)); WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis));
} }
const auto bytes_written = Common::FS::WriteStringToFile(
Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name, const auto tas_file_name = Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name;
Common::FS::FileType::TextFile, output_text); const auto bytes_written =
Common::FS::WriteStringToFile(tas_file_name, Common::FS::FileType::TextFile, output_text);
if (bytes_written == output_text.size()) { if (bytes_written == output_text.size()) {
LOG_INFO(Input, "TAS file written to file!"); LOG_INFO(Input, "TAS file written to file!");
} else { } else {
@ -205,10 +205,10 @@ void Tas::UpdateThread() {
const int button = static_cast<int>(i); const int button = static_cast<int>(i);
SetButton(identifier, button, button_status); SetButton(identifier, button, button_status);
} }
SetAxis(identifier, TasAxes::StickX, command.l_axis.x); SetTasAxis(identifier, TasAxis::StickX, command.l_axis.x);
SetAxis(identifier, TasAxes::StickY, command.l_axis.y); SetTasAxis(identifier, TasAxis::StickY, command.l_axis.y);
SetAxis(identifier, TasAxes::SubstickX, command.r_axis.x); SetTasAxis(identifier, TasAxis::SubstickX, command.r_axis.x);
SetAxis(identifier, TasAxes::SubstickY, command.r_axis.y); SetTasAxis(identifier, TasAxis::SubstickY, command.r_axis.y);
} }
} else { } else {
is_running = Settings::values.tas_loop.GetValue(); is_running = Settings::values.tas_loop.GetValue();
@ -224,27 +224,28 @@ void Tas::ClearInput() {
} }
TasAnalog Tas::ReadCommandAxis(const std::string& line) const { TasAnalog Tas::ReadCommandAxis(const std::string& line) const {
std::stringstream linestream(line); std::vector<std::string> seg_list;
{
std::istringstream line_stream(line);
std::string segment; std::string segment;
std::vector<std::string> seglist; while (std::getline(line_stream, segment, ';')) {
seg_list.push_back(std::move(segment));
while (std::getline(linestream, segment, ';')) { }
seglist.push_back(segment);
} }
const float x = std::stof(seglist.at(0)) / 32767.0f; const float x = std::stof(seg_list.at(0)) / 32767.0f;
const float y = std::stof(seglist.at(1)) / 32767.0f; const float y = std::stof(seg_list.at(1)) / 32767.0f;
return {x, y}; return {x, y};
} }
u64 Tas::ReadCommandButtons(const std::string& data) const { u64 Tas::ReadCommandButtons(const std::string& line) const {
std::stringstream button_text(data); std::istringstream button_text(line);
std::string line; std::string button_line;
u64 buttons = 0; 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) { for (const auto& [text, tas_button] : text_to_tas_button) {
if (text == line) { if (text == button_line) {
buttons |= static_cast<u64>(tas_button); buttons |= static_cast<u64>(tas_button);
break; break;
} }
@ -254,8 +255,8 @@ u64 Tas::ReadCommandButtons(const std::string& data) const {
} }
std::string Tas::WriteCommandButtons(u64 buttons) const { std::string Tas::WriteCommandButtons(u64 buttons) const {
std::string returns = ""; 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) { if ((buttons & static_cast<u64>(tas_button)) != 0) {
returns += fmt::format("{};", text_button); returns += fmt::format("{};", text_button);
} }
@ -267,6 +268,10 @@ std::string Tas::WriteCommandAxis(TasAnalog analog) const {
return fmt::format("{};{}", analog.x * 32767, analog.y * 32767); 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() { void Tas::StartStop() {
if (!Settings::values.tas_enable) { if (!Settings::values.tas_enable) {
return; return;

@ -5,11 +5,11 @@
#pragma once #pragma once
#include <array> #include <array>
#include <string>
#include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/settings_input.h"
#include "input_common/input_engine.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 To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below
@ -88,39 +88,39 @@ public:
/** /**
* Changes the input status that will be stored in each frame * Changes the input status that will be stored in each frame
* @param buttons: bitfield with the status of the buttons * @param buttons Bitfield with the status of the buttons
* @param left_axis: value of the left axis * @param left_axis Value of the left axis
* @param right_axis: value of the right axis * @param right_axis Value of the right axis
*/ */
void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis); void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis);
// Main loop that records or executes input // Main loop that records or executes input
void UpdateThread(); 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(); void StartStop();
// Stop the TAS and reverts any controller profile // Stop the TAS and reverts any controller profile
void Stop(); 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(); void Reset();
/** /**
* Sets the flag to enable or disable recording of inputs * 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(); bool Record();
/** /**
* Saves contents of record_commands on a file * 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); void SaveRecording(bool overwrite_file);
/** /**
* Returns the current status values of TAS playback/recording * Returns the current status values of TAS playback/recording
* @return Tuple of * @returns A Tuple of
* TasState indicating the current state out of Running ; * TasState indicating the current state out of Running ;
* Current playback progress ; * Current playback progress ;
* Total length of script file currently loaded or being recorded * Total length of script file currently loaded or being recorded
@ -128,6 +128,8 @@ public:
std::tuple<TasState, size_t, size_t> GetStatus() const; std::tuple<TasState, size_t, size_t> GetStatus() const;
private: private:
enum class TasAxis : u8;
struct TASCommand { struct TASCommand {
u64 buttons{}; u64 buttons{};
TasAnalog l_axis{}; TasAnalog l_axis{};
@ -137,29 +139,31 @@ private:
/// Loads TAS files from all players /// Loads TAS files from all players
void LoadTasFiles(); void LoadTasFiles();
/** Loads TAS file from the specified player /**
* @param player_index: player number to save the script * Loads TAS file from the specified player
* @param file_index: script number of the file * @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); 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); void WriteTasFile(std::u8string_view file_name);
/** /**
* Parses a string containing the axis values. X and Y have a range from -32767 to 32767 * 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" * @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 * @returns A TAS analog object with axis values with range from -1.0 to 1.0
*/ */
TasAnalog ReadCommandAxis(const std::string& line) const; TasAnalog ReadCommandAxis(const std::string& line) const;
/** /**
* Parses a string containing the button values. Each button is represented by it's text format * Parses a string containing the button values. Each button is represented by it's text format
* specified in text_to_tas_button array * specified in text_to_tas_button array
* @param line: string containing button name with the following format "a;b;c;d..." * @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 * @returns A u64 with each bit representing the status of a button
*/ */
u64 ReadCommandButtons(const std::string& line) const; u64 ReadCommandButtons(const std::string& line) const;
@ -170,17 +174,20 @@ private:
/** /**
* Converts an u64 containing the button status into the text equivalent * Converts an u64 containing the button status into the text equivalent
* @param buttons: bitfield with the status of the buttons * @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 * @returns A string with the name of the buttons to be written to the file
*/ */
std::string WriteCommandButtons(u64 buttons) const; std::string WriteCommandButtons(u64 buttons) const;
/** /**
* Converts an TAS analog object containing the axis status into the text equivalent * Converts an TAS analog object containing the axis status into the text equivalent
* @param data: value of the axis * @param analog Value of the axis
* @return A string with the value of the axis to be written to the file * @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);
size_t script_length{0}; size_t script_length{0};
bool is_recording{false}; bool is_recording{false};