summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/fs/fs_paths.h2
-rw-r--r--src/common/fs/path_util.cpp2
-rw-r--r--src/common/fs/path_util.h3
-rw-r--r--src/core/hle/service/apm/apm_interface.cpp2
-rw-r--r--src/input_common/main.cpp6
-rw-r--r--src/input_common/tas/tas_input.cpp189
-rw-r--r--src/input_common/tas/tas_input.h26
-rw-r--r--src/yuzu/CMakeLists.txt3
-rw-r--r--src/yuzu/configuration/configure_filesystem.cpp9
-rw-r--r--src/yuzu/configuration/configure_filesystem.h1
-rw-r--r--src/yuzu/configuration/configure_filesystem.ui49
-rw-r--r--src/yuzu/configuration/configure_input_player_widget.cpp4
-rw-r--r--src/yuzu/configuration/configure_tas.cpp84
-rw-r--r--src/yuzu/configuration/configure_tas.h38
-rw-r--r--src/yuzu/configuration/configure_tas.ui143
-rw-r--r--src/yuzu/debugger/controller.h1
-rw-r--r--src/yuzu/main.cpp67
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu/main.ui6
19 files changed, 452 insertions, 184 deletions
diff --git a/src/common/fs/fs_paths.h b/src/common/fs/fs_paths.h
index 84968b8e0..5d447f108 100644
--- a/src/common/fs/fs_paths.h
+++ b/src/common/fs/fs_paths.h
@@ -21,7 +21,7 @@
21#define SCREENSHOTS_DIR "screenshots" 21#define SCREENSHOTS_DIR "screenshots"
22#define SDMC_DIR "sdmc" 22#define SDMC_DIR "sdmc"
23#define SHADER_DIR "shader" 23#define SHADER_DIR "shader"
24#define TAS_DIR "scripts" 24#define TAS_DIR "tas"
25 25
26// yuzu-specific files 26// yuzu-specific files
27 27
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp
index 97d026eb8..43b79bd6d 100644
--- a/src/common/fs/path_util.cpp
+++ b/src/common/fs/path_util.cpp
@@ -116,7 +116,7 @@ private:
116 GenerateYuzuPath(YuzuPath::ScreenshotsDir, yuzu_path / SCREENSHOTS_DIR); 116 GenerateYuzuPath(YuzuPath::ScreenshotsDir, yuzu_path / SCREENSHOTS_DIR);
117 GenerateYuzuPath(YuzuPath::SDMCDir, yuzu_path / SDMC_DIR); 117 GenerateYuzuPath(YuzuPath::SDMCDir, yuzu_path / SDMC_DIR);
118 GenerateYuzuPath(YuzuPath::ShaderDir, yuzu_path / SHADER_DIR); 118 GenerateYuzuPath(YuzuPath::ShaderDir, yuzu_path / SHADER_DIR);
119 GenerateYuzuPath(YuzuPath::TASFile, yuzu_path / TAS_DIR); 119 GenerateYuzuPath(YuzuPath::TASDir, yuzu_path / TAS_DIR);
120 } 120 }
121 121
122 ~PathManagerImpl() = default; 122 ~PathManagerImpl() = default;
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h
index 6079de4c6..52e4670e2 100644
--- a/src/common/fs/path_util.h
+++ b/src/common/fs/path_util.h
@@ -23,8 +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 26 TASDir, // Where the current script file is stored.
27 TASFile, // Where the current script file is stored.
28}; 27};
29 28
30/** 29/**
diff --git a/src/core/hle/service/apm/apm_interface.cpp b/src/core/hle/service/apm/apm_interface.cpp
index 724483107..520ccfa88 100644
--- a/src/core/hle/service/apm/apm_interface.cpp
+++ b/src/core/hle/service/apm/apm_interface.cpp
@@ -121,7 +121,7 @@ void APM_Sys::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
121 121
122 LOG_DEBUG(Service_APM, "called, mode={:08X}", mode); 122 LOG_DEBUG(Service_APM, "called, mode={:08X}", mode);
123 123
124 Settings::values.is_cpu_boosted = (static_cast<u32>(mode) == 1); 124 Settings::values.is_cpu_boosted = (mode == CpuBoostMode::Full);
125 controller.SetFromCpuBoostMode(mode); 125 controller.SetFromCpuBoostMode(mode);
126 126
127 IPC::ResponseBuilder rb{ctx, 2}; 127 IPC::ResponseBuilder rb{ctx, 2};
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 @@
5#include <memory> 5#include <memory>
6#include <thread> 6#include <thread>
7#include "common/param_package.h" 7#include "common/param_package.h"
8#include "common/settings.h"
8#include "input_common/analog_from_button.h" 9#include "input_common/analog_from_button.h"
9#include "input_common/gcadapter/gc_adapter.h" 10#include "input_common/gcadapter/gc_adapter.h"
10#include "input_common/gcadapter/gc_poller.h" 11#include "input_common/gcadapter/gc_poller.h"
@@ -114,8 +115,11 @@ struct InputSubsystem::Impl {
114 std::vector<Common::ParamPackage> devices = { 115 std::vector<Common::ParamPackage> devices = {
115 Common::ParamPackage{{"display", "Any"}, {"class", "any"}}, 116 Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
116 Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}}, 117 Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}},
117 Common::ParamPackage{{"display", "TAS"}, {"class", "tas"}},
118 }; 118 };
119 if (Settings::values.tas_enable) {
120 devices.push_back(
121 Common::ParamPackage{{"display", "TAS Controller"}, {"class", "tas"}});
122 }
119#ifdef HAVE_SDL2 123#ifdef HAVE_SDL2
120 auto sdl_devices = sdl->GetInputDevices(); 124 auto sdl_devices = sdl->GetInputDevices();
121 devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); 125 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) {
67 if (!commands[player_index].empty()) { 67 if (!commands[player_index].empty()) {
68 commands[player_index].clear(); 68 commands[player_index].clear();
69 } 69 }
70 std::string file = Common::FS::ReadStringFromFile( 70 std::string file =
71 Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASFile) + "script0-" + 71 Common::FS::ReadStringFromFile(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir) +
72 std::to_string(player_index + 1) + ".txt", 72 "script0-" + std::to_string(player_index + 1) + ".txt",
73 Common::FS::FileType::BinaryFile); 73 Common::FS::FileType::BinaryFile);
74 std::stringstream command_line(file); 74 std::stringstream command_line(file);
75 std::string line; 75 std::string line;
76 int frameNo = 0; 76 int frame_no = 0;
77 TASCommand empty = {.buttons = 0, .l_axis = {0.f, 0.f}, .r_axis = {0.f, 0.f}};
78 while (std::getline(command_line, line, '\n')) { 77 while (std::getline(command_line, line, '\n')) {
79 if (line.empty()) { 78 if (line.empty()) {
80 continue; 79 continue;
@@ -94,9 +93,9 @@ void Tas::LoadTasFile(size_t player_index) {
94 continue; 93 continue;
95 } 94 }
96 95
97 while (frameNo < std::stoi(seglist.at(0))) { 96 while (frame_no < std::stoi(seglist.at(0))) {
98 commands[player_index].push_back(empty); 97 commands[player_index].push_back({});
99 frameNo++; 98 frame_no++;
100 } 99 }
101 100
102 TASCommand command = { 101 TASCommand command = {
@@ -105,30 +104,29 @@ void Tas::LoadTasFile(size_t player_index) {
105 .r_axis = ReadCommandAxis(seglist.at(3)), 104 .r_axis = ReadCommandAxis(seglist.at(3)),
106 }; 105 };
107 commands[player_index].push_back(command); 106 commands[player_index].push_back(command);
108 frameNo++; 107 frame_no++;
109 } 108 }
110 LOG_INFO(Input, "TAS file loaded! {} frames", frameNo); 109 LOG_INFO(Input, "TAS file loaded! {} frames", frame_no);
111} 110}
112 111
113void Tas::WriteTasFile() { 112void Tas::WriteTasFile() {
114 LOG_DEBUG(Input, "WriteTasFile()"); 113 LOG_DEBUG(Input, "WriteTasFile()");
115 std::string output_text = ""; 114 std::string output_text;
116 for (int frame = 0; frame < (signed)record_commands.size(); frame++) { 115 for (size_t frame = 0; frame < record_commands.size(); frame++) {
117 if (!output_text.empty()) { 116 if (!output_text.empty()) {
118 output_text += "\n"; 117 output_text += "\n";
119 } 118 }
120 TASCommand line = record_commands.at(frame); 119 const TASCommand& line = record_commands[frame];
121 output_text += std::to_string(frame) + " " + WriteCommandButtons(line.buttons) + " " + 120 output_text += std::to_string(frame) + " " + WriteCommandButtons(line.buttons) + " " +
122 WriteCommandAxis(line.l_axis) + " " + WriteCommandAxis(line.r_axis); 121 WriteCommandAxis(line.l_axis) + " " + WriteCommandAxis(line.r_axis);
123 } 122 }
124 size_t bytesWritten = Common::FS::WriteStringToFile( 123 const size_t bytes_written = Common::FS::WriteStringToFile(
125 Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASFile) + "record.txt", 124 Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir) + "record.txt",
126 Common::FS::FileType::TextFile, output_text); 125 Common::FS::FileType::TextFile, output_text);
127 if (bytesWritten == output_text.size()) { 126 if (bytes_written == output_text.size()) {
128 LOG_INFO(Input, "TAS file written to file!"); 127 LOG_INFO(Input, "TAS file written to file!");
129 } 128 } else {
130 else { 129 LOG_ERROR(Input, "Writing the TAS-file has failed! {} / {} bytes written", bytes_written,
131 LOG_ERROR(Input, "Writing the TAS-file has failed! {} / {} bytes written", bytesWritten,
132 output_text.size()); 130 output_text.size());
133 } 131 }
134} 132}
@@ -142,30 +140,33 @@ void Tas::RecordInput(u32 buttons, const std::array<std::pair<float, float>, 2>&
142 last_input = {buttons, FlipY(axes[0]), FlipY(axes[1])}; 140 last_input = {buttons, FlipY(axes[0]), FlipY(axes[1])};
143} 141}
144 142
145std::tuple<TasState, size_t, size_t> Tas::GetStatus() { 143std::tuple<TasState, size_t, size_t> Tas::GetStatus() const {
146 TasState state; 144 TasState state;
147 if (Settings::values.tas_record) { 145 if (is_recording) {
148 return {TasState::RECORDING, record_commands.size(), record_commands.size()}; 146 return {TasState::Recording, 0, record_commands.size()};
149 } else if (Settings::values.tas_enable) { 147 }
150 state = TasState::RUNNING; 148
149 if (is_running) {
150 state = TasState::Running;
151 } else { 151 } else {
152 state = TasState::STOPPED; 152 state = TasState::Stopped;
153 } 153 }
154 154
155 return {state, current_command, script_length}; 155 return {state, current_command, script_length};
156} 156}
157 157
158static std::string DebugButtons(u32 buttons) { 158static std::string DebugButtons(u32 buttons) {
159 return "{ " + TasInput::Tas::ButtonsToString(buttons) + " }"; 159 return fmt::format("{{ {} }}", TasInput::Tas::ButtonsToString(buttons));
160} 160}
161 161
162static std::string DebugJoystick(float x, float y) { 162static std::string DebugJoystick(float x, float y) {
163 return "[ " + std::to_string(x) + "," + std::to_string(y) + " ]"; 163 return fmt::format("[ {} , {} ]", std::to_string(x), std::to_string(y));
164} 164}
165 165
166static std::string DebugInput(const TasData& data) { 166static std::string DebugInput(const TasData& data) {
167 return "{ " + DebugButtons(data.buttons) + " , " + DebugJoystick(data.axis[0], data.axis[1]) + 167 return fmt::format("{{ {} , {} , {} }}", DebugButtons(data.buttons),
168 " , " + DebugJoystick(data.axis[2], data.axis[3]) + " }"; 168 DebugJoystick(data.axis[0], data.axis[1]),
169 DebugJoystick(data.axis[2], data.axis[3]));
169} 170}
170 171
171static std::string DebugInputs(const std::array<TasData, PLAYER_NUMBER>& arr) { 172static std::string DebugInputs(const std::array<TasData, PLAYER_NUMBER>& arr) {
@@ -180,66 +181,54 @@ static std::string DebugInputs(const std::array<TasData, PLAYER_NUMBER>& arr) {
180} 181}
181 182
182void Tas::UpdateThread() { 183void Tas::UpdateThread() {
183 if (update_thread_running) { 184 if (!update_thread_running) {
184 if (Settings::values.pause_tas_on_load && Settings::values.is_cpu_boosted) { 185 return;
185 for (size_t i = 0; i < PLAYER_NUMBER; i++) { 186 }
186 tas_data[i].buttons = 0;
187 tas_data[i].axis = {};
188 }
189 }
190 187
191 if (Settings::values.tas_record) { 188 if (is_recording) {
192 record_commands.push_back(last_input); 189 record_commands.push_back(last_input);
193 } 190 }
194 if (!Settings::values.tas_record && !record_commands.empty()) { 191 if (!is_recording && !record_commands.empty()) {
195 WriteTasFile(); 192 WriteTasFile();
196 Settings::values.tas_reset = true; 193 needs_reset = true;
197 refresh_tas_fle = true; 194 refresh_tas_fle = true;
198 record_commands.clear(); 195 record_commands.clear();
199 } 196 }
200 if (Settings::values.tas_reset) { 197 if (needs_reset) {
201 current_command = 0; 198 current_command = 0;
202 if (refresh_tas_fle) { 199 if (refresh_tas_fle) {
203 LoadTasFiles();
204 refresh_tas_fle = false;
205 }
206 Settings::values.tas_reset = false;
207 LoadTasFiles(); 200 LoadTasFiles();
208 LOG_DEBUG(Input, "tas_reset done"); 201 refresh_tas_fle = false;
209 } 202 }
210 if (Settings::values.tas_enable) { 203 needs_reset = false;
211 if ((signed)current_command < script_length) { 204 LoadTasFiles();
212 LOG_INFO(Input, "Playing TAS {}/{}", current_command, script_length); 205 LOG_DEBUG(Input, "tas_reset done");
213 size_t frame = current_command++; 206 }
214 for (size_t i = 0; i < PLAYER_NUMBER; i++) { 207 if (is_running) {
215 if (frame < commands[i].size()) { 208 if (current_command < script_length) {
216 TASCommand command = commands[i][frame]; 209 LOG_INFO(Input, "Playing TAS {}/{}", current_command, script_length);
217 tas_data[i].buttons = command.buttons; 210 size_t frame = current_command++;
218 auto [l_axis_x, l_axis_y] = command.l_axis; 211 for (size_t i = 0; i < PLAYER_NUMBER; i++) {
219 tas_data[i].axis[0] = l_axis_x; 212 if (frame < commands[i].size()) {
220 tas_data[i].axis[1] = l_axis_y; 213 TASCommand command = commands[i][frame];
221 auto [r_axis_x, r_axis_y] = command.r_axis; 214 tas_data[i].buttons = command.buttons;
222 tas_data[i].axis[2] = r_axis_x; 215 auto [l_axis_x, l_axis_y] = command.l_axis;
223 tas_data[i].axis[3] = r_axis_y; 216 tas_data[i].axis[0] = l_axis_x;
224 } else { 217 tas_data[i].axis[1] = l_axis_y;
225 tas_data[i].buttons = 0; 218 auto [r_axis_x, r_axis_y] = command.r_axis;
226 tas_data[i].axis = {}; 219 tas_data[i].axis[2] = r_axis_x;
227 } 220 tas_data[i].axis[3] = r_axis_y;
228 } 221 } else {
229 } else { 222 tas_data[i] = {};
230 Settings::values.tas_enable = false;
231 current_command = 0;
232 for (size_t i = 0; i < PLAYER_NUMBER; i++) {
233 tas_data[i].buttons = 0;
234 tas_data[i].axis = {};
235 } 223 }
236 } 224 }
237 } else { 225 } else {
238 for (size_t i = 0; i < PLAYER_NUMBER; i++) { 226 is_running = Settings::values.tas_loop;
239 tas_data[i].buttons = 0; 227 current_command = 0;
240 tas_data[i].axis = {}; 228 tas_data.fill({});
241 }
242 } 229 }
230 } else {
231 tas_data.fill({});
243 } 232 }
244 LOG_DEBUG(Input, "TAS inputs: {}", DebugInputs(tas_data)); 233 LOG_DEBUG(Input, "TAS inputs: {}", DebugInputs(tas_data));
245} 234}
@@ -284,8 +273,9 @@ std::string Tas::WriteCommandAxis(TasAnalog data) const {
284} 273}
285 274
286std::string Tas::WriteCommandButtons(u32 data) const { 275std::string Tas::WriteCommandButtons(u32 data) const {
287 if (data == 0) 276 if (data == 0) {
288 return "NONE"; 277 return "NONE";
278 }
289 279
290 std::string line; 280 std::string line;
291 u32 index = 0; 281 u32 index = 0;
@@ -307,6 +297,37 @@ std::string Tas::WriteCommandButtons(u32 data) const {
307 return line; 297 return line;
308} 298}
309 299
300void Tas::StartStop() {
301 is_running = !is_running;
302}
303
304void Tas::Reset() {
305 needs_reset = true;
306}
307
308void Tas::Record() {
309 is_recording = !is_recording;
310<<<<<<< HEAD
311=======
312 return is_recording;
313}
314
315void Tas::SaveRecording(bool overwrite_file) {
316 if (is_recording) {
317 return;
318 }
319 if (record_commands.empty()) {
320 return;
321 }
322 WriteTasFile("record.txt");
323 if (overwrite_file) {
324 WriteTasFile("script0-1.txt");
325 }
326 needs_reset = true;
327 record_commands.clear();
328>>>>>>> 773d268db (config: disable pause on load)
329}
330
310InputCommon::ButtonMapping Tas::GetButtonMappingForDevice( 331InputCommon::ButtonMapping Tas::GetButtonMappingForDevice(
311 const Common::ParamPackage& params) const { 332 const Common::ParamPackage& params) const {
312 // This list is missing ZL/ZR since those are not considered buttons. 333 // 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 @@
14 14
15namespace TasInput { 15namespace TasInput {
16 16
17constexpr int PLAYER_NUMBER = 8; 17constexpr size_t PLAYER_NUMBER = 8;
18 18
19using TasAnalog = std::pair<float, float>; 19using TasAnalog = std::pair<float, float>;
20 20
21enum class TasState { 21enum class TasState {
22 RUNNING, 22 Running,
23 RECORDING, 23 Recording,
24 STOPPED, 24 Stopped,
25}; 25};
26 26
27enum class TasButton : u32 { 27enum class TasButton : u32 {
@@ -114,8 +114,19 @@ public:
114 void LoadTasFiles(); 114 void LoadTasFiles();
115 void RecordInput(u32 buttons, const std::array<std::pair<float, float>, 2>& axes); 115 void RecordInput(u32 buttons, const std::array<std::pair<float, float>, 2>& axes);
116 void UpdateThread(); 116 void UpdateThread();
117 std::tuple<TasState, size_t, size_t> GetStatus();
118 117
118 void StartStop();
119 void Reset();
120 void Record();
121
122 /**
123 * Returns the current status values of TAS playback/recording
124 * @return Tuple of
125 * TasState indicating the current state out of Running, Recording or Stopped ;
126 * Current playback progress or amount of frames (so far) for Recording ;
127 * Total length of script file currently loaded or amount of frames (so far) for Recording
128 */
129 std::tuple<TasState, size_t, size_t> GetStatus() const;
119 InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const; 130 InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const;
120 InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const; 131 InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const;
121 [[nodiscard]] const TasData& GetTasState(std::size_t pad) const; 132 [[nodiscard]] const TasData& GetTasState(std::size_t pad) const;
@@ -137,9 +148,12 @@ private:
137 std::array<TasData, PLAYER_NUMBER> tas_data; 148 std::array<TasData, PLAYER_NUMBER> tas_data;
138 bool update_thread_running{true}; 149 bool update_thread_running{true};
139 bool refresh_tas_fle{false}; 150 bool refresh_tas_fle{false};
151 bool is_recording{false};
152 bool is_running{false};
153 bool needs_reset{false};
140 std::array<std::vector<TASCommand>, PLAYER_NUMBER> commands{}; 154 std::array<std::vector<TASCommand>, PLAYER_NUMBER> commands{};
141 std::vector<TASCommand> record_commands{}; 155 std::vector<TASCommand> record_commands{};
142 std::size_t current_command{0}; 156 size_t current_command{0};
143 TASCommand last_input{}; // only used for recording 157 TASCommand last_input{}; // only used for recording
144}; 158};
145} // namespace TasInput 159} // namespace TasInput
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 19ba0dbba..b6dda283d 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -108,6 +108,9 @@ add_executable(yuzu
108 configuration/configure_system.cpp 108 configuration/configure_system.cpp
109 configuration/configure_system.h 109 configuration/configure_system.h
110 configuration/configure_system.ui 110 configuration/configure_system.ui
111 configuration/configure_tas.cpp
112 configuration/configure_tas.h
113 configuration/configure_tas.ui
111 configuration/configure_touch_from_button.cpp 114 configuration/configure_touch_from_button.cpp
112 configuration/configure_touch_from_button.h 115 configuration/configure_touch_from_button.h
113 configuration/configure_touch_from_button.ui 116 configuration/configure_touch_from_button.ui
diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp
index 4636d476e..013de02db 100644
--- a/src/yuzu/configuration/configure_filesystem.cpp
+++ b/src/yuzu/configuration/configure_filesystem.cpp
@@ -26,8 +26,6 @@ ConfigureFilesystem::ConfigureFilesystem(QWidget* parent)
26 [this] { SetDirectory(DirectoryTarget::Dump, ui->dump_path_edit); }); 26 [this] { SetDirectory(DirectoryTarget::Dump, ui->dump_path_edit); });
27 connect(ui->load_path_button, &QToolButton::pressed, this, 27 connect(ui->load_path_button, &QToolButton::pressed, this,
28 [this] { SetDirectory(DirectoryTarget::Load, ui->load_path_edit); }); 28 [this] { SetDirectory(DirectoryTarget::Load, ui->load_path_edit); });
29 connect(ui->tas_path_button, &QToolButton::pressed, this,
30 [this] { SetDirectory(DirectoryTarget::TAS, ui->tas_path_edit); });
31 29
32 connect(ui->reset_game_list_cache, &QPushButton::pressed, this, 30 connect(ui->reset_game_list_cache, &QPushButton::pressed, this,
33 &ConfigureFilesystem::ResetMetadata); 31 &ConfigureFilesystem::ResetMetadata);
@@ -51,8 +49,6 @@ void ConfigureFilesystem::setConfiguration() {
51 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::DumpDir))); 49 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::DumpDir)));
52 ui->load_path_edit->setText( 50 ui->load_path_edit->setText(
53 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LoadDir))); 51 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::LoadDir)));
54 ui->tas_path_edit->setText(
55 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASFile)));
56 52
57 ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted.GetValue()); 53 ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted.GetValue());
58 ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game.GetValue()); 54 ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game.GetValue());
@@ -74,11 +70,9 @@ void ConfigureFilesystem::applyConfiguration() {
74 ui->dump_path_edit->text().toStdString()); 70 ui->dump_path_edit->text().toStdString());
75 Common::FS::SetYuzuPath(Common::FS::YuzuPath::LoadDir, 71 Common::FS::SetYuzuPath(Common::FS::YuzuPath::LoadDir,
76 ui->load_path_edit->text().toStdString()); 72 ui->load_path_edit->text().toStdString());
77 Common::FS::SetYuzuPath(Common::FS::YuzuPath::TASFile, ui->tas_path_edit->text().toStdString());
78 73
79 Settings::values.gamecard_inserted = ui->gamecard_inserted->isChecked(); 74 Settings::values.gamecard_inserted = ui->gamecard_inserted->isChecked();
80 Settings::values.gamecard_current_game = ui->gamecard_current_game->isChecked(); 75 Settings::values.gamecard_current_game = ui->gamecard_current_game->isChecked();
81 Settings::values.pause_tas_on_load = ui->tas_pause_on_load->isChecked();
82 Settings::values.dump_exefs = ui->dump_exefs->isChecked(); 76 Settings::values.dump_exefs = ui->dump_exefs->isChecked();
83 Settings::values.dump_nso = ui->dump_nso->isChecked(); 77 Settings::values.dump_nso = ui->dump_nso->isChecked();
84 78
@@ -104,9 +98,6 @@ void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit)
104 case DirectoryTarget::Load: 98 case DirectoryTarget::Load:
105 caption = tr("Select Mod Load Directory..."); 99 caption = tr("Select Mod Load Directory...");
106 break; 100 break;
107 case DirectoryTarget::TAS:
108 caption = tr("Select TAS Directory...");
109 break;
110 } 101 }
111 102
112 QString str; 103 QString str;
diff --git a/src/yuzu/configuration/configure_filesystem.h b/src/yuzu/configuration/configure_filesystem.h
index 86dab8684..2147cd405 100644
--- a/src/yuzu/configuration/configure_filesystem.h
+++ b/src/yuzu/configuration/configure_filesystem.h
@@ -32,7 +32,6 @@ private:
32 Gamecard, 32 Gamecard,
33 Dump, 33 Dump,
34 Load, 34 Load,
35 TAS,
36 }; 35 };
37 36
38 void SetDirectory(DirectoryTarget target, QLineEdit* edit); 37 void SetDirectory(DirectoryTarget target, QLineEdit* edit);
diff --git a/src/yuzu/configuration/configure_filesystem.ui b/src/yuzu/configuration/configure_filesystem.ui
index 8ac7250fd..62b9abc7a 100644
--- a/src/yuzu/configuration/configure_filesystem.ui
+++ b/src/yuzu/configuration/configure_filesystem.ui
@@ -219,55 +219,6 @@
219 </layout> 219 </layout>
220 </widget> 220 </widget>
221 </item> 221 </item>
222 <item>
223 <widget class="QGroupBox" name="groupBox">
224 <property name="title">
225 <string>TAS Directories</string>
226 </property>
227 <layout class="QGridLayout" name="gridLayout">
228 <item row="0" column="0">
229 <widget class="QLabel" name="label">
230 <property name="text">
231 <string>Path</string>
232 </property>
233 </widget>
234 </item>
235 <item row="0" column="3">
236 <widget class="QToolButton" name="tas_path_button">
237 <property name="text">
238 <string>...</string>
239 </property>
240 </widget>
241 </item>
242 <item row="0" column="2">
243 <widget class="QLineEdit" name="tas_path_edit"/>
244 </item>
245 <item row="0" column="1">
246 <spacer name="horizontalSpacer">
247 <property name="orientation">
248 <enum>Qt::Horizontal</enum>
249 </property>
250 <property name="sizeType">
251 <enum>QSizePolicy::Maximum</enum>
252 </property>
253 <property name="sizeHint" stdset="0">
254 <size>
255 <width>60</width>
256 <height>20</height>
257 </size>
258 </property>
259 </spacer>
260 </item>
261 <item row="1" column="0" colspan="4">
262 <widget class="QCheckBox" name="tas_pause_on_load">
263 <property name="text">
264 <string>Pause TAS execution during loads (SMO - 1.3)</string>
265 </property>
266 </widget>
267 </item>
268 </layout>
269 </widget>
270 </item>
271 </layout> 222 </layout>
272 </item> 223 </item>
273 <item> 224 <item>
diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp
index e649e2169..e4383676a 100644
--- a/src/yuzu/configuration/configure_input_player_widget.cpp
+++ b/src/yuzu/configuration/configure_input_player_widget.cpp
@@ -232,7 +232,7 @@ void PlayerControlPreview::UpdateInput() {
232 axis_values[Settings::NativeAnalog::RStick].value.x(), 232 axis_values[Settings::NativeAnalog::RStick].value.x(),
233 axis_values[Settings::NativeAnalog::RStick].value.y()}; 233 axis_values[Settings::NativeAnalog::RStick].value.y()};
234 input.button_values = button_values; 234 input.button_values = button_values;
235 if (controller_callback.input != NULL) { 235 if (controller_callback.input != nullptr) {
236 controller_callback.input(std::move(input)); 236 controller_callback.input(std::move(input));
237 } 237 }
238 238
@@ -242,7 +242,7 @@ void PlayerControlPreview::UpdateInput() {
242} 242}
243 243
244void PlayerControlPreview::SetCallBack(ControllerCallback callback_) { 244void PlayerControlPreview::SetCallBack(ControllerCallback callback_) {
245 controller_callback = callback_; 245 controller_callback = std::move(callback_);
246} 246}
247 247
248void PlayerControlPreview::paintEvent(QPaintEvent* event) { 248void PlayerControlPreview::paintEvent(QPaintEvent* event) {
diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp
new file mode 100644
index 000000000..f2f91d84a
--- /dev/null
+++ b/src/yuzu/configuration/configure_tas.cpp
@@ -0,0 +1,84 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QFileDialog>
6#include <QMessageBox>
7#include "common/fs/fs.h"
8#include "common/fs/path_util.h"
9#include "common/settings.h"
10#include "ui_configure_tas.h"
11#include "yuzu/configuration/configure_tas.h"
12#include "yuzu/uisettings.h"
13
14ConfigureTasDialog::ConfigureTasDialog(QWidget* parent)
15 : QDialog(parent), ui(std::make_unique<Ui::ConfigureTas>()) {
16
17 ui->setupUi(this);
18
19 setFocusPolicy(Qt::ClickFocus);
20 setWindowTitle(tr("TAS Configuration"));
21
22 connect(ui->tas_path_button, &QToolButton::pressed, this,
23 [this] { SetDirectory(DirectoryTarget::TAS, ui->tas_path_edit); });
24
25 LoadConfiguration();
26}
27
28ConfigureTasDialog::~ConfigureTasDialog() = default;
29
30void ConfigureTasDialog::LoadConfiguration() {
31 ui->tas_path_edit->setText(
32 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir)));
33 ui->tas_enable->setChecked(Settings::values.tas_enable);
34 ui->tas_control_swap->setChecked(Settings::values.tas_swap_controllers);
35 ui->tas_loop_script->setChecked(Settings::values.tas_loop);
36 ui->tas_pause_on_load->setChecked(Settings::values.pause_tas_on_load);
37}
38
39void ConfigureTasDialog::ApplyConfiguration() {
40 Common::FS::SetYuzuPath(Common::FS::YuzuPath::TASDir, ui->tas_path_edit->text().toStdString());
41 Settings::values.tas_enable = ui->tas_enable->isChecked();
42 Settings::values.tas_swap_controllers = ui->tas_control_swap->isChecked();
43 Settings::values.tas_loop = ui->tas_loop_script->isChecked();
44 Settings::values.pause_tas_on_load = ui->tas_pause_on_load->isChecked();
45}
46
47void ConfigureTasDialog::SetDirectory(DirectoryTarget target, QLineEdit* edit) {
48 QString caption;
49
50 switch (target) {
51 case DirectoryTarget::TAS:
52 caption = tr("Select TAS Load Directory...");
53 break;
54 }
55
56 QString str = QFileDialog::getExistingDirectory(this, caption, edit->text());
57
58 if (str.isNull() || str.isEmpty()) {
59 return;
60 }
61
62 if (str.back() != QChar::fromLatin1('/')) {
63 str.append(QChar::fromLatin1('/'));
64 }
65
66 edit->setText(str);
67}
68
69void ConfigureTasDialog::changeEvent(QEvent* event) {
70 if (event->type() == QEvent::LanguageChange) {
71 RetranslateUI();
72 }
73
74 QDialog::changeEvent(event);
75}
76
77void ConfigureTasDialog::RetranslateUI() {
78 ui->retranslateUi(this);
79}
80
81void ConfigureTasDialog::HandleApplyButtonClicked() {
82 UISettings::values.configuration_applied = true;
83 ApplyConfiguration();
84}
diff --git a/src/yuzu/configuration/configure_tas.h b/src/yuzu/configuration/configure_tas.h
new file mode 100644
index 000000000..1546bf16f
--- /dev/null
+++ b/src/yuzu/configuration/configure_tas.h
@@ -0,0 +1,38 @@
1// Copyright 2021 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QDialog>
8
9namespace Ui {
10class ConfigureTas;
11}
12
13class ConfigureTasDialog : public QDialog {
14 Q_OBJECT
15
16public:
17 explicit ConfigureTasDialog(QWidget* parent);
18 ~ConfigureTasDialog() override;
19
20 /// Save all button configurations to settings file
21 void ApplyConfiguration();
22
23private:
24 enum class DirectoryTarget {
25 TAS,
26 };
27
28 void LoadConfiguration();
29
30 void SetDirectory(DirectoryTarget target, QLineEdit* edit);
31
32 void changeEvent(QEvent* event) override;
33 void RetranslateUI();
34
35 void HandleApplyButtonClicked();
36
37 std::unique_ptr<Ui::ConfigureTas> ui;
38};
diff --git a/src/yuzu/configuration/configure_tas.ui b/src/yuzu/configuration/configure_tas.ui
new file mode 100644
index 000000000..906e073ff
--- /dev/null
+++ b/src/yuzu/configuration/configure_tas.ui
@@ -0,0 +1,143 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureTas</class>
4 <widget class="QDialog" name="ConfigureTas">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>800</width>
10 <height>300</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Dialog</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_1">
17 <item>
18 <layout class="QHBoxLayout" name="horizontalLayout">
19 <item>
20 <widget class="QGroupBox" name="groupBox">
21 <property name="title">
22 <string>TAS Settings</string>
23 </property>
24 <layout class="QGridLayout" name="gridLayout">
25 <item row="0" column="0" colspan="4">
26 <widget class="QCheckBox" name="tas_enable">
27 <property name="text">
28 <string>Enable TAS features</string>
29 </property>
30 </widget>
31 </item>
32 <item row="1" column="0" colspan="4">
33 <widget class="QCheckBox" name="tas_control_swap">
34 <property name="enabled">
35 <bool>false</bool>
36 </property>
37 <property name="text">
38 <string>Automatic controller profile swapping</string>
39 </property>
40 </widget>
41 </item>
42 <item row="2" column="0" colspan="4">
43 <widget class="QCheckBox" name="tas_loop_script">
44 <property name="text">
45 <string>Loop script</string>
46 </property>
47 </widget>
48 </item>
49 <item row="3" column="0" colspan="4">
50 <widget class="QCheckBox" name="tas_pause_on_load">
51 <property name="enabled">
52 <bool>false</bool>
53 </property>
54 <property name="text">
55 <string>Pause execution during loads</string>
56 </property>
57 </widget>
58 </item>
59 </layout>
60 </widget>
61 </item>
62 </layout>
63 </item>
64 <item>
65 <layout class="QHBoxLayout" name="horizontalLayout">
66 <item>
67 <widget class="QGroupBox" name="groupBox">
68 <property name="title">
69 <string>TAS Directories</string>
70 </property>
71 <layout class="QGridLayout" name="gridLayout">
72 <item row="0" column="0">
73 <widget class="QLabel" name="label">
74 <property name="text">
75 <string>Path</string>
76 </property>
77 </widget>
78 </item>
79 <item row="0" column="3">
80 <widget class="QToolButton" name="tas_path_button">
81 <property name="text">
82 <string>...</string>
83 </property>
84 </widget>
85 </item>
86 <item row="0" column="2">
87 <widget class="QLineEdit" name="tas_path_edit"/>
88 </item>
89 <item row="0" column="1">
90 <spacer name="horizontalSpacer">
91 <property name="orientation">
92 <enum>Qt::Horizontal</enum>
93 </property>
94 <property name="sizeType">
95 <enum>QSizePolicy::Maximum</enum>
96 </property>
97 <property name="sizeHint" stdset="0">
98 <size>
99 <width>60</width>
100 <height>20</height>
101 </size>
102 </property>
103 </spacer>
104 </item>
105 </layout>
106 </widget>
107 </item>
108 </layout>
109 </item>
110 <item>
111 <widget class="QDialogButtonBox" name="buttonBox">
112 <property name="sizePolicy">
113 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
114 <horstretch>0</horstretch>
115 <verstretch>0</verstretch>
116 </sizepolicy>
117 </property>
118 <property name="orientation">
119 <enum>Qt::Horizontal</enum>
120 </property>
121 <property name="standardButtons">
122 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
123 </property>
124 </widget>
125 </item>
126 </layout>
127 </widget>
128 <resources/>
129 <connections>
130 <connection>
131 <sender>buttonBox</sender>
132 <signal>accepted()</signal>
133 <receiver>ConfigureTas</receiver>
134 <slot>accept()</slot>
135 </connection>
136 <connection>
137 <sender>buttonBox</sender>
138 <signal>rejected()</signal>
139 <receiver>ConfigureTas</receiver>
140 <slot>reject()</slot>
141 </connection>
142 </connections>
143</ui>
diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h
index 659923e1b..f2f6653f7 100644
--- a/src/yuzu/debugger/controller.h
+++ b/src/yuzu/debugger/controller.h
@@ -25,7 +25,6 @@ struct ControllerInput {
25 25
26struct ControllerCallback { 26struct ControllerCallback {
27 std::function<void(ControllerInput)> input; 27 std::function<void(ControllerInput)> input;
28 std::function<void()> update;
29}; 28};
30 29
31class ControllerDialog : public QWidget { 30class ControllerDialog : public QWidget {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 0ee0fd8cd..820e31fa7 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -19,6 +19,7 @@
19#include "common/nvidia_flags.h" 19#include "common/nvidia_flags.h"
20#include "configuration/configure_input.h" 20#include "configuration/configure_input.h"
21#include "configuration/configure_per_game.h" 21#include "configuration/configure_per_game.h"
22#include "configuration/configure_tas.h"
22#include "configuration/configure_vibration.h" 23#include "configuration/configure_vibration.h"
23#include "core/file_sys/vfs.h" 24#include "core/file_sys/vfs.h"
24#include "core/file_sys/vfs_real.h" 25#include "core/file_sys/vfs_real.h"
@@ -750,6 +751,11 @@ void GMainWindow::InitializeWidgets() {
750 statusBar()->addPermanentWidget(label); 751 statusBar()->addPermanentWidget(label);
751 } 752 }
752 753
754 tas_label = new QLabel();
755 tas_label->setObjectName(QStringLiteral("TASlabel"));
756 tas_label->setFocusPolicy(Qt::NoFocus);
757 statusBar()->insertPermanentWidget(0, tas_label);
758
753 // Setup Dock button 759 // Setup Dock button
754 dock_status_button = new QPushButton(); 760 dock_status_button = new QPushButton();
755 dock_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton")); 761 dock_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
@@ -826,12 +832,6 @@ void GMainWindow::InitializeWidgets() {
826 }); 832 });
827 statusBar()->insertPermanentWidget(0, renderer_status_button); 833 statusBar()->insertPermanentWidget(0, renderer_status_button);
828 834
829 tas_label = new QLabel();
830 tas_label->setObjectName(QStringLiteral("TASlabel"));
831 tas_label->setText(tr("TAS not running"));
832 tas_label->setFocusPolicy(Qt::NoFocus);
833 statusBar()->insertPermanentWidget(0, tas_label);
834
835 statusBar()->setVisible(true); 835 statusBar()->setVisible(true);
836 setStyleSheet(QStringLiteral("QStatusBar::item{border: none;}")); 836 setStyleSheet(QStringLiteral("QStatusBar::item{border: none;}"));
837} 837}
@@ -1024,18 +1024,11 @@ void GMainWindow::InitializeHotkeys() {
1024 } 1024 }
1025 }); 1025 });
1026 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Start/Stop"), this), 1026 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Start/Stop"), this),
1027 &QShortcut::activated, this, [&] { 1027 &QShortcut::activated, this, [&] { input_subsystem->GetTas()->StartStop(); });
1028 Settings::values.tas_enable = !Settings::values.tas_enable;
1029 LOG_INFO(Frontend, "Tas enabled {}", Settings::values.tas_enable);
1030 });
1031
1032 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Reset"), this), 1028 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Reset"), this),
1033 &QShortcut::activated, this, [&] { Settings::values.tas_reset = true; }); 1029 &QShortcut::activated, this, [&] { input_subsystem->GetTas()->Reset(); });
1034 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Record"), this), 1030 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("TAS Record"), this),
1035 &QShortcut::activated, this, [&] { 1031 &QShortcut::activated, this, [&] { input_subsystem->GetTas()->Record(); });
1036 Settings::values.tas_record = !Settings::values.tas_record;
1037 LOG_INFO(Frontend, "Tas recording {}", Settings::values.tas_record);
1038 });
1039} 1032}
1040 1033
1041void GMainWindow::SetDefaultUIGeometry() { 1034void GMainWindow::SetDefaultUIGeometry() {
@@ -1154,6 +1147,7 @@ void GMainWindow::ConnectMenuEvents() {
1154 connect(ui.action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ); 1147 connect(ui.action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ);
1155 connect(ui.action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); }); 1148 connect(ui.action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); });
1156 connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); 1149 connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure);
1150 connect(ui.action_Configure_Tas, &QAction::triggered, this, &GMainWindow::OnConfigureTas);
1157 connect(ui.action_Configure_Current_Game, &QAction::triggered, this, 1151 connect(ui.action_Configure_Current_Game, &QAction::triggered, this,
1158 &GMainWindow::OnConfigurePerGame); 1152 &GMainWindow::OnConfigurePerGame);
1159 1153
@@ -2720,6 +2714,19 @@ void GMainWindow::OnConfigure() {
2720 UpdateStatusButtons(); 2714 UpdateStatusButtons();
2721} 2715}
2722 2716
2717void GMainWindow::OnConfigureTas() {
2718 const auto& system = Core::System::GetInstance();
2719 ConfigureTasDialog dialog(this);
2720 const auto result = dialog.exec();
2721
2722 if (result != QDialog::Accepted && !UISettings::values.configuration_applied) {
2723 Settings::RestoreGlobalState(system.IsPoweredOn());
2724 return;
2725 } else if (result == QDialog::Accepted) {
2726 dialog.ApplyConfiguration();
2727 }
2728}
2729
2723void GMainWindow::OnConfigurePerGame() { 2730void GMainWindow::OnConfigurePerGame() {
2724 const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); 2731 const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
2725 OpenPerGameConfiguration(title_id, game_path.toStdString()); 2732 OpenPerGameConfiguration(title_id, game_path.toStdString());
@@ -2898,14 +2905,14 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie
2898 2905
2899static std::string GetTasStateDescription(TasInput::TasState state) { 2906static std::string GetTasStateDescription(TasInput::TasState state) {
2900 switch (state) { 2907 switch (state) {
2901 case TasInput::TasState::RUNNING: 2908 case TasInput::TasState::Running:
2902 return "Running"; 2909 return "Running";
2903 case TasInput::TasState::RECORDING: 2910 case TasInput::TasState::Recording:
2904 return "Recording"; 2911 return "Recording";
2905 case TasInput::TasState::STOPPED: 2912 case TasInput::TasState::Stopped:
2906 return "Stopped"; 2913 return "Stopped";
2907 default: 2914 default:
2908 return "INVALID STATE"; 2915 return "INVALID STATE";
2909 } 2916 }
2910} 2917}
2911 2918
@@ -2915,8 +2922,16 @@ void GMainWindow::UpdateStatusBar() {
2915 return; 2922 return;
2916 } 2923 }
2917 2924
2918 auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus(); 2925 if (Settings::values.tas_enable) {
2919 tas_label->setText(tr("%1 TAS %2/%3").arg(tr(GetTasStateDescription(tas_status).c_str())).arg(current_tas_frame).arg(total_tas_frames)); 2926 auto [tas_status, current_tas_frame, total_tas_frames] =
2927 input_subsystem->GetTas()->GetStatus();
2928 tas_label->setText(tr("%1 TAS %2/%3")
2929 .arg(tr(GetTasStateDescription(tas_status).c_str()))
2930 .arg(current_tas_frame)
2931 .arg(total_tas_frames));
2932 } else {
2933 tas_label->clear();
2934 }
2920 2935
2921 auto& system = Core::System::GetInstance(); 2936 auto& system = Core::System::GetInstance();
2922 auto results = system.GetAndResetPerfStats(); 2937 auto results = system.GetAndResetPerfStats();
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index edca661ac..867a0003c 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -259,6 +259,7 @@ private slots:
259 void OnMenuInstallToNAND(); 259 void OnMenuInstallToNAND();
260 void OnMenuRecentFile(); 260 void OnMenuRecentFile();
261 void OnConfigure(); 261 void OnConfigure();
262 void OnConfigureTas();
262 void OnConfigurePerGame(); 263 void OnConfigurePerGame();
263 void OnLoadAmiibo(); 264 void OnLoadAmiibo();
264 void OnOpenYuzuFolder(); 265 void OnOpenYuzuFolder();
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 048870687..31c1a20f3 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -72,6 +72,7 @@
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"/>
75 <addaction name="action_Configure_Current_Game"/> 76 <addaction name="action_Configure_Current_Game"/>
76 </widget> 77 </widget>
77 <widget class="QMenu" name="menu_View"> 78 <widget class="QMenu" name="menu_View">
@@ -294,6 +295,11 @@
294 <string>&amp;Capture Screenshot</string> 295 <string>&amp;Capture Screenshot</string>
295 </property> 296 </property>
296 </action> 297 </action>
298 <action name="action_Configure_Tas">
299 <property name="text">
300 <string>Configure &amp;TAS...</string>
301 </property>
302 </action>
297 <action name="action_Configure_Current_Game"> 303 <action name="action_Configure_Current_Game">
298 <property name="enabled"> 304 <property name="enabled">
299 <bool>false</bool> 305 <bool>false</bool>