IZUPWMKDP7DYVZT4LI6WA4X2KGSLZ4GPVAYKDDNJUMRJ6AVZJLAAC WBDAIDQZ3J7ON5DWIDA2L4OJEEZCUP2RLEWJSNR4AC3SDBHDBXIQC 3UFL673QX2JG7KHTAM7DFH4BBYVHDNMXBS2RW45G3JBNFZFLSRRQC SNFPBDCSRTZ466KGMTCKMOSULFHXFNXN2IXT6O25RRXF6VLGEBZAC OYNCMT7YDCHK7TFRZDVCMODYMYXRQKK3AU7EOZU7KRA76QGKI3EQC 5BA7VZ3D36S2TC7NZ64R3O364TGXPY5BJUJTGCFZHWZ6JWAXJMUQC BHSJJQZKFNLL4KWBKDU5MUWK5HZ7HGNXUFC2UHAEGTIXN7ARY3UAC B4JS4Z3VVAD5RJJ272S7GJM5BUNIHHMGNK2VSKVGZFPOVFP2YO4QC GWNDFRV3SSE3VUV7AUE6KI7AXCEYYJDNRGRTJD2RNMSYG5OFPKIQC QUT2VGNOS2XSDLSYCSMILCKF343M56MRPRSUWN4GXWPGCK6APK2QC EMED7UWAGESRTWJJWVXRL27O4XMBGZDDAU4LNVF3MQAYKFKRDNXQC OET27TXMNRKBX3HWDSLQWCWAJOWNY5NU4XDKLO5N7Z3EE23CSWOAC 6REHBZAOJN4CVZY4HFXVNEUMWGQUXFTXMLQPXEH7RTH5FBL2TXIAC A75BWKGRLUDH3KF4M2HJYLNC6BSV5MAJFV2RJSF757F46HLRLCKQC ZHOSSPNKGFIKSFPDXCGLMSYMMX2J433VU2BUUWBKUH7TOLQUBSPQC DFFMZSJOCLTBA3IGRYS2ZIJNO2MC3VLBBU42QL5DFY2SMCNFXPIAC ZGS4FTTFBXTF2SHYTPAJJBWEUVWVYXPSJVEFI5NYJWTW273B4NHAC DLEEYV4V7X337ZJJM775DPARMCMXMLOBXGSBCWDMZBHYKSQTGZCQC HUH4SI4HXIP72KQSJP2I4ELHX5KUQZM7FFGKZZGJ33DF7E3JHMYQC OL5CSNTOYADQ6NOJS5YRWY4QIAWEQRGCJGBHNSRSMJD2I43COJ7AC N2M7CWXHD722QWM6IIIEOD66YMR3SSZEJZLDCGEIPXRCVNF6YBSQC AAKN4XJLZ2GARZMUFYX3CJZKYHTRRZDYNTFRLMY7VPAY7K6W4N3QC YJ3YEICSBUHMDVJB6W3ZOOVWLTAXRDCIKOGNN6HRP6N3HWQTDGVAC 4UKXFJRZYO5WEPH5PKMYDZCWVWSEAXFSPL35G5NFIUBCMH3BCXEQC const [application, setApplication] = useState<any>(initialApplication.get());// const [application, setApplication] = useState<any>(() => new BaseApplication({
const [application, setApplication] = useState(initialApplication.get());// const [application, setApplication] = useState(() => new BaseApplication({
const prevRef = useRef<DeepReadonly<GameState>>();useEffect(() => {prevRef.current = gameState;});const prevGameState = prevRef.current;
// const prevRef = useRef<DeepReadonly<GameState>>();// useEffect(() => {// prevRef.current = gameState;// });// const prevGameState = prevRef.current;
import * as Pixi from "pixi.js";import { ChunkRef, PointNodeRef, ZLevelGen } from "../data/GameState";import { KeyedHashMap, HashSet } from "../lib/util/data_structures/hash";import { RenderedChunk, RenderedChunkConstants } from "./RenderedChunk";export class RenderedZLevel {public container: Pixi.Container;public z: number;public renderedChunks: KeyedHashMap<ChunkRef, RenderedChunk> = new KeyedHashMap();constructor(args: {pointNodeTexture: Pixi.Texture,z: number,zLevelGen: ZLevelGen, // what is in mestateUpdaterQueue: [Function],ticker: Pixi.Ticker}) {// constructor(zLevel: ZLevel, onNodeFocus: (selection: PointNodeRef) => void, texture?: Pixi.Texture) {this.z = args.z;this.container = new Pixi.Container();for (let [chunkCoord, chunkGen] of args.zLevelGen.chunks.entries()) {const chunkRef = new ChunkRef({z: this.z,chunkCoord,chunkId: chunkGen.id,});const renderedChunk = new RenderedChunk({selfChunkRef: chunkRef,chunkGen,...args});this.renderedChunks.put(chunkRef, renderedChunk);this.container.addChild(renderedChunk.container);renderedChunk.container.x = chunkCoord.x * RenderedChunkConstants.CHUNK_SPACING_PX;renderedChunk.container.y = chunkCoord.y * RenderedChunkConstants.CHUNK_SPACING_PX;}}public animate(delta: number): this {return this;}public rerender(props: {selectedPointNode: PointNodeRef | undefined,allocatedPointNodeSubset: HashSet<PointNodeRef>,}) {for (let [chunkRef, child] of this.renderedChunks.entries()) {let relevantToChunk = new HashSet(props.allocatedPointNodeSubset.values().filter((pointNodeRef) => {return pointNodeRef.chunkCoord.x === chunkRef.chunkCoord.x &&pointNodeRef.chunkCoord.y === chunkRef.chunkCoord.y;}));child.rerender({selectedPointNode: props.selectedPointNode,allocatedPointNodeSubset: relevantToChunk})}}}
import * as Pixi from "pixi.js";export class RenderedChunkConstants {public static SPACING_PX: number = 24;public static CHUNK_SPACING_PX: number = (ChunkGenConstants.CHUNK_DIM + 0.5) * RenderedChunkConstants.SPACING_PX;public static NODE_SIZE_PX: number = 14;public static NODE_HITAREA_PX: number = 18;public static NODE_ROUNDED_PX: number = 4;}export class RenderedChunk {// public chunk!: Chunk;public container: Pixi.Container;this.container = new Pixi.Container();}}}}// for (let node of chunk.nodes) {// let g: Pixi.Sprite = new Pixi.Sprite(args.nodeTexture);// g.anchor.x = 0.5;// g.anchor.y = 0.5;// g.x = node.x * RenderedChunkConstants.SPACING_PX;// g.y = node.y * RenderedChunkConstants.SPACING_PX;// g.hitArea = new Pixi.Rectangle(// - RenderedChunkConstants.NODE_HITAREA_PX / 2,// - RenderedChunkConstants.NODE_HITAREA_PX / 2,// RenderedChunkConstants.NODE_HITAREA_PX,// RenderedChunkConstants.NODE_HITAREA_PX,// )// this.renderedNodes.put(node, g);// g.interactive = true;//// if (this.chunk.allocatedNodes.get(node)) {// g.tint = 0x00aaff;// } else if (this.chunk.selectedNodes.get(node)) {// g.tint = 0xBBBBBB;// }// g.addListener("pointerdown", () => {// onNodeFocus(new PointNodeRef({// z: 0, // TODO(bowei): fix// chunkCoord: this.chunk.location,// pointNodeCoord: node,// pointNodeId: 0, // TODO(bowei): fix// }));// console.log(`clicked chunk ${this.chunk.location.x} ${this.chunk.location.y} node ${node.x}, ${node.y}`);//// // if nothing is selected// if (this.chunk.selectedNodes.values().length == 0) {// // select it// this.chunk.selectedNodes.put(node);// g.tint = 0xBBBBBB;// // g.alpha = 0.5;// } else if (this.chunk.selectedNodes.get(node)) {// // i was already selected, let's allocate it// this.chunk.selectedNodes.remove(node);// // try to allocate, only allow if we are connected to something already allocated// let neighbors = [node.addX(1), node.addY(1), node.addY(-1), node.addX(-1)];// let allowed = false;// for (let neighbor of neighbors) {// if (this.chunk.allocatedNodes.get(neighbor)) {// allowed = true;// break;// }// }// if (allowed) {// this.chunk.allocatedNodes.put(node);// g.tint = 0x00aaff;// } else {// g.tint = 0xFFFFFF;// window.alert('not allowed to allocate that one!');// }// // g.alpha = 0.5;// } else {// // unselect what was previously selected// for (let selected of this.chunk.selectedNodes.values()) {// this.renderedNodes.get(selected).tint = 0xFFFFFF;// this.chunk.selectedNodes.remove(selected);// }// this.chunk.selectedNodes.put(node);// g.tint = 0xBBBBBB;// }// });// this.container.addChild(g);// }//// this.container.x = this.chunk.location.x * RenderedChunk.CHUNK_SPACING_PX;// this.container.y = this.chunk.location.y * RenderedChunk.CHUNK_SPACING_PX;// }//// public hash(): string {// return this.chunk.hash();// }public rerender(props: {selectedPointNode: PointNodeRef | undefined,allocatedPointNodeSubset: HashSet<PointNodeRef>,}) {for (let child of this.renderedPointNodes.values()) {child.rerender({isAllocated: props.allocatedPointNodeSubset.contains(child.selfPointNodeRef),})}isSelected: props.selectedPointNode?.pointNodeId === child.selfPointNodeRef.pointNodeId,public animate(delta: number): this {return this;// this.container.x = this.chunk.location.x * RenderedChunk.CHUNK_SPACING_PX;// this.container.y = this.chunk.location.y * RenderedChunk.CHUNK_SPACING_PX;}public setLocation(chunk: ChunkRef = this.selfChunkRef): this {this.container.x = chunk.chunkCoord.x * RenderedChunkConstants.CHUNK_SPACING_PX;this.container.y = chunk.chunkCoord.y * RenderedChunkConstants.CHUNK_SPACING_PX;return this}let renderedPointNode = new RenderedPointNode({selfPointNodeRef: pointNodeRef,...args})this.renderedPointNodes.put(pointNodeRef, renderedPointNode);this.container.addChild(renderedPointNode.sprite);// renderedPointNode.setCoord(pointNodeRef); renderedPointNode.setCoord();renderedPointNode.sprite.x = pointNodeCoord.x * RenderedChunkConstants.SPACING_PX;renderedPointNode.sprite.y = pointNodeCoord.y * RenderedChunkConstants.SPACING_PX;// args.chunkGen.pointNodesfor (let [pointNodeCoord, pointNodeGen] of args.chunkGen.pointNodes.entries()) {const pointNodeRef = new PointNodeRef({z: this.selfChunkRef.z,chunkCoord: this.selfChunkRef.chunkCoord,pointNodeCoord: pointNodeCoord,pointNodeId: pointNodeGen.id})this.selfChunkRef = args.selfChunkRef;this.renderedPointNodes = new KeyedHashMap();// args here will never change, and changing this will NOT force a rerenderconstructor(args: {pointNodeTexture: Pixi.Texture,selfChunkRef: ChunkRef, // where am i in parentchunkGen: ChunkGen, // what is in mestateUpdaterQueue: [Function],ticker: Pixi.Ticker}) {public renderedPointNodes: KeyedHashMap<PointNodeRef, RenderedPointNode>;// public renderedNodes: HashMap<Vector2, Pixi.Graphics | Pixi.Sprite> = new HashMap();public selfChunkRef: ChunkRef;import { ChunkGen, ChunkGenConstants, ChunkRef, PointNodeRef } from "../data/GameState";import { RenderedPointNode } from "./RenderedPointNode";import { HashSet, KeyedHashMap } from "../lib/util/data_structures/hash";
import * as Pixi from "pixi.js";import { RenderedChunkConstants } from "./RenderedChunk";/*** Usage:* class RenderedChunk {* constructor(stateUpdaterQueue) {* this.nodes = 0...10.map(i => new RenderedPointNode({texture, new NodeRef(i), stateUpdaterQueue}))* // this.nodes[0].render({ some, stuff })* this.nodes[0] should listen to gameState.playerUI.selectedPointNode and allocatedPointNodes, and* updating gameState.playerUI.selectedPointNode or gameState.playerSave.allocatedPointNodes or their* parents should trigger queueing of the rerender* or rather, rerendering* }* }*/import { DeepReadonly, UpdaterGeneratorType } from "../lib/util/misc";import { GameState, PointNodeRef } from "../data/GameState";export class RenderedPointNode {public sprite: Pixi.Sprite;public selfPointNodeRef: PointNodeRef; // which node we are// local statethis.selfPointNodeRef = args.selfPointNodeRef;this.sprite.anchor.x = 0.5;this.sprite.anchor.y = 0.5;// this.sprite.x = node.x * RenderedChunkConstants.SPACING_PX;// this.sprite.y = node.y * RenderedChunkConstants.SPACING_PX;this.sprite.interactive = true;this.sprite.hitArea = new Pixi.Rectangle(- RenderedChunkConstants.NODE_HITAREA_PX / 2,- RenderedChunkConstants.NODE_HITAREA_PX / 2,RenderedChunkConstants.NODE_HITAREA_PX,RenderedChunkConstants.NODE_HITAREA_PX,);this.sprite.addListener("pointerdown", () => {});}} else {}// 2. manually mark necessary changed components?? or autodeduce based on dependencies??// otherwise, set selected node to usargs.gameStateUpdater.playerUI.selectedPointNode.set(this.selfPointNodeRef);// TODO(bowei): make the (0,0) node in a chunk shimmer? or somehow visually distinguish itreturn this;}public onClick(args: { gameState: GameState, gameStateUpdater: UpdaterGeneratorType<GameState>, entityUpdaterQueue: [any] }) {// 1. update the state(s)// if we were already selected, allocate us// TODO(bowei): this code block should be somewhere else????args.gameStateUpdater.playerSave.allocatedPointNodeSet.update(set => {set.put(this.selfPointNodeRef);return set;})args.gameStateUpdater.playerSave.allocatedPointNodeHistory.update(history => {history.push(this.selfPointNodeRef);return history;})if (args.gameState.playerUI.selectedPointNode?.pointNodeId === this.selfPointNodeRef.pointNodeId) {public setLocation(node: PointNodeRef = this.selfPointNodeRef) : this {this.sprite.x = node.pointNodeCoord.x * RenderedChunkConstants.SPACING_PX;this.sprite.y = node.pointNodeCoord.y * RenderedChunkConstants.SPACING_PX;return this;}public animate(delta: number) : this {args.ticker.add(this.animate.bind(this));args.stateUpdaterQueue.push(this.onClick.bind(this));// this.justClicked = true;// do 3 things:// 1. queue up the necessary state changes, to be executed on tick// 2. mark other components that need rerendering based on state change// 3. do all the rerendersthis.sprite.buttonMode = true;this.sprite = new Pixi.Sprite(args.pointNodeTexture);// args here will never change, and changing this will NOT force a rerenderconstructor(args: {selfPointNodeRef: PointNodeRef,stateUpdaterQueue: [Function],ticker: Pixi.Ticker}) {pointNodeTexture: Pixi.Texture,// public justClicked: boolean = false;}}}} else {}}}//// public update(args: {// gameState: DeepReadonly<GameState>, gameStateUpdater: UpdaterGeneratorType<GameState>,// renderedNodeMap: DeepReadonly<HashMap<PointNodeRef, RenderedPointNode>>// }) {// let { gameState, gameStateUpdater } = args;// // sync ourselves with state// let isSelected = this.isSelected(gameState);// let isAllocated = this.isAllocated(gameState);//// if (this.justClicked) {// if (!gameState.playerUI.selectedPointNode) {// // if nothing is is selected, select ourselves;//// isSelected = true;// this.setTint({ isSelected, isAllocated });// gameStateUpdater.playerUI.selectedPointNode.set(this.selfPointNodeRef);//// // if we were already selected, try to allocate ourselves//// if (!isAllocated) {// isAllocated = true;// // save our allocation to state// // TODO(bowei): this code block should be somewhere else????// gameStateUpdater.playerSave.allocatedPointNodeSet.update(set => {// set.put(this.selfPointNodeRef);// return set;// })// gameStateUpdater.playerSave.allocatedPointNodeHistory.update(history => {// history.push(this.selfPointNodeRef);// return history;// })// }// this.setTint({ isSelected, isAllocated });// } else {// // if something other than ourselves is selected, unselect it and select ourselves;//// isSelected = true;// let otherNode = args.renderedNodeMap.get(gameState.playerUI.selectedPointNode);// gameStateUpdater.playerUI.selectedPointNode.set(this.selfPointNodeRef);// otherNode.setTint({// isSelected: false,// isAllocated: otherNode.isAllocated(gameState)// });// this.setTint({ isSelected: true, isAllocated})// }// }// // don't forget to reset state!// this.justClicked = false;// }// } else if (gameState.playerUI.selectedPointNode.pointNodeId === this.selfPointNodeRef.pointNodeId) {public isSelected(gameState: DeepReadonly<GameState>): boolean {}public isAllocated(gameState: DeepReadonly<GameState>): boolean {return gameState.playerSave.allocatedPointNodeSet.get(this.selfPointNodeRef)}return gameState.playerUI.selectedPointNode?.pointNodeId === this.selfPointNodeRef.pointNodeId;this.sprite.tint = 0xFFFFFF;private setTint(args: { isSelected: boolean, isAllocated: boolean }) {if (args.isAllocated) {this.sprite.tint = 0x00AAFF;} else {if (args.isSelected) {this.sprite.tint = 0xBBBBBB;// public rerenderFromState(gameState: DeepReadonly<GameState>) {// this.rerender({// isSelected: this.isSelected(gameState),// isAllocated: this.isAllocated(gameState)// })// }this.setTint(props);return this;public rerender(props: { isSelected: boolean, isAllocated: boolean }) : this {// 3. do the rerenders (someone else handles this...)
let zLevel = new RenderedZLevel({pointNodeTexture,z: 0,zLevelGen: (new ZLevelGenFactory({}).create({ seed: this.randomSeed, z: 0})),stateUpdaterQueue: [] as any,ticker: this.app.ticker})this.actionStage.addChild(zLevel.container);zLevel.container.x = this.app.screen.width / 2;zLevel.container.y = this.app.screen.height / 2;
// let zLevel = new RenderedZLevel({// pointNodeTexture,// z: 0,// zLevelGen: (new ZLevelGenFactory({}).create({ seed: this.randomSeed, z: 0})),// stateUpdaterQueue: [] as any,// ticker: this.app.ticker// })// this.actionStage.addChild(zLevel.container);// zLevel.container.x = this.app.screen.width / 2;// zLevel.container.y = this.app.screen.height / 2;