diff --git a/packages/client/src/api.ts b/packages/client/src/api.ts index 8638102..1b739e7 100644 --- a/packages/client/src/api.ts +++ b/packages/client/src/api.ts @@ -1,5 +1,9 @@ import { type Api } from "../../server/src/api"; import { treaty } from "@elysiajs/eden"; -const { api } = treaty("http://localhost:5001"); +const { api } = treaty("http://localhost:5001", { + headers: { + human: "daniel", + }, +}); export default api; diff --git a/packages/client/src/components/Game.tsx b/packages/client/src/components/Game.tsx index a236cb1..da7c25f 100644 --- a/packages/client/src/components/Game.tsx +++ b/packages/client/src/components/Game.tsx @@ -1,5 +1,9 @@ import { Accessor, createContext, createResource, Show } from "solid-js"; -import { GameState, Action } from "../../../server/src/games/simple"; +import { + GameState, + Action, + vGameState, +} from "../../../server/src/games/simple"; import api from "../api"; import Hand from "./Hand"; import Pile from "./Pile"; @@ -20,7 +24,7 @@ export default (props: { instanceId: string }) => { api .simple(props) .post({ action }) - .then((res) => mutate(res.data as GameState)); + .then((res) => res.status == 200 && mutate(res.data as vGameState)); return ( @@ -38,7 +42,7 @@ export default (props: { instanceId: string }) => { } /> - + diff --git a/packages/client/src/routes/[game]/[instance].tsx b/packages/client/src/routes/[game]/[instance].tsx index 4fbf143..a9d945f 100644 --- a/packages/client/src/routes/[game]/[instance].tsx +++ b/packages/client/src/routes/[game]/[instance].tsx @@ -1,6 +1,5 @@ import { A, useParams } from "@solidjs/router"; -import { createEffect, createResource, Show, Suspense } from "solid-js"; import Game from "../../components/Game"; export default () => { @@ -8,7 +7,7 @@ export default () => { return ( <> - + {

{param.game}

- +
    {(instance) => ( diff --git a/packages/server/db/schema.prisma b/packages/server/db/schema.prisma index e425d86..89c8a87 100644 --- a/packages/server/db/schema.prisma +++ b/packages/server/db/schema.prisma @@ -16,9 +16,17 @@ model Game { instances Instance[] } -model Instance { - id Int @id @default(autoincrement()) - gameKey String - game Game @relation(fields: [gameKey], references: [key]) - gameState Json +model Human { + key String @id + name String + Instance Instance[] +} + +model Instance { + id String @id @default(cuid(2)) + createdByKey String + createdBy Human @relation(fields: [createdByKey], references: [key]) + gameKey String + game Game @relation(fields: [gameKey], references: [key]) + gameState Json } diff --git a/packages/server/package.json b/packages/server/package.json index b40976c..c8d7ead 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -17,6 +17,7 @@ "@prisma/client": "6.13.0", "elysia": "^1.3.8", "hono": "^4.8.12", + "object-hash": "^3.0.0", "zod": "^4.0.15" }, "devDependencies": { diff --git a/packages/server/src/games/simple.ts b/packages/server/src/games/simple.ts index 852631d..1c4d90a 100644 --- a/packages/server/src/games/simple.ts +++ b/packages/server/src/games/simple.ts @@ -6,7 +6,6 @@ import { shuffle, vCard, } from "../../../shared/cards"; -import hash from "object-hash"; import { heq } from "../../../shared/utils"; import { Elysia, t } from "elysia"; import { prisma } from "../db/db"; @@ -14,7 +13,6 @@ import { prisma } from "../db/db"; // omniscient game state export type GameState = { prev?: { - hash: string; action: Action; }; @@ -41,14 +39,15 @@ export type PlayerView = { export type Action = { type: "draw" } | { type: "discard"; card: Card }; -export const newGame = (players: string[]) => - ({ +export const newGame = (players: string[]) => { + console.log("new game called with", JSON.stringify(players)); + return { deck: shuffle(newDeck()), players: Object.fromEntries(players.map((humanId) => [humanId, []])), - } as GameState); + } as GameState; +}; export const getKnowledge = (state: GameState, humanId: string) => ({ - hash: hash(state), humanId, deck: state.deck.map((_) => null), players: Object.fromEntries( @@ -59,23 +58,27 @@ export const getKnowledge = (state: GameState, humanId: string) => ({ ), }); -export const resolveAction = (state: GameState, action: Action): GameState => { - if (action.prevHash != hash(state)) { - throw new Error( - `action thinks it's applying to ${ - action.prevHash - }, but we're checking it against ${hash(state)}` - ); - } +export const resolveAction = ( + state: GameState, + humanId: string, + action: Action +): GameState => { + // if (action.prevHash != hash(state)) { + // throw new Error( + // `action thinks it's applying to ${ + // action.prevHash + // }, but we're checking it against ${hash(state)}` + // ); + // } - const playerHand = state.players[action.humanId]; + const playerHand = state.players[humanId]; if (action.type == "draw") { const [drawn, ...rest] = state.deck; return { deck: rest, players: { ...state.players, - [action.humanId]: [drawn, ...playerHand], + [humanId]: [drawn, ...playerHand], }, }; } @@ -86,7 +89,7 @@ export const resolveAction = (state: GameState, action: Action): GameState => { deck: [action.card, ...state.deck], players: { ...state.players, - [action.humanId]: playerHand + [humanId]: playerHand .slice(0, index) .concat(playerHand.slice(index + 1)), }, @@ -94,10 +97,18 @@ export const resolveAction = (state: GameState, action: Action): GameState => { }; export const simpleApi = new Elysia({ prefix: "/simple" }) + // .guard({ headers: t.Object({ Human: t.String() }) }) .post( "/newGame", - ({ body: { players } }: { body: { players: string[] } }) => - newGame(players) + (args: { body: { players: string[] }; headers: { human: string } }) => { + return prisma.instance.create({ + data: { + gameState: newGame(args.body.players), + gameKey: "simple", + createdByKey: args.headers.human, + }, + }); + } ) .group("/:instanceId", (app) => app @@ -105,33 +116,35 @@ export const simpleApi = new Elysia({ prefix: "/simple" }) prisma.instance .findUnique({ where: { - id: Number(instanceId), + id: instanceId, }, }) .then((game) => game?.gameState) ) .post( "/", - ({ params: { instanceId }, body: { action } }) => + ({ + params: { instanceId }, + body: { action }, + headers: { Human: humanId }, + }) => prisma.instance .findUniqueOrThrow({ where: { - id: Number(instanceId), + id: instanceId, }, }) .then((game) => { const newState = resolveAction( game.gameState as GameState, + humanId!, action ); - const knownState = getKnowledge( - newState, - action.humanId - ); + const knownState = getKnowledge(newState, humanId!); void prisma.instance.update({ data: { gameState: newState }, where: { - id: Number(instanceId), + id: instanceId, }, }); return knownState; diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 9204901..1870114 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -10,7 +10,9 @@ const app = new Elysia() .onRequest(({ request }) => { console.log(request.method, request.url); }) - .onError(({ code, error }) => { + .onError(({ code, error, body, headers }) => { + console.error("headers", JSON.stringify(headers, null, 2)); + console.error("body", JSON.stringify(body, null, 2)); console.error(code, error); }) .get("/ping", () => "pong") diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7d9cb66..0b2f898 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -57,6 +57,9 @@ importers: hono: specifier: ^4.8.12 version: 4.8.12 + object-hash: + specifier: ^3.0.0 + version: 3.0.0 zod: specifier: ^4.0.15 version: 4.0.15 @@ -810,6 +813,10 @@ packages: engines: {node: ^14.16.0 || >=16.10.0} hasBin: true + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} @@ -1736,6 +1743,8 @@ snapshots: pkg-types: 2.2.0 tinyexec: 1.0.1 + object-hash@3.0.0: {} + ohash@2.0.11: {} openapi-types@12.1.3: