silphius/app/react/components/dom/entities.jsx

142 lines
3.9 KiB
React
Raw Normal View History

2024-07-12 02:10:22 -05:00
import {useState} from 'react';
2024-07-13 03:02:55 -05:00
2024-07-20 04:32:33 -05:00
import {usePacket} from '@/react/context/client.js';
import {useEcs, useEcsTick} from '@/react/context/ecs.js';
2024-07-20 04:41:00 -05:00
import {parseLetters} from '@/util/dialogue.js';
2024-07-12 02:10:22 -05:00
2024-07-27 12:31:52 -05:00
import Damages from './damages.jsx';
2024-07-12 02:10:22 -05:00
import Entity from './entity.jsx';
2024-07-14 07:24:15 -05:00
export default function Entities({
camera,
scale,
setChatMessages,
setMonopolizers,
}) {
2024-07-12 02:10:22 -05:00
const [ecs] = useEcs();
const [entities, setEntities] = useState({});
2024-07-27 12:31:52 -05:00
const [damages, setDamages] = useState({});
usePacket('EcsChange', async () => {
setEntities({});
}, [setEntities]);
2024-07-12 02:10:22 -05:00
useEcsTick((payload) => {
if (!ecs) {
return;
}
2024-07-13 16:33:23 -05:00
const deleting = {};
const updating = {};
2024-07-12 02:10:22 -05:00
for (const id in payload) {
if ('1' === id) {
continue;
}
const update = payload[id];
if (false === update) {
2024-07-13 16:33:23 -05:00
deleting[id] = true;
2024-07-12 02:10:22 -05:00
continue;
}
2024-07-13 16:33:23 -05:00
updating[id] = ecs.get(id);
2024-07-12 02:10:22 -05:00
const {dialogue} = update.Interlocutor || {};
if (dialogue) {
2024-07-13 16:33:23 -05:00
const {dialogues} = updating[id].Interlocutor;
2024-07-12 02:10:22 -05:00
for (const key in dialogue) {
2024-07-13 03:02:55 -05:00
dialogues[key] = dialogue[key];
2024-07-22 04:19:29 -05:00
if (!dialogues[key].offset) {
dialogues[key].offset = {x: 0, y: 0};
}
2024-07-22 03:55:37 -05:00
if ('track' === dialogues[key].origin) {
dialogues[key].origin = () => updating[id].Position;
}
2024-07-22 04:19:29 -05:00
if ('track' === dialogues[key].position) {
dialogues[key].position = () => updating[id].Position;
}
2024-07-13 03:02:55 -05:00
dialogues[key].letters = parseLetters(dialogues[key].body);
2024-07-14 21:44:33 -05:00
setChatMessages((chatMessages) => ({
[[id, key].join('-')]: dialogues[key].letters,
...chatMessages,
}));
2024-07-13 17:08:23 -05:00
const skipListeners = new Set();
dialogues[key].addSkipListener = (listener) => {
skipListeners.add(listener);
return () => {
skipListeners.delete(listener);
}
}
const monopolizer = {
trigger: () => {
for (const listener of skipListeners) {
listener();
}
},
};
if (dialogues[key].monopolizer) {
setMonopolizers((monopolizers) => [...monopolizers, monopolizer]);
}
2024-07-13 03:02:55 -05:00
dialogues[key].onClose = () => {
setEntities((entities) => ({
...entities,
[id]: ecs.rebuild(id),
}));
2024-07-13 17:08:23 -05:00
if (dialogues[key].monopolizer) {
setMonopolizers((monopolizers) => {
const index = monopolizers.indexOf(monopolizer);
if (-1 === index) {
return monopolizers;
}
monopolizers.splice(index, 1);
return [...monopolizers];
});
}
delete dialogues[key];
2024-07-13 03:02:55 -05:00
};
2024-07-12 02:10:22 -05:00
}
}
2024-07-26 18:05:24 -05:00
const {damage} = update.Vulnerable || {};
if (damage) {
for (const key in damage) {
2024-07-27 12:31:52 -05:00
const composite = [id, key].join('-');
damage[key].onClose = () => {
setDamages((damages) => {
const {[composite]: _, ...rest} = damages; // eslint-disable-line no-unused-vars
return rest;
})
2024-07-26 18:05:24 -05:00
};
2024-07-27 12:31:52 -05:00
setDamages((damages) => ({
...damages,
[composite]: damage[key],
}));
2024-07-26 18:05:24 -05:00
}
}
2024-07-12 02:10:22 -05:00
}
2024-07-13 16:33:23 -05:00
setEntities((entities) => {
for (const id in deleting) {
delete entities[id];
}
return {
...entities,
...updating,
};
});
2024-07-13 17:08:23 -05:00
}, [ecs, setMonopolizers]);
2024-07-12 02:10:22 -05:00
const renderables = [];
for (const id in entities) {
renderables.push(
<Entity
camera={camera}
entity={entities[id]}
key={id}
scale={scale}
/>
);
}
return (
<>
{renderables}
2024-07-27 12:31:52 -05:00
<Damages
camera={camera}
damages={damages}
scale={scale}
/>
2024-07-12 02:10:22 -05:00
</>
);
}