feat: disconnected

This commit is contained in:
cha0s 2024-06-13 02:47:28 -05:00
parent 216e528c13
commit eb599c60c0
8 changed files with 130 additions and 59 deletions

View File

@ -1,5 +1,12 @@
import {encode} from '@/packets/index.js';
let connected = false;
let socket;
function onMessage(event) {
postMessage(event.data);
}
onmessage = async (event) => {
if (!connected) {
const url = new URL(`wss://${event.data.host}/ws`)
@ -8,12 +15,21 @@ onmessage = async (event) => {
}
socket = new WebSocket(url.href);
socket.binaryType = 'arraybuffer';
await new Promise((resolve) => {
socket.onopen = resolve;
const {promise, resolve, reject} = Promise.withResolvers();
socket.addEventListener('open', resolve);
socket.addEventListener('error', reject);
await promise;
socket.removeEventListener('open', resolve);
socket.removeEventListener('error', reject);
socket.addEventListener('message', onMessage);
socket.addEventListener('close', () => {
postMessage(encode({type: 'ConnectionAborted'}));
close();
});
socket.addEventListener('error', () => {
postMessage(encode({type: 'ConnectionAborted'}));
close();
});
socket.onmessage = (event) => {
postMessage(event.data);
};
connected = true;
return;
}

View File

@ -0,0 +1,3 @@
import Packet from '@/net/packet.js';
export default class ConnectionAborted extends Packet {}

View File

@ -0,0 +1,27 @@
import {useEffect, useState} from 'react';
import styles from './disconnected.module.css';
export default function Disconnected() {
const [dots, setDots] = useState(3);
const [delta, setDelta] = useState(1);
useEffect(() => {
const handle = setTimeout(() => {
const updated = dots + delta;
setDots(updated);
if (updated < 1 || updated > 5) {
setDelta(-delta);
}
}, 100);
return () => {
clearTimeout(handle);
};
}, [dots, delta]);
const rendered = Array(dots).fill('.').join('');
return (
<div className={styles.disconnected}>
<p>There&apos;s a problem with the connection.</p>
<p>{rendered}Reconnection attempt in progress{rendered}</p>
</div>
);
}

View File

@ -0,0 +1,14 @@
.disconnected {
align-items: center;
background-color: rgba(0, 0, 0, 0.4);
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
text-align: center;
width: 100%;
p {
color: #cccccc;
font-size: 2em;
}
}

View File

@ -4,6 +4,7 @@ import addKeyListener from '@/add-key-listener.js';
import {ACTION_MAP, RESOLUTION} from '@/constants.js';
import ClientContext from '@/context/client.js';
import Disconnected from './disconnected.jsx';
import Dom from './dom.jsx';
import HotBar from './hotbar.jsx';
import Pixi from './pixi.jsx';
@ -16,7 +17,7 @@ const KEY_MAP = {
keyUp: 0,
};
export default function Ui() {
export default function Ui({disconnected}) {
// Key input.
const client = useContext(ClientContext);
useEffect(() => {
@ -43,6 +44,9 @@ export default function Ui() {
<Pixi />
<Dom>
<HotBar active={0} slots={Array(10).fill(0).map(() => {})} />
{disconnected && (
<Disconnected />
)}
</Dom>
</div>
);

View File

@ -1,7 +1,66 @@
import {useEffect, useState} from 'react';
import {useParams} from 'react-router-dom';
import ClientContext from '@/context/client.js';
import LocalClient from '@/net/client/local.js';
import RemoteClient from '@/net/client/remote.js';
import {decode, encode} from '@/packets/index.js';
import Ui from '@/react-components/ui.jsx';
import styles from './play.module.css';
export default function Index() {
const [client, setClient] = useState();
const [disconnected, setDisconnected] = useState();
const params = useParams();
const [type, url] = params['*'].split('/');
useEffect(() => {
let Client;
switch (type) {
case 'local':
Client = LocalClient;
break;
case 'remote':
Client = RemoteClient;
break;
}
class SilphiusClient extends Client {
accept(packed) {
super.accept(decode(packed));
}
transmit(packet) {
super.transmit(encode(packet));
}
}
const client = new SilphiusClient();
async function connect() {
await client.connect(url);
setClient(client);
}
connect();
return () => {
client.disconnect();
};
}, [type, url]);
useEffect(() => {
if (!client) {
return;
}
function onConnectionAborted() {
setDisconnected(true);
}
client.addPacketListener('ConnectionAborted', onConnectionAborted);
return () => {
client.removePacketListener('ConnectionAborted', onConnectionAborted);
};
}, [client]);
return (
<Ui />
<div className={styles.play}>
{client && (
<ClientContext.Provider value={client}>
<Ui disconnected={disconnected} />
</ClientContext.Provider>
)}
</div>
);
}

View File

@ -1,52 +0,0 @@
import {useEffect, useState} from 'react';
import {Outlet, useParams} from 'react-router-dom';
import ClientContext from '@/context/client.js';
import LocalClient from '@/net/client/local.js';
import RemoteClient from '@/net/client/remote.js';
import {decode, encode} from '@/packets/index.js';
import styles from './play.module.css';
export default function Index() {
const [client, setClient] = useState();
const params = useParams();
const [type, url] = params['*'].split('/');
useEffect(() => {
let Client;
switch (type) {
case 'local':
Client = LocalClient;
break;
case 'remote':
Client = RemoteClient;
break;
}
class SilphiusClient extends Client {
accept(packed) {
super.accept(decode(packed));
}
transmit(packet) {
super.transmit(encode(packet));
}
}
const client = new SilphiusClient();
async function connect() {
await client.connect(url);
setClient(client);
}
connect();
return () => {
client.disconnect();
};
}, [type, url]);
return (
<div className={styles.play}>
{client && (
<ClientContext.Provider value={client}>
<Outlet />
</ClientContext.Provider>
)}
</div>
);
}