Profectus-Demo/src/game/player.ts

118 lines
4 KiB
TypeScript
Raw Normal View History

2022-01-14 04:25:47 +00:00
import Decimal, { DecimalSource } from "@/util/bignum";
import { isPlainObject } from "@/util/common";
2022-01-14 04:25:47 +00:00
import { ProxiedWithState, ProxyPath, ProxyState } from "@/util/proxies";
2022-01-25 04:25:34 +00:00
import { shallowReactive, unref } from "vue";
import transientState from "./state";
2022-01-14 04:25:47 +00:00
export interface PlayerData {
id: string;
devSpeed: DecimalSource | null;
name: string;
tabs: Array<string>;
time: number;
autosave: boolean;
offlineProd: boolean;
2022-01-25 04:25:34 +00:00
offlineTime: DecimalSource | null;
timePlayed: DecimalSource;
2022-01-14 04:25:47 +00:00
keepGoing: boolean;
minimized: Record<string, boolean>;
modID: string;
modVersion: string;
layers: Record<string, Record<string, unknown>>;
}
export type Player = ProxiedWithState<PlayerData>;
2022-01-25 04:25:34 +00:00
const state = shallowReactive<PlayerData>({
id: "",
2022-01-14 04:25:47 +00:00
devSpeed: null,
name: "",
tabs: [],
time: -1,
autosave: true,
offlineProd: true,
offlineTime: null,
timePlayed: new Decimal(0),
keepGoing: false,
minimized: {},
modID: "",
modVersion: "",
layers: {}
});
2022-01-14 04:25:47 +00:00
export function stringifySave(player: PlayerData): string {
return JSON.stringify((player as Player)[ProxyState], (key, value) => unref(value));
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const playerHandler: ProxyHandler<Record<PropertyKey, any>> = {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
get(target: Record<PropertyKey, any>, key: PropertyKey): any {
if (key === ProxyState || key === ProxyPath) {
return target[key];
}
2022-01-25 04:25:34 +00:00
const value = target[ProxyState][key];
if (isPlainObject(value) && !(value instanceof Decimal)) {
if (value !== target[key]?.[ProxyState]) {
2022-01-14 04:25:47 +00:00
const path = [...target[ProxyPath], key];
2022-01-25 04:25:34 +00:00
target[key] = new Proxy({ [ProxyState]: value, [ProxyPath]: path }, playerHandler);
}
return target[key];
}
2022-01-25 04:25:34 +00:00
return value;
},
set(
2022-01-14 04:25:47 +00:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
target: Record<PropertyKey, any>,
property: PropertyKey,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value: any,
receiver: ProxyConstructor
): boolean {
if (
!transientState.hasNaN &&
((typeof value === "number" && isNaN(value)) ||
(value instanceof Decimal &&
(isNaN(value.sign) || isNaN(value.layer) || isNaN(value.mag))))
) {
2022-01-14 04:25:47 +00:00
const currentValue = target[ProxyState][property];
if (
!(
(typeof currentValue === "number" && isNaN(currentValue)) ||
(currentValue instanceof Decimal &&
(isNaN(currentValue.sign) ||
isNaN(currentValue.layer) ||
isNaN(currentValue.mag)))
)
) {
state.autosave = false;
transientState.hasNaN = true;
2022-01-14 04:25:47 +00:00
transientState.NaNPath = [...target[ProxyPath], property];
2022-01-25 04:23:30 +00:00
transientState.NaNReceiver = receiver as unknown as Record<string, unknown>;
console.error(
`Attempted to set NaN value`,
2022-01-14 04:25:47 +00:00
[...target[ProxyPath], property],
target[ProxyState]
);
throw "Attempted to set NaN value. See above for details";
}
}
2022-01-14 04:25:47 +00:00
target[ProxyState][property] = value;
return true;
},
2022-01-14 04:25:47 +00:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ownKeys(target: Record<PropertyKey, any>) {
return Reflect.ownKeys(target[ProxyState]);
},
2022-01-14 04:25:47 +00:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
has(target: Record<PropertyKey, any>, key: string) {
return Reflect.has(target[ProxyState], key);
}
};
export default window.player = new Proxy(
2022-01-14 04:25:47 +00:00
{ [ProxyState]: state, [ProxyPath]: ["player"] },
playerHandler
) as PlayerData;