Major changes

- Players can now successfully get into a game
- None of the game view features don't work yet
- Optimisation changes
- Improved file naming
- A game will automatically end if either of the players disconnect
- Players will start the game synchronously as the server will wait for both of them to connect
- Timer and game state updating works really well
This commit is contained in:
MaciejkaG 2024-03-02 13:56:01 +01:00
parent 302fe3d328
commit dbb3ad0f1d
6 changed files with 111 additions and 33 deletions

View File

@ -25,8 +25,7 @@ const io = new Server(server);
const redis = createClient(); const redis = createClient();
redis.on('error', err => console.log('Redis Client Error', err)); redis.on('error', err => console.log('Redis Client Error', err));
await redis.connect(); await redis.connect();
redis.flushDb();
var gameData = [];
app.set('trust proxy', 1); app.set('trust proxy', 1);
const sessionMiddleware = session({ const sessionMiddleware = session({
@ -60,6 +59,7 @@ app.post('/api/setup-profile', (req, res) => {
if (req.session.nickname == null && 4 < req.body.nickname.length && req.body.nickname.length < 16) { if (req.session.nickname == null && 4 < req.body.nickname.length && req.body.nickname.length < 16) {
req.session.nickname = req.body.nickname; req.session.nickname = req.body.nickname;
req.session.playerID = uuidv4(); req.session.playerID = uuidv4();
req.session.activeGame = null;
} }
res.redirect("/") res.redirect("/")
@ -80,15 +80,16 @@ app.get("/*", (req, res) => {
res.redirect("/?path=" + req.originalUrl); res.redirect("/?path=" + req.originalUrl);
}); });
io.on('connection', (socket) => { io.on('connection', async (socket) => {
const req = socket.request;
const session = socket.request.session; const session = socket.request.session;
socket.session = session;
if (session.nickname==null) { if (session.nickname==null) {
socket.disconnect(); socket.disconnect();
return; return;
} }
console.log(isPlayerInGame(socket)); if (!await isPlayerInGame(socket)) {
if (!isPlayerInGame(socket)) {
socket.on('whats my nick', (callback) => { socket.on('whats my nick', (callback) => {
callback(session.nickname); callback(session.nickname);
}); });
@ -146,9 +147,26 @@ io.on('connection', (socket) => {
nextPlayer: 0, nextPlayer: 0,
}); });
req.session.reload((err) => {
if (err) return socket.disconnect();
req.session.activeGame = gameId;
req.session.save();
});
const oppReq = opp.request;
oppReq.session.reload((err) => {
if (err) return socket.disconnect();
oppReq.session.activeGame = gameId;
oppReq.session.save();
});
io.to(msg).emit("gameReady", gameId); io.to(msg).emit("gameReady", gameId);
io.sockets.clients(msg).forEach((s) => { io.sockets.adapter.rooms.get(msg).forEach((sid) => {
const s = io.sockets.sockets.get(sid);
s.leave(msg); s.leave(msg);
}); });
} else { } else {
@ -180,18 +198,37 @@ io.on('connection', (socket) => {
} }
}); });
} else { } else {
socket.on('shoot', () => { const playerGame = await getPlayerGameData(socket);
const playerGame = getPlayerGameData(socket);
if (playerGame.state === "action") { if (playerGame.data.state === 'pregame') {
socket.join(playerGame.id);
if (io.sockets.adapter.rooms.get(playerGame.id).size === 2) {
io.to(playerGame.id).emit('players ready');
const members = [...roomMemberIterator(playerGame.id)];
for (let i = 0; i < members.length; i++) {
const sid = members[i][0];
io.to(sid).emit('player idx', i);
}
let UTCTs = Math.floor((new Date()).getTime() / 1000 + 90);
io.to(playerGame.id).emit('turn update', { turn: 0, phase: "preparation", timerToUTC: UTCTs });
io.to(playerGame.id).emit();
}
}
// socket.on('shoot', async () => {
// const playerGame = await getPlayerGameData(socket);
// if (playerGame.state === 'action') {
} // }
}); // });
socket.on('disconnecting', () => { socket.on('disconnecting', async () => {
if (isPlayerInRoom(socket)) { io.to(playerGame.id).emit("player left");
io.to(socket.rooms).emit("player left");
} redis.json.del(`game:${playerGame.id}`);
}); });
} }
}); });
@ -220,19 +257,19 @@ function isPlayerInRoom(socket) {
} }
async function isPlayerInGame(socket) { async function isPlayerInGame(socket) {
const room = getPlayerRoom(socket); const game = await redis.json.get(`game:${socket.session.activeGame}`);
const game = await redis.json.get(`game:${room}`);
return game != null; return game != null;
} }
function getPlayerGameData(socket) { async function getPlayerGameData(socket) {
const room = getPlayerRoom(socket); const game = await redis.json.get(`game:${socket.session.activeGame}`);
return game == null ? null : {id: socket.session.activeGame, data: game};
}
const game = redis.json.get(`game:${room}`); function roomMemberIterator(id) {
return game; return io.sockets.adapter.rooms.get(id).entries();
} }
function getPlayerRoom(socket) { function getPlayerRoom(socket) {
return socket.rooms.values().next().value; return socket.rooms.entries()[1] === undefined ? null : socket.rooms.entries()[1][0];
} }

