Files
ip_content/ti_bp/scripts/save/state.js
T

147 lines
3.9 KiB
JavaScript

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);
}