diff options
| -rw-r--r-- | src/input_common/main.cpp | 2 | ||||
| -rw-r--r-- | src/input_common/tas/tas_input.cpp | 88 | ||||
| -rw-r--r-- | src/input_common/tas/tas_input.h | 48 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_tas.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_tas.ui | 47 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_vibration.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/debugger/controller.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 21 | ||||
| -rw-r--r-- | src/yuzu/main.h | 2 | ||||
| -rw-r--r-- | src/yuzu/main.ui | 2 |
10 files changed, 148 insertions, 68 deletions
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 3b9906b53..18d7d8817 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -117,7 +117,7 @@ struct InputSubsystem::Impl { | |||
| 117 | Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}}, | 117 | Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}}, |
| 118 | }; | 118 | }; |
| 119 | if (Settings::values.tas_enable) { | 119 | if (Settings::values.tas_enable) { |
| 120 | devices.push_back( | 120 | devices.emplace_back( |
| 121 | Common::ParamPackage{{"display", "TAS Controller"}, {"class", "tas"}}); | 121 | Common::ParamPackage{{"display", "TAS Controller"}, {"class", "tas"}}); |
| 122 | } | 122 | } |
| 123 | #ifdef HAVE_SDL2 | 123 | #ifdef HAVE_SDL2 |
diff --git a/src/input_common/tas/tas_input.cpp b/src/input_common/tas/tas_input.cpp index 877d35088..1598092b6 100644 --- a/src/input_common/tas/tas_input.cpp +++ b/src/input_common/tas/tas_input.cpp | |||
| @@ -40,12 +40,15 @@ constexpr std::array<std::pair<std::string_view, TasButton>, 20> text_to_tas_but | |||
| 40 | 40 | ||
| 41 | Tas::Tas() { | 41 | Tas::Tas() { |
| 42 | if (!Settings::values.tas_enable) { | 42 | if (!Settings::values.tas_enable) { |
| 43 | needs_reset = true; | ||
| 43 | return; | 44 | return; |
| 44 | } | 45 | } |
| 45 | LoadTasFiles(); | 46 | LoadTasFiles(); |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | Tas::~Tas() = default; | 49 | Tas::~Tas() { |
| 50 | Stop(); | ||
| 51 | }; | ||
| 49 | 52 | ||
| 50 | void Tas::LoadTasFiles() { | 53 | void Tas::LoadTasFiles() { |
| 51 | script_length = 0; | 54 | script_length = 0; |
| @@ -184,6 +187,9 @@ std::string Tas::ButtonsToString(u32 button) const { | |||
| 184 | 187 | ||
| 185 | void Tas::UpdateThread() { | 188 | void Tas::UpdateThread() { |
| 186 | if (!Settings::values.tas_enable) { | 189 | if (!Settings::values.tas_enable) { |
| 190 | if (is_running) { | ||
| 191 | Stop(); | ||
| 192 | } | ||
| 187 | return; | 193 | return; |
| 188 | } | 194 | } |
| 189 | 195 | ||
| @@ -196,34 +202,35 @@ void Tas::UpdateThread() { | |||
| 196 | LoadTasFiles(); | 202 | LoadTasFiles(); |
| 197 | LOG_DEBUG(Input, "tas_reset done"); | 203 | LOG_DEBUG(Input, "tas_reset done"); |
| 198 | } | 204 | } |
| 199 | if (is_running) { | 205 | |
| 200 | if (current_command < script_length) { | 206 | if (!is_running) { |
| 201 | LOG_DEBUG(Input, "Playing TAS {}/{}", current_command, script_length); | 207 | tas_data.fill({}); |
| 202 | size_t frame = current_command++; | 208 | return; |
| 203 | for (size_t i = 0; i < commands.size(); i++) { | 209 | } |
| 204 | if (frame < commands[i].size()) { | 210 | if (current_command < script_length) { |
| 205 | TASCommand command = commands[i][frame]; | 211 | LOG_DEBUG(Input, "Playing TAS {}/{}", current_command, script_length); |
| 206 | tas_data[i].buttons = command.buttons; | 212 | size_t frame = current_command++; |
| 207 | auto [l_axis_x, l_axis_y] = command.l_axis; | 213 | for (size_t i = 0; i < commands.size(); i++) { |
| 208 | tas_data[i].axis[0] = l_axis_x; | 214 | if (frame < commands[i].size()) { |
| 209 | tas_data[i].axis[1] = l_axis_y; | 215 | TASCommand command = commands[i][frame]; |
| 210 | auto [r_axis_x, r_axis_y] = command.r_axis; | 216 | tas_data[i].buttons = command.buttons; |
| 211 | tas_data[i].axis[2] = r_axis_x; | 217 | auto [l_axis_x, l_axis_y] = command.l_axis; |
| 212 | tas_data[i].axis[3] = r_axis_y; | 218 | tas_data[i].axis[0] = l_axis_x; |
| 213 | } else { | 219 | tas_data[i].axis[1] = l_axis_y; |
| 214 | tas_data[i] = {}; | 220 | auto [r_axis_x, r_axis_y] = command.r_axis; |
| 215 | } | 221 | tas_data[i].axis[2] = r_axis_x; |
| 216 | } | 222 | tas_data[i].axis[3] = r_axis_y; |
| 217 | } else { | 223 | } else { |
| 218 | is_running = Settings::values.tas_loop.GetValue(); | 224 | tas_data[i] = {}; |
| 219 | current_command = 0; | ||
| 220 | tas_data.fill({}); | ||
| 221 | if (!is_running) { | ||
| 222 | SwapToStoredController(); | ||
| 223 | } | 225 | } |
| 224 | } | 226 | } |
| 225 | } else { | 227 | } else { |
| 228 | is_running = Settings::values.tas_loop.GetValue(); | ||
| 229 | current_command = 0; | ||
| 226 | tas_data.fill({}); | 230 | tas_data.fill({}); |
| 231 | if (!is_running) { | ||
| 232 | SwapToStoredController(); | ||
| 233 | } | ||
| 227 | } | 234 | } |
| 228 | LOG_DEBUG(Input, "TAS inputs: {}", DebugInputs(tas_data)); | 235 | LOG_DEBUG(Input, "TAS inputs: {}", DebugInputs(tas_data)); |
| 229 | } | 236 | } |
| @@ -237,8 +244,8 @@ TasAnalog Tas::ReadCommandAxis(const std::string& line) const { | |||
| 237 | seglist.push_back(segment); | 244 | seglist.push_back(segment); |
| 238 | } | 245 | } |
| 239 | 246 | ||
| 240 | const float x = std::stof(seglist.at(0)) / 32767.f; | 247 | const float x = std::stof(seglist.at(0)) / 32767.0f; |
| 241 | const float y = std::stof(seglist.at(1)) / 32767.f; | 248 | const float y = std::stof(seglist.at(1)) / 32767.0f; |
| 242 | 249 | ||
| 243 | return {x, y}; | 250 | return {x, y}; |
| 244 | } | 251 | } |
| @@ -293,14 +300,22 @@ std::string Tas::WriteCommandButtons(u32 data) const { | |||
| 293 | } | 300 | } |
| 294 | 301 | ||
| 295 | void Tas::StartStop() { | 302 | void Tas::StartStop() { |
| 296 | is_running = !is_running; | 303 | if (!Settings::values.tas_enable) { |
| 304 | return; | ||
| 305 | } | ||
| 297 | if (is_running) { | 306 | if (is_running) { |
| 298 | SwapToTasController(); | 307 | Stop(); |
| 299 | } else { | 308 | } else { |
| 300 | SwapToStoredController(); | 309 | is_running = true; |
| 310 | SwapToTasController(); | ||
| 301 | } | 311 | } |
| 302 | } | 312 | } |
| 303 | 313 | ||
| 314 | void Tas::Stop() { | ||
| 315 | is_running = false; | ||
| 316 | SwapToStoredController(); | ||
| 317 | } | ||
| 318 | |||
| 304 | void Tas::SwapToTasController() { | 319 | void Tas::SwapToTasController() { |
| 305 | if (!Settings::values.tas_swap_controllers) { | 320 | if (!Settings::values.tas_swap_controllers) { |
| 306 | return; | 321 | return; |
| @@ -315,7 +330,8 @@ void Tas::SwapToTasController() { | |||
| 315 | continue; | 330 | continue; |
| 316 | } | 331 | } |
| 317 | 332 | ||
| 318 | auto tas_param = Common::ParamPackage{{"pad", static_cast<u8>(index)}}; | 333 | Common::ParamPackage tas_param; |
| 334 | tas_param.Set("pad", static_cast<u8>(index)); | ||
| 319 | auto button_mapping = GetButtonMappingForDevice(tas_param); | 335 | auto button_mapping = GetButtonMappingForDevice(tas_param); |
| 320 | auto analog_mapping = GetAnalogMappingForDevice(tas_param); | 336 | auto analog_mapping = GetAnalogMappingForDevice(tas_param); |
| 321 | auto& buttons = player.buttons; | 337 | auto& buttons = player.buttons; |
| @@ -328,25 +344,33 @@ void Tas::SwapToTasController() { | |||
| 328 | analogs[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)].Serialize(); | 344 | analogs[i] = analog_mapping[static_cast<Settings::NativeAnalog::Values>(i)].Serialize(); |
| 329 | } | 345 | } |
| 330 | } | 346 | } |
| 347 | is_old_input_saved = true; | ||
| 331 | Settings::values.is_device_reload_pending.store(true); | 348 | Settings::values.is_device_reload_pending.store(true); |
| 332 | } | 349 | } |
| 333 | 350 | ||
| 334 | void Tas::SwapToStoredController() { | 351 | void Tas::SwapToStoredController() { |
| 335 | if (!Settings::values.tas_swap_controllers) { | 352 | if (!is_old_input_saved) { |
| 336 | return; | 353 | return; |
| 337 | } | 354 | } |
| 338 | auto& players = Settings::values.players.GetValue(); | 355 | auto& players = Settings::values.players.GetValue(); |
| 339 | for (std::size_t index = 0; index < players.size(); index++) { | 356 | for (std::size_t index = 0; index < players.size(); index++) { |
| 340 | players[index] = player_mappings[index]; | 357 | players[index] = player_mappings[index]; |
| 341 | } | 358 | } |
| 359 | is_old_input_saved = false; | ||
| 342 | Settings::values.is_device_reload_pending.store(true); | 360 | Settings::values.is_device_reload_pending.store(true); |
| 343 | } | 361 | } |
| 344 | 362 | ||
| 345 | void Tas::Reset() { | 363 | void Tas::Reset() { |
| 364 | if (!Settings::values.tas_enable) { | ||
| 365 | return; | ||
| 366 | } | ||
| 346 | needs_reset = true; | 367 | needs_reset = true; |
| 347 | } | 368 | } |
| 348 | 369 | ||
| 349 | bool Tas::Record() { | 370 | bool Tas::Record() { |
| 371 | if (!Settings::values.tas_enable) { | ||
| 372 | return true; | ||
| 373 | } | ||
| 350 | is_recording = !is_recording; | 374 | is_recording = !is_recording; |
| 351 | return is_recording; | 375 | return is_recording; |
| 352 | } | 376 | } |
diff --git a/src/input_common/tas/tas_input.h b/src/input_common/tas/tas_input.h index 52d000db4..3e2db8f00 100644 --- a/src/input_common/tas/tas_input.h +++ b/src/input_common/tas/tas_input.h | |||
| @@ -13,8 +13,8 @@ | |||
| 13 | 13 | ||
| 14 | /* | 14 | /* |
| 15 | To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below | 15 | To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below |
| 16 | Emulation -> Configure TAS. The file itself has normal text format and has to be called | 16 | Tools -> Configure TAS. The file itself has normal text format and has to be called script0-1.txt |
| 17 | script0-1.txt for controller 1, script0-2.txt for controller 2 and so forth (with max. 8 players). | 17 | for controller 1, script0-2.txt for controller 2 and so forth (with max. 8 players). |
| 18 | 18 | ||
| 19 | A script file has the same format as TAS-nx uses, so final files will look like this: | 19 | A script file has the same format as TAS-nx uses, so final files will look like this: |
| 20 | 20 | ||
| @@ -56,26 +56,26 @@ enum class TasState { | |||
| 56 | }; | 56 | }; |
| 57 | 57 | ||
| 58 | enum class TasButton : u32 { | 58 | enum class TasButton : u32 { |
| 59 | BUTTON_A = 0x000001, | 59 | BUTTON_A = 1U << 0, |
| 60 | BUTTON_B = 0x000002, | 60 | BUTTON_B = 1U << 1, |
| 61 | BUTTON_X = 0x000004, | 61 | BUTTON_X = 1U << 2, |
| 62 | BUTTON_Y = 0x000008, | 62 | BUTTON_Y = 1U << 3, |
| 63 | STICK_L = 0x000010, | 63 | STICK_L = 1U << 4, |
| 64 | STICK_R = 0x000020, | 64 | STICK_R = 1U << 5, |
| 65 | TRIGGER_L = 0x000040, | 65 | TRIGGER_L = 1U << 6, |
| 66 | TRIGGER_R = 0x000080, | 66 | TRIGGER_R = 1U << 7, |
| 67 | TRIGGER_ZL = 0x000100, | 67 | TRIGGER_ZL = 1U << 8, |
| 68 | TRIGGER_ZR = 0x000200, | 68 | TRIGGER_ZR = 1U << 9, |
| 69 | BUTTON_PLUS = 0x000400, | 69 | BUTTON_PLUS = 1U << 10, |
| 70 | BUTTON_MINUS = 0x000800, | 70 | BUTTON_MINUS = 1U << 11, |
| 71 | BUTTON_LEFT = 0x001000, | 71 | BUTTON_LEFT = 1U << 12, |
| 72 | BUTTON_UP = 0x002000, | 72 | BUTTON_UP = 1U << 13, |
| 73 | BUTTON_RIGHT = 0x004000, | 73 | BUTTON_RIGHT = 1U << 14, |
| 74 | BUTTON_DOWN = 0x008000, | 74 | BUTTON_DOWN = 1U << 15, |
| 75 | BUTTON_SL = 0x010000, | 75 | BUTTON_SL = 1U << 16, |
| 76 | BUTTON_SR = 0x020000, | 76 | BUTTON_SR = 1U << 17, |
| 77 | BUTTON_HOME = 0x040000, | 77 | BUTTON_HOME = 1U << 18, |
| 78 | BUTTON_CAPTURE = 0x080000, | 78 | BUTTON_CAPTURE = 1U << 19, |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | enum class TasAxes : u8 { | 81 | enum class TasAxes : u8 { |
| @@ -105,6 +105,9 @@ public: | |||
| 105 | // Sets the flag to start or stop the TAS command excecution and swaps controllers profiles | 105 | // Sets the flag to start or stop the TAS command excecution and swaps controllers profiles |
| 106 | void StartStop(); | 106 | void StartStop(); |
| 107 | 107 | ||
| 108 | // Stop the TAS and reverts any controller profile | ||
| 109 | void Stop(); | ||
| 110 | |||
| 108 | // Sets the flag to reload the file and start from the begining in the next update | 111 | // Sets the flag to reload the file and start from the begining in the next update |
| 109 | void Reset(); | 112 | void Reset(); |
| 110 | 113 | ||
| @@ -219,6 +222,7 @@ private: | |||
| 219 | 222 | ||
| 220 | size_t script_length{0}; | 223 | size_t script_length{0}; |
| 221 | std::array<TasData, PLAYER_NUMBER> tas_data; | 224 | std::array<TasData, PLAYER_NUMBER> tas_data; |
| 225 | bool is_old_input_saved{false}; | ||
| 222 | bool is_recording{false}; | 226 | bool is_recording{false}; |
| 223 | bool is_running{false}; | 227 | bool is_running{false}; |
| 224 | bool needs_reset{false}; | 228 | bool needs_reset{false}; |
diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp index 00d6c1ba5..b666b175a 100644 --- a/src/yuzu/configuration/configure_tas.cpp +++ b/src/yuzu/configuration/configure_tas.cpp | |||
| @@ -55,7 +55,7 @@ void ConfigureTasDialog::SetDirectory(DirectoryTarget target, QLineEdit* edit) { | |||
| 55 | 55 | ||
| 56 | QString str = QFileDialog::getExistingDirectory(this, caption, edit->text()); | 56 | QString str = QFileDialog::getExistingDirectory(this, caption, edit->text()); |
| 57 | 57 | ||
| 58 | if (str.isNull() || str.isEmpty()) { | 58 | if (str.isEmpty()) { |
| 59 | return; | 59 | return; |
| 60 | } | 60 | } |
| 61 | 61 | ||
diff --git a/src/yuzu/configuration/configure_tas.ui b/src/yuzu/configuration/configure_tas.ui index 445904d8f..8a3ecb834 100644 --- a/src/yuzu/configuration/configure_tas.ui +++ b/src/yuzu/configuration/configure_tas.ui | |||
| @@ -19,7 +19,50 @@ | |||
| 19 | <item> | 19 | <item> |
| 20 | <widget class="QGroupBox" name="groupBox"> | 20 | <widget class="QGroupBox" name="groupBox"> |
| 21 | <property name="title"> | 21 | <property name="title"> |
| 22 | <string>TAS Settings</string> | 22 | <string>TAS</string> |
| 23 | </property> | ||
| 24 | <layout class="QGridLayout" name="gridLayout"> | ||
| 25 | <item row="0" column="0" colspan="1"> | ||
| 26 | <widget class="QLabel" name="label_1"> | ||
| 27 | <property name="text"> | ||
| 28 | <string>Reads controller input from scripts in the same format as TAS-nx scripts. For a more detailed explanation please consult the FAQ on the yuzu website.</string> | ||
| 29 | </property> | ||
| 30 | <property name="wordWrap"> | ||
| 31 | <bool>true</bool> | ||
| 32 | </property> | ||
| 33 | </widget> | ||
| 34 | </item> | ||
| 35 | <item row="1" column="0" colspan="1"> | ||
| 36 | <widget class="QLabel" name="label_2"> | ||
| 37 | <property name="text"> | ||
| 38 | <string>To check which hotkeys control the playback/recording, please refer to the Hotkey settings (General -> Hotkeys).</string> | ||
| 39 | </property> | ||
| 40 | <property name="wordWrap"> | ||
| 41 | <bool>true</bool> | ||
| 42 | </property> | ||
| 43 | </widget> | ||
| 44 | </item> | ||
| 45 | <item row="2" column="0" colspan="1"> | ||
| 46 | <widget class="QLabel" name="label_2"> | ||
| 47 | <property name="text"> | ||
| 48 | <string>WARNING: This is an experimental feature. It will not play back scripts frame perfectly with the current, imperfect syncing method.</string> | ||
| 49 | </property> | ||
| 50 | <property name="wordWrap"> | ||
| 51 | <bool>true</bool> | ||
| 52 | </property> | ||
| 53 | </widget> | ||
| 54 | </item> | ||
| 55 | </layout> | ||
| 56 | </widget> | ||
| 57 | </item> | ||
| 58 | </layout> | ||
| 59 | </item> | ||
| 60 | <item> | ||
| 61 | <layout class="QHBoxLayout" name="horizontalLayout"> | ||
| 62 | <item> | ||
| 63 | <widget class="QGroupBox" name="groupBox"> | ||
| 64 | <property name="title"> | ||
| 65 | <string>Settings</string> | ||
| 23 | </property> | 66 | </property> |
| 24 | <layout class="QGridLayout" name="gridLayout"> | 67 | <layout class="QGridLayout" name="gridLayout"> |
| 25 | <item row="0" column="0" colspan="4"> | 68 | <item row="0" column="0" colspan="4"> |
| @@ -63,7 +106,7 @@ | |||
| 63 | <item> | 106 | <item> |
| 64 | <widget class="QGroupBox" name="groupBox"> | 107 | <widget class="QGroupBox" name="groupBox"> |
| 65 | <property name="title"> | 108 | <property name="title"> |
| 66 | <string>TAS Directories</string> | 109 | <string>Script Directory</string> |
| 67 | </property> | 110 | </property> |
| 68 | <layout class="QGridLayout" name="gridLayout"> | 111 | <layout class="QGridLayout" name="gridLayout"> |
| 69 | <item row="0" column="0"> | 112 | <item row="0" column="0"> |
diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp index 9d92c4949..46a0f3025 100644 --- a/src/yuzu/configuration/configure_vibration.cpp +++ b/src/yuzu/configuration/configure_vibration.cpp | |||
| @@ -99,7 +99,7 @@ void ConfigureVibration::SetVibrationDevices(std::size_t player_index) { | |||
| 99 | const auto guid = param.Get("guid", ""); | 99 | const auto guid = param.Get("guid", ""); |
| 100 | const auto port = param.Get("port", ""); | 100 | const auto port = param.Get("port", ""); |
| 101 | 101 | ||
| 102 | if (engine.empty() || engine == "keyboard" || engine == "mouse") { | 102 | if (engine.empty() || engine == "keyboard" || engine == "mouse" || engine == "tas") { |
| 103 | continue; | 103 | continue; |
| 104 | } | 104 | } |
| 105 | 105 | ||
diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp index 296000ed5..5a844409b 100644 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp | |||
| @@ -78,7 +78,7 @@ void ControllerDialog::InputController(ControllerInput input) { | |||
| 78 | u32 buttons = 0; | 78 | u32 buttons = 0; |
| 79 | int index = 0; | 79 | int index = 0; |
| 80 | for (bool btn : input.button_values) { | 80 | for (bool btn : input.button_values) { |
| 81 | buttons += (btn ? 1 : 0) << index; | 81 | buttons |= (btn ? 1U : 0U) << index; |
| 82 | index++; | 82 | index++; |
| 83 | } | 83 | } |
| 84 | input_subsystem->GetTas()->RecordInput(buttons, input.axis_values); | 84 | input_subsystem->GetTas()->RecordInput(buttons, input.axis_values); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index ea77caad5..3c2824362 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1022,18 +1022,25 @@ void GMainWindow::InitializeHotkeys() { | |||
| 1022 | } | 1022 | } |
| 1023 | }); | 1023 | }); |
| 1024 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Start/Stop"), this), | 1024 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Start/Stop"), this), |
| 1025 | &QShortcut::activated, this, [&] { input_subsystem->GetTas()->StartStop(); }); | 1025 | &QShortcut::activated, this, [&] { |
| 1026 | if (!emulation_running) { | ||
| 1027 | return; | ||
| 1028 | } | ||
| 1029 | input_subsystem->GetTas()->StartStop(); | ||
| 1030 | }); | ||
| 1026 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Reset"), this), | 1031 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Reset"), this), |
| 1027 | &QShortcut::activated, this, [&] { input_subsystem->GetTas()->Reset(); }); | 1032 | &QShortcut::activated, this, [&] { input_subsystem->GetTas()->Reset(); }); |
| 1028 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Record"), this), | 1033 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Record"), this), |
| 1029 | &QShortcut::activated, this, [&] { | 1034 | &QShortcut::activated, this, [&] { |
| 1035 | if (!emulation_running) { | ||
| 1036 | return; | ||
| 1037 | } | ||
| 1030 | bool is_recording = input_subsystem->GetTas()->Record(); | 1038 | bool is_recording = input_subsystem->GetTas()->Record(); |
| 1031 | if (!is_recording) { | 1039 | if (!is_recording) { |
| 1032 | QMessageBox::StandardButton reply; | 1040 | const auto res = QMessageBox::question(this, tr("TAS Recording"), |
| 1033 | reply = QMessageBox::question(this, tr("TAS Recording"), | 1041 | tr("Overwrite file of player 1?"), |
| 1034 | tr("Overwrite file of player 1?"), | 1042 | QMessageBox::Yes | QMessageBox::No); |
| 1035 | QMessageBox::Yes | QMessageBox::No); | 1043 | input_subsystem->GetTas()->SaveRecording(res == QMessageBox::Yes); |
| 1036 | input_subsystem->GetTas()->SaveRecording(reply == QMessageBox::Yes); | ||
| 1037 | } | 1044 | } |
| 1038 | }); | 1045 | }); |
| 1039 | } | 1046 | } |
| @@ -1487,6 +1494,8 @@ void GMainWindow::ShutdownGame() { | |||
| 1487 | game_list->show(); | 1494 | game_list->show(); |
| 1488 | } | 1495 | } |
| 1489 | game_list->SetFilterFocus(); | 1496 | game_list->SetFilterFocus(); |
| 1497 | tas_label->clear(); | ||
| 1498 | input_subsystem->GetTas()->Stop(); | ||
| 1490 | 1499 | ||
| 1491 | render_window->removeEventFilter(render_window); | 1500 | render_window->removeEventFilter(render_window); |
| 1492 | render_window->setAttribute(Qt::WA_Hover, false); | 1501 | render_window->setAttribute(Qt::WA_Hover, false); |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 610b59ee5..36eed6103 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -320,7 +320,7 @@ private: | |||
| 320 | QLabel* emu_speed_label = nullptr; | 320 | QLabel* emu_speed_label = nullptr; |
| 321 | QLabel* game_fps_label = nullptr; | 321 | QLabel* game_fps_label = nullptr; |
| 322 | QLabel* emu_frametime_label = nullptr; | 322 | QLabel* emu_frametime_label = nullptr; |
| 323 | QLabel* TASlabel; | 323 | QLabel* tas_label = nullptr; |
| 324 | QPushButton* gpu_accuracy_button = nullptr; | 324 | QPushButton* gpu_accuracy_button = nullptr; |
| 325 | QPushButton* renderer_status_button = nullptr; | 325 | QPushButton* renderer_status_button = nullptr; |
| 326 | QPushButton* dock_status_button = nullptr; | 326 | QPushButton* dock_status_button = nullptr; |
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 31c1a20f3..653c010d8 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui | |||
| @@ -72,7 +72,6 @@ | |||
| 72 | <addaction name="action_Restart"/> | 72 | <addaction name="action_Restart"/> |
| 73 | <addaction name="separator"/> | 73 | <addaction name="separator"/> |
| 74 | <addaction name="action_Configure"/> | 74 | <addaction name="action_Configure"/> |
| 75 | <addaction name="action_Configure_Tas"/> | ||
| 76 | <addaction name="action_Configure_Current_Game"/> | 75 | <addaction name="action_Configure_Current_Game"/> |
| 77 | </widget> | 76 | </widget> |
| 78 | <widget class="QMenu" name="menu_View"> | 77 | <widget class="QMenu" name="menu_View"> |
| @@ -101,6 +100,7 @@ | |||
| 101 | <addaction name="action_Rederive"/> | 100 | <addaction name="action_Rederive"/> |
| 102 | <addaction name="separator"/> | 101 | <addaction name="separator"/> |
| 103 | <addaction name="action_Capture_Screenshot"/> | 102 | <addaction name="action_Capture_Screenshot"/> |
| 103 | <addaction name="action_Configure_Tas"/> | ||
| 104 | </widget> | 104 | </widget> |
| 105 | <widget class="QMenu" name="menu_Help"> | 105 | <widget class="QMenu" name="menu_Help"> |
| 106 | <property name="title"> | 106 | <property name="title"> |