Compare commits

...

4 Commits

Author SHA1 Message Date
8732ff929b Session persistance fixed 2024-04-14 00:36:51 +02:00
ad81684431 Autoplace fixes + PWA fixes 2024-04-14 00:23:59 +02:00
81b77d42de Fixed animations 2024-04-13 23:59:21 +02:00
Maciej Gomoła
05910459cc Fixed the statistics saving bug 2024-04-13 23:54:25 +02:00
12 changed files with 87 additions and 264 deletions

1
.session.secret Normal file
View File

@ -0,0 +1 @@
e733201e-f39d-4d91-9e7f-4c2d2c4a81da

View File

@ -6,6 +6,7 @@ import { createServer } from 'node:http';
import { Server } from 'socket.io'; import { Server } from 'socket.io';
import path from 'node:path'; import path from 'node:path';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
import fs from 'node:fs';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import session from "express-session"; import session from "express-session";
import { engine } from 'express-handlebars'; import { engine } from 'express-handlebars';
@ -71,15 +72,28 @@ let sessionStore = new SessionRedisStore({
prefix: "statkiSession:", prefix: "statkiSession:",
}); });
var sessionSecret = uuidv4();
let secretPath = path.join(__dirname, '.session.secret');
if (fs.existsSync(secretPath)) {
sessionSecret = fs.readFileSync(secretPath);
} else {
fs.writeFile(secretPath, sessionSecret, function (err) {
if (err) {
console.log("An error occured while saving a freshly generated session secret.\nSessions may not persist after a restart of the server.");
}
});
}
const sessionMiddleware = session({ const sessionMiddleware = session({
store: sessionStore, store: sessionStore,
secret: uuidv4(), secret: sessionSecret,
resave: true, resave: true,
saveUninitialized: true, saveUninitialized: true,
rolling: true, rolling: true,
cookie: { cookie: {
secure: checkFlag("cookie_secure"), secure: checkFlag("cookie_secure"),
maxAge: 3 * 24 * 60 * 60 * 1000, maxAge: 7 * 24 * 60 * 60 * 1000,
}, },
}); });
@ -463,7 +477,7 @@ io.on('connection', async (socket) => {
}); });
} }
if (!await GInfo.isPlayerInGame(socket) || session.nickname != null) { if (!await GInfo.isPlayerInGame(socket) && session.nickname != null) {
// if (session.nickname == null) { // if (session.nickname == null) {
// socket.disconnect(); // socket.disconnect();
// return; // return;
@ -780,16 +794,28 @@ io.on('connection', async (socket) => {
if (hit.gameFinished) { if (hit.gameFinished) {
const members = [...roomMemberIterator(playerGame.id)]; const members = [...roomMemberIterator(playerGame.id)];
let hostSocket = io.sockets.sockets.get(members[0][0]); let hostSocket;
let guestSocket;
members.forEach(player => {
player = player[0];
const playerSocket = io.sockets.sockets.get(player);
if (playerSocket.session.userId === playerGame.data.hostId) {
hostSocket = playerSocket;
} else {
guestSocket = playerSocket;
}
});
let hostNickname = hostSocket.session.nickname; let hostNickname = hostSocket.session.nickname;
let guestSocket = io.sockets.sockets.get(members[1][0]);
let guestNickname = guestSocket.session.nickname; let guestNickname = guestSocket.session.nickname;
hostSocket.emit("game finished", !enemyIdx ? 1 : 0, guestNickname); hostSocket.emit("game finished", !enemyIdx ? 1 : 0, guestNickname);
guestSocket.emit("game finished", !enemyIdx ? 1 : 0, hostNickname); guestSocket.emit("game finished", !enemyIdx ? 1 : 0, hostNickname);
playerGame = await GInfo.getPlayerGameData(socket); playerGame = await GInfo.getPlayerGameData(socket);
auth.saveMatch(playerGame.id, (new Date).getTime() / 1000 - playerGame.data.startTs, "pvp", hostSocket.session.userId, guestSocket.session.userId, playerGame.data.boards, enemyIdx ? 0 : 1); auth.saveMatch(playerGame.id, (new Date).getTime() / 1000 - playerGame.data.startTs, "pvp", hostSocket.session.userId, guestSocket.session.userId, playerGame.data.boards, enemyIdx ? 1 : 0);
GInfo.resetTimer(playerGame.id); GInfo.resetTimer(playerGame.id);
endGame(playerGame.id); endGame(playerGame.id);

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -114,16 +114,16 @@ $("#createGameButton").on("click", function () {
case "ok": case "ok":
console.log("Lobby created"); console.log("Lobby created");
$("#createGameCode").val(response.gameCode); $("#createGameCode").val(response.gameCode);
lockUI(false);
switchView("pvpCreateView"); switchView("pvpCreateView");
returnLock = true; returnLock = true;
lockUI(false);
break; break;
case "alreadyInLobby": case "alreadyInLobby":
console.log("Lobby creation failed (player is already in a lobby)"); console.log("Lobby creation failed (player is already in a lobby)");
$("#createGameCode").val(response.gameCode); $("#createGameCode").val(response.gameCode);
switchView("pvpCreateView");
lockUI(false); lockUI(false);
switchView("pvpCreateView");
break; break;
default: default:
@ -163,16 +163,10 @@ form.addEventListener('submit', (e) => {
case "ok": case "ok":
console.log("Joined a lobby by:", response.oppNickname); console.log("Joined a lobby by:", response.oppNickname);
$("#oppNameField").html(response.oppNickname); $("#oppNameField").html(response.oppNickname);
switchView("preparingGame");
lockUI(false); lockUI(false);
switchView("preparingGame");
break; break;
//case "alreadyInLobby":
// $("#createGameCode").val(response.gameCode);
// switchView("pvpCreateView");
// lockUI(false);
// break;
default: default:
alert(`${window.locale["Unknown error occured"]}\n${window.locale["Status:"]} ${response.status}`); alert(`${window.locale["Unknown error occured"]}\n${window.locale["Status:"]} ${response.status}`);
lockUI(false); lockUI(false);

View File

@ -1,6 +1,8 @@
window.addEventListener("load", function () { if ("serviceWorker" in navigator) {
navigator.serviceWorker window.addEventListener("load", () => {
.register("/assets/js/service-worker.js") navigator.serviceWorker
.then(res => console.log("Service worker registered")) .register("/serviceWorker.js")
.catch(err => console.log("Service worker not registered", err)); .then(res => console.log("Service worker registered"))
}); .catch(err => console.log("Service worker not registered", err));
});
}

View File

@ -1,5 +1,6 @@
{ {
"name": "Statki", "name": "Statki",
"description": "The #1 online multiplayer battleships game\nModern, simple UI, PvP and PvE modes, advanced statistics and more.",
"start_url": "/", "start_url": "/",
"background_color": "black", "background_color": "black",
"theme_color": "black", "theme_color": "black",
@ -7,8 +8,48 @@
"icons": [ "icons": [
{ {
"src": "/assets/img/statki-logo-crop.png", "src": "/assets/img/statki-logo-crop.png",
"sizes": "1080x1080", "sizes": "1080x1080"
"type": "image/png" },
{
"src": "/assets/img/statki-logo-crop-144.png",
"sizes": "144x144"
}
],
"screenshots": [
{
"src": "/assets/img/screenshot_game2.png",
"sizes": "1920x911",
"type": "image/png",
"form_factor": "wide",
"label": "Middle of the round"
},
{
"src": "/assets/img/screenshot_mainmenu.png",
"sizes": "1920x911",
"type": "image/png",
"form_factor": "wide",
"label": "Main menu"
},
{
"src": "/assets/img/screenshot_create.png",
"sizes": "1920x911",
"type": "image/png",
"form_factor": "wide",
"label": "Create game screen"
},
{
"src": "/assets/img/screenshot_profile.png",
"sizes": "1920x911",
"type": "image/png",
"form_factor": "wide",
"label": "Main menu"
},
{
"src": "/assets/img/screenshot_game1.png",
"sizes": "1920x911",
"type": "image/png",
"form_factor": "wide",
"label": "Preparation phase"
} }
], ],
"display": "standalone" "display": "standalone"

241
test.js
View File

@ -1,241 +0,0 @@
function findEmptyFields(grid, len) {
const rowPlacements = [];
// Helper function to check if a row can be placed horizontally at a given position
function canPlaceHorizontally(x, y) {
console.log(x, y);
// console.log(x + len)
// console.log(x + len >= grid.length)
if (x + len >= grid[0].length) {
return false; // Ship exceeds board boundaries
}
for (let i = x; i < x + len; i++) {
if (grid[i][y]) {
return false; // One of ship's fields is already occupied
}
}
return true;
}
// Helper function to check if a row can be placed vertically at a given position
function canPlaceVertically(x, y) {
// console.log(y + len)
// console.log(y + len >= grid.length)
if (y + len >= grid.length) {
return false; // Ship exceeds board boundaries
}
for (let i = y; i < y + len; i++) {
if (grid[x][i]) {
return false; // One of ship's fields is already occupied
}
}
return true;
}
for (let i = 0; i < grid.length; i++) {
for (let j = 0; j < grid[0].length; j++) {
if (grid[j][i] === false) {
if (canPlaceHorizontally(j, i)) {
rowPlacements.push({ posX: j, posY: i, rot: 0 });
}
if (canPlaceVertically(j, i)) {
rowPlacements.push({ posX: j, posY: i, rot: 1 });
}
}
}
}
return rowPlacements;
}
let data = {
hostId: "123456",
state: "action",
boards: [
{
ships: [
{ type: 3, posX: 3, posY: 4, rot: 0, hits: [false, false, false] },
],
shots: [],
},
{
ships: [],
shots: [],
}
],
nextPlayer: 0,
}
// checkHit(data, 1, 0, 0);
// console.log(validateShipPosition(type, posX, posY, rot));
let boardRender = [];
for (let i = 0; i < 10; i++) {
var array = [];
for (let i = 0; i < 10; i++) {
array.push(false);
}
boardRender.push(array);
}
data.boards[0].ships.forEach(ship => {
let multips;
switch (ship.rot) {
case 0:
multips = [1, 0];
break;
case 1:
multips = [0, 1];
break;
case 2:
multips = [-1, 0];
break;
case 3:
multips = [0, -1];
break;
}
for (let i = 0; i <= ship.type; i++) {
boardRender[ship.posX + multips[0] * i][ship.posY + multips[1] * i] = true;
}
});
// const rot = 0;
const type = 3;
// let multips;
// switch (rot) {
// case 0:
// multips = [1, 0];
// break;
// case 1:
// multips = [0, 1];
// break;
// case 2:
// multips = [-1, 0];
// break;
// case 3:
// multips = [0, -1];
// break;
// }
boardRender = [
[
true, true, true,
true, true, true,
true, false, true,
true
],
[
true, true, true,
true, true, true,
true, false, true,
true
],
[
false, true, true,
true, true, true,
true, true, true,
true
],
[
false, true, true,
true, false, false,
true, true, true,
false
],
[
false, false, false,
true, true, true,
true, true, true,
false
],
[
false, false, false,
true, true, true,
true, true, false,
false
],
[
true, true, true,
true, true, true,
true, true, true,
true
],
[
true, true, true,
true, false, false,
false, true, true,
true
],
[
true, true, true,
true, true, true,
true, true, true,
true
],
[
false, false, false,
true, true, true,
true, false, false,
false
]
];
let search = findEmptyFields(boardRender, 4);
for (let y = 0; y < 10; y++) {
let row = "";
for (let x = 0; x < 10; x++) {
row += `${boardRender[x][y] ? "\x1b[31m" : "\x1b[32m"}${boardRender[x][y]}\x1b[0m\t`;
}
console.log(row);
}
console.log(search);
const rPos = search[Math.floor(Math.random() * search.length)];
switch (rPos.rot) {
case 0:
multips = [1, 0];
break;
case 1:
multips = [0, 1];
break;
case 2:
multips = [-1, 0];
break;
case 3:
multips = [0, -1];
break;
}
for (let i = 0; i <= type; i++) {
console.log(`boardRender[${rPos.posX + multips[0] * i}][${rPos.posY + multips[1] * i}]`)
boardRender[rPos.posX + multips[0] * i][rPos.posY + multips[1] * i] = true;
}
for (let y = 0; y < 10; y++) {
let row = "";
for (let x = 0; x < 10; x++) {
row += `${boardRender[x][y] ? "\x1b[31m" : "\x1b[32m"}${boardRender[x][y]}\x1b[0m\t`;
}
console.log(row);
}
// console.log();
// console.log(findAllRowsOfXTrueValues(matrix, 3, 1));
// console.log(findAllRowsOfXTrueValues(matrix, 3, 2));