FolderMemoryCard: Only load data relevant to game. Please read commit description!

Essentially, I'm telling the memory card to re-index itself with a
filter based on the game's disc serial every time a new executable boots
in the emulator.

This currently works for a lot of games, but fails in edge cases where
the game disc's serial does not match the game serial that is written to
the memory card as part of the save file's directory name. This affects
mostly (only?) games that have multiple discs. We could circumvent this
by adding a "save game serial" or something into the GameDatabase which
tells us what we should filter by for those cases.

Apart from this edge case, this appears to work surprisingly well. Try
it and see if you can find other issues!
This commit is contained in:
Admiral H. Curtiss 2015-05-09 20:28:40 +02:00
parent 139e28988d
commit 880be6f602
9 changed files with 69 additions and 7 deletions

View File

@ -1109,7 +1109,9 @@ typedef struct _PS2E_ComponentAPI_Mcd
// Used by the FolderMemoryCard to find a good time to flush written data to the host file system.
void (PS2E_CALLBACK* McdNextFrame)( PS2E_THISPTR thisptr, uint port, uint slot );
void* reserved[7];
void (PS2E_CALLBACK* McdReIndex)( PS2E_THISPTR thisptr, uint port, uint slot, const wxString& filter );
void* reserved[6];
} PS2E_ComponentAPI_Mcd;

View File

@ -70,6 +70,10 @@ void SysPluginBindings::McdNextFrame( uint port, uint slot ) {
Mcd->McdNextFrame( (PS2E_THISPTR) Mcd, port, slot );
}
void SysPluginBindings::McdReIndex( uint port, uint slot, const wxString& filter ) {
Mcd->McdReIndex( (PS2E_THISPTR) Mcd, port, slot, filter );
}
// ----------------------------------------------------------------------------
// Yay, order of this array shouldn't be important. :)
//

View File

@ -242,6 +242,7 @@ public:
void McdEraseBlock( uint port, uint slot, u32 adr );
u64 McdGetCRC( uint port, uint slot );
void McdNextFrame( uint port, uint slot );
void McdReIndex( uint port, uint slot, const wxString& filter );
friend class SysCorePlugins;
};

View File

@ -879,6 +879,20 @@ void sioNextFrame() {
}
}
// Used to figure out when a new game boots, so that memory cards can re-index themselves and only load data relevant to that game.
wxString SioCurrentGameSerial = L"";
void sioSetGameSerial( const wxString& serial ) {
if ( serial == SioCurrentGameSerial ) { return; }
SioCurrentGameSerial = serial;
for ( uint port = 0; port < 2; ++port ) {
for ( uint slot = 0; slot < 4; ++slot ) {
mcds[port][slot].ReIndex( serial );
}
}
SetForceMcdEjectTimeoutNow();
}
void SaveStateBase::sioFreeze()
{
// CRCs for memory cards.

View File

@ -86,6 +86,10 @@ struct _mcd
void NextFrame() {
SysPlugins.McdNextFrame( port, slot );
}
void ReIndex(const wxString& filter = L"") {
SysPlugins.McdReIndex( port, slot, filter );
}
};
struct _sio
@ -124,3 +128,4 @@ extern void sioInterrupt();
extern void InitializeSIO(u8 value);
extern void SetForceMcdEjectTimeoutNow();
extern void sioNextFrame();
extern void sioSetGameSerial(const wxString& serial);

View File

@ -31,6 +31,7 @@
#include "Elfheader.h"
#include "Patch.h"
#include "R5900Exceptions.h"
#include "Sio.h"
__aligned16 SysMtgsThread mtgsThread;
__aligned16 AppCoreThread CoreThread;
@ -382,6 +383,8 @@ void AppCoreThread::ApplySettings( const Pcsx2Config& src )
}
}
sioSetGameSerial( curGameKey );
if (gameName.IsEmpty() && gameSerial.IsEmpty() && gameCRC.IsEmpty())
{
// if all these conditions are met, it should mean that we're currently running BIOS code.

View File

@ -552,6 +552,20 @@ static void PS2E_CALLBACK FileMcd_NextFrame( PS2E_THISPTR thisptr, uint port, ui
}
}
static void PS2E_CALLBACK FileMcd_ReIndex( PS2E_THISPTR thisptr, uint port, uint slot, const wxString& filter ) {
const uint combinedSlot = FileMcd_ConvertToSlot( port, slot );
switch ( g_Conf->Mcd[combinedSlot].Type ) {
//case MemoryCardType::MemoryCard_File:
// thisptr->impl.ReIndex( combinedSlot, filter );
// break;
case MemoryCardType::MemoryCard_Folder:
thisptr->implFolder.ReIndex( combinedSlot, filter );
break;
default:
return;
}
}
Component_FileMcd::Component_FileMcd()
{
memzero( api );
@ -567,6 +581,7 @@ Component_FileMcd::Component_FileMcd()
api.McdEraseBlock = FileMcd_EraseBlock;
api.McdGetCRC = FileMcd_GetCRC;
api.McdNextFrame = FileMcd_NextFrame;
api.McdReIndex = FileMcd_ReIndex;
}

