Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Join a game #38

Merged
merged 4 commits into from
Dec 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode
12 changes: 12 additions & 0 deletions client/src/components/PlayerBox/PlayerBox.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@import 'styles/variables';

$background-color: rgb(37, 153, 138);

.PlayerBox {
border: 2px solid black;
background-color: $background-color;
color: white;
padding: 1rem;
margin: 1rem;
min-width: 10rem;
}
23 changes: 23 additions & 0 deletions client/src/components/PlayerBox/PlayerBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { FC } from 'react'

import './PlayerBox.scss'

export interface PlayerProps {
name: string
isHost?: boolean
isSelf?: boolean
}

const Player: FC<PlayerProps> = props => {
return (
<div className='PlayerBox'>
<div>
<h3>{props.name}</h3>
</div>
{props.isHost && <h4>Host</h4>}
ThunderDev1 marked this conversation as resolved.
Show resolved Hide resolved
{props.isSelf && '(this is you)'}
</div>
)
}

export default Player
2 changes: 2 additions & 0 deletions client/src/components/PlayerBox/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './PlayerBox'
export { default } from './PlayerBox'
11 changes: 5 additions & 6 deletions client/src/pages/Index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { FC } from 'react'
import axios from 'axios'
import axios, { AxiosResponse } from 'axios'
import { RouteComponentProps, navigate } from '@reach/router'

import Button from '../components/Button'
Expand All @@ -9,11 +9,10 @@ import { Game } from '../types/Game'
export interface IndexProps extends RouteComponentProps {}