View File

@ -179,7 +179,7 @@ h1,h2,h3,h4,h5,h6 {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
text-align: center; text-align: center;
background: rgb(0, 0, 0, 0.4); background: rgb(0, 0, 0, 0.6);
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
transition: opacity 0.5s; transition: opacity 0.5s;
z-index: 999; z-index: 999;

View File

@ -1,6 +1,45 @@
const socket = io(); const socket = io();
var playerIdx;
var timerDestination = null;
var gamePhase = "pregame";
socket.on('connect', () => {
$(".cover h1").html("Oczekiwanie na serwer...");
});
socket.on("players ready", () => { socket.on("players ready", () => {
$(".cover").css({opacity: 0, pointerEvents: "none"}); $(".cover").css({opacity: 0, pointerEvents: "none"});
socket.emit("shoot"); });
});
socket.on("player idx", (idx) => {
console.log(idx);
playerIdx = idx;
});
socket.on('turn update', (turnData) => {
turnData.turn == playerIdx ? $("#whosTurn").html("Ty") : $("#whosTurn").html("Przeciwnik");
timerDestination = turnData.timerToUTC;
gamePhase = turnData.phase;
});
socket.on('player left', () => {
window.location.replace("/");
});
// Update timer
setInterval(() => {
if (timerDestination == null) {
$("#timer").html("");
} else {
const UTCNow = Math.floor((new Date()).getTime() / 1000);
const time = Math.abs(UTCNow - timerDestination);
const minutes = Math.floor(time / 60).toLocaleString('pl-PL', {minimumIntegerDigits: 2, useGrouping: false});
const seconds = (time - minutes * 60).toLocaleString('pl-PL', { minimumIntegerDigits: 2, useGrouping: false });
$("#timer").html(`${minutes}:${seconds}`);
}
}, 250);

View File

@ -1,5 +1,5 @@
<div class="cover"> <div class="cover">
<h1>Oczekiwanie na przeciwnika...</h1> <h1>Łączenie...</h1>
</div> </div>
<div class="container" id="gameView"> <div class="container" id="gameView">
@ -18,8 +18,8 @@
<h3 class="controlsOwnBoard"><span class="important">R</span> Obrót statku</h3> <h3 class="controlsOwnBoard"><span class="important">R</span> Obrót statku</h3>
<h3><span class="important">B</span> Zamiana planszy</h3> <h3><span class="important">B</span> Zamiana planszy</h3>
<span class="break"></span> <span class="break"></span>
<h3>Ruch: <span class="dynamic">Przeciwnik</span></h3> <h3>Ruch: <span class="dynamic" id="whosTurn">Przeciwnik</span></h3>
<h2 class="important">∞</h2> <h2 class="important" id="timer">∞</h2>
</div> </div>
<div class="boardContainer"> <div class="boardContainer">
<div id="board" oncontextmenu="return false;"></div> <div id="board" oncontextmenu="return false;"></div>
@ -28,7 +28,9 @@
<div class="spaceFiller"></div> <div class="spaceFiller"></div>
</div> </div>
</div> </div>
<script src="/assets/js/battleships_lib.js"></script> </div>
<script src="/assets/js/main.js"></script>
<script src="/assets/js/key_handling.js"></script> <script src="/assets/js/battleships-lib.js"></script>
</div> <script src="/assets/js/main.js"></script>
<script src="/assets/js/key-handling.js"></script>
<script src="/assets/js/socket-game.js"></script>