maple: base vmu file name on game ID for multidisk games
Build vmu file name with game ID so that all disks of multidisk games share the same vmu (A1 only, or all with libretro when enabled). Rename existing vmu file to new format if none exists. Issue #1556
This commit is contained in:
parent
037dc3b4b9
commit
5fc84acdfb
|
@ -5,6 +5,7 @@
|
|||
#include "hw/pvr/spg.h"
|
||||
#include "audio/audiostream.h"
|
||||
#include "oslib/oslib.h"
|
||||
#include "oslib/storage.h"
|
||||
#include "hw/aica/sgc_if.h"
|
||||
#include "cfg/option.h"
|
||||
#include <zlib.h>
|
||||
|
@ -361,10 +362,25 @@ struct maple_sega_vmu: maple_base
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool fullSave()
|
||||
{
|
||||
if (file == nullptr)
|
||||
return false;
|
||||
if (std::fseek(file, 0, SEEK_SET) != 0) {
|
||||
ERROR_LOG(MAPLE, "VMU %s: I/O error", logical_port);
|
||||
return false;
|
||||
}
|
||||
if (std::fwrite(flash_data, sizeof(flash_data), 1, file) != 1) {
|
||||
ERROR_LOG(MAPLE, "Failed to write the VMU %s to disk", logical_port);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void initializeVmu()
|
||||
{
|
||||
INFO_LOG(MAPLE, "Initialising empty VMU...");
|
||||
INFO_LOG(MAPLE, "Initialising empty VMU %s...", logical_port);
|
||||
|
||||
uLongf dec_sz = sizeof(flash_data);
|
||||
int rv = uncompress(flash_data, &dec_sz, vmu_default, sizeof(vmu_default));
|
||||
|
@ -372,34 +388,44 @@ struct maple_sega_vmu: maple_base
|
|||
verify(rv == Z_OK);
|
||||
verify(dec_sz == sizeof(flash_data));
|
||||
|
||||
if (file != nullptr)
|
||||
{
|
||||
if (std::fwrite(flash_data, sizeof(flash_data), 1, file) != 1)
|
||||
WARN_LOG(MAPLE, "Failed to write the VMU to disk");
|
||||
if (std::fseek(file, 0, SEEK_SET) != 0)
|
||||
WARN_LOG(MAPLE, "VMU: I/O error");
|
||||
}
|
||||
fullSave();
|
||||
}
|
||||
|
||||
void OnSetup() override
|
||||
{
|
||||
memset(flash_data, 0, sizeof(flash_data));
|
||||
memset(lcd_data, 0, sizeof(lcd_data));
|
||||
std::string apath = hostfs::getVmuPath(logical_port);
|
||||
|
||||
file = nowide::fopen(apath.c_str(), "rb+");
|
||||
if (file == nullptr)
|
||||
{
|
||||
INFO_LOG(MAPLE, "Unable to open VMU save file \"%s\", creating new file", apath.c_str());
|
||||
file = nowide::fopen(apath.c_str(), "wb+");
|
||||
if (file == nullptr)
|
||||
ERROR_LOG(MAPLE, "Failed to create VMU save file \"%s\"", apath.c_str());
|
||||
initializeVmu();
|
||||
}
|
||||
|
||||
if (file != nullptr)
|
||||
if (std::fread(flash_data, sizeof(flash_data), 1, file) != 1)
|
||||
WARN_LOG(MAPLE, "Failed to read the VMU from disk");
|
||||
|
||||
// Load existing vmu file if found
|
||||
std::string rpath = hostfs::getVmuPath(logical_port, false);
|
||||
// this might be a storage url
|
||||
FILE *rfile = hostfs::storage().openFile(rpath, "rb");
|
||||
if (rfile == nullptr) {
|
||||
INFO_LOG(MAPLE, "Unable to open VMU file \"%s\", creating new file", rpath.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::fread(flash_data, sizeof(flash_data), 1, rfile) != 1)
|
||||
WARN_LOG(MAPLE, "Failed to read the VMU file \"%s\" from disk", rpath.c_str());
|
||||
std::fclose(rfile);
|
||||
}
|
||||
// Open or create the vmu file to save to
|
||||
std::string wpath = hostfs::getVmuPath(logical_port, true);
|
||||
file = nowide::fopen(wpath.c_str(), "rb+");
|
||||
if (file == nullptr)
|
||||
{
|
||||
file = nowide::fopen(wpath.c_str(), "wb+");
|
||||
if (file == nullptr) {
|
||||
ERROR_LOG(MAPLE, "Failed to create VMU save file \"%s\"", wpath.c_str());
|
||||
}
|
||||
else if (rfile != nullptr)
|
||||
{
|
||||
// VMU file is being renamed so save it fully now
|
||||
// and delete the old file
|
||||
if (fullSave())
|
||||
nowide::remove(rpath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
u8 sum = 0;
|
||||
for (u32 i = 0; i < sizeof(flash_data); i++)
|
||||
|
|
|
@ -44,18 +44,49 @@
|
|||
namespace hostfs
|
||||
{
|
||||
|
||||
std::string getVmuPath(const std::string& port)
|
||||
std::string getVmuPath(const std::string& port, bool save)
|
||||
{
|
||||
if (port == "A1" && config::PerGameVmu && !settings.content.path.empty())
|
||||
return get_game_save_prefix() + "_vmu_save_A1.bin";
|
||||
if (port == "A1" && config::PerGameVmu)
|
||||
{
|
||||
if (settings.platform.isConsole() && !settings.content.gameId.empty())
|
||||
{
|
||||
constexpr std::string_view INVALID_CHARS { " /\\:*?|<>" };
|
||||
std::string vmuName = settings.content.gameId;
|
||||
for (char &c: vmuName)
|
||||
if (INVALID_CHARS.find(c) != INVALID_CHARS.npos)
|
||||
c = '_';
|
||||
vmuName += "_vmu_save_A1.bin";
|
||||
std::string wpath = get_writable_data_path(vmuName);
|
||||
if (save || file_exists(wpath))
|
||||
return wpath;
|
||||
std::string rpath = get_readonly_data_path(vmuName);
|
||||
if (hostfs::storage().exists(rpath))
|
||||
return rpath;
|
||||
if (!settings.content.path.empty())
|
||||
{
|
||||
// Legacy path using the rom file name
|
||||
rpath = get_game_save_prefix() + "_vmu_save_A1.bin";
|
||||
if (file_exists(rpath))
|
||||
return rpath;
|
||||
}
|
||||
return wpath;
|
||||
}
|
||||
if (!settings.content.path.empty())
|
||||
return get_game_save_prefix() + "_vmu_save_A1.bin";
|
||||
}
|
||||
|
||||
char tempy[512];
|
||||
sprintf(tempy, "vmu_save_%s.bin", port.c_str());
|
||||
std::string vmuName = "vmu_save_" + port + ".bin";
|
||||
std::string wpath = get_writable_data_path(vmuName);
|
||||
if (save || file_exists(wpath))
|
||||
return wpath;
|
||||
std::string rpath = get_readonly_data_path(vmuName);
|
||||
if (hostfs::storage().exists(rpath))
|
||||
return rpath;
|
||||
// VMU saves used to be stored in .reicast, not in .reicast/data
|
||||
std::string apath = get_writable_config_path(tempy);
|
||||
if (!file_exists(apath))
|
||||
apath = get_writable_data_path(tempy);
|
||||
return apath;
|
||||
rpath = get_readonly_config_path(vmuName);
|
||||
if (file_exists(rpath))
|
||||
return rpath;
|
||||
return wpath;
|
||||
}
|
||||
|
||||
std::string getArcadeFlashPath()
|
||||
|
|
|
@ -47,7 +47,7 @@ u32 static inline bitscanrev(u32 v)
|
|||
|
||||
namespace hostfs
|
||||
{
|
||||
std::string getVmuPath(const std::string& port);
|
||||
std::string getVmuPath(const std::string& port, bool save);
|
||||
|
||||
std::string getArcadeFlashPath();
|
||||
|
||||
|
|
|
@ -34,21 +34,35 @@ extern std::string arcadeFlashPath;
|
|||
namespace hostfs
|
||||
{
|
||||
|
||||
std::string getVmuPath(const std::string& port)
|
||||
std::string getVmuPath(const std::string& port, bool save)
|
||||
{
|
||||
char filename[PATH_MAX + 8];
|
||||
|
||||
if ((per_content_vmus == 1 && port == "A1")
|
||||
|| per_content_vmus == 2)
|
||||
{
|
||||
sprintf(filename, "%s.%s.bin", content_name, port.c_str());
|
||||
return std::string(vmu_dir_no_slash) + std::string(path_default_slash()) + filename;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(filename, "vmu_save_%s.bin", port.c_str());
|
||||
return std::string(game_dir_no_slash) + std::string(path_default_slash()) + filename;
|
||||
}
|
||||
if ((per_content_vmus == 1 && port == "A1")
|
||||
|| per_content_vmus == 2)
|
||||
{
|
||||
std::string vmuDir = vmu_dir_no_slash + std::string(path_default_slash());
|
||||
if (settings.platform.isConsole() && !settings.content.gameId.empty())
|
||||
{
|
||||
constexpr std::string_view INVALID_CHARS { " /\\:*?|<>" };
|
||||
std::string vmuName = settings.content.gameId;
|
||||
for (char &c: vmuName)
|
||||
if (INVALID_CHARS.find(c) != INVALID_CHARS.npos)
|
||||
c = '_';
|
||||
vmuName += "." + port + ".bin";
|
||||
std::string wpath = vmuDir + vmuName;
|
||||
if (save || file_exists(wpath.c_str()))
|
||||
return wpath;
|
||||
// Legacy path with rom name
|
||||
std::string rpath = vmuDir + std::string(content_name) + "." + port + ".bin";
|
||||
if (file_exists(rpath.c_str()))
|
||||
return rpath;
|
||||
else
|
||||
return wpath;
|
||||
}
|
||||
return vmuDir + std::string(content_name) + "." + port + ".bin";
|
||||
}
|
||||
else {
|
||||
return std::string(game_dir_no_slash) + std::string(path_default_slash()) + "vmu_save_" + port + ".bin";
|
||||
}
|
||||
}
|
||||
|
||||
std::string getArcadeFlashPath()
|
||||
|
|
Loading…
Reference in New Issue