Save encoding (maybe compression, remains to be seen for bigger saves)
This commit is contained in:
parent
61b4f4b06d
commit
921e74fb88
4 changed files with 466 additions and 7 deletions
2
src/global.d.ts
vendored
2
src/global.d.ts
vendored
|
@ -1,9 +1,11 @@
|
||||||
/// <reference types="svelte" />
|
/// <reference types="svelte" />
|
||||||
|
|
||||||
|
import type { LZString } from "./shark/LZString";
|
||||||
import type { SharkGame } from "./shark/SharkGame";
|
import type { SharkGame } from "./shark/SharkGame";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
SharkGame: SharkGame;
|
SharkGame: SharkGame;
|
||||||
|
LZString: LZString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
435
src/shark/LZString.ts
Normal file
435
src/shark/LZString.ts
Normal file
|
@ -0,0 +1,435 @@
|
||||||
|
import { StaticClass } from "./StaticClass";
|
||||||
|
|
||||||
|
export class LZString extends StaticClass {
|
||||||
|
static readonly #KeyStrBase64 =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||||
|
|
||||||
|
static readonly #KeyStrBase64Dict = LZString.#createBaseDict(
|
||||||
|
LZString.#KeyStrBase64
|
||||||
|
);
|
||||||
|
|
||||||
|
static #createBaseDict(alphabet: string): Record<string, number> {
|
||||||
|
const dict: Record<string, number> = {};
|
||||||
|
for (let i = 0; i < alphabet.length; i++) {
|
||||||
|
dict[alphabet[i]] = i;
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
static compressToBase64(input: string): string {
|
||||||
|
const result = LZString.#compress(input, 6, (a) =>
|
||||||
|
LZString.#KeyStrBase64.charAt(a)
|
||||||
|
);
|
||||||
|
return result + "=".repeat((4 - (result.length % 4)) % 4);
|
||||||
|
}
|
||||||
|
static decompressFromBase64(input: string | null): string | null {
|
||||||
|
if (input === null || input === "") return null;
|
||||||
|
return LZString.#decompress(
|
||||||
|
input.length,
|
||||||
|
32,
|
||||||
|
(index) => LZString.#KeyStrBase64Dict[input.charAt(index)]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static compress(uncompressed: string): string {
|
||||||
|
return LZString.#compress(uncompressed);
|
||||||
|
}
|
||||||
|
static #compress(uncompressed: string): string;
|
||||||
|
static #compress(
|
||||||
|
uncompressed: string,
|
||||||
|
bitsPerChar: number,
|
||||||
|
getCharFromInt: (index: number) => string
|
||||||
|
): string;
|
||||||
|
static #compress(
|
||||||
|
uncompressed: string,
|
||||||
|
bitsPerChar = 16,
|
||||||
|
getCharFromNumber = (code: number) => String.fromCharCode(code)
|
||||||
|
): string {
|
||||||
|
const contextDictionary: Record<string, number> = {};
|
||||||
|
const contextDictionaryToCreate: Record<string, boolean> = {};
|
||||||
|
|
||||||
|
let contextDictSize = 3;
|
||||||
|
let contextW = "";
|
||||||
|
let contextEnlargeIn = 2; // Compensate for the first entry which should not count
|
||||||
|
let contextNumBits = 2;
|
||||||
|
let contextData = "";
|
||||||
|
let contextDataVal = 0;
|
||||||
|
let contextDataPosition = 0;
|
||||||
|
|
||||||
|
let value: number;
|
||||||
|
|
||||||
|
for (const contextC of uncompressed) {
|
||||||
|
if (!Object.keys(contextDictionary).includes(contextC)) {
|
||||||
|
contextDictionary[contextC] = contextDictSize++;
|
||||||
|
contextDictionaryToCreate[contextC] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const contextWC = contextW + contextC;
|
||||||
|
if (Object.keys(contextDictionary).includes(contextWC)) {
|
||||||
|
contextW = contextWC;
|
||||||
|
} else {
|
||||||
|
if (Object.keys(contextDictionaryToCreate).includes(contextW)) {
|
||||||
|
if (contextW.charCodeAt(0) < 256) {
|
||||||
|
for (let i = 0; i < contextNumBits; i++) {
|
||||||
|
contextDataVal <<= 1;
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextDataPosition = 0;
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
contextDataVal = 0;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value = contextW.charCodeAt(0);
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
contextDataVal = (contextDataVal << 1) | (value & 1);
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextDataPosition = 0;
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
contextDataVal = 0;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
value >>= 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = 1;
|
||||||
|
for (let i = 0; i < contextNumBits; i++) {
|
||||||
|
contextDataVal = (contextDataVal << 1) | value;
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextDataPosition = 0;
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
contextDataVal = 0;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
value = contextW.charCodeAt(0);
|
||||||
|
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
contextDataVal = (contextDataVal << 1) | (value & 1);
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextDataPosition = 0;
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
contextDataVal = 0;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
value >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contextEnlargeIn--;
|
||||||
|
if (contextEnlargeIn === 0) {
|
||||||
|
contextEnlargeIn = 2 ** contextNumBits;
|
||||||
|
contextNumBits++;
|
||||||
|
}
|
||||||
|
delete contextDictionaryToCreate[contextW];
|
||||||
|
} else {
|
||||||
|
value = contextDictionary[contextW];
|
||||||
|
for (let i = 0; i < contextNumBits; i++) {
|
||||||
|
contextDataVal = (contextDataVal << 1) | (value & 1);
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextDataPosition = 0;
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
contextDataVal = 0;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
value >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contextEnlargeIn--;
|
||||||
|
if (contextEnlargeIn === 0) {
|
||||||
|
contextEnlargeIn = 2 ** contextNumBits;
|
||||||
|
contextNumBits++;
|
||||||
|
}
|
||||||
|
contextDictionary[contextWC] = contextDictSize++;
|
||||||
|
contextW = contextC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contextW !== "") {
|
||||||
|
if (Object.keys(contextDictionaryToCreate).includes(contextW)) {
|
||||||
|
if (contextW.charCodeAt(0) < 256) {
|
||||||
|
for (let i = 0; i < contextNumBits; i++) {
|
||||||
|
contextDataVal = contextDataVal << 1;
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextDataPosition = 0;
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
contextDataVal = 0;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value = contextW.charCodeAt(0);
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
contextDataVal = (contextDataVal << 1) | (value & 1);
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextDataPosition = 0;
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
contextDataVal = 0;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
value >>= 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = 1;
|
||||||
|
for (let i = 0; i < contextNumBits; i++) {
|
||||||
|
contextDataVal = (contextDataVal << 1) | value;
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextDataPosition = 0;
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
contextDataVal = 0;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = contextW.charCodeAt(0);
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
contextDataVal = (contextDataVal << 1) | (value & 1);
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextDataPosition = 0;
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
contextDataVal = 0;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
value >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contextEnlargeIn--;
|
||||||
|
if (contextEnlargeIn === 0) {
|
||||||
|
contextEnlargeIn = 2 ** contextNumBits;
|
||||||
|
contextNumBits++;
|
||||||
|
}
|
||||||
|
delete contextDictionaryToCreate[contextW];
|
||||||
|
} else {
|
||||||
|
value = contextDictionary[contextW];
|
||||||
|
for (let i = 0; i < contextNumBits; i++) {
|
||||||
|
contextDataVal = (contextDataVal << 1) | (value & 1);
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextDataPosition = 0;
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
contextDataVal = 0;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
value >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contextEnlargeIn--;
|
||||||
|
if (contextEnlargeIn === 0) {
|
||||||
|
contextNumBits++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value = 2;
|
||||||
|
for (let i = 0; i < contextNumBits; i++) {
|
||||||
|
contextDataVal = (contextDataVal << 1) | (value & 1);
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextDataPosition = 0;
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
contextDataVal = 0;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
value >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-constant-condition
|
||||||
|
while (true) {
|
||||||
|
contextDataVal <<= 1;
|
||||||
|
if (contextDataPosition === bitsPerChar - 1) {
|
||||||
|
contextData += getCharFromNumber(contextDataVal);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
contextDataPosition++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return contextData;
|
||||||
|
}
|
||||||
|
|
||||||
|
static decompress(compressed: string | null): string | null {
|
||||||
|
if (compressed === null || compressed === "") return null;
|
||||||
|
return LZString.#decompress(compressed.length, 32768, (index) =>
|
||||||
|
compressed.charCodeAt(index)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
static #decompress(
|
||||||
|
length: number,
|
||||||
|
resetValue: number,
|
||||||
|
getNextValue: (index: number) => number
|
||||||
|
): string | null {
|
||||||
|
const dictionary: (number | string)[] = [];
|
||||||
|
|
||||||
|
let enlargeIn = 4;
|
||||||
|
let dictSize = 4;
|
||||||
|
let numBits = 3;
|
||||||
|
let entry = "";
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
val: getNextValue(0),
|
||||||
|
position: resetValue,
|
||||||
|
index: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
dictionary[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bits = 0;
|
||||||
|
let maxPower = 2 ** 2;
|
||||||
|
let power = 1;
|
||||||
|
|
||||||
|
let resb: number;
|
||||||
|
while (power !== maxPower) {
|
||||||
|
resb = data.val & data.position;
|
||||||
|
data.position >>= 1;
|
||||||
|
if (data.position === 0) {
|
||||||
|
data.position = resetValue;
|
||||||
|
data.val = getNextValue(data.index++);
|
||||||
|
}
|
||||||
|
bits |= resb > 0 ? power : 0;
|
||||||
|
power <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let c = "";
|
||||||
|
switch (bits) {
|
||||||
|
case 0:
|
||||||
|
bits = 0;
|
||||||
|
maxPower = 2 ** 8;
|
||||||
|
power = 1;
|
||||||
|
while (power !== maxPower) {
|
||||||
|
resb = data.val & data.position;
|
||||||
|
data.position >>= 1;
|
||||||
|
if (data.position === 0) {
|
||||||
|
data.position = resetValue;
|
||||||
|
data.val = getNextValue(data.index++);
|
||||||
|
}
|
||||||
|
bits |= (resb > 0 ? 1 : 0) * power;
|
||||||
|
power <<= 1;
|
||||||
|
}
|
||||||
|
c = String.fromCharCode(bits);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
bits = 0;
|
||||||
|
maxPower = 2 ** 16;
|
||||||
|
power = 1;
|
||||||
|
while (power != maxPower) {
|
||||||
|
resb = data.val & data.position;
|
||||||
|
data.position >>= 1;
|
||||||
|
if (data.position == 0) {
|
||||||
|
data.position = resetValue;
|
||||||
|
data.val = getNextValue(data.index++);
|
||||||
|
}
|
||||||
|
bits |= (resb > 0 ? 1 : 0) * power;
|
||||||
|
power <<= 1;
|
||||||
|
}
|
||||||
|
c = String.fromCharCode(bits);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
dictionary[3] = c;
|
||||||
|
let w = c;
|
||||||
|
result.push(c);
|
||||||
|
// eslint-disable-next-line no-constant-condition
|
||||||
|
while (true) {
|
||||||
|
if (data.index > length) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bits = 0;
|
||||||
|
maxPower = 2 ** numBits;
|
||||||
|
power = 1;
|
||||||
|
|
||||||
|
while (power !== maxPower) {
|
||||||
|
resb = data.val & data.position;
|
||||||
|
data.position >>= 1;
|
||||||
|
if (data.position === 0) {
|
||||||
|
data.position = resetValue;
|
||||||
|
data.val = getNextValue(data.index++);
|
||||||
|
}
|
||||||
|
bits |= resb > 0 ? power : 0;
|
||||||
|
power <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let c2;
|
||||||
|
switch ((c2 = bits)) {
|
||||||
|
case 0:
|
||||||
|
bits = 0;
|
||||||
|
maxPower = 2 ** 8;
|
||||||
|
power = 1;
|
||||||
|
while (power !== maxPower) {
|
||||||
|
resb = data.val & data.position;
|
||||||
|
data.position >>= 1;
|
||||||
|
if (data.position === 0) {
|
||||||
|
data.position = resetValue;
|
||||||
|
data.val = getNextValue(data.index++);
|
||||||
|
}
|
||||||
|
bits |= (resb > 0 ? 1 : 0) * power;
|
||||||
|
power <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dictionary[dictSize++] = String.fromCharCode(bits);
|
||||||
|
c2 = dictSize - 1;
|
||||||
|
enlargeIn--;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
bits = 0;
|
||||||
|
maxPower = 2 ** 16;
|
||||||
|
power = 1;
|
||||||
|
while (power !== maxPower) {
|
||||||
|
resb = data.val & data.position;
|
||||||
|
data.position >>= 1;
|
||||||
|
if (data.position === 0) {
|
||||||
|
data.position = resetValue;
|
||||||
|
data.val = getNextValue(data.index++);
|
||||||
|
}
|
||||||
|
bits |= (resb > 0 ? 1 : 0) * power;
|
||||||
|
power <<= 1;
|
||||||
|
}
|
||||||
|
dictionary[dictSize++] = String.fromCharCode(bits);
|
||||||
|
c2 = dictSize - 1;
|
||||||
|
enlargeIn--;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
return result.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enlargeIn == 0) {
|
||||||
|
enlargeIn = Math.pow(2, numBits);
|
||||||
|
numBits++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dictionary[c2]) {
|
||||||
|
entry = dictionary[c2] as string;
|
||||||
|
} else {
|
||||||
|
if (c2 === dictSize) {
|
||||||
|
entry = w + w.charAt(0);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.push(entry);
|
||||||
|
|
||||||
|
// Add w+entry[0] to the dictionary.
|
||||||
|
dictionary[dictSize++] = w + entry.charAt(0);
|
||||||
|
enlargeIn--;
|
||||||
|
|
||||||
|
w = entry;
|
||||||
|
|
||||||
|
if (enlargeIn == 0) {
|
||||||
|
enlargeIn = Math.pow(2, numBits);
|
||||||
|
numBits++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.LZString = LZString;
|
|
@ -1,8 +1,8 @@
|
||||||
import type { Message, MessageType } from "./Message";
|
import type { Message, MessageType } from "./Message";
|
||||||
import type { Settings } from "./Settings";
|
|
||||||
import type { SharkGame } from "./SharkGame";
|
import type { SharkGame } from "./SharkGame";
|
||||||
import { StaticClass } from "./StaticClass";
|
import { StaticClass } from "./StaticClass";
|
||||||
import type { TabHandler } from "./TabHandler";
|
import type { TabHandler } from "./TabHandler";
|
||||||
|
import { LZString } from "./LZString";
|
||||||
|
|
||||||
const __EMPTY_OBJECT = {};
|
const __EMPTY_OBJECT = {};
|
||||||
type Version0Save = typeof __EMPTY_OBJECT;
|
type Version0Save = typeof __EMPTY_OBJECT;
|
||||||
|
@ -13,7 +13,7 @@ type Version1Save = Version0Save & {
|
||||||
type: MessageType;
|
type: MessageType;
|
||||||
}[];
|
}[];
|
||||||
selectedTab: keyof typeof TabHandler["AllTabs"];
|
selectedTab: keyof typeof TabHandler["AllTabs"];
|
||||||
settings: ReturnType<typeof Settings["getCurrent"]>;
|
settings: Record<`${string};${string}`, unknown>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type CurrentVersionSave = Version1Save;
|
type CurrentVersionSave = Version1Save;
|
||||||
|
@ -40,10 +40,21 @@ export class SaveHandler extends StaticClass {
|
||||||
);
|
);
|
||||||
const selectedTabName = allTabsEntries[selectedTabIndex][0];
|
const selectedTabName = allTabsEntries[selectedTabIndex][0];
|
||||||
|
|
||||||
|
const currentSettings = game.Settings.getSaveable();
|
||||||
|
const saveSettings: CurrentVersionSave["settings"] = {};
|
||||||
|
for (const [settingId, setting] of Object.entries(currentSettings) as [
|
||||||
|
keyof typeof currentSettings,
|
||||||
|
typeof currentSettings[keyof typeof currentSettings]
|
||||||
|
][]) {
|
||||||
|
if (setting.current !== setting.default) {
|
||||||
|
saveSettings[settingId] = setting.current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const save: CurrentVersionSave = {
|
const save: CurrentVersionSave = {
|
||||||
version: 1,
|
version: 1,
|
||||||
selectedTab: selectedTabName,
|
selectedTab: selectedTabName,
|
||||||
settings: game.Settings.getCurrent(),
|
settings: saveSettings,
|
||||||
messages: messages.map((message) => {
|
messages: messages.map((message) => {
|
||||||
return {
|
return {
|
||||||
message: message.message,
|
message: message.message,
|
||||||
|
@ -51,13 +62,24 @@ export class SaveHandler extends StaticClass {
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
const encodedSave = JSON.stringify(save);
|
const stringifiedSave = JSON.stringify(save);
|
||||||
|
const encodedSave = LZString.compressToBase64(stringifiedSave);
|
||||||
|
console.debug(
|
||||||
|
`${new Date(
|
||||||
|
Date.now()
|
||||||
|
).toISOString()} - saving ${stringifiedSave} - encoded to ${
|
||||||
|
Math.round((encodedSave.length / stringifiedSave.length) * 100 * 100) /
|
||||||
|
100
|
||||||
|
}% size`
|
||||||
|
);
|
||||||
|
|
||||||
localStorage.setItem(SaveHandler.saveName, encodedSave);
|
localStorage.setItem(SaveHandler.saveName, encodedSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async load(game: typeof SharkGame): Promise<unknown> {
|
static async load(game: typeof SharkGame): Promise<unknown> {
|
||||||
const localSave = localStorage.getItem(SaveHandler.saveName);
|
const localSave = LZString.decompressFromBase64(
|
||||||
|
localStorage.getItem(SaveHandler.saveName)
|
||||||
|
);
|
||||||
const loadedSave = JSON.parse(localSave ?? "{}");
|
const loadedSave = JSON.parse(localSave ?? "{}");
|
||||||
const saveVersion = loadedSave.version ?? 0;
|
const saveVersion = loadedSave.version ?? 0;
|
||||||
|
|
||||||
|
|
|
@ -162,12 +162,12 @@ export class Settings extends StaticClass {
|
||||||
static getSettings(): SettingsRecord {
|
static getSettings(): SettingsRecord {
|
||||||
return Object.seal(Object.assign({}, Settings.#settings));
|
return Object.seal(Object.assign({}, Settings.#settings));
|
||||||
}
|
}
|
||||||
static getCurrent(): Record<`${string};${string}`, Setting> {
|
static getSaveable(): Record<`${string};${string}`, Setting> {
|
||||||
const current = this.getSettings();
|
const current = this.getSettings();
|
||||||
const result: Record<`${string};${string}`, Setting> = {};
|
const result: Record<`${string};${string}`, Setting> = {};
|
||||||
for (const [categoryName, category] of Object.entries(current)) {
|
for (const [categoryName, category] of Object.entries(current)) {
|
||||||
for (const [settingName, setting] of Object.entries(category)) {
|
for (const [settingName, setting] of Object.entries(category)) {
|
||||||
result[`${categoryName};${settingName}`] = setting.current;
|
result[`${categoryName};${settingName}`] = setting;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
Reference in a new issue