grungnet/src/contexts/PlayerContext.tsx

143 lines
3.6 KiB
TypeScript
Raw Permalink Normal View History

2021-01-01 17:13:26 -05:00
import React, { useEffect, useContext } from "react";
2020-12-07 23:58:01 -05:00
import { useDatabase } from "./DatabaseContext";
import { useUserId } from "./UserIdContext";
2020-12-07 23:58:01 -05:00
2021-07-16 00:55:33 -04:00
import useNetworkedState, {
SetNetworkedState,
} from "../hooks/useNetworkedState";
2021-07-17 03:25:41 -04:00
import Session, { SessionStatus } from "../network/Session";
2021-07-16 00:55:33 -04:00
import { PlayerState } from "../types/PlayerState";
export const PlayerStateContext = React.createContext<PlayerState | undefined>(
undefined
);
export const PlayerUpdaterContext = React.createContext<
SetNetworkedState<PlayerState> | undefined
>(undefined);
2020-12-07 23:58:01 -05:00
2021-07-16 00:55:33 -04:00
type PlayerProviderProps = {
2021-07-02 01:54:54 -04:00
session: Session;
children: React.ReactNode;
2021-07-16 00:55:33 -04:00
};
export function PlayerProvider({ session, children }: PlayerProviderProps) {
const userId = useUserId();
const { database, databaseStatus } = useDatabase();
2020-12-07 23:58:01 -05:00
2021-07-16 00:55:33 -04:00
const [playerState, setPlayerState] = useNetworkedState<PlayerState>(
2020-12-07 23:58:01 -05:00
{
nickname: "",
2021-07-16 00:55:33 -04:00
timer: undefined,
2020-12-07 23:58:01 -05:00
dice: { share: false, rolls: [] },
2021-07-16 00:55:33 -04:00
sessionId: undefined,
userId,
2020-12-07 23:58:01 -05:00
},
session,
"player_state",
500,
false
2020-12-07 23:58:01 -05:00
);
useEffect(() => {
if (!database || databaseStatus === "loading") {
return;
}
async function loadNickname() {
2021-06-03 01:31:18 -04:00
const storedNickname = await database?.table("user").get("nickname");
2020-12-07 23:58:01 -05:00
if (storedNickname !== undefined) {
2021-07-16 00:55:33 -04:00
setPlayerState((prevState) => ({
2020-12-07 23:58:01 -05:00
...prevState,
nickname: storedNickname.value,
}));
}
}
loadNickname();
2020-12-31 01:56:51 -05:00
}, [database, databaseStatus, setPlayerState]);
2020-12-07 23:58:01 -05:00
useEffect(() => {
if (
playerState.nickname &&
database !== undefined &&
(databaseStatus === "loaded" || databaseStatus === "disabled")
2020-12-07 23:58:01 -05:00
) {
database
.table("user")
.update("nickname", { value: playerState.nickname });
}
}, [playerState, database, databaseStatus]);
useEffect(() => {
2021-04-09 01:13:06 -04:00
if (userId) {
2021-07-16 00:55:33 -04:00
setPlayerState((prevState) => {
2021-04-09 01:13:06 -04:00
if (prevState) {
return {
...prevState,
userId,
};
}
return prevState;
});
}
2020-12-31 01:56:51 -05:00
}, [userId, setPlayerState]);
useEffect(() => {
2021-04-09 01:13:06 -04:00
function updateSessionId() {
2021-07-16 00:55:33 -04:00
setPlayerState((prevState) => {
2021-04-09 01:13:06 -04:00
if (prevState) {
return {
...prevState,
sessionId: session.id,
};
}
return prevState;
});
}
function handleSocketConnect() {
2020-12-07 23:58:01 -05:00
// Set the player state to trigger a sync
2021-04-09 01:13:06 -04:00
updateSessionId();
2020-12-07 23:58:01 -05:00
}
2021-07-17 03:25:41 -04:00
function handleSocketStatus(status: SessionStatus) {
2021-02-20 02:10:00 -05:00
if (status === "joined") {
2021-04-09 01:13:06 -04:00
updateSessionId();
2021-02-20 02:10:00 -05:00
}
}
session.on("status", handleSocketStatus);
session.socket?.on("connect", handleSocketConnect);
session.socket?.io.on("reconnect", handleSocketConnect);
2020-12-07 23:58:01 -05:00
return () => {
2021-02-20 02:10:00 -05:00
session.off("status", handleSocketStatus);
session.socket?.off("connect", handleSocketConnect);
session.socket?.io.off("reconnect", handleSocketConnect);
2020-12-07 23:58:01 -05:00
};
});
return (
2020-12-31 01:56:51 -05:00
<PlayerStateContext.Provider value={playerState}>
<PlayerUpdaterContext.Provider value={setPlayerState}>
{children}
2020-12-31 01:56:51 -05:00
</PlayerUpdaterContext.Provider>
</PlayerStateContext.Provider>
2020-12-07 23:58:01 -05:00
);
}
export function usePlayerState() {
const context = useContext(PlayerStateContext);
if (context === undefined) {
throw new Error("usePlayerState must be used within a PlayerProvider");
}
return context;
}
export function usePlayerUpdater() {
const context = useContext(PlayerUpdaterContext);
if (context === undefined) {
throw new Error("usePlayerUpdater must be used within a PlayerProvider");
}
return context;
}