From e4cd769ee2b02e15f6e3e206bd9627638f12f777 Mon Sep 17 00:00:00 2001 From: cha0s Date: Wed, 31 Jul 2024 09:29:33 -0500 Subject: [PATCH] refactor: hook deps --- app/react/components/devtools.jsx | 12 ++-- app/react/components/dom/entities.jsx | 17 +++--- app/react/components/pixi/ecs.jsx | 10 +-- app/react/components/pixi/entities.jsx | 34 ++++++----- app/react/components/ui.jsx | 85 ++++++++++++++++---------- app/react/context/client.js | 5 +- app/react/context/ecs.js | 12 +++- 7 files changed, 101 insertions(+), 74 deletions(-) diff --git a/app/react/components/devtools.jsx b/app/react/components/devtools.jsx index e877c96..a8f65ca 100644 --- a/app/react/components/devtools.jsx +++ b/app/react/components/devtools.jsx @@ -1,8 +1,8 @@ -import {useState} from 'react'; +import {useCallback, useState} from 'react'; import {Tab, Tabs, TabList, TabPanel} from 'react-tabs'; import 'react-tabs/style/react-tabs.css'; -import {useEcs, useEcsTick} from '@/react/context/ecs.js'; +import {useEcsTick} from '@/react/context/ecs.js'; import {useMainEntity} from '@/react/context/main-entity.js'; import styles from './devtools.module.css'; @@ -12,15 +12,15 @@ import Tiles from './devtools/tiles.jsx'; export default function Devtools({ eventsChannel, }) { - const [ecs] = useEcs(); const [mainEntity] = useMainEntity(); const [mainEntityJson, setMainEntityJson] = useState(''); - useEcsTick(() => { - if (!ecs || !mainEntity) { + const onEcsTick = useCallback((payload, ecs) => { + if (!mainEntity) { return; } setMainEntityJson(JSON.stringify(ecs.get(mainEntity), null, 2)); - }, [ecs, mainEntity]); + }, [mainEntity]); + useEcsTick(onEcsTick); return (
diff --git a/app/react/components/dom/entities.jsx b/app/react/components/dom/entities.jsx index b0b9b19..057dea7 100644 --- a/app/react/components/dom/entities.jsx +++ b/app/react/components/dom/entities.jsx @@ -1,7 +1,7 @@ -import {useState} from 'react'; +import {useCallback, useRef, useState} from 'react'; import {usePacket} from '@/react/context/client.js'; -import {useEcs, useEcsTick} from '@/react/context/ecs.js'; +import {useEcsTick} from '@/react/context/ecs.js'; import {parseLetters} from '@/util/dialogue.js'; import Damages from './damages.jsx'; @@ -13,17 +13,13 @@ export default function Entities({ setChatMessages, setMonopolizers, }) { - const [ecs] = useEcs(); const [entities, setEntities] = useState({}); const [damages, setDamages] = useState({}); - const [pendingDamage] = useState({accumulated: [], handle: undefined}); + const {current: pendingDamage} = useRef({accumulated: [], handle: undefined}); usePacket('EcsChange', async () => { setEntities({}); - }, [setEntities]); - useEcsTick((payload) => { - if (!ecs) { - return; - } + }); + const onEcsTick = useCallback((payload, ecs) => { const deleting = {}; const updating = {}; for (const id in payload) { @@ -131,7 +127,8 @@ export default function Entities({ ...updating, }; }); - }, [ecs, setMonopolizers]); + }, [pendingDamage, setChatMessages, setMonopolizers]); + useEcsTick(onEcsTick); const renderables = []; for (const id in entities) { renderables.push( diff --git a/app/react/components/pixi/ecs.jsx b/app/react/components/pixi/ecs.jsx index 683c206..ee448e4 100644 --- a/app/react/components/pixi/ecs.jsx +++ b/app/react/components/pixi/ecs.jsx @@ -1,7 +1,7 @@ import {Container} from '@pixi/react'; -import {useState} from 'react'; +import {useCallback, useState} from 'react'; -import {useEcs, useEcsTick} from '@/react/context/ecs.js'; +import {useEcsTick} from '@/react/context/ecs.js'; import {useMainEntity} from '@/react/context/main-entity.js'; import Entities from './entities.jsx'; @@ -11,14 +11,13 @@ import TileLayer from './tile-layer.jsx'; import Water from './water.jsx'; export default function Ecs({camera, monopolizers, particleWorker, scale}) { - const [ecs] = useEcs(); const [mainEntity] = useMainEntity(); const [layers, setLayers] = useState([]); const [hour, setHour] = useState(10); const [projected, setProjected] = useState([]); const [position, setPosition] = useState({x: 0, y: 0}); const [water, setWater] = useState(); - useEcsTick((payload) => { + const onEcsTick = useCallback((payload, ecs) => { const entity = ecs.get(mainEntity); for (const id in payload) { const update = payload[id]; @@ -43,7 +42,8 @@ export default function Ecs({camera, monopolizers, particleWorker, scale}) { setPosition(Position.toJSON()); setProjected(Wielder.activeItem()?.project(Position.tile, Direction.quantize(4))); } - }, [ecs, mainEntity, scale]); + }, [mainEntity]); + useEcsTick(onEcsTick); return ( { setEntities({}); - }, [setEntities]); - useEcsTick((payload) => { - if (!ecs) { - return; - } + }); + const onEcsTickEntities = useCallback((payload, ecs) => { const deleting = {}; const updating = {}; for (const id in payload) { @@ -73,11 +70,6 @@ export default function Entities({monopolizers, particleWorker}) { continue; } updating[id] = ecs.get(id); - if (update.Emitter?.emit) { - for (const id in update.Emitter.emit) { - particleWorker?.postMessage(update.Emitter.emit[id]); - } - } } setEntities((entities) => { for (const id in deleting) { @@ -88,16 +80,26 @@ export default function Entities({monopolizers, particleWorker}) { ...updating, }; }); - }, [ecs, particleWorker]); - useEcsTick(() => { - if (!ecs) { - return; + }, []); + useEcsTick(onEcsTickEntities); + const onEcsTickParticles = useCallback((payload) => { + for (const id in payload) { + const update = payload[id]; + if (update.Emitter?.emit) { + for (const id in update.Emitter.emit) { + particleWorker?.postMessage(update.Emitter.emit[id]); + } + } } + }, [particleWorker]); + useEcsTick(onEcsTickParticles); + const onEcsTickInteractions = useCallback((payload, ecs) => { const main = ecs.get(mainEntity); if (main) { setWillInteractWith(main.Interacts.willInteractWith); } - }, [ecs, mainEntity]); + }, [mainEntity]); + useEcsTick(onEcsTickInteractions); const renderables = []; for (const id in entities) { const isHighlightedInteraction = 0 === monopolizers.length && id == willInteractWith; diff --git a/app/react/components/ui.jsx b/app/react/components/ui.jsx index 6e20f8d..8a42641 100644 --- a/app/react/components/ui.jsx +++ b/app/react/components/ui.jsx @@ -310,35 +310,21 @@ function Ui({disconnected}) { setDebug, setScale, ]); - usePacket('EcsChange', async () => { + const onEcsChangePacket = useCallback(() => { refreshEcs(); setMainEntity(undefined); setMonopolizers([]); - }, [refreshEcs, setMainEntity, setMonopolizers]); - usePacket('Tick', async (payload, client) => { + }, [refreshEcs, setMainEntity]); + usePacket('EcsChange', onEcsChangePacket); + const onTickPacket = useCallback(async (payload, client) => { if (0 === Object.keys(payload.ecs).length) { return; } await ecs.apply(payload.ecs); client.emitter.invoke(':Ecs', payload.ecs); }, [ecs]); - useEcsTick((payload) => { - if (!('1' in payload) || particleWorker) { - return - } - const localParticleWorker = new Worker( - new URL('./particle-worker.js', import.meta.url), - {type: 'module'}, - ); - localParticleWorker.postMessage(ecs.get(1).toJSON()); - setParticleWorker((particleWorker) => { - if (particleWorker) { - particleWorker.terminate(); - } - return localParticleWorker; - }); - }, [particleWorker]); - useEcsTick((payload) => { + usePacket('Tick', onTickPacket); + const onEcsTick = useCallback((payload, ecs) => { let localMainEntity = mainEntity; for (const id in payload) { const entity = ecs.get(id); @@ -346,14 +332,6 @@ function Ui({disconnected}) { if (!update) { continue; } - if (update.Direction && entity.Collider) { - entity.Collider.updateAabbs(); - } - if (update.Sound?.play) { - for (const sound of update.Sound.play) { - (new Audio(sound)).play(); - } - } if (update.MainEntity) { setMainEntity(localMainEntity = id); } @@ -390,15 +368,60 @@ function Ui({disconnected}) { } } } - if (localMainEntity) { - const mainEntityEntity = ecs.get(localMainEntity); + }, [hotbarHideHandle, mainEntity, setMainEntity]); + useEcsTick(onEcsTick); + const onEcsTickParticles = useCallback((payload, ecs) => { + if (!('1' in payload) || particleWorker) { + return + } + const localParticleWorker = new Worker( + new URL('./particle-worker.js', import.meta.url), + {type: 'module'}, + ); + localParticleWorker.postMessage(ecs.get(1).toJSON()); + setParticleWorker((particleWorker) => { + if (particleWorker) { + particleWorker.terminate(); + } + return localParticleWorker; + }); + }, [particleWorker]); + useEcsTick(onEcsTickParticles); + const onEcsTickSound = useCallback((payload) => { + for (const id in payload) { + const update = payload[id]; + if (update.Sound?.play) { + for (const sound of update.Sound.play) { + (new Audio(sound)).play(); + } + } + } + }, []); + useEcsTick(onEcsTickSound); + const onEcsTickAabbs = useCallback((payload, ecs) => { + for (const id in payload) { + const entity = ecs.get(id); + const update = payload[id]; + if (!update) { + continue; + } + if (update.Direction && entity.Collider) { + entity.Collider.updateAabbs(); + } + } + }, []); + useEcsTick(onEcsTickAabbs); + const onEcsTickCamera = useCallback((payload, ecs) => { + if (mainEntity) { + const mainEntityEntity = ecs.get(mainEntity); const x = Math.round((mainEntityEntity.Camera.x * scale) - RESOLUTION.x / 2); const y = Math.round((mainEntityEntity.Camera.y * scale) - RESOLUTION.y / 2); if (x !== camera.x || y !== camera.y) { setCamera({x, y}); } } - }, [camera, ecs, hotbarHideHandle, mainEntity, scale]); + }, [camera, mainEntity, scale]); + useEcsTick(onEcsTickCamera); useEffect(() => { function onContextMenu(event) { event.preventDefault(); diff --git a/app/react/context/client.js b/app/react/context/client.js index 60c1af3..27ba98f 100644 --- a/app/react/context/client.js +++ b/app/react/context/client.js @@ -8,7 +8,7 @@ export function useClient() { return useContext(context); } -export function usePacket(type, fn, dependencies) { +export function usePacket(type, fn) { const client = useClient(); useEffect(() => { if (!client) { @@ -21,6 +21,5 @@ export function usePacket(type, fn, dependencies) { return () => { client.removePacketListener(type, listener); }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [client, ...dependencies]); + }, [client, fn]); } \ No newline at end of file diff --git a/app/react/context/ecs.js b/app/react/context/ecs.js index f02af05..11481c2 100644 --- a/app/react/context/ecs.js +++ b/app/react/context/ecs.js @@ -1,4 +1,4 @@ -import {createContext, useContext} from 'react'; +import {createContext, useCallback, useContext} from 'react'; import {usePacket} from './client.js'; @@ -10,7 +10,13 @@ export function useEcs() { return useContext(context); } -export function useEcsTick(fn, dependencies) { +export function useEcsTick(fn) { const [ecs] = useEcs(); - usePacket(':Ecs', fn, [ecs, ...dependencies]); + const memo = useCallback((payload) => { + if (!ecs) { + return; + } + fn(payload, ecs); + }, [ecs, fn]); + usePacket(':Ecs', memo); } \ No newline at end of file