Moved party to use socket networking
This commit is contained in:
parent
b7da0cffa7
commit
b40f78042f
@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import React, { useContext, useEffect } from "react";
|
||||
import { Flex, Box, Text } from "theme-ui";
|
||||
import SimpleBar from "simplebar-react";
|
||||
import { useToasts } from "react-toast-notifications";
|
||||
|
||||
import AddPartyMemberButton from "./AddPartyMemberButton";
|
||||
import Nickname from "./Nickname";
|
||||
@ -13,26 +14,76 @@ import DiceTrayButton from "./DiceTrayButton";
|
||||
|
||||
import useSetting from "../../helpers/useSetting";
|
||||
|
||||
function Party({
|
||||
nickname,
|
||||
partyNicknames,
|
||||
gameId,
|
||||
onNicknameChange,
|
||||
stream,
|
||||
partyStreams,
|
||||
onStreamStart,
|
||||
onStreamEnd,
|
||||
timer,
|
||||
partyTimers,
|
||||
onTimerStart,
|
||||
onTimerStop,
|
||||
shareDice,
|
||||
onShareDiceChage,
|
||||
diceRolls,
|
||||
onDiceRollsChange,
|
||||
partyDiceRolls,
|
||||
}) {
|
||||
import PlayerContext from "../../contexts/PlayerContext";
|
||||
|
||||
function Party({ gameId, stream, partyStreams, onStreamStart, onStreamEnd }) {
|
||||
const { playerState, setPlayerState, partyState } = useContext(PlayerContext);
|
||||
|
||||
const [fullScreen] = useSetting("map.fullScreen");
|
||||
const [shareDice, setShareDice] = useSetting("dice.shareDice");
|
||||
|
||||
const { addToast } = useToasts();
|
||||
|
||||
function handleTimerStart(newTimer) {
|
||||
setPlayerState((prevState) => ({ ...prevState, timer: newTimer }));
|
||||
}
|
||||
|
||||
function handleTimerStop() {
|
||||
setPlayerState((prevState) => ({ ...prevState, timer: null }));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let prevTime = performance.now();
|
||||
let request = requestAnimationFrame(update);
|
||||
let counter = 0;
|
||||
function update(time) {
|
||||
request = requestAnimationFrame(update);
|
||||
const deltaTime = time - prevTime;
|
||||
prevTime = time;
|
||||
|
||||
if (playerState.timer) {
|
||||
counter += deltaTime;
|
||||
// Update timer every second
|
||||
if (counter > 1000) {
|
||||
const newTimer = {
|
||||
...playerState.timer,
|
||||
current: playerState.timer.current - counter,
|
||||
};
|
||||
if (newTimer.current < 0) {
|
||||
setPlayerState((prevState) => ({ ...prevState, timer: null }));
|
||||
} else {
|
||||
setPlayerState((prevState) => ({ ...prevState, timer: newTimer }));
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
cancelAnimationFrame(request);
|
||||
};
|
||||
}, [playerState, setPlayerState]);
|
||||
|
||||
function handleNicknameChange(newNickname) {
|
||||
setPlayerState((prevState) => ({ ...prevState, nickname: newNickname }));
|
||||
}
|
||||
|
||||
function handleDiceRollsChange(newDiceRolls) {
|
||||
setPlayerState(
|
||||
(prevState) => ({
|
||||
...prevState,
|
||||
dice: { share: shareDice, rolls: newDiceRolls },
|
||||
}),
|
||||
shareDice
|
||||
);
|
||||
}
|
||||
|
||||
function handleShareDiceChange(newShareDice) {
|
||||
setShareDice(newShareDice);
|
||||
setPlayerState((prevState) => ({
|
||||
...prevState,
|
||||
dice: { ...prevState.dice, share: newShareDice },
|
||||
}));
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
@ -74,31 +125,33 @@ function Party({
|
||||
}}
|
||||
>
|
||||
<Nickname
|
||||
nickname={`${nickname} (you)`}
|
||||
diceRolls={shareDice && diceRolls}
|
||||
nickname={`${playerState.nickname} (you)`}
|
||||
diceRolls={shareDice && playerState.dice.rolls}
|
||||
/>
|
||||
{Object.entries(partyNicknames).map(([id, partyNickname]) => (
|
||||
{Object.entries(partyState).map(([id, { nickname, dice }]) => (
|
||||
<Nickname
|
||||
nickname={partyNickname}
|
||||
nickname={nickname}
|
||||
key={id}
|
||||
stream={partyStreams[id]}
|
||||
diceRolls={partyDiceRolls[id]}
|
||||
/>
|
||||
))}
|
||||
{timer && <Timer timer={timer} index={0} />}
|
||||
{Object.entries(partyTimers).map(([id, partyTimer], index) => (
|
||||
<Timer
|
||||
timer={partyTimer}
|
||||
key={id}
|
||||
// Put party timers above your timer if there is one
|
||||
index={timer ? index + 1 : index}
|
||||
diceRolls={dice.share && dice.rolls}
|
||||
/>
|
||||
))}
|
||||
{playerState.timer && <Timer timer={playerState.timer} index={0} />}
|
||||
{Object.entries(partyState)
|
||||
.filter(([_, { timer }]) => timer)
|
||||
.map(([id, { timer }], index) => (
|
||||
<Timer
|
||||
timer={timer}
|
||||
key={id}
|
||||
// Put party timers above your timer if there is one
|
||||
index={playerState.timer ? index + 1 : index}
|
||||
/>
|
||||
))}
|
||||
</SimpleBar>
|
||||
<Flex sx={{ flexDirection: "column" }}>
|
||||
<ChangeNicknameButton
|
||||
nickname={nickname}
|
||||
onChange={onNicknameChange}
|
||||
nickname={playerState.nickname}
|
||||
onChange={handleNicknameChange}
|
||||
/>
|
||||
<AddPartyMemberButton gameId={gameId} />
|
||||
<StartStreamButton
|
||||
@ -107,18 +160,18 @@ function Party({
|
||||
stream={stream}
|
||||
/>
|
||||
<StartTimerButton
|
||||
onTimerStart={onTimerStart}
|
||||
onTimerStop={onTimerStop}
|
||||
timer={timer}
|
||||
onTimerStart={handleTimerStart}
|
||||
onTimerStop={handleTimerStop}
|
||||
timer={playerState.timer}
|
||||
/>
|
||||
<SettingsButton />
|
||||
</Flex>
|
||||
</Box>
|
||||
<DiceTrayButton
|
||||
shareDice={shareDice}
|
||||
onShareDiceChage={onShareDiceChage}
|
||||
diceRolls={diceRolls}
|
||||
onDiceRollsChange={onDiceRollsChange}
|
||||
onShareDiceChage={handleShareDiceChange}
|
||||
diceRolls={(playerState.dice && playerState.dice.rolls) || []}
|
||||
onDiceRollsChange={handleDiceRollsChange}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
|
@ -3,7 +3,6 @@ import shortid from "shortid";
|
||||
|
||||
import DatabaseContext from "./DatabaseContext";
|
||||
|
||||
import { getRandomMonster } from "../helpers/monsters";
|
||||
import FakeStorage from "../helpers/FakeStorage";
|
||||
|
||||
const AuthContext = React.createContext();
|
||||
@ -48,39 +47,8 @@ export function AuthProvider({ children }) {
|
||||
loadUserId();
|
||||
}, [database, databaseStatus]);
|
||||
|
||||
const [nickname, setNickname] = useState("");
|
||||
useEffect(() => {
|
||||
if (!database || databaseStatus === "loading") {
|
||||
return;
|
||||
}
|
||||
async function loadNickname() {
|
||||
const storedNickname = await database.table("user").get("nickname");
|
||||
if (storedNickname) {
|
||||
setNickname(storedNickname.value);
|
||||
} else {
|
||||
const name = getRandomMonster();
|
||||
setNickname(name);
|
||||
database.table("user").add({ key: "nickname", value: name });
|
||||
}
|
||||
}
|
||||
|
||||
loadNickname();
|
||||
}, [database, databaseStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
nickname !== undefined &&
|
||||
database !== undefined &&
|
||||
databaseStatus !== "loading"
|
||||
) {
|
||||
database.table("user").update("nickname", { value: nickname });
|
||||
}
|
||||
}, [nickname, database, databaseStatus]);
|
||||
|
||||
const value = {
|
||||
userId,
|
||||
nickname,
|
||||
setNickname,
|
||||
password,
|
||||
setPassword,
|
||||
authenticationStatus,
|
||||
|
96
src/contexts/PlayerContext.js
Normal file
96
src/contexts/PlayerContext.js
Normal file
@ -0,0 +1,96 @@
|
||||
import React, { useState, useEffect, useContext } from "react";
|
||||
|
||||
import useNetworkedState from "../helpers/useNetworkedState";
|
||||
import DatabaseContext from "./DatabaseContext";
|
||||
|
||||
import { getRandomMonster } from "../helpers/monsters";
|
||||
|
||||
const PlayerContext = React.createContext();
|
||||
|
||||
export function PlayerProvider({ session, children }) {
|
||||
const { database, databaseStatus } = useContext(DatabaseContext);
|
||||
|
||||
const [playerState, setPlayerState] = useNetworkedState(
|
||||
{
|
||||
nickname: "",
|
||||
timer: null,
|
||||
dice: { share: false, rolls: [] },
|
||||
pointer: {},
|
||||
},
|
||||
session,
|
||||
"player_state"
|
||||
);
|
||||
const [partyState, setPartyState] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
if (!database || databaseStatus === "loading") {
|
||||
return;
|
||||
}
|
||||
async function loadNickname() {
|
||||
const storedNickname = await database.table("user").get("nickname");
|
||||
if (storedNickname !== undefined) {
|
||||
setPlayerState((prevState) => ({
|
||||
...prevState,
|
||||
nickname: storedNickname.value,
|
||||
}));
|
||||
} else {
|
||||
const name = getRandomMonster();
|
||||
setPlayerState((prevState) => ({ ...prevState, nickname: name }));
|
||||
database.table("user").add({ key: "nickname", value: name });
|
||||
}
|
||||
}
|
||||
|
||||
loadNickname();
|
||||
}, [database, databaseStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
playerState.nickname &&
|
||||
database !== undefined &&
|
||||
databaseStatus !== "loading"
|
||||
) {
|
||||
database
|
||||
.table("user")
|
||||
.update("nickname", { value: playerState.nickname });
|
||||
}
|
||||
}, [playerState, database, databaseStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
function handleConnected() {
|
||||
// Set the player state to trigger a sync
|
||||
setPlayerState(playerState);
|
||||
}
|
||||
|
||||
function handleSocketPartyState(partyState) {
|
||||
if (partyState) {
|
||||
const { [session.id]: _, ...otherMembersState } = partyState;
|
||||
setPartyState(otherMembersState);
|
||||
} else {
|
||||
setPartyState({});
|
||||
}
|
||||
}
|
||||
|
||||
if (session.socket) {
|
||||
session.on("connected", handleConnected);
|
||||
session.socket.on("party_state", handleSocketPartyState);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (session.socket) {
|
||||
session.off("connected", handleConnected);
|
||||
session.socket.off("party_state", handleSocketPartyState);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const value = {
|
||||
playerState,
|
||||
setPlayerState,
|
||||
partyState,
|
||||
};
|
||||
return (
|
||||
<PlayerContext.Provider value={value}>{children}</PlayerContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default PlayerContext;
|
@ -1,22 +1,22 @@
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
function useNetworkedState(defaultState, session, eventName) {
|
||||
const [state, _setState] = useState(defaultState);
|
||||
// Used to control whether the state needs to be sent to the socket
|
||||
const dirtyRef = useRef(false);
|
||||
const [dirty, setDirty] = useState(false);
|
||||
|
||||
// Update dirty at the same time as state
|
||||
function setState(update, sync = true) {
|
||||
dirtyRef.current = sync;
|
||||
_setState(update);
|
||||
setDirty(sync);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (dirtyRef.current) {
|
||||
if (session.socket && dirty) {
|
||||
session.socket.emit(eventName, state);
|
||||
dirtyRef.current = false;
|
||||
setDirty(false);
|
||||
}
|
||||
}, [state, eventName]);
|
||||
}, [session.socket, dirty, eventName, state]);
|
||||
|
||||
return [state, setState];
|
||||
}
|
||||
|
@ -1,13 +1,9 @@
|
||||
import React, { useContext, useState, useEffect, useCallback } from "react";
|
||||
import { useToasts } from "react-toast-notifications";
|
||||
|
||||
// Load session for auto complete
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import Session from "./Session";
|
||||
import { isStreamStopped, omit, fromEntries } from "../helpers/shared";
|
||||
|
||||
import AuthContext from "../contexts/AuthContext";
|
||||
import useSetting from "../helpers/useSetting";
|
||||
import { isStreamStopped, omit } from "../helpers/shared";
|
||||
|
||||
import Party from "../components/party/Party";
|
||||
|
||||
@ -21,23 +17,8 @@ import Party from "../components/party/Party";
|
||||
* @param {NetworkedPartyProps} props
|
||||
*/
|
||||
function NetworkedParty({ gameId, session }) {
|
||||
const { nickname, setNickname } = useContext(AuthContext);
|
||||
const [partyNicknames, setPartyNicknames] = useState({});
|
||||
const [stream, setStream] = useState(null);
|
||||
const [partyStreams, setPartyStreams] = useState({});
|
||||
const [timer, setTimer] = useState(null);
|
||||
const [partyTimers, setPartyTimers] = useState({});
|
||||
const [diceRolls, setDiceRolls] = useState([]);
|
||||
const [partyDiceRolls, setPartyDiceRolls] = useState({});
|
||||
|
||||
const { addToast } = useToasts();
|
||||
|
||||
const [shareDice, setShareDice] = useSetting("dice.shareDice");
|
||||
|
||||
function handleNicknameChange(newNickname) {
|
||||
setNickname(newNickname);
|
||||
session.send("nickname", { [session.id]: newNickname });
|
||||
}
|
||||
|
||||
function handleStreamStart(localStream) {
|
||||
setStream(localStream);
|
||||
@ -69,121 +50,11 @@ function NetworkedParty({ gameId, session }) {
|
||||
[session]
|
||||
);
|
||||
|
||||
function handleTimerStart(newTimer) {
|
||||
setTimer(newTimer);
|
||||
session.send("timer", { [session.id]: newTimer });
|
||||
}
|
||||
|
||||
function handleTimerStop() {
|
||||
setTimer(null);
|
||||
session.send("timer", { [session.id]: null });
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let prevTime = performance.now();
|
||||
let request = requestAnimationFrame(update);
|
||||
let counter = 0;
|
||||
function update(time) {
|
||||
request = requestAnimationFrame(update);
|
||||
const deltaTime = time - prevTime;
|
||||
prevTime = time;
|
||||
|
||||
if (timer) {
|
||||
counter += deltaTime;
|
||||
// Update timer every second
|
||||
if (counter > 1000) {
|
||||
const newTimer = {
|
||||
...timer,
|
||||
current: timer.current - counter,
|
||||
};
|
||||
if (newTimer.current < 0) {
|
||||
setTimer(null);
|
||||
session.send("timer", { [session.id]: null });
|
||||
} else {
|
||||
setTimer(newTimer);
|
||||
session.send("timer", { [session.id]: newTimer });
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
cancelAnimationFrame(request);
|
||||
};
|
||||
}, [timer, session]);
|
||||
|
||||
function handleDiceRollsChange(newDiceRolls) {
|
||||
setDiceRolls(newDiceRolls);
|
||||
if (shareDice) {
|
||||
session.send("dice", { [session.id]: newDiceRolls });
|
||||
}
|
||||
}
|
||||
|
||||
function handleShareDiceChange(newShareDice) {
|
||||
setShareDice(newShareDice);
|
||||
if (newShareDice) {
|
||||
session.send("dice", { [session.id]: diceRolls });
|
||||
} else {
|
||||
session.send("dice", { [session.id]: null });
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
function handlePeerConnect({ peer, reply }) {
|
||||
reply("nickname", { [session.id]: nickname });
|
||||
if (stream) {
|
||||
peer.connection.addStream(stream);
|
||||
}
|
||||
if (timer) {
|
||||
reply("timer", { [session.id]: timer });
|
||||
}
|
||||
if (shareDice) {
|
||||
reply("dice", { [session.id]: diceRolls });
|
||||
}
|
||||
}
|
||||
|
||||
function handlePeerDisconnect({ peer }) {
|
||||
if (partyNicknames[peer.id]) {
|
||||
addToast(`${partyNicknames[peer.id]} left the party`);
|
||||
}
|
||||
setPartyNicknames((prevNicknames) => omit(prevNicknames, [peer.id]));
|
||||
setPartyTimers((prevTimers) => omit(prevTimers, [peer.id]));
|
||||
}
|
||||
|
||||
function handlePeerData({ id, data, peer }) {
|
||||
if (id === "nickname") {
|
||||
if (!peer.initiator) {
|
||||
for (let peerId in data) {
|
||||
if (!(peerId in partyNicknames)) {
|
||||
addToast(`${data[peerId]} joined the party`);
|
||||
}
|
||||
}
|
||||
}
|
||||
setPartyNicknames((prevNicknames) => ({
|
||||
...prevNicknames,
|
||||
...data,
|
||||
}));
|
||||
}
|
||||
if (id === "timer") {
|
||||
setPartyTimers((prevTimers) => {
|
||||
const newTimers = { ...prevTimers, ...data };
|
||||
// filter out timers that are null
|
||||
const filtered = Object.entries(newTimers).filter(
|
||||
([, value]) => value !== null
|
||||
);
|
||||
return fromEntries(filtered);
|
||||
});
|
||||
}
|
||||
if (id === "dice") {
|
||||
setPartyDiceRolls((prevDiceRolls) => {
|
||||
const newRolls = { ...prevDiceRolls, ...data };
|
||||
// filter out dice rolls that are null
|
||||
const filtered = Object.entries(newRolls).filter(
|
||||
([, value]) => value !== null
|
||||
);
|
||||
return fromEntries(filtered);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handlePeerTrackAdded({ peer, stream: remoteStream }) {
|
||||
@ -205,28 +76,15 @@ function NetworkedParty({ gameId, session }) {
|
||||
}
|
||||
|
||||
session.on("connect", handlePeerConnect);
|
||||
session.on("disconnect", handlePeerDisconnect);
|
||||
session.on("data", handlePeerData);
|
||||
session.on("trackAdded", handlePeerTrackAdded);
|
||||
session.on("trackRemoved", handlePeerTrackRemoved);
|
||||
|
||||
return () => {
|
||||
session.off("connect", handlePeerConnect);
|
||||
session.off("disconnect", handlePeerDisconnect);
|
||||
session.off("data", handlePeerData);
|
||||
session.off("trackAdded", handlePeerTrackAdded);
|
||||
session.off("trackRemoved", handlePeerTrackRemoved);
|
||||
};
|
||||
}, [
|
||||
session,
|
||||
nickname,
|
||||
stream,
|
||||
timer,
|
||||
shareDice,
|
||||
diceRolls,
|
||||
partyNicknames,
|
||||
addToast,
|
||||
]);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (stream) {
|
||||
@ -248,22 +106,10 @@ function NetworkedParty({ gameId, session }) {
|
||||
<>
|
||||
<Party
|
||||
gameId={gameId}
|
||||
onNicknameChange={handleNicknameChange}
|
||||
onStreamStart={handleStreamStart}
|
||||
onStreamEnd={handleStreamEnd}
|
||||
nickname={nickname}
|
||||
partyNicknames={partyNicknames}
|
||||
stream={stream}
|
||||
partyStreams={partyStreams}
|
||||
timer={timer}
|
||||
partyTimers={partyTimers}
|
||||
onTimerStart={handleTimerStart}
|
||||
onTimerStop={handleTimerStop}
|
||||
shareDice={shareDice}
|
||||
onShareDiceChage={handleShareDiceChange}
|
||||
diceRolls={diceRolls}
|
||||
onDiceRollsChange={handleDiceRollsChange}
|
||||
partyDiceRolls={partyDiceRolls}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
@ -12,6 +12,7 @@ import AuthModal from "../modals/AuthModal";
|
||||
import AuthContext from "../contexts/AuthContext";
|
||||
import { MapStageProvider } from "../contexts/MapStageContext";
|
||||
import DatabaseContext from "../contexts/DatabaseContext";
|
||||
import { PlayerProvider } from "../contexts/PlayerContext";
|
||||
|
||||
import NetworkedMapAndTokens from "../network/NetworkedMapAndTokens";
|
||||
import NetworkedParty from "../network/NetworkedParty";
|
||||
@ -102,49 +103,51 @@ function Game() {
|
||||
const mapStageRef = useRef();
|
||||
|
||||
return (
|
||||
<MapStageProvider value={mapStageRef}>
|
||||
<Flex sx={{ flexDirection: "column", height: "100%" }}>
|
||||
<Flex
|
||||
sx={{
|
||||
justifyContent: "space-between",
|
||||
flexGrow: 1,
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<NetworkedParty session={session} gameId={gameId} />
|
||||
<NetworkedMapAndTokens session={session} />
|
||||
<PlayerProvider session={session}>
|
||||
<MapStageProvider value={mapStageRef}>
|
||||
<Flex sx={{ flexDirection: "column", height: "100%" }}>
|
||||
<Flex
|
||||
sx={{
|
||||
justifyContent: "space-between",
|
||||
flexGrow: 1,
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<NetworkedParty session={session} gameId={gameId} />
|
||||
<NetworkedMapAndTokens session={session} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Banner isOpen={!!peerError} onRequestClose={() => setPeerError(null)}>
|
||||
<Box p={1}>
|
||||
<Text as="p" variant="body2">
|
||||
{peerError} See <Link to="/faq#connection">FAQ</Link> for more
|
||||
information.
|
||||
</Text>
|
||||
</Box>
|
||||
</Banner>
|
||||
<Banner isOpen={offline} onRequestClose={() => {}} allowClose={false}>
|
||||
<Box p={1}>
|
||||
<Text as="p" variant="body2">
|
||||
Unable to connect to game, refresh to reconnect.
|
||||
</Text>
|
||||
</Box>
|
||||
</Banner>
|
||||
<Banner
|
||||
isOpen={!connected && authenticationStatus === "authenticated"}
|
||||
onRequestClose={() => {}}
|
||||
allowClose={false}
|
||||
>
|
||||
<Box p={1}>
|
||||
<Text as="p" variant="body2">
|
||||
Disconnected. Attempting to reconnect...
|
||||
</Text>
|
||||
</Box>
|
||||
</Banner>
|
||||
<AuthModal isOpen={authenticationStatus === "unauthenticated"} />
|
||||
{authenticationStatus === "unknown" && !offline && <LoadingOverlay />}
|
||||
<MapLoadingOverlay />
|
||||
</MapStageProvider>
|
||||
<Banner isOpen={!!peerError} onRequestClose={() => setPeerError(null)}>
|
||||
<Box p={1}>
|
||||
<Text as="p" variant="body2">
|
||||
{peerError} See <Link to="/faq#connection">FAQ</Link> for more
|
||||
information.
|
||||
</Text>
|
||||
</Box>
|
||||
</Banner>
|
||||
<Banner isOpen={offline} onRequestClose={() => {}} allowClose={false}>
|
||||
<Box p={1}>
|
||||
<Text as="p" variant="body2">
|
||||
Unable to connect to game, refresh to reconnect.
|
||||
</Text>
|
||||
</Box>
|
||||
</Banner>
|
||||
<Banner
|
||||
isOpen={!connected && authenticationStatus === "authenticated"}
|
||||
onRequestClose={() => {}}
|
||||
allowClose={false}
|
||||
>
|
||||
<Box p={1}>
|
||||
<Text as="p" variant="body2">
|
||||
Disconnected. Attempting to reconnect...
|
||||
</Text>
|
||||
</Box>
|
||||
</Banner>
|
||||
<AuthModal isOpen={authenticationStatus === "unauthenticated"} />
|
||||
{authenticationStatus === "unknown" && !offline && <LoadingOverlay />}
|
||||
<MapLoadingOverlay />
|
||||
</MapStageProvider>
|
||||
</PlayerProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user