143 lines
3.6 KiB
TypeScript
143 lines
3.6 KiB
TypeScript
import React, { useEffect, useContext } from "react";
|
|
|
|
import { useDatabase } from "./DatabaseContext";
|
|
import { useUserId } from "./UserIdContext";
|
|
|
|
import useNetworkedState, {
|
|
SetNetworkedState,
|
|
} from "../hooks/useNetworkedState";
|
|
import Session, { SessionStatus } from "../network/Session";
|
|
import { PlayerState } from "../types/PlayerState";
|
|
|
|
export const PlayerStateContext = React.createContext<PlayerState | undefined>(
|
|
undefined
|
|
);
|
|
export const PlayerUpdaterContext = React.createContext<
|
|
SetNetworkedState<PlayerState> | undefined
|
|
>(undefined);
|
|
|
|
type PlayerProviderProps = {
|
|
session: Session;
|
|
children: React.ReactNode;
|
|
};
|
|
|
|
export function PlayerProvider({ session, children }: PlayerProviderProps) {
|
|
const userId = useUserId();
|
|
const { database, databaseStatus } = useDatabase();
|
|
|
|
const [playerState, setPlayerState] = useNetworkedState<PlayerState>(
|
|
{
|
|
nickname: "",
|
|
timer: undefined,
|
|
dice: { share: false, rolls: [] },
|
|
sessionId: undefined,
|
|
userId,
|
|
},
|
|
session,
|
|
"player_state",
|
|
500,
|
|
false
|
|
);
|
|
|
|
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,
|
|
}));
|
|
}
|
|
}
|
|
|
|
loadNickname();
|
|
}, [database, databaseStatus, setPlayerState]);
|
|
|
|
useEffect(() => {
|
|
if (
|
|
playerState.nickname &&
|
|
database !== undefined &&
|
|
(databaseStatus === "loaded" || databaseStatus === "disabled")
|
|
) {
|
|
database
|
|
.table("user")
|
|
.update("nickname", { value: playerState.nickname });
|
|
}
|
|
}, [playerState, database, databaseStatus]);
|
|
|
|
useEffect(() => {
|
|
if (userId) {
|
|
setPlayerState((prevState) => {
|
|
if (prevState) {
|
|
return {
|
|
...prevState,
|
|
userId,
|
|
};
|
|
}
|
|
return prevState;
|
|
});
|
|
}
|
|
}, [userId, setPlayerState]);
|
|
|
|
useEffect(() => {
|
|
function updateSessionId() {
|
|
setPlayerState((prevState) => {
|
|
if (prevState) {
|
|
return {
|
|
...prevState,
|
|
sessionId: session.id,
|
|
};
|
|
}
|
|
return prevState;
|
|
});
|
|
}
|
|
function handleSocketConnect() {
|
|
// Set the player state to trigger a sync
|
|
updateSessionId();
|
|
}
|
|
|
|
function handleSocketStatus(status: SessionStatus) {
|
|
if (status === "joined") {
|
|
updateSessionId();
|
|
}
|
|
}
|
|
|
|
session.on("status", handleSocketStatus);
|
|
session.socket?.on("connect", handleSocketConnect);
|
|
session.socket?.io.on("reconnect", handleSocketConnect);
|
|
|
|
return () => {
|
|
session.off("status", handleSocketStatus);
|
|
session.socket?.off("connect", handleSocketConnect);
|
|
session.socket?.io.off("reconnect", handleSocketConnect);
|
|
};
|
|
});
|
|
|
|
return (
|
|
<PlayerStateContext.Provider value={playerState}>
|
|
<PlayerUpdaterContext.Provider value={setPlayerState}>
|
|
{children}
|
|
</PlayerUpdaterContext.Provider>
|
|
</PlayerStateContext.Provider>
|
|
);
|
|
}
|
|
|
|
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;
|
|
}
|