/[pcsx2_0.9.7]/branch/debug/0.X/0.9.X/0.9.7/ramdump-lateset/pcsx2/gui/SysState.cpp
ViewVC logotype

Contents of /branch/debug/0.X/0.9.X/0.9.7/ramdump-lateset/pcsx2/gui/SysState.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 330 - (show annotations) (download)
Tue Dec 28 04:24:23 2010 UTC (9 years, 9 months ago) by william
File size: 22179 byte(s)
merged upstream r4154-r4160
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of te License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include "PrecompiledHeader.h"
17 #include "MemoryTypes.h"
18 #include "App.h"
19
20 #include "System/SysThreads.h"
21 #include "SaveState.h"
22 #include "VUmicro.h"
23
24 #include "ZipTools/ThreadedZipTools.h"
25 #include "Utilities/pxStreams.h"
26
27 #include <wx/wfstream.h>
28
29 // Used to hold the current state backup (fullcopy of PS2 memory and plugin states).
30 //static VmStateBuffer state_buffer( L"Public Savestate Buffer" );
31
32 static const wxChar* EntryFilename_StateVersion = L"PCSX2 Savestate Version.id";
33 static const wxChar* EntryFilename_Screenshot = L"Screenshot.jpg";
34 static const wxChar* EntryFilename_InternalStructures = L"PCSX2 Internal Structures.dat";
35
36
37 // --------------------------------------------------------------------------------------
38 // BaseSavestateEntry
39 // --------------------------------------------------------------------------------------
40 class BaseSavestateEntry
41 {
42 protected:
43 BaseSavestateEntry() {}
44 virtual ~BaseSavestateEntry() throw() {}
45
46 public:
47 virtual wxString GetFilename() const=0;
48 virtual void FreezeIn( pxInputStream& reader ) const=0;
49 virtual void FreezeOut( SaveStateBase& writer ) const=0;
50 virtual bool IsRequired() const=0;
51 };
52
53 class MemorySavestateEntry : public BaseSavestateEntry
54 {
55 protected:
56 MemorySavestateEntry() {}
57 virtual ~MemorySavestateEntry() throw() {}
58
59 public:
60 virtual void FreezeIn( pxInputStream& reader ) const;
61 virtual void FreezeOut( SaveStateBase& writer ) const;
62 virtual bool IsRequired() const { return true; }
63
64 protected:
65 virtual u8* GetDataPtr() const=0;
66 virtual uint GetDataSize() const=0;
67 };
68
69 class PluginSavestateEntry : public BaseSavestateEntry
70 {
71 protected:
72 PluginsEnum_t m_pid;
73
74 public:
75 PluginSavestateEntry( PluginsEnum_t pid )
76 {
77 m_pid = pid;
78 }
79
80 virtual ~PluginSavestateEntry() throw() {}
81
82 virtual wxString GetFilename() const;
83 virtual void FreezeIn( pxInputStream& reader ) const;
84 virtual void FreezeOut( SaveStateBase& writer ) const;
85
86 virtual bool IsRequired() const { return false; }
87
88 protected:
89 virtual PluginsEnum_t GetPluginId() const { return m_pid; }
90 };
91
92 void MemorySavestateEntry::FreezeIn( pxInputStream& reader ) const
93 {
94 const uint entrySize = reader.Length();
95 const uint expectedSize = GetDataSize();
96
97 if (entrySize < expectedSize)
98 {
99 Console.WriteLn( Color_Yellow, " '%s' is incomplete (expected 0x%x bytes, loading only 0x%x bytes)",
100 GetFilename().c_str(), expectedSize, entrySize );
101 }
102
103 uint copylen = std::min(entrySize, expectedSize);
104 reader.Read( GetDataPtr(), copylen );
105 }
106
107 void MemorySavestateEntry::FreezeOut( SaveStateBase& writer ) const
108 {
109 writer.FreezeMem( GetDataPtr(), GetDataSize() );
110 }
111
112 wxString PluginSavestateEntry::GetFilename() const
113 {
114 return pxsFmt( "Plugin %s.dat", tbl_PluginInfo[m_pid].shortname );
115 }
116
117 void PluginSavestateEntry::FreezeIn( pxInputStream& reader ) const
118 {
119 GetCorePlugins().FreezeIn( GetPluginId(), reader );
120 }
121
122 void PluginSavestateEntry::FreezeOut( SaveStateBase& writer ) const
123 {
124 if (uint size = GetCorePlugins().GetFreezeSize( GetPluginId() ))
125 {
126 writer.PrepBlock( size );
127 GetCorePlugins().FreezeOut( GetPluginId(), writer.GetBlockPtr() );
128 writer.CommitBlock( size );
129 }
130 }
131
132 // --------------------------------------------------------------------------------------
133 // SavestateEntry_* (EmotionMemory, IopMemory, etc)
134 // --------------------------------------------------------------------------------------
135 // Implementation Rationale:
136 // The address locations of PS2 virtual memory components is fully dynamic, so we need to
137 // resolve the pointers at the time they are requested (eeMem, iopMem, etc). Thusly, we
138 // cannot use static struct member initializers -- we need virtual functions that compute
139 // and resolve the addresses on-demand instead... --air
140
141 class SavestateEntry_EmotionMemory : public MemorySavestateEntry
142 {
143 public:
144 wxString GetFilename() const { return L"eeMemory.bin"; }
145 u8* GetDataPtr() const { return eeMem->Main; }
146 uint GetDataSize() const { return sizeof(eeMem->Main); }
147
148 virtual void FreezeIn( pxInputStream& reader ) const
149 {
150 SysClearExecutionCache();
151 MemorySavestateEntry::FreezeIn( reader );
152 }
153 };
154
155 class SavestateEntry_IopMemory : public MemorySavestateEntry
156 {
157 public:
158 wxString GetFilename() const { return L"iopMemory.bin"; }
159 u8* GetDataPtr() const { return iopMem->Main; }
160 uint GetDataSize() const { return sizeof(iopMem->Main); }
161 };
162
163 class SavestateEntry_HwRegs : public MemorySavestateEntry
164 {
165 public:
166 wxString GetFilename() const { return L"eeHwRegs.bin"; }
167 u8* GetDataPtr() const { return eeHw; }
168 uint GetDataSize() const { return sizeof(eeHw); }
169 };
170
171 class SavestateEntry_IopHwRegs : public MemorySavestateEntry
172 {
173 public:
174 wxString GetFilename() const { return L"iopHwRegs.bin"; }
175 u8* GetDataPtr() const { return iopHw; }
176 uint GetDataSize() const { return sizeof(iopHw); }
177 };
178
179 class SavestateEntry_Scratchpad : public MemorySavestateEntry
180 {
181 public:
182 wxString GetFilename() const { return L"Scratchpad.bin"; }
183 u8* GetDataPtr() const { return eeMem->Scratch; }
184 uint GetDataSize() const { return sizeof(eeMem->Scratch); }
185 };
186
187 class SavestateEntry_VU0mem : public MemorySavestateEntry
188 {
189 public:
190 wxString GetFilename() const { return L"vu0Memory.bin"; }
191 u8* GetDataPtr() const { return vuRegs[0].Mem; }
192 uint GetDataSize() const { return VU0_MEMSIZE; }
193 };
194
195 class SavestateEntry_VU1mem : public MemorySavestateEntry
196 {
197 public:
198 wxString GetFilename() const { return L"vu1Memory.bin"; }
199 u8* GetDataPtr() const { return vuRegs[1].Mem; }
200 uint GetDataSize() const { return VU1_MEMSIZE; }
201 };
202
203 class SavestateEntry_VU0prog : public MemorySavestateEntry
204 {
205 public:
206 wxString GetFilename() const { return L"vu0MicroMem.bin"; }
207 u8* GetDataPtr() const { return vuRegs[0].Micro; }
208 uint GetDataSize() const { return VU0_PROGSIZE; }
209 };
210
211 class SavestateEntry_VU1prog : public MemorySavestateEntry
212 {
213 public:
214 wxString GetFilename() const { return L"vu1MicroMem.bin"; }
215 u8* GetDataPtr() const { return vuRegs[1].Micro; }
216 uint GetDataSize() const { return VU1_PROGSIZE; }
217 };
218
219
220 // [TODO] : Add other components as files to the savestate gzip?
221 // * VU0/VU1 memory banks? VU0prog, VU1prog, VU0data, VU1data.
222 // * GS register data?
223 // * Individual plugins?
224 // (cpuRegs, iopRegs, VPU/GIF/DMAC structures should all remain as part of a larger unified
225 // block, since they're all PCSX2-dependent and having separate files in the archie for them
226 // would not be useful).
227 //
228
229 static const uint NumSavestateEntries = 9 + PluginId_Count;
230
231 class SavestateEntryPack : public ScopedAlloc<const BaseSavestateEntry*>
232 {
233 typedef ScopedAlloc<const BaseSavestateEntry*> _parent;
234
235 public:
236 SavestateEntryPack()
237 : _parent( NumSavestateEntries )
238 {
239 uint i = 0; // more convenient in case we re-arrange anything...
240
241 this->operator[](i++) = new SavestateEntry_EmotionMemory;
242 this->operator[](i++) = new SavestateEntry_IopMemory;
243 this->operator[](i++) = new SavestateEntry_HwRegs;
244 this->operator[](i++) = new SavestateEntry_IopHwRegs;
245 this->operator[](i++) = new SavestateEntry_Scratchpad;
246 this->operator[](i++) = new SavestateEntry_VU0mem;
247 this->operator[](i++) = new SavestateEntry_VU1mem;
248 this->operator[](i++) = new SavestateEntry_VU0prog;
249 this->operator[](i++) = new SavestateEntry_VU1prog;
250
251 this->operator[](i++) = new PluginSavestateEntry( PluginId_GS );
252 this->operator[](i++) = new PluginSavestateEntry( PluginId_PAD );
253 this->operator[](i++) = new PluginSavestateEntry( PluginId_SPU2 );
254 this->operator[](i++) = new PluginSavestateEntry( PluginId_CDVD );
255 this->operator[](i++) = new PluginSavestateEntry( PluginId_USB );
256 this->operator[](i++) = new PluginSavestateEntry( PluginId_FW );
257 this->operator[](i++) = new PluginSavestateEntry( PluginId_DEV9 );
258 }
259
260 using _parent::operator[];
261 };
262
263 static const SavestateEntryPack SavestateEntries;
264
265 // It's bad mojo to have savestates trying to read and write from the same file at the
266 // same time. To prevent that we use this mutex lock, which is used by both the
267 // CompressThread and the UnzipFromDisk events. (note that CompressThread locks the
268 // mutex during OnStartInThread, which ensures that the ZipToDisk event blocks; preventing
269 // the SysExecutor's Idle Event from re-enabing savestates and slots.)
270 //
271 static Mutex mtx_CompressToDisk;
272
273 static void CheckVersion( pxInputStream& thr )
274 {
275 u32 savever;
276 thr.Read( savever );
277
278 // Major version mismatch. Means we can't load this savestate at all. Support for it
279 // was removed entirely.
280 if( savever > g_SaveVersion )
281 throw Exception::SaveStateLoadError( thr.GetStreamName() )
282 .SetDiagMsg(pxsFmt( L"Savestate uses an unsupported or unknown savestate version.\n(PCSX2 ver=%x, state ver=%x)", g_SaveVersion, savever ))
283 .SetUserMsg(_("Cannot load this savestate. The state is from an incompatible edition of PCSX2 that is either newer than this version, or is no longer supported."));
284
285 // check for a "minor" version incompatibility; which happens if the savestate being loaded is a newer version
286 // than the emulator recognizes. 99% chance that trying to load it will just corrupt emulation or crash.
287 if( (savever >> 16) != (g_SaveVersion >> 16) )
288 throw Exception::SaveStateLoadError( thr.GetStreamName() )
289 .SetDiagMsg(pxsFmt( L"Savestate uses an unknown (future?!) savestate version.\n(PCSX2 ver=%x, state ver=%x)", g_SaveVersion, savever ))
290 .SetUserMsg(_("Cannot load this savestate. The state is an unsupported version, likely created by a newer edition of PCSX2."));
291 };
292
293 // --------------------------------------------------------------------------------------
294 // SysExecEvent_DownloadState
295 // --------------------------------------------------------------------------------------
296 // Pauses core emulation and downloads the savestate into a memory buffer. The memory buffer
297 // is then mailed to another thread for zip archiving, while the main emulation process is
298 // allowed to continue execution.
299 //
300 class SysExecEvent_DownloadState : public SysExecEvent
301 {
302 protected:
303 ArchiveEntryList* m_dest_list;
304
305 public:
306 wxString GetEventName() const { return L"VM_Download"; }
307
308 virtual ~SysExecEvent_DownloadState() throw() {}
309 SysExecEvent_DownloadState* Clone() const { return new SysExecEvent_DownloadState( *this ); }
310 SysExecEvent_DownloadState( ArchiveEntryList* dest_list=NULL )
311 {
312 m_dest_list = dest_list;
313 }
314
315 bool IsCriticalEvent() const { return true; }
316 bool AllowCancelOnExit() const { return false; }
317
318 protected:
319 void InvokeEvent()
320 {
321 ScopedCoreThreadPause paused_core;
322
323 if( !SysHasValidState() )
324 throw Exception::RuntimeError()
325 .SetDiagMsg(L"SysExecEvent_DownloadState: Cannot freeze/download an invalid VM state!")
326 .SetUserMsg(L"There is no active virtual machine state to download or save." );
327
328 memSavingState saveme( m_dest_list->GetBuffer() );
329 ArchiveEntry internals( EntryFilename_InternalStructures );
330 internals.SetDataIndex( saveme.GetCurrentPos() );
331
332 saveme.FreezeBios();
333 saveme.FreezeInternals();
334
335 internals.SetDataSize( saveme.GetCurrentPos() - internals.GetDataIndex() );
336 m_dest_list->Add( internals );
337
338 for (uint i=0; i<SavestateEntries.GetSize(); ++i)
339 {
340 uint startpos = saveme.GetCurrentPos();
341 SavestateEntries[i]->FreezeOut( saveme );
342 m_dest_list->Add( ArchiveEntry( SavestateEntries[i]->GetFilename() )
343 .SetDataIndex( startpos )
344 .SetDataSize( saveme.GetCurrentPos() - startpos )
345 );
346 }
347
348 UI_EnableStateActions();
349 paused_core.AllowResume();
350 }
351 };
352
353
354 // --------------------------------------------------------------------------------------
355 // CompressThread_VmState
356 // --------------------------------------------------------------------------------------
357 class VmStateCompressThread : public BaseCompressThread
358 {
359 typedef BaseCompressThread _parent;
360
361 protected:
362 ScopedLock m_lock_Compress;
363
364 public:
365 VmStateCompressThread()
366 {
367 m_lock_Compress.Assign(mtx_CompressToDisk);
368 }
369
370 virtual ~VmStateCompressThread() throw()
371 {
372 }
373
374 protected:
375 void OnStartInThread()
376 {
377 _parent::OnStartInThread();
378 m_lock_Compress.Acquire();
379 }
380
381 void OnCleanupInThread()
382 {
383 m_lock_Compress.Release();
384 _parent::OnCleanupInThread();
385 }
386 };
387
388 // --------------------------------------------------------------------------------------
389 // SysExecEvent_ZipToDisk
390 // --------------------------------------------------------------------------------------
391 class SysExecEvent_ZipToDisk : public SysExecEvent
392 {
393 protected:
394 ArchiveEntryList* m_src_list;
395 wxString m_filename;
396
397 public:
398 wxString GetEventName() const { return L"VM_ZipToDisk"; }
399
400 virtual ~SysExecEvent_ZipToDisk() throw()
401 {
402 }
403
404 SysExecEvent_ZipToDisk* Clone() const { return new SysExecEvent_ZipToDisk( *this ); }
405
406 SysExecEvent_ZipToDisk( ArchiveEntryList& srclist, const wxString& filename )
407 : m_filename( filename )
408 {
409 m_src_list = &srclist;
410 }
411
412 SysExecEvent_ZipToDisk( ArchiveEntryList* srclist, const wxString& filename )
413 : m_filename( filename )
414 {
415 m_src_list = srclist;
416 }
417
418 bool IsCriticalEvent() const { return true; }
419 bool AllowCancelOnExit() const { return false; }
420
421 protected:
422 void InvokeEvent()
423 {
424 // Provisionals for scoped cleanup, in case of exception:
425 ScopedPtr<ArchiveEntryList> elist( m_src_list );
426
427 wxString tempfile( m_filename + L".tmp" );
428
429 wxFFileOutputStream* woot = new wxFFileOutputStream(tempfile);
430 if (!woot->IsOk())
431 throw Exception::CannotCreateStream(tempfile);
432
433 // Write the version and screenshot:
434 ScopedPtr<pxOutputStream> out( new pxOutputStream(tempfile, new wxZipOutputStream(woot)) );
435 wxZipOutputStream* gzfp = (wxZipOutputStream*)out->GetWxStreamBase();
436
437 {
438 wxZipEntry* vent = new wxZipEntry(EntryFilename_StateVersion);
439 vent->SetMethod( wxZIP_METHOD_STORE );
440 gzfp->PutNextEntry( vent );
441 out->Write(g_SaveVersion);
442 gzfp->CloseEntry();
443 }
444
445 ScopedPtr<wxImage> m_screenshot;
446
447 if (m_screenshot)
448 {
449 wxZipEntry* vent = new wxZipEntry(EntryFilename_Screenshot);
450 vent->SetMethod( wxZIP_METHOD_STORE );
451 gzfp->PutNextEntry( vent );
452 m_screenshot->SaveFile( *gzfp, wxBITMAP_TYPE_JPEG );
453 gzfp->CloseEntry();
454 }
455
456 (*new VmStateCompressThread())
457 .SetSource(elist)
458 .SetOutStream(out)
459 .SetFinishedPath(m_filename)
460 .Start();
461
462 // No errors? Release cleanup handlers:
463 elist.DetachPtr();
464 out.DetachPtr();
465 }
466
467 void CleanupEvent()
468 {
469 }
470 };
471
472 // --------------------------------------------------------------------------------------
473 // SysExecEvent_UnzipFromDisk
474 // --------------------------------------------------------------------------------------
475 // Note: Unzipping always goes directly into the SysCoreThread's static VM state, and is
476 // always a blocking action on the SysExecutor thread (the system cannot execute other
477 // commands while states are unzipping or uploading into the system).
478 //
479 class SysExecEvent_UnzipFromDisk : public SysExecEvent
480 {
481 protected:
482 wxString m_filename;
483
484 public:
485 wxString GetEventName() const { return L"VM_UnzipFromDisk"; }
486
487 virtual ~SysExecEvent_UnzipFromDisk() throw() {}
488 SysExecEvent_UnzipFromDisk* Clone() const { return new SysExecEvent_UnzipFromDisk( *this ); }
489 SysExecEvent_UnzipFromDisk( const wxString& filename )
490 : m_filename( filename )
491 {
492 }
493
494 wxString GetStreamName() const { return m_filename; }
495
496 protected:
497 void InvokeEvent()
498 {
499 ScopedLock lock( mtx_CompressToDisk );
500
501 // Ugh. Exception handling made crappy because wxWidgets classes don't support scoped pointers yet.
502
503 ScopedPtr<wxFFileInputStream> woot( new wxFFileInputStream(m_filename) );
504 if (!woot->IsOk())
505 throw Exception::CannotCreateStream( m_filename ).SetDiagMsg(L"Cannot open file for reading.");
506
507 ScopedPtr<pxInputStream> reader( new pxInputStream(m_filename, new wxZipInputStream(woot)) );
508 woot.DetachPtr();
509
510 if (!reader->IsOk())
511 {
512 throw Exception::SaveStateLoadError( m_filename )
513 .SetDiagMsg( L"Savestate file is not a valid gzip archive." )
514 .SetUserMsg(_("This savestate cannot be loaded because it is not a valid gzip archive. It may have been created by an older unsupported version of PCSX2, or it may be corrupted."));
515 }
516
517 wxZipInputStream* gzreader = (wxZipInputStream*)reader->GetWxStreamBase();
518
519 // look for version and screenshot information in the zip stream:
520
521 bool foundVersion = false;
522 //bool foundScreenshot = false;
523 //bool foundEntry[numSavestateEntries] = false;
524
525 ScopedPtr<wxZipEntry> foundInternal;
526 ScopedPtr<wxZipEntry> foundEntry[NumSavestateEntries];
527
528 while(true)
529 {
530 Threading::pxTestCancel();
531
532 ScopedPtr<wxZipEntry> entry( gzreader->GetNextEntry() );
533 if (!entry) break;
534
535 if (entry->GetName().CmpNoCase(EntryFilename_StateVersion) == 0)
536 {
537 DevCon.WriteLn( Color_Green, L" ... found '%s'", EntryFilename_StateVersion);
538 foundVersion = true;
539 CheckVersion(*reader);
540 continue;
541 }
542
543 if (entry->GetName().CmpNoCase(EntryFilename_InternalStructures) == 0)
544 {
545 DevCon.WriteLn( Color_Green, L" ... found '%s'", EntryFilename_InternalStructures);
546 foundInternal = entry.DetachPtr();
547 continue;
548 }
549
550 // No point in finding screenshots when loading states -- the screenshots are
551 // only useful for the UI savestate browser.
552 /*if (entry->GetName().CmpNoCase(EntryFilename_Screenshot) == 0)
553 {
554 foundScreenshot = true;
555 }*/
556
557 for (uint i=0; i<NumSavestateEntries; ++i)
558 {
559 if (entry->GetName().CmpNoCase(SavestateEntries[i]->GetFilename()) == 0)
560 {
561 DevCon.WriteLn( Color_Green, L" ... found '%s'", SavestateEntries[i]->GetFilename().c_str() );
562 foundEntry[i] = entry.DetachPtr();
563 break;
564 }
565 }
566 }
567
568 if (!foundVersion || !foundInternal)
569 {
570 throw Exception::SaveStateLoadError( m_filename )
571 .SetDiagMsg( pxsFmt(L"Savestate file does not contain '%s'",
572 !foundVersion ? EntryFilename_StateVersion : EntryFilename_InternalStructures) )
573 .SetUserMsg(_("This file is not a valid PCSX2 savestate. See the logfile for details."));
574 }
575
576 // Log any parts and pieces that are missing, and then generate an exception.
577 bool throwIt = false;
578 for (uint i=0; i<NumSavestateEntries; ++i)
579 {
580 if (foundEntry[i]) continue;
581
582 if (SavestateEntries[i]->IsRequired())
583 {
584 throwIt = true;
585 Console.WriteLn( Color_Red, " ... not found '%s'!", SavestateEntries[i]->GetFilename().c_str() );
586 }
587 }
588
589 if (throwIt)
590 throw Exception::SaveStateLoadError( m_filename )
591 .SetDiagMsg( L"Savestate cannot be loaded: some required components were not found or are incomplete." )
592 .SetUserMsg(_("This savestate cannot be loaded due to missing critical components. See the log file for details."));
593
594 // We use direct Suspend/Resume control here, since it's desirable that emulation
595 // *ALWAYS* start execution after the new savestate is loaded.
596
597 GetCoreThread().Pause();
598 SysClearExecutionCache();
599
600 for (uint i=0; i<NumSavestateEntries; ++i)
601 {
602 if (!foundEntry[i]) continue;
603
604 Threading::pxTestCancel();
605
606 gzreader->OpenEntry( *foundEntry[i] );
607 SavestateEntries[i]->FreezeIn( *reader );
608 }
609
610 // Load all the internal data
611
612 gzreader->OpenEntry( *foundInternal );
613
614 VmStateBuffer buffer( foundInternal->GetSize(), L"StateBuffer_UnzipFromDisk" ); // start with an 8 meg buffer to avoid frequent reallocation.
615 reader->Read( buffer.GetPtr(), foundInternal->GetSize() );
616
617 memLoadingState( buffer ).FreezeBios().FreezeInternals();
618 GetCoreThread().Resume(); // force resume regardless of emulation state earlier.
619 }
620 };
621
622 // =====================================================================================================
623 // StateCopy Public Interface
624 // =====================================================================================================
625
626 void StateCopy_SaveToFile( const wxString& file )
627 {
628 UI_DisableStateActions();
629
630 ScopedPtr<ArchiveEntryList> ziplist (new ArchiveEntryList( new VmStateBuffer( L"Zippable Savestate" ) ));
631
632 GetSysExecutorThread().PostEvent(new SysExecEvent_DownloadState ( ziplist ));
633 GetSysExecutorThread().PostEvent(new SysExecEvent_ZipToDisk ( ziplist, file ));
634
635 ziplist.DetachPtr();
636 }
637
638 void StateCopy_LoadFromFile( const wxString& file )
639 {
640 UI_DisableSysActions();
641 GetSysExecutorThread().PostEvent(new SysExecEvent_UnzipFromDisk( file ));
642 }
643
644 // Saves recovery state info to the given saveslot, or saves the active emulation state
645 // (if one exists) and no recovery data was found. This is needed because when a recovery
646 // state is made, the emulation state is usually reset so the only persisting state is
647 // the one in the memory save. :)
648 void StateCopy_SaveToSlot( uint num )
649 {
650 const wxString file( SaveStateBase::GetFilename( num ) );
651
652 // Backup old Savestate if one exists.
653 if( wxFileExists( file ) && EmuConfig.BackupSavestate )
654 {
655 const wxString copy( SaveStateBase::GetFilename( num ) + pxsFmt( L".backup") );
656
657 Console.Indent().WriteLn( Color_StrongGreen, L"Backing up existing state in slot %d.", num);
658 wxCopyFile( file, copy );
659 }
660
661 Console.WriteLn( Color_StrongGreen, "Saving savestate to slot %d...", num );
662 Console.Indent().WriteLn( Color_StrongGreen, L"filename: %s", file.c_str() );
663
664 StateCopy_SaveToFile( file );
665 }
666
667 void StateCopy_LoadFromSlot( uint slot )
668 {
669 wxString file( SaveStateBase::GetFilename( slot ) );
670
671 if( !wxFileExists( file ) )
672 {
673 Console.Warning( "Savestate slot %d is empty.", slot );
674 return;
675 }
676
677 Console.WriteLn( Color_StrongGreen, "Loading savestate from slot %d...", slot );
678 Console.Indent().WriteLn( Color_StrongGreen, L"filename: %s", file.c_str() );
679
680 StateCopy_LoadFromFile( file );
681 }

  ViewVC Help
Powered by ViewVC 1.1.22