@ -19,6 +19,29 @@
namespace TasInput {
constexpr std : : array < std : : pair < std : : string_view , TasButton > , 20 > text_to_tas_button = {
std : : pair { " KEY_A " , TasButton : : BUTTON_A } ,
{ " KEY_B " , TasButton : : BUTTON_B } ,
{ " KEY_X " , TasButton : : BUTTON_X } ,
{ " KEY_Y " , TasButton : : BUTTON_Y } ,
{ " KEY_LSTICK " , TasButton : : STICK_L } ,
{ " KEY_RSTICK " , TasButton : : STICK_R } ,
{ " KEY_L " , TasButton : : TRIGGER_L } ,
{ " KEY_R " , TasButton : : TRIGGER_R } ,
{ " KEY_PLUS " , TasButton : : BUTTON_PLUS } ,
{ " KEY_MINUS " , TasButton : : BUTTON_MINUS } ,
{ " KEY_DLEFT " , TasButton : : BUTTON_LEFT } ,
{ " KEY_DUP " , TasButton : : BUTTON_UP } ,
{ " KEY_DRIGHT " , TasButton : : BUTTON_RIGHT } ,
{ " KEY_DDOWN " , TasButton : : BUTTON_DOWN } ,
{ " KEY_SL " , TasButton : : BUTTON_SL } ,
{ " KEY_SR " , TasButton : : BUTTON_SR } ,
{ " KEY_CAPTURE " , TasButton : : BUTTON_CAPTURE } ,
{ " KEY_HOME " , TasButton : : BUTTON_HOME } ,
{ " KEY_ZL " , TasButton : : TRIGGER_ZL } ,
{ " KEY_ZR " , TasButton : : TRIGGER_ZR } ,
} ;
Tas : : Tas ( ) {
LoadTasFiles ( ) ;
}
@ -31,29 +54,31 @@ void Tas::RefreshTasFile() {
refresh_tas_fle = true ;
}
void Tas : : LoadTasFiles ( ) {
script L ength = 0 ;
for ( in t i = 0 ; i < PLAYER_NUMBER ; i + + ) {
script _l ength = 0 ;
for ( size_ t i = 0 ; i < PLAYER_NUMBER ; i + + ) {
LoadTasFile ( i ) ;
if ( newCommands [ i ] . size ( ) > scriptLength )
scriptLength = newCommands [ i ] . size ( ) ;
if ( commands [ i ] . size ( ) > script_length ) {
script_length = commands [ i ] . size ( ) ;
}
}
}
void Tas : : LoadTasFile ( int playerI ndex) {
void Tas : : LoadTasFile ( size_t player_i ndex) {
LOG_DEBUG ( Input , " LoadTasFile() " ) ;
if ( ! newCommands[ playerI ndex] . empty ( ) ) {
newCommands[ playerI ndex] . clear ( ) ;
if ( ! commands[ player_i ndex] . empty ( ) ) {
commands[ player_i ndex] . clear ( ) ;
}
std : : string file = Common : : FS : : ReadStringFromFile (
Common : : FS : : GetYuzuPathString ( Common : : FS : : YuzuPath : : TASFile ) + " script0- " +
std : : to_string ( player I ndex + 1 ) + " .txt " ,
std : : to_string ( player _i ndex + 1 ) + " .txt " ,
Common : : FS : : FileType : : BinaryFile ) ;
std : : stringstream command_line ( file ) ;
std : : string line ;
int frameNo = 0 ;
TASCommand empty = { . buttons = 0 , . l_axis = { 0.f , 0.f } , . r_axis = { 0.f , 0.f } } ;
while ( std : : getline ( command_line , line , ' \n ' ) ) {
if ( line . empty ( ) )
if ( line . empty ( ) ) {
continue ;
}
LOG_DEBUG ( Input , " Loading line: {} " , line ) ;
std : : smatch m ;
@ -65,11 +90,12 @@ void Tas::LoadTasFile(int playerIndex) {
seglist . push_back ( segment ) ;
}
if ( seglist . size ( ) < 4 )
if ( seglist . size ( ) < 4 ) {
continue ;
}
while ( frameNo < std : : stoi ( seglist . at ( 0 ) ) ) {
newCommands[ playerI ndex] . push_back ( empty ) ;
commands[ player_i ndex] . push_back ( empty ) ;
frameNo + + ;
}
@ -78,7 +104,7 @@ void Tas::LoadTasFile(int playerIndex) {
. l_axis = ReadCommandAxis ( seglist . at ( 2 ) ) ,
. r_axis = ReadCommandAxis ( seglist . at ( 3 ) ) ,
} ;
newCommands[ playerI ndex] . push_back ( command ) ;
commands[ player_i ndex] . push_back ( command ) ;
frameNo + + ;
}
LOG_INFO ( Input , " TAS file loaded! {} frames " , frameNo ) ;
@ -87,84 +113,89 @@ void Tas::LoadTasFile(int playerIndex) {
void Tas : : WriteTasFile ( ) {
LOG_DEBUG ( Input , " WriteTasFile() " ) ;
std : : string output_text = " " ;
for ( int frame = 0 ; frame < ( signed ) record C ommands. size ( ) ; frame + + ) {
if ( ! output_text . empty ( ) )
for ( int frame = 0 ; frame < ( signed ) record _c ommands. size ( ) ; frame + + ) {
if ( ! output_text . empty ( ) ) {
output_text + = " \n " ;
TASCommand line = recordCommands . at ( frame ) ;
}
TASCommand line = record_commands . at ( frame ) ;
output_text + = std : : to_string ( frame ) + " " + WriteCommandButtons ( line . buttons ) + " " +
WriteCommandAxis ( line . l_axis ) + " " + WriteCommandAxis ( line . r_axis ) ;
}
size_t bytesWritten = Common : : FS : : WriteStringToFile (
Common : : FS : : GetYuzuPathString ( Common : : FS : : YuzuPath : : TASFile ) + " record.txt " ,
Common : : FS : : FileType : : TextFile , output_text ) ;
if ( bytesWritten = = output_text . size ( ) )
if ( bytesWritten = = output_text . size ( ) ) {
LOG_INFO ( Input , " TAS file written to file! " ) ;
else
}
else {
LOG_ERROR ( Input , " Writing the TAS-file has failed! {} / {} bytes written " , bytesWritten ,
output_text . size ( ) ) ;
}
}
void Tas : : RecordInput ( u32 buttons , std : : array < std : : pair < float , float > , 2 > axes ) {
lastInput = { buttons , flipY ( axes [ 0 ] ) , flipY ( axes [ 1 ] ) } ;
}
std : : pair < float , float > Tas : : flipY ( std : : pair < float , float > old ) const {
static std : : pair < float , float > FlipY ( std : : pair < float , float > old ) {
auto [ x , y ] = old ;
return { x , - y } ;
}
std : : string Tas : : GetStatusDescription ( ) {
void Tas : : RecordInput ( u32 buttons , const std : : array < std : : pair < float , float > , 2 > & axes ) {
last_input = { buttons , FlipY ( axes [ 0 ] ) , FlipY ( axes [ 1 ] ) } ;
}
std : : tuple < TasState , size_t , size_t > Tas : : GetStatus ( ) {
TasState state ;
if ( Settings : : values . tas_record ) {
return " Recording TAS: " + std : : to_string ( recordCommands . size ( ) ) ;
return { TasState : : RECORDING , record_commands . size ( ) , record_commands . size ( ) } ;
} else if ( Settings : : values . tas_enable ) {
state = TasState : : RUNNING ;
} else {
state = TasState : : STOPPED ;
}
if ( Settings : : values . tas_enable ) {
return " Playing TAS: " + std : : to_string ( current_command ) + " / " +
std : : to_string ( scriptLength ) ;
}
return " TAS not running: " + std : : to_string ( current_command ) + " / " +
std : : to_string ( scriptLength ) ;
return { state , current_command , script_length } ;
}
std : : string d ebugButtons( u32 buttons ) {
return " { " + TasInput : : Tas : : b uttonsToString( buttons ) + " } " ;
static std : : string DebugButtons ( u32 buttons ) {
return " { " + TasInput : : Tas : : ButtonsToString ( buttons ) + " } " ;
}
std : : string d ebugJoystick( float x , float y ) {
static std : : string D ebugJoystick( float x , float y ) {
return " [ " + std : : to_string ( x ) + " , " + std : : to_string ( y ) + " ] " ;
}
std : : string debugInput ( TasData data ) {
return " { " + d ebugButtons( data . buttons ) + " , " + d ebugJoystick( data . axis [ 0 ] , data . axis [ 1 ] ) +
" , " + d ebugJoystick( data . axis [ 2 ] , data . axis [ 3 ] ) + " } " ;
static std : : string DebugInput ( const TasData & data ) {
return " { " + D ebugButtons( data . buttons ) + " , " + D ebugJoystick( data . axis [ 0 ] , data . axis [ 1 ] ) +
" , " + D ebugJoystick( data . axis [ 2 ] , data . axis [ 3 ] ) + " } " ;
}
std : : string debugInputs ( std : : array < TasData , PLAYER_NUMBER > arr ) {
static std : : string DebugInputs ( const std : : array < TasData , PLAYER_NUMBER > & arr ) {
std : : string returns = " [ " ;
for ( size_t i = 0 ; i < arr . size ( ) ; i + + ) {
returns + = d ebugInput( arr [ i ] ) ;
if ( i ! = arr . size ( ) - 1 )
returns + = D ebugInput( arr [ i ] ) ;
if ( i ! = arr . size ( ) - 1 ) {
returns + = " , " ;
}
}
return returns + " ] " ;
}
void Tas : : UpdateThread ( ) {
if ( update_thread_running ) {
if ( Settings : : values . pause TasOnLoad & & Settings : : values . cpuB oosted) {
for ( in t i = 0 ; i < PLAYER_NUMBER ; i + + ) {
if ( Settings : : values . pause _tas_on_load & & Settings : : values . is_cpu_b oosted) {
for ( size_ t i = 0 ; i < PLAYER_NUMBER ; i + + ) {
tas_data [ i ] . buttons = 0 ;
tas_data [ i ] . axis = { } ;
}
}
if ( Settings : : values . tas_record ) {
record Commands. push_back ( lastI nput) ;
record _commands. push_back ( last_i nput) ;
}
if ( ! Settings : : values . tas_record & & ! record C ommands. empty ( ) ) {
if ( ! Settings : : values . tas_record & & ! record _c ommands. empty ( ) ) {
WriteTasFile ( ) ;
Settings : : values . tas_reset = true ;
refresh_tas_fle = true ;
record C ommands. clear ( ) ;
record _c ommands. clear ( ) ;
}
if ( Settings : : values . tas_reset ) {
current_command = 0 ;
@ -177,12 +208,12 @@ void Tas::UpdateThread() {
LOG_DEBUG ( Input , " tas_reset done " ) ;
}
if ( Settings : : values . tas_enable ) {
if ( ( signed ) current_command < script L ength) {
LOG_INFO ( Input , " Playing TAS {}/{} " , current_command , script L ength) ;
if ( ( signed ) current_command < script _l ength) {
LOG_INFO ( Input , " Playing TAS {}/{} " , current_command , script _l ength) ;
size_t frame = current_command + + ;
for ( in t i = 0 ; i < PLAYER_NUMBER ; i + + ) {
if ( frame < newC ommands[ i ] . size ( ) ) {
TASCommand command = newC ommands[ i ] [ frame ] ;
for ( size_ t i = 0 ; i < PLAYER_NUMBER ; i + + ) {
if ( frame < c ommands[ i ] . size ( ) ) {
TASCommand command = c ommands[ i ] [ frame ] ;
tas_data [ i ] . buttons = command . buttons ;
auto [ l_axis_x , l_axis_y ] = command . l_axis ;
tas_data [ i ] . axis [ 0 ] = l_axis_x ;
@ -198,22 +229,22 @@ void Tas::UpdateThread() {
} else {
Settings : : values . tas_enable = false ;
current_command = 0 ;
for ( in t i = 0 ; i < PLAYER_NUMBER ; i + + ) {
for ( size_ t i = 0 ; i < PLAYER_NUMBER ; i + + ) {
tas_data [ i ] . buttons = 0 ;
tas_data [ i ] . axis = { } ;
}
}
} else {
for ( in t i = 0 ; i < PLAYER_NUMBER ; i + + ) {
for ( size_ t i = 0 ; i < PLAYER_NUMBER ; i + + ) {
tas_data [ i ] . buttons = 0 ;
tas_data [ i ] . axis = { } ;
}
}
}
LOG_DEBUG ( Input , " TAS inputs: {} " , d ebugInputs( tas_data ) ) ;
LOG_DEBUG ( Input , " TAS inputs: {} " , D ebugInputs( tas_data ) ) ;
}
TasAnalog Tas : : ReadCommandAxis ( const std : : string line ) const {
TasAnalog Tas : : ReadCommandAxis ( const std : : string & line ) const {
std : : stringstream linestream ( line ) ;
std : : string segment ;
std : : vector < std : : string > seglist ;
@ -228,7 +259,7 @@ TasAnalog Tas::ReadCommandAxis(const std::string line) const {
return { x , y } ;
}
u32 Tas : : ReadCommandButtons ( const std : : string data ) const {
u32 Tas : : ReadCommandButtons ( const std : : string & data ) const {
std : : stringstream button_text ( data ) ;
std : : string line ;
u32 buttons = 0 ;
@ -262,8 +293,9 @@ std::string Tas::WriteCommandButtons(u32 data) const {
if ( ( data & 1 ) = = 1 ) {
for ( auto [ text , tas_button ] : text_to_tas_button ) {
if ( tas_button = = static_cast < TasButton > ( 1 < < index ) ) {
if ( line . size ( ) > 0 )
if ( line . size ( ) > 0 ) {
line + = " ; " ;
}
line + = text ;
break ;
}