const Index: FC<IndexProps> = () => {
const createGame = () => {
axios.post('/games').then(response => {
const game = response.data as Game
navigate(`/lobby/${game.id}`)
})
const createGame = async () => {
const postGameResponse: AxiosResponse<Game> = await axios.post(`/games`)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, can we also provide an error type ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No specific errors to catch here, maybe inside a global error handler.

const game = postGameResponse.data
navigate(`/lobby/${game.id}`)
}

return (
Expand Down
2 changes: 1 addition & 1 deletion client/src/pages/Lobby/Lobby.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ $background-color: #f8de96;
.Players {
margin-top: 1rem;
display: flex;
justify-content: space-evenly;
justify-content: flex-start;
flex-wrap: wrap;
.Player {
display: flex;
Expand Down
60 changes: 39 additions & 21 deletions client/src/pages/Lobby/Lobby.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,67 @@
import React, { FC, useEffect, useState } from 'react'
import axios from 'axios'
import axios, { AxiosResponse } from 'axios'
import { RouteComponentProps } from '@reach/router'
import { Game } from '../../types/Game'
import * as moment from 'moment'

import connectToGameHub from '../../utils/signalrConnector'

import './Lobby.scss'
import PlayerBox from '../../components/PlayerBox'

export interface LobbyProps extends RouteComponentProps {
id?: string
}

const Lobby: FC<LobbyProps> = (props: LobbyProps) => {
const [game, setGame] = useState<Game>()

const [currentPlayerId, setCurrentPlayerId] = useState<string>()

useEffect(() => {
ThunderDev1 marked this conversation as resolved.
Show resolved Hide resolved
axios.get(`/games/${props.id}`).then(response => {
setGame(response.data as Game)
})
}, [props.id])
const loadGame = async () => {
const getGameResponse: AxiosResponse<Game> = await axios.get(
`/games/${props.id}`
)
return getGameResponse.data
}
const onLoad = async () => {
var game = await loadGame()
setGame(game)

const getHostName = (game: Game) => {
const host = game.players.find(player => player.id === game.hostId)
return host ? host.name : 'host unknown'
}
if (game.status === 'PENDING_START') {
const hubConnection = connectToGameHub(game.id)
hubConnection.start().then(() => {
hubConnection.connectionId &&
setCurrentPlayerId(hubConnection.connectionId)
})
hubConnection.on('refreshGame', () => {
loadGame().then(game => setGame(game))
})
}
}

onLoad()
}, [props.id])

const getSubtitle = (game: Game) => {
return `Créé par ${getHostName(game)} ${moment
.utc(game.creationDate)
.fromNow()}`
// The oldest member of the lobby is the host
const isGameHost = (game: Game, playerId: string | undefined) => {
return game.players && game.players[0].id === playerId
}

return (
<div className='Lobby'>
{game && (
<>
<h1>Details de la partie ({game.id})</h1>
<h2>{getSubtitle(game)}</h2>
<h3>Statut {game.status}</h3>
<br></br>
<h4>Joueurs</h4>
<h2>{`Créé ${moment.utc(game.creationDate).fromNow()}`}</h2>
<div className='Players'>
{game.players.map(player => (
<div className='Player' title={player.id} key={player.id}>
{player.name}
</div>
<PlayerBox
ThunderDev1 marked this conversation as resolved.
Show resolved Hide resolved
key={player.id}
name={player.name}
isSelf={currentPlayerId === player.id || false}
isHost={isGameHost(game, player.id)}
/>
))}
</div>
</>
Expand Down
19 changes: 19 additions & 0 deletions client/src/utils/signalrConnector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as SignalR from '@microsoft/signalr'
import { HubConnection } from '@microsoft/signalr'

const API_URL: string = 'https://localhost:5001'

const connectToGameHub = (
gameId: number,
onStart: any = null
): HubConnection => {
const connection = new SignalR.HubConnectionBuilder()
.withUrl(`${API_URL}/gameHub?gameId=${gameId}`)
.withAutomaticReconnect()
.configureLogging(SignalR.LogLevel.Debug)
.build()

return connection
}

export default connectToGameHub
1 change: 0 additions & 1 deletion server/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
*.user
*.userosscache
*.sln.docstates
.vscode

# Build results
[Dd]ebug/
Expand Down
2 changes: 1 addition & 1 deletion server/DTO/GameDTOs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public GameDTO(Game game)
hostId = game.HostId;
status = game.Status.ToString();
creationDate = game.CreationDate.ToString("o", CultureInfo.InvariantCulture);
players = game.Players.Select(p => new PlayerDTO(p)).ToArray();
players = game.Players.OrderBy(p => p.CreationDate).Select(player => new PlayerDTO(player)).ToArray();
}
public int id { get; set; }
public string hostId { get; set; }
Expand Down
50 changes: 0 additions & 50 deletions server/Data/random-names.txt

This file was deleted.

50 changes: 50 additions & 0 deletions server/Data/video-game-characters.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Ryu Hayabusa
Dirk The Daring
Donkey Kong
The Horned Reaper
Vault Boy
Marcus Fenix
Leon Kennedy
HK-47
Sam & Max
Pyramid Head
Dr Fred Eddison
Mr. X
Dante
Pac Man
Big Daddy
Prince of Persia
Alucard
The Announcer
Miner Willy
Kane
Manny Cavalera
Garrett
Harman Smith
Ryu
Samus Aran
Arthas Menethil
Sabre Man
Bowser
Nathan Drake
Agent 47
Duke Nukem
ThunderDev1 marked this conversation as resolved.
Show resolved Hide resolved
Solid Snake
American McGee's Alice
Illidan Stormrage
Brucie
Kratos
Sonic
Cloud Strife
GLaDOS
Minsc & Boo
Sephiroth
The Lemmings
Master Chief
Guybrush Threepwood
Link
Lara Croft
The Nameless One
Shodan
Mario
Gordon Freeman
58 changes: 53 additions & 5 deletions server/Hubs/GameHub.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,61 @@
using Api.DTO;
using Api.Services;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Api.Hubs
{
public class GameHub : Hub
public class GameHub : Hub
{
private readonly IGameService _gameService;

public GameHub(IGameService gameService)
{
_gameService = gameService;
}

private string GetPlayerId()
{
return Context.ConnectionId;
}

private int GetGameId()
{
public async Task SendMessage()
{
await Clients.All.SendAsync("ReceiveMessage");
}
int gameId = 0;
if (!int.TryParse(Context.GetHttpContext().Request.Query["gameId"], out gameId))
throw new InvalidOperationException("Game id is missing from query string");

return gameId;
}

public override Task OnConnectedAsync()
{
string playerId = GetPlayerId();
int gameId = GetGameId();
string groupName = "game-" + gameId;

_gameService.AddPlayer(gameId, playerId);

Groups.AddToGroupAsync(Context.ConnectionId, groupName);
Clients.Group(groupName).SendAsync("refreshGame");

return base.OnConnectedAsync();
}
public override Task OnDisconnectedAsync(Exception exception)
{
string playerId = GetPlayerId();
int gameId = GetGameId();
string groupName = "game-" + gameId;

Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
_gameService.RemovePlayer(playerId);

Clients.Group(groupName).SendAsync("refreshGame");

return base.OnDisconnectedAsync(exception);
}
}
}
Loading