summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/fs/path_util.h2
-rw-r--r--src/input_common/main.h20
-rw-r--r--src/input_common/tas/tas_input.cpp63
-rw-r--r--src/input_common/tas/tas_input.h9
-rw-r--r--src/yuzu/configuration/config.cpp5
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp34
-rw-r--r--src/yuzu/configuration/configure_tas.ui3
-rw-r--r--src/yuzu/main.cpp2
8 files changed, 99 insertions, 39 deletions
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h
index 52e4670e2..0a9e3a145 100644
--- a/src/common/fs/path_util.h
+++ b/src/common/fs/path_util.h
@@ -23,7 +23,7 @@ enum class YuzuPath {
23 ScreenshotsDir, // Where yuzu screenshots are stored. 23 ScreenshotsDir, // Where yuzu screenshots are stored.
24 SDMCDir, // Where the emulated SDMC is stored. 24 SDMCDir, // Where the emulated SDMC is stored.
25 ShaderDir, // Where shaders are stored. 25 ShaderDir, // Where shaders are stored.
26 TASDir, // Where the current script file is stored. 26 TASDir, // Where TAS scripts are stored.
27}; 27};
28 28
29/** 29/**
diff --git a/src/input_common/main.h b/src/input_common/main.h
index 1d06fc5f5..6390d3f09 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -155,28 +155,28 @@ public:
155 /// Retrieves the underlying udp touch handler. 155 /// Retrieves the underlying udp touch handler.
156 [[nodiscard]] const UDPTouchFactory* GetUDPTouch() const; 156 [[nodiscard]] const UDPTouchFactory* GetUDPTouch() const;
157 157
158 /// Retrieves the underlying GameCube button handler. 158 /// Retrieves the underlying mouse button handler.
159 [[nodiscard]] MouseButtonFactory* GetMouseButtons(); 159 [[nodiscard]] MouseButtonFactory* GetMouseButtons();
160 160
161 /// Retrieves the underlying GameCube button handler. 161 /// Retrieves the underlying mouse button handler.
162 [[nodiscard]] const MouseButtonFactory* GetMouseButtons() const; 162 [[nodiscard]] const MouseButtonFactory* GetMouseButtons() const;
163 163
164 /// Retrieves the underlying udp touch handler. 164 /// Retrieves the underlying mouse analog handler.
165 [[nodiscard]] MouseAnalogFactory* GetMouseAnalogs(); 165 [[nodiscard]] MouseAnalogFactory* GetMouseAnalogs();
166 166
167 /// Retrieves the underlying udp touch handler. 167 /// Retrieves the underlying mouse analog handler.
168 [[nodiscard]] const MouseAnalogFactory* GetMouseAnalogs() const; 168 [[nodiscard]] const MouseAnalogFactory* GetMouseAnalogs() const;
169 169
170 /// Retrieves the underlying udp motion handler. 170 /// Retrieves the underlying mouse motion handler.
171 [[nodiscard]] MouseMotionFactory* GetMouseMotions(); 171 [[nodiscard]] MouseMotionFactory* GetMouseMotions();
172 172
173 /// Retrieves the underlying udp motion handler. 173 /// Retrieves the underlying mouse motion handler.
174 [[nodiscard]] const MouseMotionFactory* GetMouseMotions() const; 174 [[nodiscard]] const MouseMotionFactory* GetMouseMotions() const;
175 175
176 /// Retrieves the underlying udp touch handler. 176 /// Retrieves the underlying mouse touch handler.
177 [[nodiscard]] MouseTouchFactory* GetMouseTouch(); 177 [[nodiscard]] MouseTouchFactory* GetMouseTouch();
178 178
179 /// Retrieves the underlying udp touch handler. 179 /// Retrieves the underlying mouse touch handler.
180 [[nodiscard]] const MouseTouchFactory* GetMouseTouch() const; 180 [[nodiscard]] const MouseTouchFactory* GetMouseTouch() const;
181 181
182 /// Retrieves the underlying tas button handler. 182 /// Retrieves the underlying tas button handler.
@@ -185,10 +185,10 @@ public:
185 /// Retrieves the underlying tas button handler. 185 /// Retrieves the underlying tas button handler.
186 [[nodiscard]] const TasButtonFactory* GetTasButtons() const; 186 [[nodiscard]] const TasButtonFactory* GetTasButtons() const;
187 187
188 /// Retrieves the underlying tas touch handler. 188 /// Retrieves the underlying tas analogs handler.
189 [[nodiscard]] TasAnalogFactory* GetTasAnalogs(); 189 [[nodiscard]] TasAnalogFactory* GetTasAnalogs();
190 190
191 /// Retrieves the underlying tas touch handler. 191 /// Retrieves the underlying tas analogs handler.
192 [[nodiscard]] const TasAnalogFactory* GetTasAnalogs() const; 192 [[nodiscard]] const TasAnalogFactory* GetTasAnalogs() const;
193 193
194 /// Reloads the input devices 194 /// Reloads the input devices
diff --git a/src/input_common/tas/tas_input.cpp b/src/input_common/tas/tas_input.cpp
index eb3327520..aceb13adc 100644
--- a/src/input_common/tas/tas_input.cpp
+++ b/src/input_common/tas/tas_input.cpp
@@ -61,8 +61,8 @@ void Tas::LoadTasFile(size_t player_index) {
61 commands[player_index].clear(); 61 commands[player_index].clear();
62 } 62 }
63 std::string file = 63 std::string file =
64 Common::FS::ReadStringFromFile(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir) + 64 Common::FS::ReadStringFromFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) /
65 "script0-" + std::to_string(player_index + 1) + ".txt", 65 fmt::format("script0-{}.txt", player_index + 1),
66 Common::FS::FileType::BinaryFile); 66 Common::FS::FileType::BinaryFile);
67 std::stringstream command_line(file); 67 std::stringstream command_line(file);
68 std::string line; 68 std::string line;
@@ -102,7 +102,7 @@ void Tas::LoadTasFile(size_t player_index) {
102 LOG_INFO(Input, "TAS file loaded! {} frames", frame_no); 102 LOG_INFO(Input, "TAS file loaded! {} frames", frame_no);
103} 103}
104 104
105void Tas::WriteTasFile(std::string file_name) { 105void Tas::WriteTasFile(std::u8string file_name) {
106 std::string output_text; 106 std::string output_text;
107 for (size_t frame = 0; frame < record_commands.size(); frame++) { 107 for (size_t frame = 0; frame < record_commands.size(); frame++) {
108 if (!output_text.empty()) { 108 if (!output_text.empty()) {
@@ -112,8 +112,8 @@ void Tas::WriteTasFile(std::string file_name) {
112 output_text += std::to_string(frame) + " " + WriteCommandButtons(line.buttons) + " " + 112 output_text += std::to_string(frame) + " " + WriteCommandButtons(line.buttons) + " " +
113 WriteCommandAxis(line.l_axis) + " " + WriteCommandAxis(line.r_axis); 113 WriteCommandAxis(line.l_axis) + " " + WriteCommandAxis(line.r_axis);
114 } 114 }
115 const size_t bytes_written = Common::FS::WriteStringToFile( 115 const auto bytes_written = Common::FS::WriteStringToFile(
116 Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir) + file_name, 116 Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name,
117 Common::FS::FileType::TextFile, output_text); 117 Common::FS::FileType::TextFile, output_text);
118 if (bytes_written == output_text.size()) { 118 if (bytes_written == output_text.size()) {
119 LOG_INFO(Input, "TAS file written to file!"); 119 LOG_INFO(Input, "TAS file written to file!");
@@ -217,6 +217,9 @@ void Tas::UpdateThread() {
217 is_running = Settings::values.tas_loop; 217 is_running = Settings::values.tas_loop;
218 current_command = 0; 218 current_command = 0;
219 tas_data.fill({}); 219 tas_data.fill({});
220 if (!is_running) {
221 SwapToStoredController();
222 }
220 } 223 }
221 } else { 224 } else {
222 tas_data.fill({}); 225 tas_data.fill({});
@@ -290,6 +293,52 @@ std::string Tas::WriteCommandButtons(u32 data) const {
290 293
291void Tas::StartStop() { 294void Tas::StartStop() {
292 is_running = !is_running; 295 is_running = !is_running;
296 if (is_running) {
297 SwapToTasController();
298 } else {
299 SwapToStoredController();
300 }
301}
302
303void Tas::SwapToTasController() {
304 if (!Settings::values.tas_swap_controllers) {
305 return;
306 }
307 auto& players = Settings::values.players.GetValue();
308 for (std::size_t index = 0; index < players.size(); index++) {
309 auto& player = players[index];
310 player_mappings[index] = player;
311
312 // Only swap active controllers
313 if (!player.connected) {
314 continue;
315 }
316
317 auto tas_param = Common::ParamPackage{{"pad", static_cast<u8>(index)}};
318 auto button_mapping = GetButtonMappingForDevice(tas_param);
319 auto analog_mapping = GetAnalogMappingForDevice(tas_param);
320 auto& buttons = player.buttons;
321 auto& analogs = player.analogs;
322
323 for (std::size_t i = 0; i < buttons.size(); ++i) {
324 buttons[i] = button_mapping[static_cast<Settings::NativeButton::Values>(i)].Serialize();
325 }
326 for (std::size_t i = 0; i < analogs.size(); ++i) {
327 analogs[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)].Serialize();
328 }
329 }
330 Settings::values.is_device_reload_pending.store(true);
331}
332
333void Tas::SwapToStoredController() {
334 if (!Settings::values.tas_swap_controllers) {
335 return;
336 }
337 auto& players = Settings::values.players.GetValue();
338 for (std::size_t index = 0; index < players.size(); index++) {
339 players[index] = player_mappings[index];
340 }
341 Settings::values.is_device_reload_pending.store(true);
293} 342}
294 343
295void Tas::Reset() { 344void Tas::Reset() {
@@ -308,9 +357,9 @@ void Tas::SaveRecording(bool overwrite_file) {
308 if (record_commands.empty()) { 357 if (record_commands.empty()) {
309 return; 358 return;
310 } 359 }
311 WriteTasFile("record.txt"); 360 WriteTasFile(u8"record.txt");
312 if (overwrite_file) { 361 if (overwrite_file) {
313 WriteTasFile("script0-1.txt"); 362 WriteTasFile(u8"script0-1.txt");
314 } 363 }
315 needs_reset = true; 364 needs_reset = true;
316 record_commands.clear(); 365 record_commands.clear();
diff --git a/src/input_common/tas/tas_input.h b/src/input_common/tas/tas_input.h
index e0462e858..e1f351251 100644
--- a/src/input_common/tas/tas_input.h
+++ b/src/input_common/tas/tas_input.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/settings_input.h"
10#include "core/frontend/input.h" 11#include "core/frontend/input.h"
11#include "input_common/main.h" 12#include "input_common/main.h"
12 13
@@ -91,7 +92,7 @@ private:
91 }; 92 };
92 void LoadTasFiles(); 93 void LoadTasFiles();
93 void LoadTasFile(size_t player_index); 94 void LoadTasFile(size_t player_index);
94 void WriteTasFile(std::string file_name); 95 void WriteTasFile(std::u8string file_name);
95 TasAnalog ReadCommandAxis(const std::string& line) const; 96 TasAnalog ReadCommandAxis(const std::string& line) const;
96 u32 ReadCommandButtons(const std::string& line) const; 97 u32 ReadCommandButtons(const std::string& line) const;
97 std::string WriteCommandButtons(u32 data) const; 98 std::string WriteCommandButtons(u32 data) const;
@@ -105,6 +106,9 @@ private:
105 std::string DebugInputs(const std::array<TasData, PLAYER_NUMBER>& arr) const; 106 std::string DebugInputs(const std::array<TasData, PLAYER_NUMBER>& arr) const;
106 std::string ButtonsToString(u32 button) const; 107 std::string ButtonsToString(u32 button) const;
107 108
109 void SwapToTasController();
110 void SwapToStoredController();
111
108 size_t script_length{0}; 112 size_t script_length{0};
109 std::array<TasData, PLAYER_NUMBER> tas_data; 113 std::array<TasData, PLAYER_NUMBER> tas_data;
110 bool is_recording{false}; 114 bool is_recording{false};
@@ -114,5 +118,8 @@ private:
114 std::vector<TASCommand> record_commands{}; 118 std::vector<TASCommand> record_commands{};
115 size_t current_command{0}; 119 size_t current_command{0};
116 TASCommand last_input{}; // only used for recording 120 TASCommand last_input{}; // only used for recording
121
122 // Old settings for swapping controllers
123 std::array<Settings::PlayerInput, 10> player_mappings;
117}; 124};
118} // namespace TasInput 125} // namespace TasInput
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 99e318a8f..a0dfa06df 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -1205,6 +1205,11 @@ void Config::SaveControlValues() {
1205 WriteBasicSetting(Settings::values.emulate_analog_keyboard); 1205 WriteBasicSetting(Settings::values.emulate_analog_keyboard);
1206 WriteBasicSetting(Settings::values.mouse_panning_sensitivity); 1206 WriteBasicSetting(Settings::values.mouse_panning_sensitivity);
1207 1207
1208 WriteSetting(QStringLiteral("enable_tas"), Settings::values.tas_enable, false);
1209 WriteSetting(QStringLiteral("loop_tas"), Settings::values.tas_loop, false);
1210 WriteSetting(QStringLiteral("swap_tas_controllers"), Settings::values.tas_swap_controllers,
1211 true);
1212 WriteSetting(QStringLiteral("tas_pause_on_load"), Settings::values.pause_tas_on_load, true);
1208 qt_config->endGroup(); 1213 qt_config->endGroup();
1209} 1214}
1210 1215
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index b905fc73d..ba3720c03 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -175,10 +175,7 @@ void PlayerControlPreview::ResetInputs() {
175} 175}
176 176
177void PlayerControlPreview::UpdateInput() { 177void PlayerControlPreview::UpdateInput() {
178 if (controller_callback.update != nullptr) { 178 if (!is_enabled && !mapping_active && !Settings::values.tas_enable) {
179 controller_callback.update(std::move(true));
180 }
181 if (!is_enabled && !mapping_active) {
182 return; 179 return;
183 } 180 }
184 bool input_changed = false; 181 bool input_changed = false;
@@ -223,20 +220,25 @@ void PlayerControlPreview::UpdateInput() {
223 } 220 }
224 } 221 }
225 222
226 ControllerInput input{};
227 if (input_changed) { 223 if (input_changed) {
228 update(); 224 update();
229 input.changed = true; 225 ControllerInput input{
230 } 226 .axis_values =
231 input.axis_values[Settings::NativeAnalog::LStick] = { 227 {std::pair<float, float>{axis_values[Settings::NativeAnalog::LStick].value.x(),
232 axis_values[Settings::NativeAnalog::LStick].value.x(), 228 axis_values[Settings::NativeAnalog::LStick].value.y()},
233 axis_values[Settings::NativeAnalog::LStick].value.y()}; 229 std::pair<float, float>{axis_values[Settings::NativeAnalog::RStick].value.x(),
234 input.axis_values[Settings::NativeAnalog::RStick] = { 230 axis_values[Settings::NativeAnalog::RStick].value.y()}},
235 axis_values[Settings::NativeAnalog::RStick].value.x(), 231 .button_values = button_values,
236 axis_values[Settings::NativeAnalog::RStick].value.y()}; 232 .changed = true,
237 input.button_values = button_values; 233 };
238 if (controller_callback.input != nullptr) { 234
239 controller_callback.input(std::move(input)); 235 if (controller_callback.input != nullptr) {
236 controller_callback.input(std::move(input));
237 }
238 }
239
240 if (controller_callback.update != nullptr) {
241 controller_callback.update(std::move(true));
240 } 242 }
241 243
242 if (mapping_active) { 244 if (mapping_active) {
diff --git a/src/yuzu/configuration/configure_tas.ui b/src/yuzu/configuration/configure_tas.ui
index 906e073ff..445904d8f 100644
--- a/src/yuzu/configuration/configure_tas.ui
+++ b/src/yuzu/configuration/configure_tas.ui
@@ -31,9 +31,6 @@
31 </item> 31 </item>
32 <item row="1" column="0" colspan="4"> 32 <item row="1" column="0" colspan="4">
33 <widget class="QCheckBox" name="tas_control_swap"> 33 <widget class="QCheckBox" name="tas_control_swap">
34 <property name="enabled">
35 <bool>false</bool>
36 </property>
37 <property name="text"> 34 <property name="text">
38 <string>Automatic controller profile swapping</string> 35 <string>Automatic controller profile swapping</string>
39 </property> 36 </property>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 560de89af..7d12fcca7 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2921,7 +2921,7 @@ QString GMainWindow::GetTasStateDescription() const {
2921 case TasInput::TasState::Stopped: 2921 case TasInput::TasState::Stopped:
2922 return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames); 2922 return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames);
2923 default: 2923 default:
2924 return tr("INVALID TAS STATE"); 2924 return tr("TAS State: Invalid");
2925 } 2925 }
2926} 2926}
2927 2927