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

View File

@ -39,8 +39,6 @@ const GamePage: FunctionComponent<{
const [game, setGame] = useState<Game | undefined>(undefined);
const [crashMessage, setCrashMessage] = useState<string | undefined>(undefined);
const [userKeyWhoLeave, setUserKeyWhoLeave] = useState<string | undefined>(undefined);
const [boardViewModel, setBoardViewModel] = useState<BoardViewModel | undefined>(undefined);
@ -93,7 +91,6 @@ const GamePage: FunctionComponent<{
const newCrashMessage = message as string;
console.error("on_game_crash");
console.error(newCrashMessage);
setCrashMessage(newCrashMessage);
}
const onGameUserLeave = (message: any) => {
const userKeyWhoLeave = message;
@ -107,17 +104,17 @@ const GamePage: FunctionComponent<{
const listenMessages = (game: Game, pitAnimator: PitAnimator): () => void => {
const _onGameUpdate = (message: object) => onGameUpdateEvent(pitAnimator, message);
context.rtmt.listenMessage(channel_on_game_update, _onGameUpdate);
context.rtmt.listenMessage(channel_on_game_crashed, onGameCrashed);
context.rtmt.listenMessage(channel_on_game_user_leave, onGameUserLeave);
context.rtmt.listenMessage(channel_on_user_connection_change, onUserConnectionChange);
context.rtmt.addMessageListener(channel_on_game_update, _onGameUpdate);
context.rtmt.addMessageListener(channel_on_game_crashed, onGameCrashed);
context.rtmt.addMessageListener(channel_on_game_user_leave, onGameUserLeave);
context.rtmt.addMessageListener(channel_on_user_connection_change, onUserConnectionChange);
checkIsSpectator(game) && userKey && context.rtmt.sendMessage(channel_listen_game_events, game.id);
return () => {
checkIsSpectator(game) && userKey && context.rtmt.sendMessage(channel_unlisten_game_events, game.id);
context.rtmt.unlistenMessage(channel_on_game_update, _onGameUpdate);
context.rtmt.unlistenMessage(channel_on_game_crashed, onGameCrashed);
context.rtmt.unlistenMessage(channel_on_game_user_leave, onGameUserLeave);
context.rtmt.unlistenMessage(channel_on_user_connection_change, onUserConnectionChange);
context.rtmt.removeMessageListener(channel_on_game_update, _onGameUpdate);
context.rtmt.removeMessageListener(channel_on_game_crashed, onGameCrashed);
context.rtmt.removeMessageListener(channel_on_game_user_leave, onGameUserLeave);
context.rtmt.removeMessageListener(channel_on_user_connection_change, onUserConnectionChange);
}
};
@ -198,17 +195,53 @@ const GamePage: FunctionComponent<{
context.themeManager.theme.textColor,
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 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 (
<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>
<Link style={{ textDecoration: 'none' }} to={"/"}>
<HeaderbarIcon />
@ -225,50 +258,44 @@ const GamePage: FunctionComponent<{
text={renderNewGameBtn ? context.texts.NewGame : context.texts.Leave}
onClick={renderNewGameBtn ? onNewGameClick : onLeaveGameClick} />
</Row>
</HeaderBar>
<BoardToolbar style={{ justifyContent: "center" }} visible={showBoardView && isMobile || false}>
</HeaderBar>;
}
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
style={{ marginTop: "0.5rem", marginBottom: "0.5rem" }}
context={context}
game={game}
crashMessage={crashMessage}
userKey={userKey}
userKeyWhoLeave={userKeyWhoLeave} />
</BoardToolbar>
<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={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>
currentUser={currentUser}
whitePlayer={topLocatedUser}
blackPlayer={bottomLocatedUser}
leftPlayer={leftPlayer}
visible={!isMobile}
isSpectator={isSpectator} />
);
}
}
export default GamePage;