diff --git a/src/common/interfaces.ts b/src/common/interfaces.ts index ddbb441..ec7449a 100644 --- a/src/common/interfaces.ts +++ b/src/common/interfaces.ts @@ -38,6 +38,7 @@ export interface MatchSessionDto { matchWinner: PlayerDto | null matchInProgress: boolean playersReady: number + gameSummaries: GameSummary[] } export interface GameDto { @@ -115,4 +116,11 @@ export interface GameSummary { winner: PlayerDto score: { id: string; name: string; score: number }[] players?: PlayerDto[] + board: TileDto[] + boneyard: TileDto[] +} + +export interface Config { + waitMillisToShowSummary: number + activeHandStrokeColor: number } diff --git a/src/components/GameComponent.vue b/src/components/GameComponent.vue index de0d3f1..631d789 100644 --- a/src/components/GameComponent.vue +++ b/src/components/GameComponent.vue @@ -1,17 +1,21 @@ - - - - diff --git a/src/components/TheWelcome.vue b/src/components/TheWelcome.vue deleted file mode 100644 index 49d8f73..0000000 --- a/src/components/TheWelcome.vue +++ /dev/null @@ -1,88 +0,0 @@ - - - diff --git a/src/components/WelcomeItem.vue b/src/components/WelcomeItem.vue deleted file mode 100644 index 6d7086a..0000000 --- a/src/components/WelcomeItem.vue +++ /dev/null @@ -1,87 +0,0 @@ - - - diff --git a/src/game/Board.ts b/src/game/Board.ts index 9c6f6e2..59b8928 100644 --- a/src/game/Board.ts +++ b/src/game/Board.ts @@ -1,8 +1,8 @@ -import { Application, Assets, Container, EventEmitter, Sprite, Text, Ticker } from 'pixi.js' +import { Application, Container, EventEmitter, Text, Ticker } from 'pixi.js' import { Scale, type ScaleFunction } from '@/game/utilities/scale' import type { AnimationOptions, Movement, PlayerDto, TileDto } from '@/common/interfaces' import { Tile } from '@/game/Tile' -import { DIRECTIONS, createContainer, createCrosshair, isTilePair } from '@/common/helpers' +import { DIRECTIONS, createContainer, isTilePair } from '@/common/helpers' import { createText } from '@/game/utilities/fonts' import { LoggingService } from '@/services/LoggingService' import { GlowFilter } from 'pixi-filters' @@ -85,19 +85,12 @@ export class Board extends EventEmitter { visible: false, }) - createCrosshair(this.tilesContainer, 0xff0000, { - width: this.width, - height: this.height, - x: this.scaleX(0), - y: this.scaleY(0), - }) - - createCrosshair(this.interactionContainer, 0xffff00, { - width: this.width, - height: this.height, - x: this.scaleX(0), - y: this.scaleY(0), - }) + // createCrosshair(this.tilesContainer, 0xff0000, { + // width: this.width, + // height: this.height, + // x: this.scaleX(0), + // y: this.scaleY(0), + // }) this.textContainer = createContainer({ width: this.width, @@ -105,7 +98,7 @@ export class Board extends EventEmitter { parent: this.container, }) - this.showText(t('starting_game')) + this.showText(t('game.starting_game')) } private calculateScale() { @@ -144,11 +137,11 @@ export class Board extends EventEmitter { } async setPlayerTurn(player: PlayerDto) { - this.showText('Your turn!') + this.showText(t('game.your-turn')) } async setServerPlayerTurn(currentPlayer: PlayerDto) { - this.showText(`${currentPlayer.name}'s turn!\n Please wait...`) + this.showText(t('game.player-turn', [currentPlayer.name])) } async playerMove(move: any, playerId: string) { @@ -599,8 +592,7 @@ export class Board extends EventEmitter { return [canPlayNorth, canPlayEast, canPlaySouth, canPlayWest] } - gameFinished(data: any) { - const { lastGame, gameState } = data + clean() { this.tiles = [] this.boneyard = [] this.movements = [] @@ -614,10 +606,13 @@ export class Board extends EventEmitter { this.firstTile = undefined this.tilesContainer.removeChildren() this.interactionContainer.removeChildren() - this.showText(`Game finished \n Winner ${lastGame?.winner?.name ?? 'No winner'}`) } - matchFinished(data: any) { - // this.showText(`Game finished \n Winner ${lastGame?.winner?.name ?? 'No winner'}`) + gameFinished() { + this.showText(t('game.round-finished')) + } + + matchFinished() { + this.showText(t('game.match-finished')) } } diff --git a/src/game/Config.ts b/src/game/Config.ts new file mode 100644 index 0000000..5abb5bf --- /dev/null +++ b/src/game/Config.ts @@ -0,0 +1,8 @@ +import type { Config } from '@/common/interfaces' + +const config: Config = { + waitMillisToShowSummary: 1000, + activeHandStrokeColor: 0xb39c4d, +} + +export default config diff --git a/src/game/Game.ts b/src/game/Game.ts index a860ecf..482c000 100644 --- a/src/game/Game.ts +++ b/src/game/Game.ts @@ -1,4 +1,4 @@ -import { Application, Assets, Container, Sprite } from 'pixi.js' +import { Application, Assets, Container, EventEmitter, Sprite } from 'pixi.js' import { Board } from '@/game/Board' import { assets } from '@/game/utilities/assets' import { Tile } from '@/game/Tile' @@ -9,6 +9,7 @@ import { wait } from '@/common/helpers' import { Actions } from 'pixi-actions' import { OtherHand } from './OtherHand' import { GameSummayView } from './GameSummayView' +import Config from './Config' interface GameOptions { boardScale: number @@ -18,7 +19,7 @@ interface GameOptions { background: string } -export class Game { +export class Game extends EventEmitter { public board!: Board public hand!: Hand private app: Application = new Application() @@ -27,6 +28,7 @@ export class Game { private otherHands: OtherHand[] = [] private backgroundLayer: Container = new Container() private gameSummaryView!: GameSummayView + private players: PlayerDto[] = [] constructor( private options: GameOptions = { @@ -39,7 +41,9 @@ export class Game { private socketService: SocketIoClientService, private playerId: string, private sessionId: string, - ) {} + ) { + super() + } async setup(): Promise { const width = this.options.width || 1200 @@ -59,7 +63,8 @@ export class Game { new OtherHand(this.app, 'top'), new OtherHand(this.app, 'right'), ] - this.initOtherHands(players) + this.initPlayers(players) + this.players = players this.gameSummaryView = new GameSummayView(this.app) this.hand.scale = this.options.handScale this.board.scale = this.options.boardScale @@ -81,23 +86,23 @@ export class Game { this.backgroundLayer.addChild(background) } - initOtherHands(players: PlayerDto[]) { + initPlayers(players: PlayerDto[]) { const myIndex = players.findIndex((player) => player.id === this.playerId) const copy = [...players] const cut = copy.splice(myIndex) - cut.shift() + const player = cut.shift() const final = cut.concat(copy) for (let i = 0; i < final.length; i++) { const hand = this.otherHands[i] hand.setPlayer(final[i]) } + this.hand.setPlayer(player) this.board.otherPlayerHands = this.otherHands } - updateOtherHands(gameState: GameDto) { - const players = gameState.players + updateOtherHands(players: PlayerDto[]) { players.forEach((player) => { const hand = this.otherHands.find((hand) => hand.player?.id === player.id) if (hand) { @@ -115,6 +120,7 @@ export class Game { setPlayersInactive() { this.otherHands.forEach((hand) => hand.setActive(false)) + this.hand.setActive(false) } async preload() { @@ -148,7 +154,12 @@ export class Game { await this.board.updateBoard(move, undefined) }) + this.gameSummaryView.on('finishClick', (data) => { + this.emit('game:finish-click', data) + }) + this.gameSummaryView.on('nextClick', (data) => { + this.board.clean() this.updateScoreboard(data.sessionState) this.socketService.sendMessage('client:set-client-ready-for-next-game', { userId: this.playerId, @@ -161,11 +172,13 @@ export class Game { private updateScoreboard(sessionState: MatchSessionDto) { const scoreboard = sessionState.scoreboard - this.otherHands.forEach((hand) => { - const player: PlayerDto | undefined = hand.player + const myScore = scoreboard.find((d) => d.id === this.playerId)?.score || 0 + this.hand.setScore(myScore) + this.otherHands.forEach((otherHand) => { + const player: PlayerDto | undefined = otherHand.player const name: string = player?.name || '' const score = scoreboard.find((d) => d.name === name)?.score || 0 - hand.setScore(score) + otherHand.setScore(score) }) } @@ -198,6 +211,7 @@ export class Game { const currentPlayer = state?.currentPlayer! this.setPlayersInactive() if (currentPlayer.id === this.playerId) { + this.hand.setActive(true) this.hand.prepareForMove(this.board.count === 0, this.board.freeEnds) this.board.setPlayerTurn(currentPlayer) } else { @@ -248,15 +262,19 @@ export class Game { }) } - gameFinished(data: any) { + async gameFinished(data: any) { + await wait(Config.waitMillisToShowSummary) + this.updateOtherHands(data.lastGame.players) this.hand.gameFinished() - this.board.gameFinished(data) + this.board.gameFinished() + this.setPlayersInactive() this.gameSummaryView.setGameSummary(data, 'round') } - matchFinished(data: any) { - // this.hand.matchFinished() - this.board.matchFinished(data) + async matchFinished(data: any) { + await wait(Config.waitMillisToShowSummary) + this.updateOtherHands(data.lastGame.players) + this.board.matchFinished() this.gameSummaryView.setGameSummary(data, 'match') } diff --git a/src/game/GameSummayView.ts b/src/game/GameSummayView.ts index ad589ee..2771955 100644 --- a/src/game/GameSummayView.ts +++ b/src/game/GameSummayView.ts @@ -30,8 +30,6 @@ export class GameSummayView extends EventEmitter { height: this.height, parent: this.container, }) - console.log('GameSummaryView created!') - this.container.visible = false } @@ -67,7 +65,7 @@ export class GameSummayView extends EventEmitter { if (this.gameSummary.isBlocked) { line += 30 - this.container.addChild( + this.layer.addChild( createText({ text: '(Blocked)', x: this.width / 2, diff --git a/src/game/Hand.ts b/src/game/Hand.ts index d349d76..e995e8d 100644 --- a/src/game/Hand.ts +++ b/src/game/Hand.ts @@ -1,16 +1,19 @@ -import { Application, Container, EventEmitter, Sprite, Texture, Ticker } from 'pixi.js' +import { Application, Container, EventEmitter, Graphics, Sprite, Texture, Ticker } from 'pixi.js' import { Tile } from '@/game/Tile' import type { PlayerDto, TileDto } from '@/common/interfaces' import { GlowFilter } from 'pixi-filters' import { Scale, type ScaleFunction } from './utilities/scale' import { LoggingService } from '@/services/LoggingService' import { createButton, createContainer } from '@/common/helpers' -import { Action, Actions } from 'pixi-actions' +import { createText, playerNameText, whiteStyle } from './utilities/fonts' +import Config from '@/game/Config' export class Hand extends EventEmitter { tiles: Tile[] = [] container: Container = new Container() buttonPass: Container = new Container() + scoreLayer: Container = new Container() + activeLayer: Container = new Container() height: number width: number ticker: Ticker @@ -27,18 +30,22 @@ export class Hand extends EventEmitter { tilesLayer!: Container interactionsLayer!: Container score: number = 0 + active: boolean = false + private player!: PlayerDto constructor(app: Application) { super() app.stage.addChild(this.container) this.ticker = app.ticker this.height = 130 * this.scale - this.width = app.canvas.width + this.width = 800 // app.canvas.width this.container.y = app.canvas.height - this.height + this.container.x = app.canvas.width / 2 - this.width / 2 this.container.width = this.width this.container.height = this.height this.calculateScale() this.initLayers() + this.render() } initLayers() { @@ -58,12 +65,12 @@ export class Hand extends EventEmitter { y: 0, parent: this.container, }) + this.container.addChild(this.scoreLayer) + this.container.addChild(this.activeLayer) } gameFinished() { - this.logger.debug('gameFinished') this.tiles = [] - this.initialized = false } @@ -205,6 +212,22 @@ export class Hand extends EventEmitter { this.render() } + setPlayer(player: PlayerDto | undefined) { + if (!player) return + this.player = player + this.render() + } + + setScore(score: number) { + this.score = score + this.render() + } + + setActive(active: boolean) { + this.active = active + this.render() + } + private createTiles(playerState: PlayerDto) { return playerState.hand.map((tile: TileDto) => { const newTile: Tile = new Tile(tile.id, this.ticker, tile.pips, this.scale, tile.playerId) @@ -244,11 +267,38 @@ export class Hand extends EventEmitter { } renderScore() { - //this.scoreLayer.removeChildren() + this.scoreLayer.removeChildren() + const name = createText({ + text: this.player?.name ?? '-', + x: 100, + y: 50, + style: playerNameText, + }) + const text = createText({ + text: `${this.score}`, + x: 100, + // x: this.width - 5, + y: 80, + style: whiteStyle(36, 'bold'), + }) + text.anchor.set(1, 0.5) + this.scoreLayer.addChild(name) + this.scoreLayer.addChild(text) + } + + renderActive() { + this.activeLayer.removeChildren() + if (this.active) { + const rectangle = new Graphics() + .roundRect(0, 0, this.width, this.height - 1, 5) + .stroke(Config.activeHandStrokeColor) + this.activeLayer.addChild(rectangle) + } } render() { this.renderTiles() this.renderScore() + this.renderActive() } } diff --git a/src/game/OtherHand.ts b/src/game/OtherHand.ts index bde95f1..1921095 100644 --- a/src/game/OtherHand.ts +++ b/src/game/OtherHand.ts @@ -4,7 +4,8 @@ import { Scale, type ScaleFunction } from './utilities/scale' import { Tile } from './Tile' import type { Movement, PlayerDto, TileDto } from '@/common/interfaces' import { createContainer } from '@/common/helpers' -import { createText, playerNameText, scoreText } from './utilities/fonts' +import { createText, playerNameText, whiteStyle } from './utilities/fonts' +import Config from '@/game/Config' export class OtherHand { tilesInitialNumber: number = 7 @@ -62,10 +63,11 @@ export class OtherHand { setScore(score: number) { this.score = score + this.render() } setHand(tiles: TileDto[]) { - this.hand = tiles.map((tile) => new Tile(tile.id, this.app.ticker, undefined, this.scale)) + this.hand = tiles.map((tile) => new Tile(tile.id, this.app.ticker, tile.pips, this.scale)) this.render() } @@ -80,7 +82,7 @@ export class OtherHand { text: `${this.score}`, x: this.width - 5, y: 50, - style: scoreText, + style: whiteStyle(36, 'bold'), }) text.anchor.set(1, 0.5) this.scoreLayer.addChild(text) @@ -90,7 +92,7 @@ export class OtherHand { this.tilesLayer.removeChildren() const x = -9 this.hand.forEach((tile, index) => { - tile.setPosition(this.scaleX(x + index * 2), this.height / 2) + tile.setPosition(this.scaleX(x + index * 2), this.height / 2 + 10) this.tilesLayer.addChild(tile.getSprite()) }) } @@ -98,7 +100,9 @@ export class OtherHand { private renderActive() { this.interactionsLayer.removeChildren() if (this.active) { - const rectangle = new Graphics().roundRect(0, 0, this.width, this.height, 5).stroke(0xffff00) + const rectangle = new Graphics() + .roundRect(0, 0, this.width, this.height, 5) + .stroke(Config.activeHandStrokeColor) this.interactionsLayer.addChild(rectangle) } } diff --git a/src/i18n/en.json b/src/i18n/en.json new file mode 100644 index 0000000..3a8caa9 --- /dev/null +++ b/src/i18n/en.json @@ -0,0 +1,48 @@ +{ + "match-page": "Match Page", + "login": "Login", + "username": "Username", + "username-placeholder": "Username", + "password": "Password", + "password-placeholder": "Password", + "login-button": "Login", + "invalid-username-or-password": "Invalid username or password", + "winner": "Winner", + "points-to-win": "Points to win", + "final-scoreboard": "Final Scoreboard", + "round-index-1": "Round {0}", + "scoreboard": "Scoreboard", + "available-sessions": "Available Sessions", + "no-sessions-available": "No sessions available", + "id-session-_id": "ID: {0}", + "players-session-players-length": "Players: {0}", + "copy": "Copy", + "seed-session-seed": "Seed: {0}", + "status-session-status": "Status: {0}", + "delete": "Delete", + "join": "Join", + "welcome-to-the-user-username-s-home-page": "Welcome to the {0}'s Home Page", + "name": "Name", + "session-name-placeholder": "Session Name", + "seed": "Seed", + "seed-placeholder": "Type the session seed here!", + "background-color": "Background color", + "green-fabric": "Green Fabric", + "gray-fabric": "Gray Fabric", + "blue-fabric": "Blue Fabric", + "yellow-fabric": "Yellow Fabric", + "red-fabric": "Red Fabric", + "crossed-game-teamed": "Crossed game ({0})", + "create-match-session": "Create Match Session", + "ready": "Ready", + "unready": "Unready", + "start": "Start", + "cancel": "Cancel", + "game": { + "match-finished": "Match finished", + "round-finished": "Round finished", + "starting_game": "Starting game...", + "your-turn": "Your turn!", + "player-turn": "{0}'s turn!" + } +} diff --git a/src/i18n/en.ts b/src/i18n/en.ts deleted file mode 100644 index 38c0fb3..0000000 --- a/src/i18n/en.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const en = { - starting_game: 'Starting game...', -} diff --git a/src/i18n/es.json b/src/i18n/es.json new file mode 100644 index 0000000..9c79065 --- /dev/null +++ b/src/i18n/es.json @@ -0,0 +1,48 @@ +{ + "match-page": "Página de partido", + "login": "Acceso", + "username": "Nombre de usuario", + "username-placeholder": "Nombre de usuario", + "login-button": "Acceso", + "password": "Contraseña", + "password-placeholder": "Contraseña", + "invalid-username-or-password": "usuario o contraseña invalido", + "points-to-win": "Puntos para ganar", + "round-index-1": "Ronda {0}", + "scoreboard": "Marcador", + "winner": "Ganador", + "final-scoreboard": "Puntaje Final", + "id-session-_id": "ID: {0}", + "seed-placeholder": "¡Escriba la semilla de la sesión aquí!", + "session-name-placeholder": "Nombre de la sesión", + "status-session-status": "Estado: {0}", + "unready": "No preparado", + "welcome-to-the-user-username-s-home-page": "Bienvenido a la página de inicio de {0}", + "available-sessions": "Sesiones disponibles", + "background-color": "Color de fondo", + "blue-fabric": "Fabrica azul", + "cancel": "Cancelar", + "copy": "Copiar", + "game": { + "starting_game": "Iniciando la partida...", + "match-finished": "Partido terminado", + "player-turn": "¡Es el turno de {0}!", + "round-finished": "Ronda terminada", + "your-turn": "¡Tu turno!" + }, + "create-match-session": "Crear sesión de partido", + "crossed-game-teamed": "Juego cruzado ({0})", + "delete": "Borrar", + "gray-fabric": "Tela gris", + "green-fabric": "Tela verde", + "join": "Unirse", + "name": "Nombre", + "no-sessions-available": "No hay sesiones disponibles", + "players-session-players-length": "Jugadores: {0}", + "ready": "Listo", + "red-fabric": "Tela roja", + "seed": "Semilla", + "seed-session-seed": "Semilla: {0}", + "start": "Comenzar", + "yellow-fabric": "Tela amarilla" +} diff --git a/src/i18n/es.ts b/src/i18n/es.ts deleted file mode 100644 index 985c4e5..0000000 --- a/src/i18n/es.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const es = { - starting_game: 'Iniciando la partida...', -} diff --git a/src/i18n/index.ts b/src/i18n/index.ts index 0b3aac0..91bc6e3 100644 --- a/src/i18n/index.ts +++ b/src/i18n/index.ts @@ -1,8 +1,9 @@ import { createI18n } from 'vue-i18n' -import { en } from './en' -import { es } from './es' +import en from './en.json' +import es from './es.json' const i18n = createI18n({ + legacy: false, locale: 'es', messages: { en, @@ -10,9 +11,11 @@ const i18n = createI18n({ }, }) -const translate = (key: string) => { - return i18n.global.t(key) -} +// const translate = (key: string, context: any, plural: number = 1) => { +// return i18n.global.t(key, plural) +// } export default i18n -export { translate, translate as t } + +const { t } = i18n.global +export { t, t as $t } diff --git a/src/router/index.ts b/src/router/index.ts index 8a555c5..4e223a1 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -14,9 +14,9 @@ const router = createRouter({ { path: '', component: LandingView, - name: 'landing' - } - ] + name: 'landing', + }, + ], }, { path: '/home', @@ -27,10 +27,10 @@ const router = createRouter({ name: 'home', component: HomeView, meta: { - requiresAuth: true - } - } - ] + requiresAuth: true, + }, + }, + ], // route level code-splitting // this generates a separate chunk (About.[hash].js) for this route // which is lazy-loaded when the route is visited. @@ -45,13 +45,13 @@ const router = createRouter({ name: 'match', component: () => import('@/views/MatchView.vue'), meta: { - requiresAuth: true - } - } - ] + requiresAuth: true, + }, + }, + ], }, { - path: '/game', + path: '/game:id', component: AuthenticatedLayout, children: [ { @@ -59,12 +59,12 @@ const router = createRouter({ name: 'game', component: () => import('@/views/GameView.vue'), meta: { - requiresAuth: true - } - } - ] - } - ] + requiresAuth: true, + }, + }, + ], + }, + ], }) router.beforeEach((to, from, next) => { diff --git a/src/services/GameService.ts b/src/services/GameService.ts index 0170428..b335451 100644 --- a/src/services/GameService.ts +++ b/src/services/GameService.ts @@ -4,11 +4,11 @@ import { ServiceBase } from './ServiceBase' export class GameService extends ServiceBase { private networkService = new NetworkService() - async createMatchSession(sessionName: string, seed: string) { + async createMatchSession(sessionName: string, seed: string, options: any) { const response = await this.networkService.post({ uri: '/game/match', - body: { sessionName, seed }, - auth: true + body: { sessionName, seed, options }, + auth: true, }) const { sessionId } = response return sessionId @@ -17,7 +17,7 @@ export class GameService extends ServiceBase { async cancelMatchSession(sessionId: string) { const response = await this.networkService.delete({ uri: `/game/match/${sessionId}`, - auth: true + auth: true, }) return response } @@ -25,7 +25,7 @@ export class GameService extends ServiceBase { async joinMatchSession(sessionId: string) { const response = await this.networkService.put({ uri: `/game/match/${sessionId}`, - auth: true + auth: true, }) return response } @@ -33,7 +33,7 @@ export class GameService extends ServiceBase { async listMatchSessions() { const response = await this.networkService.get({ uri: '/game/match', - auth: true + auth: true, }) return response } @@ -41,7 +41,7 @@ export class GameService extends ServiceBase { async getMatchSession(sessionId: string) { const response = await this.networkService.get({ uri: `/game/match/${sessionId}`, - auth: true + auth: true, }) return response } diff --git a/src/services/LoggingService.ts b/src/services/LoggingService.ts index acb6d9e..9c6fd7f 100644 --- a/src/services/LoggingService.ts +++ b/src/services/LoggingService.ts @@ -1,4 +1,4 @@ -import { createColors } from 'colorette' +import { createColors, gray, redBright, yellow } from 'colorette' import dayjs from 'dayjs' import pino, { type BaseLogger } from 'pino' import { isProxy, toRaw } from 'vue' @@ -11,7 +11,7 @@ export class LoggingService { constructor() { this._logger = pino({ browser: { - asObject: true, + asObject: false, transmit: { level: import.meta.env.VITE_LOG_LEVEL || 'error', send: (level, logEvent) => { @@ -31,14 +31,14 @@ export class LoggingService { if (messages.length > 0) { console.log( `${logStr.join(' ')}:`, - ...messages.filter((m) => m !== undefined && m !== null) + ...messages.filter((m) => m !== undefined && m !== null), ) } else { console.log(logStr.join(' ')) } - } - } - } + }, + }, + }, }) } @@ -46,7 +46,10 @@ export class LoggingService { return { info: green, debug: blue, - error: red + error: red, + trace: gray, + warn: yellow, + fatal: redBright, } } @@ -55,11 +58,11 @@ export class LoggingService { } info(message: string, data?: any) { - this._logger.info(this._getMessageWidthObject(message, data)) + this._logger.info(message, data) } warn(message: string, data?: any) { - this._logger.warn(this._getMessageWidthObject(message, data)) + this._logger.warn(message, data) } error(error: any, message?: string) { @@ -67,11 +70,11 @@ export class LoggingService { } fatal(message: string, data?: any) { - this._logger.fatal(this._getMessageWidthObject(message, data)) + this._logger.fatal(message, data) } trace(message: string, data?: any) { - this._logger.trace(this._getMessageWidthObject(message, data)) + this._logger.trace(message, data) } object(message: any) { diff --git a/src/services/SocketIoClientService.ts b/src/services/SocketIoClientService.ts index d7c29dd..38fc557 100644 --- a/src/services/SocketIoClientService.ts +++ b/src/services/SocketIoClientService.ts @@ -28,9 +28,9 @@ export class SocketIoClientService extends ServiceBase { }) this.socket.on('connect', () => { if (this.socket && this.socket.recovered) { - console.log('socket recovered succesfully') + this.logger.debug('SOCKET: socket recovered succesfully') } else { - console.log('socket connected') + this.logger.debug('SOCKET: socket connected') } this.isConnected = true this.addEvents() @@ -42,21 +42,20 @@ export class SocketIoClientService extends ServiceBase { addEvents(): void { this.socket.on('disconnect', () => { this.isConnected = false - console.log('Disconnected from server') + console.log('SOCKET: Disconnected from server') }) this.socket.on('reconnect', () => { this.isConnected = true - console.log('Reconnected to server') + this.logger.debug('SOCKET: Reconnected to server') }) this.socket.on('reconnect_error', () => { this.isConnected = false - console.log('Failed to reconnect to server') + this.logger.debug('SOCKET: Failed to reconnect to server') }) this.socket.on('ping', () => { - console.log('Ping received from server') this.socket.emit('pong') // Send pong response }) @@ -73,7 +72,7 @@ export class SocketIoClientService extends ServiceBase { this.socket.onAny((eventName, eventData) => { if (eventName === 'server:game-event' || eventName === 'server:game-event-ack') { const { event, data } = eventData - this.logger.debug(`Received event: ${event}`, data) + this.logger.trace(`SOCKET: Received event: ${event}`, data) } }) } @@ -81,24 +80,24 @@ export class SocketIoClientService extends ServiceBase { sendMessage(event: string, data: any): void { if (this.isConnected) { this.socket?.emit('client:event', { event, data }) - console.log('sendMessage :>> ', event, data) + this.logger.trace(`SOCKET: sendMessage :>> ${event}`, data) } else { - console.log('Not connected to server') + this.logger.trace('Not connected to server') } } async sendMessageWithAck(event: string, data: any): Promise { if (this.isConnected) { - console.log('sendMessageWithAck :>> ', event, data) + this.logger.trace(`SOCKET: sendMessageWithAck :>> ${event}}`, data) return await this.socket?.emitWithAck('client:event-with-ack', { event, data }) } else { - console.log('Not connected to server') + this.logger.trace('SOCKET: Not connected to server') } } disconnect(): void { this.socket?.disconnect() this.isConnected = false - console.log('Disconnected from server') + this.logger.debug('SOCKET: Disconnected from server') } } diff --git a/src/services/socket.ts b/src/services/socket.ts index 4e5ef49..e0cba3e 100644 --- a/src/services/socket.ts +++ b/src/services/socket.ts @@ -12,16 +12,16 @@ const ioOpts = { reconnectionDelay: 1000, // Time between each attempt (in ms) reconnectionDelayMax: 5000, // Maximum time between attempts (in ms) randomizationFactor: 0.5, // Randomization factor for the delay - timeout: 20000 // Connection timeout (in ms) + timeout: 20000, // Connection timeout (in ms) } // const socket = URL === undefined ? io(ioOpts) : io(URL, ioOpts) const socket = io('http://localhost:3000', ioOpts) socket.on('connect', () => { if (socket.recovered) { - console.log('socket recovered succesfully') + console.log('SOCKET: socket recovered succesfully') } else { - console.log('socket connected') + console.log('SOCKET: socket connected') } // setTimeout(() => { @@ -42,5 +42,5 @@ export default { }, disconnect() { socket.disconnect() - } + }, } diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue index 000664e..97ce5e2 100644 --- a/src/views/HomeView.vue +++ b/src/views/HomeView.vue @@ -28,9 +28,11 @@ const socketService: any = inject('socket') const gameService: GameService = inject('game') as GameService const logger: LoggingService = inject('logger') as LoggingService -const { sessionState, isSessionStarted, playerState, amIHost } = storeToRefs(gameStore) +const { sessionState, isSessionStarted, playerState, amIHost, readyForStart } = + storeToRefs(gameStore) const { user } = storeToRefs(auth) const { gameOptions } = storeToRefs(gameOptionsStore) +const { updateSessionState, updatePlayerState, updateGameState } = gameStore // function setPlayerReady() { // logger.debug('Starting game') @@ -57,11 +59,60 @@ async function createMatch() { logger.debug('Creating match') await socketService.connect() gameOptions.value = { background: background.value } - const id = await gameService.createMatchSession(sessionName.value, seed.value) + const sessionOptions = { + pointsToWin: pointsToWin.value, + } + const id = await gameService.createMatchSession(sessionName.value, seed.value, sessionOptions) logger.debug('Match created successfully') - router.push({ name: 'match', params: { id } }) + // router.push({ name: 'match', params: { id } }) } +async function setPlayerReady() { + logger.debug('Starting game') + if (!sessionState.value) { + logger.error('No session found') + return + } + if (!playerState.value) { + logger.error('No player found') + return + } + await socketService.sendMessage('client:set-player-ready', { + userId: playerState.value.id, + sessionId: sessionState.value.id, + }) +} + +async function startMatch() { + const sessionId = sessionState?.value?.id + const playerId = playerState?.value?.id + if (sessionId) { + await socketService.sendMessageWithAck('client:start-session', { + sessionId: sessionId, + playerId: playerId, + }) + } +} + +async function cancelMatch() { + logger.debug('Cancelling match') + if (sessionState?.value?.id) { + await gameService.cancelMatchSession(sessionState?.value?.id) + updateSessionState(undefined) + updatePlayerState(undefined) + updateGameState(undefined) + + logger.debug('Match cancelled successfully') + router.push({ name: 'home' }) + } +} + +eventBus.subscribe('server:match-starting', (data) => { + const session = data.sessionState as MatchSessionDto + updateSessionState(session) + router.push({ name: 'game', params: { id: session.id } }) +}) + async function joinMatch(id: string) { if (id) { await socketService.connect() @@ -80,7 +131,7 @@ async function deleteMatch(id: string) { async function loadData() { const listResponse = await gameService.listMatchSessions() matchSessions.value = listResponse.data - sessionName.value = `Test #${listResponse.pagination.total + 1}` + sessionName.value = `Test #${Date.now()}` } onMounted(() => { @@ -99,41 +150,47 @@ function copy(sessionSeed: string) {