feat: handle reconnection

This commit is contained in:
cha0s 2019-04-14 16:14:03 -05:00
parent 16bba31786
commit 2bcb541c99
3 changed files with 100 additions and 1 deletions

View File

@ -142,6 +142,15 @@ const AugmentedParser = augmentParserWithThroughput(SocketIoParser);
const socket = createClient(window.location.href, { const socket = createClient(window.location.href, {
parser: AugmentedParser, parser: AugmentedParser,
}); });
let isConnected = false;
socket.on('connect', () => {
room.layers.destroy();
selfEntity = undefined;
isConnected = true;
});
socket.on('disconnect', () => {
isConnected = false;
});
// Mouse/touch movement. // Mouse/touch movement.
const pointerMovementHandle = setInterval(() => { const pointerMovementHandle = setInterval(() => {
do { do {
@ -172,6 +181,9 @@ const pointerMovementHandle = setInterval(() => {
}, 1000 / 15); }, 1000 / 15);
// Input messages. // Input messages.
const inputHandle = setInterval(() => { const inputHandle = setInterval(() => {
if (!isConnected) {
return;
}
if (actionState !== actionRegistry.state) { if (actionState !== actionRegistry.state) {
actionState = actionRegistry.state; actionState = actionRegistry.state;
socket.send(InputPacket.fromState(actionState)); socket.send(InputPacket.fromState(actionState));
@ -185,6 +197,9 @@ renderTicker.on('tick', () => {
}); });
let lastTime = performance.now(); let lastTime = performance.now();
const predictionHandle = setInterval(() => { const predictionHandle = setInterval(() => {
if (!isConnected) {
return;
}
const now = performance.now(); const now = performance.now();
const elapsed = (now - lastTime) / 1000; const elapsed = (now - lastTime) / 1000;
lastTime = now; lastTime = now;
@ -254,6 +269,9 @@ function applyStageLighting() {
} }
// Render. // Render.
function render() { function render() {
if (!isConnected) {
return;
}
stage.tick(); stage.tick();
if (!mayRender) { if (!mayRender) {
return false; return false;
@ -266,6 +284,7 @@ function render() {
const renderHandle = setAnimation(render); const renderHandle = setAnimation(render);
// UI. // UI.
const UiComponent = <Ui const UiComponent = <Ui
socket={socket}
worldTime={worldTime} worldTime={worldTime}
/>; />;
ReactDOM.render(UiComponent, stage.ui); ReactDOM.render(UiComponent, stage.ui);

View File

@ -0,0 +1,78 @@
// 3rd party.
import classnames from 'classnames';
import React, {useEffect, useState} from 'react';
// 2nd party.
import {compose} from '@avocado/core';
import contempo from 'contempo';
const decorate = compose(
contempo(`
.connection-status {
display: none;
}
.connection-status.interrupted {
background-color: rgba(0, 0, 0, .75);
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
position: relative;
}
.connection-status.interrupted .message {
color: white;
font-family: mono;
font-size: 0.7em;
text-align: center;
text-transform: uppercase;
}
.connection-status.interrupted .message .dots {
color: rgb(150, 150, 150);
font-size: 0.5em;
}
`),
);
const ConnectionStatusComponent = ({socket}) => {
// Start true even if not really connected to prevent initial "interrupted"
// state.
const [isConnected, setIsConnected] = useState(true);
const [dots, setDots] = useState(0);
// Juggle connected state.
useEffect(() => {
const onConnect = () => {
setIsConnected(true);
};
socket.on('connect', onConnect);
const onDisconnect = () => {
setIsConnected(false);
};
socket.on('disconnect', onDisconnect);
return () => {
socket.off('connect', onConnect);
socket.off('disconnect', onDisconnect);
};
}, []);
// Make the dots dance.
useEffect(() => {
if (isConnected) {
return;
}
setTimeout(() => {
setDots((dots + 1) % 39);
}, 50);
}, [dots, isConnected]);
const renderedDots = Array(dots + 1).fill('.').join('');
return <div className={classnames(
'connection-status',
!isConnected ? 'interrupted' : '',
'unselectable',
)}>
<div className="message">
<p>:[ Connection interrupted ]:</p>
<p className="dots">{renderedDots}</p>
</div>
</div>;
}
export default decorate(ConnectionStatusComponent);

View File

@ -2,11 +2,13 @@
import React from 'react'; import React from 'react';
import {hot} from 'react-hot-loader/root'; import {hot} from 'react-hot-loader/root';
// 1st party. // 1st party.
import ConnectionStatus from './connection-status';
import WorldTime from './world-time'; import WorldTime from './world-time';
const Ui = ({worldTime}) => { const Ui = ({socket, worldTime}) => {
return <React.Fragment> return <React.Fragment>
<WorldTime worldTime={worldTime} /> <WorldTime worldTime={worldTime} />
<ConnectionStatus socket={socket} />
</React.Fragment>; </React.Fragment>;
}; };