diff options
| author | 2021-06-19 14:38:49 -0500 | |
|---|---|---|
| committer | 2021-09-18 23:22:30 +0200 | |
| commit | c01a872c8efa90065b6ba1a74079ddf6ec12058f (patch) | |
| tree | d441117b0d133bff32b39f5060b31db57bc0413f /src | |
| parent | core: Hacky TAS syncing & load pausing (diff) | |
| download | yuzu-c01a872c8efa90065b6ba1a74079ddf6ec12058f.tar.gz yuzu-c01a872c8efa90065b6ba1a74079ddf6ec12058f.tar.xz yuzu-c01a872c8efa90065b6ba1a74079ddf6ec12058f.zip | |
config: Move TAS options to it's own menu
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/fs/fs_paths.h | 2 | ||||
| -rw-r--r-- | src/common/fs/path_util.cpp | 2 | ||||
| -rw-r--r-- | src/common/fs/path_util.h | 3 | ||||
| -rw-r--r-- | src/core/hle/service/apm/apm_interface.cpp | 2 | ||||
| -rw-r--r-- | src/input_common/main.cpp | 6 | ||||
| -rw-r--r-- | src/input_common/tas/tas_input.cpp | 189 | ||||
| -rw-r--r-- | src/input_common/tas/tas_input.h | 26 | ||||
| -rw-r--r-- | src/yuzu/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_filesystem.cpp | 9 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_filesystem.h | 1 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_filesystem.ui | 49 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_player_widget.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_tas.cpp | 84 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_tas.h | 38 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_tas.ui | 143 | ||||
| -rw-r--r-- | src/yuzu/debugger/controller.h | 1 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 67 | ||||
| -rw-r--r-- | src/yuzu/main.h | 1 | ||||
| -rw-r--r-- | src/yuzu/main.ui | 6 |
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 | ||
| 113 | void Tas::WriteTasFile() { | 112 | void 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 | ||
| 145 | std::tuple<TasState, size_t, size_t> Tas::GetStatus() { | 143 | std::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 | ||
| 158 | static std::string DebugButtons(u32 buttons) { | 158 | static std::string DebugButtons(u32 buttons) { |
| 159 | return "{ " + TasInput::Tas::ButtonsToString(buttons) + " }"; | 159 | return fmt::format("{{ {} }}", TasInput::Tas::ButtonsToString(buttons)); |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | static std::string DebugJoystick(float x, float y) { | 162 | static 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 | ||
| 166 | static std::string DebugInput(const TasData& data) { | 166 | static 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 | ||
| 171 | static std::string DebugInputs(const std::array<TasData, PLAYER_NUMBER>& arr) { | 172 | static 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 | ||
| 182 | void Tas::UpdateThread() { | 183 | void 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 | ||
| 286 | std::string Tas::WriteCommandButtons(u32 data) const { | 275 | std::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 | ||
| 300 | void Tas::StartStop() { | ||
| 301 | is_running = !is_running; | ||
| 302 | } | ||
| 303 | |||
| 304 | void Tas::Reset() { | ||
| 305 | needs_reset = true; | ||
| 306 | } | ||
| 307 | |||
| 308 | void Tas::Record() { | ||
| 309 | is_recording = !is_recording; | ||
| 310 | <<<<<<< HEAD | ||
| 311 | ======= | ||
| 312 | return is_recording; | ||
| 313 | } | ||
| 314 | |||
| 315 | void 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 | |||
| 310 | InputCommon::ButtonMapping Tas::GetButtonMappingForDevice( | 331 | InputCommon::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 | ||
| 15 | namespace TasInput { | 15 | namespace TasInput { |
| 16 | 16 | ||
| 17 | constexpr int PLAYER_NUMBER = 8; | 17 | constexpr size_t PLAYER_NUMBER = 8; |
| 18 | 18 | ||
| 19 | using TasAnalog = std::pair<float, float>; | 19 | using TasAnalog = std::pair<float, float>; |
| 20 | 20 | ||
| 21 | enum class TasState { | 21 | enum class TasState { |
| 22 | RUNNING, | 22 | Running, |
| 23 | RECORDING, | 23 | Recording, |
| 24 | STOPPED, | 24 | Stopped, |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | enum class TasButton : u32 { | 27 | enum 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 | ||
| 244 | void PlayerControlPreview::SetCallBack(ControllerCallback callback_) { | 244 | void PlayerControlPreview::SetCallBack(ControllerCallback callback_) { |
| 245 | controller_callback = callback_; | 245 | controller_callback = std::move(callback_); |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | void PlayerControlPreview::paintEvent(QPaintEvent* event) { | 248 | void 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 | |||
| 14 | ConfigureTasDialog::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 | |||
| 28 | ConfigureTasDialog::~ConfigureTasDialog() = default; | ||
| 29 | |||
| 30 | void 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 | |||
| 39 | void 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 | |||
| 47 | void 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 | |||
| 69 | void ConfigureTasDialog::changeEvent(QEvent* event) { | ||
| 70 | if (event->type() == QEvent::LanguageChange) { | ||
| 71 | RetranslateUI(); | ||
| 72 | } | ||
| 73 | |||
| 74 | QDialog::changeEvent(event); | ||
| 75 | } | ||
| 76 | |||
| 77 | void ConfigureTasDialog::RetranslateUI() { | ||
| 78 | ui->retranslateUi(this); | ||
| 79 | } | ||
| 80 | |||
| 81 | void 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 | |||
| 9 | namespace Ui { | ||
| 10 | class ConfigureTas; | ||
| 11 | } | ||
| 12 | |||
| 13 | class ConfigureTasDialog : public QDialog { | ||
| 14 | Q_OBJECT | ||
| 15 | |||
| 16 | public: | ||
| 17 | explicit ConfigureTasDialog(QWidget* parent); | ||
| 18 | ~ConfigureTasDialog() override; | ||
| 19 | |||
| 20 | /// Save all button configurations to settings file | ||
| 21 | void ApplyConfiguration(); | ||
| 22 | |||
| 23 | private: | ||
| 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 | ||
| 26 | struct ControllerCallback { | 26 | struct ControllerCallback { |
| 27 | std::function<void(ControllerInput)> input; | 27 | std::function<void(ControllerInput)> input; |
| 28 | std::function<void()> update; | ||
| 29 | }; | 28 | }; |
| 30 | 29 | ||
| 31 | class ControllerDialog : public QWidget { | 30 | class 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 | ||
| 1041 | void GMainWindow::SetDefaultUIGeometry() { | 1034 | void 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 | ||
| 2717 | void 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 | |||
| 2723 | void GMainWindow::OnConfigurePerGame() { | 2730 | void 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 | ||
| 2899 | static std::string GetTasStateDescription(TasInput::TasState state) { | 2906 | static 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>&Capture Screenshot</string> | 295 | <string>&Capture Screenshot</string> |
| 295 | </property> | 296 | </property> |
| 296 | </action> | 297 | </action> |
| 298 | <action name="action_Configure_Tas"> | ||
| 299 | <property name="text"> | ||
| 300 | <string>Configure &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> |