tas_input.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright 2020 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <array>
  6. #include "common/common_types.h"
  7. #include "common/settings_input.h"
  8. #include "core/frontend/input.h"
  9. #include "input_common/main.h"
  10. /*
  11. To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below
  12. Tools -> Configure TAS. The file itself has normal text format and has to be called script0-1.txt
  13. for controller 1, script0-2.txt for controller 2 and so forth (with max. 8 players).
  14. A script file has the same format as TAS-nx uses, so final files will look like this:
  15. 1 KEY_B 0;0 0;0
  16. 6 KEY_ZL 0;0 0;0
  17. 41 KEY_ZL;KEY_Y 0;0 0;0
  18. 43 KEY_X;KEY_A 32767;0 0;0
  19. 44 KEY_A 32767;0 0;0
  20. 45 KEY_A 32767;0 0;0
  21. 46 KEY_A 32767;0 0;0
  22. 47 KEY_A 32767;0 0;0
  23. After placing the file at the correct location, it can be read into Yuzu with the (default) hotkey
  24. CTRL+F6 (refresh). In the bottom left corner, it will display the amount of frames the script file
  25. has. Playback can be started or stopped using CTRL+F5.
  26. However, for playback to actually work, the correct input device has to be selected: In the Controls
  27. menu, select TAS from the device list for the controller that the script should be played on.
  28. Recording a new script file is really simple: Just make sure that the proper device (not TAS) is
  29. connected on P1, and press CTRL+F7 to start recording. When done, just press the same keystroke
  30. again (CTRL+F7). The new script will be saved at the location previously selected, as the filename
  31. record.txt.
  32. For debugging purposes, the common controller debugger can be used (View -> Debugging -> Controller
  33. P1).
  34. */
  35. namespace TasInput {
  36. constexpr size_t PLAYER_NUMBER = 8;
  37. using TasAnalog = std::pair<float, float>;
  38. enum class TasState {
  39. Running,
  40. Recording,
  41. Stopped,
  42. };
  43. enum class TasButton : u32 {
  44. BUTTON_A = 1U << 0,
  45. BUTTON_B = 1U << 1,
  46. BUTTON_X = 1U << 2,
  47. BUTTON_Y = 1U << 3,
  48. STICK_L = 1U << 4,
  49. STICK_R = 1U << 5,
  50. TRIGGER_L = 1U << 6,
  51. TRIGGER_R = 1U << 7,
  52. TRIGGER_ZL = 1U << 8,
  53. TRIGGER_ZR = 1U << 9,
  54. BUTTON_PLUS = 1U << 10,
  55. BUTTON_MINUS = 1U << 11,
  56. BUTTON_LEFT = 1U << 12,
  57. BUTTON_UP = 1U << 13,
  58. BUTTON_RIGHT = 1U << 14,
  59. BUTTON_DOWN = 1U << 15,
  60. BUTTON_SL = 1U << 16,
  61. BUTTON_SR = 1U << 17,
  62. BUTTON_HOME = 1U << 18,
  63. BUTTON_CAPTURE = 1U << 19,
  64. };
  65. enum class TasAxes : u8 {
  66. StickX,
  67. StickY,
  68. SubstickX,
  69. SubstickY,
  70. Undefined,
  71. };
  72. struct TasData {
  73. u32 buttons{};
  74. std::array<float, 4> axis{};
  75. };
  76. class Tas {
  77. public:
  78. Tas();
  79. ~Tas();
  80. // Changes the input status that will be stored in each frame
  81. void RecordInput(u32 buttons, const std::array<std::pair<float, float>, 2>& axes);
  82. // Main loop that records or executes input
  83. void UpdateThread();
  84. // Sets the flag to start or stop the TAS command excecution and swaps controllers profiles
  85. void StartStop();
  86. // Stop the TAS and reverts any controller profile
  87. void Stop();
  88. // Sets the flag to reload the file and start from the begining in the next update
  89. void Reset();
  90. /**
  91. * Sets the flag to enable or disable recording of inputs
  92. * @return Returns true if the current recording status is enabled
  93. */
  94. bool Record();
  95. // Saves contents of record_commands on a file if overwrite is enabled player 1 will be
  96. // overwritten with the recorded commands
  97. void SaveRecording(bool overwrite_file);
  98. /**
  99. * Returns the current status values of TAS playback/recording
  100. * @return Tuple of
  101. * TasState indicating the current state out of Running, Recording or Stopped ;
  102. * Current playback progress or amount of frames (so far) for Recording ;
  103. * Total length of script file currently loaded or amount of frames (so far) for Recording
  104. */
  105. std::tuple<TasState, size_t, size_t> GetStatus() const;
  106. // Retuns an array of the default button mappings
  107. InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const;
  108. // Retuns an array of the default analog mappings
  109. InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const;
  110. [[nodiscard]] const TasData& GetTasState(std::size_t pad) const;
  111. private:
  112. struct TASCommand {
  113. u32 buttons{};
  114. TasAnalog l_axis{};
  115. TasAnalog r_axis{};
  116. };
  117. // Loads TAS files from all players
  118. void LoadTasFiles();
  119. // Loads TAS file from the specified player
  120. void LoadTasFile(size_t player_index);
  121. // Writes a TAS file from the recorded commands
  122. void WriteTasFile(std::u8string file_name);
  123. /**
  124. * Parses a string containing the axis values with the following format "x;y"
  125. * X and Y have a range from -32767 to 32767
  126. * @return Returns a TAS analog object with axis values with range from -1.0 to 1.0
  127. */
  128. TasAnalog ReadCommandAxis(const std::string& line) const;
  129. /**
  130. * Parses a string containing the button values with the following format "a;b;c;d..."
  131. * Each button is represented by it's text format specified in text_to_tas_button array
  132. * @return Returns a u32 with each bit representing the status of a button
  133. */
  134. u32 ReadCommandButtons(const std::string& line) const;
  135. /**
  136. * Converts an u32 containing the button status into the text equivalent
  137. * @return Returns a string with the name of the buttons to be written to the file
  138. */
  139. std::string WriteCommandButtons(u32 data) const;
  140. /**
  141. * Converts an TAS analog object containing the axis status into the text equivalent
  142. * @return Returns a string with the value of the axis to be written to the file
  143. */
  144. std::string WriteCommandAxis(TasAnalog data) const;
  145. // Inverts the Y axis polarity
  146. std::pair<float, float> FlipAxisY(std::pair<float, float> old);
  147. /**
  148. * Converts an u32 containing the button status into the text equivalent
  149. * @return Returns a string with the name of the buttons to be printed on console
  150. */
  151. std::string DebugButtons(u32 buttons) const;
  152. /**
  153. * Converts an TAS analog object containing the axis status into the text equivalent
  154. * @return Returns a string with the value of the axis to be printed on console
  155. */
  156. std::string DebugJoystick(float x, float y) const;
  157. /**
  158. * Converts the given TAS status into the text equivalent
  159. * @return Returns a string with the value of the TAS status to be printed on console
  160. */
  161. std::string DebugInput(const TasData& data) const;
  162. /**
  163. * Converts the given TAS status of multiple players into the text equivalent
  164. * @return Returns a string with the value of the status of all TAS players to be printed on
  165. * console
  166. */
  167. std::string DebugInputs(const std::array<TasData, PLAYER_NUMBER>& arr) const;
  168. /**
  169. * Converts an u32 containing the button status into the text equivalent
  170. * @return Returns a string with the name of the buttons
  171. */
  172. std::string ButtonsToString(u32 button) const;
  173. // Stores current controller configuration and sets a TAS controller for every active controller
  174. // to the current config
  175. void SwapToTasController();
  176. // Sets the stored controller configuration to the current config
  177. void SwapToStoredController();
  178. size_t script_length{0};
  179. std::array<TasData, PLAYER_NUMBER> tas_data;
  180. bool is_old_input_saved{false};
  181. bool is_recording{false};
  182. bool is_running{false};
  183. bool needs_reset{false};
  184. std::array<std::vector<TASCommand>, PLAYER_NUMBER> commands{};
  185. std::vector<TASCommand> record_commands{};
  186. size_t current_command{0};
  187. TASCommand last_input{}; // only used for recording
  188. // Old settings for swapping controllers
  189. std::array<Settings::PlayerInput, 10> player_mappings;
  190. };
  191. } // namespace TasInput