refactor: hook deps

This commit is contained in:
cha0s 2024-07-31 09:29:33 -05:00
parent c9e7b33d25
commit e4cd769ee2
7 changed files with 101 additions and 74 deletions

View File

@ -1,8 +1,8 @@
import {useState} from 'react'; import {useCallback, useState} from 'react';
import {Tab, Tabs, TabList, TabPanel} from 'react-tabs'; import {Tab, Tabs, TabList, TabPanel} from 'react-tabs';
import 'react-tabs/style/react-tabs.css'; 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 {useMainEntity} from '@/react/context/main-entity.js';
import styles from './devtools.module.css'; import styles from './devtools.module.css';
@ -12,15 +12,15 @@ import Tiles from './devtools/tiles.jsx';
export default function Devtools({ export default function Devtools({
eventsChannel, eventsChannel,
}) { }) {
const [ecs] = useEcs();
const [mainEntity] = useMainEntity(); const [mainEntity] = useMainEntity();
const [mainEntityJson, setMainEntityJson] = useState(''); const [mainEntityJson, setMainEntityJson] = useState('');
useEcsTick(() => { const onEcsTick = useCallback((payload, ecs) => {
if (!ecs || !mainEntity) { if (!mainEntity) {
return; return;
} }
setMainEntityJson(JSON.stringify(ecs.get(mainEntity), null, 2)); setMainEntityJson(JSON.stringify(ecs.get(mainEntity), null, 2));
}, [ecs, mainEntity]); }, [mainEntity]);
useEcsTick(onEcsTick);
return ( return (
<div className={styles.devtools}> <div className={styles.devtools}>
<Tabs> <Tabs>

View File

@ -1,7 +1,7 @@
import {useState} from 'react'; import {useCallback, useRef, useState} from 'react';
import {usePacket} from '@/react/context/client.js'; 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 {parseLetters} from '@/util/dialogue.js';
import Damages from './damages.jsx'; import Damages from './damages.jsx';
@ -13,17 +13,13 @@ export default function Entities({
setChatMessages, setChatMessages,
setMonopolizers, setMonopolizers,
}) { }) {
const [ecs] = useEcs();
const [entities, setEntities] = useState({}); const [entities, setEntities] = useState({});
const [damages, setDamages] = useState({}); const [damages, setDamages] = useState({});
const [pendingDamage] = useState({accumulated: [], handle: undefined}); const {current: pendingDamage} = useRef({accumulated: [], handle: undefined});
usePacket('EcsChange', async () => { usePacket('EcsChange', async () => {
setEntities({}); setEntities({});
}, [setEntities]); });
useEcsTick((payload) => { const onEcsTick = useCallback((payload, ecs) => {
if (!ecs) {
return;
}
const deleting = {}; const deleting = {};
const updating = {}; const updating = {};
for (const id in payload) { for (const id in payload) {
@ -131,7 +127,8 @@ export default function Entities({
...updating, ...updating,
}; };
}); });
}, [ecs, setMonopolizers]); }, [pendingDamage, setChatMessages, setMonopolizers]);
useEcsTick(onEcsTick);
const renderables = []; const renderables = [];
for (const id in entities) { for (const id in entities) {
renderables.push( renderables.push(

View File

@ -1,7 +1,7 @@
import {Container} from '@pixi/react'; 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 {useMainEntity} from '@/react/context/main-entity.js';
import Entities from './entities.jsx'; import Entities from './entities.jsx';
@ -11,14 +11,13 @@ import TileLayer from './tile-layer.jsx';
import Water from './water.jsx'; import Water from './water.jsx';
export default function Ecs({camera, monopolizers, particleWorker, scale}) { export default function Ecs({camera, monopolizers, particleWorker, scale}) {
const [ecs] = useEcs();
const [mainEntity] = useMainEntity(); const [mainEntity] = useMainEntity();
const [layers, setLayers] = useState([]); const [layers, setLayers] = useState([]);
const [hour, setHour] = useState(10); const [hour, setHour] = useState(10);
const [projected, setProjected] = useState([]); const [projected, setProjected] = useState([]);
const [position, setPosition] = useState({x: 0, y: 0}); const [position, setPosition] = useState({x: 0, y: 0});
const [water, setWater] = useState(); const [water, setWater] = useState();
useEcsTick((payload) => { const onEcsTick = useCallback((payload, ecs) => {
const entity = ecs.get(mainEntity); const entity = ecs.get(mainEntity);
for (const id in payload) { for (const id in payload) {
const update = payload[id]; const update = payload[id];
@ -43,7 +42,8 @@ export default function Ecs({camera, monopolizers, particleWorker, scale}) {
setPosition(Position.toJSON()); setPosition(Position.toJSON());
setProjected(Wielder.activeItem()?.project(Position.tile, Direction.quantize(4))); setProjected(Wielder.activeItem()?.project(Position.tile, Direction.quantize(4)));
} }
}, [ecs, mainEntity, scale]); }, [mainEntity]);
useEcsTick(onEcsTick);
return ( return (
<Container <Container
scale={scale} scale={scale}

View File

@ -1,7 +1,7 @@
import {AdjustmentFilter} from '@pixi/filter-adjustment'; import {AdjustmentFilter} from '@pixi/filter-adjustment';
import {GlowFilter} from '@pixi/filter-glow'; import {GlowFilter} from '@pixi/filter-glow';
import {Container} from '@pixi/react'; import {Container} from '@pixi/react';
import {useEffect, useState} from 'react'; import {useCallback, useEffect, useState} from 'react';
import {usePacket} from '@/react/context/client.js'; import {usePacket} from '@/react/context/client.js';
import {useEcs, useEcsTick} from '@/react/context/ecs.js'; import {useEcs, useEcsTick} from '@/react/context/ecs.js';
@ -56,11 +56,8 @@ export default function Entities({monopolizers, particleWorker}) {
interactionFilters[1].outerStrength = pulse * 0.5; interactionFilters[1].outerStrength = pulse * 0.5;
usePacket('EcsChange', async () => { usePacket('EcsChange', async () => {
setEntities({}); setEntities({});
}, [setEntities]); });
useEcsTick((payload) => { const onEcsTickEntities = useCallback((payload, ecs) => {
if (!ecs) {
return;
}
const deleting = {}; const deleting = {};
const updating = {}; const updating = {};
for (const id in payload) { for (const id in payload) {
@ -73,11 +70,6 @@ export default function Entities({monopolizers, particleWorker}) {
continue; continue;
} }
updating[id] = ecs.get(id); updating[id] = ecs.get(id);
if (update.Emitter?.emit) {
for (const id in update.Emitter.emit) {
particleWorker?.postMessage(update.Emitter.emit[id]);
}
}
} }
setEntities((entities) => { setEntities((entities) => {
for (const id in deleting) { for (const id in deleting) {
@ -88,16 +80,26 @@ export default function Entities({monopolizers, particleWorker}) {
...updating, ...updating,
}; };
}); });
}, [ecs, particleWorker]); }, []);
useEcsTick(() => { useEcsTick(onEcsTickEntities);
if (!ecs) { const onEcsTickParticles = useCallback((payload) => {
return; 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); const main = ecs.get(mainEntity);
if (main) { if (main) {
setWillInteractWith(main.Interacts.willInteractWith); setWillInteractWith(main.Interacts.willInteractWith);
} }
}, [ecs, mainEntity]); }, [mainEntity]);
useEcsTick(onEcsTickInteractions);
const renderables = []; const renderables = [];
for (const id in entities) { for (const id in entities) {
const isHighlightedInteraction = 0 === monopolizers.length && id == willInteractWith; const isHighlightedInteraction = 0 === monopolizers.length && id == willInteractWith;

View File

@ -310,35 +310,21 @@ function Ui({disconnected}) {
setDebug, setDebug,
setScale, setScale,
]); ]);
usePacket('EcsChange', async () => { const onEcsChangePacket = useCallback(() => {
refreshEcs(); refreshEcs();
setMainEntity(undefined); setMainEntity(undefined);
setMonopolizers([]); setMonopolizers([]);
}, [refreshEcs, setMainEntity, setMonopolizers]); }, [refreshEcs, setMainEntity]);
usePacket('Tick', async (payload, client) => { usePacket('EcsChange', onEcsChangePacket);
const onTickPacket = useCallback(async (payload, client) => {
if (0 === Object.keys(payload.ecs).length) { if (0 === Object.keys(payload.ecs).length) {
return; return;
} }
await ecs.apply(payload.ecs); await ecs.apply(payload.ecs);
client.emitter.invoke(':Ecs', payload.ecs); client.emitter.invoke(':Ecs', payload.ecs);
}, [ecs]); }, [ecs]);
useEcsTick((payload) => { usePacket('Tick', onTickPacket);
if (!('1' in payload) || particleWorker) { const onEcsTick = useCallback((payload, ecs) => {
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) => {
let localMainEntity = mainEntity; let localMainEntity = mainEntity;
for (const id in payload) { for (const id in payload) {
const entity = ecs.get(id); const entity = ecs.get(id);
@ -346,14 +332,6 @@ function Ui({disconnected}) {
if (!update) { if (!update) {
continue; 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) { if (update.MainEntity) {
setMainEntity(localMainEntity = id); setMainEntity(localMainEntity = id);
} }
@ -390,15 +368,60 @@ function Ui({disconnected}) {
} }
} }
} }
if (localMainEntity) { }, [hotbarHideHandle, mainEntity, setMainEntity]);
const mainEntityEntity = ecs.get(localMainEntity); 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 x = Math.round((mainEntityEntity.Camera.x * scale) - RESOLUTION.x / 2);
const y = Math.round((mainEntityEntity.Camera.y * scale) - RESOLUTION.y / 2); const y = Math.round((mainEntityEntity.Camera.y * scale) - RESOLUTION.y / 2);
if (x !== camera.x || y !== camera.y) { if (x !== camera.x || y !== camera.y) {
setCamera({x, y}); setCamera({x, y});
} }
} }
}, [camera, ecs, hotbarHideHandle, mainEntity, scale]); }, [camera, mainEntity, scale]);
useEcsTick(onEcsTickCamera);
useEffect(() => { useEffect(() => {
function onContextMenu(event) { function onContextMenu(event) {
event.preventDefault(); event.preventDefault();

View File

@ -8,7 +8,7 @@ export function useClient() {
return useContext(context); return useContext(context);
} }
export function usePacket(type, fn, dependencies) { export function usePacket(type, fn) {
const client = useClient(); const client = useClient();
useEffect(() => { useEffect(() => {
if (!client) { if (!client) {
@ -21,6 +21,5 @@ export function usePacket(type, fn, dependencies) {
return () => { return () => {
client.removePacketListener(type, listener); client.removePacketListener(type, listener);
}; };
// eslint-disable-next-line react-hooks/exhaustive-deps }, [client, fn]);
}, [client, ...dependencies]);
} }

View File

@ -1,4 +1,4 @@
import {createContext, useContext} from 'react'; import {createContext, useCallback, useContext} from 'react';
import {usePacket} from './client.js'; import {usePacket} from './client.js';
@ -10,7 +10,13 @@ export function useEcs() {
return useContext(context); return useContext(context);
} }
export function useEcsTick(fn, dependencies) { export function useEcsTick(fn) {
const [ecs] = useEcs(); const [ecs] = useEcs();
usePacket(':Ecs', fn, [ecs, ...dependencies]); const memo = useCallback((payload) => {
if (!ecs) {
return;
}
fn(payload, ecs);
}, [ecs, fn]);
usePacket(':Ecs', memo);
} }