Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22f4abd82d
|
No files matched your search
@@ -15,7 +15,3 @@ MAIL_PORT=2500
|
|||||||
GOOGLE_OAUTH_CLIENT_ID=your_google_oauth_client_id
|
GOOGLE_OAUTH_CLIENT_ID=your_google_oauth_client_id
|
||||||
GOOGLE_OAUTH_CLIENT_SECRET=your_google_oauth_client_secret
|
GOOGLE_OAUTH_CLIENT_SECRET=your_google_oauth_client_secret
|
||||||
GOOGLE_ANALITICS_ID=your_google_analytics_id
|
GOOGLE_ANALITICS_ID=your_google_analytics_id
|
||||||
MULTI_INTERNAL_HOST=multi
|
|
||||||
MULTI_INTERNAL_PORT=5000
|
|
||||||
MULTI_WS_URL=mapguesser-dev.ch:8090
|
|
||||||
MULTI_WS_PORT=8090
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
.env
|
.env
|
||||||
installed
|
installed
|
||||||
vendor
|
vendor
|
||||||
node_modules
|
|
||||||
Vendored
-8
@@ -9,14 +9,6 @@
|
|||||||
"pathMappings": {
|
"pathMappings": {
|
||||||
"/var/www/mapguesser": "${workspaceRoot}",
|
"/var/www/mapguesser": "${workspaceRoot}",
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Listen for NodeJS Inspector in Docker",
|
|
||||||
"type": "node",
|
|
||||||
"request": "attach",
|
|
||||||
"port": 9229,
|
|
||||||
"localRoot": "${workspaceFolder}",
|
|
||||||
"remoteRoot": "/var/www/mapguesser"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
+1
-2
@@ -6,8 +6,7 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"vlucas/phpdotenv": "^4.1",
|
"vlucas/phpdotenv": "^4.1",
|
||||||
"symfony/console": "^5.1",
|
"symfony/console": "^5.1",
|
||||||
"phpmailer/phpmailer": "^6.1",
|
"phpmailer/phpmailer": "^6.1"
|
||||||
"fzaninotto/faker": "^1.9"
|
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^9",
|
"phpunit/phpunit": "^9",
|
||||||
|
|||||||
Generated
+2
-57
@@ -4,63 +4,8 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "b71c0ffc0761a6b90f6242346b735a09",
|
"content-hash": "34563bfc619f47473b2e37a5639dd63e",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
|
||||||
"name": "fzaninotto/faker",
|
|
||||||
"version": "v1.9.2",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/fzaninotto/Faker.git",
|
|
||||||
"reference": "848d8125239d7dbf8ab25cb7f054f1a630e68c2e"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/fzaninotto/Faker/zipball/848d8125239d7dbf8ab25cb7f054f1a630e68c2e",
|
|
||||||
"reference": "848d8125239d7dbf8ab25cb7f054f1a630e68c2e",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": "^5.3.3 || ^7.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"ext-intl": "*",
|
|
||||||
"phpunit/phpunit": "^4.8.35 || ^5.7",
|
|
||||||
"squizlabs/php_codesniffer": "^2.9.2"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "1.9-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Faker\\": "src/Faker/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "François Zaninotto"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Faker is a PHP library that generates fake data for you.",
|
|
||||||
"keywords": [
|
|
||||||
"data",
|
|
||||||
"faker",
|
|
||||||
"fixtures"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/fzaninotto/Faker/issues",
|
|
||||||
"source": "https://github.com/fzaninotto/Faker/tree/v1.9.2"
|
|
||||||
},
|
|
||||||
"abandoned": true,
|
|
||||||
"time": "2020-12-11T09:56:16+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "phpmailer/phpmailer",
|
"name": "phpmailer/phpmailer",
|
||||||
"version": "v6.1.6",
|
"version": "v6.1.6",
|
||||||
@@ -2765,5 +2710,5 @@
|
|||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
"platform": [],
|
"platform": [],
|
||||||
"platform-dev": [],
|
"platform-dev": [],
|
||||||
"plugin-api-version": "2.0.0"
|
"plugin-api-version": "1.1.0"
|
||||||
}
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
CREATE TABLE `multi_rooms` (
|
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
|
||||||
`room_id` varchar(6) NOT NULL,
|
|
||||||
`state` text NOT NULL,
|
|
||||||
`members` text NOT NULL,
|
|
||||||
`updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `room_id` (`room_id`)
|
|
||||||
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
|
|
||||||
+4
-13
@@ -1,23 +1,14 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
build:
|
build: ./docker
|
||||||
context: ./docker
|
|
||||||
dockerfile: Dockerfile-app
|
|
||||||
ports:
|
ports:
|
||||||
- 80:80
|
- 80:80
|
||||||
volumes:
|
volumes:
|
||||||
- .:/var/www/mapguesser
|
- .:/var/www/mapguesser
|
||||||
multi:
|
links:
|
||||||
build:
|
- 'mariadb'
|
||||||
context: ./docker
|
- 'mail'
|
||||||
dockerfile: Dockerfile-multi
|
|
||||||
ports:
|
|
||||||
- 5000:5000
|
|
||||||
- 8090:8090
|
|
||||||
- 9229:9229
|
|
||||||
volumes:
|
|
||||||
- .:/var/www/mapguesser
|
|
||||||
mariadb:
|
mariadb:
|
||||||
image: mariadb:10.3
|
image: mariadb:10.3
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
File renamed without changes.
@@ -1,16 +0,0 @@
|
|||||||
FROM ubuntu:focal
|
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND noninteractive
|
|
||||||
|
|
||||||
# Install necessary packages
|
|
||||||
RUN apt update --fix-missing
|
|
||||||
RUN apt install -y curl build-essential
|
|
||||||
|
|
||||||
# Install Node.js and required packages
|
|
||||||
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
|
|
||||||
RUN apt install -y nodejs
|
|
||||||
|
|
||||||
VOLUME /var/www/mapguesser
|
|
||||||
WORKDIR /var/www/mapguesser
|
|
||||||
|
|
||||||
ENTRYPOINT /usr/bin/node --inspect=0.0.0.0:9229 multi
|
|
||||||
-369
@@ -1,369 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
process.title = 'mapguesser-multi';
|
|
||||||
|
|
||||||
class MultiGame {
|
|
||||||
static ROUND_TIMEOUT_DEFAULT = 120000;
|
|
||||||
static ROUND_TIMEOUT_MINIMUM = 15000;
|
|
||||||
static ROUND_TIMEOUT_DIVIDER = 1.5;
|
|
||||||
static ROUND_TIMEOUT_OFFSET = 500;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
this._sendInitialData(room, member, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
createRoom(roomId) {
|
|
||||||
this.rooms.set(roomId, { members: new Map(), rounds: [], currentRound: -1, updated: new Date() });
|
|
||||||
|
|
||||||
return { ok: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
joinRoom(roomId, token, userName) {
|
|
||||||
if (!this.rooms.has(roomId)) {
|
|
||||||
return { error: 'room_not_found' };
|
|
||||||
}
|
|
||||||
|
|
||||||
var room = this.rooms.get(roomId);
|
|
||||||
room.updated = new Date();
|
|
||||||
|
|
||||||
if (room.members.has(token)) {
|
|
||||||
return { error: 'member_already_joined' };
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = { userName: userName };
|
|
||||||
var self = this;
|
|
||||||
room.members.forEach(function (member) {
|
|
||||||
self._sendToMember(member, 'member_joined', data);
|
|
||||||
});
|
|
||||||
|
|
||||||
room.members.set(token, { userName: userName, connection: null });
|
|
||||||
|
|
||||||
return { ok: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
startGame(roomId, places) {
|
|
||||||
if (!this.rooms.has(roomId)) {
|
|
||||||
return { error: 'room_not_found' };
|
|
||||||
}
|
|
||||||
|
|
||||||
var room = this.rooms.get(roomId);
|
|
||||||
room.updated = new Date();
|
|
||||||
|
|
||||||
var rounds = [];
|
|
||||||
places.forEach(function (place) {
|
|
||||||
rounds.push({
|
|
||||||
place: place,
|
|
||||||
results: new Map(),
|
|
||||||
timeout: MultiGame.ROUND_TIMEOUT_DEFAULT,
|
|
||||||
timeoutStarted: null,
|
|
||||||
timeoutHandler: null
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
room.rounds = rounds;
|
|
||||||
|
|
||||||
this.nextRound(roomId, 0);
|
|
||||||
|
|
||||||
return { ok: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
guess(roomId, token, guessPosition, distance, score) {
|
|
||||||
if (!this.rooms.has(roomId)) {
|
|
||||||
return { error: 'room_not_found' };
|
|
||||||
}
|
|
||||||
|
|
||||||
var room = this.rooms.get(roomId);
|
|
||||||
room.updated = new Date();
|
|
||||||
|
|
||||||
var round = room.rounds[room.currentRound];
|
|
||||||
if (round.results.has(token)) {
|
|
||||||
return { error: 'already_guessed' };
|
|
||||||
}
|
|
||||||
|
|
||||||
var member = room.members.get(token);
|
|
||||||
var allResults = this._collectResultsInRound(room, round);
|
|
||||||
|
|
||||||
this._broadcastGuess(room, member.userName, guessPosition, distance, score);
|
|
||||||
|
|
||||||
round.results.set(token, { guessPosition: guessPosition, distance: distance, score: score });
|
|
||||||
|
|
||||||
this._setNewTimeout(room, round);
|
|
||||||
|
|
||||||
return { allResults: allResults };
|
|
||||||
}
|
|
||||||
|
|
||||||
nextRound(roomId, currentRound) {
|
|
||||||
if (!this.rooms.has(roomId)) {
|
|
||||||
return { error: 'room_not_found' };
|
|
||||||
}
|
|
||||||
|
|
||||||
var room = this.rooms.get(roomId);
|
|
||||||
room.updated = new Date();
|
|
||||||
|
|
||||||
room.currentRound = currentRound;
|
|
||||||
|
|
||||||
var round = room.rounds[room.currentRound];
|
|
||||||
|
|
||||||
round.timeoutStarted = new Date();
|
|
||||||
var self = this;
|
|
||||||
round.timeoutHandler = setTimeout(function () {
|
|
||||||
self._endRound(room, round);
|
|
||||||
}, round.timeout + MultiGame.ROUND_TIMEOUT_OFFSET);
|
|
||||||
|
|
||||||
var data = {};
|
|
||||||
data.place = { panoId: round.place.panoId, pov: round.place.pov };
|
|
||||||
data.timeout = round.timeout;
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
room.members.forEach(function (member) {
|
|
||||||
self._sendToMember(member, 'new_round', data);
|
|
||||||
});
|
|
||||||
|
|
||||||
return { ok: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
_setNewTimeout(room, round) {
|
|
||||||
clearTimeout(round.timeoutHandler);
|
|
||||||
|
|
||||||
if (room.members.size === round.results.size) {
|
|
||||||
round.timeout = 0;
|
|
||||||
round.timeoutStarted = new Date();
|
|
||||||
|
|
||||||
this._endRound(room, round);
|
|
||||||
} else {
|
|
||||||
round.timeout = round.timeout - (new Date() - round.timeoutStarted);
|
|
||||||
if (round.timeout > MultiGame.ROUND_TIMEOUT_DIVIDER * MultiGame.ROUND_TIMEOUT_MINIMUM) {
|
|
||||||
round.timeout = Math.round(round.timeout / MultiGame.ROUND_TIMEOUT_DIVIDER);
|
|
||||||
} else if (round.timeout > MultiGame.ROUND_TIMEOUT_MINIMUM) {
|
|
||||||
round.timeout = MultiGame.ROUND_TIMEOUT_MINIMUM;
|
|
||||||
}
|
|
||||||
round.timeoutStarted = new Date();
|
|
||||||
var self = this;
|
|
||||||
round.timeoutHandler = setTimeout(function () {
|
|
||||||
self._endRound(room, round);
|
|
||||||
}, round.timeout + MultiGame.ROUND_TIMEOUT_OFFSET);
|
|
||||||
|
|
||||||
this._broadcastTimeout(room, round);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_endRound(room, round) {
|
|
||||||
var allResults = this._collectResultsInRound(room, round);
|
|
||||||
var self = this;
|
|
||||||
room.members.forEach(function (member, token) {
|
|
||||||
var result = { guessPosition: null, distance: null, score: 0 };
|
|
||||||
|
|
||||||
if (round.results.has(token)) {
|
|
||||||
result = round.results.get(token);
|
|
||||||
} else {
|
|
||||||
round.results.set(token, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = { position: round.place.position, result: result, allResults: allResults };
|
|
||||||
self._sendToMember(member, 'end_round', data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_sendInitialData(room, member, token) {
|
|
||||||
var data = {};
|
|
||||||
|
|
||||||
if (room.currentRound >= 0) {
|
|
||||||
var round = room.rounds[room.currentRound];
|
|
||||||
|
|
||||||
data.place = round.place;
|
|
||||||
data.timeout = round.timeout - (new Date() - round.timeoutStarted);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.history = [];
|
|
||||||
for (var i = 0; i <= room.currentRound; ++i) {
|
|
||||||
var round = room.rounds[i];
|
|
||||||
|
|
||||||
if (i === room.currentRound && !round.results.has(token)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
result: result,
|
|
||||||
allResults: allResults
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
data.members = [];
|
|
||||||
room.members.forEach(function (currentMember) {
|
|
||||||
data.members.push({ userName: currentMember.userName, me: member === currentMember });
|
|
||||||
});
|
|
||||||
|
|
||||||
data.readyToContinue = room.currentRound >= 0 && room.members.size === room.rounds[room.currentRound].results.size
|
|
||||||
|
|
||||||
this._sendToMember(member, 'initialize', data);
|
|
||||||
}
|
|
||||||
|
|
||||||
_collectResultsInRound(room, round) {
|
|
||||||
var results = [];
|
|
||||||
round.results.forEach(function (result, token) {
|
|
||||||
results.push({
|
|
||||||
userName: room.members.get(token).userName,
|
|
||||||
guessPosition: result.guessPosition,
|
|
||||||
distance: result.distance,
|
|
||||||
score: result.score
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
_broadcastTimeout(room, round) {
|
|
||||||
var self = this;
|
|
||||||
room.members.forEach(function (member) {
|
|
||||||
self._sendToMember(member, 'timeout_changed', { timeout: round.timeout });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_broadcastGuess(room, userName, guessPosition, distance, score) {
|
|
||||||
var data = { userName: userName, guessPosition: guessPosition, distance: distance, score: score };
|
|
||||||
var round = room.rounds[room.currentRound];
|
|
||||||
var self = this;
|
|
||||||
room.members.forEach(function (member, token) {
|
|
||||||
if (!round.results.has(token)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
var response;
|
|
||||||
switch (data.func) {
|
|
||||||
case 'create_room':
|
|
||||||
response = multiGame.createRoom(data.args.roomId);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'join_room':
|
|
||||||
response = multiGame.joinRoom(data.args.roomId, data.args.token, data.args.userName);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'start_game':
|
|
||||||
response = multiGame.startGame(data.args.roomId, data.args.places);
|
|
||||||
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'guess':
|
|
||||||
response = multiGame.guess(data.args.roomId, data.args.token, data.args.guessPosition, data.args.distance, data.args.score);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'next_round':
|
|
||||||
response = multiGame.nextRound(data.args.roomId, data.args.currentRound);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
Generated
-17
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "mapguesser-multi",
|
|
||||||
"requires": true,
|
|
||||||
"lockfileVersion": 1,
|
|
||||||
"dependencies": {
|
|
||||||
"dotenv": {
|
|
||||||
"version": "8.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
|
||||||
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
|
|
||||||
},
|
|
||||||
"ws": {
|
|
||||||
"version": "7.4.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz",
|
|
||||||
"integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "mapguesser-multi",
|
|
||||||
"version": "",
|
|
||||||
"description": "MapGuesser Application - Multiplayer",
|
|
||||||
"main": "index.js",
|
|
||||||
"dependencies": {
|
|
||||||
"dotenv": "^8.2.0",
|
|
||||||
"ws": "^7.4.4"
|
|
||||||
},
|
|
||||||
"scripts": {},
|
|
||||||
"author": "Pőcze Bence and The MapGuesser Contributors <bence@pocze.ch>",
|
|
||||||
"license": "GNU AGPL 3.0"
|
|
||||||
}
|
|
||||||
+2
-107
@@ -79,7 +79,7 @@
|
|||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#distanceInfo>p:nth-child(2), #distanceInfo>p:nth-child(3), #scoreInfo>p:nth-child(2) {
|
#distanceInfo>p:nth-child(2), #scoreInfo>p:nth-child(2) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,94 +102,13 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#startMultiGameButton {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#players > p {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#countdown {
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
right: 5px;
|
|
||||||
height: 28px;
|
|
||||||
line-height: 28px;
|
|
||||||
padding: 0 8px;
|
|
||||||
background-color: #eeeeee;
|
|
||||||
border: solid 1px #555555;
|
|
||||||
border-radius: 3px;
|
|
||||||
opacity: 0.95;
|
|
||||||
z-index: 5;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#countdown.yellow {
|
|
||||||
background-color: #f7c789;
|
|
||||||
border: solid 1px #e8a349;
|
|
||||||
}
|
|
||||||
|
|
||||||
#countdown.red {
|
|
||||||
background-color: #f7a5a5;
|
|
||||||
border: solid 1px #aa5e5e;
|
|
||||||
}
|
|
||||||
|
|
||||||
#countdown p {
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
#countdown.yellow p {
|
|
||||||
color: #9c4308;
|
|
||||||
}
|
|
||||||
|
|
||||||
#countdown.red p {
|
|
||||||
color: #701919;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation {
|
|
||||||
position: absolute;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation .navigationItem {
|
|
||||||
margin-top: 10px;
|
|
||||||
opacity: 70%;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation .navigationItem:hover {
|
|
||||||
opacity: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation .navigationItem div {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation .circleBackground {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
opacity: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#navigation .navigationIcon {
|
|
||||||
width: 75%;
|
|
||||||
height: 75%;
|
|
||||||
margin: auto;
|
|
||||||
margin-top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
-ms-transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 599px) {
|
@media screen and (max-width: 599px) {
|
||||||
#mapName {
|
#mapName {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
#showGuessButtonContainer {
|
#showGuessButtonContainer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 65px;
|
left: 20px;
|
||||||
bottom: 30px;
|
bottom: 30px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
@@ -206,14 +125,6 @@
|
|||||||
#scoreBarBase {
|
#scoreBarBase {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
#navigation {
|
|
||||||
bottom: 25px;
|
|
||||||
left: 10px;
|
|
||||||
width: 45px;
|
|
||||||
}
|
|
||||||
#navigation .navigationItem {
|
|
||||||
height: 45px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 600px) {
|
@media screen and (min-width: 600px) {
|
||||||
@@ -257,14 +168,6 @@
|
|||||||
#scoreBarBase {
|
#scoreBarBase {
|
||||||
width: 60%;
|
width: 60%;
|
||||||
}
|
}
|
||||||
#navigation {
|
|
||||||
bottom: 50px;
|
|
||||||
left: 20px;
|
|
||||||
width: 60px;
|
|
||||||
}
|
|
||||||
#navigation .navigationItem {
|
|
||||||
height: 60px;
|
|
||||||
}
|
|
||||||
@media screen and (max-height: 424px) {
|
@media screen and (max-height: 424px) {
|
||||||
#guess {
|
#guess {
|
||||||
top: 10px;
|
top: 10px;
|
||||||
@@ -279,13 +182,5 @@
|
|||||||
right: 20px;
|
right: 20px;
|
||||||
bottom: 30px;
|
bottom: 30px;
|
||||||
}
|
}
|
||||||
#navigation {
|
|
||||||
bottom: 30px;
|
|
||||||
left: 10px;
|
|
||||||
width: 45px;
|
|
||||||
}
|
|
||||||
#navigation .navigationItem {
|
|
||||||
height: 45px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,10 +12,6 @@ html, body {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: #cccccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
button::-moz-focus-inner, input::-moz-focus-inner {
|
button::-moz-focus-inner, input::-moz-focus-inner {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
@@ -378,7 +374,6 @@ header>p>span:not(:last-child) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
main {
|
main {
|
||||||
background-color: #ffffff;
|
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 16 16">
|
|
||||||
<circle cx="50%" cy="50%" r="50%" fill="black" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 146 B |
@@ -1,5 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
|
||||||
<polygon id="needleNorth" points="50,0 33,50 66,50" style="fill:red;stroke:black;stroke-width:1" />
|
|
||||||
<polygon id="needleSouth" points="50,100 33,50 66,50" style="fill:white;stroke:black;stroke-width:1" />
|
|
||||||
Sorry, your browser does not support inline SVG.
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 328 B |
@@ -1,5 +0,0 @@
|
|||||||
<!-- Original image: Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. -->
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" fill="#3183ce" viewBox="0 0 16 16">
|
|
||||||
<path fill-rule="evenodd" d="m8 3.293 6 6V13.5a1.5 1.5 0 0 1-1.5 1.5h-9A1.5 1.5 0 0 1 2 13.5V9.293l6-6zm5-.793V6l-2-2V2.5a.5.5 0 0 1 .5-.5h1a.5.5 0 0 1 .5.5z"/>
|
|
||||||
<path fill-rule="evenodd" d="M7.293 1.5a1 1 0 0 1 1.414 0l6.647 6.646a.5.5 0 0 1-.708.708L8 2.207 1.354 8.854a.5.5 0 1 1-.708-.708L7.293 1.5z"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 556 B |
@@ -1,10 +0,0 @@
|
|||||||
<!-- Original image: Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. -->
|
|
||||||
<svg viewBox="0 0 12 16" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path
|
|
||||||
fill="#3183ce"
|
|
||||||
fill-rule="evenodd"
|
|
||||||
stroke="#19456d"
|
|
||||||
stroke-width="0.3"
|
|
||||||
stroke-linecap="round"
|
|
||||||
d="m 5.9999998,15.849652 c 0,0 5.8511182,-5.579947 5.8511182,-9.8134832 a 5.8511179,5.8880898 0 0 0 -11.7022358,0 c 0,4.2335362 5.8511176,9.8134832 5.8511176,9.8134832" />
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 529 B |
+96
-590
@@ -5,8 +5,6 @@
|
|||||||
NUMBER_OF_ROUNDS: 5,
|
NUMBER_OF_ROUNDS: 5,
|
||||||
MAX_SCORE: 1000,
|
MAX_SCORE: 1000,
|
||||||
|
|
||||||
mapBounds: null,
|
|
||||||
multi: { token: null, owner: false },
|
|
||||||
rounds: [],
|
rounds: [],
|
||||||
scoreSum: 0,
|
scoreSum: 0,
|
||||||
panoId: null,
|
panoId: null,
|
||||||
@@ -17,281 +15,41 @@
|
|||||||
adaptGuess: false,
|
adaptGuess: false,
|
||||||
googleLink: null,
|
googleLink: null,
|
||||||
|
|
||||||
readyToContinue: true,
|
|
||||||
timeoutEnd: null,
|
|
||||||
countdownHandler: null,
|
|
||||||
|
|
||||||
MultiConnector: {
|
|
||||||
connection: null,
|
|
||||||
reconnectCounter: 0,
|
|
||||||
|
|
||||||
connect: function () {
|
|
||||||
if (Game.MultiConnector.connection && Game.MultiConnector.connection.readyState !== WebSocket.CLOSED) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Game.MultiConnector.connection = new WebSocket((MapGuesser.isSecure ? 'wss' : 'ws') + '://' + multiUrl);
|
|
||||||
|
|
||||||
Game.MultiConnector.connection.onopen = function () {
|
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
|
||||||
Game.MultiConnector.reconnectCounter = 0;
|
|
||||||
Game.MultiConnector.connection.send(JSON.stringify({ func: 'connect_to_room', args: { roomId: roomId, token: Game.multi.token } }));
|
|
||||||
};
|
|
||||||
|
|
||||||
Game.MultiConnector.connection.onclose = Game.MultiConnector.noConnection;
|
|
||||||
|
|
||||||
Game.MultiConnector.connection.onerror = function (event) {
|
|
||||||
console.error('WebSocket error in Game.MultiConnector:', event);
|
|
||||||
};
|
|
||||||
|
|
||||||
Game.MultiConnector.connection.onmessage = function (message) {
|
|
||||||
var json;
|
|
||||||
|
|
||||||
try {
|
|
||||||
json = JSON.parse(message.data);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Cannot parse message!');
|
|
||||||
console.error(message.data);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (json.type) {
|
|
||||||
case 'initialize':
|
|
||||||
Game.MultiConnector.initialize(json.data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'member_joined':
|
|
||||||
Game.MultiConnector.memberJoined(json.data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'new_round':
|
|
||||||
Game.MultiConnector.newRound(json.data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'guess':
|
|
||||||
Game.MultiConnector.guess(json.data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'timeout_changed':
|
|
||||||
Game.MultiConnector.timeoutChanged(json.data);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'end_round':
|
|
||||||
Game.MultiConnector.endRound(json.data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
noConnection: function () {
|
|
||||||
if (Game.MultiConnector.reconnectCounter === 2) {
|
|
||||||
console.error('Could not reconnect WebSocket for Game.MultiConnector...')
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(function () {
|
|
||||||
Game.MultiConnector.reconnectCounter++;
|
|
||||||
|
|
||||||
console.log('Reconnecting WebSocket for Game.MultiConnector... ' + Game.MultiConnector.reconnectCounter);
|
|
||||||
Game.MultiConnector.connect();
|
|
||||||
}, 1000 + Math.min(Game.MultiConnector.reconnectCounter * 500, 9000));
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function (data) {
|
|
||||||
Game.readyToContinue = false;
|
|
||||||
|
|
||||||
if (data.history.length === 0 && !data.place) {
|
|
||||||
var div = document.getElementById('players');
|
|
||||||
|
|
||||||
for (var i = 0; i < data.members.length; ++i) {
|
|
||||||
var member = data.members[i];
|
|
||||||
|
|
||||||
var p = document.createElement('p');
|
|
||||||
p.innerHTML = member.userName + (member.me ? ' (me)' : '');
|
|
||||||
div.appendChild(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < data.history.length; ++i) {
|
|
||||||
var round = data.history[i];
|
|
||||||
Game.rounds.push({ position: round.position, guessPosition: round.result.guessPosition, realMarker: null, guessMarkers: [] });
|
|
||||||
Game.addPositionToResultMap(true);
|
|
||||||
if (round.result.guessPosition) {
|
|
||||||
Game.addGuessPositionToResultMap(round.result.guessPosition, null, true);
|
|
||||||
}
|
|
||||||
Game.scoreSum += round.result.score;
|
|
||||||
|
|
||||||
for (var j = 0; j < round.allResults.length; ++j) {
|
|
||||||
var result = round.allResults[j];
|
|
||||||
if (result.guessPosition) {
|
|
||||||
Game.addGuessPositionToResultMap(result.guessPosition, result, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
|
||||||
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
|
|
||||||
|
|
||||||
if (data.timeout) {
|
|
||||||
Game.startCountdown(data.timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.place) {
|
|
||||||
Game.readyToContinue = data.readyToContinue;
|
|
||||||
Game.panoId = data.place.panoId;
|
|
||||||
Game.pov = data.place.pov;
|
|
||||||
|
|
||||||
document.getElementById('multi').style.visibility = 'hidden';
|
|
||||||
|
|
||||||
if (Game.rounds.length === 0 || !Game.rounds[Game.rounds.length - 1].position) {
|
|
||||||
document.getElementById('panoCover').style.visibility = 'hidden';
|
|
||||||
Game.startNewRound();
|
|
||||||
} else {
|
|
||||||
Game.loadPano(Game.panoId, Game.pov);
|
|
||||||
Game.showResultFromHistory(data.history[data.history.length - 1].result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
|
||||||
},
|
|
||||||
|
|
||||||
memberJoined: function (data) {
|
|
||||||
var div = document.getElementById('players');
|
|
||||||
|
|
||||||
var p = document.createElement('p');
|
|
||||||
p.innerHTML = data.userName;
|
|
||||||
div.appendChild(p);
|
|
||||||
},
|
|
||||||
|
|
||||||
newRound: function (data) {
|
|
||||||
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
|
|
||||||
Game.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
Game.readyToContinue = false;
|
|
||||||
Game.panoId = data.place.panoId;
|
|
||||||
Game.pov = data.place.pov;
|
|
||||||
|
|
||||||
document.getElementById('multi').style.visibility = 'hidden';
|
|
||||||
Game.resetRound();
|
|
||||||
Game.startNewRound();
|
|
||||||
|
|
||||||
Game.startCountdown(data.timeout);
|
|
||||||
},
|
|
||||||
|
|
||||||
guess: function (data) {
|
|
||||||
var resultBounds = Game.map.getBounds();
|
|
||||||
|
|
||||||
Game.addGuessPositionToResultMap(data.guessPosition, data);
|
|
||||||
resultBounds.extend(data.guessPosition);
|
|
||||||
|
|
||||||
Game.map.fitBounds(resultBounds);
|
|
||||||
},
|
|
||||||
|
|
||||||
timeoutChanged: function (data) {
|
|
||||||
Game.startCountdown(data.timeout);
|
|
||||||
},
|
|
||||||
|
|
||||||
endRound: function (data) {
|
|
||||||
Game.readyToContinue = true;
|
|
||||||
Game.startCountdown(0);
|
|
||||||
|
|
||||||
if (Game.rounds[Game.rounds.length - 1].guessPosition || Game.rounds[Game.rounds.length - 1].position) {
|
|
||||||
if (Game.multi.owner) {
|
|
||||||
document.getElementById('continueButton').disabled = false;
|
|
||||||
document.getElementById('startNewGameButton').disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('guessButton').disabled = true;
|
|
||||||
document.getElementById('panoCover').style.visibility = 'visible';
|
|
||||||
|
|
||||||
Game.receiveResult(data.position, data.result.guessPosition, { distance: data.result.distance, score: data.result.score }, data.allResults);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
prepare: function () {
|
|
||||||
var data = new FormData();
|
|
||||||
var userNames;
|
|
||||||
|
|
||||||
if (roomId) {
|
|
||||||
var userNames = localStorage.userNames ? JSON.parse(localStorage.userNames) : {};
|
|
||||||
if (!userNames.hasOwnProperty(roomId)) {
|
|
||||||
userNames[roomId] = prompt('Your name: ');
|
|
||||||
localStorage.userNames = JSON.stringify(userNames);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.append('userName', userNames[roomId]);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
|
||||||
var url = roomId ? '/multiGame/' + roomId + '/prepare.json' : '/game/' + mapId + '/prepare.json';
|
|
||||||
MapGuesser.httpRequest('POST', url, function () {
|
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
|
||||||
|
|
||||||
if (this.response.error) {
|
|
||||||
Game.handleErrorResponse(this.response.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('mapName').innerHTML = this.response.mapName;
|
|
||||||
Game.mapBounds = this.response.bounds;
|
|
||||||
|
|
||||||
Game.initialize();
|
|
||||||
|
|
||||||
if (roomId) {
|
|
||||||
Game.multi.token = this.response.token;
|
|
||||||
Game.multi.owner = this.response.owner;
|
|
||||||
|
|
||||||
document.getElementById('multi').style.visibility = 'visible';
|
|
||||||
if (Game.multi.owner) {
|
|
||||||
document.getElementById('startMultiGameButton').style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
|
||||||
Game.MultiConnector.connect();
|
|
||||||
}
|
|
||||||
}, data);
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function () {
|
initialize: function () {
|
||||||
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
document.getElementById('panoCover').style.visibility = 'visible';
|
document.getElementById('panoCover').style.visibility = 'visible';
|
||||||
|
document.getElementById('currentRound').innerHTML = '1/' + String(Game.NUMBER_OF_ROUNDS);
|
||||||
|
document.getElementById('currentScoreSum').innerHTML = '0/0';
|
||||||
|
|
||||||
Game.map.setOptions({
|
Game.map.setOptions({
|
||||||
draggableCursor: 'crosshair'
|
draggableCursor: 'crosshair'
|
||||||
});
|
});
|
||||||
Game.map.fitBounds(Game.mapBounds);
|
Game.map.fitBounds(mapBounds);
|
||||||
|
|
||||||
if (roomId) {
|
MapGuesser.httpRequest('GET', '/game/' + mapId + '/newPlace.json', function () {
|
||||||
// if it is multiplayer mode, data is sent via WS
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
|
||||||
MapGuesser.httpRequest('POST', '/game/' + mapId + '/initialData.json', function () {
|
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
document.getElementById('panoCover').style.visibility = 'hidden';
|
document.getElementById('panoCover').style.visibility = 'hidden';
|
||||||
|
|
||||||
if (this.response.error) {
|
if (this.response.error) {
|
||||||
Game.handleErrorResponse(this.response.error);
|
//TODO: handle this error
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game.panoId = this.response.place.panoId;
|
Game.panoId = this.response.panoId;
|
||||||
Game.pov = this.response.place.pov;
|
Game.pov = this.response.pov;
|
||||||
|
|
||||||
for (var i = 0; i < this.response.history.length; ++i) {
|
if (this.response.history) {
|
||||||
var round = this.response.history[i];
|
for (var i = 0; i < this.response.history.length; ++i) {
|
||||||
Game.rounds.push({ position: round.position, guessPosition: round.result.guessPosition, realMarker: null, guessMarkers: [] });
|
var round = this.response.history[i];
|
||||||
Game.addPositionToResultMap(true);
|
Game.rounds.push({ position: round.position, guessPosition: round.guessPosition, realMarker: null, guessMarker: null, line: null });
|
||||||
Game.addGuessPositionToResultMap(round.result.guessPosition, null, true);
|
Game.addRealGuessPair(round.position, round.guessPosition, true);
|
||||||
Game.scoreSum += round.result.score;
|
Game.scoreSum += round.score;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
||||||
|
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
|
||||||
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
|
|
||||||
|
|
||||||
Game.startNewRound();
|
Game.startNewRound();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -305,16 +63,10 @@
|
|||||||
for (var i = 0; i < Game.rounds.length; ++i) {
|
for (var i = 0; i < Game.rounds.length; ++i) {
|
||||||
var round = Game.rounds[i];
|
var round = Game.rounds[i];
|
||||||
|
|
||||||
if (round.realMarker) {
|
if (round.realMarker && round.guessMarker && round.line) {
|
||||||
round.realMarker.setMap(null);
|
round.realMarker.setMap(null);
|
||||||
}
|
round.guessMarker.setMap(null);
|
||||||
for (var j = 0; j < round.guessMarkers.length; ++j) {
|
round.line.setMap(null);
|
||||||
var guessMarker = round.guessMarkers[j];
|
|
||||||
guessMarker.marker.setMap(null);
|
|
||||||
guessMarker.line.setMap(null);
|
|
||||||
if (guessMarker.info) {
|
|
||||||
guessMarker.info.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,21 +76,16 @@
|
|||||||
var distanceInfo = document.getElementById('distanceInfo');
|
var distanceInfo = document.getElementById('distanceInfo');
|
||||||
distanceInfo.children[0].style.display = null;
|
distanceInfo.children[0].style.display = null;
|
||||||
distanceInfo.children[1].style.display = null;
|
distanceInfo.children[1].style.display = null;
|
||||||
distanceInfo.children[2].style.display = null;
|
|
||||||
var scoreInfo = document.getElementById('scoreInfo');
|
var scoreInfo = document.getElementById('scoreInfo');
|
||||||
scoreInfo.children[0].style.display = null;
|
scoreInfo.children[0].style.display = null;
|
||||||
scoreInfo.children[1].style.display = null;
|
scoreInfo.children[1].style.display = null;
|
||||||
document.getElementById('continueButton').style.display = null;
|
document.getElementById('continueButton').style.display = null;
|
||||||
document.getElementById('showSummaryButton').style.display = null;
|
|
||||||
document.getElementById('startNewGameButton').style.display = null;
|
document.getElementById('startNewGameButton').style.display = null;
|
||||||
|
|
||||||
document.getElementById('showGuessButton').style.visibility = null;
|
document.getElementById('showGuessButton').style.visibility = null;
|
||||||
document.getElementById('guess').style.visibility = null;
|
document.getElementById('guess').style.visibility = null;
|
||||||
document.getElementById('guess').classList.remove('result');
|
document.getElementById('guess').classList.remove('result');
|
||||||
|
|
||||||
// needs to be set visible after the show guess map hid it in mobile view
|
|
||||||
document.getElementById("navigation").style.visibility = 'visible';
|
|
||||||
|
|
||||||
Game.initialize();
|
Game.initialize();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -349,71 +96,39 @@
|
|||||||
var lastRound = Game.rounds[Game.rounds.length - 1];
|
var lastRound = Game.rounds[Game.rounds.length - 1];
|
||||||
|
|
||||||
lastRound.realMarker.setVisible(false);
|
lastRound.realMarker.setVisible(false);
|
||||||
for (var i = 0; i < lastRound.guessMarkers.length; ++i) {
|
lastRound.guessMarker.setVisible(false);
|
||||||
var guessMarker = lastRound.guessMarkers[i];
|
lastRound.line.setVisible(false);
|
||||||
guessMarker.marker.setVisible(false);
|
|
||||||
guessMarker.line.setVisible(false);
|
|
||||||
if (guessMarker.info) {
|
|
||||||
guessMarker.info.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('panoCover').style.visibility = 'hidden';
|
document.getElementById('panoCover').style.visibility = 'hidden';
|
||||||
document.getElementById('showGuessButton').style.visibility = null;
|
document.getElementById('showGuessButton').style.visibility = null;
|
||||||
document.getElementById('guess').style.visibility = null;
|
document.getElementById('guess').style.visibility = null;
|
||||||
document.getElementById('guess').classList.remove('result');
|
document.getElementById('guess').classList.remove('result')
|
||||||
|
|
||||||
// needs to be set visible after the show guess map hid it in mobile view
|
|
||||||
document.getElementById("navigation").style.visibility = 'visible';
|
|
||||||
|
|
||||||
Game.map.setOptions({
|
Game.map.setOptions({
|
||||||
draggableCursor: 'crosshair'
|
draggableCursor: 'crosshair'
|
||||||
});
|
});
|
||||||
Game.map.fitBounds(Game.mapBounds);
|
Game.map.fitBounds(mapBounds);
|
||||||
|
|
||||||
if (roomId) {
|
|
||||||
// if it is multiplayer mode, data is sent via WS
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Game.startNewRound();
|
Game.startNewRound();
|
||||||
},
|
},
|
||||||
|
|
||||||
startNewRound: function () {
|
startNewRound: function () {
|
||||||
Game.rounds.push({ position: null, guessPosition: null, realMarker: null, guessMarkers: [] });
|
Game.rounds.push({ position: null, guessPosition: null, realMarker: null, guessMarker: null, line: null });
|
||||||
|
|
||||||
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
||||||
|
|
||||||
Game.loadPano(Game.panoId, Game.pov);
|
Game.loadPano(Game.panoId, Game.pov);
|
||||||
|
|
||||||
// update the compass
|
|
||||||
const heading = Game.panorama.getPov().heading;
|
|
||||||
document.getElementById("compass").style.transform = "translateY(-50%) rotate(" + heading + "deg)";
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleErrorResponse: function (error) {
|
handleErrorResponse: function (error) {
|
||||||
switch (error) {
|
// for the time being we only handle the "no_session_found" error and reset the game
|
||||||
case 'no_session_found':
|
|
||||||
MapGuesser.showModalWithContent('Error', 'Your session is invalid!', [{
|
|
||||||
type: 'button',
|
|
||||||
classNames: [],
|
|
||||||
text: 'Restart game',
|
|
||||||
onclick: function () {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
}]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'game_already_started':
|
MapGuesser.httpRequest('GET', '/game/' + mapId + '/json', function () {
|
||||||
MapGuesser.showModalWithContent('Error', 'This game is already started, you cannot join.');
|
mapBounds = this.response.bounds;
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
Game.reset();
|
||||||
MapGuesser.showModalWithContent('Error', 'Error code: \'' + error + '\'');
|
});
|
||||||
break
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
loadPano: function (panoId, pov) {
|
loadPano: function (panoId, pov) {
|
||||||
@@ -426,106 +141,7 @@
|
|||||||
Game.panorama.setPano(panoId);
|
Game.panorama.setPano(panoId);
|
||||||
},
|
},
|
||||||
|
|
||||||
receiveResult: function (position, guessPosition, result, allResults) {
|
evaluateGuess: function () {
|
||||||
Game.scoreSum += result.score;
|
|
||||||
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
|
|
||||||
|
|
||||||
var resultBounds = new google.maps.LatLngBounds();
|
|
||||||
|
|
||||||
Game.rounds[Game.rounds.length - 1].position = position;
|
|
||||||
Game.addPositionToResultMap();
|
|
||||||
resultBounds.extend(position);
|
|
||||||
|
|
||||||
if (guessPosition) {
|
|
||||||
Game.addGuessPositionToResultMap(guessPosition);
|
|
||||||
resultBounds.extend(guessPosition);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allResults) {
|
|
||||||
for (var i = 0; i < allResults.length; ++i) {
|
|
||||||
var currentResult = allResults[i];
|
|
||||||
if (currentResult.guessPosition) {
|
|
||||||
Game.addGuessPositionToResultMap(currentResult.guessPosition, currentResult);
|
|
||||||
resultBounds.extend(currentResult.guessPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Game.showResultMap(result, resultBounds);
|
|
||||||
},
|
|
||||||
|
|
||||||
showResultFromHistory: function (result) {
|
|
||||||
var round = Game.rounds[Game.rounds.length - 1];
|
|
||||||
var resultBounds = new google.maps.LatLngBounds();
|
|
||||||
|
|
||||||
round.realMarker.setVisible(true);
|
|
||||||
resultBounds.extend(round.position);
|
|
||||||
|
|
||||||
for (var j = 0; j < round.guessMarkers.length; ++j) {
|
|
||||||
var guessMarker = round.guessMarkers[j];
|
|
||||||
guessMarker.marker.setVisible(true);
|
|
||||||
guessMarker.line.setVisible(true);
|
|
||||||
|
|
||||||
resultBounds.extend(guessMarker.marker.getPosition());
|
|
||||||
}
|
|
||||||
|
|
||||||
Game.showResultMap(result, resultBounds);
|
|
||||||
},
|
|
||||||
|
|
||||||
showResultMap: function (result, resultBounds) {
|
|
||||||
// TODO: refactor - it is necessary for mobile
|
|
||||||
if (window.getComputedStyle(document.getElementById('guess')).visibility === 'hidden') {
|
|
||||||
document.getElementById('showGuessButton').click();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Game.adaptGuess) {
|
|
||||||
document.getElementById('guess').classList.remove('adapt');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Game.guessMarker) {
|
|
||||||
Game.guessMarker.setMap(null);
|
|
||||||
Game.guessMarker = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('guess').classList.add('result');
|
|
||||||
|
|
||||||
Game.map.setOptions({
|
|
||||||
draggableCursor: 'grab'
|
|
||||||
});
|
|
||||||
Game.map.fitBounds(resultBounds);
|
|
||||||
|
|
||||||
var distanceInfo = document.getElementById('distanceInfo');
|
|
||||||
if (result.distance === null) {
|
|
||||||
distanceInfo.children[0].style.display = 'none';
|
|
||||||
distanceInfo.children[1].style.display = 'block';
|
|
||||||
} else {
|
|
||||||
distanceInfo.children[0].style.display = 'block';
|
|
||||||
distanceInfo.children[1].style.display = 'none';
|
|
||||||
document.getElementById('distance').innerHTML = Util.printDistanceForHuman(result.distance);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('score').innerHTML = result.score;
|
|
||||||
|
|
||||||
var scoreBarProperties = Game.calculateScoreBarProperties(result.score, Game.MAX_SCORE);
|
|
||||||
var scoreBar = document.getElementById('scoreBar');
|
|
||||||
scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor;
|
|
||||||
scoreBar.style.width = scoreBarProperties.width;
|
|
||||||
|
|
||||||
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
|
|
||||||
document.getElementById('continueButton').style.display = 'none';
|
|
||||||
document.getElementById('showSummaryButton').style.display = 'block';
|
|
||||||
} else if (roomId) {
|
|
||||||
if (Game.multi.owner) {
|
|
||||||
if (!Game.readyToContinue) {
|
|
||||||
document.getElementById('continueButton').disabled = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
document.getElementById('continueButton').style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
guess: function () {
|
|
||||||
if (!Game.guessMarker) {
|
if (!Game.guessMarker) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -534,34 +150,63 @@
|
|||||||
Game.rounds[Game.rounds.length - 1].guessPosition = guessPosition;
|
Game.rounds[Game.rounds.length - 1].guessPosition = guessPosition;
|
||||||
|
|
||||||
document.getElementById('guessButton').disabled = true;
|
document.getElementById('guessButton').disabled = true;
|
||||||
|
if (Game.adaptGuess) {
|
||||||
|
document.getElementById('guess').classList.remove('adapt');
|
||||||
|
}
|
||||||
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
document.getElementById('panoCover').style.visibility = 'visible';
|
document.getElementById('panoCover').style.visibility = 'visible';
|
||||||
|
|
||||||
var data = new FormData();
|
var data = new FormData();
|
||||||
data.append('lat', String(guessPosition.lat));
|
data.append('lat', String(guessPosition.lat));
|
||||||
data.append('lng', String(guessPosition.lng));
|
data.append('lng', String(guessPosition.lng));
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
MapGuesser.httpRequest('POST', '/game/' + mapId + '/guess.json', function () {
|
||||||
var url = roomId ? '/multiGame/' + roomId + '/guess.json' : '/game/' + mapId + '/guess.json';
|
|
||||||
MapGuesser.httpRequest('POST', url, function () {
|
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
|
||||||
|
|
||||||
if (this.response.error) {
|
if (this.response.error) {
|
||||||
Game.handleErrorResponse(this.response.error);
|
Game.handleErrorResponse(this.response.error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Game.receiveResult(this.response.position, guessPosition, this.response.result, this.response.allResults);
|
Game.guessMarker.setMap(null);
|
||||||
|
Game.guessMarker = null;
|
||||||
|
|
||||||
if (this.response.place) {
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
Game.panoId = this.response.place.panoId;
|
document.getElementById('guess').classList.add('result');
|
||||||
Game.pov = this.response.place.pov;
|
|
||||||
|
Game.scoreSum += this.response.result.score;
|
||||||
|
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
|
||||||
|
|
||||||
|
Game.rounds[Game.rounds.length - 1].position = this.response.result.position;
|
||||||
|
Game.addRealGuessPair(this.response.result.position, guessPosition);
|
||||||
|
|
||||||
|
var resultBounds = new google.maps.LatLngBounds();
|
||||||
|
resultBounds.extend(this.response.result.position);
|
||||||
|
resultBounds.extend(guessPosition);
|
||||||
|
|
||||||
|
Game.map.setOptions({
|
||||||
|
draggableCursor: 'grab'
|
||||||
|
});
|
||||||
|
Game.map.fitBounds(resultBounds);
|
||||||
|
|
||||||
|
document.getElementById('distance').innerHTML = Util.printDistanceForHuman(this.response.result.distance);
|
||||||
|
document.getElementById('score').innerHTML = this.response.result.score;
|
||||||
|
|
||||||
|
var scoreBarProperties = Game.calculateScoreBarProperties(this.response.result.score, Game.MAX_SCORE);
|
||||||
|
var scoreBar = document.getElementById('scoreBar');
|
||||||
|
scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor;
|
||||||
|
scoreBar.style.width = scoreBarProperties.width;
|
||||||
|
|
||||||
|
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
|
||||||
|
document.getElementById('continueButton').style.display = 'none';
|
||||||
|
document.getElementById('showSummaryButton').style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Game.panoId = this.response.panoId;
|
||||||
|
Game.pov = this.response.pov;
|
||||||
}, data);
|
}, data);
|
||||||
},
|
},
|
||||||
|
|
||||||
addPositionToResultMap: function (hidden) {
|
addRealGuessPair: function (position, guessPosition, hidden) {
|
||||||
var round = Game.rounds[Game.rounds.length - 1];
|
var round = Game.rounds[Game.rounds.length - 1];
|
||||||
var position = round.position;
|
|
||||||
|
|
||||||
round.realMarker = new google.maps.Marker({
|
round.realMarker = new google.maps.Marker({
|
||||||
map: Game.map,
|
map: Game.map,
|
||||||
@@ -582,25 +227,16 @@
|
|||||||
round.realMarker.addListener('click', function () {
|
round.realMarker.addListener('click', function () {
|
||||||
window.open('https://www.google.com/maps/search/?api=1&query=' + this.getPosition().toUrlValue(), '_blank');
|
window.open('https://www.google.com/maps/search/?api=1&query=' + this.getPosition().toUrlValue(), '_blank');
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
addGuessPositionToResultMap: function (guessPosition, result, hidden) {
|
round.guessMarker = new google.maps.Marker({
|
||||||
var round = Game.rounds[Game.rounds.length - 1];
|
|
||||||
var position = round.position;
|
|
||||||
|
|
||||||
var guessMarker = { marker: null, line: null, info: null };
|
|
||||||
var markerSvg = result ? 'marker-gray-empty.svg' : 'marker-blue-empty.svg';
|
|
||||||
var markerLabel = result ? result.userName.charAt(0).toUpperCase() : '?';
|
|
||||||
|
|
||||||
guessMarker.marker = new google.maps.Marker({
|
|
||||||
map: Game.map,
|
map: Game.map,
|
||||||
visible: !hidden,
|
visible: !hidden,
|
||||||
position: guessPosition,
|
position: guessPosition,
|
||||||
zIndex: Game.rounds.length,
|
zIndex: Game.rounds.length,
|
||||||
clickable: !!result,
|
clickable: false,
|
||||||
draggable: false,
|
draggable: false,
|
||||||
icon: {
|
icon: {
|
||||||
url: STATIC_ROOT + '/img/markers/' + markerSvg + '?rev=' + REVISION,
|
url: STATIC_ROOT + '/img/markers/marker-gray-empty.svg?rev=' + REVISION,
|
||||||
size: new google.maps.Size(24, 32),
|
size: new google.maps.Size(24, 32),
|
||||||
scaledSize: new google.maps.Size(24, 32),
|
scaledSize: new google.maps.Size(24, 32),
|
||||||
anchor: new google.maps.Point(12, 32),
|
anchor: new google.maps.Point(12, 32),
|
||||||
@@ -611,11 +247,11 @@
|
|||||||
fontFamily: 'Roboto',
|
fontFamily: 'Roboto',
|
||||||
fontSize: '16px',
|
fontSize: '16px',
|
||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
text: markerLabel
|
text: '?'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
guessMarker.line = new google.maps.Polyline({
|
round.line = new google.maps.Polyline({
|
||||||
map: Game.map,
|
map: Game.map,
|
||||||
visible: !hidden,
|
visible: !hidden,
|
||||||
path: [
|
path: [
|
||||||
@@ -638,19 +274,6 @@
|
|||||||
draggable: false,
|
draggable: false,
|
||||||
editable: false
|
editable: false
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
|
||||||
guessMarker.info = new google.maps.InfoWindow({
|
|
||||||
content: '<p class="small bold">' + result.userName + '</p>' +
|
|
||||||
'<p class="small">' + Util.printDistanceForHuman(result.distance) + ' | ' + result.score + ' points</p>',
|
|
||||||
});
|
|
||||||
|
|
||||||
guessMarker.marker.addListener('click', function () {
|
|
||||||
guessMarker.info.open(Game.map, this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
round.guessMarkers.push(guessMarker);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
calculateScoreBarProperties: function (score, maxScore) {
|
calculateScoreBarProperties: function (score, maxScore) {
|
||||||
@@ -671,19 +294,12 @@
|
|||||||
showSummary: function () {
|
showSummary: function () {
|
||||||
var distanceInfo = document.getElementById('distanceInfo');
|
var distanceInfo = document.getElementById('distanceInfo');
|
||||||
distanceInfo.children[0].style.display = 'none';
|
distanceInfo.children[0].style.display = 'none';
|
||||||
distanceInfo.children[1].style.display = 'none';
|
distanceInfo.children[1].style.display = 'block';
|
||||||
distanceInfo.children[2].style.display = 'block';
|
|
||||||
var scoreInfo = document.getElementById('scoreInfo');
|
var scoreInfo = document.getElementById('scoreInfo');
|
||||||
scoreInfo.children[0].style.display = 'none';
|
scoreInfo.children[0].style.display = 'none';
|
||||||
scoreInfo.children[1].style.display = 'block';
|
scoreInfo.children[1].style.display = 'block';
|
||||||
document.getElementById('showSummaryButton').style.display = null;
|
document.getElementById('showSummaryButton').style.display = null;
|
||||||
|
document.getElementById('startNewGameButton').style.display = 'block';
|
||||||
if (!roomId || Game.multi.owner) {
|
|
||||||
document.getElementById('startNewGameButton').style.display = 'block';
|
|
||||||
if (!Game.readyToContinue) {
|
|
||||||
document.getElementById('startNewGameButton').disabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var resultBounds = new google.maps.LatLngBounds();
|
var resultBounds = new google.maps.LatLngBounds();
|
||||||
|
|
||||||
@@ -704,17 +320,12 @@
|
|||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
text: String(i + 1)
|
text: String(i + 1)
|
||||||
});
|
});
|
||||||
|
|
||||||
round.realMarker.setVisible(true);
|
round.realMarker.setVisible(true);
|
||||||
|
round.guessMarker.setVisible(true);
|
||||||
|
round.line.setVisible(true);
|
||||||
|
|
||||||
resultBounds.extend(round.position);
|
resultBounds.extend(round.position);
|
||||||
|
resultBounds.extend(round.guessPosition);
|
||||||
for (var j = 0; j < round.guessMarkers.length; ++j) {
|
|
||||||
var guessMarker = round.guessMarkers[j];
|
|
||||||
guessMarker.marker.setVisible(true);
|
|
||||||
guessMarker.line.setVisible(true);
|
|
||||||
|
|
||||||
resultBounds.extend(guessMarker.marker.getPosition());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Game.map.fitBounds(resultBounds);
|
Game.map.fitBounds(resultBounds);
|
||||||
@@ -745,52 +356,6 @@
|
|||||||
Game.googleLink.href = 'https://maps.google.com/maps';
|
Game.googleLink.href = 'https://maps.google.com/maps';
|
||||||
}
|
}
|
||||||
}, 1);
|
}, 1);
|
||||||
},
|
|
||||||
|
|
||||||
startCountdown: function (timeout) {
|
|
||||||
if (Game.countdownHandler) {
|
|
||||||
clearInterval(Game.countdownHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
Game.countdownElement = document.getElementById('countdown');
|
|
||||||
Game.countdownTimeElement = document.getElementById('countdownTime');
|
|
||||||
|
|
||||||
Game.setCountdownTime(Math.round(timeout / 1000));
|
|
||||||
|
|
||||||
if (timeout <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Game.timeoutEnd = new Date(new Date().getTime() + timeout);
|
|
||||||
|
|
||||||
Game.countdownHandler = setInterval(function () {
|
|
||||||
var timeLeft = Math.round((Game.timeoutEnd - new Date()) / 1000);
|
|
||||||
|
|
||||||
Game.setCountdownTime(timeLeft);
|
|
||||||
|
|
||||||
if (timeLeft <= 0) {
|
|
||||||
document.getElementById('panoCover').style.visibility = 'visible';
|
|
||||||
clearInterval(Game.countdownHandler);
|
|
||||||
}
|
|
||||||
}, 1000);
|
|
||||||
},
|
|
||||||
|
|
||||||
setCountdownTime: function (time) {
|
|
||||||
if (time <= 0) {
|
|
||||||
Game.countdownElement.style.visibility = 'hidden';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (time <= 15) {
|
|
||||||
Game.countdownElement.className = 'red';
|
|
||||||
} else if (time <= 30) {
|
|
||||||
Game.countdownElement.className = 'yellow';
|
|
||||||
} else {
|
|
||||||
Game.countdownElement.className = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
Game.countdownElement.style.visibility = 'visible';
|
|
||||||
Game.countdownTimeElement.innerHTML = time;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -808,7 +373,13 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
MapGuesser.sessionAvailableHooks.reinitializeGame = Game.prepare;
|
MapGuesser.sessionAvailableHooks.reinitializeGame = function () {
|
||||||
|
MapGuesser.httpRequest('GET', '/game/' + mapId + '/json', function () {
|
||||||
|
mapBounds = this.response.bounds;
|
||||||
|
|
||||||
|
Game.initialize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (!('ontouchstart' in document.documentElement)) {
|
if (!('ontouchstart' in document.documentElement)) {
|
||||||
Game.adaptGuess = true;
|
Game.adaptGuess = true;
|
||||||
@@ -821,7 +392,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
Game.map.addListener('click', function (e) {
|
Game.map.addListener('click', function (e) {
|
||||||
if (Game.rounds[Game.rounds.length - 1].guessPosition || Game.rounds[Game.rounds.length - 1].position) {
|
if (Game.rounds[Game.rounds.length - 1].guessPosition) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -836,7 +407,7 @@
|
|||||||
clickable: false,
|
clickable: false,
|
||||||
draggable: true,
|
draggable: true,
|
||||||
icon: {
|
icon: {
|
||||||
url: STATIC_ROOT + '/img/markers/marker-blue-empty.svg?rev=' + REVISION,
|
url: STATIC_ROOT + '/img/markers/marker-gray-empty.svg?rev=' + REVISION,
|
||||||
size: new google.maps.Size(24, 32),
|
size: new google.maps.Size(24, 32),
|
||||||
scaledSize: new google.maps.Size(24, 32),
|
scaledSize: new google.maps.Size(24, 32),
|
||||||
anchor: new google.maps.Point(12, 32),
|
anchor: new google.maps.Point(12, 32),
|
||||||
@@ -867,49 +438,26 @@
|
|||||||
|
|
||||||
Game.panorama.addListener('pov_changed', function () {
|
Game.panorama.addListener('pov_changed', function () {
|
||||||
Game.rewriteGoogleLink();
|
Game.rewriteGoogleLink();
|
||||||
|
|
||||||
const heading = Game.panorama.getPov().heading;
|
|
||||||
document.getElementById("compass").style.transform = "translateY(-50%) rotate(" + heading + "deg)";
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (COOKIES_CONSENT) {
|
Game.initialize();
|
||||||
Game.prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('showGuessButton').onclick = function () {
|
document.getElementById('showGuessButton').onclick = function () {
|
||||||
this.style.visibility = 'hidden';
|
this.style.visibility = 'hidden';
|
||||||
document.getElementById('guess').style.visibility = 'visible';
|
document.getElementById('guess').style.visibility = 'visible';
|
||||||
document.getElementById('navigation').style.visibility = 'hidden';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('closeGuessButton').onclick = function () {
|
document.getElementById('closeGuessButton').onclick = function () {
|
||||||
document.getElementById('showGuessButton').style.visibility = null;
|
document.getElementById('showGuessButton').style.visibility = null;
|
||||||
document.getElementById('guess').style.visibility = null;
|
document.getElementById('guess').style.visibility = null;
|
||||||
document.getElementById('navigation').style.visibility = 'visible';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('guessButton').onclick = function () {
|
document.getElementById('guessButton').onclick = function () {
|
||||||
Game.guess();
|
Game.evaluateGuess();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('continueButton').onclick = function () {
|
document.getElementById('continueButton').onclick = function () {
|
||||||
if (roomId) {
|
Game.resetRound();
|
||||||
if (!Game.multi.owner || !Game.readyToContinue) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
|
||||||
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/nextRound.json', function () {
|
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
|
||||||
|
|
||||||
if (this.response.error) {
|
|
||||||
Game.handleErrorResponse(this.response.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Game.resetRound();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('showSummaryButton').onclick = function () {
|
document.getElementById('showSummaryButton').onclick = function () {
|
||||||
@@ -917,48 +465,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('startNewGameButton').onclick = function () {
|
document.getElementById('startNewGameButton').onclick = function () {
|
||||||
if (roomId) {
|
Game.reset();
|
||||||
if (!Game.multi.owner) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
|
||||||
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/initialData.json', function () {
|
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
|
||||||
|
|
||||||
if (this.response.error) {
|
|
||||||
Game.handleErrorResponse(this.response.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Game.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('startMultiGameButton').onclick = function () {
|
|
||||||
if (!roomId || !Game.multi.owner) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('multi').style.visibility = 'hidden';
|
|
||||||
|
|
||||||
document.getElementById('loading').style.visibility = 'visible';
|
|
||||||
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/initialData.json', function () {
|
|
||||||
document.getElementById('loading').style.visibility = 'hidden';
|
|
||||||
|
|
||||||
if (this.response.error) {
|
|
||||||
Game.handleErrorResponse(this.response.error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('returnToStart').onclick = function () {
|
|
||||||
Game.loadPano(Game.panoId, Game.pov);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('compassContainer').onclick = function () {
|
|
||||||
Game.panorama.setPov({ heading: 0, pitch: Game.panorama.getPov().pitch });
|
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
@@ -310,21 +310,6 @@
|
|||||||
var placeId = addedPlaces[i].id;
|
var placeId = addedPlaces[i].id;
|
||||||
places[tempId].id = placeId;
|
places[tempId].id = placeId;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
// TODO: check whether marker is already existing on the map for the coordinates
|
|
||||||
// or alternatively block saving for matching coordinates
|
|
||||||
placeMarker: function (latlng) {
|
|
||||||
var marker = L.marker(latlng, {
|
|
||||||
icon: IconCollection.iconBlue,
|
|
||||||
zIndexOffset: 2000
|
|
||||||
})
|
|
||||||
.addTo(MapEditor.map)
|
|
||||||
.on('click', function () {
|
|
||||||
MapEditor.select(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
MapEditor.select(marker);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -355,32 +340,6 @@
|
|||||||
} else {
|
} else {
|
||||||
return { ppi: 72, tileSize: 512, zoomOffset: -1, minZoom: 2, maxZoom: 20 };
|
return { ppi: 72, tileSize: 512, zoomOffset: -1, minZoom: 2, maxZoom: 20 };
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
extractCoordinates: function (coordinatesStr) {
|
|
||||||
var coordinates = { valid: false, latlng: { lat: 0., lng: 0. } };
|
|
||||||
var delimiters = [',', ' ', ';'];
|
|
||||||
|
|
||||||
coordinatesStr = coordinatesStr.trim();
|
|
||||||
if (coordinatesStr.length == 0) {
|
|
||||||
return coordinates;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var delimiter of delimiters) {
|
|
||||||
if (coordinatesStr.indexOf(delimiter) != -1) {
|
|
||||||
|
|
||||||
var coordinatesArr = coordinatesStr.split(delimiter);
|
|
||||||
coordinates.latlng.lat = parseFloat(coordinatesArr[0]);
|
|
||||||
coordinates.latlng.lng = parseFloat(coordinatesArr[1]);
|
|
||||||
|
|
||||||
if (!isNaN(coordinates.latlng.lat) && !isNaN(coordinates.latlng.lng)) {
|
|
||||||
coordinates.valid = true;
|
|
||||||
return coordinates;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return coordinates;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -389,7 +348,16 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
MapEditor.map.on('click', function (e) {
|
MapEditor.map.on('click', function (e) {
|
||||||
MapEditor.placeMarker(e.latlng);
|
var marker = L.marker(e.latlng, {
|
||||||
|
icon: IconCollection.iconBlue,
|
||||||
|
zIndexOffset: 2000
|
||||||
|
})
|
||||||
|
.addTo(MapEditor.map)
|
||||||
|
.on('click', function () {
|
||||||
|
MapEditor.select(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
MapEditor.select(marker);
|
||||||
});
|
});
|
||||||
|
|
||||||
var highResData = Util.getHighResData();
|
var highResData = Util.getHighResData();
|
||||||
@@ -472,31 +440,4 @@
|
|||||||
document.getElementById('deleteButton').onclick = function () {
|
document.getElementById('deleteButton').onclick = function () {
|
||||||
MapEditor.deletePlace();
|
MapEditor.deletePlace();
|
||||||
};
|
};
|
||||||
|
|
||||||
document.getElementById('jumpButton').onclick = function (e) {
|
|
||||||
var coordinatesStr = document.getElementById("jumpCoordinates").value;
|
|
||||||
var coordinates = Util.extractCoordinates(coordinatesStr);
|
|
||||||
|
|
||||||
if (coordinates.valid) {
|
|
||||||
MapEditor.placeMarker(coordinates.latlng);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.getElementById('jumpCoordinates').onkeyup = function (e) {
|
|
||||||
var coordinatesStr = document.getElementById("jumpCoordinates").value;
|
|
||||||
var coordinates = Util.extractCoordinates(coordinatesStr);
|
|
||||||
var jumpButton = document.getElementById("jumpButton");
|
|
||||||
|
|
||||||
if (coordinates.valid) {
|
|
||||||
jumpButton.disabled = false;
|
|
||||||
|
|
||||||
if (e.key == 'Enter') {
|
|
||||||
MapEditor.placeMarker(coordinates.latlng);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
jumpButton.disabled = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
var MapGuesser = {
|
var MapGuesser = {
|
||||||
isSecure: window.location.protocol === 'https:',
|
|
||||||
cookiesAgreed: false,
|
cookiesAgreed: false,
|
||||||
sessionAvailableHooks: {},
|
sessionAvailableHooks: {},
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,12 @@
|
|||||||
var imgContainer = imgContainers[i];
|
var imgContainer = imgContainers[i];
|
||||||
|
|
||||||
var imgSrc = 'https://maps.googleapis.com/maps/api/staticmap?size=350x175&' +
|
var imgSrc = 'https://maps.googleapis.com/maps/api/staticmap?size=350x175&' +
|
||||||
'scale=' + (window.devicePixelRatio >= 2 ? 2 : 1) + '&' +
|
'scale=' + (window.devicePixelRatio >= 2 ? 2 : 1) + '&path=color:0x0000ff40|weight:3|fillcolor:0x0000ff20|' +
|
||||||
'visible=' + imgContainer.dataset.boundSouthLat + ',' + imgContainer.dataset.boundWestLng + '|' +
|
imgContainer.dataset.boundSouthLat + ',' + imgContainer.dataset.boundWestLng + '|' +
|
||||||
imgContainer.dataset.boundNorthLat + ',' + imgContainer.dataset.boundEastLng +
|
imgContainer.dataset.boundNorthLat + ',' + imgContainer.dataset.boundWestLng + '|' +
|
||||||
|
imgContainer.dataset.boundNorthLat + ',' + imgContainer.dataset.boundEastLng + '|' +
|
||||||
|
imgContainer.dataset.boundSouthLat + ',' + imgContainer.dataset.boundEastLng + '|' +
|
||||||
|
imgContainer.dataset.boundSouthLat + ',' + imgContainer.dataset.boundWestLng +
|
||||||
'&key=' + GOOGLE_MAPS_JS_API_KEY;
|
'&key=' + GOOGLE_MAPS_JS_API_KEY;
|
||||||
|
|
||||||
imgContainer.style.backgroundImage = 'url("' + imgSrc + '")';
|
imgContainer.style.backgroundImage = 'url("' + imgSrc + '")';
|
||||||
@@ -73,40 +76,4 @@
|
|||||||
window.onresize = function () {
|
window.onresize = function () {
|
||||||
Maps.calculateDescriptionDivHeights();
|
Maps.calculateDescriptionDivHeights();
|
||||||
};
|
};
|
||||||
|
|
||||||
document.getElementById('multiForm').onsubmit = function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
var roomId = this.elements.roomId.value;
|
|
||||||
if (roomId.length !== 6) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.location.href = '/multiGame/' + this.elements.roomId.value;
|
|
||||||
};
|
|
||||||
|
|
||||||
document.getElementById('multiButton').onclick = function () {
|
|
||||||
MapGuesser.showModal('multi');
|
|
||||||
document.getElementById('createNewRoomButton').href = '/multiGame/new/' + this.dataset.mapId;
|
|
||||||
document.getElementById('multiForm').elements.roomId.select();
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('closePlayModeButton').onclick = function () {
|
|
||||||
MapGuesser.hideModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
document.getElementById('closeMultiButton').onclick = function () {
|
|
||||||
MapGuesser.hideModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
var buttons = document.getElementById('mapContainer').getElementsByClassName('playButton');
|
|
||||||
for (var i = 0; i < buttons.length; i++) {
|
|
||||||
var button = buttons[i];
|
|
||||||
|
|
||||||
button.onclick = function () {
|
|
||||||
MapGuesser.showModal('playMode');
|
|
||||||
document.getElementById('singleButton').href = '/game/' + this.dataset.mapId;
|
|
||||||
document.getElementById('multiButton').dataset.mapId = this.dataset.mapId;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})();
|
})();
|
||||||
@@ -59,25 +59,10 @@ def getRevisionForRef(ref):
|
|||||||
return subprocess.check_output(["git", "rev-list", "-1", ref], cwd=REPO).decode().strip()
|
return subprocess.check_output(["git", "rev-list", "-1", ref], cwd=REPO).decode().strip()
|
||||||
|
|
||||||
def getLatestReleaseTag():
|
def getLatestReleaseTag():
|
||||||
process = subprocess.Popen(["git", "for-each-ref", "refs/tags/Release*", "--sort=-creatordate", "--format=%(refname:short)"], stdout=subprocess.PIPE, cwd=REPO)
|
return subprocess.check_output(["git", "for-each-ref", "refs/tags/Release*", "--count=1", "--sort=-creatordate", "--format=%(refname:short)"], cwd=REPO).decode().strip()
|
||||||
|
|
||||||
for line in process.stdout:
|
|
||||||
tag = line.decode().rstrip()
|
|
||||||
|
|
||||||
if isTagVerified(tag):
|
|
||||||
return tag
|
|
||||||
|
|
||||||
print(f"[WARNING] Tag '{tag}' is not verified, skipping.")
|
|
||||||
|
|
||||||
raise Exception("No verified 'Release*' tag found!")
|
|
||||||
|
|
||||||
def isTagVerified(tag):
|
|
||||||
process = subprocess.run(["git", "tag", "--verify", tag], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=REPO)
|
|
||||||
|
|
||||||
return process.returncode == 0
|
|
||||||
|
|
||||||
def updateRepoFromRemote():
|
def updateRepoFromRemote():
|
||||||
subprocess.call(["git", "fetch", "origin", "--prune", "--prune-tags"], cwd=REPO)
|
subprocess.call(["git", "fetch", "origin", "--prune"], cwd=REPO)
|
||||||
|
|
||||||
def checkoutWorktree(worktreePath, ref):
|
def checkoutWorktree(worktreePath, ref):
|
||||||
subprocess.call(["git", "checkout", "-f", ref], cwd=worktreePath)
|
subprocess.call(["git", "checkout", "-f", ref], cwd=worktreePath)
|
||||||
|
|||||||
+1
-4
@@ -9,14 +9,11 @@ if [ -f ${ROOT_DIR}/installed ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Installing NPM packages..."
|
|
||||||
(cd ${ROOT_DIR}/multi && npm install)
|
|
||||||
|
|
||||||
echo "Installing Yarn packages..."
|
echo "Installing Yarn packages..."
|
||||||
(cd ${ROOT_DIR}/public/static && yarn install)
|
(cd ${ROOT_DIR}/public/static && yarn install)
|
||||||
|
|
||||||
echo "Installing MapGuesser DB..."
|
echo "Installing MapGuesser DB..."
|
||||||
mysql --host=${DB_HOST} --user=${DB_USER} --password=${DB_PASSWORD} ${DB_NAME} < ${ROOT_DIR}/database/mapguesser.sql
|
mysql --host=${DB_HOST} --user=${DB_USER} --password=${DB_PASSWORD} ${DB_NAME} < ${ROOT_DIR}/db/mapguesser.sql
|
||||||
|
|
||||||
echo "Migrating DB..."
|
echo "Migrating DB..."
|
||||||
(cd ${ROOT_DIR} && ./mapg db:migrate)
|
(cd ${ROOT_DIR} && ./mapg db:migrate)
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ else
|
|||||||
(cd ${ROOT_DIR} && composer install --dev)
|
(cd ${ROOT_DIR} && composer install --dev)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Installing NPM packages..."
|
|
||||||
(cd ${ROOT_DIR}/multi && npm install)
|
|
||||||
|
|
||||||
echo "Installing Yarn packages..."
|
echo "Installing Yarn packages..."
|
||||||
(cd ${ROOT_DIR}/public/static && yarn install)
|
(cd ${ROOT_DIR}/public/static && yarn install)
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use MapGuesser\Database\Query\Modify;
|
|||||||
use MapGuesser\Database\Query\Select;
|
use MapGuesser\Database\Query\Select;
|
||||||
use MapGuesser\Interfaces\Database\IResultSet;
|
use MapGuesser\Interfaces\Database\IResultSet;
|
||||||
use MapGuesser\PersistentData\PersistentDataManager;
|
use MapGuesser\PersistentData\PersistentDataManager;
|
||||||
use MapGuesser\Repository\MultiRoomRepository;
|
|
||||||
use MapGuesser\Repository\UserConfirmationRepository;
|
use MapGuesser\Repository\UserConfirmationRepository;
|
||||||
use MapGuesser\Repository\UserPasswordResetterRepository;
|
use MapGuesser\Repository\UserPasswordResetterRepository;
|
||||||
use MapGuesser\Repository\UserRepository;
|
use MapGuesser\Repository\UserRepository;
|
||||||
@@ -23,8 +22,6 @@ class MaintainDatabaseCommand extends Command
|
|||||||
|
|
||||||
private UserPasswordResetterRepository $userPasswordResetterRepository;
|
private UserPasswordResetterRepository $userPasswordResetterRepository;
|
||||||
|
|
||||||
private MultiRoomRepository $multiRoomRepository;
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
@@ -33,7 +30,6 @@ class MaintainDatabaseCommand extends Command
|
|||||||
$this->userRepository = new UserRepository();
|
$this->userRepository = new UserRepository();
|
||||||
$this->userConfirmationRepository = new UserConfirmationRepository();
|
$this->userConfirmationRepository = new UserConfirmationRepository();
|
||||||
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
|
$this->userPasswordResetterRepository = new UserPasswordResetterRepository();
|
||||||
$this->multiRoomRepository = new MultiRoomRepository();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configure(): void
|
public function configure(): void
|
||||||
@@ -47,7 +43,6 @@ class MaintainDatabaseCommand extends Command
|
|||||||
try {
|
try {
|
||||||
$this->deleteInactiveExpiredUsers();
|
$this->deleteInactiveExpiredUsers();
|
||||||
$this->deleteExpiredPasswordResetters();
|
$this->deleteExpiredPasswordResetters();
|
||||||
$this->deleteExpiredRooms();
|
|
||||||
$this->deleteExpiredSessions();
|
$this->deleteExpiredSessions();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$output->writeln('<error>Maintenance failed!</error>');
|
$output->writeln('<error>Maintenance failed!</error>');
|
||||||
@@ -94,13 +89,6 @@ class MaintainDatabaseCommand extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function deleteExpiredRooms(): void
|
|
||||||
{
|
|
||||||
foreach ($this->multiRoomRepository->getAllExpired() as $multiRoom) {
|
|
||||||
$this->pdm->deleteFromDb($multiRoom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function deleteExpiredSessions(): void
|
private function deleteExpiredSessions(): void
|
||||||
{
|
{
|
||||||
//TODO: model may be used for sessions too
|
//TODO: model may be used for sessions too
|
||||||
|
|||||||
@@ -1,37 +1,20 @@
|
|||||||
<?php namespace MapGuesser\Controller;
|
<?php namespace MapGuesser\Controller;
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use Faker\Factory;
|
|
||||||
use MapGuesser\Interfaces\Request\IRequest;
|
use MapGuesser\Interfaces\Request\IRequest;
|
||||||
use MapGuesser\Response\HtmlContent;
|
use MapGuesser\Response\HtmlContent;
|
||||||
use MapGuesser\Response\JsonContent;
|
use MapGuesser\Response\JsonContent;
|
||||||
use MapGuesser\Interfaces\Response\IContent;
|
use MapGuesser\Interfaces\Response\IContent;
|
||||||
use MapGuesser\Interfaces\Response\IRedirect;
|
|
||||||
use MapGuesser\Multi\MultiConnector;
|
|
||||||
use MapGuesser\PersistentData\Model\MultiRoom;
|
|
||||||
use MapGuesser\PersistentData\PersistentDataManager;
|
|
||||||
use MapGuesser\Repository\MapRepository;
|
use MapGuesser\Repository\MapRepository;
|
||||||
use MapGuesser\Repository\MultiRoomRepository;
|
|
||||||
use MapGuesser\Response\Redirect;
|
|
||||||
|
|
||||||
class GameController
|
class GameController
|
||||||
{
|
{
|
||||||
private IRequest $request;
|
private IRequest $request;
|
||||||
|
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
private MultiConnector $multiConnector;
|
|
||||||
|
|
||||||
private MultiRoomRepository $multiRoomRepository;
|
|
||||||
|
|
||||||
private MapRepository $mapRepository;
|
private MapRepository $mapRepository;
|
||||||
|
|
||||||
public function __construct(IRequest $request)
|
public function __construct(IRequest $request)
|
||||||
{
|
{
|
||||||
$this->request = $request;
|
$this->request = $request;
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
$this->multiConnector = new MultiConnector();
|
|
||||||
$this->multiRoomRepository = new MultiRoomRepository();
|
|
||||||
$this->mapRepository = new MapRepository();
|
$this->mapRepository = new MapRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,131 +22,30 @@ class GameController
|
|||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) $this->request->query('mapId');
|
||||||
|
|
||||||
return new HtmlContent('game', ['mapId' => $mapId]);
|
return new HtmlContent('game', $this->prepareGame($mapId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getNewMultiGame(): IRedirect
|
public function getGameJson(): IContent
|
||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) $this->request->query('mapId');
|
||||||
$map = $this->mapRepository->getById($mapId);
|
|
||||||
$roomId = bin2hex(random_bytes(3));
|
|
||||||
$token = $this->getMultiToken($roomId);
|
|
||||||
|
|
||||||
$room = new MultiRoom();
|
return new JsonContent($this->prepareGame($mapId));
|
||||||
$room->setRoomId($roomId);
|
|
||||||
$room->setStateArray([
|
|
||||||
'mapId' => $mapId,
|
|
||||||
'area' => $map->getArea(),
|
|
||||||
'rounds' => [],
|
|
||||||
'currentRound' => -1
|
|
||||||
]);
|
|
||||||
$room->setMembersArray(['owner' => $token, 'all' => []]);
|
|
||||||
$room->setUpdatedDate(new DateTime());
|
|
||||||
|
|
||||||
$this->pdm->saveToDb($room);
|
|
||||||
|
|
||||||
$this->multiConnector->sendMessage('create_room', ['roomId' => $roomId]);
|
|
||||||
|
|
||||||
return new Redirect(
|
|
||||||
\Container::$routeCollection
|
|
||||||
->getRoute('multiGame')
|
|
||||||
->generateLink(['roomId' => $roomId]),
|
|
||||||
IRedirect::TEMPORARY
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMultiGame(): IContent
|
private function prepareGame(int $mapId): array
|
||||||
{
|
{
|
||||||
$roomId = $this->request->query('roomId');
|
|
||||||
|
|
||||||
return new HtmlContent('game', ['roomId' => $roomId]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function prepareGame(): IContent
|
|
||||||
{
|
|
||||||
$mapId = (int) $this->request->query('mapId');
|
|
||||||
$map = $this->mapRepository->getById($mapId);
|
$map = $this->mapRepository->getById($mapId);
|
||||||
|
|
||||||
$session = $this->request->session();
|
$session = $this->request->session();
|
||||||
|
|
||||||
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
||||||
$session->set('state', [
|
$session->set('state', [
|
||||||
'mapId' => $mapId,
|
'mapId' => $mapId,
|
||||||
'area' => $map->getArea(),
|
'area' => $map->getArea(),
|
||||||
'rounds' => [],
|
'rounds' => []
|
||||||
'currentRound' => -1
|
|
||||||
]);
|
]);
|
||||||
} else { // update the area of the map in the session in any case
|
|
||||||
$state['area'] = $map->getArea();
|
|
||||||
$session->set('state', $state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JsonContent([
|
return ['mapId' => $mapId, 'mapName' => $map->getName(), 'bounds' => $map->getBounds()->toArray()];
|
||||||
'mapId' => $mapId,
|
|
||||||
'mapName' => $map->getName(),
|
|
||||||
'bounds' => $map->getBounds()->toArray()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function prepareMultiGame(): IContent
|
|
||||||
{
|
|
||||||
$roomId = $this->request->query('roomId');
|
|
||||||
$userName = $this->request->post('userName');
|
|
||||||
if (empty($userName)) {
|
|
||||||
$faker = Factory::create();
|
|
||||||
$userName = $faker->userName;
|
|
||||||
}
|
|
||||||
|
|
||||||
$room = $this->multiRoomRepository->getByRoomId($roomId);
|
|
||||||
$state = $room->getStateArray();
|
|
||||||
$map = $this->mapRepository->getById($state['mapId']);
|
|
||||||
$token = $this->getMultiToken($roomId);
|
|
||||||
|
|
||||||
$members = $room->getMembersArray();
|
|
||||||
|
|
||||||
if (!in_array($token, $members['all'])) {
|
|
||||||
if ($state['currentRound'] >= 0) {
|
|
||||||
return new JsonContent(['error' => 'game_already_started']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$members['all'][] = $token;
|
|
||||||
}
|
|
||||||
|
|
||||||
$room->setMembersArray($members);
|
|
||||||
$room->setUpdatedDate(new DateTime());
|
|
||||||
|
|
||||||
$this->pdm->saveToDb($room);
|
|
||||||
|
|
||||||
$this->multiConnector->sendMessage('join_room', [
|
|
||||||
'roomId' => $roomId,
|
|
||||||
'token' => $token,
|
|
||||||
'userName' => $userName
|
|
||||||
]);
|
|
||||||
|
|
||||||
return new JsonContent([
|
|
||||||
'roomId' => $roomId,
|
|
||||||
'token' => $token,
|
|
||||||
'owner' => $members['owner'] == $token,
|
|
||||||
'mapId' => $state['mapId'],
|
|
||||||
'mapName' => $map->getName(),
|
|
||||||
'bounds' => $map->getBounds()->toArray()
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getMultiToken(string $roomId): string
|
|
||||||
{
|
|
||||||
$session = $this->request->session();
|
|
||||||
|
|
||||||
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
|
||||||
$token = bin2hex(random_bytes(16));
|
|
||||||
|
|
||||||
$session->set('multiState', [
|
|
||||||
'roomId' => $roomId,
|
|
||||||
'token' => $token
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
$token = $multiState['token'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $token;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
<?php namespace MapGuesser\Controller;
|
<?php namespace MapGuesser\Controller;
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use MapGuesser\Interfaces\Request\IRequest;
|
use MapGuesser\Interfaces\Request\IRequest;
|
||||||
use MapGuesser\Util\Geo\Position;
|
use MapGuesser\Util\Geo\Position;
|
||||||
use MapGuesser\Response\JsonContent;
|
use MapGuesser\Response\JsonContent;
|
||||||
use MapGuesser\Interfaces\Response\IContent;
|
use MapGuesser\Interfaces\Response\IContent;
|
||||||
use MapGuesser\Multi\MultiConnector;
|
use MapGuesser\PersistentData\Model\Place;
|
||||||
use MapGuesser\PersistentData\PersistentDataManager;
|
|
||||||
use MapGuesser\Repository\MultiRoomRepository;
|
|
||||||
use MapGuesser\Repository\PlaceRepository;
|
use MapGuesser\Repository\PlaceRepository;
|
||||||
|
|
||||||
class GameFlowController
|
class GameFlowController
|
||||||
@@ -17,226 +14,129 @@ class GameFlowController
|
|||||||
|
|
||||||
private IRequest $request;
|
private IRequest $request;
|
||||||
|
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
private MultiConnector $multiConnector;
|
|
||||||
|
|
||||||
private MultiRoomRepository $multiRoomRepository;
|
|
||||||
|
|
||||||
private PlaceRepository $placeRepository;
|
private PlaceRepository $placeRepository;
|
||||||
|
|
||||||
public function __construct(IRequest $request)
|
public function __construct(IRequest $request)
|
||||||
{
|
{
|
||||||
$this->request = $request;
|
$this->request = $request;
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
$this->multiConnector = new MultiConnector();
|
|
||||||
$this->multiRoomRepository = new MultiRoomRepository();
|
|
||||||
$this->placeRepository = new PlaceRepository();
|
$this->placeRepository = new PlaceRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function initialData(): IContent
|
public function getNewPlace(): IContent
|
||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) $this->request->query('mapId');
|
||||||
|
|
||||||
$session = $this->request->session();
|
$session = $this->request->session();
|
||||||
|
|
||||||
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
||||||
return new JsonContent(['error' => 'no_session_found']);
|
return new JsonContent(['error' => 'no_session_found']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset($state['currentRound']) || $state['currentRound'] == -1 || $state['currentRound'] >= static::NUMBER_OF_ROUNDS) {
|
if (count($state['rounds']) === 0) {
|
||||||
$this->startNewGame($state, $mapId);
|
$placesWithoutPano = [];
|
||||||
|
$place = $this->placeRepository->getRandomForMapWithValidPano($mapId, [], $placesWithoutPano);
|
||||||
|
|
||||||
|
$this->addNewRoundToState($state, $place, $placesWithoutPano);
|
||||||
|
|
||||||
$session->set('state', $state);
|
$session->set('state', $state);
|
||||||
}
|
|
||||||
|
|
||||||
$response = [];
|
$data = [
|
||||||
|
'panoId' => $place->getPanoIdCached(),
|
||||||
|
'pov' => $place->getPov()->toArray()
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$rounds = count($state['rounds']);
|
||||||
|
$last = $state['rounds'][$rounds - 1];
|
||||||
|
|
||||||
$last = $state['rounds'][$state['currentRound']];
|
$history = [];
|
||||||
$response['place'] = [
|
for ($i = 0; $i < $rounds - 1; ++$i) {
|
||||||
'panoId' => $last['panoId'],
|
$round = $state['rounds'][$i];
|
||||||
'pov' => $last['pov']->toArray()
|
$history[] = [
|
||||||
];
|
'position' => $round['position']->toArray(),
|
||||||
|
|
||||||
$response['history'] = [];
|
|
||||||
for ($i = 0; $i < $state['currentRound']; ++$i) {
|
|
||||||
$round = $state['rounds'][$i];
|
|
||||||
$response['history'][] = [
|
|
||||||
'position' => $round['position']->toArray(),
|
|
||||||
'result' => [
|
|
||||||
'guessPosition' => $round['guessPosition']->toArray(),
|
'guessPosition' => $round['guessPosition']->toArray(),
|
||||||
'distance' => $round['distance'],
|
'distance' => $round['distance'],
|
||||||
'score' => $round['score']
|
'score' => $round['score']
|
||||||
]
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'history' => $history,
|
||||||
|
'panoId' => $last['panoId'],
|
||||||
|
'pov' => isset($last['pov']) ? // should be checked not to break with old sessions
|
||||||
|
$last['pov']->toArray() :
|
||||||
|
['heading' => 0.0, 'pitch' => 0.0, 'zoom' => 0.0],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JsonContent($response);
|
return new JsonContent($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function multiInitialData(): IContent
|
public function evaluateGuess(): IContent
|
||||||
{
|
|
||||||
$roomId = $this->request->query('roomId');
|
|
||||||
$session = $this->request->session();
|
|
||||||
|
|
||||||
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
|
||||||
return new JsonContent(['error' => 'no_session_found']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$room = $this->multiRoomRepository->getByRoomId($roomId);
|
|
||||||
$state = $room->getStateArray();
|
|
||||||
$members = $room->getMembersArray();
|
|
||||||
|
|
||||||
if ($members['owner'] !== $multiState['token']) {
|
|
||||||
return new JsonContent(['error' => 'not_owner_of_room']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($state['currentRound'] == -1 || $state['currentRound'] >= static::NUMBER_OF_ROUNDS - 1) {
|
|
||||||
$this->startNewGame($state, $state['mapId']);
|
|
||||||
$room->setStateArray($state);
|
|
||||||
$room->setUpdatedDate(new DateTime());
|
|
||||||
$this->pdm->saveToDb($room);
|
|
||||||
}
|
|
||||||
|
|
||||||
$places = [];
|
|
||||||
foreach ($state['rounds'] as $round) {
|
|
||||||
$places[] = [
|
|
||||||
'position' => $round['position']->toArray(),
|
|
||||||
'panoId' => $round['panoId'],
|
|
||||||
'pov' => $round['pov']->toArray()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->multiConnector->sendMessage('start_game', ['roomId' => $roomId, 'places' => $places]);
|
|
||||||
|
|
||||||
return new JsonContent(['ok' => true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function guess(): IContent
|
|
||||||
{
|
{
|
||||||
$mapId = (int) $this->request->query('mapId');
|
$mapId = (int) $this->request->query('mapId');
|
||||||
|
|
||||||
$session = $this->request->session();
|
$session = $this->request->session();
|
||||||
|
|
||||||
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) {
|
||||||
return new JsonContent(['error' => 'no_session_found']);
|
return new JsonContent(['error' => 'no_session_found']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$last = $state['rounds'][$state['currentRound']];
|
$last = $state['rounds'][count($state['rounds']) - 1];
|
||||||
|
|
||||||
|
$position = $last['position'];
|
||||||
$guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng'));
|
$guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng'));
|
||||||
$result = $this->evalueteGuess($last['position'], $guessPosition, $state['area']);
|
|
||||||
|
$distance = $this->calculateDistance($position, $guessPosition);
|
||||||
|
$score = $this->calculateScore($distance, $state['area']);
|
||||||
|
|
||||||
$last['guessPosition'] = $guessPosition;
|
$last['guessPosition'] = $guessPosition;
|
||||||
$last['distance'] = $result['distance'];
|
$last['distance'] = $distance;
|
||||||
$last['score'] = $result['score'];
|
$last['score'] = $score;
|
||||||
|
$state['rounds'][count($state['rounds']) - 1] = $last;
|
||||||
|
|
||||||
$response = [
|
if (count($state['rounds']) < static::NUMBER_OF_ROUNDS) {
|
||||||
'position' => $last['position']->toArray(),
|
$exclude = [];
|
||||||
'result' => $result
|
|
||||||
];
|
|
||||||
|
|
||||||
$state['rounds'][$state['currentRound']] = $last;
|
foreach ($state['rounds'] as $round) {
|
||||||
$state['currentRound'] += 1;
|
$exclude = array_merge($exclude, $round['placesWithoutPano'], [$round['placeId']]);
|
||||||
if ($state['currentRound'] < static::NUMBER_OF_ROUNDS) {
|
}
|
||||||
$next = $state['rounds'][$state['currentRound']];
|
|
||||||
|
|
||||||
$response['place'] = [
|
$placesWithoutPano = [];
|
||||||
'panoId' => $next['panoId'],
|
$place = $this->placeRepository->getRandomForMapWithValidPano($mapId, $exclude, $placesWithoutPano);
|
||||||
'pov' => $next['pov']->toArray()
|
|
||||||
];
|
$this->addNewRoundToState($state, $place, $placesWithoutPano);
|
||||||
|
|
||||||
|
$panoId = $place->getPanoIdCached();
|
||||||
|
$pov = $place->getPov()->toArray();
|
||||||
|
} else {
|
||||||
|
$state['rounds'] = [];
|
||||||
|
|
||||||
|
$panoId = null;
|
||||||
|
$pov = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$session->set('state', $state);
|
$session->set('state', $state);
|
||||||
|
|
||||||
return new JsonContent($response);
|
return new JsonContent([
|
||||||
}
|
'result' => [
|
||||||
|
'position' => $position->toArray(),
|
||||||
public function multiGuess(): IContent
|
'distance' => $distance,
|
||||||
{
|
'score' => $score
|
||||||
$roomId = $this->request->query('roomId');
|
],
|
||||||
$session = $this->request->session();
|
'panoId' => $panoId,
|
||||||
|
'pov' => $pov
|
||||||
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
|
||||||
return new JsonContent(['error' => 'no_session_found']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$room = $this->multiRoomRepository->getByRoomId($roomId);
|
|
||||||
$state = $room->getStateArray();
|
|
||||||
|
|
||||||
$last = $state['rounds'][$state['currentRound']];
|
|
||||||
$guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng'));
|
|
||||||
$result = $this->evalueteGuess($last['position'], $guessPosition, $state['area']);
|
|
||||||
|
|
||||||
$responseFromMulti = $this->multiConnector->sendMessage('guess', [
|
|
||||||
'roomId' => $roomId,
|
|
||||||
'token' => $multiState['token'],
|
|
||||||
'guessPosition' => $guessPosition->toArray(),
|
|
||||||
'distance' => $result['distance'],
|
|
||||||
'score' => $result['score']
|
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($responseFromMulti['error'])) {
|
private function addNewRoundToState(array &$state, Place $place, array $placesWithoutPano): void
|
||||||
return new JsonContent(['error' => $responseFromMulti['error']]);
|
{
|
||||||
}
|
$state['rounds'][] = [
|
||||||
|
'placesWithoutPano' => $placesWithoutPano,
|
||||||
$response = [
|
'placeId' => $place->getId(),
|
||||||
'position' => $last['position']->toArray(),
|
'position' => $place->getPosition(),
|
||||||
'result' => $result,
|
'panoId' => $place->getPanoIdCached(),
|
||||||
'allResults' => $responseFromMulti['allResults']
|
'pov' => $place->getPov()
|
||||||
];
|
];
|
||||||
|
|
||||||
return new JsonContent($response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function multiNextRound(): IContent
|
|
||||||
{
|
|
||||||
$roomId = $this->request->query('roomId');
|
|
||||||
$session = $this->request->session();
|
|
||||||
|
|
||||||
if (!($multiState = $session->get('multiState')) || $multiState['roomId'] !== $roomId) {
|
|
||||||
return new JsonContent(['error' => 'no_session_found']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$room = $this->multiRoomRepository->getByRoomId($roomId);
|
|
||||||
$state = $room->getStateArray();
|
|
||||||
$members = $room->getMembersArray();
|
|
||||||
|
|
||||||
if ($members['owner'] !== $multiState['token']) {
|
|
||||||
return new JsonContent(['error' => 'not_owner_of_room']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$state['currentRound'] += 1;
|
|
||||||
if ($state['currentRound'] < static::NUMBER_OF_ROUNDS) {
|
|
||||||
$this->multiConnector->sendMessage('next_round', ['roomId' => $roomId, 'currentRound' => $state['currentRound']]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$room->setStateArray($state);
|
|
||||||
$room->setUpdatedDate(new DateTime());
|
|
||||||
$this->pdm->saveToDb($room);
|
|
||||||
|
|
||||||
return new JsonContent(['ok' => true]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function evalueteGuess(Position $realPosition, Position $guessPosition, float $area)
|
|
||||||
{
|
|
||||||
$distance = $this->calculateDistance($realPosition, $guessPosition);
|
|
||||||
$score = $this->calculateScore($distance, $area);
|
|
||||||
|
|
||||||
return ['distance' => $distance, 'score' => $score];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function startNewGame(array &$state, int $mapId): void
|
|
||||||
{
|
|
||||||
$places = $this->placeRepository->getRandomNForMapWithValidPano($mapId, static::NUMBER_OF_ROUNDS);
|
|
||||||
|
|
||||||
$state['rounds'] = [];
|
|
||||||
$state['currentRound'] = 0;
|
|
||||||
|
|
||||||
foreach ($places as $place) {
|
|
||||||
$state['rounds'][] = [
|
|
||||||
'placeId' => $place->getId(),
|
|
||||||
'position' => $place->getPosition(),
|
|
||||||
'panoId' => $place->getPanoIdCached(),
|
|
||||||
'pov' => $place->getPov()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function calculateDistance(Position $realPosition, Position $guessPosition): float
|
private function calculateDistance(Position $realPosition, Position $guessPosition): float
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
<?php namespace MapGuesser\Multi;
|
|
||||||
|
|
||||||
class MultiConnector
|
|
||||||
{
|
|
||||||
public function sendMessage(string $func, array $args = [])
|
|
||||||
{
|
|
||||||
$message = json_encode([
|
|
||||||
'func' => $func,
|
|
||||||
'args' => $args
|
|
||||||
]);
|
|
||||||
|
|
||||||
$connection = fsockopen($_ENV['MULTI_INTERNAL_HOST'], $_ENV['MULTI_INTERNAL_PORT']);
|
|
||||||
fwrite($connection, $message);
|
|
||||||
$response = '';
|
|
||||||
while (!feof($connection)) {
|
|
||||||
$response .= fgets($connection);
|
|
||||||
}
|
|
||||||
fclose($connection);
|
|
||||||
|
|
||||||
return json_decode($response, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
<?php namespace MapGuesser\PersistentData\Model;
|
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
|
|
||||||
class MultiRoom extends Model
|
|
||||||
{
|
|
||||||
protected static string $table = 'multi_rooms';
|
|
||||||
|
|
||||||
protected static array $fields = ['room_id', 'state', 'members', 'updated'];
|
|
||||||
|
|
||||||
private string $roomId = '';
|
|
||||||
|
|
||||||
private array $state = [];
|
|
||||||
|
|
||||||
private array $members = [];
|
|
||||||
|
|
||||||
private DateTime $updated;
|
|
||||||
|
|
||||||
public function setRoomId(string $roomId): void
|
|
||||||
{
|
|
||||||
$this->roomId = $roomId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setStateArray(array $state): void
|
|
||||||
{
|
|
||||||
$this->state = $state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setMembersArray(array $members): void
|
|
||||||
{
|
|
||||||
$this->members = $members;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setState(string $state): void
|
|
||||||
{
|
|
||||||
$this->state = unserialize($state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setMembers(string $members): void
|
|
||||||
{
|
|
||||||
$this->members = unserialize($members);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setUpdatedDate(DateTime $updated): void
|
|
||||||
{
|
|
||||||
$this->updated = $updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setUpdated(string $updated): void
|
|
||||||
{
|
|
||||||
$this->updated = new DateTime($updated);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRoomId(): string
|
|
||||||
{
|
|
||||||
return $this->roomId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getStateArray(): array
|
|
||||||
{
|
|
||||||
return $this->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getState(): string
|
|
||||||
{
|
|
||||||
return serialize($this->state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMembersArray(): array
|
|
||||||
{
|
|
||||||
return $this->members;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMembers(): string
|
|
||||||
{
|
|
||||||
return serialize($this->members);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUpdatedDate(): DateTime
|
|
||||||
{
|
|
||||||
return $this->updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUpdated(): string
|
|
||||||
{
|
|
||||||
return $this->updated->format('Y-m-d H:i:s');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?php namespace MapGuesser\Repository;
|
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
use Generator;
|
|
||||||
use MapGuesser\Database\Query\Select;
|
|
||||||
use MapGuesser\PersistentData\Model\MultiRoom;
|
|
||||||
use MapGuesser\PersistentData\PersistentDataManager;
|
|
||||||
|
|
||||||
class MultiRoomRepository
|
|
||||||
{
|
|
||||||
private PersistentDataManager $pdm;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$this->pdm = new PersistentDataManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getById(int $id): ?MultiRoom
|
|
||||||
{
|
|
||||||
return $this->pdm->selectFromDbById($id, MultiRoom::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getByRoomId(string $roomId): ?MultiRoom
|
|
||||||
{
|
|
||||||
$select = new Select(\Container::$dbConnection);
|
|
||||||
$select->where('room_id', '=', $roomId);
|
|
||||||
|
|
||||||
return $this->pdm->selectFromDb($select, MultiRoom::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAllExpired(): Generator
|
|
||||||
{
|
|
||||||
$select = new Select(\Container::$dbConnection);
|
|
||||||
$select->where('updated', '<', (new DateTime('-7 day'))->format('Y-m-d H:i:s'));
|
|
||||||
|
|
||||||
yield from $this->pdm->selectMultipleFromDb($select, MultiRoom::class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,29 +29,17 @@ class PlaceRepository
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO: use Map instead of id
|
//TODO: use Map instead of id
|
||||||
public function getRandomNForMapWithValidPano(int $mapId, int $n, array $exclude = []): array
|
public function getRandomForMapWithValidPano(int $mapId, array $exclude = [], array &$placesWithoutPano): Place
|
||||||
{
|
{
|
||||||
$places = [];
|
$placesWithoutPano = [];
|
||||||
|
|
||||||
for ($i = 1; $i <= $n; ++$i) {
|
|
||||||
$place = $this->getRandomForMapWithValidPano($mapId, $exclude);
|
|
||||||
|
|
||||||
$places[] = $place;
|
|
||||||
$exclude[] = $place->getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $places;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: use Map instead of id
|
|
||||||
public function getRandomForMapWithValidPano(int $mapId, array $exclude = []): Place
|
|
||||||
{
|
|
||||||
do {
|
do {
|
||||||
$place = $this->selectRandomFromDbForMap($mapId, $exclude);
|
$place = $this->selectRandomFromDbForMap($mapId, $exclude);
|
||||||
|
|
||||||
$panoId = $place->getFreshPanoId();
|
$panoId = $place->getFreshPanoId();
|
||||||
|
|
||||||
if ($panoId === null) {
|
if ($panoId === null) {
|
||||||
$exclude[] = $place->getId();
|
$placesWithoutPano[] = $exclude[] = $place->getId();
|
||||||
}
|
}
|
||||||
} while ($panoId === null);
|
} while ($panoId === null);
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,6 @@
|
|||||||
|
|
||||||
@section(subheader)
|
@section(subheader)
|
||||||
<span><a href="javascript:;" id="mapName" title="Edit map data"><?= $mapName ?></a></span><!--
|
<span><a href="javascript:;" id="mapName" title="Edit map data"><?= $mapName ?></a></span><!--
|
||||||
--><span>
|
|
||||||
<input type="text" id="jumpCoordinates" placeholder="Insert coordinates here" />
|
|
||||||
<button id="jumpButton" disabled >Jump</button>
|
|
||||||
</span><!--
|
|
||||||
--><span><!--
|
--><span><!--
|
||||||
<?php /* Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. */ ?>
|
<?php /* Copyright (c) 2019 The Bootstrap Authors. License can be found in 'USED_SOFTWARE' in section 'Bootstrap Icons'. */ ?>
|
||||||
--><svg class="inline" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
--><svg class="inline" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|||||||
+5
-37
@@ -5,25 +5,13 @@
|
|||||||
|
|
||||||
@extends(templates/layout_full)
|
@extends(templates/layout_full)
|
||||||
|
|
||||||
@section(pagemodal)
|
|
||||||
<div id="multi" class="modal">
|
|
||||||
<h2>Multiplayer (beta)</h2>
|
|
||||||
<p class="marginTop">Waiting for players...</p>
|
|
||||||
<div id="players" class="marginTop"></div>
|
|
||||||
<button id="startMultiGameButton" class="button fullWidth marginTop green">Start game</button>
|
|
||||||
</div>
|
|
||||||
@endsection
|
|
||||||
|
|
||||||
@section(subheader)
|
@section(subheader)
|
||||||
<span id="mapName" class="bold">Loading map...</span><!--
|
<span id="mapName" class="bold"><?= $mapName ?></span><!--
|
||||||
--><span>Round <span id="currentRound" class="bold"></span></span><!--
|
--><span>Round <span id="currentRound" class="bold"></span></span><!--
|
||||||
--><span>Score <span id="currentScoreSum" class="bold"></span></span>
|
--><span>Score <span id="currentScoreSum" class="bold"></span></span>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section(main)
|
@section(main)
|
||||||
<div id="countdown">
|
|
||||||
<p id="countdownTime" class="mono bold"></p>
|
|
||||||
</div>
|
|
||||||
<div id="panoCover"></div>
|
<div id="panoCover"></div>
|
||||||
<div id="panorama"></div>
|
<div id="panorama"></div>
|
||||||
<div id="showGuessButtonContainer">
|
<div id="showGuessButtonContainer">
|
||||||
@@ -40,7 +28,6 @@
|
|||||||
<div id="resultInfo">
|
<div id="resultInfo">
|
||||||
<div id="distanceInfo">
|
<div id="distanceInfo">
|
||||||
<p>You were <span id="distance" class="bold"></span> close.</p>
|
<p>You were <span id="distance" class="bold"></span> close.</p>
|
||||||
<p>You didn't guess in this round.</p>
|
|
||||||
<p class="bold">Game finished.</p>
|
<p class="bold">Game finished.</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="scoreInfo">
|
<div id="scoreInfo">
|
||||||
@@ -59,30 +46,11 @@
|
|||||||
<button id="startNewGameButton" class="fullWidth">Play this map again</button>
|
<button id="startNewGameButton" class="fullWidth">Play this map again</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="navigation">
|
|
||||||
<div id="compassContainer" class="navigationItem">
|
|
||||||
<div>
|
|
||||||
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/circle_background.svg?rev=<?= REVISION ?>" alt="Circle Background" class="circleBackground" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<img id="compass" src="<?= $_ENV['STATIC_ROOT'] ?>/img/compass.svg?rev=<?= REVISION ?>" alt="compass icon" class="navigationIcon" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="returnToStart" class="navigationItem">
|
|
||||||
<div>
|
|
||||||
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/circle_background.svg?rev=<?= REVISION ?>" alt="Circle Background" class="circleBackground" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<img src="<?= $_ENV['STATIC_ROOT'] ?>/img/house-fill.svg?rev=<?= REVISION ?>" alt="Return to Start icon" class="navigationIcon" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section(pageScript)
|
@section(pageScript)
|
||||||
<script>
|
<script>
|
||||||
var multiUrl = '<?= $_ENV['MULTI_WS_URL'] ?>';
|
var mapId = <?= $mapId ?>;
|
||||||
var roomId = <?= isset($roomId) ? '\'' . $roomId . '\'' : 'null' ?>;
|
var mapBounds = <?= json_encode($bounds) ?>;
|
||||||
var mapId = <?= isset($mapId) ? '\'' . $mapId . '\'' : 'null' ?>;
|
|
||||||
</script>
|
</script>
|
||||||
@endsection
|
@endsection
|
||||||
+7
-33
@@ -5,32 +5,6 @@ TODO: condition!
|
|||||||
|
|
||||||
@extends(templates/layout_normal)
|
@extends(templates/layout_normal)
|
||||||
|
|
||||||
@section(pagemodal)
|
|
||||||
<div id="playMode" class="modal">
|
|
||||||
<h2>Play map</h2>
|
|
||||||
<a id="singleButton" class="button fullWidth marginTop" href="" title="Single player">Single player</a>
|
|
||||||
<p class="bold center marginTop marginBottom">OR</p>
|
|
||||||
<button id="multiButton" class="fullWidth green" data-map-id="">Multiplayer (beta)</button>
|
|
||||||
<div class="right">
|
|
||||||
<button id="closePlayModeButton" class="gray marginTop" type="button">Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="multi" class="modal">
|
|
||||||
<h2>Multiplayer (beta)</h2>
|
|
||||||
<form id="multiForm" class="marginTop" data-no-submit="true">
|
|
||||||
<a id="createNewRoomButton" class="button fullWidth green" href="" title="Create new room">Create new room</a>
|
|
||||||
<p class="bold center marginTop marginBottom">OR</p>
|
|
||||||
<div class="inputWithButton">
|
|
||||||
<input type="text" name="roomId" placeholder="Room to connect" required minlength="6" maxlength="6"><!--
|
|
||||||
--><button id="authenticateWithGoogleButton" type="submit">Connect</button>
|
|
||||||
</div>
|
|
||||||
<div class="right">
|
|
||||||
<button id="closeMultiButton" class="gray marginTop" type="button">Close</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
@endsection
|
|
||||||
|
|
||||||
@section(main)
|
@section(main)
|
||||||
<div id="mapContainer">
|
<div id="mapContainer">
|
||||||
<?php foreach ($maps as $map): ?>
|
<?php foreach ($maps as $map): ?>
|
||||||
@@ -61,15 +35,15 @@ TODO: condition!
|
|||||||
<p class="small center"><?= $map['description'] ?></p>
|
<p class="small center"><?= $map['description'] ?></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttonContainer">
|
<?php if ($isAdmin): ?>
|
||||||
<?php if ($isAdmin): ?>
|
<div class="buttonContainer">
|
||||||
<button class="button fullWidth noRightRadius playButton" data-map-id="<?= $map['id'] ?>" data-map-name="<?= htmlspecialchars($map['name']) ?>" title="Play map '<?= $map['name'] ?>'">Play this map</button>
|
<a class="button fullWidth noRightRadius" href="/game/<?= $map['id']; ?>" title="Play map '<?= $map['name'] ?>'">Play this map</a>
|
||||||
<a class="button yellow fullWidth noLeftRadius noRightRadius" href="/admin/mapEditor/<?= $map['id']; ?>" title="Edit map '<?= $map['name'] ?>'">Edit</a>
|
<a class="button yellow fullWidth noLeftRadius noRightRadius" href="/admin/mapEditor/<?= $map['id']; ?>" title="Edit map '<?= $map['name'] ?>'">Edit</a>
|
||||||
<button class="button red fullWidth noLeftRadius deleteButton" data-map-id="<?= $map['id'] ?>" data-map-name="<?= htmlspecialchars($map['name']) ?>" title="Delete map '<?= $map['name'] ?>'">Delete</button>
|
<button class="button red fullWidth noLeftRadius deleteButton" data-map-id="<?= $map['id'] ?>" data-map-name="<?= htmlspecialchars($map['name']) ?>" title="Delete map '<?= $map['name'] ?>'">Delete</button>
|
||||||
<?php else: ?>
|
</div>
|
||||||
<button class="button fullWidth playButton" data-map-id="<?= $map['id'] ?>" data-map-name="<?= htmlspecialchars($map['name']) ?>" title="Play map '<?= $map['name'] ?>'">Play this map</button>
|
<?php else: ?>
|
||||||
<?php endif; ?>
|
<a class="button fullWidth" href="/game/<?= $map['id']; ?>" title="Play map '<?= $map['name'] ?>'">Play this map</a>
|
||||||
</div>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<?php if ($isAdmin): ?>
|
<?php if ($isAdmin): ?>
|
||||||
|
|||||||
@@ -29,6 +29,6 @@
|
|||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<p><span class="bold"><?= $_ENV['APP_NAME'] ?></span> <?= str_replace('Release_', '', VERSION) ?></p><!--
|
<p><span class="bold"><?= $_ENV['APP_NAME'] ?></span> <?= str_replace('Release_', '', VERSION) ?></p><!--
|
||||||
--><p>© The MapGuesser Contributors <?= (new DateTime(REVISION_DATE))->format('Y') ?></p>
|
--><p>© Pőcze Bence <?= (new DateTime(REVISION_DATE))->format('Y') ?></p>
|
||||||
</footer>
|
</footer>
|
||||||
@endsection
|
@endsection
|
||||||
@@ -50,17 +50,9 @@ Container::$routeCollection->group('account', function (MapGuesser\Routing\Route
|
|||||||
//Container::$routeCollection->get('maps', 'maps', [MapGuesser\Controller\MapsController::class, 'getMaps']);
|
//Container::$routeCollection->get('maps', 'maps', [MapGuesser\Controller\MapsController::class, 'getMaps']);
|
||||||
Container::$routeCollection->group('game', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('game', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
||||||
$routeCollection->get('game', '{mapId}', [MapGuesser\Controller\GameController::class, 'getGame']);
|
$routeCollection->get('game', '{mapId}', [MapGuesser\Controller\GameController::class, 'getGame']);
|
||||||
$routeCollection->post('game.prepare-json', '{mapId}/prepare.json', [MapGuesser\Controller\GameController::class, 'prepareGame']);
|
$routeCollection->get('game-json', '{mapId}/json', [MapGuesser\Controller\GameController::class, 'getGameJson']);
|
||||||
$routeCollection->post('game.initialData-json', '{mapId}/initialData.json', [MapGuesser\Controller\GameFlowController::class, 'initialData']);
|
$routeCollection->get('newPlace-json', '{mapId}/newPlace.json', [MapGuesser\Controller\GameFlowController::class, 'getNewPlace']);
|
||||||
$routeCollection->post('game.guess-json', '{mapId}/guess.json', [MapGuesser\Controller\GameFlowController::class, 'guess']);
|
$routeCollection->post('guess-json', '{mapId}/guess.json', [MapGuesser\Controller\GameFlowController::class, 'evaluateGuess']);
|
||||||
});
|
|
||||||
Container::$routeCollection->group('multiGame', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
|
||||||
$routeCollection->get('multiGame.new', 'new/{mapId}', [MapGuesser\Controller\GameController::class, 'getNewMultiGame']);
|
|
||||||
$routeCollection->get('multiGame', '{roomId}', [MapGuesser\Controller\GameController::class, 'getMultiGame']);
|
|
||||||
$routeCollection->post('multiGame.prepare-json', '{roomId}/prepare.json', [MapGuesser\Controller\GameController::class, 'prepareMultiGame']);
|
|
||||||
$routeCollection->post('multiGame.initialData-json', '{roomId}/initialData.json', [MapGuesser\Controller\GameFlowController::class, 'multiInitialData']);
|
|
||||||
$routeCollection->post('multiGame.nextRound-json', '{roomId}/nextRound.json', [MapGuesser\Controller\GameFlowController::class, 'multiNextRound']);
|
|
||||||
$routeCollection->post('multiGame.guess-json', '{roomId}/guess.json', [MapGuesser\Controller\GameFlowController::class, 'multiGuess']);
|
|
||||||
});
|
});
|
||||||
Container::$routeCollection->group('admin', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('admin', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
||||||
$routeCollection->get('admin.mapEditor', 'mapEditor/{mapId?}', [MapGuesser\Controller\MapAdminController::class, 'getMapEditor']);
|
$routeCollection->get('admin.mapEditor', 'mapEditor/{mapId?}', [MapGuesser\Controller\MapAdminController::class, 'getMapEditor']);
|
||||||
|
|||||||
Reference in new issue
Block a user