View File

@ -47,6 +47,10 @@ bool FolderMemoryCard::IsFormatted() {
}
void FolderMemoryCard::Open() {
Open( L"" );
}
void FolderMemoryCard::Open( const wxString& filter ) {
InitializeInternalData();
wxFileName configuredFileName( g_Conf->FullpathToMcd( m_slot ) );
@ -80,7 +84,7 @@ void FolderMemoryCard::Open() {
if ( disabled ) return;
m_isEnabled = true;
LoadMemoryCardData();
LoadMemoryCardData( filter );
SetTimeLastWrittenToNow();
m_framesUntilFlush = 0;
@ -98,7 +102,7 @@ void FolderMemoryCard::Close() {
}
}
void FolderMemoryCard::LoadMemoryCardData() {
void FolderMemoryCard::LoadMemoryCardData( const wxString& filter ) {
bool formatted = false;
// read superblock if it exists
@ -115,7 +119,7 @@ void FolderMemoryCard::LoadMemoryCardData() {
CreateFat();
CreateRootDir();
MemoryCardFileEntry* const rootDirEntry = &m_fileEntryDict[m_superBlock.data.rootdir_cluster].entries[0];
AddFolder( rootDirEntry, folderName.GetPath() );
AddFolder( rootDirEntry, folderName.GetPath(), filter );
}
}
@ -260,7 +264,7 @@ MemoryCardFileEntry* FolderMemoryCard::AppendFileEntryToDir( MemoryCardFileEntry
return newFileEntry;
}
bool FolderMemoryCard::AddFolder( MemoryCardFileEntry* const dirEntry, const wxString& dirPath ) {
bool FolderMemoryCard::AddFolder( MemoryCardFileEntry* const dirEntry, const wxString& dirPath, const wxString& filter ) {
wxDir dir( dirPath );
if ( dir.IsOpened() ) {
Console.WriteLn( L"(FolderMcd) Adding folder: %s", WX_STR( dirPath ) );
@ -286,6 +290,14 @@ bool FolderMemoryCard::AddFolder( MemoryCardFileEntry* const dirEntry, const wxS
++entryNumber;
}
} else {
// if possible filter added directories by game serial
// this has the effective result of only files relevant to the current game being loaded into the memory card
// which means every game essentially sees the memory card as if no other files exist
if ( !filter.IsEmpty() && !fileName.Contains( filter ) ) {
hasNext = dir.GetNext( &fileName );
continue;
}
// make sure we have enough space on the memcard for the directory
const u32 newNeededClusters = ( dirEntry->entry.data.length % 2 ) == 0 ? 2 : 1;
if ( newNeededClusters > GetAmountFreeDataClusters() ) {
@ -1029,4 +1041,8 @@ void FolderMemoryCardAggregator::NextFrame( uint slot ) {
m_cards[slot].NextFrame();
}
void FolderMemoryCardAggregator::ReIndex( uint slot, const wxString& filter ) {
m_cards[slot].Close();
m_cards[slot].Open( filter );
}

View File

@ -169,6 +169,7 @@ public:
void Unlock();
void Open();
void Open( const wxString& filter );
void Close();
s32 IsPresent();
@ -219,7 +220,7 @@ protected:
// loads files and folders from the host file system if a superblock exists in the root directory
void LoadMemoryCardData();
void LoadMemoryCardData( const wxString& filter );
// creates the FAT and indirect FAT
void CreateFat();
@ -252,7 +253,7 @@ protected:
// adds a folder in the host file system to the memory card, including all files and subdirectories
// - dirEntry: the entry of the directory in the parent directory, or the root "." entry
// - dirPath: the full path to the directory in the host file system
bool AddFolder( MemoryCardFileEntry* const dirEntry, const wxString& dirPath );
bool AddFolder( MemoryCardFileEntry* const dirEntry, const wxString& dirPath, const wxString& filter = L"" );
// adds a file in the host file sytem to the memory card
// - dirEntry: the entry of the directory in the parent directory, or the root "." entry
@ -313,4 +314,5 @@ public:
s32 EraseBlock( uint slot, u32 adr );
u64 GetCRC( uint slot );
void NextFrame( uint slot );
void ReIndex( uint slot, const wxString& filter );
};