Allow RZD* and GZ2 save file interoperatibility (#2529)

* Allow RZD* and GZ2 save file interoperatibility

Tested loading a wii save from Dusklight
on a GC disk in dusklight, and a GC save from dusklight
on a wii disk in dusklight.

Saves from an actual wii are in .dat form and equivalent
to the payload of a .gci, but with no headers.
No support for those yet.

* code styling
This commit is contained in:
Olivia!!
2026-09-21 17:37:31 +02:00
committed by GitHub
parent e58ddbdb8d
commit cc81157fb8
3 changed files with 17 additions and 11 deletions
+8 -5
View File
@@ -905,18 +905,21 @@ ValueResult<GciHeader> parse_gci(const std::vector<uint8_t>& bytes) {
DiscCompatibility disc_compatibility(const GciHeader& header, const SaveIdentity& identity) {
if (header.game.size() != 4 || identity.game.size() != 4 || header.maker.size() != 2 ||
header.maker != identity.maker)
{
header.maker != identity.maker) {
return DiscCompatibility::Incompatible;
}
if (header.game == identity.game) {
return DiscCompatibility::Exact;
}
if (std::string_view{header.game}.substr(0, 3) == std::string_view{identity.game}.substr(0, 3))
{
if (std::string_view{header.game}.substr(0, 3) == std::string_view{identity.game}.substr(0, 3)) {
return DiscCompatibility::RegionChange;
}
return DiscCompatibility::Incompatible;
if ((std::string_view{header.game}.substr(0, 3) == "RZD" &&
std::string_view{identity.game}.substr(0, 3) == "GZ2") ||
std::string_view{header.game}.substr(0, 3) == "GZ2" &&
std::string_view{identity.game}.substr(0, 3) == "RZD") {
return DiscCompatibility::PlatformChange;
}
}
ValueResult<Artifact> read_artifact(std::string_view location) {
+1
View File
@@ -35,6 +35,7 @@ enum class ModDataAction {
enum class DiscCompatibility {
Exact,
RegionChange,
PlatformChange,
Incompatible,
};
+8 -6
View File
@@ -290,7 +290,8 @@ void confirm_import(Artifact artifact) {
const auto compatibility =
raw ? save_manager::DiscCompatibility::Exact :
save_manager::disc_compatibility(artifact.header, context.value.identity);
const bool changingRegion = compatibility == save_manager::DiscCompatibility::RegionChange;
const bool changingVersion = (compatibility == save_manager::DiscCompatibility::RegionChange ||
compatibility == save_manager::DiscCompatibility::PlatformChange);
if (compatibility == save_manager::DiscCompatibility::Incompatible) {
show_message("Import Failed", "This save does not match the configured disc.", true,
&finish_import_flow);
@@ -344,7 +345,7 @@ void confirm_import(Artifact artifact) {
{
{.label = "Cancel", .onPressed = cancel},
{
.label = changingRegion ? "Import Anyway" : "Import",
.label = changingVersion ? "Import Anyway" : "Import",
.onPressed =
[items, keepModData, hasBundledModData](Modal& modal) {
const auto action = hasBundledModData ? ModDataAction::Replace :
@@ -354,7 +355,7 @@ void confirm_import(Artifact artifact) {
},
.isDisabled =
[items] { return std::ranges::none_of(*items, &ImportItem::selected); },
.icon = changingRegion ? "warning" : "",
.icon = changingVersion ? "warning" : "",
},
},
.onDismiss = cancel,
@@ -374,9 +375,10 @@ void confirm_import(Artifact artifact) {
});
}
} else {
const auto* regionMessage = changingRegion ?
" This save is from a different region than the "
"configured disc and may not work correctly." :
const auto* regionMessage = changingVersion ?
" This save is from a different region or "
"platform than the configured disc and may "
"not work correctly." :
"";
modal->set_body(
fmt::format("{} the <b>{}</b> save?{}{}", replacingSave ? "Replace" : "Import",