Made no features extend Persistent

This commit is contained in:
thepaperpilot 2022-04-23 18:20:15 -05:00
parent cfe378020a
commit aae6455ea6
7 changed files with 70 additions and 60 deletions

View file

@ -11,7 +11,7 @@ import {
Visibility Visibility
} from "features/feature"; } from "features/feature";
import "game/notifications"; import "game/notifications";
import { Persistent, PersistentState, persistent } from "game/persistence"; import { Persistent, persistent } from "game/persistence";
import { import {
Computable, Computable,
GetComputableType, GetComputableType,
@ -21,7 +21,7 @@ import {
} from "util/computed"; } from "util/computed";
import { createLazyProxy } from "util/proxies"; import { createLazyProxy } from "util/proxies";
import { coerceComponent } from "util/vue"; import { coerceComponent } from "util/vue";
import { Ref, unref, watchEffect } from "vue"; import { unref, watchEffect } from "vue";
import { useToast } from "vue-toastification"; import { useToast } from "vue-toastification";
const toast = useToast(); const toast = useToast();
@ -39,9 +39,9 @@ export interface AchievementOptions {
onComplete?: VoidFunction; onComplete?: VoidFunction;
} }
export interface BaseAchievement extends Persistent<boolean> { export interface BaseAchievement {
id: string; id: string;
earned: Ref<boolean>; earned: Persistent<boolean>;
complete: VoidFunction; complete: VoidFunction;
type: typeof AchievementType; type: typeof AchievementType;
[Component]: typeof AchievementComponent; [Component]: typeof AchievementComponent;
@ -70,15 +70,16 @@ export type GenericAchievement = Replace<
export function createAchievement<T extends AchievementOptions>( export function createAchievement<T extends AchievementOptions>(
optionsFunc: OptionsFunc<T, Achievement<T>, BaseAchievement> optionsFunc: OptionsFunc<T, Achievement<T>, BaseAchievement>
): Achievement<T> { ): Achievement<T> {
return createLazyProxy(persistent => { const earned = persistent<boolean>(false);
const achievement = Object.assign(persistent, optionsFunc()); return createLazyProxy(() => {
const achievement = optionsFunc();
achievement.id = getUniqueID("achievement-"); achievement.id = getUniqueID("achievement-");
achievement.type = AchievementType; achievement.type = AchievementType;
achievement[Component] = AchievementComponent; achievement[Component] = AchievementComponent;
achievement.earned = achievement[PersistentState]; achievement.earned = earned;
achievement.complete = function () { achievement.complete = function () {
achievement[PersistentState].value = true; earned.value = true;
}; };
processComputable(achievement as T, "visibility"); processComputable(achievement as T, "visibility");
@ -122,5 +123,5 @@ export function createAchievement<T extends AchievementOptions>(
} }
return achievement as unknown as Achievement<T>; return achievement as unknown as Achievement<T>;
}, persistent<boolean>(false)); });
} }

View file

@ -1,6 +1,6 @@
import ClickableComponent from "features/clickables/Clickable.vue"; import ClickableComponent from "features/clickables/Clickable.vue";
import { Resource } from "features/resources/resource"; import { Resource } from "features/resources/resource";
import { Persistent, PersistentState, persistent } from "game/persistence"; import { Persistent, persistent } from "game/persistence";
import Decimal, { DecimalSource, format, formatWhole } from "util/bignum"; import Decimal, { DecimalSource, format, formatWhole } from "util/bignum";
import { import {
Computable, Computable,
@ -49,9 +49,9 @@ export interface BuyableOptions {
onPurchase?: (cost: DecimalSource) => void; onPurchase?: (cost: DecimalSource) => void;
} }
export interface BaseBuyable extends Persistent<DecimalSource> { export interface BaseBuyable {
id: string; id: string;
amount: Ref<DecimalSource>; amount: Persistent<DecimalSource>;
maxed: Ref<boolean>; maxed: Ref<boolean>;
canAfford: Ref<boolean>; canAfford: Ref<boolean>;
canClick: ProcessedComputable<boolean>; canClick: ProcessedComputable<boolean>;
@ -90,8 +90,9 @@ export type GenericBuyable = Replace<
export function createBuyable<T extends BuyableOptions>( export function createBuyable<T extends BuyableOptions>(
optionsFunc: OptionsFunc<T, Buyable<T>, BaseBuyable> optionsFunc: OptionsFunc<T, Buyable<T>, BaseBuyable>
): Buyable<T> { ): Buyable<T> {
return createLazyProxy(persistent => { const amount = persistent<DecimalSource>(0);
const buyable = Object.assign(persistent, optionsFunc()); return createLazyProxy(() => {
const buyable = optionsFunc();
if (buyable.canPurchase == null && (buyable.resource == null || buyable.cost == null)) { if (buyable.canPurchase == null && (buyable.resource == null || buyable.cost == null)) {
console.warn( console.warn(
@ -105,7 +106,7 @@ export function createBuyable<T extends BuyableOptions>(
buyable.type = BuyableType; buyable.type = BuyableType;
buyable[Component] = ClickableComponent; buyable[Component] = ClickableComponent;
buyable.amount = buyable[PersistentState]; buyable.amount = amount;
buyable.canAfford = computed(() => { buyable.canAfford = computed(() => {
const genericBuyable = buyable as GenericBuyable; const genericBuyable = buyable as GenericBuyable;
const cost = unref(genericBuyable.cost); const cost = unref(genericBuyable.cost);
@ -239,5 +240,5 @@ export function createBuyable<T extends BuyableOptions>(
}; };
return buyable as unknown as Buyable<T>; return buyable as unknown as Buyable<T>;
}, persistent<DecimalSource>(0)); });
} }

View file

@ -20,7 +20,7 @@ import {
} from "util/computed"; } from "util/computed";
import { createLazyProxy } from "util/proxies"; import { createLazyProxy } from "util/proxies";
import { computed, Ref, unref } from "vue"; import { computed, Ref, unref } from "vue";
import { State, Persistent, PersistentState, persistent } from "game/persistence"; import { State, Persistent, persistent } from "game/persistence";
export const GridType = Symbol("Grid"); export const GridType = Symbol("Grid");
@ -205,12 +205,13 @@ export interface GridOptions {
onHold?: (id: string | number, state: State) => void; onHold?: (id: string | number, state: State) => void;
} }
export interface BaseGrid extends Persistent<Record<string | number, State>> { export interface BaseGrid {
id: string; id: string;
getID: (id: string | number, state: State) => string; getID: (id: string | number, state: State) => string;
getState: (id: string | number) => State; getState: (id: string | number) => State;
setState: (id: string | number, state: State) => void; setState: (id: string | number, state: State) => void;
cells: Record<string | number, GridCell>; cells: Record<string | number, GridCell>;
cellState: Persistent<Record<string | number, State>>;
type: typeof GridType; type: typeof GridType;
[Component]: typeof GridComponent; [Component]: typeof GridComponent;
[GatherProps]: () => Record<string, unknown>; [GatherProps]: () => Record<string, unknown>;
@ -244,22 +245,25 @@ export type GenericGrid = Replace<
export function createGrid<T extends GridOptions>( export function createGrid<T extends GridOptions>(
optionsFunc: OptionsFunc<T, Grid<T>, BaseGrid> optionsFunc: OptionsFunc<T, Grid<T>, BaseGrid>
): Grid<T> { ): Grid<T> {
return createLazyProxy(persistent => { const cellState = persistent<Record<string | number, State>>({});
const grid = Object.assign(persistent, optionsFunc()); return createLazyProxy(() => {
const grid = optionsFunc();
grid.id = getUniqueID("grid-"); grid.id = getUniqueID("grid-");
grid[Component] = GridComponent; grid[Component] = GridComponent;
grid.cellState = cellState;
grid.getID = function (this: GenericGrid, cell: string | number) { grid.getID = function (this: GenericGrid, cell: string | number) {
return grid.id + "-" + cell; return grid.id + "-" + cell;
}; };
grid.getState = function (this: GenericGrid, cell: string | number) { grid.getState = function (this: GenericGrid, cell: string | number) {
if (this[PersistentState].value[cell] != undefined) { if (this.cellState.value[cell] != undefined) {
return this[PersistentState].value[cell]; return cellState.value[cell];
} }
return this.cells[cell].startState; return this.cells[cell].startState;
}; };
grid.setState = function (this: GenericGrid, cell: string | number, state: State) { grid.setState = function (this: GenericGrid, cell: string | number, state: State) {
this[PersistentState].value[cell] = state; cellState.value[cell] = state;
}; };
grid.cells = createGridProxy(grid as GenericGrid); grid.cells = createGridProxy(grid as GenericGrid);
@ -301,5 +305,5 @@ export function createGrid<T extends GridOptions>(
}; };
return grid as unknown as Grid<T>; return grid as unknown as Grid<T>;
}, persistent({})); });
} }

View file

@ -1,15 +1,16 @@
import InfoboxComponent from "features/infoboxes/Infobox.vue";
import { import {
CoercableComponent, CoercableComponent,
Component, Component,
OptionsFunc,
GatherProps, GatherProps,
getUniqueID, getUniqueID,
OptionsFunc,
Replace, Replace,
setDefault, setDefault,
StyleValue, StyleValue,
Visibility Visibility
} from "features/feature"; } from "features/feature";
import InfoboxComponent from "features/infoboxes/Infobox.vue";
import { Persistent, persistent } from "game/persistence";
import { import {
Computable, Computable,
GetComputableType, GetComputableType,
@ -18,8 +19,7 @@ import {
ProcessedComputable ProcessedComputable
} from "util/computed"; } from "util/computed";
import { createLazyProxy } from "util/proxies"; import { createLazyProxy } from "util/proxies";
import { Ref, unref } from "vue"; import { unref } from "vue";
import { Persistent, PersistentState, persistent } from "game/persistence";
export const InfoboxType = Symbol("Infobox"); export const InfoboxType = Symbol("Infobox");
@ -34,9 +34,9 @@ export interface InfoboxOptions {
display: Computable<CoercableComponent>; display: Computable<CoercableComponent>;
} }
export interface BaseInfobox extends Persistent<boolean> { export interface BaseInfobox {
id: string; id: string;
collapsed: Ref<boolean>; collapsed: Persistent<boolean>;
type: typeof InfoboxType; type: typeof InfoboxType;
[Component]: typeof InfoboxComponent; [Component]: typeof InfoboxComponent;
[GatherProps]: () => Record<string, unknown>; [GatherProps]: () => Record<string, unknown>;
@ -66,13 +66,14 @@ export type GenericInfobox = Replace<
export function createInfobox<T extends InfoboxOptions>( export function createInfobox<T extends InfoboxOptions>(
optionsFunc: OptionsFunc<T, Infobox<T>, BaseInfobox> optionsFunc: OptionsFunc<T, Infobox<T>, BaseInfobox>
): Infobox<T> { ): Infobox<T> {
return createLazyProxy(persistent => { const collapsed = persistent<boolean>(false);
const infobox = Object.assign(persistent, optionsFunc()); return createLazyProxy(() => {
const infobox = optionsFunc();
infobox.id = getUniqueID("infobox-"); infobox.id = getUniqueID("infobox-");
infobox.type = InfoboxType; infobox.type = InfoboxType;
infobox[Component] = InfoboxComponent; infobox[Component] = InfoboxComponent;
infobox.collapsed = infobox[PersistentState]; infobox.collapsed = collapsed;
processComputable(infobox as T, "visibility"); processComputable(infobox as T, "visibility");
setDefault(infobox, "visibility", Visibility.Visible); setDefault(infobox, "visibility", Visibility.Visible);
@ -112,5 +113,5 @@ export function createInfobox<T extends InfoboxOptions>(
}; };
return infobox as unknown as Infobox<T>; return infobox as unknown as Infobox<T>;
}, persistent<boolean>(false)); });
} }

View file

@ -14,7 +14,7 @@ import {
import MilestoneComponent from "features/milestones/Milestone.vue"; import MilestoneComponent from "features/milestones/Milestone.vue";
import { globalBus } from "game/events"; import { globalBus } from "game/events";
import "game/notifications"; import "game/notifications";
import { persistent, Persistent, PersistentState } from "game/persistence"; import { persistent, Persistent } from "game/persistence";
import settings, { registerSettingField } from "game/settings"; import settings, { registerSettingField } from "game/settings";
import { camelToTitle } from "util/common"; import { camelToTitle } from "util/common";
import { import {
@ -26,7 +26,7 @@ import {
} from "util/computed"; } from "util/computed";
import { createLazyProxy } from "util/proxies"; import { createLazyProxy } from "util/proxies";
import { coerceComponent, isCoercableComponent } from "util/vue"; import { coerceComponent, isCoercableComponent } from "util/vue";
import { computed, Ref, unref, watchEffect } from "vue"; import { computed, unref, watchEffect } from "vue";
import { useToast } from "vue-toastification"; import { useToast } from "vue-toastification";
const toast = useToast(); const toast = useToast();
@ -57,9 +57,9 @@ export interface MilestoneOptions {
onComplete?: VoidFunction; onComplete?: VoidFunction;
} }
export interface BaseMilestone extends Persistent<boolean> { export interface BaseMilestone {
id: string; id: string;
earned: Ref<boolean>; earned: Persistent<boolean>;
complete: VoidFunction; complete: VoidFunction;
type: typeof MilestoneType; type: typeof MilestoneType;
[Component]: typeof MilestoneComponent; [Component]: typeof MilestoneComponent;
@ -86,15 +86,16 @@ export type GenericMilestone = Replace<
export function createMilestone<T extends MilestoneOptions>( export function createMilestone<T extends MilestoneOptions>(
optionsFunc: OptionsFunc<T, Milestone<T>, BaseMilestone> optionsFunc: OptionsFunc<T, Milestone<T>, BaseMilestone>
): Milestone<T> { ): Milestone<T> {
const earned = persistent<boolean>(false);
return createLazyProxy(persistent => { return createLazyProxy(persistent => {
const milestone = Object.assign(persistent, optionsFunc()); const milestone = Object.assign(persistent, optionsFunc());
milestone.id = getUniqueID("milestone-"); milestone.id = getUniqueID("milestone-");
milestone.type = MilestoneType; milestone.type = MilestoneType;
milestone[Component] = MilestoneComponent; milestone[Component] = MilestoneComponent;
milestone.earned = milestone[PersistentState]; milestone.earned = earned;
milestone.complete = function () { milestone.complete = function () {
milestone[PersistentState].value = true; earned.value = true;
}; };
processComputable(milestone as T, "visibility"); processComputable(milestone as T, "visibility");
@ -168,7 +169,7 @@ export function createMilestone<T extends MilestoneOptions>(
} }
return milestone as unknown as Milestone<T>; return milestone as unknown as Milestone<T>;
}, persistent<boolean>(false)); });
} }
declare module "game/settings" { declare module "game/settings" {

View file

@ -11,7 +11,7 @@ import {
} from "features/feature"; } from "features/feature";
import TabButtonComponent from "features/tabs/TabButton.vue"; import TabButtonComponent from "features/tabs/TabButton.vue";
import TabFamilyComponent from "features/tabs/TabFamily.vue"; import TabFamilyComponent from "features/tabs/TabFamily.vue";
import { Persistent, PersistentState, persistent } from "game/persistence"; import { Persistent, persistent } from "game/persistence";
import { import {
Computable, Computable,
GetComputableType, GetComputableType,
@ -65,11 +65,11 @@ export interface TabFamilyOptions {
style?: Computable<StyleValue>; style?: Computable<StyleValue>;
} }
export interface BaseTabFamily extends Persistent<string> { export interface BaseTabFamily {
id: string; id: string;
tabs: Record<string, TabButtonOptions>; tabs: Record<string, TabButtonOptions>;
activeTab: Ref<GenericTab | CoercableComponent | null>; activeTab: Ref<GenericTab | CoercableComponent | null>;
selected: Ref<string>; selected: Persistent<string>;
type: typeof TabFamilyType; type: typeof TabFamilyType;
[Component]: typeof TabFamilyComponent; [Component]: typeof TabFamilyComponent;
[GatherProps]: () => Record<string, unknown>; [GatherProps]: () => Record<string, unknown>;
@ -99,8 +99,10 @@ export function createTabFamily<T extends TabFamilyOptions>(
throw "Cannot create tab family with 0 tabs"; throw "Cannot create tab family with 0 tabs";
} }
return createLazyProxy(persistent => { const selected = persistent(Object.keys(tabs)[0]);
const tabFamily = Object.assign(persistent, optionsFunc?.()); return createLazyProxy(() => {
const tabFamily =
optionsFunc?.() || ({} as ReturnType<OptionsFunc<T, TabFamily<T>, BaseTabFamily>>);
tabFamily.id = getUniqueID("tabFamily-"); tabFamily.id = getUniqueID("tabFamily-");
tabFamily.type = TabFamilyType; tabFamily.type = TabFamilyType;
@ -124,15 +126,14 @@ export function createTabFamily<T extends TabFamilyOptions>(
}, },
{} {}
); );
tabFamily.selected = tabFamily[PersistentState]; tabFamily.selected = selected;
tabFamily.activeTab = computed(() => { tabFamily.activeTab = computed(() => {
const tabs = unref(processedTabFamily.tabs); const tabs = unref(processedTabFamily.tabs);
if ( if (
tabFamily[PersistentState].value in tabs && selected.value in tabs &&
unref(tabs[processedTabFamily[PersistentState].value].visibility) === unref(tabs[selected.value].visibility) === Visibility.Visible
Visibility.Visible
) { ) {
return unref(tabs[processedTabFamily[PersistentState].value].tab); return unref(tabs[selected.value].tab);
} }
const firstTab = Object.values(tabs).find( const firstTab = Object.values(tabs).find(
tab => unref(tab.visibility) === Visibility.Visible tab => unref(tab.visibility) === Visibility.Visible
@ -156,5 +157,5 @@ export function createTabFamily<T extends TabFamilyOptions>(
// This is necessary because board.types is different from T and TabFamily // This is necessary because board.types is different from T and TabFamily
const processedTabFamily = tabFamily as unknown as TabFamily<T>; const processedTabFamily = tabFamily as unknown as TabFamily<T>;
return processedTabFamily; return processedTabFamily;
}, persistent(Object.keys(tabs)[0])); });
} }

View file

@ -24,7 +24,7 @@ import {
} from "util/computed"; } from "util/computed";
import { createLazyProxy } from "util/proxies"; import { createLazyProxy } from "util/proxies";
import { computed, Ref, unref } from "vue"; import { computed, Ref, unref } from "vue";
import { persistent, Persistent, PersistentState } from "game/persistence"; import { persistent, Persistent } from "game/persistence";
export const UpgradeType = Symbol("Upgrade"); export const UpgradeType = Symbol("Upgrade");
@ -47,9 +47,9 @@ export interface UpgradeOptions {
onPurchase?: VoidFunction; onPurchase?: VoidFunction;
} }
export interface BaseUpgrade extends Persistent<boolean> { export interface BaseUpgrade {
id: string; id: string;
bought: Ref<boolean>; bought: Persistent<boolean>;
canPurchase: Ref<boolean>; canPurchase: Ref<boolean>;
purchase: VoidFunction; purchase: VoidFunction;
type: typeof UpgradeType; type: typeof UpgradeType;
@ -81,8 +81,9 @@ export type GenericUpgrade = Replace<
export function createUpgrade<T extends UpgradeOptions>( export function createUpgrade<T extends UpgradeOptions>(
optionsFunc: OptionsFunc<T, Upgrade<T>, BaseUpgrade> optionsFunc: OptionsFunc<T, Upgrade<T>, BaseUpgrade>
): Upgrade<T> { ): Upgrade<T> {
return createLazyProxy(persistent => { const bought = persistent<boolean>(false);
const upgrade = Object.assign(persistent, optionsFunc()); return createLazyProxy(() => {
const upgrade = optionsFunc();
upgrade.id = getUniqueID("upgrade-"); upgrade.id = getUniqueID("upgrade-");
upgrade.type = UpgradeType; upgrade.type = UpgradeType;
upgrade[Component] = UpgradeComponent; upgrade[Component] = UpgradeComponent;
@ -94,7 +95,7 @@ export function createUpgrade<T extends UpgradeOptions>(
); );
} }
upgrade.bought = upgrade[PersistentState]; upgrade.bought = bought;
if (upgrade.canAfford == null) { if (upgrade.canAfford == null) {
upgrade.canAfford = computed(() => { upgrade.canAfford = computed(() => {
const genericUpgrade = upgrade as GenericUpgrade; const genericUpgrade = upgrade as GenericUpgrade;
@ -124,7 +125,7 @@ export function createUpgrade<T extends UpgradeOptions>(
unref(genericUpgrade.cost) unref(genericUpgrade.cost)
); );
} }
genericUpgrade[PersistentState].value = true; bought.value = true;
genericUpgrade.onPurchase?.(); genericUpgrade.onPurchase?.();
}; };
@ -167,7 +168,7 @@ export function createUpgrade<T extends UpgradeOptions>(
}; };
return upgrade as unknown as Upgrade<T>; return upgrade as unknown as Upgrade<T>;
}, persistent<boolean>(false)); });
} }
export function setupAutoPurchase( export function setupAutoPurchase(