2013-04-18 02:43:11 +00:00
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
2010-06-09 01:37:08 +00:00
2014-02-19 18:09:14 +00:00
# include <polarssl/md5.h>
2014-02-17 10:18:15 +00:00
2014-07-27 17:37:09 +00:00
# include "Common/ChunkFile.h"
2014-04-06 13:28:44 +00:00
# include "Common/CommonPaths.h"
2014-02-17 10:18:15 +00:00
# include "Common/FileUtil.h"
2014-04-06 13:28:44 +00:00
# include "Common/Hash.h"
2014-02-17 10:18:15 +00:00
# include "Common/NandPaths.h"
2014-07-03 02:42:36 +00:00
# include "Common/StringUtil.h"
2014-02-17 10:18:15 +00:00
# include "Common/Thread.h"
# include "Common/Timer.h"
# include "Core/ConfigManager.h"
# include "Core/Core.h"
2014-06-18 20:13:46 +00:00
# include "Core/CoreTiming.h"
2014-02-17 10:18:15 +00:00
# include "Core/Movie.h"
# include "Core/NetPlayProto.h"
# include "Core/State.h"
2014-04-06 13:28:44 +00:00
# include "Core/DSP/DSPCore.h"
2014-02-17 10:18:15 +00:00
# include "Core/HW/DVDInterface.h"
# include "Core/HW/EXI_Device.h"
# include "Core/HW/SI.h"
# include "Core/HW/Wiimote.h"
# include "Core/HW/WiimoteEmu/WiimoteEmu.h"
# include "Core/HW/WiimoteEmu/WiimoteHid.h"
2014-09-30 03:17:59 +00:00
# include "Core/HW/WiimoteEmu/Attachment/Classic.h"
# include "Core/HW/WiimoteEmu/Attachment/Nunchuk.h"
2014-02-17 10:18:15 +00:00
# include "Core/IPC_HLE/WII_IPC_HLE_Device_usb.h"
# include "Core/PowerPC/PowerPC.h"
2014-07-27 17:37:09 +00:00
# include "InputCommon/GCPadStatus.h"
2014-02-17 10:18:15 +00:00
# include "VideoCommon/VideoConfig.h"
2011-02-12 02:14:20 +00:00
2012-11-26 03:41:48 +00:00
// The chunk to allocate movie data in multiples of.
# define DTM_BASE_LENGTH (1024)
2011-05-03 00:06:44 +00:00
2014-07-08 13:58:25 +00:00
static std : : mutex cs_frameSkip ;
2010-06-09 01:37:08 +00:00
2011-06-24 06:50:50 +00:00
namespace Movie {
2010-06-09 01:37:08 +00:00
2014-09-08 23:13:49 +00:00
static bool s_bFrameStep = false ;
static bool s_bFrameStop = false ;
static bool s_bReadOnly = true ;
static u32 s_rerecords = 0 ;
static PlayMode s_playMode = MODE_NONE ;
2010-06-09 01:37:08 +00:00
2014-09-08 23:13:49 +00:00
static u32 s_framesToSkip = 0 , s_frameSkipCounter = 0 ;
2010-06-09 01:37:08 +00:00
2014-09-08 23:13:49 +00:00
static u8 s_numPads = 0 ;
static ControllerState s_padState ;
2014-07-08 13:58:25 +00:00
static DTMHeader tmpHeader ;
static u8 * tmpInput = nullptr ;
static size_t tmpInputAllocated = 0 ;
2014-09-08 23:13:49 +00:00
static u64 s_currentByte = 0 , s_totalBytes = 0 ;
2011-12-14 12:03:05 +00:00
u64 g_currentFrame = 0 , g_totalFrames = 0 ; // VI
2014-07-08 20:37:58 +00:00
u64 g_currentLagCount = 0 ;
2014-09-11 05:55:43 +00:00
static u64 s_totalLagCount = 0 ; // just stats
2011-12-14 12:03:05 +00:00
u64 g_currentInputCount = 0 , g_totalInputCount = 0 ; // just stats
2014-09-08 23:13:49 +00:00
static u64 s_totalTickCount = 0 , s_tickCountAtLastInput = 0 ; // just stats
static u64 s_recordingStartTime ; // seconds since 1970 that recording started
static bool s_bSaveConfig = false , s_bSkipIdle = false , s_bDualCore = false , s_bProgressive = false , s_bDSPHLE = false , s_bFastDiscSpeed = false ;
static bool s_bSyncGPU = false , s_bNetPlay = false ;
static std : : string s_videoBackend = " unknown " ;
static int s_iCPUCore = 1 ;
2014-07-08 13:58:25 +00:00
bool g_bClearSave = false ;
2012-10-20 18:18:42 +00:00
bool g_bDiscChange = false ;
2014-09-08 23:13:49 +00:00
static std : : string s_author = " " ;
2012-10-20 18:18:42 +00:00
std : : string g_discChange = " " ;
2012-10-25 06:44:30 +00:00
u64 g_titleID = 0 ;
2014-09-08 23:13:49 +00:00
static u8 s_MD5 [ 16 ] ;
static u8 s_bongos , s_memcards ;
static u8 s_revision [ 20 ] ;
static u32 s_DSPiromHash = 0 ;
static u32 s_DSPcoefHash = 0 ;
2010-06-09 01:37:08 +00:00
2014-09-08 23:13:49 +00:00
static bool s_bRecordingFromSaveState = false ;
static bool s_bPolled = false ;
2010-06-09 01:37:08 +00:00
2014-07-08 13:58:25 +00:00
static std : : string tmpStateFilename = File : : GetUserPath ( D_STATESAVES_IDX ) + " dtm.sav " ;
2010-06-09 01:37:08 +00:00
2014-09-08 23:13:49 +00:00
static std : : string s_InputDisplay [ 8 ] ;
2011-02-17 09:12:36 +00:00
2014-09-15 03:42:32 +00:00
static GCManipFunction gcmfunc = nullptr ;
static WiiManipFunction wiimfunc = nullptr ;
2011-06-24 06:50:50 +00:00
2014-07-08 12:29:26 +00:00
static void EnsureTmpInputSize ( size_t bound )
2012-11-26 03:41:48 +00:00
{
if ( tmpInputAllocated > = bound )
return ;
// The buffer expands in powers of two of DTM_BASE_LENGTH
// (standard exponential buffer growth).
size_t newAlloc = DTM_BASE_LENGTH ;
while ( newAlloc < bound )
newAlloc * = 2 ;
2013-10-29 05:23:17 +00:00
2012-11-26 03:41:48 +00:00
u8 * newTmpInput = new u8 [ newAlloc ] ;
tmpInputAllocated = newAlloc ;
2014-03-09 20:14:26 +00:00
if ( tmpInput ! = nullptr )
2012-11-26 03:41:48 +00:00
{
2014-09-08 23:13:49 +00:00
if ( s_totalBytes > 0 )
memcpy ( newTmpInput , tmpInput , ( size_t ) s_totalBytes ) ;
2012-11-26 03:41:48 +00:00
delete [ ] tmpInput ;
}
tmpInput = newTmpInput ;
}
2011-12-26 11:09:30 +00:00
2014-08-30 22:53:18 +00:00
static bool IsMovieHeader ( u8 magic [ 4 ] )
{
return magic [ 0 ] = = ' D ' & &
magic [ 1 ] = = ' T ' & &
magic [ 2 ] = = ' M ' & &
magic [ 3 ] = = 0x1A ;
}
2011-02-17 09:12:36 +00:00
std : : string GetInputDisplay ( )
{
2014-09-07 03:44:25 +00:00
if ( ! IsMovieActive ( ) )
2012-12-10 11:20:06 +00:00
{
2014-09-08 23:13:49 +00:00
s_numPads = 0 ;
2014-09-09 00:15:47 +00:00
for ( int i = 0 ; i < 4 ; + + i )
2012-12-10 11:20:06 +00:00
{
2014-09-22 15:45:54 +00:00
if ( SerialInterface : : GetDeviceType ( i ) ! = SIDEVICE_NONE )
2014-09-08 23:13:49 +00:00
s_numPads | = ( 1 < < i ) ;
2012-12-10 11:20:06 +00:00
if ( g_wiimote_sources [ i ] ! = WIIMOTE_SRC_NONE )
2014-09-08 23:13:49 +00:00
s_numPads | = ( 1 < < ( i + 4 ) ) ;
2012-12-10 11:20:06 +00:00
}
}
2013-04-17 03:14:36 +00:00
2011-02-17 09:12:36 +00:00
std : : string inputDisplay = " " ;
2011-12-14 12:03:05 +00:00
for ( int i = 0 ; i < 8 ; + + i )
2014-09-08 23:13:49 +00:00
if ( ( s_numPads & ( 1 < < i ) ) ! = 0 )
inputDisplay . append ( s_InputDisplay [ i ] ) ;
2013-10-29 05:23:17 +00:00
return inputDisplay ;
2011-02-17 09:12:36 +00:00
}
2010-06-09 01:37:08 +00:00
void FrameUpdate ( )
{
2011-12-14 12:03:05 +00:00
g_currentFrame + + ;
2014-09-08 23:13:49 +00:00
if ( ! s_bPolled )
2011-12-14 12:03:05 +00:00
g_currentLagCount + + ;
2011-02-15 17:03:20 +00:00
if ( IsRecordingInput ( ) )
2011-12-14 12:03:05 +00:00
{
g_totalFrames = g_currentFrame ;
2014-09-11 05:55:43 +00:00
s_totalLagCount = g_currentLagCount ;
2011-12-14 12:03:05 +00:00
}
2014-09-08 23:13:49 +00:00
if ( s_bFrameStep )
2011-12-12 05:08:26 +00:00
{
2010-06-09 01:37:08 +00:00
Core : : SetState ( Core : : CORE_PAUSE ) ;
2014-09-08 23:13:49 +00:00
s_bFrameStep = false ;
2011-12-12 05:08:26 +00:00
}
2013-10-29 05:23:17 +00:00
2010-06-09 01:37:08 +00:00
// ("framestop") the only purpose of this is to cause interpreter/jit Run() to return temporarily.
2014-07-07 03:30:06 +00:00
// after that we set it back to CPU_RUNNING and continue as normal.
2014-09-08 23:13:49 +00:00
if ( s_bFrameStop )
2014-07-07 03:30:06 +00:00
* PowerPC : : GetStatePtr ( ) = PowerPC : : CPU_STEPPING ;
2010-06-09 01:37:08 +00:00
2014-09-08 23:13:49 +00:00
if ( s_framesToSkip )
2010-06-09 01:37:08 +00:00
FrameSkipping ( ) ;
2013-10-29 05:23:17 +00:00
2014-09-08 23:13:49 +00:00
s_bPolled = false ;
2010-06-09 01:37:08 +00:00
}
2012-01-02 10:20:22 +00:00
// called when game is booting up, even if no movie is active,
// but potentially after BeginRecordingInput or PlayInput has been called.
void Init ( )
{
2014-09-08 23:13:49 +00:00
s_bPolled = false ;
s_bFrameStep = false ;
s_bFrameStop = false ;
s_bSaveConfig = false ;
s_iCPUCore = SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . iCPUCore ;
2012-10-20 23:54:38 +00:00
if ( IsPlayingInput ( ) )
2012-10-18 08:18:40 +00:00
{
2012-10-20 23:54:38 +00:00
ReadHeader ( ) ;
2012-11-26 00:26:37 +00:00
std : : thread md5thread ( CheckMD5 ) ;
2013-07-28 15:55:35 +00:00
md5thread . detach ( ) ;
2014-09-09 00:15:47 +00:00
if ( strncmp ( ( char * ) tmpHeader . gameID , SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . GetUniqueID ( ) . c_str ( ) , 6 ) )
2012-10-24 23:37:51 +00:00
{
2014-09-09 00:15:47 +00:00
PanicAlertT ( " The recorded game (%s) is not the same as the selected game (%s) " , tmpHeader . gameID , SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . GetUniqueID ( ) . c_str ( ) ) ;
2012-10-24 23:37:51 +00:00
EndPlayInput ( false ) ;
}
2012-10-18 08:18:40 +00:00
}
2013-04-17 03:14:36 +00:00
2012-10-24 20:35:52 +00:00
if ( IsRecordingInput ( ) )
{
GetSettings ( ) ;
2012-11-26 17:29:36 +00:00
std : : thread md5thread ( GetMD5 ) ;
2013-07-28 15:55:35 +00:00
md5thread . detach ( ) ;
2014-09-08 23:13:49 +00:00
s_tickCountAtLastInput = 0 ;
2012-10-24 20:35:52 +00:00
}
2012-11-26 17:29:36 +00:00
2014-09-08 23:13:49 +00:00
s_frameSkipCounter = s_framesToSkip ;
memset ( & s_padState , 0 , sizeof ( s_padState ) ) ;
2012-10-21 21:48:45 +00:00
if ( ! tmpHeader . bFromSaveState | | ! IsPlayingInput ( ) )
2012-10-18 08:14:25 +00:00
Core : : SetStateFileName ( " " ) ;
2012-10-25 03:21:34 +00:00
2014-09-08 23:13:49 +00:00
for ( auto & disp : s_InputDisplay )
2013-10-29 05:09:01 +00:00
disp . clear ( ) ;
2012-01-02 10:20:22 +00:00
2014-09-07 03:44:25 +00:00
if ( ! IsMovieActive ( ) )
2012-01-02 10:20:22 +00:00
{
2014-09-08 23:13:49 +00:00
s_bRecordingFromSaveState = false ;
s_rerecords = 0 ;
s_currentByte = 0 ;
2012-01-02 10:20:22 +00:00
g_currentFrame = 0 ;
g_currentLagCount = 0 ;
g_currentInputCount = 0 ;
}
}
2011-03-17 10:41:56 +00:00
void InputUpdate ( )
{
2011-12-14 12:03:05 +00:00
g_currentInputCount + + ;
if ( IsRecordingInput ( ) )
2014-06-18 20:13:46 +00:00
{
2011-12-14 12:03:05 +00:00
g_totalInputCount = g_currentInputCount ;
2014-09-08 23:13:49 +00:00
s_totalTickCount + = CoreTiming : : GetTicks ( ) - s_tickCountAtLastInput ;
s_tickCountAtLastInput = CoreTiming : : GetTicks ( ) ;
2014-06-18 20:13:46 +00:00
}
2012-11-18 06:07:48 +00:00
2014-09-09 00:15:47 +00:00
if ( IsPlayingInput ( ) & & g_currentInputCount = = ( g_totalInputCount - 1 ) & & SConfig : : GetInstance ( ) . m_PauseMovie )
2012-11-18 06:07:48 +00:00
Core : : SetState ( Core : : CORE_PAUSE ) ;
2011-03-17 10:41:56 +00:00
}
2010-06-09 01:37:08 +00:00
void SetFrameSkipping ( unsigned int framesToSkip )
{
2011-03-05 06:11:26 +00:00
std : : lock_guard < std : : mutex > lk ( cs_frameSkip ) ;
2013-10-29 05:23:17 +00:00
2014-09-08 23:13:49 +00:00
s_framesToSkip = framesToSkip ;
s_frameSkipCounter = 0 ;
2013-10-29 05:23:17 +00:00
2010-06-09 01:37:08 +00:00
// Don't forget to re-enable rendering in case it wasn't...
// as this won't be changed anymore when frameskip is turned off
if ( framesToSkip = = 0 )
2011-01-31 01:28:32 +00:00
g_video_backend - > Video_SetRendering ( true ) ;
2010-06-09 01:37:08 +00:00
}
void SetPolledDevice ( )
{
2014-09-08 23:13:49 +00:00
s_bPolled = true ;
2010-06-09 01:37:08 +00:00
}
2011-12-12 05:08:26 +00:00
void DoFrameStep ( )
2010-06-09 01:37:08 +00:00
{
2014-03-10 11:30:55 +00:00
if ( Core : : GetState ( ) = = Core : : CORE_PAUSE )
2011-12-12 05:08:26 +00:00
{
// if already paused, frame advance for 1 frame
Core : : SetState ( Core : : CORE_RUN ) ;
2011-12-14 12:03:05 +00:00
Core : : RequestRefreshInfo ( ) ;
2014-09-08 23:13:49 +00:00
s_bFrameStep = true ;
2011-12-12 05:08:26 +00:00
}
2014-09-08 23:13:49 +00:00
else if ( ! s_bFrameStep )
2011-12-12 05:08:26 +00:00
{
// if not paused yet, pause immediately instead
Core : : SetState ( Core : : CORE_PAUSE ) ;
}
2010-06-09 01:37:08 +00:00
}
2011-01-17 01:47:27 +00:00
void SetFrameStopping ( bool bEnabled )
2010-06-09 01:37:08 +00:00
{
2014-09-08 23:13:49 +00:00
s_bFrameStop = bEnabled ;
2010-06-09 01:37:08 +00:00
}
2011-02-12 02:14:20 +00:00
void SetReadOnly ( bool bEnabled )
{
2014-09-08 23:13:49 +00:00
if ( s_bReadOnly ! = bEnabled )
2011-12-12 05:08:26 +00:00
Core : : DisplayMessage ( bEnabled ? " Read-only mode. " : " Read+Write mode. " , 1000 ) ;
2014-09-08 23:13:49 +00:00
s_bReadOnly = bEnabled ;
2011-02-12 02:14:20 +00:00
}
2010-06-09 01:37:08 +00:00
void FrameSkipping ( )
{
2011-02-11 12:26:15 +00:00
// Frameskipping will desync movie playback
2014-09-09 00:15:47 +00:00
if ( ! IsMovieActive ( ) | | NetPlay : : IsNetPlayRunning ( ) )
2011-02-11 12:26:15 +00:00
{
2011-03-05 06:11:26 +00:00
std : : lock_guard < std : : mutex > lk ( cs_frameSkip ) ;
2011-02-11 12:26:15 +00:00
2014-09-08 23:13:49 +00:00
s_frameSkipCounter + + ;
if ( s_frameSkipCounter > s_framesToSkip | | Core : : ShouldSkipFrame ( s_frameSkipCounter ) = = false )
s_frameSkipCounter = 0 ;
2012-10-20 23:54:38 +00:00
2014-09-08 23:13:49 +00:00
g_video_backend - > Video_SetRendering ( ! s_frameSkipCounter ) ;
2011-02-11 12:26:15 +00:00
}
2010-06-09 01:37:08 +00:00
}
bool IsRecordingInput ( )
{
2014-09-08 23:13:49 +00:00
return ( s_playMode = = MODE_RECORDING ) ;
2010-06-09 01:37:08 +00:00
}
2011-02-15 09:07:55 +00:00
bool IsRecordingInputFromSaveState ( )
{
2014-09-08 23:13:49 +00:00
return s_bRecordingFromSaveState ;
2011-02-15 09:07:55 +00:00
}
2011-12-14 12:03:05 +00:00
bool IsJustStartingRecordingInputFromSaveState ( )
{
return IsRecordingInputFromSaveState ( ) & & g_currentFrame = = 0 ;
}
2012-10-18 08:03:12 +00:00
bool IsJustStartingPlayingInputFromSaveState ( )
{
2012-10-21 21:48:45 +00:00
return IsRecordingInputFromSaveState ( ) & & g_currentFrame = = 1 & & IsPlayingInput ( ) ;
2012-10-18 08:03:12 +00:00
}
2010-06-09 01:37:08 +00:00
bool IsPlayingInput ( )
{
2014-09-08 23:13:49 +00:00
return ( s_playMode = = MODE_PLAYING ) ;
2010-06-09 01:37:08 +00:00
}
2014-09-07 03:44:25 +00:00
bool IsMovieActive ( )
{
2014-09-08 23:13:49 +00:00
return s_playMode ! = MODE_NONE ;
2014-09-07 03:44:25 +00:00
}
2011-07-11 20:15:05 +00:00
bool IsReadOnly ( )
{
2014-09-08 23:13:49 +00:00
return s_bReadOnly ;
2011-07-11 20:15:05 +00:00
}
2011-12-26 11:09:30 +00:00
u64 GetRecordingStartTime ( )
{
2014-09-08 23:13:49 +00:00
return s_recordingStartTime ;
2011-12-26 11:09:30 +00:00
}
2010-09-06 21:41:01 +00:00
bool IsUsingPad ( int controller )
{
2014-09-08 23:13:49 +00:00
return ( ( s_numPads & ( 1 < < controller ) ) ! = 0 ) ;
2011-02-11 19:09:46 +00:00
}
2012-12-19 04:19:15 +00:00
bool IsUsingBongo ( int controller )
{
2014-09-08 23:13:49 +00:00
return ( ( s_bongos & ( 1 < < controller ) ) ! = 0 ) ;
2012-12-19 04:19:15 +00:00
}
2011-02-11 19:09:46 +00:00
bool IsUsingWiimote ( int wiimote )
{
2014-09-08 23:13:49 +00:00
return ( ( s_numPads & ( 1 < < ( wiimote + 4 ) ) ) ! = 0 ) ;
2010-09-06 21:41:01 +00:00
}
2012-10-18 08:18:40 +00:00
bool IsConfigSaved ( )
{
2014-09-08 23:13:49 +00:00
return s_bSaveConfig ;
2012-10-18 08:18:40 +00:00
}
bool IsDualCore ( )
{
2014-09-08 23:13:49 +00:00
return s_bDualCore ;
2012-10-18 08:18:40 +00:00
}
bool IsProgressive ( )
{
2014-09-08 23:13:49 +00:00
return s_bProgressive ;
2012-10-18 08:18:40 +00:00
}
bool IsSkipIdle ( )
{
2014-09-08 23:13:49 +00:00
return s_bSkipIdle ;
2012-10-18 08:18:40 +00:00
}
bool IsDSPHLE ( )
{
2014-09-08 23:13:49 +00:00
return s_bDSPHLE ;
2012-10-18 08:18:40 +00:00
}
bool IsFastDiscSpeed ( )
{
2014-09-08 23:13:49 +00:00
return s_bFastDiscSpeed ;
2012-10-18 08:18:40 +00:00
}
2014-07-07 03:30:06 +00:00
int GetCPUMode ( )
2012-10-18 08:18:40 +00:00
{
2014-09-08 23:13:49 +00:00
return s_iCPUCore ;
2012-10-21 21:48:45 +00:00
}
2012-10-25 06:44:30 +00:00
bool IsStartingFromClearSave ( )
2012-10-21 21:48:45 +00:00
{
2012-10-25 06:44:30 +00:00
return g_bClearSave ;
2012-10-21 21:48:45 +00:00
}
2014-07-03 01:45:59 +00:00
bool IsUsingMemcard ( int memcard )
2012-10-21 21:48:45 +00:00
{
2014-09-08 23:13:49 +00:00
return ( s_memcards & ( 1 < < memcard ) ) ! = 0 ;
2012-10-18 08:18:40 +00:00
}
2013-06-20 10:08:17 +00:00
bool IsSyncGPU ( )
{
2014-09-08 23:13:49 +00:00
return s_bSyncGPU ;
2013-06-20 10:08:17 +00:00
}
2012-10-18 08:18:40 +00:00
2013-09-03 19:50:41 +00:00
bool IsNetPlayRecording ( )
{
2014-09-08 23:13:49 +00:00
return s_bNetPlay ;
2013-09-03 19:50:41 +00:00
}
2011-02-12 00:06:58 +00:00
void ChangePads ( bool instantly )
2010-09-06 21:41:01 +00:00
{
2014-07-07 22:47:57 +00:00
if ( ! Core : : IsRunning ( ) )
2011-07-11 20:15:05 +00:00
return ;
int controllers = 0 ;
2014-09-09 00:15:47 +00:00
for ( int i = 0 ; i < MAX_SI_CHANNELS ; + + i )
2012-12-19 04:19:15 +00:00
if ( SConfig : : GetInstance ( ) . m_SIDevice [ i ] = = SIDEVICE_GC_CONTROLLER | | SConfig : : GetInstance ( ) . m_SIDevice [ i ] = = SIDEVICE_GC_TARUKONGA )
2011-07-11 20:15:05 +00:00
controllers | = ( 1 < < i ) ;
2014-09-08 23:13:49 +00:00
if ( instantly & & ( s_numPads & 0x0F ) = = controllers )
2011-07-11 20:15:05 +00:00
return ;
2014-09-09 00:15:47 +00:00
for ( int i = 0 ; i < MAX_SI_CHANNELS ; + + i )
2011-07-11 20:15:05 +00:00
if ( instantly ) // Changes from savestates need to be instantaneous
2012-12-19 04:19:15 +00:00
SerialInterface : : AddDevice ( IsUsingPad ( i ) ? ( IsUsingBongo ( i ) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER ) : SIDEVICE_NONE , i ) ;
2011-07-11 20:15:05 +00:00
else
2012-12-19 04:19:15 +00:00
SerialInterface : : ChangeDevice ( IsUsingPad ( i ) ? ( IsUsingBongo ( i ) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER ) : SIDEVICE_NONE , i ) ;
2011-02-11 19:09:46 +00:00
}
2011-07-11 20:15:05 +00:00
void ChangeWiiPads ( bool instantly )
2011-02-11 19:09:46 +00:00
{
2011-07-11 20:15:05 +00:00
int controllers = 0 ;
2014-09-09 00:15:47 +00:00
for ( int i = 0 ; i < MAX_WIIMOTES ; + + i )
2011-07-11 20:15:05 +00:00
if ( g_wiimote_sources [ i ] ! = WIIMOTE_SRC_NONE )
controllers | = ( 1 < < i ) ;
// This is important for Wiimotes, because they can desync easily if they get re-activated
2014-09-08 23:13:49 +00:00
if ( instantly & & ( s_numPads > > 4 ) = = controllers )
2011-07-11 20:15:05 +00:00
return ;
2014-09-09 00:15:47 +00:00
for ( int i = 0 ; i < MAX_WIIMOTES ; + + i )
2011-02-11 19:09:46 +00:00
{
g_wiimote_sources [ i ] = IsUsingWiimote ( i ) ? WIIMOTE_SRC_EMU : WIIMOTE_SRC_NONE ;
GetUsbPointer ( ) - > AccessWiiMote ( i | 0x100 ) - > Activate ( IsUsingWiimote ( i ) ) ;
2010-09-06 21:41:01 +00:00
}
}
2010-08-30 07:05:47 +00:00
bool BeginRecordingInput ( int controllers )
2010-06-09 01:37:08 +00:00
{
2014-09-08 23:13:49 +00:00
if ( s_playMode ! = MODE_NONE | | controllers = = 0 )
2010-06-09 01:37:08 +00:00
return false ;
2011-02-15 09:07:55 +00:00
2014-09-06 21:26:40 +00:00
bool was_unpaused = Core : : PauseAndLock ( true ) ;
2014-09-08 23:13:49 +00:00
s_numPads = controllers ;
2012-10-18 08:03:12 +00:00
g_currentFrame = g_totalFrames = 0 ;
2014-09-11 05:55:43 +00:00
g_currentLagCount = s_totalLagCount = 0 ;
2012-10-18 08:03:12 +00:00
g_currentInputCount = g_totalInputCount = 0 ;
2014-09-08 23:13:49 +00:00
s_totalTickCount = s_tickCountAtLastInput = 0 ;
s_bongos = 0 ;
s_memcards = 0 ;
2013-09-03 19:50:41 +00:00
if ( NetPlay : : IsNetPlayRunning ( ) )
{
2014-09-08 23:13:49 +00:00
s_bNetPlay = true ;
s_recordingStartTime = NETPLAY_INITIAL_GCTIME ;
2013-09-03 19:50:41 +00:00
}
else
2014-09-06 11:10:41 +00:00
{
2014-09-08 23:13:49 +00:00
s_recordingStartTime = Common : : Timer : : GetLocalTimeSinceJan1970 ( ) ;
2014-09-06 11:10:41 +00:00
}
2013-09-03 19:50:41 +00:00
2014-09-08 23:13:49 +00:00
s_rerecords = 0 ;
2012-10-18 08:03:12 +00:00
2014-09-06 11:10:41 +00:00
for ( int i = 0 ; i < MAX_SI_CHANNELS ; + + i )
2012-12-19 04:19:15 +00:00
if ( SConfig : : GetInstance ( ) . m_SIDevice [ i ] = = SIDEVICE_GC_TARUKONGA )
2014-09-08 23:13:49 +00:00
s_bongos | = ( 1 < < i ) ;
2012-12-19 04:19:15 +00:00
2014-07-08 20:32:35 +00:00
if ( Core : : IsRunningAndStarted ( ) )
2011-02-15 09:07:55 +00:00
{
2014-03-10 11:30:55 +00:00
if ( File : : Exists ( tmpStateFilename ) )
2011-05-03 00:06:44 +00:00
File : : Delete ( tmpStateFilename ) ;
2011-02-15 09:07:55 +00:00
2014-03-12 19:33:41 +00:00
State : : SaveAs ( tmpStateFilename ) ;
2014-09-08 23:13:49 +00:00
s_bRecordingFromSaveState = true ;
2012-10-25 06:44:30 +00:00
2012-10-26 16:06:32 +00:00
// This is only done here if starting from save state because otherwise we won't have the titleid. Otherwise it's set in WII_IPC_HLE_Device_es.cpp.
2012-10-25 06:44:30 +00:00
// TODO: find a way to GetTitleDataPath() from Movie::Init()
2014-09-09 04:24:49 +00:00
if ( SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . bWii )
2012-11-24 03:23:58 +00:00
{
2014-03-12 19:33:41 +00:00
if ( File : : Exists ( Common : : GetTitleDataPath ( g_titleID ) + " banner.bin " ) )
2012-11-24 03:23:58 +00:00
Movie : : g_bClearSave = false ;
else
Movie : : g_bClearSave = true ;
}
2012-11-26 17:29:36 +00:00
std : : thread md5thread ( GetMD5 ) ;
2013-09-11 07:34:05 +00:00
md5thread . detach ( ) ;
2013-07-01 21:44:42 +00:00
GetSettings ( ) ;
2010-06-09 01:37:08 +00:00
}
2014-09-08 23:13:49 +00:00
s_playMode = MODE_RECORDING ;
s_author = SConfig : : GetInstance ( ) . m_strMovieAuthor ;
2012-11-26 03:41:48 +00:00
EnsureTmpInputSize ( 1 ) ;
2014-09-08 23:13:49 +00:00
s_currentByte = s_totalBytes = 0 ;
2012-10-18 08:18:40 +00:00
2014-09-06 21:26:40 +00:00
Core : : UpdateWantDeterminism ( ) ;
Core : : PauseAndLock ( false , was_unpaused ) ;
2010-08-30 07:05:47 +00:00
Core : : DisplayMessage ( " Starting movie recording " , 2000 ) ;
2010-06-09 01:37:08 +00:00
return true ;
}
2014-09-30 03:17:59 +00:00
static std : : string Analog2DToString ( u8 x , u8 y , const std : : string & prefix , u8 range = 255 )
2011-12-14 12:03:05 +00:00
{
2014-09-30 03:17:59 +00:00
u8 center = range / 2 + 1 ;
if ( ( x < = 1 | | x = = center | | x > = range ) & &
( y < = 1 | | y = = center | | y > = range ) )
2011-12-14 12:03:05 +00:00
{
2014-09-30 03:17:59 +00:00
if ( x ! = center | | y ! = center )
2011-12-14 12:03:05 +00:00
{
2014-09-30 03:17:59 +00:00
if ( x ! = center & & y ! = center )
2011-12-14 12:03:05 +00:00
{
2014-09-30 03:17:59 +00:00
return StringFromFormat ( " %s:%s,%s " , prefix . c_str ( ) , x < center ? " LEFT " : " RIGHT " , y < center ? " DOWN " : " UP " ) ;
2011-12-14 12:03:05 +00:00
}
2014-09-30 03:17:59 +00:00
else if ( x ! = center )
2011-12-14 12:03:05 +00:00
{
2014-09-30 03:17:59 +00:00
return StringFromFormat ( " %s:%s " , prefix . c_str ( ) , x < center ? " LEFT " : " RIGHT " ) ;
2011-12-14 12:03:05 +00:00
}
else
{
2014-09-30 03:17:59 +00:00
return StringFromFormat ( " %s:%s " , prefix . c_str ( ) , y < center ? " DOWN " : " UP " ) ;
2011-12-14 12:03:05 +00:00
}
}
else
{
2014-07-03 02:42:36 +00:00
return " " ;
2011-12-14 12:03:05 +00:00
}
}
else
{
2014-07-03 02:42:36 +00:00
return StringFromFormat ( " %s:%d,%d " , prefix . c_str ( ) , x , y ) ;
2011-12-14 12:03:05 +00:00
}
}
2014-09-30 03:17:59 +00:00
static std : : string Analog1DToString ( u8 v , const std : : string & prefix , u8 range = 255 )
2011-12-14 12:03:05 +00:00
{
2014-03-10 11:30:55 +00:00
if ( v > 0 )
2011-12-14 12:03:05 +00:00
{
2014-09-30 03:17:59 +00:00
if ( v = = range )
2011-12-14 12:03:05 +00:00
{
2014-07-03 02:42:36 +00:00
return prefix ;
2011-12-14 12:03:05 +00:00
}
else
{
2014-07-03 02:42:36 +00:00
return StringFromFormat ( " %s:%d " , prefix . c_str ( ) , v ) ;
2011-12-14 12:03:05 +00:00
}
}
else
{
2014-07-03 02:42:36 +00:00
return " " ;
2011-12-14 12:03:05 +00:00
}
}
2014-07-08 12:29:26 +00:00
static void SetInputDisplayString ( ControllerState padState , int controllerID )
2011-02-17 09:12:36 +00:00
{
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] = StringFromFormat ( " P%d: " , controllerID + 1 ) ;
2011-02-17 09:12:36 +00:00
2014-07-26 21:14:54 +00:00
if ( padState . A )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " A " ) ;
2014-07-26 21:14:54 +00:00
if ( padState . B )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " B " ) ;
2014-07-26 21:14:54 +00:00
if ( padState . X )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " X " ) ;
2014-07-26 21:14:54 +00:00
if ( padState . Y )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " Y " ) ;
2014-07-26 21:14:54 +00:00
if ( padState . Z )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " Z " ) ;
2014-07-26 21:14:54 +00:00
if ( padState . Start )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " START " ) ;
2011-02-17 09:12:36 +00:00
2014-07-26 21:14:54 +00:00
if ( padState . DPadUp )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " UP " ) ;
2014-07-26 21:14:54 +00:00
if ( padState . DPadDown )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " DOWN " ) ;
2014-07-26 21:14:54 +00:00
if ( padState . DPadLeft )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " LEFT " ) ;
2014-07-26 21:14:54 +00:00
if ( padState . DPadRight )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " RIGHT " ) ;
2011-12-14 12:03:05 +00:00
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( Analog1DToString ( padState . TriggerL , " L " ) ) ;
s_InputDisplay [ controllerID ] . append ( Analog1DToString ( padState . TriggerR , " R " ) ) ;
s_InputDisplay [ controllerID ] . append ( Analog2DToString ( padState . AnalogStickX , padState . AnalogStickY , " ANA " ) ) ;
s_InputDisplay [ controllerID ] . append ( Analog2DToString ( padState . CStickX , padState . CStickY , " C " ) ) ;
s_InputDisplay [ controllerID ] . append ( " \n " ) ;
2011-12-14 12:03:05 +00:00
}
2014-09-30 03:17:59 +00:00
static void SetWiiInputDisplayString ( int remoteID , u8 * const data , const WiimoteEmu : : ReportFeatures & rptf , int ext , const wiimote_key key )
2011-12-14 12:03:05 +00:00
{
int controllerID = remoteID + 4 ;
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] = StringFromFormat ( " R%d: " , remoteID + 1 ) ;
2011-12-14 12:03:05 +00:00
2014-09-30 03:17:59 +00:00
u8 * const coreData = rptf . core ? ( data + rptf . core ) : nullptr ;
u8 * const accelData = rptf . accel ? ( data + rptf . accel ) : nullptr ;
u8 * const irData = rptf . ir ? ( data + rptf . ir ) : nullptr ;
u8 * const extData = rptf . ext ? ( data + rptf . ext ) : nullptr ;
2014-03-10 11:30:55 +00:00
if ( coreData )
2011-12-14 12:03:05 +00:00
{
2014-10-25 01:59:16 +00:00
wm_buttons buttons = * ( wm_buttons * ) coreData ;
if ( buttons . left )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " LEFT " ) ;
2014-10-25 01:59:16 +00:00
if ( buttons . right )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " RIGHT " ) ;
2014-10-25 01:59:16 +00:00
if ( buttons . down )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " DOWN " ) ;
2014-10-25 01:59:16 +00:00
if ( buttons . up )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " UP " ) ;
2014-10-25 01:59:16 +00:00
if ( buttons . a )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " A " ) ;
2014-10-25 01:59:16 +00:00
if ( buttons . b )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " B " ) ;
2014-10-25 01:59:16 +00:00
if ( buttons . plus )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " + " ) ;
2014-10-25 01:59:16 +00:00
if ( buttons . minus )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " - " ) ;
2014-10-25 01:59:16 +00:00
if ( buttons . one )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " 1 " ) ;
2014-10-25 01:59:16 +00:00
if ( buttons . two )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " 2 " ) ;
2014-10-25 01:59:16 +00:00
if ( buttons . home )
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " HOME " ) ;
2011-02-17 09:12:36 +00:00
}
2014-03-10 11:30:55 +00:00
if ( accelData )
2011-02-17 09:12:36 +00:00
{
2011-12-14 12:03:05 +00:00
wm_accel * dt = ( wm_accel * ) accelData ;
2014-07-03 02:42:36 +00:00
std : : string accel = StringFromFormat ( " ACC:%d,%d,%d " , dt - > x , dt - > y , dt - > z ) ;
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( accel ) ;
2011-02-17 09:12:36 +00:00
}
2011-12-14 12:03:05 +00:00
2014-09-30 12:24:18 +00:00
if ( irData )
2011-02-17 09:12:36 +00:00
{
2014-09-30 12:24:18 +00:00
u16 x = irData [ 0 ] | ( ( irData [ 2 ] > > 4 & 0x3 ) < < 8 ) ;
2014-09-15 03:42:32 +00:00
u16 y = irData [ 1 ] | ( ( irData [ 2 ] > > 6 & 0x3 ) < < 8 ) ;
std : : string ir = StringFromFormat ( " IR:%d,%d " , x , y ) ;
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( ir ) ;
2011-02-17 09:12:36 +00:00
}
2014-09-30 03:17:59 +00:00
// Nunchuck
if ( extData & & ext = = 1 )
{
2014-10-25 01:59:16 +00:00
wm_nc nunchuck ;
memcpy ( & nunchuck , extData , sizeof ( wm_nc ) ) ;
WiimoteDecrypt ( & key , ( u8 * ) & nunchuck , 0 , sizeof ( wm_nc ) ) ;
nunchuck . bt . hex = nunchuck . bt . hex ^ 0xFF ;
2014-09-30 03:17:59 +00:00
std : : string accel = StringFromFormat ( " N-ACC:%d,%d,%d " , nunchuck . ax , nunchuck . ay , nunchuck . az ) ;
2014-10-25 01:59:16 +00:00
if ( nunchuck . bt . c )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " C " ) ;
2014-10-25 01:59:16 +00:00
if ( nunchuck . bt . z )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " Z " ) ;
s_InputDisplay [ controllerID ] . append ( accel ) ;
s_InputDisplay [ controllerID ] . append ( Analog2DToString ( nunchuck . jx , nunchuck . jy , " ANA " ) ) ;
}
// Classic controller
if ( extData & & ext = = 2 )
{
wm_classic_extension cc ;
memcpy ( & cc , extData , sizeof ( wm_classic_extension ) ) ;
WiimoteDecrypt ( & key , ( u8 * ) & cc , 0 , sizeof ( wm_classic_extension ) ) ;
2014-10-25 01:59:16 +00:00
cc . bt . hex = cc . bt . hex ^ 0xFFFF ;
2014-09-30 03:17:59 +00:00
2014-10-25 01:59:16 +00:00
if ( cc . bt . regular_data . dpad_left )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " LEFT " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . dpad_right )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " RIGHT " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . dpad_down )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " DOWN " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . regular_data . dpad_up )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " UP " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . a )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " A " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . b )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " B " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . x )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " X " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . y )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " Y " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . zl )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " ZL " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . zr )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " ZR " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . plus )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " + " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . minus )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " - " ) ;
2014-10-25 01:59:16 +00:00
if ( cc . bt . home )
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( " HOME " ) ;
s_InputDisplay [ controllerID ] . append ( Analog1DToString ( cc . lt1 | ( cc . lt2 < < 3 ) , " L " , 31 ) ) ;
s_InputDisplay [ controllerID ] . append ( Analog1DToString ( cc . rt , " R " , 31 ) ) ;
2014-10-25 01:59:16 +00:00
s_InputDisplay [ controllerID ] . append ( Analog2DToString ( cc . regular_data . lx , cc . regular_data . ly , " ANA " , 63 ) ) ;
2014-09-30 03:17:59 +00:00
s_InputDisplay [ controllerID ] . append ( Analog2DToString ( cc . rx1 | ( cc . rx2 < < 1 ) | ( cc . rx3 < < 3 ) , cc . ry , " R-ANA " , 31 ) ) ;
}
2014-09-08 23:13:49 +00:00
s_InputDisplay [ controllerID ] . append ( " \n " ) ;
2011-02-17 09:12:36 +00:00
}
2014-07-11 02:02:32 +00:00
void CheckPadStatus ( GCPadStatus * PadStatus , int controllerID )
2010-06-09 01:37:08 +00:00
{
2014-09-08 23:13:49 +00:00
s_padState . A = ( ( PadStatus - > button & PAD_BUTTON_A ) ! = 0 ) ;
s_padState . B = ( ( PadStatus - > button & PAD_BUTTON_B ) ! = 0 ) ;
s_padState . X = ( ( PadStatus - > button & PAD_BUTTON_X ) ! = 0 ) ;
s_padState . Y = ( ( PadStatus - > button & PAD_BUTTON_Y ) ! = 0 ) ;
s_padState . Z = ( ( PadStatus - > button & PAD_TRIGGER_Z ) ! = 0 ) ;
s_padState . Start = ( ( PadStatus - > button & PAD_BUTTON_START ) ! = 0 ) ;
s_padState . DPadUp = ( ( PadStatus - > button & PAD_BUTTON_UP ) ! = 0 ) ;
s_padState . DPadDown = ( ( PadStatus - > button & PAD_BUTTON_DOWN ) ! = 0 ) ;
s_padState . DPadLeft = ( ( PadStatus - > button & PAD_BUTTON_LEFT ) ! = 0 ) ;
s_padState . DPadRight = ( ( PadStatus - > button & PAD_BUTTON_RIGHT ) ! = 0 ) ;
2014-09-09 00:15:47 +00:00
s_padState . L = ( ( PadStatus - > button & PAD_TRIGGER_L ) ! = 0 ) ;
s_padState . R = ( ( PadStatus - > button & PAD_TRIGGER_R ) ! = 0 ) ;
s_padState . TriggerL = PadStatus - > triggerLeft ;
s_padState . TriggerR = PadStatus - > triggerRight ;
2014-09-08 23:13:49 +00:00
s_padState . AnalogStickX = PadStatus - > stickX ;
s_padState . AnalogStickY = PadStatus - > stickY ;
2014-09-09 00:15:47 +00:00
s_padState . CStickX = PadStatus - > substickX ;
s_padState . CStickY = PadStatus - > substickY ;
2014-09-08 23:13:49 +00:00
SetInputDisplayString ( s_padState , controllerID ) ;
2012-12-10 11:20:06 +00:00
}
2014-07-11 02:02:32 +00:00
void RecordInput ( GCPadStatus * PadStatus , int controllerID )
2012-12-10 11:20:06 +00:00
{
if ( ! IsRecordingInput ( ) | | ! IsUsingPad ( controllerID ) )
return ;
CheckPadStatus ( PadStatus , controllerID ) ;
2012-10-20 18:18:42 +00:00
if ( g_bDiscChange )
{
2014-09-08 23:13:49 +00:00
s_padState . disc = g_bDiscChange ;
2012-10-20 18:18:42 +00:00
g_bDiscChange = false ;
}
2012-12-10 11:20:06 +00:00
2014-09-08 23:13:49 +00:00
EnsureTmpInputSize ( ( size_t ) ( s_currentByte + 8 ) ) ;
memcpy ( & ( tmpInput [ s_currentByte ] ) , & s_padState , 8 ) ;
s_currentByte + = 8 ;
s_totalBytes = s_currentByte ;
2010-06-09 01:37:08 +00:00
}
2014-09-30 03:17:59 +00:00
void CheckWiimoteStatus ( int wiimote , u8 * data , const WiimoteEmu : : ReportFeatures & rptf , int ext , const wiimote_key key )
2011-02-11 18:53:51 +00:00
{
2011-12-15 17:22:16 +00:00
u8 size = rptf . size ;
2014-09-30 03:17:59 +00:00
SetWiiInputDisplayString ( wiimote , data , rptf , ext , key ) ;
2012-12-10 11:20:06 +00:00
if ( IsRecordingInput ( ) )
RecordWiimote ( wiimote , data , size ) ;
}
void RecordWiimote ( int wiimote , u8 * data , u8 size )
{
2014-03-10 11:30:55 +00:00
if ( ! IsRecordingInput ( ) | | ! IsUsingWiimote ( wiimote ) )
2012-12-10 11:20:06 +00:00
return ;
2011-12-15 17:22:16 +00:00
2011-12-14 12:03:05 +00:00
InputUpdate ( ) ;
2014-09-08 23:13:49 +00:00
EnsureTmpInputSize ( ( size_t ) ( s_currentByte + size + 1 ) ) ;
tmpInput [ s_currentByte + + ] = size ;
memcpy ( & ( tmpInput [ s_currentByte ] ) , data , size ) ;
s_currentByte + = size ;
s_totalBytes = s_currentByte ;
2011-02-11 18:53:51 +00:00
}
2012-10-20 18:18:42 +00:00
void ReadHeader ( )
{
2014-09-08 23:13:49 +00:00
s_numPads = tmpHeader . numControllers ;
s_recordingStartTime = tmpHeader . recordingStartTime ;
if ( s_rerecords < tmpHeader . numRerecords )
s_rerecords = tmpHeader . numRerecords ;
2012-10-20 18:18:42 +00:00
2012-10-20 23:54:38 +00:00
if ( tmpHeader . bSaveConfig )
{
2014-09-08 23:13:49 +00:00
s_bSaveConfig = true ;
s_bSkipIdle = tmpHeader . bSkipIdle ;
s_bDualCore = tmpHeader . bDualCore ;
s_bProgressive = tmpHeader . bProgressive ;
s_bDSPHLE = tmpHeader . bDSPHLE ;
s_bFastDiscSpeed = tmpHeader . bFastDiscSpeed ;
s_iCPUCore = tmpHeader . CPUCore ;
2012-10-25 06:44:30 +00:00
g_bClearSave = tmpHeader . bClearSave ;
2014-09-08 23:13:49 +00:00
s_memcards = tmpHeader . memcards ;
s_bongos = tmpHeader . bongos ;
s_bSyncGPU = tmpHeader . bSyncGPU ;
s_bNetPlay = tmpHeader . bNetPlay ;
memcpy ( s_revision , tmpHeader . revision , ArraySize ( s_revision ) ) ;
2012-10-20 23:54:38 +00:00
}
else
{
2012-10-24 20:35:52 +00:00
GetSettings ( ) ;
2012-10-20 23:54:38 +00:00
}
2012-10-20 18:18:42 +00:00
2014-09-08 23:13:49 +00:00
s_videoBackend = ( char * ) tmpHeader . videoBackend ;
2013-07-01 21:44:42 +00:00
g_discChange = ( char * ) tmpHeader . discChange ;
2014-09-08 23:13:49 +00:00
s_author = ( char * ) tmpHeader . author ;
memcpy ( s_MD5 , tmpHeader . md5 , 16 ) ;
s_DSPiromHash = tmpHeader . DSPiromHash ;
s_DSPcoefHash = tmpHeader . DSPcoefHash ;
2012-10-20 18:18:42 +00:00
}
2014-03-12 19:33:41 +00:00
bool PlayInput ( const std : : string & filename )
2010-06-09 01:37:08 +00:00
{
2014-09-08 23:13:49 +00:00
if ( s_playMode ! = MODE_NONE )
2010-06-09 01:37:08 +00:00
return false ;
2011-05-03 00:06:44 +00:00
2014-03-10 11:30:55 +00:00
if ( ! File : : Exists ( filename ) )
2010-06-09 01:37:08 +00:00
return false ;
2012-10-21 21:48:45 +00:00
2011-05-03 00:06:44 +00:00
File : : IOFile g_recordfd ;
2012-10-21 21:48:45 +00:00
2011-05-03 00:06:44 +00:00
if ( ! g_recordfd . Open ( filename , " rb " ) )
2010-06-09 01:37:08 +00:00
return false ;
2012-10-21 21:48:45 +00:00
2011-05-03 00:06:44 +00:00
g_recordfd . ReadArray ( & tmpHeader , 1 ) ;
2013-10-29 05:23:17 +00:00
2014-08-30 22:53:18 +00:00
if ( ! IsMovieHeader ( tmpHeader . filetype ) )
2014-08-30 21:23:13 +00:00
{
2011-01-13 02:05:58 +00:00
PanicAlertT ( " Invalid recording file " ) ;
2014-09-09 00:15:47 +00:00
g_recordfd . Close ( ) ;
return false ;
2010-06-09 01:37:08 +00:00
}
2012-10-21 21:48:45 +00:00
2012-10-20 18:18:42 +00:00
ReadHeader ( ) ;
2011-12-14 12:03:05 +00:00
g_totalFrames = tmpHeader . frameCount ;
2014-09-11 05:55:43 +00:00
s_totalLagCount = tmpHeader . lagCount ;
2011-12-14 12:03:05 +00:00
g_totalInputCount = tmpHeader . inputCount ;
2014-09-08 23:13:49 +00:00
s_totalTickCount = tmpHeader . tickCount ;
2011-12-15 17:22:16 +00:00
g_currentFrame = 0 ;
g_currentLagCount = 0 ;
g_currentInputCount = 0 ;
2014-09-08 23:13:49 +00:00
s_playMode = MODE_PLAYING ;
2013-10-29 05:23:17 +00:00
2014-09-06 21:26:40 +00:00
Core : : UpdateWantDeterminism ( ) ;
2014-09-08 23:13:49 +00:00
s_totalBytes = g_recordfd . GetSize ( ) - 256 ;
EnsureTmpInputSize ( ( size_t ) s_totalBytes ) ;
g_recordfd . ReadArray ( tmpInput , ( size_t ) s_totalBytes ) ;
s_currentByte = 0 ;
2011-05-03 00:06:44 +00:00
g_recordfd . Close ( ) ;
2012-10-21 21:48:45 +00:00
2013-01-19 20:02:02 +00:00
// Load savestate (and skip to frame data)
2014-03-10 11:30:55 +00:00
if ( tmpHeader . bFromSaveState )
2013-01-19 20:02:02 +00:00
{
2014-03-12 19:33:41 +00:00
const std : : string stateFilename = filename + " .sav " ;
2014-03-10 11:30:55 +00:00
if ( File : : Exists ( stateFilename ) )
2013-01-19 20:02:02 +00:00
Core : : SetStateFileName ( stateFilename ) ;
2014-09-08 23:13:49 +00:00
s_bRecordingFromSaveState = true ;
2013-01-19 20:02:02 +00:00
Movie : : LoadInput ( filename ) ;
}
2010-06-09 01:37:08 +00:00
return true ;
}
2011-12-28 08:33:41 +00:00
void DoState ( PointerWrap & p )
2011-12-14 12:03:05 +00:00
{
// many of these could be useful to save even when no movie is active,
// and the data is tiny, so let's just save it regardless of movie state.
p . Do ( g_currentFrame ) ;
2014-09-08 23:13:49 +00:00
p . Do ( s_currentByte ) ;
2011-12-14 12:03:05 +00:00
p . Do ( g_currentLagCount ) ;
p . Do ( g_currentInputCount ) ;
2014-09-08 23:13:49 +00:00
p . Do ( s_bPolled ) ;
p . Do ( s_tickCountAtLastInput ) ;
// other variables (such as s_totalBytes and g_totalFrames) are set in LoadInput
2011-12-14 12:03:05 +00:00
}
2014-03-12 19:33:41 +00:00
void LoadInput ( const std : : string & filename )
2010-08-30 07:05:47 +00:00
{
2013-01-19 20:02:02 +00:00
File : : IOFile t_record ;
if ( ! t_record . Open ( filename , " r+b " ) )
{
2014-03-12 19:33:41 +00:00
PanicAlertT ( " Failed to read %s " , filename . c_str ( ) ) ;
2013-01-19 20:02:02 +00:00
EndPlayInput ( false ) ;
return ;
}
2012-10-20 18:18:42 +00:00
2011-05-03 00:06:44 +00:00
t_record . ReadArray ( & tmpHeader , 1 ) ;
2012-10-21 21:48:45 +00:00
2014-08-30 22:53:18 +00:00
if ( ! IsMovieHeader ( tmpHeader . filetype ) )
2011-02-15 09:07:55 +00:00
{
2014-03-12 19:33:41 +00:00
PanicAlertT ( " Savestate movie %s is corrupted, movie recording stopping... " , filename . c_str ( ) ) ;
2011-02-15 17:03:20 +00:00
EndPlayInput ( false ) ;
2010-08-30 07:05:47 +00:00
return ;
}
2012-10-20 18:18:42 +00:00
ReadHeader ( ) ;
2014-09-08 23:13:49 +00:00
if ( ! s_bReadOnly )
2011-12-18 07:27:11 +00:00
{
2014-09-08 23:13:49 +00:00
s_rerecords + + ;
tmpHeader . numRerecords = s_rerecords ;
2011-12-18 07:27:11 +00:00
t_record . Seek ( 0 , SEEK_SET ) ;
t_record . WriteArray ( & tmpHeader , 1 ) ;
}
2012-10-20 18:18:42 +00:00
2011-02-12 00:06:58 +00:00
ChangePads ( true ) ;
2014-09-09 04:24:49 +00:00
if ( SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . bWii )
2011-07-11 20:15:05 +00:00
ChangeWiiPads ( true ) ;
2011-05-03 00:06:44 +00:00
2011-12-18 07:27:11 +00:00
u64 totalSavedBytes = t_record . GetSize ( ) - 256 ;
bool afterEnd = false ;
2014-07-05 23:48:44 +00:00
// This can only happen if the user manually deletes data from the dtm.
2014-09-08 23:13:49 +00:00
if ( s_currentByte > totalSavedBytes )
2011-12-18 07:27:11 +00:00
{
2014-09-08 23:13:49 +00:00
PanicAlertT ( " Warning: You loaded a save whose movie ends before the current frame in the save (byte %u < %u) (frame %u < %u). You should load another save before continuing. " , ( u32 ) totalSavedBytes + 256 , ( u32 ) s_currentByte + 256 , ( u32 ) tmpHeader . frameCount , ( u32 ) g_currentFrame ) ;
2011-12-18 07:27:11 +00:00
afterEnd = true ;
}
2014-09-08 23:13:49 +00:00
if ( ! s_bReadOnly | | tmpInput = = nullptr )
2011-12-14 12:03:05 +00:00
{
g_totalFrames = tmpHeader . frameCount ;
2014-09-11 05:55:43 +00:00
s_totalLagCount = tmpHeader . lagCount ;
2011-12-14 12:03:05 +00:00
g_totalInputCount = tmpHeader . inputCount ;
2014-09-08 23:13:49 +00:00
s_totalTickCount = s_tickCountAtLastInput = tmpHeader . tickCount ;
2011-12-14 12:03:05 +00:00
2012-11-26 03:41:48 +00:00
EnsureTmpInputSize ( ( size_t ) totalSavedBytes ) ;
2014-09-08 23:13:49 +00:00
s_totalBytes = totalSavedBytes ;
t_record . ReadArray ( tmpInput , ( size_t ) s_totalBytes ) ;
2011-12-14 12:03:05 +00:00
}
2014-09-08 23:13:49 +00:00
else if ( s_currentByte > 0 )
2011-12-14 12:03:05 +00:00
{
2014-09-08 23:13:49 +00:00
if ( s_currentByte > totalSavedBytes )
2011-12-14 12:03:05 +00:00
{
}
2014-09-08 23:13:49 +00:00
else if ( s_currentByte > s_totalBytes )
2011-12-14 12:03:05 +00:00
{
2014-07-05 23:48:44 +00:00
afterEnd = true ;
2014-09-08 23:13:49 +00:00
PanicAlertT ( " Warning: You loaded a save that's after the end of the current movie. (byte %u > %u) (frame %u > %u). You should load another save before continuing, or load this state with read-only mode off. " , ( u32 ) s_currentByte + 256 , ( u32 ) s_totalBytes + 256 , ( u32 ) g_currentFrame , ( u32 ) g_totalFrames ) ;
2011-12-18 07:27:11 +00:00
}
2014-09-08 23:13:49 +00:00
else if ( s_currentByte > 0 & & s_totalBytes > 0 )
2011-12-18 07:27:11 +00:00
{
2011-12-26 11:09:30 +00:00
// verify identical from movie start to the save's current frame
2014-09-08 23:13:49 +00:00
u32 len = ( u32 ) s_currentByte ;
2011-12-18 07:27:11 +00:00
u8 * movInput = new u8 [ len ] ;
t_record . ReadArray ( movInput , ( size_t ) len ) ;
2011-12-14 12:03:05 +00:00
for ( u32 i = 0 ; i < len ; + + i )
{
2011-12-18 07:27:11 +00:00
if ( movInput [ i ] ! = tmpInput [ i ] )
2011-12-14 12:03:05 +00:00
{
2011-12-18 07:27:11 +00:00
// this is a "you did something wrong" alert for the user's benefit.
// we'll try to say what's going on in excruciating detail, otherwise the user might not believe us.
2014-03-10 11:30:55 +00:00
if ( IsUsingWiimote ( 0 ) )
2013-10-29 05:23:17 +00:00
{
2011-12-18 07:27:11 +00:00
// TODO: more detail
PanicAlertT ( " Warning: You loaded a save whose movie mismatches on byte %d (0x%X). You should load another save before continuing, or load this state with read-only mode off. Otherwise you'll probably get a desync. " , i + 256 , i + 256 ) ;
2014-09-08 23:13:49 +00:00
memcpy ( tmpInput , movInput , s_currentByte ) ;
2011-12-18 07:27:11 +00:00
}
2011-12-14 12:03:05 +00:00
else
2011-12-18 07:27:11 +00:00
{
2014-09-09 00:15:47 +00:00
int frame = i / 8 ;
2011-12-18 07:27:11 +00:00
ControllerState curPadState ;
memcpy ( & curPadState , & ( tmpInput [ frame * 8 ] ) , 8 ) ;
ControllerState movPadState ;
memcpy ( & movPadState , & ( movInput [ frame * 8 ] ) , 8 ) ;
PanicAlertT ( " Warning: You loaded a save whose movie mismatches on frame %d. You should load another save before continuing, or load this state with read-only mode off. Otherwise you'll probably get a desync. \n \n "
" More information: The current movie is %d frames long and the savestate's movie is %d frames long. \n \n "
" On frame %d, the current movie presses: \n "
" Start=%d, A=%d, B=%d, X=%d, Y=%d, Z=%d, DUp=%d, DDown=%d, DLeft=%d, DRight=%d, L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d "
" \n \n "
" On frame %d, the savestate's movie presses: \n "
" Start=%d, A=%d, B=%d, X=%d, Y=%d, Z=%d, DUp=%d, DDown=%d, DLeft=%d, DRight=%d, L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d " ,
( int ) frame ,
( int ) g_totalFrames , ( int ) tmpHeader . frameCount ,
( int ) frame ,
( int ) curPadState . Start , ( int ) curPadState . A , ( int ) curPadState . B , ( int ) curPadState . X , ( int ) curPadState . Y , ( int ) curPadState . Z , ( int ) curPadState . DPadUp , ( int ) curPadState . DPadDown , ( int ) curPadState . DPadLeft , ( int ) curPadState . DPadRight , ( int ) curPadState . L , ( int ) curPadState . R , ( int ) curPadState . TriggerL , ( int ) curPadState . TriggerR , ( int ) curPadState . AnalogStickX , ( int ) curPadState . AnalogStickY , ( int ) curPadState . CStickX , ( int ) curPadState . CStickY ,
( int ) frame ,
( int ) movPadState . Start , ( int ) movPadState . A , ( int ) movPadState . B , ( int ) movPadState . X , ( int ) movPadState . Y , ( int ) movPadState . Z , ( int ) movPadState . DPadUp , ( int ) movPadState . DPadDown , ( int ) movPadState . DPadLeft , ( int ) movPadState . DPadRight , ( int ) movPadState . L , ( int ) movPadState . R , ( int ) movPadState . TriggerL , ( int ) movPadState . TriggerR , ( int ) movPadState . AnalogStickX , ( int ) movPadState . AnalogStickY , ( int ) movPadState . CStickX , ( int ) movPadState . CStickY ) ;
2013-06-21 05:53:50 +00:00
2011-12-18 07:27:11 +00:00
}
2011-12-14 12:03:05 +00:00
break ;
}
}
2012-03-24 17:41:13 +00:00
delete [ ] movInput ;
2011-12-14 12:03:05 +00:00
}
}
2011-05-03 00:06:44 +00:00
t_record . Close ( ) ;
2011-12-14 12:03:05 +00:00
2014-09-08 23:13:49 +00:00
s_bSaveConfig = tmpHeader . bSaveConfig ;
2011-07-11 20:15:05 +00:00
2011-12-18 07:27:11 +00:00
if ( ! afterEnd )
2011-07-11 20:15:05 +00:00
{
2014-09-08 23:13:49 +00:00
if ( s_bReadOnly )
2011-12-14 12:03:05 +00:00
{
2014-09-08 23:13:49 +00:00
if ( s_playMode ! = MODE_PLAYING )
2011-12-18 07:27:11 +00:00
{
2014-09-08 23:13:49 +00:00
s_playMode = MODE_PLAYING ;
2011-12-18 07:27:11 +00:00
Core : : DisplayMessage ( " Switched to playback " , 2000 ) ;
}
}
else
{
2014-09-08 23:13:49 +00:00
if ( s_playMode ! = MODE_RECORDING )
2011-12-18 07:27:11 +00:00
{
2014-09-08 23:13:49 +00:00
s_playMode = MODE_RECORDING ;
2011-12-18 07:27:11 +00:00
Core : : DisplayMessage ( " Switched to recording " , 2000 ) ;
}
2011-12-14 12:03:05 +00:00
}
2011-07-11 20:15:05 +00:00
}
else
{
2011-12-18 07:27:11 +00:00
EndPlayInput ( false ) ;
2011-12-14 12:03:05 +00:00
}
}
static void CheckInputEnd ( )
{
2014-09-08 23:13:49 +00:00
if ( g_currentFrame > g_totalFrames | | s_currentByte > = s_totalBytes | | ( CoreTiming : : GetTicks ( ) > s_totalTickCount & & ! IsRecordingInputFromSaveState ( ) ) )
2011-12-14 12:03:05 +00:00
{
2014-09-08 23:13:49 +00:00
EndPlayInput ( ! s_bReadOnly ) ;
2011-07-11 20:15:05 +00:00
}
2010-08-30 07:05:47 +00:00
}
2014-07-11 02:02:32 +00:00
void PlayController ( GCPadStatus * PadStatus , int controllerID )
2010-06-09 01:37:08 +00:00
{
2012-10-21 21:48:45 +00:00
// Correct playback is entirely dependent on the emulator polling the controllers
// in the same order done during recording
2014-03-09 20:14:26 +00:00
if ( ! IsPlayingInput ( ) | | ! IsUsingPad ( controllerID ) | | tmpInput = = nullptr )
2012-10-21 21:48:45 +00:00
return ;
2014-09-08 23:13:49 +00:00
if ( s_currentByte + 8 > s_totalBytes )
2011-03-11 10:21:46 +00:00
{
2014-09-08 23:13:49 +00:00
PanicAlertT ( " Premature movie end in PlayController. %u + 8 > %u " , ( u32 ) s_currentByte , ( u32 ) s_totalBytes ) ;
EndPlayInput ( ! s_bReadOnly ) ;
2011-05-03 00:06:44 +00:00
return ;
2011-03-11 10:21:46 +00:00
}
2011-06-24 06:50:50 +00:00
2012-10-26 16:06:32 +00:00
// dtm files don't save the mic button or error bit. not sure if they're actually used, but better safe than sorry
2011-06-24 06:50:50 +00:00
signed char e = PadStatus - > err ;
2014-07-11 02:02:32 +00:00
memset ( PadStatus , 0 , sizeof ( GCPadStatus ) ) ;
2011-06-24 06:50:50 +00:00
PadStatus - > err = e ;
2011-12-15 17:22:16 +00:00
2014-09-08 23:13:49 +00:00
memcpy ( & s_padState , & ( tmpInput [ s_currentByte ] ) , 8 ) ;
s_currentByte + = 8 ;
2013-10-29 05:23:17 +00:00
2014-09-08 23:13:49 +00:00
PadStatus - > triggerLeft = s_padState . TriggerL ;
PadStatus - > triggerRight = s_padState . TriggerR ;
2011-02-17 09:12:36 +00:00
2014-09-08 23:13:49 +00:00
PadStatus - > stickX = s_padState . AnalogStickX ;
PadStatus - > stickY = s_padState . AnalogStickY ;
2011-02-17 09:12:36 +00:00
2014-09-08 23:13:49 +00:00
PadStatus - > substickX = s_padState . CStickX ;
PadStatus - > substickY = s_padState . CStickY ;
2011-02-17 09:12:36 +00:00
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_USE_ORIGIN ;
2013-10-29 05:23:17 +00:00
2014-09-08 23:13:49 +00:00
if ( s_padState . A )
2011-02-17 09:12:36 +00:00
{
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_BUTTON_A ;
PadStatus - > analogA = 0xFF ;
}
2014-09-08 23:13:49 +00:00
if ( s_padState . B )
2011-02-17 09:12:36 +00:00
{
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_BUTTON_B ;
PadStatus - > analogB = 0xFF ;
}
2014-09-08 23:13:49 +00:00
if ( s_padState . X )
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_BUTTON_X ;
2014-09-08 23:13:49 +00:00
if ( s_padState . Y )
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_BUTTON_Y ;
2014-09-08 23:13:49 +00:00
if ( s_padState . Z )
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_TRIGGER_Z ;
2014-09-08 23:13:49 +00:00
if ( s_padState . Start )
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_BUTTON_START ;
2013-10-29 05:23:17 +00:00
2014-09-08 23:13:49 +00:00
if ( s_padState . DPadUp )
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_BUTTON_UP ;
2014-09-08 23:13:49 +00:00
if ( s_padState . DPadDown )
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_BUTTON_DOWN ;
2014-09-08 23:13:49 +00:00
if ( s_padState . DPadLeft )
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_BUTTON_LEFT ;
2014-09-08 23:13:49 +00:00
if ( s_padState . DPadRight )
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_BUTTON_RIGHT ;
2013-10-29 05:23:17 +00:00
2014-09-08 23:13:49 +00:00
if ( s_padState . L )
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_TRIGGER_L ;
2014-09-08 23:13:49 +00:00
if ( s_padState . R )
2010-06-09 01:37:08 +00:00
PadStatus - > button | = PAD_TRIGGER_R ;
2014-09-08 23:13:49 +00:00
if ( s_padState . disc )
2012-10-20 18:18:42 +00:00
{
// This implementation assumes the disc change will only happen once. Trying to change more than that will cause
// it to load the last disc every time. As far as i know though, there are no 3+ disc games, so this should be fine.
Core : : SetState ( Core : : CORE_PAUSE ) ;
bool found = false ;
std : : string path ;
2014-09-11 05:55:43 +00:00
for ( size_t i = 0 ; i < SConfig : : GetInstance ( ) . m_ISOFolder . size ( ) ; + + i )
2012-10-20 18:18:42 +00:00
{
path = SConfig : : GetInstance ( ) . m_ISOFolder [ i ] ;
2014-03-12 19:33:41 +00:00
if ( File : : Exists ( path + ' / ' + g_discChange ) )
2012-10-20 18:18:42 +00:00
{
found = true ;
break ;
}
}
if ( found )
{
2014-03-12 19:33:41 +00:00
DVDInterface : : ChangeDisc ( path + ' / ' + g_discChange ) ;
2012-10-20 18:18:42 +00:00
Core : : SetState ( Core : : CORE_RUN ) ;
}
else
{
2014-09-09 00:15:47 +00:00
PanicAlertT ( " Change the disc to %s " , g_discChange . c_str ( ) ) ;
2012-10-20 18:18:42 +00:00
}
}
2011-02-17 09:12:36 +00:00
2014-09-08 23:13:49 +00:00
SetInputDisplayString ( s_padState , controllerID ) ;
2011-12-14 12:03:05 +00:00
CheckInputEnd ( ) ;
2010-06-09 01:37:08 +00:00
}
2014-09-30 03:17:59 +00:00
bool PlayWiimote ( int wiimote , u8 * data , const WiimoteEmu : : ReportFeatures & rptf , int ext , const wiimote_key key )
2011-02-11 18:53:51 +00:00
{
2014-03-10 11:30:55 +00:00
if ( ! IsPlayingInput ( ) | | ! IsUsingWiimote ( wiimote ) | | tmpInput = = nullptr )
2011-02-12 08:25:09 +00:00
return false ;
2011-12-15 17:22:16 +00:00
2014-09-08 23:13:49 +00:00
if ( s_currentByte > s_totalBytes )
2011-05-03 00:06:44 +00:00
{
2014-09-08 23:13:49 +00:00
PanicAlertT ( " Premature movie end in PlayWiimote. %u > %u " , ( u32 ) s_currentByte , ( u32 ) s_totalBytes ) ;
EndPlayInput ( ! s_bReadOnly ) ;
2011-05-03 00:06:44 +00:00
return false ;
}
2011-12-15 17:22:16 +00:00
u8 size = rptf . size ;
2014-09-08 23:13:49 +00:00
u8 sizeInMovie = tmpInput [ s_currentByte ] ;
2011-12-15 17:22:16 +00:00
if ( size ! = sizeInMovie )
2011-05-03 00:06:44 +00:00
{
2014-09-08 23:13:49 +00:00
PanicAlertT ( " Fatal desync. Aborting playback. (Error in PlayWiimote: %u != %u, byte %u.)%s " , ( u32 ) sizeInMovie , ( u32 ) size , ( u32 ) s_currentByte ,
( s_numPads & 0xF ) ? " Try re-creating the recording with all GameCube controllers disabled (in Configure > GameCube > Device Settings). " : " " ) ;
EndPlayInput ( ! s_bReadOnly ) ;
2011-12-15 17:22:16 +00:00
return false ;
}
2014-09-08 23:13:49 +00:00
s_currentByte + + ;
2011-12-15 17:22:16 +00:00
2014-09-08 23:13:49 +00:00
if ( s_currentByte + size > s_totalBytes )
2011-12-15 17:22:16 +00:00
{
2014-09-08 23:13:49 +00:00
PanicAlertT ( " Premature movie end in PlayWiimote. %u + %d > %u " , ( u32 ) s_currentByte , size , ( u32 ) s_totalBytes ) ;
EndPlayInput ( ! s_bReadOnly ) ;
2011-05-03 00:06:44 +00:00
return false ;
}
2013-10-29 05:23:17 +00:00
2014-09-08 23:13:49 +00:00
memcpy ( data , & ( tmpInput [ s_currentByte ] ) , size ) ;
s_currentByte + = size ;
2013-10-29 05:23:17 +00:00
2014-09-30 03:17:59 +00:00
SetWiiInputDisplayString ( wiimote , data , rptf , ext , key ) ;
2011-12-14 12:03:05 +00:00
g_currentInputCount + + ;
2013-10-29 05:23:17 +00:00
2011-12-14 12:03:05 +00:00
CheckInputEnd ( ) ;
2011-02-12 08:25:09 +00:00
return true ;
2011-02-11 18:53:51 +00:00
}
2013-10-29 05:23:17 +00:00
void EndPlayInput ( bool cont )
2011-02-15 17:03:20 +00:00
{
2011-05-03 00:06:44 +00:00
if ( cont )
{
2014-09-08 23:13:49 +00:00
s_playMode = MODE_RECORDING ;
2011-12-18 07:27:11 +00:00
Core : : DisplayMessage ( " Reached movie end. Resuming recording. " , 2000 ) ;
2011-02-12 02:14:20 +00:00
}
2014-09-08 23:13:49 +00:00
else if ( s_playMode ! = MODE_NONE )
2011-02-12 02:14:20 +00:00
{
2014-09-08 23:13:49 +00:00
s_rerecords = 0 ;
s_currentByte = 0 ;
s_playMode = MODE_NONE ;
2014-09-06 21:26:40 +00:00
Core : : UpdateWantDeterminism ( ) ;
2011-12-18 07:27:11 +00:00
Core : : DisplayMessage ( " Movie End. " , 2000 ) ;
2014-09-08 23:13:49 +00:00
s_bRecordingFromSaveState = false ;
2011-12-18 07:27:11 +00:00
// we don't clear these things because otherwise we can't resume playback if we load a movie state later
2014-09-08 23:13:49 +00:00
//g_totalFrames = s_totalBytes = 0;
2011-12-18 07:27:11 +00:00
//delete tmpInput;
2014-03-09 20:14:26 +00:00
//tmpInput = nullptr;
2011-02-12 02:14:20 +00:00
}
2010-06-09 01:37:08 +00:00
}
2014-03-12 19:33:41 +00:00
void SaveRecording ( const std : : string & filename )
2010-08-30 07:05:47 +00:00
{
2011-05-03 00:06:44 +00:00
File : : IOFile save_record ( filename , " wb " ) ;
2011-07-11 20:15:05 +00:00
// Create the real header now and write it
DTMHeader header ;
memset ( & header , 0 , sizeof ( DTMHeader ) ) ;
2013-10-29 05:23:17 +00:00
2011-07-11 20:15:05 +00:00
header . filetype [ 0 ] = ' D ' ; header . filetype [ 1 ] = ' T ' ; header . filetype [ 2 ] = ' M ' ; header . filetype [ 3 ] = 0x1A ;
2014-09-09 04:24:49 +00:00
strncpy ( ( char * ) header . gameID , SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . GetUniqueID ( ) . c_str ( ) , 6 ) ;
header . bWii = SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . bWii ;
2014-09-08 23:13:49 +00:00
header . numControllers = s_numPads & ( SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . bWii ? 0xFF : 0x0F ) ;
2013-10-29 05:23:17 +00:00
2014-09-08 23:13:49 +00:00
header . bFromSaveState = s_bRecordingFromSaveState ;
2011-12-14 12:03:05 +00:00
header . frameCount = g_totalFrames ;
2014-09-11 05:55:43 +00:00
header . lagCount = s_totalLagCount ;
2011-12-14 12:03:05 +00:00
header . inputCount = g_totalInputCount ;
2014-09-08 23:13:49 +00:00
header . numRerecords = s_rerecords ;
header . recordingStartTime = s_recordingStartTime ;
2012-10-18 08:18:40 +00:00
header . bSaveConfig = true ;
2014-09-08 23:13:49 +00:00
header . bSkipIdle = s_bSkipIdle ;
header . bDualCore = s_bDualCore ;
header . bProgressive = s_bProgressive ;
header . bDSPHLE = s_bDSPHLE ;
header . bFastDiscSpeed = s_bFastDiscSpeed ;
strncpy ( ( char * ) header . videoBackend , s_videoBackend . c_str ( ) , ArraySize ( header . videoBackend ) ) ;
header . CPUCore = s_iCPUCore ;
2012-10-18 08:18:40 +00:00
header . bEFBAccessEnable = g_ActiveConfig . bEFBAccessEnable ;
header . bEFBCopyEnable = g_ActiveConfig . bEFBCopyEnable ;
header . bCopyEFBToTexture = g_ActiveConfig . bCopyEFBToTexture ;
header . bEFBCopyCacheEnable = g_ActiveConfig . bEFBCopyCacheEnable ;
header . bEFBEmulateFormatChanges = g_ActiveConfig . bEFBEmulateFormatChanges ;
header . bUseXFB = g_ActiveConfig . bUseXFB ;
header . bUseRealXFB = g_ActiveConfig . bUseRealXFB ;
2014-09-08 23:13:49 +00:00
header . memcards = s_memcards ;
2012-10-25 06:44:30 +00:00
header . bClearSave = g_bClearSave ;
2014-09-08 23:13:49 +00:00
header . bSyncGPU = s_bSyncGPU ;
header . bNetPlay = s_bNetPlay ;
2013-09-12 00:19:36 +00:00
strncpy ( ( char * ) header . discChange , g_discChange . c_str ( ) , ArraySize ( header . discChange ) ) ;
2014-09-08 23:13:49 +00:00
strncpy ( ( char * ) header . author , s_author . c_str ( ) , ArraySize ( header . author ) ) ;
memcpy ( header . md5 , s_MD5 , 16 ) ;
header . bongos = s_bongos ;
memcpy ( header . revision , s_revision , ArraySize ( header . revision ) ) ;
header . DSPiromHash = s_DSPiromHash ;
header . DSPcoefHash = s_DSPcoefHash ;
header . tickCount = s_totalTickCount ;
2012-10-18 08:18:40 +00:00
2011-07-11 20:15:05 +00:00
// TODO
2013-10-29 05:23:17 +00:00
header . uniqueID = 0 ;
2011-07-11 20:15:05 +00:00
// header.audioEmulator;
2012-10-20 23:54:38 +00:00
2011-07-11 20:15:05 +00:00
save_record . WriteArray ( & header , 1 ) ;
2011-02-12 02:14:20 +00:00
2014-09-08 23:13:49 +00:00
bool success = save_record . WriteArray ( tmpInput , ( size_t ) s_totalBytes ) ;
2011-02-12 02:14:20 +00:00
2014-09-08 23:13:49 +00:00
if ( success & & s_bRecordingFromSaveState )
2011-02-15 09:07:55 +00:00
{
2014-03-12 19:33:41 +00:00
std : : string stateFilename = filename + " .sav " ;
2011-03-01 03:06:14 +00:00
success = File : : Copy ( tmpStateFilename , stateFilename ) ;
2011-02-15 09:07:55 +00:00
}
2013-10-29 05:23:17 +00:00
2011-02-12 02:14:20 +00:00
if ( success )
2014-03-12 19:33:41 +00:00
Core : : DisplayMessage ( StringFromFormat ( " DTM %s saved " , filename . c_str ( ) ) , 2000 ) ;
2010-08-30 07:05:47 +00:00
else
2014-03-12 19:33:41 +00:00
Core : : DisplayMessage ( StringFromFormat ( " Failed to save %s " , filename . c_str ( ) ) , 2000 ) ;
2010-08-30 07:05:47 +00:00
}
2011-06-24 06:50:50 +00:00
2014-09-15 03:42:32 +00:00
void SetGCInputManip ( GCManipFunction func )
2011-06-24 06:50:50 +00:00
{
2014-09-15 03:42:32 +00:00
gcmfunc = func ;
}
void SetWiiInputManip ( WiiManipFunction func )
{
wiimfunc = func ;
2011-06-24 06:50:50 +00:00
}
2014-09-15 03:42:32 +00:00
void CallGCInputManip ( GCPadStatus * PadStatus , int controllerID )
{
if ( gcmfunc )
( * gcmfunc ) ( PadStatus , controllerID ) ;
}
void CallWiiInputManip ( u8 * data , WiimoteEmu : : ReportFeatures rptf , int controllerID )
2011-06-24 06:50:50 +00:00
{
2014-09-15 03:42:32 +00:00
if ( wiimfunc )
( * wiimfunc ) ( data , rptf , controllerID ) ;
2011-06-24 06:50:50 +00:00
}
2012-10-18 08:18:40 +00:00
void SetGraphicsConfig ( )
{
g_Config . bEFBAccessEnable = tmpHeader . bEFBAccessEnable ;
g_Config . bEFBCopyEnable = tmpHeader . bEFBCopyEnable ;
g_Config . bCopyEFBToTexture = tmpHeader . bCopyEFBToTexture ;
g_Config . bEFBCopyCacheEnable = tmpHeader . bEFBCopyCacheEnable ;
g_Config . bEFBEmulateFormatChanges = tmpHeader . bEFBEmulateFormatChanges ;
g_Config . bUseXFB = tmpHeader . bUseXFB ;
g_Config . bUseRealXFB = tmpHeader . bUseRealXFB ;
}
2012-10-24 20:35:52 +00:00
void GetSettings ( )
{
2014-09-08 23:13:49 +00:00
s_bSaveConfig = true ;
s_bSkipIdle = SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . bSkipIdle ;
s_bDualCore = SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . bCPUThread ;
s_bProgressive = SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . bProgressive ;
s_bDSPHLE = SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . bDSPHLE ;
s_bFastDiscSpeed = SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . bFastDiscSpeed ;
s_videoBackend = g_video_backend - > GetName ( ) ;
s_bSyncGPU = SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . bSyncGPU ;
s_iCPUCore = SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . iCPUCore ;
s_bNetPlay = NetPlay : : IsNetPlayRunning ( ) ;
2014-09-09 04:24:49 +00:00
if ( ! SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . bWii )
2012-10-25 06:44:30 +00:00
g_bClearSave = ! File : : Exists ( SConfig : : GetInstance ( ) . m_strMemoryCardA ) ;
2014-09-08 23:13:49 +00:00
s_memcards | = ( SConfig : : GetInstance ( ) . m_EXIDevice [ 0 ] = = EXIDEVICE_MEMORYCARD ) < < 0 ;
s_memcards | = ( SConfig : : GetInstance ( ) . m_EXIDevice [ 1 ] = = EXIDEVICE_MEMORYCARD ) < < 1 ;
2014-04-23 21:51:59 +00:00
unsigned int tmp ;
2013-06-24 13:14:22 +00:00
for ( int i = 0 ; i < 20 ; + + i )
2013-01-19 20:02:02 +00:00
{
2014-04-23 21:51:59 +00:00
sscanf ( & scm_rev_git_str [ 2 * i ] , " %02x " , & tmp ) ;
2014-09-08 23:13:49 +00:00
s_revision [ i ] = tmp ;
2013-01-19 20:02:02 +00:00
}
2014-09-08 23:13:49 +00:00
if ( ! s_bDSPHLE )
2014-04-06 13:28:44 +00:00
{
std : : string irom_file = File : : GetUserPath ( D_GCUSER_IDX ) + DSP_IROM ;
std : : string coef_file = File : : GetUserPath ( D_GCUSER_IDX ) + DSP_COEF ;
if ( ! File : : Exists ( irom_file ) )
irom_file = File : : GetSysDirectory ( ) + GC_SYS_DIR DIR_SEP DSP_IROM ;
if ( ! File : : Exists ( coef_file ) )
coef_file = File : : GetSysDirectory ( ) + GC_SYS_DIR DIR_SEP DSP_COEF ;
std : : vector < u16 > irom ( DSP_IROM_SIZE ) ;
File : : IOFile file_irom ( irom_file , " rb " ) ;
file_irom . ReadArray ( irom . data ( ) , DSP_IROM_SIZE ) ;
file_irom . Close ( ) ;
2014-09-09 00:15:47 +00:00
for ( int i = 0 ; i < DSP_IROM_SIZE ; + + i )
2014-04-06 13:28:44 +00:00
irom [ i ] = Common : : swap16 ( irom [ i ] ) ;
std : : vector < u16 > coef ( DSP_COEF_SIZE ) ;
File : : IOFile file_coef ( coef_file , " rb " ) ;
file_coef . ReadArray ( coef . data ( ) , DSP_COEF_SIZE ) ;
file_coef . Close ( ) ;
2014-09-09 00:15:47 +00:00
for ( int i = 0 ; i < DSP_COEF_SIZE ; + + i )
2014-04-06 13:28:44 +00:00
coef [ i ] = Common : : swap16 ( coef [ i ] ) ;
2014-09-08 23:13:49 +00:00
s_DSPiromHash = HashAdler32 ( ( u8 * ) irom . data ( ) , DSP_IROM_BYTE_SIZE ) ;
s_DSPcoefHash = HashAdler32 ( ( u8 * ) coef . data ( ) , DSP_COEF_BYTE_SIZE ) ;
2014-04-06 13:28:44 +00:00
}
else
{
2014-09-08 23:13:49 +00:00
s_DSPiromHash = 0 ;
s_DSPcoefHash = 0 ;
2014-04-06 13:28:44 +00:00
}
2012-10-24 20:35:52 +00:00
}
2012-11-24 03:23:58 +00:00
void CheckMD5 ( )
{
2014-09-06 11:10:41 +00:00
for ( int i = 0 , n = 0 ; i < 16 ; + + i )
2012-11-24 03:23:58 +00:00
{
2012-11-26 00:26:37 +00:00
if ( tmpHeader . md5 [ i ] ! = 0 )
continue ;
n + + ;
if ( n = = 16 )
return ;
2012-11-24 03:23:58 +00:00
}
2012-11-26 00:26:37 +00:00
Core : : DisplayMessage ( " Verifying checksum... " , 2000 ) ;
2012-11-24 03:23:58 +00:00
unsigned char gameMD5 [ 16 ] ;
char game [ 255 ] ;
2012-11-26 17:29:36 +00:00
memcpy ( game , SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . m_strFilename . c_str ( ) , SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . m_strFilename . size ( ) ) ;
2012-11-24 03:23:58 +00:00
md5_file ( game , gameMD5 ) ;
2014-09-08 23:13:49 +00:00
if ( memcmp ( gameMD5 , s_MD5 , 16 ) = = 0 )
2012-11-26 00:26:37 +00:00
Core : : DisplayMessage ( " Checksum of current game matches the recorded game. " , 2000 ) ;
2012-11-24 03:23:58 +00:00
else
2013-12-23 12:18:28 +00:00
Core : : DisplayMessage ( " Checksum of current game does not match the recorded game! " , 3000 ) ;
2012-11-26 00:26:37 +00:00
}
void GetMD5 ( )
{
Core : : DisplayMessage ( " Calculating checksum of game file... " , 2000 ) ;
2014-09-08 23:13:49 +00:00
memset ( s_MD5 , 0 , sizeof ( s_MD5 ) ) ;
2012-11-26 00:26:37 +00:00
char game [ 255 ] ;
2012-11-26 17:29:36 +00:00
memcpy ( game , SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . m_strFilename . c_str ( ) , SConfig : : GetInstance ( ) . m_LocalCoreStartupParameter . m_strFilename . size ( ) ) ;
2014-09-08 23:13:49 +00:00
md5_file ( game , s_MD5 ) ;
2012-11-26 00:26:37 +00:00
Core : : DisplayMessage ( " Finished calculating checksum. " , 2000 ) ;
2012-11-24 03:23:58 +00:00
}
2012-11-24 23:27:20 +00:00
void Shutdown ( )
{
2014-09-08 23:13:49 +00:00
g_currentInputCount = g_totalInputCount = g_totalFrames = s_totalBytes = s_tickCountAtLastInput = 0 ;
2012-11-24 23:27:20 +00:00
delete [ ] tmpInput ;
2014-03-09 20:14:26 +00:00
tmpInput = nullptr ;
2012-11-26 03:41:48 +00:00
tmpInputAllocated = 0 ;
2012-11-24 23:27:20 +00:00
}
2012-11-26 03:41:48 +00:00
} ;