feature: spectator

This commit is contained in:
Halit Aksoy 2022-09-02 00:04:21 +03:00
parent 419ae7600a
commit c73333667d
2 changed files with 145 additions and 103 deletions

View File

@ -2,70 +2,83 @@ import * as React from "react";
import { FunctionComponent } from "react"; import { FunctionComponent } from "react";
import { Context } from "../context/context"; import { Context } from "../context/context";
import { Game } from "../models/Game"; import { Game } from "../models/Game";
import { User } from "../models/User";
import { getColorByBrightness } from "../util/ColorUtil"; import { getColorByBrightness } from "../util/ColorUtil";
import CircularPanel from "./CircularPanel"; import CircularPanel from "./CircularPanel";
function getInfoPanelTextByGameState(params: { function getInfoPanelTextByGameState(params: {
context: Context; context: Context;
game?: Game; game?: Game;
crashMessage?: string; currentUser: User;
userKey?: string; whitePlayer: User;
userKeyWhoLeave?: string; blackPlayer: User;
leftPlayer?: User;
isSpectator?: boolean;
}): string | undefined { }): string | undefined {
const { const {
context, context,
game, game,
crashMessage, currentUser,
userKey, whitePlayer,
userKeyWhoLeave, blackPlayer,
leftPlayer,
isSpectator
} = params; } = params;
if (crashMessage) {
return context.texts.GameCrashed + " " + crashMessage; if (leftPlayer) {
} else if (userKeyWhoLeave) { return isSpectator ? `${leftPlayer.name} ${context.texts.UserLeftTheGame}` :
let message = context.texts.OpponentLeavesTheGame; leftPlayer.id == currentUser.id ? context.texts.YouLeftTheGame : context.texts.OpponentLeftTheGame;
if (userKeyWhoLeave == userKey) {
message = context.texts.YouLeftTheGame;
} }
return message;
} else if (game?.mancalaGame.state == "ended") { const isGameEnded = game?.mancalaGame.state == "ended";
const wonPlayer = game.mancalaGame.getWonPlayerId(); if (isGameEnded) {
let whoWon = const wonPlayerID = game.mancalaGame.getWonPlayerId();
game.mancalaGame.getWonPlayerId() === userKey const wonPlayer = wonPlayerID == whitePlayer.id ? whitePlayer : blackPlayer;
let whoWon;
if (wonPlayer) {
whoWon = isSpectator ? `${wonPlayer.name} ${context.texts.Won}` :
game.mancalaGame.getWonPlayerId() === currentUser.id
? context.texts.YouWon ? context.texts.YouWon
: context.texts.YouLost; : context.texts.YouLost;
if (!wonPlayer) { } else {
whoWon = context.texts.GameDraw; whoWon = context.texts.GameDraw;
} }
return context.texts.GameEnded + " " + whoWon; return context.texts.GameEnded + " " + whoWon;
} else { }
if (game) { if (game) {
return userKey ? game.mancalaGame.checkIsPlayerTurn(userKey) const playingPlayer = game.mancalaGame.checkIsPlayerTurn(whitePlayer.id) ? whitePlayer : blackPlayer;
return isSpectator ? `${playingPlayer.name} ${context.texts.Playing}` : game.mancalaGame.checkIsPlayerTurn(currentUser.id)
? context.texts.YourTurn ? context.texts.YourTurn
: context.texts.OpponentTurn : undefined; : context.texts.OpponentTurn;
}
} }
return undefined; return undefined;
} }
const InfoPanel: FunctionComponent<{ const InfoPanel: FunctionComponent<{
context: Context; context: Context;
game?: Game; game?: Game;
crashMessage?: string; currentUser: User;
userKey?: string; whitePlayer: User;
userKeyWhoLeave?: string; blackPlayer: User;
leftPlayer?: User;
style?: React.CSSProperties; style?: React.CSSProperties;
visible?: boolean; visible?: boolean;
isSpectator?: boolean;
}> = ({ }> = ({
context, context,
game, game,
crashMessage, currentUser,
userKey, whitePlayer,
userKeyWhoLeave, blackPlayer,
leftPlayer,
style, style,
visible visible,
isSpectator
}) => { }) => {
if (visible === false) return <></>; if (visible === false) return <></>;
const isUserTurn = userKey ? game?.mancalaGame.checkIsPlayerTurn(userKey) : false; const isUserTurn = currentUser.id ? game?.mancalaGame.checkIsPlayerTurn(currentUser.id) : false;
const containerColor = isUserTurn const containerColor = isUserTurn
? context.themeManager.theme.playerTurnColor ? context.themeManager.theme.playerTurnColor
: context.themeManager.theme.boardColor; : context.themeManager.theme.boardColor;
@ -77,9 +90,11 @@ const InfoPanel: FunctionComponent<{
const text = getInfoPanelTextByGameState({ const text = getInfoPanelTextByGameState({
context, context,
game, game,
crashMessage, currentUser,
userKey, whitePlayer,
userKeyWhoLeave blackPlayer,
leftPlayer,
isSpectator
}); });
if (text) { if (text) {
return ( return (

View File

@ -39,8 +39,6 @@ const GamePage: FunctionComponent<{
const [game, setGame] = useState<Game | undefined>(undefined); const [game, setGame] = useState<Game | undefined>(undefined);
const [crashMessage, setCrashMessage] = useState<string | undefined>(undefined);
const [userKeyWhoLeave, setUserKeyWhoLeave] = useState<string | undefined>(undefined); const [userKeyWhoLeave, setUserKeyWhoLeave] = useState<string | undefined>(undefined);
const [boardViewModel, setBoardViewModel] = useState<BoardViewModel | undefined>(undefined); const [boardViewModel, setBoardViewModel] = useState<BoardViewModel | undefined>(undefined);
@ -93,7 +91,6 @@ const GamePage: FunctionComponent<{
const newCrashMessage = message as string; const newCrashMessage = message as string;
console.error("on_game_crash"); console.error("on_game_crash");
console.error(newCrashMessage); console.error(newCrashMessage);
setCrashMessage(newCrashMessage);
} }
const onGameUserLeave = (message: any) => { const onGameUserLeave = (message: any) => {
const userKeyWhoLeave = message; const userKeyWhoLeave = message;
@ -107,17 +104,17 @@ const GamePage: FunctionComponent<{
const listenMessages = (game: Game, pitAnimator: PitAnimator): () => void => { const listenMessages = (game: Game, pitAnimator: PitAnimator): () => void => {
const _onGameUpdate = (message: object) => onGameUpdateEvent(pitAnimator, message); const _onGameUpdate = (message: object) => onGameUpdateEvent(pitAnimator, message);
context.rtmt.listenMessage(channel_on_game_update, _onGameUpdate); context.rtmt.addMessageListener(channel_on_game_update, _onGameUpdate);
context.rtmt.listenMessage(channel_on_game_crashed, onGameCrashed); context.rtmt.addMessageListener(channel_on_game_crashed, onGameCrashed);
context.rtmt.listenMessage(channel_on_game_user_leave, onGameUserLeave); context.rtmt.addMessageListener(channel_on_game_user_leave, onGameUserLeave);
context.rtmt.listenMessage(channel_on_user_connection_change, onUserConnectionChange); context.rtmt.addMessageListener(channel_on_user_connection_change, onUserConnectionChange);
checkIsSpectator(game) && userKey && context.rtmt.sendMessage(channel_listen_game_events, game.id); checkIsSpectator(game) && userKey && context.rtmt.sendMessage(channel_listen_game_events, game.id);
return () => { return () => {
checkIsSpectator(game) && userKey && context.rtmt.sendMessage(channel_unlisten_game_events, game.id); checkIsSpectator(game) && userKey && context.rtmt.sendMessage(channel_unlisten_game_events, game.id);
context.rtmt.unlistenMessage(channel_on_game_update, _onGameUpdate); context.rtmt.removeMessageListener(channel_on_game_update, _onGameUpdate);
context.rtmt.unlistenMessage(channel_on_game_crashed, onGameCrashed); context.rtmt.removeMessageListener(channel_on_game_crashed, onGameCrashed);
context.rtmt.unlistenMessage(channel_on_game_user_leave, onGameUserLeave); context.rtmt.removeMessageListener(channel_on_game_user_leave, onGameUserLeave);
context.rtmt.unlistenMessage(channel_on_user_connection_change, onUserConnectionChange); context.rtmt.removeMessageListener(channel_on_user_connection_change, onUserConnectionChange);
} }
}; };
@ -198,17 +195,53 @@ const GamePage: FunctionComponent<{
context.themeManager.theme.textColor, context.themeManager.theme.textColor,
context.themeManager.theme.textLightColor context.themeManager.theme.textLightColor
); );
const renderNewGameBtn = userKeyWhoLeave || !game || (game && game.mancalaGame.state == "ended");
const showBoardView = game && boardViewModel && userKey && true;
const opponentId = getOpponentId();
const opponentUser = { id: getOpponentId() || "0", name: "Anonymous", isOnline: opponentId ? isUserOnline(opponentId) : false, isAnonymous: true };
const user = { id: userKey || "1", name: "Anonymous", isOnline: connectionState === "connected", isAnonymous: true };
const isMobile = width < 600; const isMobile = width < 600;
const renderNewGameBtn = isSpectator || (userKeyWhoLeave || !game || (game && game.mancalaGame.state == "ended"));
const showBoardView = game && boardViewModel && userKey && true;
const topLocatedUserId = (isSpectator ? mancalaGame?.player2Id : getOpponentId()) || "0";
const bottomLocatedUserId = (isSpectator ? mancalaGame?.player1Id : userKey) || "1";
const topLocatedUser = {
id: topLocatedUserId,
name: "Anonymous",
isOnline: isUserOnline(topLocatedUserId),
isAnonymous: true
};
const bottomLocatedUser = {
id: bottomLocatedUserId,
name: "Anonymous",
isOnline: isSpectator ? isUserOnline(bottomLocatedUserId) : connectionState === "connected",
isAnonymous: true
};
const currentUser = isSpectator ? {
id: "2",
name: "Anonymous",
isOnline: connectionState === "connected",
isAnonymous: true
} : bottomLocatedUser;
const leftPlayer = userKeyWhoLeave ? (userKeyWhoLeave === topLocatedUser.id ? topLocatedUser : bottomLocatedUser) : undefined;
return ( return (
<PageContainer theme={theme!}> <PageContainer theme={theme!}>
<HeaderBar color={theme?.appBarBgColor}> {renderHeaderBar()}
{renderMobileBoardToolbar()}
{buildBoardTopToolbar()}
{showBoardView && (
<BoardView
game={game}
boardId={boardId}
boardViewModel={boardViewModel}
context={context}
onPitSelect={onPitSelect}
revert={isPlayer2} />
)}
<Center>
<LoadingComponent context={context} loadingState={gameLoadingState}></LoadingComponent>
</Center>
</PageContainer>
);
function renderHeaderBar() {
return <HeaderBar color={theme?.appBarBgColor}>
<Row> <Row>
<Link style={{ textDecoration: 'none' }} to={"/"}> <Link style={{ textDecoration: 'none' }} to={"/"}>
<HeaderbarIcon /> <HeaderbarIcon />
@ -225,50 +258,44 @@ const GamePage: FunctionComponent<{
text={renderNewGameBtn ? context.texts.NewGame : context.texts.Leave} text={renderNewGameBtn ? context.texts.NewGame : context.texts.Leave}
onClick={renderNewGameBtn ? onNewGameClick : onLeaveGameClick} /> onClick={renderNewGameBtn ? onNewGameClick : onLeaveGameClick} />
</Row> </Row>
</HeaderBar> </HeaderBar>;
<BoardToolbar style={{ justifyContent: "center" }} visible={showBoardView && isMobile || false}> }
function renderMobileBoardToolbar() {
return <BoardToolbar style={{ justifyContent: "center" }} visible={showBoardView && isMobile || false}>
{buildInfoPanel()}
</BoardToolbar>;
}
function buildBoardTopToolbar() {
return <BoardToolbar style={{ alignItems: "flex-end" }} visible={showBoardView || false}>
<UserStatus style={{
marginBottom: "0.5rem", marginLeft: "6%", maxWidth: isMobile ? "40vw" : "30vw",
width: isMobile ? "40vw" : "30vw"
}} context={context} layoutMode="left" user={topLocatedUser} visible={showBoardView || false} />
{buildInfoPanel()}
<UserStatus style={{
marginBottom: "0.5rem", marginRight: "6%", maxWidth: isMobile ? "40vw" : "30vw",
width: isMobile ? "40vw" : "30vw"
}} context={context} layoutMode="right" user={bottomLocatedUser} visible={showBoardView || false} />
</BoardToolbar>;
}
function buildInfoPanel() {
return (
<InfoPanel <InfoPanel
style={{ marginTop: "0.5rem", marginBottom: "0.5rem" }} style={{ marginTop: "0.5rem", marginBottom: "0.5rem" }}
context={context} context={context}
game={game} game={game}
crashMessage={crashMessage} currentUser={currentUser}
userKey={userKey} whitePlayer={topLocatedUser}
userKeyWhoLeave={userKeyWhoLeave} /> blackPlayer={bottomLocatedUser}
</BoardToolbar> leftPlayer={leftPlayer}
<BoardToolbar style={{ alignItems: "flex-end" }} visible={showBoardView || false}> visible={!isMobile}
<UserStatus style={{ isSpectator={isSpectator} />
marginBottom: "0.5rem", marginLeft: "6%", maxWidth: isMobile ? "40vw" : "30vw",
width: isMobile ? "40vw" : "30vw"
}} context={context} layoutMode="left" user={opponentUser} visible={showBoardView || false} />
<InfoPanel
style={{
marginTop: "0.5rem", marginBottom: "0.5rem",
}}
context={context}
game={game}
crashMessage={crashMessage}
userKey={userKey}
userKeyWhoLeave={userKeyWhoLeave}
visible={!isMobile} />
<UserStatus style={{
marginBottom: "0.5rem", marginRight: "6%", maxWidth: isMobile ? "40vw" : "30vw",
width: isMobile ? "40vw" : "30vw"
}} context={context} layoutMode="right" user={user} visible={showBoardView || false} />
</BoardToolbar>
{showBoardView && (
<BoardView
game={game}
boardId={boardId}
boardViewModel={boardViewModel}
context={context}
onPitSelect={onPitSelect}
revert={isPlayer2} />
)}
<Center>
<LoadingComponent context={context} loadingState={gameLoadingState}></LoadingComponent>
</Center>
</PageContainer>
); );
} }
}
export default GamePage; export default GamePage;