mapguesser/multi/index.js

291 lines
8.1 KiB
JavaScript
Raw Normal View History

'use strict';
process.title = 'mapguesser-multi';
class MultiGame {
constructor() {
this.rooms = new Map();
}
cleanupRooms() {
this.rooms.forEach(function (room, roomId) {
var lastValidDate = new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000);
if (room.updated < lastValidDate) {
this.rooms.delete(roomId);
}
});
}
connectToRoom(roomId, token, connection) {
if (!this.rooms.has(roomId) || !this.rooms.get(roomId).members.has(token)) {
return;
}
var room = this.rooms.get(roomId)
var member = room.members.get(token);
member.connection = connection;
2021-04-03 13:38:16 +02:00
this._sendInitialData(room, member, token);
}
createRoom(roomId) {
this.rooms.set(roomId, { members: new Map(), rounds: [], currentRound: -1, updated: new Date() });
}
joinRoom(roomId, token, userName) {
if (!this.rooms.has(roomId)) {
console.error('Room does not exist!')
return;
}
var room = this.rooms.get(roomId);
room.updated = new Date();
if (room.members.has(token)) {
return;
}
var data = { userName: userName };
var self = this;
room.members.forEach(function (member) {
self._sendToMember(member, 'member_joined', data);
});
2021-04-03 13:38:16 +02:00
room.members.set(token, { userName: userName, connection: null });
}
startGame(roomId, places) {
if (!this.rooms.has(roomId)) {
//TODO: send something back
console.log('Room does not exist!')
return;
}
var room = this.rooms.get(roomId);
room.updated = new Date();
var rounds = [];
places.forEach(function (place) {
rounds.push({ place: place, results: new Map() })
});
room.rounds = rounds;
this.nextRound(roomId, 0);
}
guess(roomId, token, guessPosition, distance, score) {
if (!this.rooms.has(roomId)) {
//TODO: send something back
console.log('Room does not exist!')
return;
}
var room = this.rooms.get(roomId);
room.updated = new Date();
var round = room.rounds[room.currentRound];
2021-04-03 13:38:16 +02:00
var member = room.members.get(token);
var allResults = this._collectResultsInRound(room, round);
2021-04-03 13:38:16 +02:00
this._broadcastGuess(room, member.userName, guessPosition, distance, score);
2021-04-03 13:38:16 +02:00
round.results.set(token, { guessPosition: guessPosition, distance: distance, score: score });
2021-04-03 13:38:16 +02:00
return allResults;
}
nextRound(roomId, currentRound) {
if (!this.rooms.has(roomId)) {
//TODO: send something back
console.log('Room does not exist!')
return;
}
var room = this.rooms.get(roomId);
room.updated = new Date();
room.currentRound = currentRound;
var round = room.rounds[room.currentRound];
var data = {};
data.place = { panoId: round.place.panoId, pov: round.place.pov };
if (room.currentRound > 0) {
data.result = { position: room.rounds[room.currentRound - 1].place.position };
}
var self = this;
room.members.forEach(function (member) {
self._sendToMember(member, 'new_round', data);
});
}
2021-04-03 13:38:16 +02:00
_sendInitialData(room, member, token) {
var data = {};
if (room.currentRound >= 0) {
data.place = room.rounds[room.currentRound].place;
}
data.history = [];
for (var i = 0; i < room.currentRound; ++i) {
var round = room.rounds[i];
2021-04-03 13:38:16 +02:00
var result = { guessPosition: null, distance: null, score: 0 };
var allResults = [];
round.results.forEach(function (currentResult, currentToken) {
if (token === currentToken) {
result = currentResult;
return;
}
allResults.push({ userName: room.members.get(currentToken).userName, guessPosition: currentResult.guessPosition, distance: currentResult.distance, score: currentResult.score });
});
data.history.push({
position: round.place.position,
2021-04-03 13:38:16 +02:00
result: result,
allResults: allResults
});
}
data.members = [];
room.members.forEach(function (currentMember) {
data.members.push({ userName: currentMember.userName, me: member === currentMember });
});
this._sendToMember(member, 'initialize', data);
}
2021-04-03 13:38:16 +02:00
_collectResultsInRound(room, round) {
var results = [];
2021-04-03 13:38:16 +02:00
round.results.forEach(function (result, token) {
results.push({
userName: room.members.get(token).userName,
guessPosition: result.guessPosition,
distance: result.distance,
score: result.score
});
});
2021-04-03 13:38:16 +02:00
return results;
}
_broadcastGuess(room, userName, guessPosition, distance, score) {
var data = { userName: userName, guessPosition: guessPosition, distance: distance, score: score };
2021-04-03 13:38:16 +02:00
var round = room.rounds[room.currentRound];
var self = this;
room.members.forEach(function (member, token) {
if (!round.results.has(token)) {
return;
}
2021-04-03 13:38:16 +02:00
self._sendToMember(member, 'guess', data);
});
}
_sendToMember(member, type, data) {
if (!member.connection) {
return;
}
if (member.connection.readyState !== ws.OPEN) {
member.connection = null;
return;
}
member.connection.send(JSON.stringify({ type: type, data: data }));
}
}
require('dotenv').config();
var
net = require('net'),
ws = require('ws');
var multiGame = new MultiGame();
//TODO: following should be in a separate class/function
var tcpServer = net.createServer(function (socket) {
socket.on('data', function (data) {
try {
data = JSON.parse(data);
} catch (e) {
console.error('Cannot parse data: ' + data);
return;
}
2021-04-03 13:38:16 +02:00
var response = { data: null };
switch (data.func) {
case 'create_room':
2021-04-03 13:38:16 +02:00
response.data = multiGame.createRoom(data.args.roomId);
break;
case 'join_room':
2021-04-03 13:38:16 +02:00
response.data = multiGame.joinRoom(data.args.roomId, data.args.token, data.args.userName);
break;
case 'start_game':
2021-04-03 13:38:16 +02:00
response.data = multiGame.startGame(data.args.roomId, data.args.places);
break
case 'guess':
2021-04-03 13:38:16 +02:00
response.data = multiGame.guess(data.args.roomId, data.args.token, data.args.guessPosition, data.args.distance, data.args.score);
break;
case 'next_round':
2021-04-03 13:38:16 +02:00
response.data = multiGame.nextRound(data.args.roomId, data.args.currentRound);
break;
}
2021-04-03 13:38:16 +02:00
socket.write(JSON.stringify(response));
socket.end();
});
});
tcpServer.on('listening', function () {
console.log('[INFO] TCP server started');
});
tcpServer.listen(process.env.MULTI_INTERNAL_PORT);
var wsServer = new ws.Server({ port: process.env.MULTI_WS_PORT });
wsServer.on('connection', function (connection, request) {
console.log('[INFO] New WS connection: ' + request.connection.remoteAddress);
connection.on('message', function (data) {
try {
data = JSON.parse(data);
} catch (e) {
console.error('Cannot parse data: ' + data);
return;
}
switch (data.func) {
case 'connect_to_room':
multiGame.connectToRoom(data.args.roomId, data.args.token, connection);
break;
}
});
connection.on('close', function () {
console.log('[INFO] WS connection ended: ' + request.connection.remoteAddress);
});
});
wsServer.on('listening', function () {
console.log('[INFO] WS server started');
});
setInterval(function () {
multiGame.cleanupRooms();
}, 24 * 60 * 60 * 1000);