diff --git a/packages/client/src/components/Game.tsx b/packages/client/src/components/Game.tsx
index 8afcc36..be274d7 100644
--- a/packages/client/src/components/Game.tsx
+++ b/packages/client/src/components/Game.tsx
@@ -40,6 +40,12 @@ export default () => {
{" "}
turn
+
);
};
diff --git a/packages/client/src/components/Table.tsx b/packages/client/src/components/Table.tsx
index a34e089..d2f7472 100644
--- a/packages/client/src/components/Table.tsx
+++ b/packages/client/src/components/Table.tsx
@@ -11,7 +11,7 @@ import {
} from "solid-js";
import api, { fromWebsocket } from "~/api";
import { createObservable, createObservableWithInit, cx } from "~/fn";
-import { me } from "~/profile";
+import { me, mePromise } from "~/profile";
import Game from "./Game";
import Player from "./Player";
@@ -37,7 +37,7 @@ export default (props: { tableKey: string }) => {
onCleanup(() => wsPromise.then((ws) => ws.close()));
const presenceEvents = wsEvents.filter((evt) => evt.players != null);
- const gameEvents = wsEvents.filter((evt) => evt.view != null);
+ const gameEvents = wsEvents.filter((evt) => evt.view !== undefined);
const players = createObservableWithInit(
presenceEvents.map((evt) => evt.players!),
@@ -45,6 +45,15 @@ export default (props: { tableKey: string }) => {
);
const [ready, setReady] = createSignal(false);
+ mePromise.then(
+ (me) =>
+ me &&
+ wsEvents
+ .filter((evt) => evt.playersReady !== undefined)
+ .map((evt) => evt.playersReady?.[me] ?? false)
+ .onValue(setReady)
+ );
+
createEffect(() => sendWs({ ready: ready() }));
const view = createObservable(gameEvents.map((evt) => evt.view));
diff --git a/packages/server/src/table.ts b/packages/server/src/table.ts
index 2d7409a..ed8a2cf 100644
--- a/packages/server/src/table.ts
+++ b/packages/server/src/table.ts
@@ -12,7 +12,7 @@ import { transform } from "./kefir-extension";
export const WsOut = t.Object({
players: t.Optional(t.Array(t.String())),
- playersReady: t.Optional(t.Record(t.String(), t.Boolean())),
+ playersReady: t.Optional(t.Nullable(t.Record(t.String(), t.Boolean()))),
view: t.Optional(t.Any()),
});
export type TWsOut = typeof WsOut.static;
@@ -31,15 +31,15 @@ type TablePayload = {
never
>;
- readys: TBus;
- actions: TBus;
- quits: TBus;
+ readys: TBus;
+ actions: TBus;
+ quits: TBus;
};
outputs: {
- playersPresent: Property;
- playersReady: Property<{ [key: string]: boolean }, unknown>;
- gameConfig: Property;
- gameState: Property;
+ playersPresent: Property;
+ playersReady: Property<{ [key: string]: boolean } | null, any>;
+ gameConfig: Property;
+ gameState: Property;
};
};
@@ -60,6 +60,7 @@ export const liveTable = (key: string) => {
quits: Bus(),
};
const { connectionChanges, readys, actions, quits } = inputs;
+ quits.log("quits");
// =======
const playersPresent = connectionChanges
@@ -78,34 +79,45 @@ export const liveTable = (key: string) => {
.map((counts) => Object.keys(counts))
.toProperty();
+ const gameEnds = quits.map((_) => null);
+
+ const gameStarts = pool();
const playersReady = transform(
- {} as { [key: string]: boolean },
+ null as { [key: string]: boolean } | null,
[
playersPresent,
(prev, players: string[]) =>
Object.fromEntries(
- players.map((p) => [p, prev[p] ?? false])
+ players.map((p) => [p, prev?.[p] ?? false])
),
],
[
readys,
(prev, evt: { humanKey: string; ready: boolean }) =>
- prev[evt.humanKey] != null
+ prev?.[evt.humanKey] != null
? { ...prev, [evt.humanKey]: evt.ready }
: prev,
+ ],
+ [gameStarts, () => null],
+ [
+ combine([gameEnds], [playersPresent], (_, players) => players),
+ (_, players: string[]) =>
+ Object.fromEntries(players.map((p) => [p, false])),
]
)
.toProperty()
.log("playersReady");
- const gameStarts = playersReady
- .filter(
- (pr) =>
- Object.values(pr).length > 0 &&
- Object.values(pr).every((ready) => ready)
- )
- .map((_) => null)
- .log("gameStarts");
+ gameStarts.plug(
+ playersReady
+ .filter(
+ (pr) =>
+ Object.values(pr ?? {}).length > 0 &&
+ Object.values(pr!).every((ready) => ready)
+ )
+ .map((_) => null)
+ .log("gameStarts")
+ );
const gameConfigPool = pool<
{
@@ -144,8 +156,12 @@ export const liveTable = (key: string) => {
humanKey: evt.action.humanKey,
})
: prev,
- ]
+ ],
+ [quits, () => null]
).toProperty();
+ gameState
+ .map((state) => JSON.stringify(state).substring(0, 10))
+ .log("gameState");
const gameIsActive = gameState
.map((gs) => gs != null)
@@ -166,9 +182,9 @@ export const liveTable = (key: string) => {
inputs,
outputs: {
playersPresent,
- playersReady,
- gameConfig: gameConfig as Property,
- gameState: gameState as Property,
+ playersReady: playersReady.toProperty(),
+ gameConfig: gameConfig as Property,
+ gameState: gameState as Property,
},
};