silphius/app/routes/_main-menu.play.$.$/route.jsx
2024-09-22 02:16:32 -05:00

177 lines
5.1 KiB
JavaScript

import {useCallback, useEffect, useRef, useState} from 'react';
import {useOutletContext, useParams} from 'react-router-dom';
import Ui from '@/react/components/ui.jsx';
import AssetsContext from '@/react/context/assets.js';
import ClientContext from '@/react/context/client.js';
import DebugContext from '@/react/context/debug.js';
import EcsContext from '@/react/context/ecs.js';
import MainEntityContext from '@/react/context/main-entity.js';
import ClientEcs from '@/react/components/client-ecs.js';
export default function PlaySpecific() {
const Client = useOutletContext();
const assetsTuple = useState({});
const [client, setClient] = useState();
const mainEntityRef = useRef();
const debugTuple = useState(false);
const [Components, setComponents] = useState();
const [Systems, setSystems] = useState();
const ecsRef = useRef();
const [disconnected, setDisconnected] = useState(false);
const params = useParams();
const [type, url] = params['*'].split('/');
useEffect(() => {
if (!Client) {
return;
}
const client = new Client();
async function connect() {
await client.connect(url);
setClient(client);
}
connect();
return () => {
client.disconnect();
};
}, [Client, url]);
// Sneakily use beforeunload to snag some time to save.
useEffect(() => {
if ('local' !== type) {
return;
}
async function onBeforeUnload() {
client.disconnect();
function waitForSave() {
return new Promise((resolve) => setTimeout(resolve, 0));
}
while (client.worker) { await waitForSave(); }
}
addEventListener('beforeunload', onBeforeUnload);
return () => {
removeEventListener('beforeunload', onBeforeUnload);
};
});
const refreshEcs = useCallback(() => {
class ClientEcsPerf extends ClientEcs {
markChange() {}
}
ecsRef.current = new ClientEcsPerf({Components, Systems});
}, [ecsRef, Components, Systems]);
useEffect(() => {
async function setEcsStuff() {
const {default: Components} = await import('@/ecs/components/index.js');
const {default: Systems} = await import('@/ecs/systems/index.js');
setComponents(Components);
setSystems(Systems);
}
setEcsStuff();
}, []);
useEffect(() => {
refreshEcs();
}, [refreshEcs]);
useEffect(() => {
if (!client) {
return;
}
function onEcsChangePacket() {
refreshEcs();
}
client.addPacketListener('EcsChange', onEcsChangePacket);
return () => {
client.removePacketListener('EcsChange', onEcsChangePacket);
};
}, [client, refreshEcs]);
useEffect(() => {
if (!client) {
return;
}
function onConnectionStatus(status) {
switch (status) {
case 'aborted': {
setDisconnected(true);
break;
}
case 'connected': {
setDisconnected(false);
break;
}
}
}
client.addPacketListener('ConnectionStatus', onConnectionStatus);
return () => {
client.removePacketListener('ConnectionStatus', onConnectionStatus);
};
}, [client]);
useEffect(() => {
if (!client) {
return;
}
function onDownload({data, filename}) {
var blob = new Blob(
[(new TextEncoder()).encode(JSON.stringify(data))],
{type: 'application/json'},
);
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = filename;
link.click();
}
client.addPacketListener('Download', onDownload);
return () => {
client.removePacketListener('Download', onDownload);
};
}, [client]);
useEffect(() => {
if (!client || !disconnected) {
return;
}
mainEntityRef.current = undefined;
async function reconnect() {
await client.connect(url);
}
reconnect();
const handle = setInterval(reconnect, 1000);
return () => {
clearInterval(handle);
};
}, [client, disconnected, mainEntityRef, url]);
// useEffect(() => {
// let source = true;
// async function play() {
// const ctx = new AudioContext();
// const response = await fetch(new URL('/resources/yuff.wav', window.location.origin));
// const buffer = await ctx.decodeAudioData(await response.arrayBuffer());
// if (!source) {
// return;
// }
// source = ctx.createBufferSource();
// source.buffer = buffer;
// source.connect(ctx.destination);
// source.loop = true;
// source.start();
// }
// setTimeout(play, 1000);
// return () => {
// if (true !== source) {
// source.stop();
// }
// source = false;
// };
// }, [])
return (
<ClientContext.Provider value={client}>
<MainEntityContext.Provider value={mainEntityRef}>
<EcsContext.Provider value={ecsRef}>
<DebugContext.Provider value={debugTuple}>
<AssetsContext.Provider value={assetsTuple}>
<Ui disconnected={disconnected} />
</AssetsContext.Provider>
</DebugContext.Provider>
</EcsContext.Provider>
</MainEntityContext.Provider>
</ClientContext.Provider>
);
}