Spaces:
Sleeping
Sleeping
test
Browse files- src/components/Game.tsx +33 -31
src/components/Game.tsx
CHANGED
@@ -1,7 +1,4 @@
|
|
1 |
-
import { useRef, useState } from 'react';
|
2 |
-
import PixiGame from './PixiGame.tsx';
|
3 |
-
|
4 |
-
import { useElementSize } from 'usehooks-ts';
|
5 |
import { Stage } from '@pixi/react';
|
6 |
import { ConvexProvider, useConvex, useQuery } from 'convex/react';
|
7 |
import PlayerDetails from './PlayerDetails.tsx';
|
@@ -20,21 +17,24 @@ import { createPortal } from 'react-dom';
|
|
20 |
import GameVote from './GameVote.tsx';
|
21 |
import { EndGame } from './EndGame.tsx';
|
22 |
import { LOBBY_SIZE } from '../../convex/constants';
|
|
|
23 |
|
24 |
export const SHOW_DEBUG_UI = !!import.meta.env.VITE_SHOW_DEBUG_UI;
|
25 |
|
26 |
-
|
27 |
const [humans, setHumans] = useState(0);
|
28 |
|
29 |
useEffect(() => {
|
30 |
const updateHumanPlayers = () => {
|
31 |
-
const humanCount = [...game.world.
|
32 |
setHumans(humanCount);
|
33 |
};
|
34 |
|
35 |
// Update the count of human players when the component mounts and when game.world.players changes
|
36 |
updateHumanPlayers();
|
37 |
-
}, [game.world.
|
|
|
|
|
38 |
|
39 |
switch (game.world.gameCycle.cycleState) {
|
40 |
case 'Day':
|
@@ -45,7 +45,7 @@ export function GameStateLabel(game: GameObj, me: PlayerDescription | undefined)
|
|
45 |
case 'WerewolfVoting':
|
46 |
return {
|
47 |
label: 'Werewolf Vote',
|
48 |
-
desc: 'Select a player who is a
|
49 |
};
|
50 |
case 'PlayerKillVoting':
|
51 |
return {
|
@@ -55,31 +55,32 @@ export function GameStateLabel(game: GameObj, me: PlayerDescription | undefined)
|
|
55 |
case 'LobbyState':
|
56 |
return {
|
57 |
label: 'Lobby (waiting for start)',
|
58 |
-
desc: `Waiting
|
59 |
};
|
60 |
case 'Night':
|
61 |
return {
|
62 |
label: 'Night',
|
63 |
-
desc: me?.type === 'werewolf' ? 'Discuss who to kill with other
|
64 |
};
|
65 |
case 'EndGame':
|
66 |
return {
|
67 |
label: 'The End',
|
68 |
-
desc: `Winners are ${
|
69 |
};
|
|
|
|
|
70 |
}
|
71 |
}
|
72 |
|
73 |
-
export function canVote(game
|
74 |
return me && (game.world.gameCycle.cycleState === "WerewolfVoting" || (game.world.gameCycle.cycleState === "PlayerKillVoting" && me.type === "werewolf"));
|
75 |
}
|
76 |
|
77 |
-
export function isEndGame(game
|
78 |
return game.world.gameCycle.cycleState === "EndGame";
|
79 |
}
|
80 |
|
81 |
-
function showMap(gameCycle
|
82 |
-
// Here also check for player description
|
83 |
return (gameCycle.cycleState === "Day" || gameCycle.cycleState === "WerewolfVoting") || me?.type === "werewolf";
|
84 |
}
|
85 |
|
@@ -95,8 +96,7 @@ export default function Game() {
|
|
95 |
const engineId = worldStatus?.engineId;
|
96 |
const oauth = JSON.parse(localStorage.getItem('oauth'));
|
97 |
const oauthToken = oauth ? oauth.userInfo.fullname : undefined;
|
98 |
-
const humanTokenIdentifier =
|
99 |
-
|
100 |
|
101 |
const game = useServerGame(worldId);
|
102 |
|
@@ -108,24 +108,26 @@ export default function Game() {
|
|
108 |
|
109 |
const scrollViewRef = useRef<HTMLDivElement>(null);
|
110 |
|
111 |
-
if (!worldId || !engineId || !game
|
112 |
return null;
|
113 |
}
|
114 |
-
|
115 |
-
//console.log("game.world.players.values() :",game.world.players.values())
|
116 |
const playerId = [...game.world.players.values()].find(
|
117 |
(p) => !!p && p.human === humanTokenIdentifier,
|
118 |
)?.id;
|
119 |
-
console.log("playerId",playerId)
|
120 |
|
121 |
const meDescription = playerId ? game?.playerDescriptions.get(playerId) : undefined;
|
|
|
|
|
|
|
122 |
return (
|
123 |
<>
|
124 |
{SHOW_DEBUG_UI && <DebugTimeManager timeManager={timeManager} width={200} height={100} />}
|
125 |
<div className="mx-auto w-full max-w grid grid-rows-[240px_1fr] lg:grid-rows-[1fr] lg:grid-cols-[1fr_auto] lg:grow max-w-[1400px] min-h-[480px] game-frame">
|
126 |
{/* Game area */}
|
127 |
<div className="relative overflow-hidden bg-brown-900" ref={gameWrapperRef}>
|
128 |
-
<div className={`absolute inset-0 ${showMap(game.world.gameCycle, meDescription) ? '' : 'invisible'
|
129 |
<div className="container">
|
130 |
<Stage width={width} height={height} options={{ backgroundColor: 0x7ab5ff }}>
|
131 |
{/* Re-propagate context because contexts are not shared between renderers.
|
@@ -144,21 +146,21 @@ https://github.com/michalochman/react-pixi-fiber/issues/145#issuecomment-5315492
|
|
144 |
</Stage>
|
145 |
</div>
|
146 |
</div>
|
147 |
-
<div className={`absolute inset-0 ${!showMap(game.world.gameCycle, meDescription) ? '' : 'invisible'
|
148 |
<Cloud worldId={worldId} />
|
149 |
</div>
|
150 |
</div>
|
151 |
{/* Right column area */}
|
152 |
<div
|
153 |
-
className="flex flex-col overflow-y-auto shrink-0 px-4 py-6 sm:px-6 lg:w-96 xl:pr-6 border-t-8 sm:border-t-0 sm:border-l-8 border-brown-900
|
154 |
ref={scrollViewRef}
|
155 |
>
|
156 |
<div className="flex flex-col items-center mb-4 gap-4">
|
157 |
-
<h2 className="text-2xl font-bold">{
|
158 |
-
<p className="text-lg text-center">{
|
159 |
</div>
|
160 |
{playerId && !isEndGame(game) && canVote(game, meDescription) && <GameVote engineId={engineId} game={game} playerId={playerId} />}
|
161 |
-
{!isEndGame(game) && !canVote(game, meDescription) && playerId
|
162 |
worldId={worldId}
|
163 |
engineId={engineId}
|
164 |
game={game}
|
@@ -171,10 +173,10 @@ https://github.com/michalochman/react-pixi-fiber/issues/145#issuecomment-5315492
|
|
171 |
</div>
|
172 |
</div>
|
173 |
{createPortal(
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
)}
|
179 |
</>
|
180 |
);
|
|
|
1 |
+
import React, { useRef, useState, useEffect } from 'react';
|
|
|
|
|
|
|
2 |
import { Stage } from '@pixi/react';
|
3 |
import { ConvexProvider, useConvex, useQuery } from 'convex/react';
|
4 |
import PlayerDetails from './PlayerDetails.tsx';
|
|
|
17 |
import GameVote from './GameVote.tsx';
|
18 |
import { EndGame } from './EndGame.tsx';
|
19 |
import { LOBBY_SIZE } from '../../convex/constants';
|
20 |
+
import { useElementSize } from 'usehooks-ts';
|
21 |
|
22 |
export const SHOW_DEBUG_UI = !!import.meta.env.VITE_SHOW_DEBUG_UI;
|
23 |
|
24 |
+
function GameStateLabel({ game, me }) {
|
25 |
const [humans, setHumans] = useState(0);
|
26 |
|
27 |
useEffect(() => {
|
28 |
const updateHumanPlayers = () => {
|
29 |
+
const humanCount = [...game.world.players.values()].filter(player => player.human).length;
|
30 |
setHumans(humanCount);
|
31 |
};
|
32 |
|
33 |
// Update the count of human players when the component mounts and when game.world.players changes
|
34 |
updateHumanPlayers();
|
35 |
+
}, [game.world.players]);
|
36 |
+
|
37 |
+
console.log('Human player seen by lobby', game.world.players.values());
|
38 |
|
39 |
switch (game.world.gameCycle.cycleState) {
|
40 |
case 'Day':
|
|
|
45 |
case 'WerewolfVoting':
|
46 |
return {
|
47 |
label: 'Werewolf Vote',
|
48 |
+
desc: 'Select a player who is a werewolf',
|
49 |
};
|
50 |
case 'PlayerKillVoting':
|
51 |
return {
|
|
|
55 |
case 'LobbyState':
|
56 |
return {
|
57 |
label: 'Lobby (waiting for start)',
|
58 |
+
desc: `Waiting for the game to start. ${humans} out of the ${LOBBY_SIZE} required`,
|
59 |
};
|
60 |
case 'Night':
|
61 |
return {
|
62 |
label: 'Night',
|
63 |
+
desc: me?.type === 'werewolf' ? 'Discuss who to kill with other werewolves' : 'Hide in your home!!',
|
64 |
};
|
65 |
case 'EndGame':
|
66 |
return {
|
67 |
label: 'The End',
|
68 |
+
desc: `Winners are ${game.world.winner}!`,
|
69 |
};
|
70 |
+
default:
|
71 |
+
return null;
|
72 |
}
|
73 |
}
|
74 |
|
75 |
+
export function canVote(game, me) {
|
76 |
return me && (game.world.gameCycle.cycleState === "WerewolfVoting" || (game.world.gameCycle.cycleState === "PlayerKillVoting" && me.type === "werewolf"));
|
77 |
}
|
78 |
|
79 |
+
export function isEndGame(game) {
|
80 |
return game.world.gameCycle.cycleState === "EndGame";
|
81 |
}
|
82 |
|
83 |
+
function showMap(gameCycle, me) {
|
|
|
84 |
return (gameCycle.cycleState === "Day" || gameCycle.cycleState === "WerewolfVoting") || me?.type === "werewolf";
|
85 |
}
|
86 |
|
|
|
96 |
const engineId = worldStatus?.engineId;
|
97 |
const oauth = JSON.parse(localStorage.getItem('oauth'));
|
98 |
const oauthToken = oauth ? oauth.userInfo.fullname : undefined;
|
99 |
+
const humanTokenIdentifier = useQuery(api.world.userStatus, { worldId, oauthToken });
|
|
|
100 |
|
101 |
const game = useServerGame(worldId);
|
102 |
|
|
|
108 |
|
109 |
const scrollViewRef = useRef<HTMLDivElement>(null);
|
110 |
|
111 |
+
if (!worldId || !engineId || !game) {
|
112 |
return null;
|
113 |
}
|
114 |
+
|
|
|
115 |
const playerId = [...game.world.players.values()].find(
|
116 |
(p) => !!p && p.human === humanTokenIdentifier,
|
117 |
)?.id;
|
118 |
+
console.log("playerId", playerId);
|
119 |
|
120 |
const meDescription = playerId ? game?.playerDescriptions.get(playerId) : undefined;
|
121 |
+
|
122 |
+
const gameStateLabel = GameStateLabel({ game: game as GameObj, me: meDescription });
|
123 |
+
|
124 |
return (
|
125 |
<>
|
126 |
{SHOW_DEBUG_UI && <DebugTimeManager timeManager={timeManager} width={200} height={100} />}
|
127 |
<div className="mx-auto w-full max-w grid grid-rows-[240px_1fr] lg:grid-rows-[1fr] lg:grid-cols-[1fr_auto] lg:grow max-w-[1400px] min-h-[480px] game-frame">
|
128 |
{/* Game area */}
|
129 |
<div className="relative overflow-hidden bg-brown-900" ref={gameWrapperRef}>
|
130 |
+
<div className={`absolute inset-0 ${showMap(game.world.gameCycle, meDescription) ? '' : 'invisible'}`}>
|
131 |
<div className="container">
|
132 |
<Stage width={width} height={height} options={{ backgroundColor: 0x7ab5ff }}>
|
133 |
{/* Re-propagate context because contexts are not shared between renderers.
|
|
|
146 |
</Stage>
|
147 |
</div>
|
148 |
</div>
|
149 |
+
<div className={`absolute inset-0 ${!showMap(game.world.gameCycle, meDescription) ? '' : 'invisible'}`}>
|
150 |
<Cloud worldId={worldId} />
|
151 |
</div>
|
152 |
</div>
|
153 |
{/* Right column area */}
|
154 |
<div
|
155 |
+
className="flex flex-col overflow-y-auto shrink-0 px-4 py-6 sm:px-6 lg:w-96 xl:pr-6 border-t-8 sm:border-t-0 sm:border-l-8 border-brown-900 bg-brown-800 text-brown-100"
|
156 |
ref={scrollViewRef}
|
157 |
>
|
158 |
<div className="flex flex-col items-center mb-4 gap-4">
|
159 |
+
<h2 className="text-2xl font-bold">{gameStateLabel.label}</h2>
|
160 |
+
<p className="text-lg text-center">{gameStateLabel.desc}</p>
|
161 |
</div>
|
162 |
{playerId && !isEndGame(game) && canVote(game, meDescription) && <GameVote engineId={engineId} game={game} playerId={playerId} />}
|
163 |
+
{!isEndGame(game) && !canVote(game, meDescription) && playerId && <PlayerDetails
|
164 |
worldId={worldId}
|
165 |
engineId={engineId}
|
166 |
game={game}
|
|
|
173 |
</div>
|
174 |
</div>
|
175 |
{createPortal(
|
176 |
+
<div className="max-w-[1400px] mx-auto">
|
177 |
+
{playerId && <VotingPopover engineId={engineId} game={game} playerId={playerId} />}
|
178 |
+
</div>,
|
179 |
+
document.getElementById('footer-buttons')
|
180 |
)}
|
181 |
</>
|
182 |
);
|