259 lines
8.8 KiB
JavaScript
259 lines
8.8 KiB
JavaScript
const WebSocket = require("ws");
|
|
const { v4: uuidv4 } = require("uuid");
|
|
const puzzles = require('./puzzles.json');
|
|
const names = require('./assignedNames.json');
|
|
const crypto = require('crypto');
|
|
|
|
const wss = new WebSocket.Server({ port: 8080 });
|
|
const rooms = {}; // Stores rooms and their clients
|
|
const wheel = [
|
|
'lose a turn',800,350,450,700,300,600,5000,
|
|
300,600,300,500,800,550,400,300,900,500,'spin again',
|
|
900,'Bankrupt',600,400,300
|
|
] //represents wheel in wheel of fortune game.
|
|
function getRandomValue(array) {
|
|
const randomIndex = crypto.randomInt(0, array.length);
|
|
return array[randomIndex];
|
|
}
|
|
function shuffleArray(array) {
|
|
for (let i = array.length - 1; i > 0; i--) {
|
|
// Generate a cryptographically secure random index
|
|
const j = crypto.randomInt(0, i + 1);
|
|
// Swap elements
|
|
[array[i], array[j]] = [array[j], array[i]];
|
|
}
|
|
return array;
|
|
}
|
|
|
|
const DefaultNames = shuffleArray(names);
|
|
let NameIndex = 0;
|
|
function getRandomName() {
|
|
if (NameIndex >= DefaultNames.length) {
|
|
NameIndex = 0;
|
|
}else{
|
|
NameIndex++;
|
|
}
|
|
//since we've incremented the index but not returned the value,
|
|
//calculate the index again
|
|
return NameIndex === 0 ? DefaultNames[NameIndex] : DefaultNames[NameIndex-1];
|
|
}
|
|
|
|
function loadCurrentPuzzle(gameStateObject) {
|
|
console.log(gameStateObject);
|
|
//calculate the puzzle for now we'll just go through however many iterations there are
|
|
//for each slot
|
|
let letterArray = gameStateObject.puzzles[gameStateObject.puzzleLevel].answer.split('');
|
|
const given =gameStateObject.puzzles[gameStateObject.puzzleLevel].given;
|
|
console.log('letterArray',letterArray);
|
|
let puzzleArray = [];
|
|
for (let letter of letterArray) {
|
|
if (letter == ' ') {
|
|
puzzleArray.push(' ');
|
|
}
|
|
letterFound = false;
|
|
for (let g of given ) {
|
|
if(g.toUpperCase() == letter.toUpperCase()) {
|
|
puzzleArray.push(g);
|
|
letterFound = true;
|
|
}
|
|
}
|
|
if (!letterFound) {puzzleArray.push('');}
|
|
|
|
}
|
|
console.log(puzzleArray);
|
|
gameStateObject.puzzles[gameStateObject.puzzleLevel].puzzle = puzzleArray;
|
|
return {
|
|
'puzzleLevel':gameStateObject.puzzleLevel,
|
|
'given':gameStateObject.puzzles[gameStateObject.puzzleLevel].given,
|
|
'category':gameStateObject.puzzles[gameStateObject.puzzleLevel].category,
|
|
'puzzle':puzzleArray,
|
|
'levelsRemaining':(gameStateObject.puzzles.length - 1 - gameStateObject.puzzleLevel)
|
|
}
|
|
}
|
|
|
|
|
|
// server.js
|
|
wss.on("connection", (ws) => {
|
|
ws.on("message", (message) => {
|
|
const data = JSON.parse(message);
|
|
if (data.type === "change_name") {
|
|
const roomCode = ws.roomCode;
|
|
const room = rooms[ws.roomCode];
|
|
console.log(room);
|
|
console.log(room.leader.name,room.clients[0].name);
|
|
console.log(room.clients.filter((i)=> i.name == data.deadName));
|
|
console.log(ws.name,ws.identifierToken);
|
|
//change names in all places.
|
|
//if the leader wants to change their name account for this
|
|
//note this could probably be exploited oneday and break the game but whatever
|
|
//since there is no logging in of users this is bound to happen.
|
|
|
|
//find the names by index using the identifier Token which i user can't easily create
|
|
//a name collision.
|
|
const nameToChange = room.clients.findIndex((i)=> i.identifierToken == ws.identifierToken )
|
|
console.log(nameToChange);
|
|
if (nameToChange != -1) {
|
|
room.clients[nameToChange].name = data.newName;
|
|
}
|
|
if (room.leader.identifierToken == room.clients[nameToChange].identifierToken) {
|
|
room.leader.name = data.newName;
|
|
}
|
|
//if the user is not the leader, in theory just change the name on the clients list
|
|
//not sure if it exists in other places but test and see
|
|
|
|
//send name changed event to client, similar to joined room but it will work when people are in game.
|
|
ws.send(JSON.stringify({
|
|
type: "changed_name_you", roomCode,
|
|
isLeader: rooms[roomCode].leader === ws,
|
|
you:data.newName
|
|
}));
|
|
room.clients.forEach((client) => {
|
|
client.send(JSON.stringify({
|
|
type: "changed_name", roomCode,
|
|
isLeader: room.leader === ws ,
|
|
clients: room.clients.map((i)=> i.name),
|
|
leaderName:room.leader.name
|
|
}));
|
|
});
|
|
|
|
}
|
|
if (data.type === "create_room") {
|
|
const roomCode = uuidv4().slice(0, 5);
|
|
ws.name = getRandomName();
|
|
ws.identifierToken = uuidv4().slice(0, 5);
|
|
rooms[roomCode] = {
|
|
clients: [ws],
|
|
leader: ws,
|
|
gameState: {
|
|
started:false,
|
|
puzzles:shuffleArray(puzzles),
|
|
puzzleLevel:0,
|
|
},
|
|
};
|
|
ws.roomCode = roomCode;
|
|
ws.send(JSON.stringify({ type: "room_created", roomCode,
|
|
isLeader: true,
|
|
leaderName: ws.name,
|
|
clients: rooms[roomCode].clients.map((i)=> i.name),
|
|
you:ws.name
|
|
}));
|
|
}
|
|
|
|
if (data.type === "join_room") {
|
|
const { roomCode } = data;
|
|
console.log(rooms);
|
|
console.log(rooms[roomCode],roomCode);
|
|
|
|
if (!rooms[roomCode]) {
|
|
ws.send(JSON.stringify({ type: "error", message: "Room not found" }));
|
|
}
|
|
else if (rooms[roomCode].gameState.started) {
|
|
ws.send(JSON.stringify({ type: "error", message: "Game has already Started!!!" }));
|
|
}
|
|
else {
|
|
ws.name = getRandomName();
|
|
ws.identifierToken = uuidv4().slice(0, 5);
|
|
rooms[roomCode].clients.push(ws);
|
|
ws.roomCode = roomCode;
|
|
const room = rooms[ws.roomCode];
|
|
ws.send(JSON.stringify({
|
|
type: "joined_room_you", roomCode,
|
|
isLeader: rooms[roomCode].leader === ws,
|
|
you:ws.name
|
|
}));
|
|
|
|
room.clients.forEach((client) => {
|
|
client.send(JSON.stringify({
|
|
type: "joined_room", roomCode,
|
|
isLeader: rooms[roomCode].leader === ws ,
|
|
clients: rooms[roomCode].clients.map((i)=> i.name),
|
|
leaderName:rooms[roomCode].leader.name
|
|
}));
|
|
});
|
|
|
|
|
|
}
|
|
//console.log('clients: ',rooms[roomCode].leader.name);
|
|
}
|
|
|
|
if (data.type === "start_game") {
|
|
const room = rooms[ws.roomCode];
|
|
room.gameState.started = true;
|
|
console.log('game started for:',room);
|
|
|
|
if (room && room.leader === ws) {
|
|
room.clients.forEach((client) => {
|
|
client.send(JSON.stringify({
|
|
type: "game_started",
|
|
roomCode: ws.roomCode,
|
|
puzzle:loadCurrentPuzzle(room.gameState)
|
|
}));
|
|
});
|
|
} else {
|
|
ws.send(JSON.stringify({ type: "error", message: "Only the leader can start the game" }));
|
|
}
|
|
}
|
|
|
|
if (data.type === "spin_wheel" || data.type === "guess_letter") {
|
|
const room = rooms[ws.roomCode];
|
|
if (room && room.clients.includes(ws)) {
|
|
// Handle spin and guess events
|
|
if (data.type === "spin_wheel") {
|
|
// Simulate a wheel spin result and update room state
|
|
const spinResult = getRandomValue(wheel);
|
|
room.gameState.spinResult = spinResult;
|
|
room.clients.forEach((client) =>
|
|
client.send(JSON.stringify({
|
|
type: "spin_result", spinResult,
|
|
player: ws === room.leader ? "Leader" : "Player"
|
|
}))
|
|
);
|
|
}
|
|
|
|
if (data.type === "guess_letter") {
|
|
const { letter } = data;
|
|
// Handle guess logic (e.g., check if the letter is in the puzzle)
|
|
const correctGuess = Math.random() > 0.5; // Random outcome for simplicity
|
|
room.gameState.lastGuess = { letter, correct: correctGuess };
|
|
room.clients.forEach((client) =>
|
|
client.send(JSON.stringify({ type: "guess_result", letter, correct: correctGuess, player: ws === room.leader ? "Leader" : "Player" }))
|
|
);
|
|
}
|
|
} else {
|
|
ws.send(JSON.stringify({ type: "error", message: "You are not in this room" }));
|
|
}
|
|
}
|
|
});
|
|
|
|
ws.on("close", () => {
|
|
if (ws.roomCode && rooms[ws.roomCode]) {
|
|
console.log('closing');
|
|
const room = rooms[ws.roomCode];
|
|
const roomCode = ws.roomCode;
|
|
room.clients = room.clients.filter((client) => client !== ws);
|
|
if (room.leader === ws && room.clients.length > 0) {
|
|
console.log('closing within room leader')
|
|
room.leader = room.clients[0];
|
|
room.leader.send(JSON.stringify({ type: "new_leader" }));
|
|
|
|
}
|
|
room.clients.forEach((client) =>
|
|
client.send(JSON.stringify({
|
|
type: "joined_room", roomCode,
|
|
isLeader: rooms[roomCode].leader === ws ,
|
|
clients: rooms[roomCode].clients.map((i)=> i.name),
|
|
leaderName:rooms[roomCode].leader.name
|
|
}))
|
|
);
|
|
if (room.clients.length === 0) delete rooms[ws.roomCode];
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
console.log("WebSocket server is running on ws://localhost:8080");
|
|
|
|
module.exports = {
|
|
DefaultNames,NameIndex,
|
|
getRandomName,getRandomValue,shuffleArray
|
|
} |