Adding a simple README
This commit is contained in:
17
server/TODO.org
Normal file
17
server/TODO.org
Normal file
@@ -0,0 +1,17 @@
|
||||
* TODO Implementa il muto/audio on
|
||||
* TODO Implementa il video on/off
|
||||
|
||||
* TODO Stilizza i video
|
||||
* TODO Stilizza i player offline
|
||||
|
||||
* TODO Controlla il bug quando sballi in presenza di matta
|
||||
* TODO ridisegnare i game controls in un drawer
|
||||
* TODO Investigate current player hand and prompt (move it to the context)
|
||||
* TODO Implementare il full-screen (non funziona!)
|
||||
|
||||
* DONE Controlla meglio che i conti tornino sempre!
|
||||
* DONE disegnare la :currentBet:
|
||||
* DONE marcare il dealer
|
||||
* DONE evidenziare il giocatore di turno
|
||||
* DONE Brucia i quattro!
|
||||
* DONE Integra la videochat
|
||||
100
server/games/banco.ts
Normal file
100
server/games/banco.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { BaseGameType, CardName, ICard, PlayingCard, RankSet, Suit } from 'typedeck';
|
||||
|
||||
enum SemeNapoletano {
|
||||
Bastoni, // Suit.Clubs
|
||||
Spade, // Suit.Spades
|
||||
Coppe, // Suit.Diamonds
|
||||
Denari // Suit.Hearts
|
||||
};
|
||||
|
||||
export class CartaNapoletana extends PlayingCard {
|
||||
public toString(): string {
|
||||
return `${CardName[this.cardName]} of ${SemeNapoletano[this.suit]}`;
|
||||
}
|
||||
}
|
||||
|
||||
class NapoliGameType extends BaseGameType {
|
||||
public cardsAllowed: ICard[] = [
|
||||
new CartaNapoletana(CardName.Ace, Suit.Clubs),
|
||||
new CartaNapoletana(CardName.Two, Suit.Clubs),
|
||||
new CartaNapoletana(CardName.Three, Suit.Clubs),
|
||||
new CartaNapoletana(CardName.Four, Suit.Clubs),
|
||||
new CartaNapoletana(CardName.Five, Suit.Clubs),
|
||||
new CartaNapoletana(CardName.Six, Suit.Clubs),
|
||||
new CartaNapoletana(CardName.Seven, Suit.Clubs),
|
||||
new CartaNapoletana(CardName.Eight, Suit.Clubs),
|
||||
new CartaNapoletana(CardName.Nine, Suit.Clubs),
|
||||
new CartaNapoletana(CardName.Ten, Suit.Clubs),
|
||||
|
||||
new CartaNapoletana(CardName.Ace, Suit.Diamonds),
|
||||
new CartaNapoletana(CardName.Two, Suit.Diamonds),
|
||||
new CartaNapoletana(CardName.Three, Suit.Diamonds),
|
||||
new CartaNapoletana(CardName.Four, Suit.Diamonds),
|
||||
new CartaNapoletana(CardName.Five, Suit.Diamonds),
|
||||
new CartaNapoletana(CardName.Six, Suit.Diamonds),
|
||||
new CartaNapoletana(CardName.Seven, Suit.Diamonds),
|
||||
new CartaNapoletana(CardName.Eight, Suit.Diamonds),
|
||||
new CartaNapoletana(CardName.Nine, Suit.Diamonds),
|
||||
new CartaNapoletana(CardName.Ten, Suit.Diamonds),
|
||||
|
||||
new CartaNapoletana(CardName.Ace, Suit.Spades),
|
||||
new CartaNapoletana(CardName.Two, Suit.Spades),
|
||||
new CartaNapoletana(CardName.Three, Suit.Spades),
|
||||
new CartaNapoletana(CardName.Four, Suit.Spades),
|
||||
new CartaNapoletana(CardName.Five, Suit.Spades),
|
||||
new CartaNapoletana(CardName.Six, Suit.Spades),
|
||||
new CartaNapoletana(CardName.Seven, Suit.Spades),
|
||||
new CartaNapoletana(CardName.Eight, Suit.Spades),
|
||||
new CartaNapoletana(CardName.Nine, Suit.Spades),
|
||||
new CartaNapoletana(CardName.Ten, Suit.Spades),
|
||||
|
||||
new CartaNapoletana(CardName.Ace, Suit.Hearts),
|
||||
new CartaNapoletana(CardName.Two, Suit.Hearts),
|
||||
new CartaNapoletana(CardName.Three, Suit.Hearts),
|
||||
new CartaNapoletana(CardName.Four, Suit.Hearts),
|
||||
new CartaNapoletana(CardName.Five, Suit.Hearts),
|
||||
new CartaNapoletana(CardName.Six, Suit.Hearts),
|
||||
new CartaNapoletana(CardName.Seven, Suit.Hearts),
|
||||
new CartaNapoletana(CardName.Eight, Suit.Hearts),
|
||||
new CartaNapoletana(CardName.Nine, Suit.Hearts),
|
||||
new CartaNapoletana(CardName.Ten, Suit.Hearts)
|
||||
];
|
||||
}
|
||||
|
||||
class BancoRankSet extends RankSet {
|
||||
public rankSet: CardName[] = [
|
||||
CardName.Ace,
|
||||
CardName.Two,
|
||||
CardName.Three,
|
||||
CardName.Four,
|
||||
CardName.Five,
|
||||
CardName.Six,
|
||||
CardName.Seven,
|
||||
CardName.Eight,
|
||||
CardName.Nine,
|
||||
CardName.Ten
|
||||
];
|
||||
}
|
||||
|
||||
export class BancoGameType extends NapoliGameType {
|
||||
public rankSet = new BancoRankSet();
|
||||
}
|
||||
|
||||
class SettemmezzoRankSet extends RankSet {
|
||||
public rankSet: CardName[] = [
|
||||
CardName.Eight,
|
||||
CardName.Nine,
|
||||
CardName.Ten,
|
||||
CardName.Ace,
|
||||
CardName.Two,
|
||||
CardName.Three,
|
||||
CardName.Four,
|
||||
CardName.Five,
|
||||
CardName.Six,
|
||||
CardName.Seven
|
||||
];
|
||||
}
|
||||
|
||||
export class SettemmezzoGameType extends NapoliGameType {
|
||||
public rankSet = new SettemmezzoRankSet();
|
||||
}
|
||||
159
server/games/state.ts
Normal file
159
server/games/state.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import { Client } from 'colyseus';
|
||||
import { type, filter, ArraySchema, Schema, MapSchema } from '@colyseus/schema';
|
||||
|
||||
|
||||
export class CardValue extends Schema {
|
||||
@type('uint8')
|
||||
value: number;
|
||||
|
||||
@type('uint8')
|
||||
suit: number;
|
||||
}
|
||||
|
||||
export class SerializedCard extends Schema {
|
||||
@type('string')
|
||||
owner: string;
|
||||
|
||||
@type('boolean')
|
||||
public: boolean;
|
||||
|
||||
@type(CardValue)
|
||||
card: CardValue;
|
||||
}
|
||||
|
||||
export class CardPlaceholder extends Schema {
|
||||
@filter(function (
|
||||
this: CardPlaceholder,
|
||||
client: Client,
|
||||
value: SerializedCard,
|
||||
root: Schema) {
|
||||
return value.public || value.owner === client.sessionId;
|
||||
})
|
||||
@type(SerializedCard)
|
||||
card: SerializedCard;
|
||||
}
|
||||
|
||||
export class PromptField extends Schema {
|
||||
@type('string')
|
||||
type: string;
|
||||
|
||||
@type('string')
|
||||
name: string;
|
||||
|
||||
@type('string')
|
||||
label: string;
|
||||
|
||||
@type('int32')
|
||||
min: string;
|
||||
|
||||
@type('int32')
|
||||
max: string;
|
||||
}
|
||||
|
||||
export class PromptButton extends Schema {
|
||||
@type('string')
|
||||
name: string;
|
||||
|
||||
@type('string')
|
||||
label: string;
|
||||
|
||||
@type('string')
|
||||
type: string;
|
||||
}
|
||||
|
||||
export class Prompt extends Schema {
|
||||
@type('boolean')
|
||||
visible: boolean;
|
||||
|
||||
@type([PromptField])
|
||||
fields = new ArraySchema<PromptField>();
|
||||
|
||||
@type([PromptButton])
|
||||
buttons = new ArraySchema<PromptButton>();
|
||||
}
|
||||
|
||||
export class Player extends Schema {
|
||||
@type('string')
|
||||
id: string;
|
||||
|
||||
@type('string')
|
||||
sessionId: string;
|
||||
|
||||
@type('string')
|
||||
displayName: string;
|
||||
|
||||
@type('boolean')
|
||||
owner: boolean;
|
||||
|
||||
@type('int32')
|
||||
stash: number = 60;
|
||||
|
||||
@type('int32')
|
||||
bet: number = 0;
|
||||
|
||||
@type('boolean')
|
||||
connected: boolean;
|
||||
|
||||
@type('boolean')
|
||||
playing: boolean;
|
||||
|
||||
@type('boolean')
|
||||
enteringNextTurn: boolean;
|
||||
|
||||
@type('uint8')
|
||||
seat: number;
|
||||
|
||||
@type('boolean')
|
||||
dealer: boolean;
|
||||
|
||||
@type([CardPlaceholder])
|
||||
hand = new ArraySchema<CardPlaceholder>();
|
||||
|
||||
@type(Prompt)
|
||||
prompt: Prompt;
|
||||
|
||||
@filter(function (
|
||||
this: Player,
|
||||
client: Client,
|
||||
value: string,
|
||||
root: Schema) {
|
||||
return this.sessionId === client.sessionId;
|
||||
})
|
||||
@type('number')
|
||||
score: number = 0;
|
||||
}
|
||||
|
||||
export class GameState extends Schema {
|
||||
@type('boolean')
|
||||
running: boolean = false;
|
||||
|
||||
@type('boolean')
|
||||
paused: boolean = false;
|
||||
|
||||
@type('int32')
|
||||
pot: number = 0;
|
||||
|
||||
@type('int32')
|
||||
minimumBet: number = 10;
|
||||
|
||||
@type({ map: Player })
|
||||
players = new MapSchema<Player>();
|
||||
|
||||
@type('number')
|
||||
bg: number = 1;
|
||||
|
||||
@type('string')
|
||||
roomOwner: string;
|
||||
|
||||
@type(Player)
|
||||
player1: Player;
|
||||
|
||||
@type(Player)
|
||||
player2: Player;
|
||||
|
||||
@type('number')
|
||||
currentBet: number = 0;
|
||||
|
||||
@type('number')
|
||||
remainingCards: number;
|
||||
}
|
||||
32
server/package.json
Normal file
32
server/package.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "games-party",
|
||||
"version": "1.0.0",
|
||||
"description": "A WebRTC playroom",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"devel": "nodemon server.ts"
|
||||
},
|
||||
"author": "Domenico Testa",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@colyseus/command": "^0.1.6",
|
||||
"@types/express": "^4.17.9",
|
||||
"@types/express-session": "^1.17.3",
|
||||
"@types/jest": "^26.0.19",
|
||||
"@types/node": "^14.14.19",
|
||||
"colyseus": "^0.14.6",
|
||||
"ejs": "^3.1.5",
|
||||
"express": "^4.17.1",
|
||||
"express-session": "^1.17.1",
|
||||
"nanoevents": "^5.1.10",
|
||||
"peer": "^0.6.1",
|
||||
"socket.io": "^3.0.4",
|
||||
"ts-node": "^9.1.1",
|
||||
"typedeck": "^1.5.2",
|
||||
"typescript": "^4.1.3",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"nodemon": "^2.0.6"
|
||||
}
|
||||
}
|
||||
74
server/public/app.js
Normal file
74
server/public/app.js
Normal file
@@ -0,0 +1,74 @@
|
||||
const socket = io('/')
|
||||
const videoGrid = document.getElementById('video-grid')
|
||||
const myPeer = new Peer(undefined, {
|
||||
host: location.hostname,
|
||||
path: '/peerjs/domingo'
|
||||
})
|
||||
|
||||
|
||||
const myVideo = document.createElement('video')
|
||||
myVideo.muted = true
|
||||
myVideo.setAttribute("playsinline", true);
|
||||
|
||||
const peers = {}
|
||||
|
||||
var facingMode = "user";
|
||||
|
||||
navigator.mediaDevices.getUserMedia({
|
||||
video: {
|
||||
facingMode: facingMode
|
||||
},
|
||||
audio: true // TODO: set to true
|
||||
}).then(stream => {
|
||||
addVideoStream(myVideo, stream)
|
||||
|
||||
myPeer.on('call', call => {
|
||||
call.answer(stream)
|
||||
|
||||
const video = document.createElement('video')
|
||||
video.setAttribute("playsinline", true);
|
||||
call.on('stream', userVideoStream => {
|
||||
addVideoStream(video, userVideoStream)
|
||||
})
|
||||
})
|
||||
|
||||
socket.on('user-connected', userId => {
|
||||
connectToNewUser(userId, stream)
|
||||
})
|
||||
})
|
||||
|
||||
socket.on('user-disconnected', userId => {
|
||||
console.log("User disconnected: ", userId)
|
||||
if (peers[userId]) peers[userId].close()
|
||||
})
|
||||
|
||||
myPeer.on('open', id => {
|
||||
socket.emit('join-room', ROOM_ID, id)
|
||||
})
|
||||
|
||||
socket.on('user-connected', userId => {
|
||||
console.log('User connected: ', userId)
|
||||
})
|
||||
|
||||
function addVideoStream(video, stream) {
|
||||
video.srcObject = stream
|
||||
video.addEventListener('loadedmetadata', () => {
|
||||
video.play()
|
||||
})
|
||||
videoGrid.append(video)
|
||||
}
|
||||
|
||||
function connectToNewUser(userId, stream) {
|
||||
const call = myPeer.call(userId, stream)
|
||||
const video = document.createElement('video')
|
||||
video.setAttribute("playsinline", true);
|
||||
call.on('stream', userVideoStream => {
|
||||
addVideoStream(video, userVideoStream)
|
||||
})
|
||||
|
||||
call.on('close', () => {
|
||||
video.remove()
|
||||
})
|
||||
|
||||
peers[userId] = call
|
||||
}
|
||||
91
server/rooms/commands/admin.ts
Normal file
91
server/rooms/commands/admin.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { Client } from 'colyseus';
|
||||
import { Command } from '@colyseus/command';
|
||||
import { GameState } from '../../games/state';
|
||||
import { GameRoom } from '../game';
|
||||
|
||||
|
||||
export class SetUserStashCommand extends Command<GameState, { client: Client, sessionId: string, amount: number }> {
|
||||
execute({ client, sessionId, amount }) {
|
||||
this.state.players[sessionId].stash = amount;
|
||||
const admin = this.state.players.get(client.sessionId);
|
||||
const targetClient = this.room.clients.find((client) => { return client.sessionId === sessionId });
|
||||
targetClient.send('notification', { text: `${admin.displayName} ha impostato il tuo stash a ${amount}`, type: 'success' });
|
||||
}
|
||||
}
|
||||
|
||||
export class AddToUserStashCommand extends Command<GameState, { client: Client, sessionId: string, amount: number }> {
|
||||
execute({ client, sessionId, amount }) {
|
||||
console.log('add-to-user-stash', client, sessionId, amount);
|
||||
this.state.players[sessionId].stash = this.state.players[sessionId].stash + amount;
|
||||
const admin = this.state.players.get(client.sessionId);
|
||||
const targetClient = this.room.clients.find((client) => { return client.sessionId === sessionId });
|
||||
targetClient.send('notification', { text: `${admin.displayName} ha aggiunto ${amount} al tuo stash`, type: 'success' });
|
||||
}
|
||||
}
|
||||
|
||||
export class RemoveFromUserStashCommand extends Command<GameState, { client: Client, sessionId: string, amount: number }> {
|
||||
execute({ client, sessionId, amount }) {
|
||||
const admin = this.state.players.get(client.sessionId);
|
||||
const targetClient = this.room.clients.find((client) => { return client.sessionId === sessionId });
|
||||
targetClient.send('notification', { text: `${admin.displayName} ha rimosso ${amount} dal tuo stash`, type: 'warning' });
|
||||
this.state.players[sessionId].stash = Math.max(0, this.state.players[sessionId].stash - amount);
|
||||
}
|
||||
}
|
||||
|
||||
export class GiveRoomOwnershipCommand extends Command<GameState, { client: Client, sessionId: string }> {
|
||||
execute({ client, sessionId }) {
|
||||
const player = this.state.players.get(sessionId);
|
||||
this.state.roomOwner = player.id;
|
||||
this.state.players.forEach((p, index) => {
|
||||
p.owner = p.id == player.id;
|
||||
});
|
||||
|
||||
// sends a notification to the new owner
|
||||
const newOwner = this.room.clients.find((client) => { return client.sessionId === sessionId });
|
||||
newOwner.send('notification', { text: 'Sei il nuovo propietario della stanza' });
|
||||
}
|
||||
}
|
||||
|
||||
export class AssignSeatCommand extends Command<GameState, { client: Client, sessionId: string }> {
|
||||
execute({ client, sessionId }) {
|
||||
const player = this.state.players.get(sessionId);
|
||||
const minimumStash = this.state.minimumBet * 2;
|
||||
if (player.stash < minimumStash) {
|
||||
client.send('notification', {
|
||||
type: 'warning',
|
||||
text: `Al giocatore servono almeno ${minimumStash} punti per sedersi al tavolo`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.state.running) {
|
||||
player.enteringNextTurn = true;
|
||||
} else {
|
||||
const seat = (<GameRoom>this.room).nextAvailableSeat();
|
||||
console.log('assigning seat to user:', player.displayName, seat);
|
||||
player.playing = true;
|
||||
player.seat = seat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class StartGameCommand extends Command<GameState, { client: Client }> {
|
||||
execute({ client }) {
|
||||
if (Array.from(this.state.players.values()).filter((el) => { return el.playing; }).length < 2) {
|
||||
client.send('notification', {
|
||||
type: 'warning',
|
||||
text: 'Servono almeno 2 giocatori per cominciare una partita'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.state.running = true;
|
||||
(<GameRoom>this.room).onStartGame();
|
||||
}
|
||||
}
|
||||
|
||||
export class PauseGameCommand extends Command<GameState, { client: Client }> {
|
||||
execute() {
|
||||
this.state.running = false;
|
||||
}
|
||||
}
|
||||
0
server/rooms/commands/banco.ts
Normal file
0
server/rooms/commands/banco.ts
Normal file
654
server/rooms/game.ts
Normal file
654
server/rooms/game.ts
Normal file
@@ -0,0 +1,654 @@
|
||||
import { Client, Room } from 'colyseus';
|
||||
import { Dispatcher } from '@colyseus/command';
|
||||
import { createNanoEvents } from 'nanoevents';
|
||||
import { Player as CardPlayer, Hand } from 'typedeck';
|
||||
|
||||
import {
|
||||
GameState,
|
||||
Player,
|
||||
CardPlaceholder,
|
||||
SerializedCard,
|
||||
CardValue,
|
||||
PromptButton,
|
||||
PromptField,
|
||||
Prompt,
|
||||
} from '../games/state';
|
||||
|
||||
import {
|
||||
SetUserStashCommand,
|
||||
AddToUserStashCommand,
|
||||
RemoveFromUserStashCommand,
|
||||
GiveRoomOwnershipCommand,
|
||||
AssignSeatCommand,
|
||||
StartGameCommand,
|
||||
PauseGameCommand
|
||||
} from './commands/admin';
|
||||
|
||||
import { CartaNapoletana, SettemmezzoGameType } from '../games/banco';
|
||||
import { assert } from 'console';
|
||||
|
||||
interface OneOffEvent {
|
||||
[action: string]: (client: Client, message: any) => void
|
||||
}
|
||||
|
||||
interface PlayerAction {
|
||||
action: string
|
||||
bet: number
|
||||
}
|
||||
|
||||
export class GameRoom extends Room<GameState> {
|
||||
private dispatcher = new Dispatcher(this);
|
||||
private messageHandlers = createNanoEvents<OneOffEvent>();
|
||||
private validateSession;
|
||||
private gameType = new SettemmezzoGameType();
|
||||
private deck;
|
||||
private currentDealer: number = -1;
|
||||
|
||||
sleep = (milliseconds: number = 1000): Promise<void> => {
|
||||
return new Promise<void>(resolve => {
|
||||
this.clock.setTimeout(resolve, milliseconds);
|
||||
});
|
||||
}
|
||||
|
||||
getSeatedPlayers(): Player[] {
|
||||
const players = Array.from<Player>(this.state.players.values());
|
||||
return players.filter((p) => { return (p.playing) });
|
||||
}
|
||||
|
||||
getPlayerBySeat(n: number): Player {
|
||||
const players = Array.from<Player>(this.state.players.values());
|
||||
return players.find((p) => { return (p.playing && p.seat === n) });
|
||||
}
|
||||
|
||||
pMap(callbackFn: (value: Player, index: number, array: Player[]) => Player, thisArg?: any): Player[] {
|
||||
const players = Array.from<Player>(this.state.players.values());
|
||||
return players.map(callbackFn);
|
||||
}
|
||||
|
||||
setDealer(n: number) {
|
||||
this.pMap((player) => {
|
||||
player.dealer = player.seat === n;
|
||||
return player;
|
||||
});
|
||||
}
|
||||
|
||||
nextAvailableSeat = (): number => {
|
||||
const playing = this.getSeatedPlayers();
|
||||
return Math.max(...playing.map((p) => { return p.seat }), 0) + 1;
|
||||
}
|
||||
|
||||
nextDealer = (): number => {
|
||||
const players = this.getSeatedPlayers();
|
||||
this.currentDealer = (this.currentDealer + 1) % players.length;
|
||||
const dealerSeat = players[this.currentDealer].seat;
|
||||
console.log('Setting dealer seat:', dealerSeat);
|
||||
|
||||
this.setDealer(dealerSeat);
|
||||
return dealerSeat;
|
||||
}
|
||||
|
||||
*nextPlayerGenerator(dealer: Player) {
|
||||
const players = this.getSeatedPlayers();
|
||||
const dealerIndex = players.indexOf(dealer);
|
||||
let n = 1;
|
||||
while (true) {
|
||||
let p: Player = yield players[(dealerIndex + n) % players.length];
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
|
||||
shuffleCards = () => {
|
||||
console.log('Hard shuffling cards!');
|
||||
this.gameType = new SettemmezzoGameType();
|
||||
this.deck = this.gameType.createDeck();
|
||||
this.deck.shuffle();
|
||||
this.state.remainingCards = 40;
|
||||
}
|
||||
|
||||
dealCard(player: Player, faceUp: boolean = false) {
|
||||
const cardPlayer = new CardPlayer(player.displayName,
|
||||
new Hand());
|
||||
|
||||
this.deck.deal(cardPlayer.getHand(), 1);
|
||||
this.state.remainingCards -= 1;
|
||||
|
||||
const [card] = <CartaNapoletana[]>cardPlayer.getHand().takeCardsFromBottom(1);
|
||||
console.log('Card dealt:', card, 'remaining:', this.state.remainingCards);
|
||||
if (card === undefined) {
|
||||
// FIXME: why this ever happens?
|
||||
console.warn('Card was undefined, deck:', this.deck);
|
||||
return;
|
||||
}
|
||||
|
||||
const cardValue = new CardValue({ value: card.cardName, suit: card.suit });
|
||||
const serializedCard = new SerializedCard({
|
||||
owner: player.sessionId,
|
||||
public: faceUp,
|
||||
card: cardValue
|
||||
});
|
||||
|
||||
player.hand.push(new CardPlaceholder({ card: serializedCard }));
|
||||
}
|
||||
|
||||
publishCards = (player: Player) => {
|
||||
player.hand.forEach(pc => {
|
||||
pc.card.public = true;
|
||||
});
|
||||
}
|
||||
|
||||
tossAllHands = () => {
|
||||
this.pMap((player) => {
|
||||
player.hand = player.hand.filter((pc) => { return false });
|
||||
player.prompt = new Prompt();
|
||||
return player;
|
||||
});
|
||||
}
|
||||
|
||||
getPlayerAction(player: Player): Promise<PlayerAction> {
|
||||
return new Promise<PlayerAction>(resolve => {
|
||||
const unbind = this.messageHandlers.on('resolve-prompt', (client, message) => {
|
||||
if (player.sessionId !== client.sessionId) {
|
||||
console.log('Waiting for a different sessionId:', player.sessionId, client.sessionId);
|
||||
return;
|
||||
}
|
||||
unbind();
|
||||
|
||||
console.log('Got player response:', message);
|
||||
resolve(message);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
hasJolly = (hand: CardPlaceholder[]): boolean => {
|
||||
return undefined !== hand.find((pc) => {
|
||||
const value = pc.card.card.value;
|
||||
const suit = pc.card.card.suit;
|
||||
return value === 9 && suit === 3;
|
||||
});
|
||||
}
|
||||
|
||||
calculateScore = (hand: CardPlaceholder[]) => {
|
||||
let score = hand.reduce((accumulator, currentValue) => {
|
||||
const cardValue = currentValue.card.card.value;
|
||||
const cardSuit = currentValue.card.card.suit;
|
||||
if (cardValue == 9 && cardSuit == 3) {
|
||||
return accumulator + 0;
|
||||
}
|
||||
const v = (cardValue <= 6) ? cardValue + 1 : 0.5;
|
||||
return accumulator + v;
|
||||
}, 0);
|
||||
|
||||
const withJolly = this.hasJolly(hand);
|
||||
if (withJolly) {
|
||||
score += Math.floor(7.5 - score);
|
||||
}
|
||||
|
||||
return { score, withJolly };
|
||||
}
|
||||
|
||||
playHand = async (player: Player, placeBet: boolean) => {
|
||||
let playerLoose = false;
|
||||
let moreCards = true;
|
||||
let betPlaced = false;
|
||||
let score;
|
||||
|
||||
const prompt = player.prompt = new Prompt();
|
||||
while (moreCards && !playerLoose) {
|
||||
prompt.fields.splice(0, prompt.fields.length);
|
||||
prompt.buttons.splice(0, prompt.buttons.length);
|
||||
if (placeBet && !betPlaced) {
|
||||
prompt.fields.push(new PromptField({
|
||||
name: 'bet',
|
||||
label: 'Quanto scommetti',
|
||||
min: this.state.minimumBet,
|
||||
max: Math.min(this.state.pot, player.stash),
|
||||
value: this.state.minimumBet
|
||||
}));
|
||||
}
|
||||
|
||||
prompt.buttons.push(new PromptButton({
|
||||
name: 'stand',
|
||||
label: 'Sto bene',
|
||||
type: 'primary'
|
||||
}));
|
||||
|
||||
prompt.buttons.push(new PromptButton({
|
||||
name: 'more',
|
||||
label: 'Carta',
|
||||
type: 'primary'
|
||||
}));
|
||||
|
||||
// se é un quattro servito, offri la possibilitá di "bruciare"
|
||||
const lucio = player.hand.find((c) => { return c.card.card.value === 3 });
|
||||
if (player.hand.length == 1 && lucio !== undefined) {
|
||||
console.log('LUCIO:', lucio, lucio.card);
|
||||
prompt.buttons.push(new PromptButton({
|
||||
name: 'discard',
|
||||
label: 'Brucia!',
|
||||
type: 'primary'
|
||||
}));
|
||||
}
|
||||
|
||||
prompt.visible = true;
|
||||
|
||||
const choice = await this.getPlayerAction(player);
|
||||
console.log('Player choice was:', choice);
|
||||
|
||||
if (choice.action === 'discard') {
|
||||
// mostra la carta
|
||||
this.publishCards(player);
|
||||
this.broadcast('notification', {
|
||||
type: 'info',
|
||||
text: `${player.displayName} brucia il quattro`
|
||||
});
|
||||
|
||||
// aspetta un paio di secondi
|
||||
await this.sleep(2000);
|
||||
|
||||
// dunque svuota la mano e serve un'altra carta coperta:
|
||||
player.hand.pop();
|
||||
this.dealCard(player, false);
|
||||
} else {
|
||||
moreCards = false;
|
||||
}
|
||||
|
||||
if (choice.hasOwnProperty('bet') && choice.action !== 'discard') {
|
||||
player.stash -= choice.bet;
|
||||
this.state.currentBet += choice.bet;
|
||||
betPlaced = true;
|
||||
}
|
||||
|
||||
if (choice.action === 'more') {
|
||||
this.dealCard(player, true);
|
||||
moreCards = true;
|
||||
}
|
||||
|
||||
// il giocatore ha sballato? -> perde e passa il turno
|
||||
score = this.calculateScore(player.hand);
|
||||
console.log('Score:', score);
|
||||
player.score = score.score;
|
||||
|
||||
if (score.score > 7.5) {
|
||||
console.log('Hai sballato fraté!');
|
||||
playerLoose = true;
|
||||
this.publishCards(player);
|
||||
this.broadcast('notification', {
|
||||
type: 'error',
|
||||
text: `${player.displayName} ha sballato`
|
||||
});
|
||||
player.prompt.visible = false;
|
||||
await this.sleep(3000);
|
||||
} else if (score.score == 7.5) {
|
||||
console.log('Sette e mezzo!!!!');
|
||||
this.publishCards(player);
|
||||
moreCards = false;
|
||||
player.prompt.visible = false;
|
||||
}
|
||||
}
|
||||
prompt.visible = false;
|
||||
return { score, playerLoose };
|
||||
}
|
||||
|
||||
pauseGameIfPlayersDontMeetRequirements = async (): Promise<void> => {
|
||||
const poorPlayers = this.getSeatedPlayers().filter((player) => {
|
||||
return player.stash < this.state.minimumBet * 2;
|
||||
});
|
||||
|
||||
if (poorPlayers.length > 0) {
|
||||
console.log('Pausing game since not all players meet requirements');
|
||||
|
||||
this.state.paused = true;
|
||||
poorPlayers.forEach((player) => {
|
||||
this.broadcast('notification', {
|
||||
type: 'warning',
|
||||
text: `${player.displayName} non ha abbastanza soldi per giocare`
|
||||
});
|
||||
});
|
||||
|
||||
return new Promise<void>(resolve => {
|
||||
const unbind = this.messageHandlers.on('resume-game', (client, message) => {
|
||||
console.log('RESUME GAME?');
|
||||
const poorPlayers = this.getSeatedPlayers().filter((player) => {
|
||||
return player.stash < this.state.minimumBet * 2;
|
||||
});
|
||||
|
||||
if (poorPlayers.length > 0) {
|
||||
this.broadcast('notification', {
|
||||
type: 'warning',
|
||||
text: `Tutti i giocatori al tavolo devono avere almeno ${this.state.minimumBet * 2} per riprendere la partita`
|
||||
});
|
||||
console.log('not resuming');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('resuming');
|
||||
this.state.paused = false;
|
||||
|
||||
unbind();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
async onStartGame() {
|
||||
console.log('Game started');
|
||||
|
||||
while (this.state.running) {
|
||||
await this.pauseGameIfPlayersDontMeetRequirements();
|
||||
|
||||
// Letting in players waiting
|
||||
this.pMap((player) => {
|
||||
if (player.enteringNextTurn) {
|
||||
const seat = this.nextAvailableSeat();
|
||||
console.log('assigning seat to user:', player.displayName, seat);
|
||||
player.enteringNextTurn = false;
|
||||
player.seat = seat;
|
||||
player.playing = true;
|
||||
|
||||
};
|
||||
return player;
|
||||
})
|
||||
|
||||
// collect the initial bets
|
||||
this.getSeatedPlayers().map((player) => {
|
||||
player.stash -= this.state.minimumBet;
|
||||
this.state.pot += this.state.minimumBet;
|
||||
return player;
|
||||
});
|
||||
|
||||
// shuffle cards
|
||||
this.shuffleCards();
|
||||
this.broadcast('notification', {
|
||||
type: 'info',
|
||||
text: 'Le carte sono state mischiate perché il mazzo passa ad un nuovo mazziere'
|
||||
});
|
||||
|
||||
// set the dealer
|
||||
const dealerSeat = this.nextDealer();
|
||||
this.state.player1 = this.getPlayerBySeat(dealerSeat);
|
||||
console.log('Dealer player is:', this.state.player1.displayName);
|
||||
this.broadcast('notification', {
|
||||
type: 'info',
|
||||
text: `${this.state.player1.displayName} é il nuovo banco`
|
||||
});
|
||||
// await this.sleep(3000);
|
||||
|
||||
const table = this.nextPlayerGenerator(this.state.player1);
|
||||
|
||||
while (this.state.pot > 0) {
|
||||
const p: Player = <Player>table.next().value;
|
||||
if (p === null) {
|
||||
throw Error('nextPlayerGenerator didn\'t return a valid Player instance');
|
||||
}
|
||||
|
||||
if (p === this.state.player1) {
|
||||
const prompt = this.state.player1.prompt = new Prompt();
|
||||
|
||||
prompt.buttons.push(new PromptButton({
|
||||
name: 'cash-out',
|
||||
label: 'Prendi il piatto',
|
||||
type: 'primary'
|
||||
}));
|
||||
|
||||
prompt.buttons.push(new PromptButton({
|
||||
name: 'another-round',
|
||||
label: 'Ancora un altro giro',
|
||||
type: 'secondary'
|
||||
}));
|
||||
prompt.visible = true;
|
||||
const choice = await this.getPlayerAction(this.state.player1);
|
||||
this.state.player1.prompt = new Prompt();
|
||||
console.log('Player choice was:', choice);
|
||||
|
||||
if (choice.action === 'cash-out') {
|
||||
this.broadcast('notification', {
|
||||
type: 'info',
|
||||
text: `Il banco (${this.state.player1.displayName}) prende ${this.state.pot} del piatto e passa la mano`
|
||||
});
|
||||
this.state.player1.stash += this.state.pot;
|
||||
this.state.pot = 0;
|
||||
|
||||
await this.sleep(3000);
|
||||
break;
|
||||
} else {
|
||||
this.broadcast('notification', {
|
||||
type: 'info',
|
||||
text: `Il banco (${this.state.player1.displayName}) ha deciso per un altro giro`
|
||||
});
|
||||
await this.sleep(3000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
await this.pauseGameIfPlayersDontMeetRequirements();
|
||||
|
||||
this.state.player2 = p;
|
||||
console.log('Challenger player is:', this.state.player2.displayName);
|
||||
|
||||
// Deal draft cards
|
||||
this.dealCard(this.state.player2, false);
|
||||
this.state.player2.score = this.calculateScore(this.state.player2.hand).score;
|
||||
|
||||
this.dealCard(this.state.player1, false);
|
||||
this.state.player1.score = this.calculateScore(this.state.player1.hand).score
|
||||
|
||||
// Let challenger play his hand
|
||||
let challengerWins = false;
|
||||
|
||||
const challengerResult = await this.playHand(this.state.player2, true);
|
||||
console.log('Challenger:', challengerResult);;
|
||||
|
||||
this.publishCards(this.state.player1);
|
||||
if (!challengerResult.playerLoose) {
|
||||
const dealerResult = await this.playHand(this.state.player1, false);
|
||||
console.log('Dealer:', dealerResult);
|
||||
|
||||
this.publishCards(this.state.player2);
|
||||
if (!dealerResult.playerLoose) {
|
||||
challengerWins = challengerResult.score.score > dealerResult.score.score;
|
||||
} else {
|
||||
challengerWins = true;
|
||||
}
|
||||
} else {
|
||||
challengerWins = false;
|
||||
console.log('Dealer wins!');
|
||||
}
|
||||
|
||||
await this.sleep(5000);
|
||||
|
||||
const jollyWasDealt = this.hasJolly(this.state.player1.hand) || this.hasJolly(this.state.player2.hand);
|
||||
console.log('La matta é stata giocata? ', jollyWasDealt);
|
||||
|
||||
if (challengerWins) {
|
||||
this.broadcast('notification', {
|
||||
type: 'success',
|
||||
text: `${this.state.player2.displayName} vince (${this.state.currentBet}) dal piatto`
|
||||
});
|
||||
this.state.player2.stash += this.state.currentBet * 2;
|
||||
this.state.pot -= this.state.currentBet;
|
||||
assert(this.state.pot >= 0);
|
||||
await this.sleep(3000);
|
||||
} else {
|
||||
this.broadcast('notification', {
|
||||
type: 'success',
|
||||
text: `Il banco (${this.state.player1.displayName}) vince la mano`
|
||||
});
|
||||
this.state.pot += this.state.currentBet;
|
||||
}
|
||||
this.state.currentBet = 0;
|
||||
|
||||
// svuota le mani
|
||||
this.tossAllHands();
|
||||
|
||||
if (jollyWasDealt) {
|
||||
console.log('Shuffling deck since jolly was dealt in last hand');
|
||||
this.shuffleCards();
|
||||
|
||||
this.broadcast('notification', {
|
||||
type: 'info',
|
||||
text: 'Le carte sono state mischiate perché la matta é stata estratta nell\'ultima mano'
|
||||
});
|
||||
await this.sleep(3000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onAuth(client, options, request) {
|
||||
console.log('onauth', options, request.session.user_id);
|
||||
const user = this.validateSession(request.session.user_id);
|
||||
console.log('Found user:', user);
|
||||
return user;
|
||||
}
|
||||
|
||||
onCreate(options) {
|
||||
this.deck = this.gameType.createDeck();
|
||||
this.deck.shuffle();
|
||||
console.log('Deck created:', this.deck);
|
||||
|
||||
console.log('GameRoom instance created', this.roomId, options);
|
||||
this.validateSession = options.validateSession;
|
||||
|
||||
this.setState(new GameState());
|
||||
this.state.roomOwner = options.user_id;
|
||||
|
||||
this.onMessage('admin', (client, message) => this.onAdminCommand(client, message));
|
||||
this.onMessage('webrtc', (client, message) => this.onWebRTCCommand(client, message));
|
||||
this.onMessage('*', (client, type: string, message) => {
|
||||
console.log('Relaying message:', type, message);
|
||||
this.messageHandlers.emit(type, client, message);
|
||||
});
|
||||
|
||||
this.clock.start();
|
||||
|
||||
// DEMO: rotates the background every 60 seconds
|
||||
this.clock.setInterval(() => {
|
||||
this.state.bg = 1 + (this.state.bg + 1) % 5;
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
onJoin(client, options, user) {
|
||||
console.log(`User ${user.display_name} (${user.user_id}) joined room ${this.roomId}`, options);
|
||||
|
||||
if (this.state.players.size === 0) {
|
||||
console.log(`User ${user.display_name} (${user.user_id}) set as room ${this.roomId} owner`);
|
||||
this.state.roomOwner = user.user_id;
|
||||
}
|
||||
|
||||
const user_already_logged_in = Array.from(this.state.players.values()).find((item) => item.id === user.user_id);
|
||||
if (user_already_logged_in) {
|
||||
console.log('User was already in the game!', user_already_logged_in);
|
||||
return;
|
||||
}
|
||||
|
||||
this.state.players.set(client.sessionId, new Player({
|
||||
id: user.user_id,
|
||||
sessionId: client.sessionId,
|
||||
displayName: user.display_name,
|
||||
owner: user.user_id === this.state.roomOwner,
|
||||
stash: 0,
|
||||
connected: true,
|
||||
playing: false,
|
||||
dealer: false,
|
||||
hand: []
|
||||
}));
|
||||
}
|
||||
|
||||
async onLeave(client, consented) {
|
||||
console.log('Player leaving:', client.sessionId);
|
||||
if (this.state.players.has(client.sessionId)) {
|
||||
this.state.players[client.sessionId].connected = false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (consented) {
|
||||
throw new Error("consented leave");
|
||||
}
|
||||
|
||||
// allow disconnected client to reconnect into this room until 60 seconds
|
||||
await this.allowReconnection(client, 60);
|
||||
|
||||
// client returned! let's re-activate it.
|
||||
this.state.players[client.sessionId].connected = true;
|
||||
|
||||
} catch (e) {
|
||||
// 60 seconds expired. let's remove the client.
|
||||
this.state.players.delete(client.sessionId);
|
||||
|
||||
// explicitly broadcasting the event to let WebRTC cleanup corectly
|
||||
this.broadcast('player-left', client.sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
onAdminCommand(client, message) {
|
||||
console.log('Admin command received:', message);
|
||||
const player = this.state.players.get(client.sessionId);
|
||||
if (player.id !== this.state.roomOwner) {
|
||||
console.warn('Received admin command from non-owner user:', client.sessionId, message);
|
||||
return;
|
||||
}
|
||||
|
||||
const admin_commands = {
|
||||
// set user stash (session_id, amount)
|
||||
'set-user-stash': SetUserStashCommand,
|
||||
|
||||
// add to user stash (session_id, amount)
|
||||
'add-to-user-stash': AddToUserStashCommand,
|
||||
|
||||
// remove from user stash (session_id, amount)
|
||||
'remove-from-user-stash': RemoveFromUserStashCommand,
|
||||
|
||||
// assign seat to player (session_id)
|
||||
'assign-seat': AssignSeatCommand,
|
||||
|
||||
// demote player (session_id)
|
||||
// shuffle seats
|
||||
|
||||
// give room ownership (session_id)
|
||||
'give-room-ownership': GiveRoomOwnershipCommand,
|
||||
|
||||
// start game
|
||||
'start-game': StartGameCommand,
|
||||
|
||||
// pause game
|
||||
'pause-game': PauseGameCommand,
|
||||
|
||||
// set room name (new name)
|
||||
// set room background (background)
|
||||
};
|
||||
|
||||
if (!admin_commands.hasOwnProperty(message.command)) {
|
||||
console.error("Invalid admin command", message);
|
||||
return;
|
||||
}
|
||||
|
||||
const commandClass = admin_commands[message.command];
|
||||
this.dispatcher.dispatch(new commandClass(), { ...message.payload, client });
|
||||
}
|
||||
|
||||
onWebRTCCommand(client, message) {
|
||||
console.log('WebRTC command received:', message);
|
||||
const player = this.clients.find((value) => { return value.sessionId === message.payload.targetId });
|
||||
if (player === null) {
|
||||
console.warn('Cannot find client with sessionId', message.payload.targetId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.command === 'call-player') {
|
||||
console.log('Relaying WebRTC call:', message.payload);
|
||||
if (player === undefined) {
|
||||
console.warn('Incoming call to an unknown player');
|
||||
return;
|
||||
}
|
||||
player.send('incoming-call', message.payload);
|
||||
}
|
||||
|
||||
if (message.command === 'answer-call') {
|
||||
console.log('Relaying WebRTC call:', message.payload);
|
||||
player.send('answer-call', message.payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
181
server/server.ts
Normal file
181
server/server.ts
Normal file
@@ -0,0 +1,181 @@
|
||||
import { Server } from 'colyseus';
|
||||
import * as express from 'express';
|
||||
|
||||
import { createServer } from 'http';
|
||||
|
||||
import * as session from 'express-session';
|
||||
|
||||
import { randomBytes } from 'crypto';
|
||||
import { GameRoom } from './rooms/game';
|
||||
|
||||
interface User {
|
||||
user_id: string;
|
||||
display_name: string;
|
||||
}
|
||||
|
||||
const connected_users: { [id: string]: User } = {};
|
||||
const validateSession = (user_id => {
|
||||
console.log(`Is ${user_id} in ${Object.keys(connected_users)}?`);
|
||||
if (Object.keys(connected_users).includes(user_id)) {
|
||||
const user_info = connected_users[user_id];
|
||||
console.log('Yes!', user_info);
|
||||
return user_info;
|
||||
}
|
||||
console.log('No!');
|
||||
return false;
|
||||
});
|
||||
|
||||
// - Augments built-in Node.js IncomingMessage to include "session"
|
||||
// - Lets TypeScript recognize "request.session" during onAuth()
|
||||
declare module 'http' {
|
||||
interface IncomingMessage {
|
||||
session: session.Session
|
||||
}
|
||||
}
|
||||
|
||||
const sessionParser = session({
|
||||
secret: 'any secret string',
|
||||
// store: new RedisStore({ client: redisClient })
|
||||
});
|
||||
|
||||
const port = Number(process.env.port) || 3001;
|
||||
|
||||
const app = express();
|
||||
app.use(sessionParser);
|
||||
app.use(express.json());
|
||||
app.use(express.static('../client/build'))
|
||||
|
||||
app.post('/api/login', (req, res) => {
|
||||
// login to the server (a unique display name is enough)
|
||||
const username = req.body.display_name;
|
||||
console.log('Login request with display name', username, connected_users);
|
||||
const existing_user = Object.values(connected_users).find(user => user.display_name === username);
|
||||
if (existing_user) {
|
||||
console.log('oh no, no no, oh no non ononononono');
|
||||
res.status(401).json({ sto: 'cazzo' });
|
||||
} else {
|
||||
const random_id = `player-${randomBytes(16).toString('hex')}`;
|
||||
connected_users[random_id] = {
|
||||
user_id: random_id,
|
||||
display_name: username,
|
||||
};
|
||||
|
||||
req.session!['user_id'] = random_id;
|
||||
req.session!['display_name'] = username;
|
||||
|
||||
console.log('oh yeah!', connected_users);
|
||||
res.json({ user_id: random_id });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/logout', (req, res) => {
|
||||
const user_id = req.session!['user_id'];
|
||||
console.log('Logging out user:', user_id);
|
||||
|
||||
delete connected_users[user_id];
|
||||
delete req.session!['user_id'];
|
||||
delete req.session!['display_name'];
|
||||
res.json({ bye: 'bye' });
|
||||
});
|
||||
|
||||
app.get('/api/session', (req, res) => {
|
||||
// returns session data
|
||||
res.json(req.session!);
|
||||
});
|
||||
|
||||
const gameServer = new Server({
|
||||
server: createServer(app),
|
||||
verifyClient: (info, next) => {
|
||||
// Make 'session' available for the websocket connection (during onAuth())
|
||||
sessionParser(info.req as any, {} as any, () => next(true));
|
||||
}
|
||||
});
|
||||
|
||||
gameServer.define('game', GameRoom, { validateSession: validateSession });
|
||||
gameServer.listen(port, '0.0.0.0');
|
||||
|
||||
|
||||
|
||||
// Connection broker
|
||||
// const peerServerOptions = {
|
||||
// debug: true,
|
||||
// path: '/domingo'
|
||||
// };
|
||||
|
||||
// const peerServer = ExpressPeerServer(server, peerServerOptions);
|
||||
// app.use('/peerjs', peerServer);
|
||||
|
||||
|
||||
// const joined_users = {};
|
||||
// const rooms = {};
|
||||
|
||||
// io.on('connection', socket => {
|
||||
// let user = null;
|
||||
// let session_id = null;
|
||||
|
||||
// socket.on('JOIN_AS', (username) => {
|
||||
// console.log('JOIN_AS', username);
|
||||
// if (username === null || username in Object.values(joined_users)) {
|
||||
// socket.emit('ERROR', 'Lo username non é valido oppure risulta giá in uso');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// session_id = uuidV4();
|
||||
// user = username;
|
||||
// joined_users[session_id] = user;
|
||||
// socket.emit('JOINED', session_id);
|
||||
// });
|
||||
|
||||
// socket.on('CREATE_ROOM', (session_token) => {
|
||||
// if (session_token !== session_id) {
|
||||
// socket.emit('ERROR', 'Non sei autorizzato a creare una stanza');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const roomId = uuidV4();
|
||||
// rooms[roomId] = {
|
||||
// owner: user,
|
||||
// participants: {} // maps session tokens to peer ids
|
||||
// };
|
||||
|
||||
// console.log(`Created new room ${roomId} for user ${user}`);
|
||||
// socket.emit('ROOM_CREATED', roomId);
|
||||
// });
|
||||
|
||||
// socket.on('JOIN_ROOM', (session_token, roomId, peerId, callback) => {
|
||||
// console.log('DEBUG: JOIN_ROOM', session_token, roomId, peerId);
|
||||
// if (roomId in rooms === false) {
|
||||
// socket.emit('ERROR', 'Stanza non trovata');
|
||||
// console.log(`Cercava ${roomId} in ${rooms}`);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (peerId === null) {
|
||||
// socket.emit('ERROR', 'Peer ID mancante nella richiesta');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (session_token in joined_users === false) {
|
||||
// socket.emit('ERROR', 'La sessione non é valida');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// const user = joined_users[session_token];
|
||||
// console.log(`User ${user} is joining room ${roomId}`);
|
||||
|
||||
// // Aggiorna la stanza con il peerId
|
||||
// const user_obj = {
|
||||
// user_id: session_token,
|
||||
// display_name: user,
|
||||
// peer: peerId
|
||||
// };
|
||||
// rooms[roomId].participants[session_token] = user_obj;
|
||||
|
||||
// // Annuncia l'utente nella stanza
|
||||
// socket.join(roomId);
|
||||
// socket.to(roomId).broadcast.emit('USER_CONNECTED', session_token, user_obj);
|
||||
|
||||
// // Restituisce la lista aggiornata dei giocatori della stanza
|
||||
// callback({ participants: rooms[roomId].participants });
|
||||
// });
|
||||
// })
|
||||
10
server/tsconfig.json
Normal file
10
server/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es6"
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
]
|
||||
}
|
||||
2176
server/yarn.lock
Normal file
2176
server/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user