From c01a872c8efa90065b6ba1a74079ddf6ec12058f Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 19 Jun 2021 14:38:49 -0500 Subject: config: Move TAS options to it's own menu --- src/input_common/main.cpp | 6 +- src/input_common/tas/tas_input.cpp | 189 ++++++++++++++++++++----------------- src/input_common/tas/tas_input.h | 26 +++-- 3 files changed, 130 insertions(+), 91 deletions(-) (limited to 'src/input_common') diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 4f170493e..3b9906b53 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -5,6 +5,7 @@ #include #include #include "common/param_package.h" +#include "common/settings.h" #include "input_common/analog_from_button.h" #include "input_common/gcadapter/gc_adapter.h" #include "input_common/gcadapter/gc_poller.h" @@ -114,8 +115,11 @@ struct InputSubsystem::Impl { std::vector devices = { Common::ParamPackage{{"display", "Any"}, {"class", "any"}}, Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}}, - Common::ParamPackage{{"display", "TAS"}, {"class", "tas"}}, }; + if (Settings::values.tas_enable) { + devices.push_back( + Common::ParamPackage{{"display", "TAS Controller"}, {"class", "tas"}}); + } #ifdef HAVE_SDL2 auto sdl_devices = sdl->GetInputDevices(); devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); diff --git a/src/input_common/tas/tas_input.cpp b/src/input_common/tas/tas_input.cpp index 7320a7004..6efa1234a 100644 --- a/src/input_common/tas/tas_input.cpp +++ b/src/input_common/tas/tas_input.cpp @@ -67,14 +67,13 @@ void Tas::LoadTasFile(size_t player_index) { if (!commands[player_index].empty()) { commands[player_index].clear(); } - std::string file = Common::FS::ReadStringFromFile( - Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASFile) + "script0-" + - std::to_string(player_index + 1) + ".txt", - Common::FS::FileType::BinaryFile); + std::string file = + Common::FS::ReadStringFromFile(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir) + + "script0-" + std::to_string(player_index + 1) + ".txt", + Common::FS::FileType::BinaryFile); std::stringstream command_line(file); std::string line; - int frameNo = 0; - TASCommand empty = {.buttons = 0, .l_axis = {0.f, 0.f}, .r_axis = {0.f, 0.f}}; + int frame_no = 0; while (std::getline(command_line, line, '\n')) { if (line.empty()) { continue; @@ -94,9 +93,9 @@ void Tas::LoadTasFile(size_t player_index) { continue; } - while (frameNo < std::stoi(seglist.at(0))) { - commands[player_index].push_back(empty); - frameNo++; + while (frame_no < std::stoi(seglist.at(0))) { + commands[player_index].push_back({}); + frame_no++; } TASCommand command = { @@ -105,30 +104,29 @@ void Tas::LoadTasFile(size_t player_index) { .r_axis = ReadCommandAxis(seglist.at(3)), }; commands[player_index].push_back(command); - frameNo++; + frame_no++; } - LOG_INFO(Input, "TAS file loaded! {} frames", frameNo); + LOG_INFO(Input, "TAS file loaded! {} frames", frame_no); } void Tas::WriteTasFile() { LOG_DEBUG(Input, "WriteTasFile()"); - std::string output_text = ""; - for (int frame = 0; frame < (signed)record_commands.size(); frame++) { + std::string output_text; + for (size_t frame = 0; frame < record_commands.size(); frame++) { if (!output_text.empty()) { output_text += "\n"; } - TASCommand line = record_commands.at(frame); + const TASCommand& line = record_commands[frame]; output_text += std::to_string(frame) + " " + WriteCommandButtons(line.buttons) + " " + WriteCommandAxis(line.l_axis) + " " + WriteCommandAxis(line.r_axis); } - size_t bytesWritten = Common::FS::WriteStringToFile( - Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASFile) + "record.txt", + const size_t bytes_written = Common::FS::WriteStringToFile( + Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir) + "record.txt", Common::FS::FileType::TextFile, output_text); - if (bytesWritten == output_text.size()) { + if (bytes_written == output_text.size()) { LOG_INFO(Input, "TAS file written to file!"); - } - else { - LOG_ERROR(Input, "Writing the TAS-file has failed! {} / {} bytes written", bytesWritten, + } else { + LOG_ERROR(Input, "Writing the TAS-file has failed! {} / {} bytes written", bytes_written, output_text.size()); } } @@ -142,30 +140,33 @@ void Tas::RecordInput(u32 buttons, const std::array, 2>& last_input = {buttons, FlipY(axes[0]), FlipY(axes[1])}; } -std::tuple Tas::GetStatus() { +std::tuple Tas::GetStatus() const { TasState state; - if (Settings::values.tas_record) { - return {TasState::RECORDING, record_commands.size(), record_commands.size()}; - } else if (Settings::values.tas_enable) { - state = TasState::RUNNING; + if (is_recording) { + return {TasState::Recording, 0, record_commands.size()}; + } + + if (is_running) { + state = TasState::Running; } else { - state = TasState::STOPPED; + state = TasState::Stopped; } return {state, current_command, script_length}; } static std::string DebugButtons(u32 buttons) { - return "{ " + TasInput::Tas::ButtonsToString(buttons) + " }"; + return fmt::format("{{ {} }}", TasInput::Tas::ButtonsToString(buttons)); } static std::string DebugJoystick(float x, float y) { - return "[ " + std::to_string(x) + "," + std::to_string(y) + " ]"; + return fmt::format("[ {} , {} ]", std::to_string(x), std::to_string(y)); } static std::string DebugInput(const TasData& data) { - return "{ " + DebugButtons(data.buttons) + " , " + DebugJoystick(data.axis[0], data.axis[1]) + - " , " + DebugJoystick(data.axis[2], data.axis[3]) + " }"; + return fmt::format("{{ {} , {} , {} }}", DebugButtons(data.buttons), + DebugJoystick(data.axis[0], data.axis[1]), + DebugJoystick(data.axis[2], data.axis[3])); } static std::string DebugInputs(const std::array& arr) { @@ -180,66 +181,54 @@ static std::string DebugInputs(const std::array& arr) { } void Tas::UpdateThread() { - if (update_thread_running) { - if (Settings::values.pause_tas_on_load && Settings::values.is_cpu_boosted) { - for (size_t i = 0; i < PLAYER_NUMBER; i++) { - tas_data[i].buttons = 0; - tas_data[i].axis = {}; - } - } + if (!update_thread_running) { + return; + } - if (Settings::values.tas_record) { - record_commands.push_back(last_input); - } - if (!Settings::values.tas_record && !record_commands.empty()) { - WriteTasFile(); - Settings::values.tas_reset = true; - refresh_tas_fle = true; - record_commands.clear(); - } - if (Settings::values.tas_reset) { - current_command = 0; - if (refresh_tas_fle) { - LoadTasFiles(); - refresh_tas_fle = false; - } - Settings::values.tas_reset = false; + if (is_recording) { + record_commands.push_back(last_input); + } + if (!is_recording && !record_commands.empty()) { + WriteTasFile(); + needs_reset = true; + refresh_tas_fle = true; + record_commands.clear(); + } + if (needs_reset) { + current_command = 0; + if (refresh_tas_fle) { LoadTasFiles(); - LOG_DEBUG(Input, "tas_reset done"); + refresh_tas_fle = false; } - if (Settings::values.tas_enable) { - if ((signed)current_command < script_length) { - LOG_INFO(Input, "Playing TAS {}/{}", current_command, script_length); - size_t frame = current_command++; - for (size_t i = 0; i < PLAYER_NUMBER; i++) { - if (frame < commands[i].size()) { - TASCommand command = commands[i][frame]; - tas_data[i].buttons = command.buttons; - auto [l_axis_x, l_axis_y] = command.l_axis; - tas_data[i].axis[0] = l_axis_x; - tas_data[i].axis[1] = l_axis_y; - auto [r_axis_x, r_axis_y] = command.r_axis; - tas_data[i].axis[2] = r_axis_x; - tas_data[i].axis[3] = r_axis_y; - } else { - tas_data[i].buttons = 0; - tas_data[i].axis = {}; - } - } - } else { - Settings::values.tas_enable = false; - current_command = 0; - for (size_t i = 0; i < PLAYER_NUMBER; i++) { - tas_data[i].buttons = 0; - tas_data[i].axis = {}; + needs_reset = false; + LoadTasFiles(); + LOG_DEBUG(Input, "tas_reset done"); + } + if (is_running) { + if (current_command < script_length) { + LOG_INFO(Input, "Playing TAS {}/{}", current_command, script_length); + size_t frame = current_command++; + for (size_t i = 0; i < PLAYER_NUMBER; i++) { + if (frame < commands[i].size()) { + TASCommand command = commands[i][frame]; + tas_data[i].buttons = command.buttons; + auto [l_axis_x, l_axis_y] = command.l_axis; + tas_data[i].axis[0] = l_axis_x; + tas_data[i].axis[1] = l_axis_y; + auto [r_axis_x, r_axis_y] = command.r_axis; + tas_data[i].axis[2] = r_axis_x; + tas_data[i].axis[3] = r_axis_y; + } else { + tas_data[i] = {}; } } } else { - for (size_t i = 0; i < PLAYER_NUMBER; i++) { - tas_data[i].buttons = 0; - tas_data[i].axis = {}; - } + is_running = Settings::values.tas_loop; + current_command = 0; + tas_data.fill({}); } + } else { + tas_data.fill({}); } LOG_DEBUG(Input, "TAS inputs: {}", DebugInputs(tas_data)); } @@ -284,8 +273,9 @@ std::string Tas::WriteCommandAxis(TasAnalog data) const { } std::string Tas::WriteCommandButtons(u32 data) const { - if (data == 0) + if (data == 0) { return "NONE"; + } std::string line; u32 index = 0; @@ -307,6 +297,37 @@ std::string Tas::WriteCommandButtons(u32 data) const { return line; } +void Tas::StartStop() { + is_running = !is_running; +} + +void Tas::Reset() { + needs_reset = true; +} + +void Tas::Record() { + is_recording = !is_recording; +<<<<<<< HEAD +======= + return is_recording; +} + +void Tas::SaveRecording(bool overwrite_file) { + if (is_recording) { + return; + } + if (record_commands.empty()) { + return; + } + WriteTasFile("record.txt"); + if (overwrite_file) { + WriteTasFile("script0-1.txt"); + } + needs_reset = true; + record_commands.clear(); +>>>>>>> 773d268db (config: disable pause on load) +} + InputCommon::ButtonMapping Tas::GetButtonMappingForDevice( const Common::ParamPackage& params) const { // This list is missing ZL/ZR since those are not considered buttons. diff --git a/src/input_common/tas/tas_input.h b/src/input_common/tas/tas_input.h index 8ee70bcaf..49ef10ff9 100644 --- a/src/input_common/tas/tas_input.h +++ b/src/input_common/tas/tas_input.h @@ -14,14 +14,14 @@ namespace TasInput { -constexpr int PLAYER_NUMBER = 8; +constexpr size_t PLAYER_NUMBER = 8; using TasAnalog = std::pair; enum class TasState { - RUNNING, - RECORDING, - STOPPED, + Running, + Recording, + Stopped, }; enum class TasButton : u32 { @@ -114,8 +114,19 @@ public: void LoadTasFiles(); void RecordInput(u32 buttons, const std::array, 2>& axes); void UpdateThread(); - std::tuple GetStatus(); + void StartStop(); + void Reset(); + void Record(); + + /** + * Returns the current status values of TAS playback/recording + * @return Tuple of + * TasState indicating the current state out of Running, Recording or Stopped ; + * Current playback progress or amount of frames (so far) for Recording ; + * Total length of script file currently loaded or amount of frames (so far) for Recording + */ + std::tuple GetStatus() const; InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const; InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const; [[nodiscard]] const TasData& GetTasState(std::size_t pad) const; @@ -137,9 +148,12 @@ private: std::array tas_data; bool update_thread_running{true}; bool refresh_tas_fle{false}; + bool is_recording{false}; + bool is_running{false}; + bool needs_reset{false}; std::array, PLAYER_NUMBER> commands{}; std::vector record_commands{}; - std::size_t current_command{0}; + size_t current_command{0}; TASCommand last_input{}; // only used for recording }; } // namespace TasInput -- cgit v1.2.3