import {useEffect, useState} from 'react'; import addKeyListener from '@/add-key-listener.js'; import {RESOLUTION} from '@/constants.js'; import {useClient} from '@/context/client.js'; import {useDebug} from '@/context/debug.js'; import {useEcs} from '@/context/ecs.js'; import {useMainEntity} from '@/context/main-entity.js'; import usePacket from '@/hooks/use-packet.js'; import Disconnected from './disconnected.jsx'; import Dom from './dom.jsx'; import HotBar from './hotbar.jsx'; import Pixi from './pixi.jsx'; import styles from './ui.module.css'; const ratio = RESOLUTION.x / RESOLUTION.y; function emptySlots() { return Array(10).fill(undefined); } export default function Ui({disconnected}) { // Key input. const client = useClient(); const [mainEntity, setMainEntity] = useMainEntity(); const [debug, setDebug] = useDebug(); const [ecs] = useEcs(); const [showDisconnected, setShowDisconnected] = useState(false); const [bufferSlot, setBufferSlot] = useState(); const [hotbarSlots, setHotbarSlots] = useState(emptySlots()); const [activeSlot, setActiveSlot] = useState(0); useEffect(() => { let handle; if (disconnected) { handle = setTimeout(() => { setShowDisconnected(true); }, 1000); } else { setShowDisconnected(false) } return () => { clearTimeout(handle); }; }, [disconnected]); useEffect(() => { return addKeyListener(document.body, ({event, type, payload}) => { const KEY_MAP = { keyDown: 1, keyUp: 0, }; let actionPayload; switch (payload) { case 'F3': { if (event) { event.preventDefault(); } if ('keyDown' === type) { setDebug(!debug); } break; } case 'w': { actionPayload = {type: 'moveUp', value: KEY_MAP[type]}; break; } case 'a': { actionPayload = {type: 'moveLeft', value: KEY_MAP[type]}; break; } case 's': { actionPayload = {type: 'moveDown', value: KEY_MAP[type]}; break; } case 'd': { actionPayload = {type: 'moveRight', value: KEY_MAP[type]}; break; } case ' ': { actionPayload = {type: 'use', value: KEY_MAP[type]}; break; } case '1': { if ('keyDown' === type) { actionPayload = {type: 'changeSlot', value: 1}; } break; } case '2': { if ('keyDown' === type) { actionPayload = {type: 'changeSlot', value: 2}; } break; } case '3': { if ('keyDown' === type) { actionPayload = {type: 'changeSlot', value: 3}; } break; } case '4': { if ('keyDown' === type) { actionPayload = {type: 'changeSlot', value: 4}; } break; } case '5': { if ('keyDown' === type) { actionPayload = {type: 'changeSlot', value: 5}; } break; } case '6': { if ('keyDown' === type) { actionPayload = {type: 'changeSlot', value: 6}; } break; } case '7': { if ('keyDown' === type) { actionPayload = {type: 'changeSlot', value: 7}; } break; } case '8': { if ('keyDown' === type) { actionPayload = {type: 'changeSlot', value: 8}; } break; } case '9': { if ('keyDown' === type) { actionPayload = {type: 'changeSlot', value: 9}; } break; } case '0': { if ('keyDown' === type) { actionPayload = {type: 'changeSlot', value: 10}; } break; } } if (actionPayload) { client.send({ type: 'Action', payload: actionPayload, }); } }); }, [client, debug, setDebug]); usePacket('Tick', (payload) => { if (0 === Object.keys(payload.ecs).length) { return; } ecs.apply(payload.ecs); let localMainEntity = mainEntity; for (const id in payload.ecs) { const entity = ecs.get(id); const update = payload.ecs[id]; if (update.Sound?.play) { for (const sound of update.Sound.play) { (new Audio(sound)).play(); } } if (update?.MainEntity) { setMainEntity(localMainEntity = id); } if (localMainEntity === id) { if (update.Inventory) { setBufferSlot(entity.Inventory.slots[0]); const newHotbarSlots = emptySlots(); for (let i = 1; i < 11; ++i) { newHotbarSlots[i - 1] = entity.Inventory.slots[i]; } setHotbarSlots(newHotbarSlots); } if (update.Wielder && 'activeSlot' in update.Wielder) { setActiveSlot(update.Wielder.activeSlot); } } } }, [hotbarSlots, mainEntity, setMainEntity]); return (
{mainEntity && ( { client.send({ type: 'Action', payload: {type: 'swapSlots', value: [0, i + 1]}, }); }} slots={hotbarSlots} /> {showDisconnected && ( )} )}
); }