Profectus/src/game/settings.ts

124 lines
4.3 KiB
TypeScript
Raw Normal View History

2022-03-04 03:39:48 +00:00
import projInfo from "data/projInfo.json";
import { Themes } from "data/themes";
2022-06-27 00:17:22 +00:00
import type { CoercableComponent } from "features/feature";
2022-03-04 03:39:48 +00:00
import { globalBus } from "game/events";
import LZString from "lz-string";
2022-03-04 03:39:48 +00:00
import { hardReset } from "util/save";
import { reactive, watch } from "vue";
2022-07-15 05:55:36 +00:00
/** The player's settings object. */
2022-01-14 04:25:47 +00:00
export interface Settings {
2022-07-15 05:55:36 +00:00
/** The ID of the active save. */
2022-01-14 04:25:47 +00:00
active: string;
2022-07-15 05:55:36 +00:00
/** The IDs of all created saves. */
2022-01-14 04:25:47 +00:00
saves: string[];
2022-07-15 05:55:36 +00:00
/** Whether or not to show the current ticks per second in the lower left corner of the page. */
2022-01-14 04:25:47 +00:00
showTPS: boolean;
2022-07-15 05:55:36 +00:00
/** The current theme to display the game in. */
2022-01-14 04:25:47 +00:00
theme: Themes;
2022-07-15 05:55:36 +00:00
/** Whether or not to cap the project at 20 ticks per second. */
2022-01-14 04:25:47 +00:00
unthrottled: boolean;
2023-02-16 03:58:06 +00:00
/** Whether to align modifiers to the unit. */
alignUnits: boolean;
2022-01-14 04:25:47 +00:00
}
const state = reactive<Partial<Settings>>({
active: "",
saves: [],
showTPS: true,
2021-09-06 00:13:56 +00:00
theme: Themes.Nordic,
2023-02-16 03:58:06 +00:00
unthrottled: false,
alignUnits: false
});
2022-01-14 04:25:47 +00:00
watch(
state,
state => {
const stringifiedSettings = LZString.compressToUTF16(JSON.stringify(state));
localStorage.setItem(projInfo.id, stringifiedSettings);
},
2022-01-14 04:25:47 +00:00
{ deep: true }
);
2022-07-10 03:09:25 +00:00
declare global {
/**
2022-07-10 05:43:52 +00:00
* Augment the window object so the settings, and hard resetting the settings, can be accessed from the console.
2022-07-10 03:09:25 +00:00
*/
interface Window {
settings: Settings;
hardResetSettings: VoidFunction;
}
}
2022-07-15 05:55:36 +00:00
/**
* The player settings object. Stores data that persists across all saves.
* Automatically saved to localStorage whenever changed.
*/
2022-01-14 04:25:47 +00:00
export default window.settings = state as Settings;
2022-07-15 05:55:36 +00:00
/** A function that erases all player settings, including all saves. */
2022-07-10 03:09:25 +00:00
export const hardResetSettings = (window.hardResetSettings = () => {
const settings = {
active: "",
saves: [],
showTPS: true,
2023-02-16 03:58:06 +00:00
theme: Themes.Nordic,
alignUnits: false
2022-07-10 03:09:25 +00:00
};
globalBus.emit("loadSettings", settings);
Object.assign(state, settings);
hardReset();
});
2022-07-15 05:55:36 +00:00
/**
* Loads the player settings from localStorage.
* Calls the {@link GlobalEvents.loadSettings} event for custom properties to be included.
* Custom properties should be added by the file they relate to, so they won't be included if the file is tree shaken away.
* Custom properties should also register the field to modify said setting using {@link registerSettingField}.
*/
export function loadSettings(): void {
try {
let item: string | null = localStorage.getItem(projInfo.id);
if (item != null && item !== "") {
if (item[0] === "{") {
// plaintext. No processing needed
} else if (item[0] === "e") {
// Assumed to be base64, which starts with e
item = decodeURIComponent(escape(atob(item)));
} else if (item[0] === "ᯡ") {
// Assumed to be lz, which starts with ᯡ
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
item = LZString.decompressFromUTF16(item)!;
} else {
console.warn("Unable to determine settings encoding", item);
return;
}
const settings = JSON.parse(item);
if (typeof settings === "object") {
Object.assign(state, settings);
}
}
2022-01-14 04:25:47 +00:00
globalBus.emit("loadSettings", state);
// eslint-disable-next-line no-empty
} catch {}
}
2022-07-15 05:55:36 +00:00
/** A list of fields to append to the settings modal. */
export const settingFields: CoercableComponent[] = reactive([]);
2022-07-15 05:55:36 +00:00
/** Register a field to be displayed in the settings modal. */
export function registerSettingField(component: CoercableComponent) {
settingFields.push(component);
}
2022-03-11 22:38:49 +00:00
2022-07-15 05:55:36 +00:00
/** A list of components to show in the info modal. */
2022-03-11 22:38:49 +00:00
export const infoComponents: CoercableComponent[] = reactive([]);
2022-07-15 05:55:36 +00:00
/** Register a component to be displayed in the info modal. */
2022-03-11 22:38:49 +00:00
export function registerInfoComponent(component: CoercableComponent) {
infoComponents.push(component);
}
2022-03-20 04:59:52 +00:00
2022-07-15 05:55:36 +00:00
/** A list of components to add to the root of the page. */
2022-03-20 04:59:52 +00:00
export const gameComponents: CoercableComponent[] = reactive([]);
2022-07-15 05:55:36 +00:00
/** Register a component to be displayed at the root of the page. */
2022-03-20 04:59:52 +00:00
export function registerGameComponent(component: CoercableComponent) {
gameComponents.push(component);
}