Advertisement
Abahbob

Untitled

Oct 30th, 2013
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 26.76 KB | None | 0 0
  1. // Copyright (C) 2003 Dolphin Project.
  2.  
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, version 2.0.
  6.  
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU General Public License 2.0 for more details.
  11.  
  12. // A copy of the GPL 2.0 should have been included with the program.
  13. // If not, see http://www.gnu.org/licenses/
  14.  
  15. // Official SVN repository and contact information can be found at
  16. // http://code.google.com/p/dolphin-emu/
  17.  
  18. #include "Movie.h"
  19.  
  20. #include "Core.h"
  21. #include "ConfigManager.h"
  22. #include "Thread.h"
  23. #include "FileUtil.h"
  24. #include "PowerPC/PowerPC.h"
  25. #include "HW/SI.h"
  26. #include "HW/Wiimote.h"
  27. #include "HW/WiimoteEmu/WiimoteEmu.h"
  28. #include "HW/WiimoteEmu/WiimoteHid.h"
  29. #include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
  30. #include "VideoBackendBase.h"
  31. #include "State.h"
  32. #include "Timer.h"
  33.  
  34. // large enough for just over 24 hours of single-player recording
  35. #define MAX_DTM_LENGTH (40 * 1024 * 1024)
  36.  
  37. std::mutex cs_frameSkip;
  38.  
  39. namespace Movie {
  40.  
  41. bool g_bFrameStep = false;
  42. bool g_bFrameStop = false;
  43. bool g_bReadOnly = true;
  44. u32 g_rerecords = 0;
  45. PlayMode g_playMode = MODE_NONE;
  46.  
  47. u32 g_framesToSkip = 0, g_frameSkipCounter = 0;
  48.  
  49. u8 g_numPads = 0;
  50. ControllerState g_padState;
  51. DTMHeader tmpHeader;
  52. u8* tmpInput = NULL;
  53. u64 g_currentByte = 0, g_totalBytes = 0;
  54. u64 g_currentFrame = 0, g_totalFrames = 0; // VI
  55. u64 g_currentLagCount = 0, g_totalLagCount = 0; // just stats
  56. u64 g_currentInputCount = 0, g_totalInputCount = 0; // just stats
  57. u64 g_recordingStartTime; // seconds since 1970 that recording started
  58.  
  59. bool g_bRecordingFromSaveState = false;
  60. bool g_bPolled = false;
  61. int g_currentSaveVersion = 0;
  62.  
  63. std::string tmpStateFilename = "dtm.sav";
  64.  
  65. std::string g_InputDisplay[8];
  66.  
  67. ManipFunction mfunc = NULL;
  68.  
  69.  
  70. std::string GetInputDisplay()
  71. {
  72. std::string inputDisplay = "";
  73. for (int i = 0; i < 8; ++i)
  74. if ((g_numPads & (1 << i)) != 0)
  75. inputDisplay.append(g_InputDisplay[i]);
  76. return inputDisplay;
  77. }
  78.  
  79. void FrameUpdate()
  80. {
  81. if (SConfig::GetInstance().m_pauseMovie && IsPlayingInput() && g_currentInputCount == g_totalInputCount -1)
  82. {
  83. Core::SetState(Core::CORE_PAUSE);
  84. }
  85. g_currentFrame++;
  86. if(!g_bPolled)
  87. g_currentLagCount++;
  88.  
  89. if (IsRecordingInput())
  90. {
  91. g_totalFrames = g_currentFrame;
  92. g_totalLagCount = g_currentLagCount;
  93. }
  94.  
  95. if (g_bFrameStep)
  96. {
  97. Core::SetState(Core::CORE_PAUSE);
  98. g_bFrameStep = false;
  99. }
  100.  
  101. // ("framestop") the only purpose of this is to cause interpreter/jit Run() to return temporarily.
  102. // after that we set it back to CPU_RUNNING and continue as normal.
  103. if (g_bFrameStop)
  104. *PowerPC::GetStatePtr() = PowerPC::CPU_STEPPING;
  105.  
  106. if(g_framesToSkip)
  107. FrameSkipping();
  108.  
  109. g_bPolled = false;
  110. }
  111.  
  112. // called when game is booting up, even if no movie is active,
  113. // but potentially after BeginRecordingInput or PlayInput has been called.
  114. void Init()
  115. {
  116. g_bPolled = false;
  117. g_bFrameStep = false;
  118. g_bFrameStop = false;
  119. g_frameSkipCounter = g_framesToSkip;
  120. memset(&g_padState, 0, sizeof(g_padState));
  121. for (int i = 0; i < 8; ++i)
  122. g_InputDisplay[i].clear();
  123.  
  124. if (!IsPlayingInput() && !IsRecordingInput())
  125. {
  126. g_bRecordingFromSaveState = false;
  127. g_rerecords = 0;
  128. g_numPads = 0;
  129. g_currentByte = 0;
  130. g_currentFrame = 0;
  131. g_currentLagCount = 0;
  132. g_currentInputCount = 0;
  133. // we don't clear these things because otherwise we can't resume playback if we load a movie state later
  134. //g_totalFrames = g_totalBytes = 0;
  135. //delete tmpInput;
  136. //tmpInput = NULL;
  137. }
  138. }
  139.  
  140. void InputUpdate()
  141. {
  142. g_currentInputCount++;
  143. if (IsRecordingInput())
  144. g_totalInputCount = g_currentInputCount;
  145. }
  146.  
  147. void SetFrameSkipping(unsigned int framesToSkip)
  148. {
  149. std::lock_guard<std::mutex> lk(cs_frameSkip);
  150.  
  151. g_framesToSkip = framesToSkip;
  152. g_frameSkipCounter = 0;
  153.  
  154. // Don't forget to re-enable rendering in case it wasn't...
  155. // as this won't be changed anymore when frameskip is turned off
  156. if (framesToSkip == 0)
  157. g_video_backend->Video_SetRendering(true);
  158. }
  159.  
  160. void SetPolledDevice()
  161. {
  162. g_bPolled = true;
  163. }
  164.  
  165. void DoFrameStep()
  166. {
  167. if(Core::GetState() == Core::CORE_PAUSE)
  168. {
  169. // if already paused, frame advance for 1 frame
  170. Core::SetState(Core::CORE_RUN);
  171. Core::RequestRefreshInfo();
  172. g_bFrameStep = true;
  173. }
  174. else if(!g_bFrameStep)
  175. {
  176. // if not paused yet, pause immediately instead
  177. Core::SetState(Core::CORE_PAUSE);
  178. }
  179. }
  180.  
  181. void SetFrameStopping(bool bEnabled)
  182. {
  183. g_bFrameStop = bEnabled;
  184. }
  185.  
  186. void SetReadOnly(bool bEnabled)
  187. {
  188. if (g_bReadOnly != bEnabled)
  189. Core::DisplayMessage(bEnabled ? "Read-only mode." : "Read+Write mode.", 1000);
  190.  
  191. g_bReadOnly = bEnabled;
  192. }
  193.  
  194. void FrameSkipping()
  195. {
  196. // Frameskipping will desync movie playback
  197. if (!IsPlayingInput() && !IsRecordingInput())
  198. {
  199. std::lock_guard<std::mutex> lk(cs_frameSkip);
  200.  
  201. g_frameSkipCounter++;
  202. if (g_frameSkipCounter > g_framesToSkip || Core::ShouldSkipFrame(g_frameSkipCounter) == false)
  203. g_frameSkipCounter = 0;
  204.  
  205. g_video_backend->Video_SetRendering(!g_frameSkipCounter);
  206. }
  207. }
  208.  
  209. bool IsRecordingInput()
  210. {
  211. return (g_playMode == MODE_RECORDING);
  212. }
  213.  
  214. bool IsRecordingInputFromSaveState()
  215. {
  216. return g_bRecordingFromSaveState;
  217. }
  218.  
  219. bool IsJustStartingRecordingInputFromSaveState()
  220. {
  221. return IsRecordingInputFromSaveState() && g_currentFrame == 0;
  222. }
  223.  
  224. bool IsPlayingInput()
  225. {
  226. return (g_playMode == MODE_PLAYING);
  227. }
  228.  
  229. bool IsReadOnly()
  230. {
  231. return g_bReadOnly;
  232. }
  233.  
  234. u64 GetRecordingStartTime()
  235. {
  236. return g_recordingStartTime;
  237. }
  238.  
  239. bool IsUsingPad(int controller)
  240. {
  241. return ((g_numPads & (1 << controller)) != 0);
  242. }
  243.  
  244. bool IsUsingWiimote(int wiimote)
  245. {
  246. return ((g_numPads & (1 << (wiimote + 4))) != 0);
  247. }
  248.  
  249. void ChangePads(bool instantly)
  250. {
  251. if (Core::GetState() == Core::CORE_UNINITIALIZED)
  252. return;
  253.  
  254. int controllers = 0;
  255.  
  256. for (int i = 0; i < 4; i++)
  257. if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER)
  258. controllers |= (1 << i);
  259.  
  260. if (instantly && (g_numPads & 0x0F) == controllers)
  261. return;
  262.  
  263. for (int i = 0; i < 4; i++)
  264. if (instantly) // Changes from savestates need to be instantaneous
  265. SerialInterface::AddDevice(IsUsingPad(i) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE, i);
  266. else
  267. SerialInterface::ChangeDevice(IsUsingPad(i) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE, i);
  268. }
  269.  
  270. void ChangeWiiPads(bool instantly)
  271. {
  272. int controllers = 0;
  273.  
  274. for (int i = 0; i < 4; i++)
  275. if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE)
  276. controllers |= (1 << i);
  277.  
  278. // This is important for Wiimotes, because they can desync easily if they get re-activated
  279. if (instantly && (g_numPads >> 4) == controllers)
  280. return;
  281.  
  282. for (int i = 0; i < 4; i++)
  283. {
  284. g_wiimote_sources[i] = IsUsingWiimote(i) ? WIIMOTE_SRC_EMU : WIIMOTE_SRC_NONE;
  285. GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(IsUsingWiimote(i));
  286. }
  287. }
  288.  
  289. bool BeginRecordingInput(int controllers)
  290. {
  291. if(g_playMode != MODE_NONE || controllers == 0)
  292. return false;
  293.  
  294. if (Core::IsRunning())
  295. {
  296. if(File::Exists(tmpStateFilename))
  297. File::Delete(tmpStateFilename);
  298.  
  299. State::SaveAs(tmpStateFilename.c_str());
  300. g_bRecordingFromSaveState = true;
  301. }
  302.  
  303. g_numPads = controllers;
  304. g_currentFrame = g_totalFrames = 0;
  305. g_currentLagCount = g_totalLagCount = 0;
  306. g_currentInputCount = g_totalInputCount = 0;
  307. g_recordingStartTime = Common::Timer::GetLocalTimeSinceJan1970();
  308. g_rerecords = 0;
  309. g_playMode = MODE_RECORDING;
  310.  
  311. delete [] tmpInput;
  312. tmpInput = new u8[MAX_DTM_LENGTH];
  313. g_currentByte = g_totalBytes = 0;
  314.  
  315. Core::DisplayMessage("Starting movie recording", 2000);
  316. return true;
  317. }
  318.  
  319. static void Analog2DToString(u8 x, u8 y, const char* prefix, char* str)
  320. {
  321. if((x <= 1 || x == 128 || x >= 255)
  322. && (y <= 1 || y == 128 || y >= 255))
  323. {
  324. if(x != 128 || y != 128)
  325. {
  326. if(x != 128 && y != 128)
  327. {
  328. sprintf(str, "%s:%s,%s", prefix, x<128?"LEFT":"RIGHT", y<128?"DOWN":"UP");
  329. }
  330. else if(x != 128)
  331. {
  332. sprintf(str, "%s:%s", prefix, x<128?"LEFT":"RIGHT");
  333. }
  334. else
  335. {
  336. sprintf(str, "%s:%s", prefix, y<128?"DOWN":"UP");
  337. }
  338. }
  339. else
  340. {
  341. str[0] = '\0';
  342. }
  343. }
  344. else
  345. {
  346. sprintf(str, "%s:%d,%d", prefix, x, y);
  347. }
  348. }
  349.  
  350. static void Analog1DToString(u8 v, const char* prefix, char* str)
  351. {
  352. if(v > 0)
  353. {
  354. if(v == 255)
  355. {
  356. strcpy(str, prefix);
  357. }
  358. else
  359. {
  360. sprintf(str, "%s:%d", prefix, v);
  361. }
  362. }
  363. else
  364. {
  365. str[0] = '\0';
  366. }
  367. }
  368.  
  369. void SetInputDisplayString(ControllerState padState, int controllerID)
  370. {
  371. char inp[70];
  372. sprintf(inp, "P%d:", controllerID + 1);
  373. g_InputDisplay[controllerID] = inp;
  374.  
  375. if(g_padState.A)
  376. g_InputDisplay[controllerID].append(" A");
  377. if(g_padState.B)
  378. g_InputDisplay[controllerID].append(" B");
  379. if(g_padState.X)
  380. g_InputDisplay[controllerID].append(" X");
  381. if(g_padState.Y)
  382. g_InputDisplay[controllerID].append(" Y");
  383. if(g_padState.Z)
  384. g_InputDisplay[controllerID].append(" Z");
  385. if(g_padState.Start)
  386. g_InputDisplay[controllerID].append(" START");
  387.  
  388. if(g_padState.DPadUp)
  389. g_InputDisplay[controllerID].append(" UP");
  390. if(g_padState.DPadDown)
  391. g_InputDisplay[controllerID].append(" DOWN");
  392. if(g_padState.DPadLeft)
  393. g_InputDisplay[controllerID].append(" LEFT");
  394. if(g_padState.DPadRight)
  395. g_InputDisplay[controllerID].append(" RIGHT");
  396.  
  397. //if(g_padState.L)
  398. //{
  399. // g_InputDisplay[controllerID].append(" L");
  400. //}
  401. //if(g_padState.R)
  402. //{
  403. // g_InputDisplay[controllerID].append(" R");
  404. //}
  405.  
  406. Analog1DToString(g_padState.TriggerL, " L", inp);
  407. g_InputDisplay[controllerID].append(inp);
  408.  
  409. Analog1DToString(g_padState.TriggerR, " R", inp);
  410. g_InputDisplay[controllerID].append(inp);
  411.  
  412. Analog2DToString(g_padState.AnalogStickX, g_padState.AnalogStickY, " ANA", inp);
  413. g_InputDisplay[controllerID].append(inp);
  414.  
  415. Analog2DToString(g_padState.CStickX, g_padState.CStickY, " C", inp);
  416. g_InputDisplay[controllerID].append(inp);
  417.  
  418. g_InputDisplay[controllerID].append("\n");
  419. }
  420.  
  421. void SetWiiInputDisplayString(int remoteID, u8* const coreData, u8* const accelData, u8* const irData)
  422. {
  423. int controllerID = remoteID + 4;
  424.  
  425. char inp[70];
  426. sprintf(inp, "R%d:", remoteID + 1);
  427. g_InputDisplay[controllerID] = inp;
  428.  
  429. if(coreData)
  430. {
  431. wm_core buttons = *(wm_core*)coreData;
  432. if(buttons & WiimoteEmu::Wiimote::PAD_LEFT)
  433. g_InputDisplay[controllerID].append(" LEFT");
  434. if(buttons & WiimoteEmu::Wiimote::PAD_RIGHT)
  435. g_InputDisplay[controllerID].append(" RIGHT");
  436. if(buttons & WiimoteEmu::Wiimote::PAD_DOWN)
  437. g_InputDisplay[controllerID].append(" DOWN");
  438. if(buttons & WiimoteEmu::Wiimote::PAD_UP)
  439. g_InputDisplay[controllerID].append(" UP");
  440. if(buttons & WiimoteEmu::Wiimote::BUTTON_A)
  441. g_InputDisplay[controllerID].append(" A");
  442. if(buttons & WiimoteEmu::Wiimote::BUTTON_B)
  443. g_InputDisplay[controllerID].append(" B");
  444. if(buttons & WiimoteEmu::Wiimote::BUTTON_PLUS)
  445. g_InputDisplay[controllerID].append(" +");
  446. if(buttons & WiimoteEmu::Wiimote::BUTTON_MINUS)
  447. g_InputDisplay[controllerID].append(" -");
  448. if(buttons & WiimoteEmu::Wiimote::BUTTON_ONE)
  449. g_InputDisplay[controllerID].append(" 1");
  450. if(buttons & WiimoteEmu::Wiimote::BUTTON_TWO)
  451. g_InputDisplay[controllerID].append(" 2");
  452. if(buttons & WiimoteEmu::Wiimote::BUTTON_HOME)
  453. g_InputDisplay[controllerID].append(" HOME");
  454. }
  455.  
  456. if(accelData)
  457. {
  458. wm_accel* dt = (wm_accel*)accelData;
  459. sprintf(inp, " ACC:%d,%d,%d", dt->x, dt->y, dt->z);
  460. g_InputDisplay[controllerID].append(inp);
  461. }
  462.  
  463. if(irData) // incomplete
  464. {
  465. sprintf(inp, " IR:%d,%d", ((u8*)irData)[0], ((u8*)irData)[1]);
  466. g_InputDisplay[controllerID].append(inp);
  467. }
  468.  
  469. g_InputDisplay[controllerID].append("\n");
  470. }
  471.  
  472.  
  473.  
  474. void RecordInput(SPADStatus *PadStatus, int controllerID)
  475. {
  476. if(!IsRecordingInput() || !IsUsingPad(controllerID))
  477. return;
  478.  
  479. g_padState.A = ((PadStatus->button & PAD_BUTTON_A) != 0);
  480. g_padState.B = ((PadStatus->button & PAD_BUTTON_B) != 0);
  481. g_padState.X = ((PadStatus->button & PAD_BUTTON_X) != 0);
  482. g_padState.Y = ((PadStatus->button & PAD_BUTTON_Y) != 0);
  483. g_padState.Z = ((PadStatus->button & PAD_TRIGGER_Z) != 0);
  484. g_padState.Start = ((PadStatus->button & PAD_BUTTON_START) != 0);
  485.  
  486. g_padState.DPadUp = ((PadStatus->button & PAD_BUTTON_UP) != 0);
  487. g_padState.DPadDown = ((PadStatus->button & PAD_BUTTON_DOWN) != 0);
  488. g_padState.DPadLeft = ((PadStatus->button & PAD_BUTTON_LEFT) != 0);
  489. g_padState.DPadRight = ((PadStatus->button & PAD_BUTTON_RIGHT) != 0);
  490.  
  491. g_padState.L = ((PadStatus->button & PAD_TRIGGER_L) != 0);
  492. g_padState.R = ((PadStatus->button & PAD_TRIGGER_R) != 0);
  493. g_padState.TriggerL = PadStatus->triggerLeft;
  494. g_padState.TriggerR = PadStatus->triggerRight;
  495.  
  496. g_padState.AnalogStickX = PadStatus->stickX;
  497. g_padState.AnalogStickY = PadStatus->stickY;
  498.  
  499. g_padState.CStickX = PadStatus->substickX;
  500. g_padState.CStickY = PadStatus->substickY;
  501.  
  502.  
  503. memcpy(&(tmpInput[g_currentByte]), &g_padState, 8);
  504. g_currentByte += 8;
  505. g_totalBytes = g_currentByte;
  506.  
  507. SetInputDisplayString(g_padState, controllerID);
  508. }
  509.  
  510. void RecordWiimote(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int irMode)
  511. {
  512. if(!IsRecordingInput() || !IsUsingWiimote(wiimote))
  513. return;
  514.  
  515. u8* const coreData = rptf.core?(data+rptf.core):NULL;
  516. u8* const accelData = rptf.accel?(data+rptf.accel):NULL;
  517. u8* const irData = rptf.ir?(data+rptf.ir):NULL;
  518. u8 size = rptf.size;
  519.  
  520. InputUpdate();
  521. tmpInput[g_currentByte++] = size;
  522. memcpy(&(tmpInput[g_currentByte]), data, size);
  523. g_currentByte += size;
  524. g_totalBytes = g_currentByte;
  525. SetWiiInputDisplayString(wiimote, coreData, accelData, irData);
  526. }
  527.  
  528. bool PlayInput(const char *filename)
  529. {
  530. if(!filename || g_playMode != MODE_NONE)
  531. return false;
  532.  
  533. if(!File::Exists(filename))
  534. return false;
  535.  
  536. File::IOFile g_recordfd;
  537.  
  538. if (!g_recordfd.Open(filename, "rb"))
  539. return false;
  540.  
  541. g_recordfd.ReadArray(&tmpHeader, 1);
  542.  
  543. if(tmpHeader.filetype[0] != 'D' || tmpHeader.filetype[1] != 'T' || tmpHeader.filetype[2] != 'M' || tmpHeader.filetype[3] != 0x1A) {
  544. PanicAlertT("Invalid recording file");
  545. goto cleanup;
  546. }
  547.  
  548. // Load savestate (and skip to frame data)
  549. if(tmpHeader.bFromSaveState)
  550. {
  551. const std::string stateFilename = std::string(filename) + ".sav";
  552. if(File::Exists(stateFilename))
  553. Core::SetStateFileName(stateFilename);
  554. g_bRecordingFromSaveState = true;
  555. }
  556.  
  557. /* TODO: Put this verification somewhere we have the gameID of the played game
  558. // TODO: Replace with Unique ID
  559. if(tmpHeader.uniqueID != 0) {
  560. PanicAlert("Recording Unique ID Verification Failed");
  561. goto cleanup;
  562. }
  563.  
  564. if(strncmp((char *)tmpHeader.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str(), 6)) {
  565. PanicAlert("The recorded game (%s) is not the same as the selected game (%s)", header.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str());
  566. goto cleanup;
  567. }
  568. */
  569.  
  570. g_numPads = tmpHeader.numControllers;
  571. g_rerecords = tmpHeader.numRerecords;
  572.  
  573. g_totalFrames = tmpHeader.frameCount;
  574. g_totalLagCount = tmpHeader.lagCount;
  575. g_totalInputCount = tmpHeader.inputCount;
  576. g_recordingStartTime = tmpHeader.recordingStartTime;
  577.  
  578. g_currentFrame = 0;
  579. g_currentLagCount = 0;
  580. g_currentInputCount = 0;
  581.  
  582. g_playMode = MODE_PLAYING;
  583.  
  584. g_totalBytes = g_recordfd.GetSize() - 256;
  585. delete tmpInput;
  586. tmpInput = new u8[MAX_DTM_LENGTH];
  587. g_recordfd.ReadArray(tmpInput, (size_t)g_totalBytes);
  588. g_currentByte = 0;
  589. g_recordfd.Close();
  590.  
  591. return true;
  592.  
  593. cleanup:
  594. g_recordfd.Close();
  595. return false;
  596. }
  597.  
  598. void DoState(PointerWrap &p)
  599. {
  600. static const int MOVIE_STATE_VERSION = 1;
  601. g_currentSaveVersion = MOVIE_STATE_VERSION;
  602. p.Do(g_currentSaveVersion);
  603. // many of these could be useful to save even when no movie is active,
  604. // and the data is tiny, so let's just save it regardless of movie state.
  605. p.Do(g_currentFrame);
  606. p.Do(g_currentByte);
  607. p.Do(g_currentLagCount);
  608. p.Do(g_currentInputCount);
  609. p.Do(g_bPolled);
  610. // other variables (such as g_totalBytes and g_totalFrames) are set in LoadInput
  611. }
  612.  
  613. void LoadInput(const char *filename)
  614. {
  615. File::IOFile t_record(filename, "r+b");
  616.  
  617. t_record.ReadArray(&tmpHeader, 1);
  618.  
  619. if(tmpHeader.filetype[0] != 'D' || tmpHeader.filetype[1] != 'T' || tmpHeader.filetype[2] != 'M' || tmpHeader.filetype[3] != 0x1A)
  620. {
  621. PanicAlertT("Savestate movie %s is corrupted, movie recording stopping...", filename);
  622. EndPlayInput(false);
  623. return;
  624. }
  625.  
  626. if (!g_bReadOnly)
  627. {
  628. if (g_rerecords > tmpHeader.numRerecords)
  629. {
  630. tmpHeader.numRerecords = g_rerecords;
  631. }
  632. tmpHeader.numRerecords++;
  633. t_record.Seek(0, SEEK_SET);
  634. t_record.WriteArray(&tmpHeader, 1);
  635. }
  636.  
  637. g_numPads = tmpHeader.numControllers;
  638. ChangePads(true);
  639. if (Core::g_CoreStartupParameter.bWii)
  640. ChangeWiiPads(true);
  641.  
  642. u64 totalSavedBytes = t_record.GetSize() - 256;
  643.  
  644. bool afterEnd = false;
  645. if (g_currentByte > totalSavedBytes)
  646. {
  647. //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)g_currentByte+256, (u32)tmpHeader.frameCount, (u32)g_currentFrame);
  648. afterEnd = true;
  649. }
  650.  
  651. if (!g_bReadOnly || tmpInput == NULL)
  652. {
  653. g_totalFrames = tmpHeader.frameCount;
  654. g_totalLagCount = tmpHeader.lagCount;
  655. g_totalInputCount = tmpHeader.inputCount;
  656.  
  657. g_totalBytes = totalSavedBytes;
  658. delete [] tmpInput;
  659. tmpInput = new u8[MAX_DTM_LENGTH];
  660. t_record.ReadArray(tmpInput, (size_t)g_totalBytes);
  661. }
  662. else if (g_currentByte > 0)
  663. {
  664. if (g_currentByte > totalSavedBytes)
  665. {
  666. }
  667. else if (g_currentByte > g_totalBytes)
  668. {
  669. 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)g_currentByte+256, (u32)g_totalBytes+256, (u32)g_currentFrame, (u32)g_totalFrames);
  670. }
  671. else if(g_currentByte > 0 && g_totalBytes > 0)
  672. {
  673. // verify identical from movie start to the save's current frame
  674. u32 len = (u32)g_currentByte;
  675. u8* movInput = new u8[len];
  676. t_record.ReadArray(movInput, (size_t)len);
  677. for (u32 i = 0; i < len; ++i)
  678. {
  679. if (movInput[i] != tmpInput[i])
  680. {
  681. // this is a "you did something wrong" alert for the user's benefit.
  682. // we'll try to say what's going on in excruciating detail, otherwise the user might not believe us.
  683. if(Core::g_CoreStartupParameter.bWii)
  684. {
  685. // TODO: more detail
  686. 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);
  687. }
  688. else
  689. {
  690. int frame = i/8;
  691. ControllerState curPadState;
  692. memcpy(&curPadState, &(tmpInput[frame*8]), 8);
  693. ControllerState movPadState;
  694. memcpy(&movPadState, &(movInput[frame*8]), 8);
  695. 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"
  696. "More information: The current movie is %d frames long and the savestate's movie is %d frames long.\n\n"
  697. "On frame %d, the current movie presses:\n"
  698. "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"
  699. "\n\n"
  700. "On frame %d, the savestate's movie presses:\n"
  701. "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",
  702. (int)frame,
  703. (int)g_totalFrames, (int)tmpHeader.frameCount,
  704. (int)frame,
  705. (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,
  706. (int)frame,
  707. (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);
  708. }
  709. break;
  710. }
  711. }
  712. delete [] movInput;
  713. }
  714. }
  715. t_record.Close();
  716.  
  717. g_rerecords = tmpHeader.numRerecords;
  718.  
  719. if (!afterEnd)
  720. {
  721. if (g_bReadOnly)
  722. {
  723. if(g_playMode != MODE_PLAYING)
  724. {
  725. g_playMode = MODE_PLAYING;
  726. Core::DisplayMessage("Switched to playback", 2000);
  727. }
  728. }
  729. else
  730. {
  731. if(g_playMode != MODE_RECORDING)
  732. {
  733. g_playMode = MODE_RECORDING;
  734. Core::DisplayMessage("Switched to recording", 2000);
  735. }
  736. }
  737. }
  738. else
  739. {
  740. EndPlayInput(false);
  741. }
  742. }
  743.  
  744. static void CheckInputEnd()
  745. {
  746. if (g_currentFrame > g_totalFrames || g_currentByte >= g_totalBytes)
  747. {
  748. EndPlayInput(!g_bReadOnly);
  749. }
  750. }
  751.  
  752. void PlayController(SPADStatus *PadStatus, int controllerID)
  753. {
  754. // Correct playback is entirely dependent on the emulator polling the controllers
  755. // in the same order done during recording
  756. if (!IsPlayingInput() || !IsUsingPad(controllerID) || tmpInput == NULL)
  757. return;
  758.  
  759. if (g_currentByte + 8 > g_totalBytes)
  760. {
  761. PanicAlertT("Premature movie end in PlayController. %u + 8 > %u", (u32)g_currentByte, (u32)g_totalBytes);
  762. EndPlayInput(!g_bReadOnly);
  763. return;
  764. }
  765.  
  766. // dtm files don't save the mic button or error bit. not sure if they're actually
  767. // used, but better safe than sorry
  768. signed char e = PadStatus->err;
  769. memset(PadStatus, 0, sizeof(SPADStatus));
  770. PadStatus->err = e;
  771.  
  772.  
  773. memcpy(&g_padState, &(tmpInput[g_currentByte]), 8);
  774. g_currentByte += 8;
  775.  
  776. PadStatus->triggerLeft = g_padState.TriggerL;
  777. PadStatus->triggerRight = g_padState.TriggerR;
  778.  
  779. PadStatus->stickX = g_padState.AnalogStickX;
  780. PadStatus->stickY = g_padState.AnalogStickY;
  781.  
  782. PadStatus->substickX = g_padState.CStickX;
  783. PadStatus->substickY = g_padState.CStickY;
  784.  
  785. PadStatus->button |= PAD_USE_ORIGIN;
  786.  
  787. if(g_padState.A)
  788. {
  789. PadStatus->button |= PAD_BUTTON_A;
  790. PadStatus->analogA = 0xFF;
  791. }
  792. if(g_padState.B)
  793. {
  794. PadStatus->button |= PAD_BUTTON_B;
  795. PadStatus->analogB = 0xFF;
  796. }
  797. if(g_padState.X)
  798. PadStatus->button |= PAD_BUTTON_X;
  799. if(g_padState.Y)
  800. PadStatus->button |= PAD_BUTTON_Y;
  801. if(g_padState.Z)
  802. PadStatus->button |= PAD_TRIGGER_Z;
  803. if(g_padState.Start)
  804. PadStatus->button |= PAD_BUTTON_START;
  805.  
  806. if(g_padState.DPadUp)
  807. PadStatus->button |= PAD_BUTTON_UP;
  808. if(g_padState.DPadDown)
  809. PadStatus->button |= PAD_BUTTON_DOWN;
  810. if(g_padState.DPadLeft)
  811. PadStatus->button |= PAD_BUTTON_LEFT;
  812. if(g_padState.DPadRight)
  813. PadStatus->button |= PAD_BUTTON_RIGHT;
  814.  
  815. if(g_padState.L)
  816. PadStatus->button |= PAD_TRIGGER_L;
  817. if(g_padState.R)
  818. PadStatus->button |= PAD_TRIGGER_R;
  819.  
  820. SetInputDisplayString(g_padState, controllerID);
  821.  
  822. CheckInputEnd();
  823. }
  824.  
  825. bool PlayWiimote(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int irMode)
  826. {
  827. if(!IsPlayingInput() || !IsUsingWiimote(wiimote) || tmpInput == NULL)
  828. return false;
  829.  
  830. if (g_currentByte > g_totalBytes)
  831. {
  832. PanicAlertT("Premature movie end in PlayWiimote. %u > %u", (u32)g_currentByte, (u32)g_totalBytes);
  833. EndPlayInput(!g_bReadOnly);
  834. return false;
  835. }
  836.  
  837. u8* const coreData = rptf.core?(data+rptf.core):NULL;
  838. u8* const accelData = rptf.accel?(data+rptf.accel):NULL;
  839. u8* const irData = rptf.ir?(data+rptf.ir):NULL;
  840. u8 size = rptf.size;
  841.  
  842. u8 sizeInMovie = tmpInput[g_currentByte];
  843.  
  844. if (size != sizeInMovie)
  845. {
  846. PanicAlertT("Fatal desync. Aborting playback. (Error in PlayWiimote: %u != %u, byte %u.)%s", (u32)sizeInMovie, (u32)size, (u32)g_currentByte, (g_numPads & 0xF)?" Try re-creating the recording with all GameCube controllers disabled (in Configure > Gamecube > Device Settings).":"");
  847. EndPlayInput(!g_bReadOnly);
  848. return false;
  849. }
  850.  
  851. g_currentByte++;
  852.  
  853. if (g_currentByte + size > g_totalBytes)
  854. {
  855. PanicAlertT("Premature movie end in PlayWiimote. %u + %d > %u", (u32)g_currentByte, size, (u32)g_totalBytes);
  856. EndPlayInput(!g_bReadOnly);
  857. return false;
  858. }
  859.  
  860. memcpy(data, &(tmpInput[g_currentByte]), size);
  861. g_currentByte += size;
  862.  
  863. SetWiiInputDisplayString(wiimote, coreData, accelData, irData);
  864.  
  865. g_currentInputCount++;
  866.  
  867. CheckInputEnd();
  868. return true;
  869. }
  870.  
  871. void EndPlayInput(bool cont)
  872. {
  873. if (cont)
  874. {
  875. g_playMode = MODE_RECORDING;
  876. Core::DisplayMessage("Reached movie end. Resuming recording.", 2000);
  877. }
  878. else if(g_playMode != MODE_NONE)
  879. {
  880. g_numPads = g_rerecords = 0;
  881. g_currentByte = 0;
  882. g_playMode = MODE_NONE;
  883. Core::DisplayMessage("Movie End.", 2000);
  884. // we don't clear these things because otherwise we can't resume playback if we load a movie state later
  885. //g_totalFrames = g_totalBytes = 0;
  886. //delete tmpInput;
  887. //tmpInput = NULL;
  888. }
  889. }
  890.  
  891. void SaveRecording(const char *filename)
  892. {
  893. File::IOFile save_record(filename, "wb");
  894.  
  895. // Create the real header now and write it
  896. DTMHeader header;
  897. memset(&header, 0, sizeof(DTMHeader));
  898.  
  899. header.filetype[0] = 'D'; header.filetype[1] = 'T'; header.filetype[2] = 'M'; header.filetype[3] = 0x1A;
  900. strncpy((char *)header.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str(), 6);
  901. header.bWii = Core::g_CoreStartupParameter.bWii;
  902. header.numControllers = g_numPads & (Core::g_CoreStartupParameter.bWii ? 0xFF : 0x0F);
  903.  
  904. header.bFromSaveState = g_bRecordingFromSaveState;
  905. header.frameCount = g_totalFrames;
  906. header.lagCount = g_totalLagCount;
  907. header.inputCount = g_totalInputCount;
  908. header.numRerecords = g_rerecords;
  909. header.recordingStartTime = g_recordingStartTime;
  910.  
  911. // TODO
  912. header.uniqueID = 0;
  913. // header.author;
  914. // header.videoBackend;
  915. // header.audioEmulator;
  916.  
  917. save_record.WriteArray(&header, 1);
  918.  
  919. bool success = save_record.WriteArray(tmpInput, (size_t)g_totalBytes);
  920.  
  921. if (success && g_bRecordingFromSaveState)
  922. {
  923. std::string stateFilename = filename;
  924. stateFilename.append(".sav");
  925. success = File::Copy(tmpStateFilename, stateFilename);
  926. }
  927.  
  928. if (success)
  929. Core::DisplayMessage(StringFromFormat("DTM %s saved", filename).c_str(), 2000);
  930. else
  931. Core::DisplayMessage(StringFromFormat("Failed to save %s", filename).c_str(), 2000);
  932. }
  933.  
  934. void SetInputManip(ManipFunction func)
  935. {
  936. mfunc = func;
  937. }
  938.  
  939. void CallInputManip(SPADStatus *PadStatus, int controllerID)
  940. {
  941. if (mfunc)
  942. (*mfunc)(PadStatus, controllerID);
  943. }
  944. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement