perf: refs

This commit is contained in:
cha0s 2024-09-06 21:13:52 -05:00
parent 3b88ab8969
commit 503a7d2514
8 changed files with 65 additions and 68 deletions

View File

@ -14,14 +14,14 @@ export default function Devtools({
eventsChannel,
}) {
const client = useClient();
const [mainEntity] = useMainEntity();
const mainEntityRef = useMainEntity();
const [mainEntityJson, setMainEntityJson] = useState('');
const onEcsTick = useCallback((payload, ecs) => {
if (!mainEntity) {
if (!mainEntityRef.current) {
return;
}
setMainEntityJson(JSON.stringify(ecs.get(mainEntity), null, 2));
}, [mainEntity]);
setMainEntityJson(JSON.stringify(ecs.get(mainEntityRef.current), null, 2));
}, [mainEntityRef]);
useEcsTick(onEcsTick);
return (
<div className={styles.devtools}>

View File

@ -17,12 +17,12 @@ export default function Tiles({eventsChannel}) {
const [layer, setLayer] = useState(0);
const [brush, setBrush] = useState(0);
const [stamp, setStamp] = useState([]);
const [ecs] = useEcs();
const ecsRef = useEcs();
useEffect(() => {
if (!ecs) {
if (!ecsRef.current) {
return;
}
const master = ecs.get(1);
const master = ecsRef.current.get(1);
if (!master) {
return;
}
@ -56,10 +56,10 @@ export default function Tiles({eventsChannel}) {
eventsChannel.removeListener('click', onClick);
};
});
if (!ecs) {
if (!ecsRef.current) {
return false;
}
const master = ecs.get(1);
const master = ecsRef.current.get(1);
if (!master) {
return false;
}

View File

@ -11,14 +11,14 @@ import TileLayer from './tile-layer.jsx';
import Water from './water.jsx';
export default function Ecs({camera, monopolizers, particleWorker, scale}) {
const [mainEntity] = useMainEntity();
const mainEntityRef = 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();
const onEcsTick = useCallback((payload, ecs) => {
const entity = ecs.get(mainEntity);
const entity = ecs.get(mainEntityRef.current);
for (const id in payload) {
const update = payload[id];
switch (id) {
@ -42,7 +42,7 @@ export default function Ecs({camera, monopolizers, particleWorker, scale}) {
setPosition(Position.toJSON());
setProjected(Wielder.activeItem()?.project(Position.tile, Direction.quantize(4)));
}
}, [mainEntity]);
}, [mainEntityRef]);
useEcsTick(onEcsTick);
return (
<Container

View File

@ -13,12 +13,12 @@ import Entity from './entity.js';
export default function Entities({monopolizers, particleWorker}) {
const [debug] = useDebug();
const [ecs] = useEcs();
const ecsRef = useEcs();
const containerRef = useRef();
const latestTick = useRef();
const entities = useRef({});
const pool = useRef([]);
const [mainEntity] = useMainEntity();
const mainEntityRef = useMainEntity();
const radians = useRadians();
const willInteractWith = useRef(0);
const [interactionFilters] = useState([
@ -28,7 +28,7 @@ export default function Entities({monopolizers, particleWorker}) {
const pulse = (Math.cos(radians / 4) + 1) * 0.5;
interactionFilters[0].brightness = (pulse * 0.75) + 1;
interactionFilters[1].outerStrength = pulse * 0.5;
const updateEntities = useCallback((payload) => {
const updateEntities = useCallback((payload, ecs) => {
for (const id in payload) {
if ('1' === id) {
continue;
@ -43,14 +43,15 @@ export default function Entities({monopolizers, particleWorker}) {
entities.current[id] = pool.current.length > 0
? pool.current.pop()
: new Entity();
entities.current[id].reset(ecs.get(id), debug);
if (mainEntity === id) {
entities.current[id].reset(ecs.get(id));
entities.current[id].setDebug(false);
if (mainEntityRef.current === id) {
entities.current[id].setMainEntity();
}
}
entities.current[id].update(payload[id], containerRef.current);
}
}, [debug, ecs, mainEntity])
}, [mainEntityRef])
useEffect(() => {
if (0 === pool.current.length) {
for (let i = 0; i < 1000; ++i) {
@ -69,25 +70,25 @@ export default function Entities({monopolizers, particleWorker}) {
}
entities.current = {};
});
const onEcsTickEntities = useCallback((payload) => {
updateEntities(payload);
}, [updateEntities]);
useEcsTick(onEcsTickEntities);
useEcsTick(updateEntities);
useEffect(() => {
if (!ecs || !particleWorker) {
if (!particleWorker) {
return;
}
async function onMessage(diff) {
if (!ecsRef.current) {
return;
}
latestTick.current = Promise.resolve(latestTick.current).then(async () => {
await ecs.apply(diff.data);
updateEntities(diff.data);
await ecsRef.current.apply(diff.data);
updateEntities(diff.data, ecsRef.current);
});
}
particleWorker.addEventListener('message', onMessage);
return () => {
particleWorker.removeEventListener('message', onMessage);
};
}, [ecs, particleWorker, updateEntities]);
}, [ecsRef, particleWorker, updateEntities]);
const onEcsTickParticles = useCallback((payload) => {
for (const id in payload) {
const update = payload[id];
@ -100,7 +101,7 @@ export default function Entities({monopolizers, particleWorker}) {
}, [particleWorker]);
useEcsTick(onEcsTickParticles);
const onEcsTickInteractions = useCallback((payload, ecs) => {
const main = ecs.get(mainEntity);
const main = ecs.get(mainEntityRef.current);
if (main) {
if (willInteractWith.current !== main.Interacts.willInteractWith) {
if (entities.current[willInteractWith.current]) {
@ -115,7 +116,7 @@ export default function Entities({monopolizers, particleWorker}) {
: [];
}
}
}, [interactionFilters, mainEntity, monopolizers]);
}, [interactionFilters, mainEntityRef, monopolizers]);
useEcsTick(onEcsTickInteractions);
return (
<Container

View File

@ -43,13 +43,12 @@ export default class Entity {
this.debug.parent.removeChild(this.debug);
this.attached = false;
}
reset(entity, debug) {
reset(entity) {
this.entity = entity;
if (this.light) {
this.container.removeChild(this.light);
this.light = undefined;
}
this.setDebug(debug);
this.isMainEntity = false;
if (this.interactionAabb) {
this.debug.removeChild(this.interactionAabb);

View File

@ -37,9 +37,9 @@ function Ui({disconnected}) {
const chatInputRef = useRef();
const latestTick = useRef();
const gameRef = useRef();
const [mainEntity, setMainEntity] = useMainEntity();
const [debug, setDebug] = useDebug();
const [ecs, setEcs] = useEcs();
const mainEntityRef = useMainEntity();
const [, setDebug] = useDebug();
const ecsRef = useEcs();
const [showDisconnected, setShowDisconnected] = useState(false);
const [bufferSlot, setBufferSlot] = useState();
const [devtoolsIsOpen, setDevtoolsIsOpen] = useState(false);
@ -67,8 +67,8 @@ function Ui({disconnected}) {
class ClientEcsPerf extends ClientEcs {
markChange() {}
}
setEcs(new ClientEcsPerf({Components, Systems}));
}, [Components, Systems, setEcs]);
ecsRef.current = new ClientEcsPerf({Components, Systems});
}, [ecsRef, Components, Systems]);
useEffect(() => {
async function setEcsStuff() {
const {default: Components} = await import('@/ecs/components/index.js');
@ -174,7 +174,7 @@ function Ui({disconnected}) {
event.preventDefault();
}
if ('keyDown' === type) {
setDebug(!debug);
setDebug((debug) => !debug);
}
break;
}
@ -302,7 +302,6 @@ function Ui({disconnected}) {
}, [
chatIsOpen,
client,
debug,
devtoolsIsOpen,
hotbarHideHandle,
isInventoryOpen,
@ -313,22 +312,21 @@ function Ui({disconnected}) {
]);
const onEcsChangePacket = useCallback(() => {
refreshEcs();
setMainEntity(undefined);
mainEntityRef.current = undefined;
setMonopolizers([]);
}, [refreshEcs, setMainEntity]);
}, [refreshEcs, mainEntityRef]);
usePacket('EcsChange', onEcsChangePacket);
const onTickPacket = useCallback(async (payload, client) => {
if (0 === Object.keys(payload.ecs).length) {
return;
}
latestTick.current = Promise.resolve(latestTick.current).then(async () => {
await ecs.apply(payload.ecs);
await ecsRef.current.apply(payload.ecs);
client.emitter.invoke(':Ecs', payload.ecs);
});
}, [ecs]);
}, [ecsRef]);
usePacket('Tick', onTickPacket);
const onEcsTick = useCallback((payload, ecs) => {
let localMainEntity = mainEntity;
for (const id in payload) {
const entity = ecs.get(id);
const update = payload[id];
@ -336,10 +334,10 @@ function Ui({disconnected}) {
continue;
}
if (update.MainEntity) {
setMainEntity(localMainEntity = id);
mainEntityRef.current = id;
}
if (update.Inventory) {
if (localMainEntity === id) {
if (mainEntityRef.current === id) {
setBufferSlot(entity.Inventory.item(0));
const newInventorySlots = emptySlots();
for (let i = 1; i < 41; ++i) {
@ -365,13 +363,13 @@ function Ui({disconnected}) {
setExternalInventorySlots();
}
}
if (localMainEntity === id) {
if (mainEntityRef.current === id) {
if (update.Wielder && 'activeSlot' in update.Wielder) {
setActiveSlot(update.Wielder.activeSlot);
}
}
}
}, [hotbarHideHandle, mainEntity, setMainEntity]);
}, [hotbarHideHandle, mainEntityRef]);
useEcsTick(onEcsTick);
const onEcsTickParticles = useCallback((payload, ecs) => {
if (!('1' in payload) || particleWorker) {
@ -415,15 +413,15 @@ function Ui({disconnected}) {
}, []);
useEcsTick(onEcsTickAabbs);
const onEcsTickCamera = useCallback((payload, ecs) => {
if (mainEntity) {
const mainEntityEntity = ecs.get(mainEntity);
if (mainEntityRef.current) {
const mainEntityEntity = ecs.get(mainEntityRef.current);
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, mainEntity, scale]);
}, [camera, mainEntityRef, scale]);
useEcsTick(onEcsTickCamera);
useEffect(() => {
function onContextMenu(event) {
@ -435,15 +433,15 @@ function Ui({disconnected}) {
};
}, []);
const computePosition = useCallback(({clientX, clientY}) => {
if (!gameRef.current || !mainEntity) {
if (!gameRef.current || !mainEntityRef.current) {
return;
}
const {top, left, width} = gameRef.current.getBoundingClientRect();
const master = ecs.get(1);
const master = ecsRef.current.get(1);
if (!master) {
return;
}
const {Camera} = ecs.get(mainEntity);
const {Camera} = ecsRef.current.get(mainEntityRef.current);
const size = width / RESOLUTION.x;
const camera = {
x: ((Camera.x * scale) - (RESOLUTION.x / 2)),
@ -454,8 +452,8 @@ function Ui({disconnected}) {
y: (((clientY - top) / size) + camera.y) / scale,
};
}, [
ecs,
mainEntity,
ecsRef,
mainEntityRef,
scale,
]);
return (
@ -576,7 +574,7 @@ function Ui({disconnected}) {
keepHotbarOpen();
client.send({
type: 'Action',
payload: {type: 'swapSlots', value: [0, mainEntity, i + 1]},
payload: {type: 'swapSlots', value: [0, mainEntityRef.current, i + 1]},
});
}}
slots={inventorySlots.slice(0, 10)}
@ -586,7 +584,7 @@ function Ui({disconnected}) {
onActivate={(i) => {
client.send({
type: 'Action',
payload: {type: 'swapSlots', value: [0, mainEntity, i + 11]},
payload: {type: 'swapSlots', value: [0, mainEntityRef.current, i + 11]},
});
}}
slots={inventorySlots.slice(10, 20)}

View File

@ -11,12 +11,12 @@ export function useEcs() {
}
export function useEcsTick(fn) {
const [ecs] = useEcs();
const ecsRef = useEcs();
const memo = useCallback((payload) => {
if (!ecs) {
if (!ecsRef.current) {
return;
}
fn(payload, ecs);
}, [ecs, fn]);
fn(payload, ecsRef.current);
}, [ecsRef, fn]);
usePacket(':Ecs', memo);
}

View File

@ -1,5 +1,5 @@
import {json} from "@remix-run/node";
import {useCallback, useEffect, useState} from 'react';
import {useCallback, useEffect, useRef, useState} from 'react';
import {useOutletContext, useParams} from 'react-router-dom';
import Ui from '@/react/components/ui.jsx';
@ -22,10 +22,9 @@ export default function PlaySpecific() {
const Client = useOutletContext();
const assetsTuple = useState({});
const [client, setClient] = useState();
const mainEntityTuple = useState();
const setMainEntity = mainEntityTuple[1];
const mainEntityRef = useRef();
const debugTuple = useState(false);
const ecsTuple = useState();
const ecsRef = useRef();
const [disconnected, setDisconnected] = useState(false);
const params = useParams();
const [type, url] = params['*'].split('/');
@ -109,7 +108,7 @@ export default function PlaySpecific() {
if (!client || !disconnected) {
return;
}
setMainEntity(undefined);
mainEntityRef.current = undefined;
async function reconnect() {
await client.connect(url);
}
@ -118,7 +117,7 @@ export default function PlaySpecific() {
return () => {
clearInterval(handle);
};
}, [client, disconnected, setMainEntity, url]);
}, [client, disconnected, mainEntityRef, url]);
// useEffect(() => {
// let source = true;
// async function play() {
@ -144,8 +143,8 @@ export default function PlaySpecific() {
// }, [])
return (
<ClientContext.Provider value={client}>
<MainEntityContext.Provider value={mainEntityTuple}>
<EcsContext.Provider value={ecsTuple}>
<MainEntityContext.Provider value={mainEntityRef}>
<EcsContext.Provider value={ecsRef}>
<DebugContext.Provider value={debugTuple}>
<AssetsContext.Provider value={assetsTuple}>
<RadiansContext.Provider value={radians}>