diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index cb7cffd1c7..90589b479e 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -98,7 +98,7 @@ static bool FixFilenameCase(const std::string &path, std::string &filename) return retValue; } -bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior) +bool FixPathCase(const std::string &basePath, std::string &path, FixPathCaseBehavior behavior) { size_t len = path.size(); @@ -158,25 +158,25 @@ DirectoryFileSystem::~DirectoryFileSystem() { CloseAll(); } -std::string DirectoryFileHandle::GetLocalPath(std::string& basePath, std::string localpath) +std::string DirectoryFileHandle::GetLocalPath(const std::string &basePath, std::string localpath) { if (localpath.empty()) return basePath; if (localpath[0] == '/') - localpath.erase(0,1); - //Convert slashes + localpath.erase(0, 1); + + std::string result = basePath + localpath; #ifdef _WIN32 - for (size_t i = 0; i < localpath.size(); i++) { - if (localpath[i] == '/') - localpath[i] = '\\'; + for (char &c : result) { + if (c == '/') + c = '\\'; } #endif - return basePath + localpath; + return result; } -bool DirectoryFileHandle::Open(std::string &basePath, std::string &fileName, FileAccess access, u32 &error) -{ +bool DirectoryFileHandle::Open(const std::string &basePath, std::string &fileName, FileAccess access, u32 &error) { error = 0; #if HOST_IS_CASE_SENSITIVE @@ -190,7 +190,7 @@ bool DirectoryFileHandle::Open(std::string &basePath, std::string &fileName, Fil // else we try fopen first (in case we're lucky) before simulating case insensitivity #endif - std::string fullName = GetLocalPath(basePath,fileName); + std::string fullName = GetLocalPath(basePath, fileName); VERBOSE_LOG(FILESYS,"Actually opening %s", fullName.c_str()); // On the PSP, truncating doesn't lose data. If you seek later, you'll recover it. @@ -322,6 +322,11 @@ bool DirectoryFileHandle::Open(std::string &basePath, std::string &fileName, Fil } #endif + // Try to detect reads/writes to PSP/GAME to avoid them in replays. + if (fullName.find("/PSP/GAME/") != fullName.npos || fullName.find("\\PSP\\GAME\\") != fullName.npos) { + inGameDir_ = true; + } + return success; } @@ -333,7 +338,7 @@ size_t DirectoryFileHandle::Read(u8* pointer, s64 size) // On a PSP. it actually is truncated, but the data wasn't erased. off_t off = (off_t)Seek(0, FILEMOVE_CURRENT); if (needsTrunc_ <= off) { - return replay_ ? ReplayApplyDiskRead(pointer, 0, (uint32_t)size, CoreTiming::GetGlobalTimeUs()) : 0; + return replay_ ? ReplayApplyDiskRead(pointer, 0, (uint32_t)size, inGameDir_, CoreTiming::GetGlobalTimeUs()) : 0; } if (needsTrunc_ < off + size) { size = needsTrunc_ - off; @@ -344,7 +349,7 @@ size_t DirectoryFileHandle::Read(u8* pointer, s64 size) #else bytesRead = read(hFile, pointer, size); #endif - return replay_ ? ReplayApplyDiskRead(pointer, (uint32_t)bytesRead, (uint32_t)size, CoreTiming::GetGlobalTimeUs()) : bytesRead; + return replay_ ? ReplayApplyDiskRead(pointer, (uint32_t)bytesRead, (uint32_t)size, inGameDir_, CoreTiming::GetGlobalTimeUs()) : bytesRead; } size_t DirectoryFileHandle::Write(const u8* pointer, s64 size) @@ -371,6 +376,10 @@ size_t DirectoryFileHandle::Write(const u8* pointer, s64 size) } } + if (replay_) { + bytesWritten = ReplayApplyDiskWrite(pointer, (uint64_t)bytesWritten, (uint64_t)size, &diskFull, inGameDir_, CoreTiming::GetGlobalTimeUs()); + } + if (diskFull) { ERROR_LOG(FILESYS, "Disk full"); I18NCategory *err = GetI18NCategory("Error"); diff --git a/Core/FileSystems/DirectoryFileSystem.h b/Core/FileSystems/DirectoryFileSystem.h index 7301679964..54742cd3a1 100644 --- a/Core/FileSystems/DirectoryFileSystem.h +++ b/Core/FileSystems/DirectoryFileSystem.h @@ -54,7 +54,7 @@ enum FixPathCaseBehavior { FPC_PARTIAL_ALLOWED, // don't care how many exist (mkdir recursive) }; -bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior); +bool FixPathCase(const std::string &basePath, std::string &path, FixPathCaseBehavior behavior); #endif struct DirectoryFileHandle { @@ -70,12 +70,13 @@ struct DirectoryFileHandle { #endif s64 needsTrunc_ = -1; bool replay_ = true; + bool inGameDir_ = false; DirectoryFileHandle(Flags flags) : replay_(flags != SKIP_REPLAY) { } - std::string GetLocalPath(std::string& basePath, std::string localpath); - bool Open(std::string& basePath, std::string& fileName, FileAccess access, u32 &err); + std::string GetLocalPath(const std::string &basePath, std::string localpath); + bool Open(const std::string &basePath, std::string &fileName, FileAccess access, u32 &err); size_t Read(u8* pointer, s64 size); size_t Write(const u8* pointer, s64 size); size_t Seek(s32 position, FileMove type); diff --git a/Core/Replay.cpp b/Core/Replay.cpp index 145c5b3477..0e76c2c481 100644 --- a/Core/Replay.cpp +++ b/Core/Replay.cpp @@ -118,6 +118,7 @@ static std::vector replayItems; static size_t replayExecPos = 0; static bool replaySaveWroteHeader = false; static ReplayState replayState = ReplayState::IDLE; +static bool replaySawGameDirWrite = false; static size_t replayCtrlPos = 0; static uint32_t lastButtons = 0; @@ -299,6 +300,7 @@ void ReplayAbort() { replayExecPos = 0; replaySaveWroteHeader = false; replayState = ReplayState::IDLE; + replaySawGameDirWrite = false; replayCtrlPos = 0; lastButtons = 0; @@ -439,7 +441,12 @@ uint64_t ReplayApplyDisk64(ReplayAction action, uint64_t result, uint64_t t) { } } -uint32_t ReplayApplyDiskRead(void *data, uint32_t readSize, uint32_t dataSize, uint64_t t) { +uint32_t ReplayApplyDiskRead(void *data, uint32_t readSize, uint32_t dataSize, bool inGameDir, uint64_t t) { + // Ignore PSP/GAME reads if we haven't seen a write there. + if (inGameDir && !replaySawGameDirWrite) { + return readSize; + } + switch (replayState) { case ReplayState::EXECUTE: { @@ -466,6 +473,23 @@ uint32_t ReplayApplyDiskRead(void *data, uint32_t readSize, uint32_t dataSize, u } } +uint64_t ReplayApplyDiskWrite(const void *data, uint64_t writeSize, uint64_t dataSize, bool *diskFull, bool inGameDir, uint64_t t) { + switch (replayState) { + case ReplayState::EXECUTE: + case ReplayState::SAVE: + // Never let the disk return full during replay. + if (diskFull) + *diskFull = false; + if (inGameDir) + replaySawGameDirWrite = true; + return writeSize; + + case ReplayState::IDLE: + default: + return writeSize; + } +} + static int64_t ConvertFromTm(const struct tm *t) { // Remember, mktime modifies. struct tm copy = *t; diff --git a/Core/Replay.h b/Core/Replay.h index 2cb6bbcb85..bcbf7dc6e0 100644 --- a/Core/Replay.h +++ b/Core/Replay.h @@ -68,6 +68,7 @@ void ReplayAbort(); void ReplayApplyCtrl(uint32_t &buttons, uint8_t analog[2][2], uint64_t t); uint32_t ReplayApplyDisk(ReplayAction action, uint32_t result, uint64_t t); uint64_t ReplayApplyDisk64(ReplayAction action, uint64_t result, uint64_t t); -uint32_t ReplayApplyDiskRead(void *data, uint32_t readSize, uint32_t dataSize, uint64_t t); +uint32_t ReplayApplyDiskRead(void *data, uint32_t readSize, uint32_t dataSize, bool inGameDir, uint64_t t); +uint64_t ReplayApplyDiskWrite(const void *data, uint64_t writeSize, uint64_t dataSize, bool *diskFull, bool inGameDir, uint64_t t); PSPFileInfo ReplayApplyDiskFileInfo(const PSPFileInfo &data, uint64_t t); std::vector ReplayApplyDiskListing(const std::vector &data, uint64_t t);