From b76bca9c572284a89fd536176fbc5bb767115ac2 Mon Sep 17 00:00:00 2001 From: Moritz Ruth Date: Sat, 22 Apr 2023 22:11:53 +0200 Subject: [PATCH] commit #4 --- package.json | 1 + pnpm-lock.yaml | 7 + schema.prisma | 31 +--- src/App.vue | 30 ++-- src/auth.ts | 13 +- src/clientGame.ts | 45 ++++-- src/components/GameEndModal.vue | 2 +- src/components/JoinScreen.vue | 97 ++++++++++++ src/components/LoginScreen.vue | 49 ++++++ src/components/PreStartScreen.vue | 26 ++++ src/components/input/TextInput.vue | 2 +- src/server/{activeGame.ts => game.ts} | 140 ++++++++++++------ src/server/main.ts | 12 +- src/server/seed.ts | 27 ---- src/server/trpc/base.ts | 24 ++- src/server/trpc/game.ts | 19 ++- src/server/trpc/index.ts | 87 ++++++++--- .../game/{gameActions.ts => actions.ts} | 11 +- src/shared/game/events.ts | 6 + src/shared/game/state.ts | 15 +- src/shared/lobbyCode.ts | 1 + src/trpc.ts | 1 + 22 files changed, 464 insertions(+), 182 deletions(-) create mode 100644 src/components/JoinScreen.vue create mode 100644 src/components/LoginScreen.vue create mode 100644 src/components/PreStartScreen.vue rename src/server/{activeGame.ts => game.ts} (51%) delete mode 100644 src/server/seed.ts rename src/shared/game/{gameActions.ts => actions.ts} (91%) create mode 100644 src/shared/game/events.ts create mode 100644 src/shared/lobbyCode.ts diff --git a/package.json b/package.json index 3161d45..12cc769 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "bufferutil": "^4.0.7", "cookie": "^0.5.0", "cookie-parser": "^1.4.6", + "date-fns": "^2.29.3", "eventemitter3": "^5.0.0", "express": "^4.18.2", "immer": "^10.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index be836c5..537306a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,7 @@ importers: bufferutil: ^4.0.7 cookie: ^0.5.0 cookie-parser: ^1.4.6 + date-fns: ^2.29.3 eventemitter3: ^5.0.0 express: ^4.18.2 immer: ^10.0.1 @@ -56,6 +57,7 @@ importers: bufferutil: 4.0.7 cookie: 0.5.0 cookie-parser: 1.4.6 + date-fns: 2.29.3 eventemitter3: 5.0.0 express: 4.18.2 immer: 10.0.1 @@ -1320,6 +1322,11 @@ packages: /csstype/2.6.21: resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} + /date-fns/2.29.3: + resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==} + engines: {node: '>=0.11'} + dev: false + /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: diff --git a/schema.prisma b/schema.prisma index 76d1e2b..06acf76 100644 --- a/schema.prisma +++ b/schema.prisma @@ -7,32 +7,9 @@ generator client { provider = "prisma-client-js" } -model Game { - id String @id @default(cuid()) - lobbyCodeIfActive String? @unique - - actions GameAction[] -} - model User { - id String @id @default(cuid()) - name String - token String @unique - - gameActions GameAction[] -} - -model GameAction { - id String @id @default(cuid()) - - index Int - gameId String - game Game @relation(references: [id], fields: [gameId], onDelete: Cascade) - - playerId String? // null → the server or a deleted user - player User? @relation(references: [id], fields: [playerId], onDelete: SetNull) - - data String - - @@unique([gameId, index]) + id String @id @default(cuid()) + name String + token String @unique + lastActivityDate DateTime @default(now()) } diff --git a/src/App.vue b/src/App.vue index 529a6d1..4a50731 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,13 +2,13 @@
-
- - +
+
+ Loading… +
+ + +
@@ -67,24 +67,20 @@ diff --git a/src/auth.ts b/src/auth.ts index da067c7..a5c147b 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -1,5 +1,6 @@ import { defineStore } from "pinia" import { computed, ref } from "vue" +import { trpcClient } from "./trpc" export const useAuth = defineStore("auth", () => { const authenticatedUser = ref<{ id: string; name: string } | null>(null) @@ -7,6 +8,16 @@ export const useAuth = defineStore("auth", () => { return { authenticatedUser, - requiredUser + requiredUser, + async fetchSelf() { + authenticatedUser.value = (await trpcClient.getSelf.query()).user + }, + async login(username: string) { + const { id } = await trpcClient.login.mutate({ name: username }) + authenticatedUser.value = { + id, + name: username + } + } } }) \ No newline at end of file diff --git a/src/clientGame.ts b/src/clientGame.ts index def0b49..6c903a5 100644 --- a/src/clientGame.ts +++ b/src/clientGame.ts @@ -1,9 +1,11 @@ import { defineStore } from "pinia" import { EventBusKey, useEventBus } from "@vueuse/core" -import type { GameAction } from "./shared/game/gameActions" -import { reactive, readonly, ref } from "vue" +import type { GameAction } from "./shared/game/actions" +import { computed, reactive, readonly, ref } from "vue" import { GameState, getUninitializedGameState, produceNewState } from "./shared/game/state" import { trpcClient } from "./trpc" +import { useAuth } from "./auth" +import { read } from "fs" const gameActionsBusKey = Symbol() as EventBusKey const useGameActionsBus = () => useEventBus(gameActionsBusKey) @@ -18,10 +20,12 @@ export const useGameActionNotification = (listener: (action: GameAction) => unkn } export const useGame = defineStore("game", () => { - const isActive = ref(false) + const lobbyCode = ref(null) const state = ref(getUninitializedGameState()) const actions = reactive([]) + const auth = useAuth() + const actionsBus = useGameActionsBus() actionsBus.on(action => { actions.push(action) @@ -30,18 +34,37 @@ export const useGame = defineStore("game", () => { }) return { - isActive: readonly(isActive), + lobbyCode: readonly(lobbyCode), + isActive: computed(() => lobbyCode.value !== null), + isOwnGame: computed(() => state.value.players.findIndex(p => p.id === (auth.authenticatedUser?.id ?? "")) === 0), state: readonly(state), actions: readonly(actions), join(code: string) { - trpcClient.join.subscribe({ code: "game" }, { - onData: actionsBus.emit + return new Promise((resolve, reject) => { + trpcClient.join.subscribe({ lobbyCode: code }, { + onStarted: () => { + lobbyCode.value = code + resolve() + }, + onData: event => { + switch (event.type) { + case "action": + actionsBus.emit(event.action) + break + } + }, + onError: error => { + console.error("🔴", error) + reject(error) + } + }) }) - - isActive.value = true }, - start: () => trpcClient.game.start.mutate(), - hit: () => trpcClient.game.hit.mutate(), - stay: () => trpcClient.game.stay.mutate() + async create() { + return await trpcClient.createGame.mutate() + }, + start: () => trpcClient.game.start.mutate({ lobbyCode: lobbyCode.value! }), + hit: () => trpcClient.game.hit.mutate({ lobbyCode: lobbyCode.value! }), + stay: () => trpcClient.game.stay.mutate({ lobbyCode: lobbyCode.value! }) } }) \ No newline at end of file diff --git a/src/components/GameEndModal.vue b/src/components/GameEndModal.vue index 5e13bea..9714a33 100644 --- a/src/components/GameEndModal.vue +++ b/src/components/GameEndModal.vue @@ -14,7 +14,7 @@ {{ getNumberCardsSum(singleWinner.numberCards) }} point{{ getNumberCardsSum(singleWinner.numberCards) === 1 ? "" : "s" }}. -