mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-17 17:27:19 +02:00
With "unlock all cosmetics" (and objects) on, the default, ReSkate wrote every installed item into the profile as owned and never removed one, so every mod a player ever tried stayed in the save: 8765 cosmetics and 520 objects in one profile, past the limit that left a player with no items. What is owned is now worked out from what is installed (installed_item_owned): a paid store copy never, every other item while the kind's unlock option is on, and with it off what the profile saved. The catalog given to the game, the owned list, saved outfits, the player card, the Build object browser and the park editor all ask it. Nothing per item is saved any more, and a profile with an option on drops the rows earlier versions saved, once, on the next start. profile_migration_tests checks that drop on a copy of a real save: the rows stay with the options off, are gone after a restart with them on, and nothing else in the profile changes.
80 lines
4.6 KiB
C++
80 lines
4.6 KiB
C++
// Opens a COPY of a real save and reports what loading it changes. Only runs
|
|
// when given a scratch folder holding reskate.sqlite3 (never point it at the
|
|
// live profile folder: loading commits the migrated document).
|
|
// dingosdk_profile_migration_tests <scratch folder>
|
|
#include "Extension/Profile/local_profile.h"
|
|
#include <iostream>
|
|
|
|
namespace {
|
|
std::size_t saved_items(const dingosdk::profile::Snapshot& snapshot, bool objects) {
|
|
const auto& section = objects ? snapshot.extensions.value("object_dropper", dingosdk::Json::object()) : snapshot.customization;
|
|
return section.value("inventory", dingosdk::Json::object()).size();
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
using namespace dingosdk;
|
|
if (argc < 2) {
|
|
std::cout << "No scratch save given; skipped.\n";
|
|
return 0;
|
|
}
|
|
const auto save = std::filesystem::absolute(argv[1]) / "reskate.sqlite3";
|
|
int failures = 0;
|
|
const auto check = [&](bool condition, const char* message) {
|
|
if (!condition) { std::cerr << "FAIL: " << message << '\n'; ++failures; }
|
|
};
|
|
{
|
|
profile::Store store(save);
|
|
const auto snapshot = store.snapshot();
|
|
const auto policy = profile::challenge_policy(snapshot);
|
|
const auto& section = snapshot.extensions.at("challenges");
|
|
std::size_t available{};
|
|
for (const auto& [id, definition] : policy.catalog) available += definition.available;
|
|
std::cout << "challenges: " << policy.catalog.size() << " in catalogue (" << available << " available), "
|
|
<< section.at("catalog").size() << " stored changes, " << section.at("progress").size()
|
|
<< " with progress\n"
|
|
<< "entitlements: " << snapshot.entitlements.size() << "\n";
|
|
check(!policy.catalog.empty(), "the challenge catalogue loads");
|
|
|
|
// Ownership is a rule while a kind's unlock option is on: the rows earlier versions saved
|
|
// for every item they saw go, and nothing else in the profile changes. Off, they stay.
|
|
const auto cosmetics = store.bool_option(profile::unlock_cosmetics_option);
|
|
const auto objects = store.bool_option(profile::unlock_objects_option);
|
|
std::cout << "saved ownership: " << saved_items(snapshot, false) << " cosmetic(s), " << saved_items(snapshot, true)
|
|
<< " object(s)\n";
|
|
store.set_bool_option(profile::unlock_cosmetics_option, false);
|
|
store.set_bool_option(profile::unlock_objects_option, false);
|
|
store.forget_unlocked_inventory();
|
|
check(saved_items(store.snapshot(), false) == saved_items(snapshot, false) &&
|
|
saved_items(store.snapshot(), true) == saved_items(snapshot, true),
|
|
"with the unlock options off, saved ownership stays");
|
|
store.set_bool_option(profile::unlock_cosmetics_option, true);
|
|
store.set_bool_option(profile::unlock_objects_option, true);
|
|
store.forget_unlocked_inventory();
|
|
// (The options as they were, so only the inventory differs from the save that was copied.)
|
|
if (cosmetics) store.set_bool_option(profile::unlock_cosmetics_option, *cosmetics);
|
|
if (objects) store.set_bool_option(profile::unlock_objects_option, *objects);
|
|
}
|
|
{
|
|
profile::Store reopened(save);
|
|
const auto after = reopened.snapshot();
|
|
check(saved_items(after, false) == 0 && saved_items(after, true) == 0, "with the unlock options on, saved ownership is gone after a restart");
|
|
profile::Store original(std::filesystem::absolute(argv[1]) / "original" / "reskate.sqlite3");
|
|
const auto before = original.snapshot();
|
|
auto expected = before, actual = after;
|
|
expected.customization.erase("inventory");
|
|
actual.customization.erase("inventory");
|
|
if (expected.extensions.contains("object_dropper")) expected.extensions.at("object_dropper").erase("inventory");
|
|
if (actual.extensions.contains("object_dropper")) actual.extensions.at("object_dropper").erase("inventory");
|
|
expected.revision = actual.revision = 0;
|
|
check(expected.customization == actual.customization, "outfits, the player card and the rest of customization are unchanged");
|
|
check(expected.extensions == actual.extensions, "every other saved section is unchanged");
|
|
check(expected.bool_options == actual.bool_options && expected.entitlements == actual.entitlements &&
|
|
expected.quests == actual.quests && expected.settings == actual.settings,
|
|
"options, entitlements, quests and settings are unchanged");
|
|
}
|
|
if (failures) return 1;
|
|
std::cout << "profile migration: ok\n";
|
|
return 0;
|
|
}
|