forked from profectus/Profectus
Fix save data object redundancy
Note: Requires the use of noPersist quite a bit, but the console will tell you when you missed a spot Also required breaking up events.ts due to cyclical dependencies
This commit is contained in:
parent
ae0d19c267
commit
4207677944
6 changed files with 218 additions and 128 deletions
|
@ -1,5 +1,5 @@
|
||||||
import { globalBus } from "game/events";
|
import { globalBus } from "game/events";
|
||||||
import type { State } from "game/persistence";
|
import { NonPersistent, Persistent, State } from "game/persistence";
|
||||||
import { persistent } from "game/persistence";
|
import { persistent } from "game/persistence";
|
||||||
import type { DecimalSource } from "util/bignum";
|
import type { DecimalSource } from "util/bignum";
|
||||||
import Decimal, { format, formatWhole } from "util/bignum";
|
import Decimal, { format, formatWhole } from "util/bignum";
|
||||||
|
@ -13,18 +13,38 @@ export interface Resource<T = DecimalSource> extends Ref<T> {
|
||||||
small?: boolean;
|
small?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createResource<T extends State>(
|
||||||
|
defaultValue: T,
|
||||||
|
displayName?: string,
|
||||||
|
precision?: number,
|
||||||
|
small?: boolean | undefined
|
||||||
|
): Resource<T> & Persistent<T> & { [NonPersistent]: Resource<T> };
|
||||||
|
export function createResource<T extends State>(
|
||||||
|
defaultValue: Ref<T>,
|
||||||
|
displayName?: string,
|
||||||
|
precision?: number,
|
||||||
|
small?: boolean | undefined
|
||||||
|
): Resource<T>;
|
||||||
export function createResource<T extends State>(
|
export function createResource<T extends State>(
|
||||||
defaultValue: T | Ref<T>,
|
defaultValue: T | Ref<T>,
|
||||||
displayName = "points",
|
displayName = "points",
|
||||||
precision = 0,
|
precision = 0,
|
||||||
small = undefined
|
small: boolean | undefined = undefined
|
||||||
): Resource<T> {
|
) {
|
||||||
const resource: Partial<Resource<T>> = isRef(defaultValue)
|
const resource: Partial<Resource<T>> = isRef(defaultValue)
|
||||||
? defaultValue
|
? defaultValue
|
||||||
: persistent(defaultValue);
|
: persistent(defaultValue);
|
||||||
resource.displayName = displayName;
|
resource.displayName = displayName;
|
||||||
resource.precision = precision;
|
resource.precision = precision;
|
||||||
resource.small = small;
|
resource.small = small;
|
||||||
|
if (!isRef(defaultValue)) {
|
||||||
|
const nonPersistentResource = (resource as Persistent<T>)[
|
||||||
|
NonPersistent
|
||||||
|
] as unknown as Resource<T>;
|
||||||
|
nonPersistentResource.displayName = displayName;
|
||||||
|
nonPersistentResource.precision = precision;
|
||||||
|
nonPersistentResource.small = small;
|
||||||
|
}
|
||||||
return resource as Resource<T>;
|
return resource as Resource<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
import projInfo from "data/projInfo.json";
|
|
||||||
import player from "game/player";
|
|
||||||
import type { Settings } from "game/settings";
|
import type { Settings } from "game/settings";
|
||||||
import settings from "game/settings";
|
|
||||||
import state from "game/state";
|
|
||||||
import { createNanoEvents } from "nanoevents";
|
import { createNanoEvents } from "nanoevents";
|
||||||
import Decimal from "util/bignum";
|
import type { App } from "vue";
|
||||||
import type { App, Ref } from "vue";
|
|
||||||
import { watch } from "vue";
|
|
||||||
import type { GenericLayer } from "./layers";
|
import type { GenericLayer } from "./layers";
|
||||||
|
|
||||||
/** All types of events able to be sent or emitted from the global event bus. */
|
/** All types of events able to be sent or emitted from the global event bus. */
|
||||||
|
@ -60,102 +54,4 @@ export interface GlobalEvents {
|
||||||
/** A global event bus for hooking into {@link GlobalEvents}. */
|
/** A global event bus for hooking into {@link GlobalEvents}. */
|
||||||
export const globalBus = createNanoEvents<GlobalEvents>();
|
export const globalBus = createNanoEvents<GlobalEvents>();
|
||||||
|
|
||||||
let intervalID: NodeJS.Timer | null = null;
|
|
||||||
|
|
||||||
// Not imported immediately due to dependency cycles
|
|
||||||
// This gets set during startGameLoop(), and will only be used in the update function
|
|
||||||
let hasWon: null | Ref<boolean> = null;
|
|
||||||
|
|
||||||
function update() {
|
|
||||||
const now = Date.now();
|
|
||||||
let diff = (now - player.time) / 1e3;
|
|
||||||
player.time = now;
|
|
||||||
const trueDiff = diff;
|
|
||||||
|
|
||||||
state.lastTenTicks.push(trueDiff);
|
|
||||||
if (state.lastTenTicks.length > 10) {
|
|
||||||
state.lastTenTicks = state.lastTenTicks.slice(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop here if the game is paused on the win screen
|
|
||||||
if (hasWon?.value && !player.keepGoing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Stop here if the player had a NaN value
|
|
||||||
if (state.hasNaN) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
diff = Math.max(diff, 0);
|
|
||||||
|
|
||||||
if (player.devSpeed === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add offline time if any
|
|
||||||
if (player.offlineTime != undefined) {
|
|
||||||
if (Decimal.gt(player.offlineTime, projInfo.offlineLimit * 3600)) {
|
|
||||||
player.offlineTime = projInfo.offlineLimit * 3600;
|
|
||||||
}
|
|
||||||
if (Decimal.gt(player.offlineTime, 0) && player.devSpeed !== 0) {
|
|
||||||
const offlineDiff = Math.max(player.offlineTime / 10, diff);
|
|
||||||
player.offlineTime = player.offlineTime - offlineDiff;
|
|
||||||
diff += offlineDiff;
|
|
||||||
} else if (player.devSpeed === 0) {
|
|
||||||
player.offlineTime += diff;
|
|
||||||
}
|
|
||||||
if (!player.offlineProd || Decimal.lt(player.offlineTime, 0)) {
|
|
||||||
player.offlineTime = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cap at max tick length
|
|
||||||
diff = Math.min(diff, projInfo.maxTickLength);
|
|
||||||
|
|
||||||
// Apply dev speed
|
|
||||||
if (player.devSpeed != undefined) {
|
|
||||||
diff *= player.devSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Number.isFinite(diff)) {
|
|
||||||
diff = 1e308;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update
|
|
||||||
if (Decimal.eq(diff, 0)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
player.timePlayed += diff;
|
|
||||||
if (!Number.isFinite(player.timePlayed)) {
|
|
||||||
player.timePlayed = 1e308;
|
|
||||||
}
|
|
||||||
globalBus.emit("update", diff, trueDiff);
|
|
||||||
|
|
||||||
if (settings.unthrottled) {
|
|
||||||
requestAnimationFrame(update);
|
|
||||||
if (intervalID != null) {
|
|
||||||
clearInterval(intervalID);
|
|
||||||
intervalID = null;
|
|
||||||
}
|
|
||||||
} else if (intervalID == null) {
|
|
||||||
intervalID = setInterval(update, 50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Starts the game loop for the project, which updates the game in ticks. */
|
|
||||||
export async function startGameLoop() {
|
|
||||||
hasWon = (await import("data/projEntry")).hasWon;
|
|
||||||
watch(hasWon, hasWon => {
|
|
||||||
if (hasWon) {
|
|
||||||
globalBus.emit("gameWon");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (settings.unthrottled) {
|
|
||||||
requestAnimationFrame(update);
|
|
||||||
} else {
|
|
||||||
intervalID = setInterval(update, 50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.fonts.onloadingdone = () => globalBus.emit("fontsLoaded");
|
document.fonts.onloadingdone = () => globalBus.emit("fontsLoaded");
|
||||||
|
|
106
src/game/gameLoop.ts
Normal file
106
src/game/gameLoop.ts
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
import projInfo from "data/projInfo.json";
|
||||||
|
import { globalBus } from "game/events";
|
||||||
|
import settings from "game/settings";
|
||||||
|
import Decimal from "util/bignum";
|
||||||
|
import type { Ref } from "vue";
|
||||||
|
import { watch } from "vue";
|
||||||
|
import player from "./player";
|
||||||
|
import state from "./state";
|
||||||
|
|
||||||
|
let intervalID: NodeJS.Timer | null = null;
|
||||||
|
|
||||||
|
// Not imported immediately due to dependency cycles
|
||||||
|
// This gets set during startGameLoop(), and will only be used in the update function
|
||||||
|
let hasWon: null | Ref<boolean> = null;
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
const now = Date.now();
|
||||||
|
let diff = (now - player.time) / 1e3;
|
||||||
|
player.time = now;
|
||||||
|
const trueDiff = diff;
|
||||||
|
|
||||||
|
state.lastTenTicks.push(trueDiff);
|
||||||
|
if (state.lastTenTicks.length > 10) {
|
||||||
|
state.lastTenTicks = state.lastTenTicks.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop here if the game is paused on the win screen
|
||||||
|
if (hasWon?.value && !player.keepGoing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Stop here if the player had a NaN value
|
||||||
|
if (state.hasNaN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = Math.max(diff, 0);
|
||||||
|
|
||||||
|
if (player.devSpeed === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add offline time if any
|
||||||
|
if (player.offlineTime != undefined) {
|
||||||
|
if (Decimal.gt(player.offlineTime, projInfo.offlineLimit * 3600)) {
|
||||||
|
player.offlineTime = projInfo.offlineLimit * 3600;
|
||||||
|
}
|
||||||
|
if (Decimal.gt(player.offlineTime, 0) && player.devSpeed !== 0) {
|
||||||
|
const offlineDiff = Math.max(player.offlineTime / 10, diff);
|
||||||
|
player.offlineTime = player.offlineTime - offlineDiff;
|
||||||
|
diff += offlineDiff;
|
||||||
|
} else if (player.devSpeed === 0) {
|
||||||
|
player.offlineTime += diff;
|
||||||
|
}
|
||||||
|
if (!player.offlineProd || Decimal.lt(player.offlineTime, 0)) {
|
||||||
|
player.offlineTime = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cap at max tick length
|
||||||
|
diff = Math.min(diff, projInfo.maxTickLength);
|
||||||
|
|
||||||
|
// Apply dev speed
|
||||||
|
if (player.devSpeed != undefined) {
|
||||||
|
diff *= player.devSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Number.isFinite(diff)) {
|
||||||
|
diff = 1e308;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update
|
||||||
|
if (Decimal.eq(diff, 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.timePlayed += diff;
|
||||||
|
if (!Number.isFinite(player.timePlayed)) {
|
||||||
|
player.timePlayed = 1e308;
|
||||||
|
}
|
||||||
|
globalBus.emit("update", diff, trueDiff);
|
||||||
|
|
||||||
|
if (settings.unthrottled) {
|
||||||
|
requestAnimationFrame(update);
|
||||||
|
if (intervalID != null) {
|
||||||
|
clearInterval(intervalID);
|
||||||
|
intervalID = null;
|
||||||
|
}
|
||||||
|
} else if (intervalID == null) {
|
||||||
|
intervalID = setInterval(update, 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Starts the game loop for the project, which updates the game in ticks. */
|
||||||
|
export async function startGameLoop() {
|
||||||
|
hasWon = (await import("data/projEntry")).hasWon;
|
||||||
|
watch(hasWon, hasWon => {
|
||||||
|
if (hasWon) {
|
||||||
|
globalBus.emit("gameWon");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (settings.unthrottled) {
|
||||||
|
requestAnimationFrame(update);
|
||||||
|
} else {
|
||||||
|
intervalID = setInterval(update, 50);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { identifier } from "@babel/types";
|
||||||
import { isArray } from "@vue/shared";
|
import { isArray } from "@vue/shared";
|
||||||
import { globalBus } from "game/events";
|
import { globalBus } from "game/events";
|
||||||
import type { GenericLayer } from "game/layers";
|
import type { GenericLayer } from "game/layers";
|
||||||
|
@ -5,8 +6,8 @@ import { addingLayers, persistentRefs } from "game/layers";
|
||||||
import type { DecimalSource } from "util/bignum";
|
import type { DecimalSource } from "util/bignum";
|
||||||
import Decimal from "util/bignum";
|
import Decimal from "util/bignum";
|
||||||
import { ProxyState } from "util/proxies";
|
import { ProxyState } from "util/proxies";
|
||||||
import type { Ref } from "vue";
|
import type { Ref, WritableComputedRef } from "vue";
|
||||||
import { isReactive, isRef, ref } from "vue";
|
import { computed, isReactive, isRef, ref } from "vue";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A symbol used in {@link Persistent} objects.
|
* A symbol used in {@link Persistent} objects.
|
||||||
|
@ -28,6 +29,16 @@ export const StackTrace = Symbol("StackTrace");
|
||||||
* @see {@link Persistent[Deleted]}
|
* @see {@link Persistent[Deleted]}
|
||||||
*/
|
*/
|
||||||
export const Deleted = Symbol("Deleted");
|
export const Deleted = Symbol("Deleted");
|
||||||
|
/**
|
||||||
|
* A symbol used in {@link Persistent} objects.
|
||||||
|
* @see {@link Persistent[NonPersistent]}
|
||||||
|
*/
|
||||||
|
export const NonPersistent = Symbol("NonPersistent");
|
||||||
|
/**
|
||||||
|
* A symbol used in {@link Persistent} objects.
|
||||||
|
* @see {@link Persistent[SaveDataPath]}
|
||||||
|
*/
|
||||||
|
export const SaveDataPath = Symbol("SaveDataPath");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a union of things that should be safely stringifiable without needing special processes or knowing what to load them in as.
|
* This is a union of things that should be safely stringifiable without needing special processes or knowing what to load them in as.
|
||||||
|
@ -57,6 +68,14 @@ export type Persistent<T extends State = State> = Ref<T> & {
|
||||||
* @see {@link deletePersistent} for marking a persistent ref as deleted.
|
* @see {@link deletePersistent} for marking a persistent ref as deleted.
|
||||||
*/
|
*/
|
||||||
[Deleted]: boolean;
|
[Deleted]: boolean;
|
||||||
|
/**
|
||||||
|
* A non-persistent ref that just reads and writes ot the persistent ref. Used for passing to other features without duplicating the persistent ref in the constructed save data object.
|
||||||
|
*/
|
||||||
|
[NonPersistent]: WritableComputedRef<T>;
|
||||||
|
/**
|
||||||
|
* The path this persistent appears in within the save data object. Predominantly used to ensure it's only placed in there one time.
|
||||||
|
*/
|
||||||
|
[SaveDataPath]: string[] | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
function getStackTrace() {
|
function getStackTrace() {
|
||||||
|
@ -83,6 +102,15 @@ export function persistent<T extends State>(defaultValue: T | Ref<T>): Persisten
|
||||||
persistent[DefaultValue] = isRef(defaultValue) ? defaultValue.value : defaultValue;
|
persistent[DefaultValue] = isRef(defaultValue) ? defaultValue.value : defaultValue;
|
||||||
persistent[StackTrace] = getStackTrace();
|
persistent[StackTrace] = getStackTrace();
|
||||||
persistent[Deleted] = false;
|
persistent[Deleted] = false;
|
||||||
|
persistent[NonPersistent] = computed({
|
||||||
|
get() {
|
||||||
|
return persistent.value;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
persistent.value = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
persistent[SaveDataPath] = undefined;
|
||||||
|
|
||||||
if (addingLayers.length === 0) {
|
if (addingLayers.length === 0) {
|
||||||
console.warn(
|
console.warn(
|
||||||
|
@ -97,6 +125,25 @@ export function persistent<T extends State>(defaultValue: T | Ref<T>): Persisten
|
||||||
return persistent as Persistent<T>;
|
return persistent as Persistent<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type guard for whether an arbitrary value is a persistent ref
|
||||||
|
* @param value The value that may or may not be a persistent ref
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export function isPersistent(value: any): value is Persistent {
|
||||||
|
return value && typeof value === "object" && PersistentState in value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unwraps the non-persistent ref inside of persistent refs, to be passed to other features without duplicating values in the save data object.
|
||||||
|
* @param persistent The persistent ref to unwrap
|
||||||
|
*/
|
||||||
|
export function noPersist<T extends Persistent<S>, S extends State>(
|
||||||
|
persistent: T
|
||||||
|
): T[typeof NonPersistent] {
|
||||||
|
return persistent[NonPersistent];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark a {@link Persistent} as deleted, so it won't be saved and loaded.
|
* Mark a {@link Persistent} as deleted, so it won't be saved and loaded.
|
||||||
* Since persistent refs must be created during a layer's options func, features can not create persistent refs after evaluating their own options funcs.
|
* Since persistent refs must be created during a layer's options func, features can not create persistent refs after evaluating their own options funcs.
|
||||||
|
@ -117,24 +164,40 @@ globalBus.on("addLayer", (layer: GenericLayer, saveData: Record<string, unknown>
|
||||||
const handleObject = (obj: Record<string, unknown>, path: string[] = []): boolean => {
|
const handleObject = (obj: Record<string, unknown>, path: string[] = []): boolean => {
|
||||||
let foundPersistent = false;
|
let foundPersistent = false;
|
||||||
Object.keys(obj).forEach(key => {
|
Object.keys(obj).forEach(key => {
|
||||||
const value = obj[key];
|
let value = obj[key];
|
||||||
if (value && typeof value === "object") {
|
if (value && typeof value === "object") {
|
||||||
if (PersistentState in value) {
|
if (ProxyState in value) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
value = (value as any)[ProxyState] as object;
|
||||||
|
}
|
||||||
|
if (isPersistent(value)) {
|
||||||
foundPersistent = true;
|
foundPersistent = true;
|
||||||
if ((value as Persistent)[Deleted]) {
|
if (value[Deleted]) {
|
||||||
console.warn(
|
console.warn(
|
||||||
"Deleted persistent ref present in returned object. Ignoring...",
|
"Deleted persistent ref present in returned object. Ignoring...",
|
||||||
value,
|
value,
|
||||||
"\nCreated at:\n" + (value as Persistent)[StackTrace]
|
"\nCreated at:\n" + value[StackTrace]
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
persistentRefs[layer.id].delete(
|
persistentRefs[layer.id].delete(value);
|
||||||
ProxyState in value
|
|
||||||
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// Handle SaveDataPath
|
||||||
((value as any)[ProxyState] as Persistent)
|
const newPath = [layer.id, ...path, key];
|
||||||
: (value as Persistent)
|
if (
|
||||||
);
|
value[SaveDataPath] != undefined &&
|
||||||
|
JSON.stringify(newPath) !== JSON.stringify(value[SaveDataPath])
|
||||||
|
) {
|
||||||
|
console.error(
|
||||||
|
`Persistent ref is being saved to \`${newPath.join(
|
||||||
|
"."
|
||||||
|
)}\` when it's already present at \`${value[SaveDataPath].join(
|
||||||
|
"."
|
||||||
|
)}\`. This can cause unexpected behavior when loading saves between updates.`,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
value[SaveDataPath] = newPath;
|
||||||
|
|
||||||
// Construct save path if it doesn't exist
|
// Construct save path if it doesn't exist
|
||||||
const persistentState = path.reduce<Record<string, unknown>>((acc, curr) => {
|
const persistentState = path.reduce<Record<string, unknown>>((acc, curr) => {
|
||||||
|
@ -147,21 +210,19 @@ globalBus.on("addLayer", (layer: GenericLayer, saveData: Record<string, unknown>
|
||||||
// Cache currently saved value
|
// Cache currently saved value
|
||||||
const savedValue = persistentState[key];
|
const savedValue = persistentState[key];
|
||||||
// Add ref to save data
|
// Add ref to save data
|
||||||
persistentState[key] = (value as Persistent)[PersistentState];
|
persistentState[key] = value[PersistentState];
|
||||||
// Load previously saved value
|
// Load previously saved value
|
||||||
if (isReactive(persistentState)) {
|
if (isReactive(persistentState)) {
|
||||||
if (savedValue != null) {
|
if (savedValue != null) {
|
||||||
persistentState[key] = savedValue;
|
persistentState[key] = savedValue;
|
||||||
} else {
|
} else {
|
||||||
persistentState[key] = (value as Persistent)[DefaultValue];
|
persistentState[key] = value[DefaultValue];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (savedValue != null) {
|
if (savedValue != null) {
|
||||||
(persistentState[key] as Ref<unknown>).value = savedValue;
|
(persistentState[key] as Ref<unknown>).value = savedValue;
|
||||||
} else {
|
} else {
|
||||||
(persistentState[key] as Ref<unknown>).value = (value as Persistent)[
|
(persistentState[key] as Ref<unknown>).value = value[DefaultValue];
|
||||||
DefaultValue
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
|
@ -200,7 +261,8 @@ globalBus.on("addLayer", (layer: GenericLayer, saveData: Record<string, unknown>
|
||||||
});
|
});
|
||||||
return foundPersistent;
|
return foundPersistent;
|
||||||
};
|
};
|
||||||
handleObject(layer);
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
handleObject((layer as any)[ProxyState]);
|
||||||
persistentRefs[layer.id].forEach(persistent => {
|
persistentRefs[layer.id].forEach(persistent => {
|
||||||
console.error(
|
console.error(
|
||||||
`Created persistent ref in ${layer.id} without registering it to the layer! Make sure to include everything persistent in the returned object`,
|
`Created persistent ref in ${layer.id} without registering it to the layer! Make sure to include everything persistent in the returned object`,
|
||||||
|
|
|
@ -36,7 +36,8 @@ requestAnimationFrame(async () => {
|
||||||
"padding: 4px;"
|
"padding: 4px;"
|
||||||
);
|
);
|
||||||
await load();
|
await load();
|
||||||
const { globalBus, startGameLoop } = await import("./game/events");
|
const { globalBus } = await import("./game/events");
|
||||||
|
const { startGameLoop } = await import("./game/gameLoop");
|
||||||
|
|
||||||
// Create Vue
|
// Create Vue
|
||||||
const vue = (window.vue = createApp(App));
|
const vue = (window.vue = createApp(App));
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { NonPersistent } from "game/persistence";
|
||||||
import Decimal from "util/bignum";
|
import Decimal from "util/bignum";
|
||||||
|
|
||||||
export const ProxyState = Symbol("ProxyState");
|
export const ProxyState = Symbol("ProxyState");
|
||||||
|
@ -37,7 +38,11 @@ export function createLazyProxy<T extends object, S extends T>(
|
||||||
return calculateObj();
|
return calculateObj();
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
return (calculateObj() as any)[key];
|
const val = (calculateObj() as any)[key];
|
||||||
|
if (val && typeof val === "object" && NonPersistent in val) {
|
||||||
|
return val[NonPersistent];
|
||||||
|
}
|
||||||
|
return val;
|
||||||
},
|
},
|
||||||
set(target, key, value) {
|
set(target, key, value) {
|
||||||
// TODO give warning about this? It should only be done with caution
|
// TODO give warning about this? It should only be done with caution
|
||||||
|
|
Loading…
Reference in a new issue