Make layers lazy instantiate

This commit is contained in:
thepaperpilot 2022-01-27 22:47:26 -06:00
parent 90e49e196f
commit 067ba6ce90
8 changed files with 929 additions and 909 deletions

View file

@ -118,6 +118,7 @@ export type LayerTreeNode<T extends LayerTreeNodeOptions> = Replace<
append: ProcessedComputable<boolean>; append: ProcessedComputable<boolean>;
} }
>; >;
export type GenericLayerTreeNode = LayerTreeNode<LayerTreeNodeOptions>;
export function createLayerTreeNode<T extends LayerTreeNodeOptions>(options: T): LayerTreeNode<T> { export function createLayerTreeNode<T extends LayerTreeNodeOptions>(options: T): LayerTreeNode<T> {
processComputable(options as T, "append"); processComputable(options as T, "append");

View file

@ -1,5 +1,5 @@
import Tooltip from "@/components/system/Tooltip.vue"; import Tooltip from "@/components/system/Tooltip.vue";
import { points as mainPoints } from "@/data/mod"; import { main } from "@/data/mod";
import { createAchievement } from "@/features/achievement"; import { createAchievement } from "@/features/achievement";
import { createGrid } from "@/features/grid"; import { createGrid } from "@/features/grid";
import { createResource } from "@/features/resource"; import { createResource } from "@/features/resource";
@ -8,108 +8,110 @@ import { createLayer } from "@/game/layers";
import { DecimalSource } from "@/lib/break_eternity"; import { DecimalSource } from "@/lib/break_eternity";
import Decimal from "@/util/bignum"; import Decimal from "@/util/bignum";
import { render, renderRow } from "@/util/vue"; import { render, renderRow } from "@/util/vue";
import { points as fPoints } from "./f"; import f from "./f";
const id = "a"; const layer = createLayer(() => {
const color = "yellow"; const id = "a";
const name = "Achievements"; const color = "yellow";
const points = createResource<DecimalSource>(0, "achievement power"); const name = "Achievements";
const points = createResource<DecimalSource>(0, "achievement power");
export const treeNode = createTreeNode({ const treeNode = createTreeNode({
tooltip: "Achievements", tooltip: "Achievements",
onClick() { onClick() {
// TODO open this layer as a modal // TODO open this layer as a modal
}
});
const ach1 = createAchievement({
image: "https://unsoftcapped2.github.io/The-Modding-Tree-2/discord.png",
display: "Get me!",
tooltip() {
if (this.earned.value) {
return "You did it!";
} }
return "How did this happen?"; });
},
shouldEarn: true const ach1 = createAchievement({
}); image: "https://unsoftcapped2.github.io/The-Modding-Tree-2/discord.png",
const ach2 = createAchievement({ display: "Get me!",
display: "Impossible!", tooltip() {
tooltip() { if (this.earned.value) {
if (this.earned.value) { return "You did it!";
return "HOW????"; }
return "How did this happen?";
},
shouldEarn: true
});
const ach2 = createAchievement({
display: "Impossible!",
tooltip() {
if (this.earned.value) {
return "HOW????";
}
return "Mwahahaha!";
},
style: { color: "#04e050" }
});
const ach3 = createAchievement({
display: "EIEIO",
tooltip:
"Get a farm point.\n\nReward: The dinosaur is now your friend (you can max Farm Points).",
shouldEarn: function () {
return Decimal.gte(f.value.points.value, 1);
},
onComplete() {
console.log("Bork bork bork!");
} }
return "Mwahahaha!"; });
}, const achievements = [ach1, ach2, ach3];
style: { color: "#04e050" }
});
const ach3 = createAchievement({
display: "EIEIO",
tooltip:
"Get a farm point.\n\nReward: The dinosaur is now your friend (you can max Farm Points).",
shouldEarn: function () {
return Decimal.gte(fPoints.value, 1);
},
onComplete() {
console.log("Bork bork bork!");
}
});
const achievements = [ach1, ach2, ach3];
const grid = createGrid({ const grid = createGrid({
rows: 2, rows: 2,
cols: 2, cols: 2,
getStartState(id) { getStartState(id) {
return id; return id;
}, },
getStyle(id) { getStyle(id) {
return { backgroundColor: `#${(Number(id) * 1234) % 999999}` }; return { backgroundColor: `#${(Number(id) * 1234) % 999999}` };
}, },
// TODO display should return an object // TODO display should return an object
getTitle(id) { getTitle(id) {
let direction; let direction;
if (id === "101") { if (id === "101") {
direction = "top"; direction = "top";
} else if (id === "102") { } else if (id === "102") {
direction = "bottom"; direction = "bottom";
} else if (id === "201") { } else if (id === "201") {
direction = "left"; direction = "left";
} else if (id === "202") { } else if (id === "202") {
direction = "right"; direction = "right";
}
return (
<Tooltip display={JSON.stringify(this.cells[id].style)} {...{ direction }}>
<h3>Gridable #{id}</h3>
</Tooltip>
);
},
getDisplay(id) {
return String(id);
},
getCanClick(): boolean {
return Decimal.eq(main.value.points.value, 10);
},
onClick(id, state) {
this.cells[id].state = Number(state) + 1;
} }
return ( });
<Tooltip display={JSON.stringify(this.cells[id].style)} {...{ direction }}>
<h3>Gridable #{id}</h3>
</Tooltip>
);
},
getDisplay(id) {
return String(id);
},
getCanClick() {
return Decimal.eq(mainPoints.value, 10);
},
onClick(id, state) {
this.cells[id].state = Number(state) + 1;
}
});
const display = ( const display = (
<template> <template>
{renderRow(achievements)} {renderRow(achievements)}
{render(grid)} {render(grid)}
</template> </template>
); );
const layer = createLayer({ return {
id, id,
color, color,
name, name,
points, points,
achievements, achievements,
grid, grid,
treeNode, treeNode,
display display
};
}); });
export default layer; export default layer;

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
import MainDisplay from "@/components/features/MainDisplay.vue"; import MainDisplay from "@/components/features/MainDisplay.vue";
import { createLayerTreeNode, createResetButton } from "@/data/common"; import { createLayerTreeNode, createResetButton } from "@/data/common";
import { points as mainPoints, tree as mainTree } from "@/data/mod"; import { main } from "@/data/mod";
import { createClickable } from "@/features/clickable"; import { createClickable } from "@/features/clickable";
import { createExponentialScaling, createIndependentConversion } from "@/features/conversion"; import { createExponentialScaling, createIndependentConversion } from "@/features/conversion";
import { persistent } from "@/features/feature"; import { persistent } from "@/features/feature";
@ -10,169 +10,169 @@ import { createResource, displayResource } from "@/features/resource";
import { createLayer, getLayer } from "@/game/layers"; import { createLayer, getLayer } from "@/game/layers";
import Decimal, { DecimalSource, formatWhole } from "@/util/bignum"; import Decimal, { DecimalSource, formatWhole } from "@/util/bignum";
import { render } from "@/util/vue"; import { render } from "@/util/vue";
import { otherThingy } from "./c"; import c from "./c";
const f = getLayer("f"); const layer = createLayer(() => {
const id = "f";
const color = "#FE0102";
const name = "Farms";
const points = createResource<DecimalSource>(0, "farm points");
const boop = persistent<boolean>(false);
const id = "f"; const coolInfo = createInfobox({
const color = "#FE0102"; title: "Lore",
const name = "Farms"; titleStyle: { color: "#FE0000" },
export const points = createResource<DecimalSource>(0, "farm points"); display: "DEEP LORE!",
export const boop = persistent<boolean>(false); bodyStyle: { backgroundColor: "#0000EE" }
});
const coolInfo = createInfobox({ const clickableState = persistent<string>("Start");
title: "Lore", const clickable = createClickable({
titleStyle: { color: "#FE0000" }, display: {
display: "DEEP LORE!", title: "Clicky clicky!",
bodyStyle: { backgroundColor: "#0000EE" } description() {
}); return "Current state:<br>" + clickableState.value;
}
const clickableState = persistent<string>("Start"); },
const clickable = createClickable({ initialState: "Start",
display: { canClick() {
title: "Clicky clicky!", return clickableState.value !== "Borkened...";
description() { },
return "Current state:<br>" + clickableState.value; onClick() {
switch (clickableState.value) {
case "Start":
clickableState.value = "A new state!";
break;
case "A new state!":
clickableState.value = "Keep going!";
break;
case "Keep going!":
clickableState.value = "Maybe that's a bit too far...";
break;
case "Maybe that's a bit too far...":
//makeParticles(coolParticle, 4)
clickableState.value = "Borkened...";
break;
default:
clickableState.value = "Start";
break;
}
},
onHold() {
console.log("Clickkkkk...");
},
style() {
switch (clickableState.value) {
case "Start":
return { "background-color": "green" };
case "A new state!":
return { "background-color": "yellow" };
case "Keep going!":
return { "background-color": "orange" };
case "Maybe that's a bit too far...":
return { "background-color": "red" };
default:
return {};
}
} }
}, });
initialState: "Start",
canClick() { const resetClickable = createClickable({
return clickableState.value !== "Borkened..."; onClick() {
}, if (clickableState.value == "Borkened...") {
onClick() {
switch (clickableState.value) {
case "Start":
clickableState.value = "A new state!";
break;
case "A new state!":
clickableState.value = "Keep going!";
break;
case "Keep going!":
clickableState.value = "Maybe that's a bit too far...";
break;
case "Maybe that's a bit too far...":
//makeParticles(coolParticle, 4)
clickableState.value = "Borkened...";
break;
default:
clickableState.value = "Start"; clickableState.value = "Start";
break; }
},
display() {
return clickableState.value == "Borkened..." ? "Fix the clickable!" : "Does nothing";
} }
}, });
onHold() {
console.log("Clickkkkk..."); const reset = createReset({
}, thingsToReset: () => [getLayer("f")]
style() { });
switch (clickableState.value) {
case "Start": const conversion = createIndependentConversion({
return { "background-color": "green" }; scaling: createExponentialScaling(10, 3, 0.5),
case "A new state!": baseResource: main.value.points,
return { "background-color": "yellow" }; gainResource: points,
case "Keep going!": modifyGainAmount: gain => Decimal.times(gain, c.value.otherThingy.value)
return { "background-color": "orange" }; });
case "Maybe that's a bit too far...":
return { "background-color": "red" }; const treeNode = createLayerTreeNode({
default: layerID: id,
return {}; color,
reset,
tooltip() {
if (treeNode.canClick.value) {
return `${displayResource(points)} ${points.displayName}`;
}
return `This weird farmer dinosaur will only see you if you have at least 10 points. You only have ${displayResource(
main.value.points
)}`;
},
canClick() {
return Decimal.gte(main.value.points.value, 10);
} }
} });
});
const resetClickable = createClickable({ const resetButton = createResetButton({
onClick() { conversion,
if (clickableState.value == "Borkened...") { tree: main.value.tree,
clickableState.value = "Start"; treeNode,
display() {
if (this.conversion.buyMax) {
return (
<span>
Hi! I'm a <u>weird dinosaur</u> and I'll give you{" "}
<b>{formatWhole(this.conversion.currentGain.value)}</b> Farm Points in
exchange for all of your points and lollipops! (You'll get another one at{" "}
{formatWhole(this.conversion.nextAt.value)} points)
</span>
);
} else {
return (
<span>
Hi! I'm a <u>weird dinosaur</u> and I'll give you a Farm Point in exchange
for all of your points and lollipops! (At least{" "}
{formatWhole(this.conversion.nextAt.value)} points)
</span>
);
}
} }
}, });
display() {
return clickableState.value == "Borkened..." ? "Fix the clickable!" : "Does nothing";
}
});
const reset = createReset({ const tab = (): JSX.Element => (
thingsToReset: () => [f()] <template>
}); {render(coolInfo)}
<MainDisplay resource={points} color={color} />
{render(resetButton)}
<div>You have {formatWhole(conversion.baseResource.value)} points</div>
<div>
<br />
<img src="https://images.beano.com/store/24ab3094eb95e5373bca1ccd6f330d4406db8d1f517fc4170b32e146f80d?auto=compress%2Cformat&dpr=1&w=390" />
<div>Bork Bork!</div>
</div>
{render(clickable)}
</template>
);
const conversion = createIndependentConversion({ return {
scaling: createExponentialScaling(10, 3, 0.5), id,
baseResource: mainPoints, color,
gainResource: points, name,
modifyGainAmount: gain => Decimal.times(gain, otherThingy.value) points,
}); boop,
coolInfo,
export const treeNode = createLayerTreeNode({ clickable,
layerID: id, clickableState,
color, resetClickable,
reset, reset,
tooltip() { conversion,
if (treeNode.canClick.value) { treeNode,
return `${displayResource(points)} ${points.displayName}`; resetButton,
} display: tab
return `This weird farmer dinosaur will only see you if you have at least 10 points. You only have ${displayResource( };
mainPoints
)}`;
},
canClick() {
return Decimal.gte(mainPoints.value, 10);
}
});
const resetButton = createResetButton({
conversion,
tree: mainTree,
treeNode,
display() {
if (this.conversion.buyMax) {
return (
<span>
Hi! I'm a <u>weird dinosaur</u> and I'll give you{" "}
<b>{formatWhole(this.conversion.currentGain.value)}</b> Farm Points in exchange
for all of your points and lollipops! (You'll get another one at{" "}
{formatWhole(this.conversion.nextAt.value)} points)
</span>
);
} else {
return (
<span>
Hi! I'm a <u>weird dinosaur</u> and I'll give you a Farm Point in exchange for
all of your points and lollipops! (At least{" "}
{formatWhole(this.conversion.nextAt.value)} points)
</span>
);
}
}
});
export const tab = (): JSX.Element => (
<template>
{render(coolInfo)}
<MainDisplay resource={points} color={color} />
{render(resetButton)}
<div>You have {formatWhole(conversion.baseResource.value)} points</div>
<div>
<br />
<img src="https://images.beano.com/store/24ab3094eb95e5373bca1ccd6f330d4406db8d1f517fc4170b32e146f80d?auto=compress%2Cformat&dpr=1&w=390" />
<div>Bork Bork!</div>
</div>
{render(clickable)}
</template>
);
const layer = createLayer({
id,
color,
name,
points,
boop,
coolInfo,
clickable,
clickableState,
resetClickable,
reset,
conversion,
treeNode,
resetButton,
display: tab
}); });
export default layer; export default layer;

View file

@ -10,97 +10,97 @@ import Decimal, { format, formatSmall, formatTime } from "@/util/bignum";
import { render } from "@/util/vue"; import { render } from "@/util/vue";
import { computed, ref } from "vue"; import { computed, ref } from "vue";
import a from "./layers/aca/a"; import a from "./layers/aca/a";
import c, { import c from "./layers/aca/c";
generatorUpgrade,
lollipopMultiplierEffect,
lollipopMultiplierUpgrade
} from "./layers/aca/c";
import f from "./layers/aca/f"; import f from "./layers/aca/f";
export const points = createResource<DecimalSource>(0); export const main = createLayer(() => {
const best = trackBest(points); const points = createResource<DecimalSource>(0);
const total = trackTotal(points); const best = trackBest(points);
const oomps = trackOOMPS(points); const total = trackTotal(points);
const showModal = ref(false); const oomps = trackOOMPS(points);
const showModal = ref(false);
const pointGain = computed(() => { const pointGain = computed(() => {
if (!generatorUpgrade.bought) return new Decimal(0); if (!c.value.generatorUpgrade.bought) return new Decimal(0);
let gain = new Decimal(3.19); let gain = new Decimal(3.19);
if (lollipopMultiplierUpgrade.bought) gain = gain.times(lollipopMultiplierEffect.value); if (c.value.lollipopMultiplierUpgrade.bought)
return gain; gain = gain.times(c.value.lollipopMultiplierEffect.value);
}); return gain;
globalBus.on("update", diff => { });
points.value = Decimal.add(points.value, Decimal.times(pointGain.value, diff)); globalBus.on("update", diff => {
}); points.value = Decimal.add(points.value, Decimal.times(pointGain.value, diff));
});
// Note: Casting as generic tree to avoid recursive type definitions // Note: Casting as generic tree to avoid recursive type definitions
export const tree = createTree({ const tree = createTree({
nodes: () => [[c.treeNode], [f.treeNode, c.spook]], nodes: [[c.value.treeNode], [f.value.treeNode, c.value.spook]],
leftSideNodes: [a.treeNode, c.h], leftSideNodes: [a.value.treeNode, c.value.h],
branches: [ branches: [
{ {
startNode: f.treeNode, startNode: f.value.treeNode,
endNode: c.treeNode, endNode: c.value.treeNode,
stroke: "blue", stroke: "blue",
"stroke-width": "25px", "stroke-width": "25px",
style: { style: {
filter: "blur(5px)" filter: "blur(5px)"
} }
}, },
{ startNode: c.treeNode, endNode: c.g } { startNode: c.value.treeNode, endNode: c.value.g }
] ]
}) as GenericTree; }) as GenericTree;
// Note: layers don't _need_ a reference to everything, but I'd recommend it over trying to remember // Note: layers don't _need_ a reference to everything,
// what does and doesn't need to be included. Officially all you need are anything with persistency // but I'd recommend it over trying to remember what does and doesn't need to be included.
export const main = createLayer({ // Officially all you need are anything with persistency or that you want to access elsewhere
id: "main", return {
name: "Tree", id: "main",
links: tree.links, name: "Tree",
display: ( links: tree.links,
<template> display: (
<div v-show={player.devSpeed === 0}>Game Paused</div> <template>
<div v-show={player.devSpeed && player.devSpeed !== 1}> <div v-show={player.devSpeed === 0}>Game Paused</div>
Dev Speed: {format(player.devSpeed || 0)}x <div v-show={player.devSpeed && player.devSpeed !== 1}>
</div> Dev Speed: {format(player.devSpeed || 0)}x
<div v-show={player.offlineTime != undefined}> </div>
Offline Time: {formatTime(player.offlineTime || 0)} <div v-show={player.offlineTime != undefined}>
</div> Offline Time: {formatTime(player.offlineTime || 0)}
<div> </div>
<span v-show={Decimal.lt(points.value, "1e1000")}>You have </span> <div>
<h2>{format(points.value)}</h2> <span v-show={Decimal.lt(points.value, "1e1000")}>You have </span>
<span v-show={Decimal.lt(points.value, "1e1e6")}> points</span> <h2>{format(points.value)}</h2>
</div> <span v-show={Decimal.lt(points.value, "1e1e6")}> points</span>
<div v-show={Decimal.gt(pointGain.value, 0)}> </div>
({oomps.value === "" ? formatSmall(pointGain.value) : oomps.value}/sec) <div v-show={Decimal.gt(pointGain.value, 0)}>
</div> ({oomps.value === "" ? formatSmall(pointGain.value) : oomps.value}/sec)
<Spacer /> </div>
<Modal <Spacer />
modelValue={showModal.value} <Modal
onUpdate:modelValue={value => (showModal.value = value)} modelValue={showModal.value}
> onUpdate:modelValue={value => (showModal.value = value)}
<svg style="height: 80vmin; width: 80vmin;"> >
<path d="M 32 222 Q 128 222, 128 0 Q 128 222, 224 222 L 224 224 L 32 224" /> <svg style="height: 80vmin; width: 80vmin;">
<path d="M 32 222 Q 128 222, 128 0 Q 128 222, 224 222 L 224 224 L 32 224" />
<circle cx="64" cy="128" r="64" fill="#8da8b0" /> <circle cx="64" cy="128" r="64" fill="#8da8b0" />
<circle cx="128" cy="64" r="64" fill="#71368a" /> <circle cx="128" cy="64" r="64" fill="#71368a" />
<circle cx="192" cy="128" r="64" fill="#fa8508" /> <circle cx="192" cy="128" r="64" fill="#fa8508" />
</svg> </svg>
</Modal> </Modal>
{render(tree)} {render(tree)}
</template> </template>
), ),
points, points,
best, best,
total, total,
oomps, oomps,
tree tree
};
}); });
export const getInitialLayers = ( export const getInitialLayers = (
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
player: Partial<PlayerData> player: Partial<PlayerData>
): Array<GenericLayer> => [main, f, c, a]; ): Array<GenericLayer> => [main.value, f.value, c.value, a.value];
export const hasWon = computed(() => { export const hasWon = computed(() => {
return false; return false;

View file

@ -37,7 +37,7 @@ type BuyableDisplay =
export interface BuyableOptions { export interface BuyableOptions {
visibility?: Computable<Visibility>; visibility?: Computable<Visibility>;
cost?: Computable<DecimalSource>; cost?: Computable<DecimalSource>;
resource?: Computable<Resource>; resource?: Resource;
canPurchase?: Computable<boolean>; canPurchase?: Computable<boolean>;
purchaseLimit?: Computable<DecimalSource>; purchaseLimit?: Computable<DecimalSource>;
classes?: Computable<Record<string, boolean>>; classes?: Computable<Record<string, boolean>>;

View file

@ -34,7 +34,7 @@ export interface ChallengeOptions {
canComplete?: Computable<boolean | DecimalSource>; canComplete?: Computable<boolean | DecimalSource>;
completionLimit?: Computable<DecimalSource>; completionLimit?: Computable<DecimalSource>;
mark?: Computable<boolean | string>; mark?: Computable<boolean | string>;
resource?: Computable<Resource>; resource?: Resource;
goal?: Computable<DecimalSource>; goal?: Computable<DecimalSource>;
classes?: Computable<Record<string, boolean>>; classes?: Computable<Record<string, boolean>>;
style?: Computable<StyleValue>; style?: Computable<StyleValue>;
@ -72,7 +72,6 @@ export type Challenge<T extends ChallengeOptions> = Replace<
canComplete: GetComputableTypeWithDefault<T["canComplete"], Ref<boolean>>; canComplete: GetComputableTypeWithDefault<T["canComplete"], Ref<boolean>>;
completionLimit: GetComputableTypeWithDefault<T["completionLimit"], 1>; completionLimit: GetComputableTypeWithDefault<T["completionLimit"], 1>;
mark: GetComputableTypeWithDefault<T["mark"], Ref<boolean>>; mark: GetComputableTypeWithDefault<T["mark"], Ref<boolean>>;
resource: GetComputableType<T["resource"]>;
goal: GetComputableType<T["goal"]>; goal: GetComputableType<T["goal"]>;
classes: GetComputableType<T["classes"]>; classes: GetComputableType<T["classes"]>;
style: GetComputableType<T["style"]>; style: GetComputableType<T["style"]>;
@ -160,7 +159,7 @@ export function createChallenge<T extends ChallengeOptions>(
if (!proxy.active.value || proxy.resource == null || proxy.goal == null) { if (!proxy.active.value || proxy.resource == null || proxy.goal == null) {
return false; return false;
} }
return Decimal.gte(unref<Resource>(proxy.resource).value, unref(proxy.goal)); return Decimal.gte(proxy.resource.value, unref(proxy.goal));
}); });
} }
if (challenge.mark == null) { if (challenge.mark == null) {
@ -174,7 +173,6 @@ export function createChallenge<T extends ChallengeOptions>(
processComputable(challenge as T, "completionLimit"); processComputable(challenge as T, "completionLimit");
setDefault(challenge, "completionLimit", 1); setDefault(challenge, "completionLimit", 1);
processComputable(challenge as T, "mark"); processComputable(challenge as T, "mark");
processComputable(challenge as T, "resource");
processComputable(challenge as T, "goal"); processComputable(challenge as T, "goal");
processComputable(challenge as T, "classes"); processComputable(challenge as T, "classes");
processComputable(challenge as T, "style"); processComputable(challenge as T, "style");

View file

@ -17,6 +17,7 @@ import {
} from "@/util/computed"; } from "@/util/computed";
import { createProxy } from "@/util/proxies"; import { createProxy } from "@/util/proxies";
import { createNanoEvents, Emitter } from "nanoevents"; import { createNanoEvents, Emitter } from "nanoevents";
import { customRef, Ref } from "vue";
import { globalBus } from "./events"; import { globalBus } from "./events";
import player from "./player"; import player from "./player";
@ -81,27 +82,40 @@ export type GenericLayer = Replace<
} }
>; >;
export function createLayer<T extends LayerOptions>(options: T): Layer<T> { export function createLayer<T extends LayerOptions>(optionsFunc: () => T): Ref<Layer<T>> {
const layer: T & Partial<BaseLayer> = options; let layer: Layer<T> | null = null;
const emitter = (layer.emitter = createNanoEvents<LayerEvents>()); return customRef(track => {
layer.on = emitter.on.bind(emitter); return {
layer.emit = emitter.emit.bind(emitter); get() {
if (layer == undefined) {
const partialLayer = optionsFunc() as T & Partial<BaseLayer>;
const emitter = (partialLayer.emitter = createNanoEvents<LayerEvents>());
partialLayer.on = emitter.on.bind(emitter);
partialLayer.emit = emitter.emit.bind(emitter);
layer.minimized = persistent(false); partialLayer.minimized = persistent(false);
processComputable(layer as T, "color"); processComputable(partialLayer as T, "color");
processComputable(layer as T, "display"); processComputable(partialLayer as T, "display");
processComputable(layer as T, "name"); processComputable(partialLayer as T, "name");
setDefault(layer, "name", options.id); setDefault(partialLayer, "name", partialLayer.id);
processComputable(layer as T, "minWidth"); processComputable(partialLayer as T, "minWidth");
setDefault(layer, "minWidth", 600); setDefault(partialLayer, "minWidth", 600);
processComputable(layer as T, "minimizable"); processComputable(partialLayer as T, "minimizable");
setDefault(layer, "minimizable", true); setDefault(partialLayer, "minimizable", true);
processComputable(layer as T, "links"); processComputable(partialLayer as T, "links");
const proxy = createProxy(layer as unknown as Layer<T>); layer = createProxy(partialLayer as unknown as Layer<T>);
return proxy; }
track();
return layer;
},
set() {
console.error("Layers are read-only!");
}
};
});
} }
export function addLayer( export function addLayer(
@ -127,8 +141,8 @@ export function addLayer(
globalBus.emit("addLayer", layer, player.layers[layer.id]); globalBus.emit("addLayer", layer, player.layers[layer.id]);
} }
export function getLayer<T extends GenericLayer>(layerID: string): () => T { export function getLayer<T extends GenericLayer>(layerID: string): T {
return () => layers[layerID] as T; return layers[layerID] as T;
} }
export function removeLayer(layer: GenericLayer): void { export function removeLayer(layer: GenericLayer): void {