import { REGIONS } from "../config/regions.js"; import { log } from "../core/log.js"; import { world } from "@minecraft/server"; const KEY = "tama.progress"; const VERSION = 1; //For updating the json in the save /** * The in-memory copy of the whole save document, so we don't re-read the * world's dynamic properties every time something needs a value. * Null until load() runs. saveState() writes it back out to the world save. * * cache = { * version: 1, * coins: 0, * gates: { * lagoon: true, * farmland: false, * seaside: false, * skyland: false * } * } */ let cache = null; /** * Reads the save document out of the world and puts it in `cache`. * * Nothing stored under KEY yet means a brand-new world - getDynamicProperty * returns undefined - so build the defaults and write them straight back, * which is what creates the save. * * Otherwise the stored value is JSON text, so parse it back into an object. */ export function load(){ const raw = world.getDynamicProperty(KEY); //let raw = undefined; //good for debugging before the value is updated //console.log(raw); if(raw === undefined) { cache = buildDefaults(); saveState(); } else { //good for debugging post update //console.log(raw); cache = JSON.parse(raw); } if(cache.version < VERSION) { //if(version < (VERSION) -> add attribute etc)) log("=================================="); log(`version: ${cache.version}, code expects ${VERSION}`); log("=================================="); //if attribute === undefined -> set default value cache.version = VERSION; } } /** * Builds a fresh save document for a world that has never been played. * * `gates` is an object (not an array) filled by looping REGIONS and copying * each region's unlockedAtStart value, so adding a region to the config * automatically adds its gate here with no change to this function. */ function buildDefaults() { const gates = {}; const coins = 0; for(const id in REGIONS) { gates[id] = REGIONS[id].unlockedAtStart; } return{version: VERSION, gates: gates, coins: coins}; } /** * Returns the cached save document. * This is the live object, not a copy - anything that mutates what comes back * must call saveState() afterwards, or the change is lost on world close. */ export function getState() { return cache; } /** * buildDefaults returns a value, * using .gates returns just the * gates value rather than coins * and other default data */ export function resetGates() { cache.gates = buildDefaults().gates; saveState(); } export function resetGate(id) { //resets the gate from the config/region config cache.gates[id] = REGIONS[id].unlockedAtStart; saveState(); } /** * Sets a region's gate to T/F and persists the change. * e.g. updateGate("farmland", state) -> * cache.gates["farmland"] = state * * undefined will remove a gate from the cache */ export function unlockGate(nKey, state) { cache.gates[nKey] = state; saveState(); } export function unlockGates() { for(const id in REGIONS) { cache.gates[id] = true; } saveState(); } export function updateBalance(cost) { cache.coins += cost; saveState(); } export function returnBalance(){ const value = cache.coins; return value; } export function printGateState(){ console.log(JSON.stringify(getState().gates)); } /** * Writes the cache out to the world save, where it survives the world closing. * * Returns early if nothing has been loaded yet - writing a null cache would * store the text "null" and corrupt the save. * * Objects are not a permitted dynamic property value (only boolean, number, * string and Vector3), so the document is converted to JSON text first. */ export function saveState() { if(cache === null) return; const text = JSON.stringify(cache); world.setDynamicProperty(KEY, text); }