fix/saving: Final storage fix.
Some checks failed
Build (Linux, x86-64) / build-linux-amalgamate (push) Has been cancelled
Build (Linux, x86-64) / build-linux-full (push) Has been cancelled
Format Check / clang-format (push) Has been cancelled
Release Nightly (Linux, x86-64) / release-linux (push) Has been cancelled

This commit is contained in:
JuiceyDev 2026-04-05 02:44:30 +02:00
parent d30e18ef4d
commit 6215e1365f
3 changed files with 73 additions and 23 deletions

View file

@ -216,11 +216,13 @@ void ConsoleSaveFileSplit::RegionFileReference::Decompress() {
unsigned char* dataIn = dataCompressed + 4;
unsigned char* dataInLast = dataCompressed + dataCompressedSize;
while (dataIn != dataInLast) {
while (dataIn < dataInLast) {
unsigned char thisByte = *dataIn++;
if (thisByte == 0) {
if (dataIn >= dataInLast) break;
thisByte = *dataIn++;
if (thisByte == 0) {
if (dataIn + 1 >= dataInLast) break;
unsigned int runLength = (*dataIn++) << 8;
runLength |= (*dataIn++);
runLength += 256;
@ -237,7 +239,6 @@ void ConsoleSaveFileSplit::RegionFileReference::Decompress() {
if (fileEntry->data.length != uncompressedSize) {
// Treat as if it was an empty region file
fileEntry->data.length = 0;
assert(0);
return;
}
}
@ -246,21 +247,24 @@ void ConsoleSaveFileSplit::RegionFileReference::Decompress() {
unsigned char* dataIn = dataCompressed + 4;
unsigned char* dataInLast = dataCompressed + dataCompressedSize;
unsigned char* dataOut = data;
unsigned char* dataOutLast = data + fileEntry->data.length;
while (dataIn != dataInLast) {
while (dataIn < dataInLast && dataOut < dataOutLast) {
unsigned char thisByte = *dataIn++;
if (thisByte == 0) {
if (dataIn >= dataInLast) break;
thisByte = *dataIn++;
if (thisByte == 0) {
if (dataIn + 1 >= dataInLast) break;
unsigned int runLength = (*dataIn++) << 8;
runLength |= (*dataIn++);
runLength += 256;
for (unsigned int i = 0; i < runLength; i++) {
for (unsigned int i = 0; i < runLength && dataOut < dataOutLast; i++) {
*dataOut++ = 0;
}
} else {
unsigned int runLength = thisByte;
for (unsigned int i = 0; i < runLength; i++) {
for (unsigned int i = 0; i < runLength && dataOut < dataOutLast; i++) {
*dataOut++ = 0;
}
}
@ -274,7 +278,6 @@ void ConsoleSaveFileSplit::RegionFileReference::Decompress() {
free(data);
fileEntry->data.length = 0;
data = nullptr;
assert(0);
}
// std::int64_t endTime = System::currentTimeMillis();
// app.DebugPrintf("Decompressing region file from 0x%.8x %d to %d bytes -
@ -437,6 +440,7 @@ void ConsoleSaveFileSplit::_init(const std::wstring& fileName, void* pvSaveData,
// Get details of region files. From this point on we are responsible for
// the memory that the storage manager initially allocated for them
unsigned int regionCount = PlatformStorage.GetSubfileCount();
for (unsigned int i = 0; i < regionCount; i++) {
unsigned int regionIndex;
unsigned char* regionDataCompressed;
@ -446,8 +450,14 @@ void ConsoleSaveFileSplit::_init(const std::wstring& fileName, void* pvSaveData,
(void**)&regionDataCompressed,
&regionSizeCompressed);
unsigned char* copiedData = nullptr;
if (regionSizeCompressed > 0 && regionDataCompressed) {
copiedData = (unsigned char*)malloc(regionSizeCompressed);
memcpy(copiedData, regionDataCompressed, regionSizeCompressed);
}
RegionFileReference* regionFileRef = new RegionFileReference(
i, regionIndex, regionSizeCompressed, regionDataCompressed);
regionIndex, regionIndex, regionSizeCompressed, copiedData);
if (regionSizeCompressed > 0) {
regionFileRef->Decompress();
} else {
@ -493,10 +503,12 @@ void ConsoleSaveFileSplit::_init(const std::wstring& fileName, void* pvSaveData,
PlatformStorage.GetSaveData(pvSaveMem, &storageLength);
app.DebugPrintf("Filesize - %d, Adjusted size - %d\n", fileSize,
storageLength);
fileSize = storageLength;
}
int compressed = *(int*)pvSaveMem;
if (compressed == 0) {
unsigned int decompSize = *((int*)pvSaveMem + 1);
@ -1288,6 +1300,7 @@ void ConsoleSaveFileSplit::Flush(bool autosave, bool updateThumbnail) {
unsigned int fileSize = header.GetFileSize();
// Assume that the compression will make it smaller so initially attempt to
// allocate the current file size We add 4 bytes to the start so that we can
// signal compressed data And another 4 bytes to store the decompressed data

View file

@ -203,6 +203,7 @@ void FileHeader::ReadHeader(
// based PlayerUID
// : Bumped it to 8 for Durango v1 when to save the chunks in a
// different compressed format
case SAVE_FILE_VERSION_CHUNK_INHABITED_TIME:
case SAVE_FILE_VERSION_COMPRESSED_CHUNK_STORAGE:
case SAVE_FILE_VERSION_DURANGO_CHANGE_MAP_DATA_MAPPING_SIZE:
case SAVE_FILE_VERSION_CHANGE_MAP_DATA_MAPPING_SIZE:

View file

@ -33,8 +33,11 @@ static unsigned int s_SaveBufferSize = 0;
struct SubfileData {
std::vector<std::uint8_t> data;
};
#include <mutex>
static std::map<int, SubfileData> s_Subfiles;
static int s_SubfileCounter = 0;
static std::mutex s_SubfileMutex;
// helper functions
static StdFileIO s_FileIO;
@ -87,8 +90,11 @@ void C4JStorage::Init(unsigned int uiSaveVersion,
void C4JStorage::ResetSaveData() {
s_CurrentSaveTitle = L"New World";
s_CurrentSaveFilename = "";
s_Subfiles.clear();
s_SubfileCounter = 0;
{
std::lock_guard<std::mutex> lock(s_SubfileMutex);
s_Subfiles.clear();
s_SubfileCounter = 0;
}
if (s_SaveBuffer) {
free(s_SaveBuffer);
s_SaveBuffer = nullptr;
@ -314,19 +320,33 @@ C4JStorage::ESaveGameState C4JStorage::LoadSaveData(
s_SaveBufferSize = (unsigned int)blobData.size();
s_SaveBuffer = (std::uint8_t*)malloc(s_SaveBufferSize);
memcpy(s_SaveBuffer, blobData.data(), s_SaveBufferSize);
}
// put in mem
s_Subfiles.clear();
for (int i = 0; i < 50; i++) {
auto subData = s_FileIO.readFileToVec(
GetSaveFile(s_CurrentSaveFilename,
"subfile_" + std::to_string(i) + ".dat"));
if (!subData.empty()) {
SubfileData sd;
sd.data = std::move(subData);
s_Subfiles[i] = std::move(sd);
{
std::lock_guard<std::mutex> lock(s_SubfileMutex);
s_Subfiles.clear();
int maxIndex = -1;
auto dir = GetSaveDir(s_CurrentSaveFilename);
std::error_code ec;
for (const auto& entry : std::filesystem::directory_iterator(dir, ec)) {
if (!entry.is_regular_file()) continue;
std::string filename = entry.path().filename().string();
if (filename.find("subfile_") == 0 && filename.find(".dat") == filename.size() - 4) {
try {
int i = std::stoi(filename.substr(8, filename.size() - 12));
auto subData = s_FileIO.readFileToVec(entry.path());
if (!subData.empty()) {
SubfileData sd;
sd.data = std::move(subData);
s_Subfiles[i] = std::move(sd);
if (i > maxIndex) maxIndex = i;
}
} catch (...) {}
}
}
s_SubfileCounter = maxIndex + 1;
}
}
@ -426,17 +446,30 @@ unsigned int C4JStorage::CRC(unsigned char* buf, int len) {
// that fucking bird that i hate
int C4JStorage::AddSubfile(int regionIndex) {
s_Subfiles[s_SubfileCounter] = SubfileData();
return s_SubfileCounter++;
std::lock_guard<std::mutex> lock(s_SubfileMutex);
s_Subfiles[regionIndex] = SubfileData();
if (regionIndex >= s_SubfileCounter) {
s_SubfileCounter = regionIndex + 1;
}
return regionIndex;
}
unsigned int C4JStorage::GetSubfileCount() { return s_Subfiles.size(); }
unsigned int C4JStorage::GetSubfileCount() {
std::lock_guard<std::mutex> lock(s_SubfileMutex);
return s_Subfiles.size();
}
void C4JStorage::GetSubfileDetails(unsigned int i, int* regionIndex,
void** data, unsigned int* size) {
auto it = s_Subfiles.find(i);
std::lock_guard<std::mutex> lock(s_SubfileMutex);
auto it = s_Subfiles.begin();
unsigned int index = 0;
while (it != s_Subfiles.end() && index < i) {
++it;
++index;
}
if (it != s_Subfiles.end()) {
if (regionIndex) *regionIndex = 0;
if (regionIndex) *regionIndex = it->first;
if (data) *data = it->second.data.data();
if (size) *size = (unsigned int)it->second.data.size();
} else {
@ -447,15 +480,18 @@ void C4JStorage::GetSubfileDetails(unsigned int i, int* regionIndex,
}
void C4JStorage::ResetSubfiles() {
std::lock_guard<std::mutex> lock(s_SubfileMutex);
s_Subfiles.clear();
s_SubfileCounter = 0;
}
void C4JStorage::UpdateSubfile(int index, void* data, unsigned int size) {
std::lock_guard<std::mutex> lock(s_SubfileMutex);
SubfileData& sd = s_Subfiles[index]; // inserts if missing
sd.data.resize(size);
memcpy(sd.data.data(), data, size);
}
void C4JStorage::SaveSubfiles(std::function<int(const bool)> callback) {
std::lock_guard<std::mutex> lock(s_SubfileMutex);
if (!s_CurrentSaveFilename.empty() && !s_Subfiles.empty()) {
auto dir = GetSaveDir(s_CurrentSaveFilename);
std::error_code ec;