177 lines
5.1 KiB
JavaScript
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>
|
|
);
|
|
}
|