Просмотр исходного кода

input_common/tas: Add swap controller

german77 5 лет назад
Родитель
Сommit
e6c4bf52f0

+ 1 - 1
src/common/fs/path_util.h

@@ -23,7 +23,7 @@ enum class YuzuPath {
     ScreenshotsDir, // Where yuzu screenshots are stored.
     SDMCDir,        // Where the emulated SDMC is stored.
     ShaderDir,      // Where shaders are stored.
-    TASDir,         // Where the current script file is stored.
+    TASDir,         // Where TAS scripts are stored.
 };
 
 /**

+ 10 - 10
src/input_common/main.h

@@ -155,28 +155,28 @@ public:
     /// Retrieves the underlying udp touch handler.
     [[nodiscard]] const UDPTouchFactory* GetUDPTouch() const;
 
-    /// Retrieves the underlying GameCube button handler.
+    /// Retrieves the underlying mouse button handler.
     [[nodiscard]] MouseButtonFactory* GetMouseButtons();
 
-    /// Retrieves the underlying GameCube button handler.
+    /// Retrieves the underlying mouse button handler.
     [[nodiscard]] const MouseButtonFactory* GetMouseButtons() const;
 
-    /// Retrieves the underlying udp touch handler.
+    /// Retrieves the underlying mouse analog handler.
     [[nodiscard]] MouseAnalogFactory* GetMouseAnalogs();
 
-    /// Retrieves the underlying udp touch handler.
+    /// Retrieves the underlying mouse analog handler.
     [[nodiscard]] const MouseAnalogFactory* GetMouseAnalogs() const;
 
-    /// Retrieves the underlying udp motion handler.
+    /// Retrieves the underlying mouse motion handler.
     [[nodiscard]] MouseMotionFactory* GetMouseMotions();
 
-    /// Retrieves the underlying udp motion handler.
+    /// Retrieves the underlying mouse motion handler.
     [[nodiscard]] const MouseMotionFactory* GetMouseMotions() const;
 
-    /// Retrieves the underlying udp touch handler.
+    /// Retrieves the underlying mouse touch handler.
     [[nodiscard]] MouseTouchFactory* GetMouseTouch();
 
-    /// Retrieves the underlying udp touch handler.
+    /// Retrieves the underlying mouse touch handler.
     [[nodiscard]] const MouseTouchFactory* GetMouseTouch() const;
 
     /// Retrieves the underlying tas button handler.
@@ -185,10 +185,10 @@ public:
     /// Retrieves the underlying tas button handler.
     [[nodiscard]] const TasButtonFactory* GetTasButtons() const;
 
-    /// Retrieves the underlying tas touch handler.
+    /// Retrieves the underlying tas analogs handler.
     [[nodiscard]] TasAnalogFactory* GetTasAnalogs();
 
-    /// Retrieves the underlying tas touch handler.
+    /// Retrieves the underlying tas analogs handler.
     [[nodiscard]] const TasAnalogFactory* GetTasAnalogs() const;
 
     /// Reloads the input devices

+ 56 - 7
src/input_common/tas/tas_input.cpp

@@ -61,8 +61,8 @@ void Tas::LoadTasFile(size_t player_index) {
         commands[player_index].clear();
     }
     std::string file =
-        Common::FS::ReadStringFromFile(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir) +
-                                           "script0-" + std::to_string(player_index + 1) + ".txt",
+        Common::FS::ReadStringFromFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) /
+                                           fmt::format("script0-{}.txt", player_index + 1),
                                        Common::FS::FileType::BinaryFile);
     std::stringstream command_line(file);
     std::string line;
@@ -102,7 +102,7 @@ void Tas::LoadTasFile(size_t player_index) {
     LOG_INFO(Input, "TAS file loaded! {} frames", frame_no);
 }
 
-void Tas::WriteTasFile(std::string file_name) {
+void Tas::WriteTasFile(std::u8string file_name) {
     std::string output_text;
     for (size_t frame = 0; frame < record_commands.size(); frame++) {
         if (!output_text.empty()) {
@@ -112,8 +112,8 @@ void Tas::WriteTasFile(std::string file_name) {
         output_text += std::to_string(frame) + " " + WriteCommandButtons(line.buttons) + " " +
                        WriteCommandAxis(line.l_axis) + " " + WriteCommandAxis(line.r_axis);
     }
-    const size_t bytes_written = Common::FS::WriteStringToFile(
-        Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir) + file_name,
+    const auto bytes_written = Common::FS::WriteStringToFile(
+        Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name,
         Common::FS::FileType::TextFile, output_text);
     if (bytes_written == output_text.size()) {
         LOG_INFO(Input, "TAS file written to file!");
@@ -217,6 +217,9 @@ void Tas::UpdateThread() {
             is_running = Settings::values.tas_loop;
             current_command = 0;
             tas_data.fill({});
+            if (!is_running) {
+                SwapToStoredController();
+            }
         }
     } else {
         tas_data.fill({});
@@ -290,6 +293,52 @@ std::string Tas::WriteCommandButtons(u32 data) const {
 
 void Tas::StartStop() {
     is_running = !is_running;
+    if (is_running) {
+        SwapToTasController();
+    } else {
+        SwapToStoredController();
+    }
+}
+
+void Tas::SwapToTasController() {
+    if (!Settings::values.tas_swap_controllers) {
+        return;
+    }
+    auto& players = Settings::values.players.GetValue();
+    for (std::size_t index = 0; index < players.size(); index++) {
+        auto& player = players[index];
+        player_mappings[index] = player;
+
+        // Only swap active controllers
+        if (!player.connected) {
+            continue;
+        }
+
+        auto tas_param = Common::ParamPackage{{"pad", static_cast<u8>(index)}};
+        auto button_mapping = GetButtonMappingForDevice(tas_param);
+        auto analog_mapping = GetAnalogMappingForDevice(tas_param);
+        auto& buttons = player.buttons;
+        auto& analogs = player.analogs;
+
+        for (std::size_t i = 0; i < buttons.size(); ++i) {
+            buttons[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)].Serialize();
+        }
+        for (std::size_t i = 0; i < analogs.size(); ++i) {
+            analogs[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)].Serialize();
+        }
+    }
+    Settings::values.is_device_reload_pending.store(true);
+}
+
+void Tas::SwapToStoredController() {
+    if (!Settings::values.tas_swap_controllers) {
+        return;
+    }
+    auto& players = Settings::values.players.GetValue();
+    for (std::size_t index = 0; index < players.size(); index++) {
+        players[index] = player_mappings[index];
+    }
+    Settings::values.is_device_reload_pending.store(true);
 }
 
 void Tas::Reset() {
@@ -308,9 +357,9 @@ void Tas::SaveRecording(bool overwrite_file) {
     if (record_commands.empty()) {
         return;
     }
-    WriteTasFile("record.txt");
+    WriteTasFile(u8"record.txt");
     if (overwrite_file) {
-        WriteTasFile("script0-1.txt");
+        WriteTasFile(u8"script0-1.txt");
     }
     needs_reset = true;
     record_commands.clear();

+ 8 - 1
src/input_common/tas/tas_input.h

@@ -7,6 +7,7 @@
 #include <array>
 
 #include "common/common_types.h"
+#include "common/settings_input.h"
 #include "core/frontend/input.h"
 #include "input_common/main.h"
 
@@ -91,7 +92,7 @@ private:
     };
     void LoadTasFiles();
     void LoadTasFile(size_t player_index);
-    void WriteTasFile(std::string file_name);
+    void WriteTasFile(std::u8string file_name);
     TasAnalog ReadCommandAxis(const std::string& line) const;
     u32 ReadCommandButtons(const std::string& line) const;
     std::string WriteCommandButtons(u32 data) const;
@@ -105,6 +106,9 @@ private:
     std::string DebugInputs(const std::array<TasData, PLAYER_NUMBER>& arr) const;
     std::string ButtonsToString(u32 button) const;
 
+    void SwapToTasController();
+    void SwapToStoredController();
+
     size_t script_length{0};
     std::array<TasData, PLAYER_NUMBER> tas_data;
     bool is_recording{false};
@@ -114,5 +118,8 @@ private:
     std::vector<TASCommand> record_commands{};
     size_t current_command{0};
     TASCommand last_input{}; // only used for recording
+
+    // Old settings for swapping controllers
+    std::array<Settings::PlayerInput, 10> player_mappings;
 };
 } // namespace TasInput

+ 5 - 0
src/yuzu/configuration/config.cpp

@@ -1205,6 +1205,11 @@ void Config::SaveControlValues() {
     WriteBasicSetting(Settings::values.emulate_analog_keyboard);
     WriteBasicSetting(Settings::values.mouse_panning_sensitivity);
 
+    WriteSetting(QStringLiteral("enable_tas"), Settings::values.tas_enable, false);
+    WriteSetting(QStringLiteral("loop_tas"), Settings::values.tas_loop, false);
+    WriteSetting(QStringLiteral("swap_tas_controllers"), Settings::values.tas_swap_controllers,
+                 true);
+    WriteSetting(QStringLiteral("tas_pause_on_load"), Settings::values.pause_tas_on_load, true);
     qt_config->endGroup();
 }
 

+ 18 - 16
src/yuzu/configuration/configure_input_player_widget.cpp

@@ -175,10 +175,7 @@ void PlayerControlPreview::ResetInputs() {
 }
 
 void PlayerControlPreview::UpdateInput() {
-    if (controller_callback.update != nullptr) {
-        controller_callback.update(std::move(true));
-    }
-    if (!is_enabled && !mapping_active) {
+    if (!is_enabled && !mapping_active && !Settings::values.tas_enable) {
         return;
     }
     bool input_changed = false;
@@ -223,20 +220,25 @@ void PlayerControlPreview::UpdateInput() {
         }
     }
 
-    ControllerInput input{};
     if (input_changed) {
         update();
-        input.changed = true;
-    }
-    input.axis_values[Settings::NativeAnalog::LStick] = {
-        axis_values[Settings::NativeAnalog::LStick].value.x(),
-        axis_values[Settings::NativeAnalog::LStick].value.y()};
-    input.axis_values[Settings::NativeAnalog::RStick] = {
-        axis_values[Settings::NativeAnalog::RStick].value.x(),
-        axis_values[Settings::NativeAnalog::RStick].value.y()};
-    input.button_values = button_values;
-    if (controller_callback.input != nullptr) {
-        controller_callback.input(std::move(input));
+        ControllerInput input{
+            .axis_values =
+                {std::pair<float, float>{axis_values[Settings::NativeAnalog::LStick].value.x(),
+                                         axis_values[Settings::NativeAnalog::LStick].value.y()},
+                 std::pair<float, float>{axis_values[Settings::NativeAnalog::RStick].value.x(),
+                                         axis_values[Settings::NativeAnalog::RStick].value.y()}},
+            .button_values = button_values,
+            .changed = true,
+        };
+
+        if (controller_callback.input != nullptr) {
+            controller_callback.input(std::move(input));
+        }
+    }
+
+    if (controller_callback.update != nullptr) {
+        controller_callback.update(std::move(true));
     }
 
     if (mapping_active) {

+ 0 - 3
src/yuzu/configuration/configure_tas.ui

@@ -31,9 +31,6 @@
                 </item>
                 <item row="1" column="0" colspan="4">
                   <widget class="QCheckBox" name="tas_control_swap">
-                    <property name="enabled">
-                      <bool>false</bool>
-                    </property>
                     <property name="text">
                       <string>Automatic controller profile swapping</string>
                     </property>

+ 1 - 1
src/yuzu/main.cpp

@@ -2921,7 +2921,7 @@ QString GMainWindow::GetTasStateDescription() const {
     case TasInput::TasState::Stopped:
         return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames);
     default:
-        return tr("INVALID TAS STATE");
+        return tr("TAS State: Invalid");
     }
 }