perf: refs
This commit is contained in:
parent
3b88ab8969
commit
503a7d2514
|
@ -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}>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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}>
|
||||
|
|
Loading…
Reference in New Issue
Block a user