-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
156 lines (136 loc) · 4.71 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");
const runGame = require("./lib/game");
const msgs = require("./lib/messages");
const port = process.env.PORT || 4000;
const app = express();
const server = http.createServer(app);
const io = socketIo(server);
function Room(id, hostId, playerName) {
this.id = id;
this.name = `${playerName}'s room`;
this.hostId = hostId;
this.players = [];
this.open = true;
this.gameOptions = {
passWordOnOdd: false,
useHarderWords: false,
}
this.isAllReady = function () {
return this.players.every((player) => player.ready);
};
this.clearReadies = function () {
this.players = this.players.map((player) => ({ ...player, ready: false }));
};
this.clearReplayData = function () {
this.players = this.players.map((player) => ({
...player,
replayData: [],
}));
};
}
function Player(socket, playerName) {
this.id = socket.id;
this.name = playerName;
this.ready = false;
this.replayData = [];
this.toggleReady = function () {
this.ready = !this.ready;
};
}
let rooms = [];
function joinRoom(socket, roomId, playerName) {
// Join socket to room; return `new Room`
if (Object.keys(socket.rooms).includes(roomId))
return socket.send("You're already in that room!");
const room = rooms.find((room) => room.id === roomId);
if (!room) return socket.send("Oops! Can't find that room.");
if (!room.open) return socket.send("Oops! That room is closed.");
socket.join(room.id);
room.players = [...room.players, new Player(socket, playerName)];
io.to(roomId).emit(msgs.ROOM_UPDATE, room);
return room;
}
function leaveRoom(socket, roomId) {
// get room by ID
const room = rooms.find(({ id }) => id === roomId);
if (!room) return socket.send("Oops! Can't leave that room.");
// Disconnect socket from room
socket.leave(room.id);
// Remove player from `Room` object
room.players = room.players.filter(({ id }) => id !== socket.id);
// Remove the Room if it's empty
if (room.players.length === 0) {
rooms = rooms.filter(({ id }) => id !== room.id);
return null;
}
// Hand off `host` to another player if necessary
if (room.hostId === socket.id) {
room.hostId = room.players[0].id;
room.name = `${room.players[0].name}'s Room`;
}
io.to(room.id).emit(msgs.ROOM_UPDATE, room);
}
/**
* Handle players on socket.io connection
*/
io.on("connection", (socket) => {
console.log(`New client id ${socket.id} connected`);
let currentRoom;
// Clear client's previous room view if reconnecting:
socket.emit(msgs.ROOM_UPDATE, null);
socket.on(msgs.CREATE_ROOM, (playerName) => {
const roomId = `rm${socket.id}`;
if (rooms.some(({ id }) => id === roomId))
return socket.send("You have already created that room");
// create and join room
rooms.push(new Room(roomId, socket.id, playerName));
io.emit(
msgs.OPEN_ROOMS,
rooms.filter(({ open }) => open).map(({ id, name }) => ({ id, name }))
);
currentRoom = joinRoom(socket, roomId, playerName);
});
socket.on(msgs.JOIN_ROOM, (roomId, playerName) => {
currentRoom = joinRoom(socket, roomId, playerName);
});
socket.on(msgs.LEAVE_ROOM, () => {
if (currentRoom)
leaveRoom(socket, currentRoom.id);
currentRoom = null;
socket.emit(msgs.ROOM_UPDATE, null);
});
socket.on(msgs.GET_ROOMS, (ack) => {
// Return `open` rooms
ack(rooms.filter(({ open }) => open).map(({ id, name }) => ({ id, name })));
});
socket.on(msgs.TOGGLE_READY, () => {
if (!currentRoom) {
socket.emit(msgs.ROOM_UPDATE, null);
return socket.send("Oops! That room doesn't exist any more.");
}
currentRoom.players.find(({ id }) => id === socket.id).toggleReady();
io.to(currentRoom.id).emit(msgs.ROOM_UPDATE, currentRoom);
// Here is a possible place to check for "all ready" and listen for "start-game"
// instead of having "start game" be open all the time
});
socket.on(msgs.START_GAME, (gameOptions) => {
if (!currentRoom) {
socket.emit(msgs.ROOM_UPDATE, null);
return socket.send("Oops! That room doesn't exist any more.");
}
if (!currentRoom.isAllReady()) return socket.send("Oops! Not everyone is ready!");
currentRoom.gameOptions = { ...gameOptions };
runGame(socket, io, currentRoom, gameOptions);
});
socket.on("disconnect", (reason) => {
// TODO: Handle reconnect (ex: "would you like to reconnect as player ____?")
if (currentRoom) leaveRoom(socket, currentRoom.id);
console.log(`Client id ${socket.id} disconnected - reason: ${reason}`);
});
});
app.get("/", (req, res) => {
res.status(200).send("GET received");
});
server.listen(port, () => console.log(`Listening on port ${port}`));