Merge branch 'feature/serverSide' into develop

develop
Nathan Steel 1 year ago
commit 579848c84c

@ -4,22 +4,12 @@ const database = require('./database');
const util = require('util')
// cardClass, cardColourRequirement
// may want to be seperate too (as well as in cardItem), so that
// during match they can be altered by effects while keeping the OG card
// for inspecting (and compare against new stats,reqs,etc.)
// same with attack, cost, etc. things that will can be visually shown as
// changed in game
// Just grabbing everything from DB for now, as it's quite small at current
// then will rejig when needed.
// Should all cards, effects, classes etc. be loaded in on server start
// then just load decks and decklists when needed?
// Get the decks requested
function getDecks(deckIds = false){
// Await promise, once it's done get the data, if errors send err
const dPromise = new Promise((resolve, reject) => {
database.dbGetDecks().then(data => {
database.dbGetDecks(deckIds).then(data => {
let decks = [];
@ -48,10 +38,10 @@ function getDecks(deckIds = false){
return dPromise;
}
//getDecks();
function getDeckList(){
function getDeckList(deckIds = false){
const dPromise = new Promise((resolve, reject) => {
database.dbGetDeckList().then(data => {
database.dbGetDeckList(deckIds).then(data => {
let deckList = [];
@ -70,11 +60,10 @@ function getDeckList(){
});
return dPromise;
}
//getDeckList();
function getCards(){
function getCards(cardIds = false){
const dPromise = new Promise((resolve, reject) => {
database.dbGetCards().then(data => {
database.dbGetCards(cardIds).then(data => {
let cards = [];
@ -97,10 +86,9 @@ function getCards(){
});
return dPromise;
}
//getCards();
function getCardClasses(){
function getCardClasses(cardIds = false){
const dPromise = new Promise((resolve, reject) => {
database.dbGetCardClasses().then(data => {
database.dbGetCardClasses(cardIds).then(data => {
let cardClasses = [];
@ -118,10 +106,9 @@ function getCardClasses(){
});
return dPromise;
}
//getCardClasses();
function getCardColourRequirement(){
function getCardColourRequirement(cardIds = false){
const dPromise = new Promise((resolve, reject) => {
database.dbGetCardColourRequirement().then(data => {
database.dbGetCardColourRequirement(cardIds).then(data => {
let colourRequirements = [];
@ -141,9 +128,9 @@ function getCardColourRequirement(){
});
return dPromise;
}
function getCardManaColour(){
function getCardManaColour(cardIds = false){
const cPromise = new Promise((resolve, reject) => {
database.dbGetCardManaColour().then(data => {
database.dbGetCardManaColour(cardIds).then(data => {
let manaColours = [];
@ -274,25 +261,9 @@ function getCardPassive(){
return cPromise;
}
//getCardColourRequirement();
// Then effects which will have effects with parent triggers, and unit type checks
// colour checks, all sorts. So will be more difficult. Basic (flight, etc)
// shouldn't be too bad
// something like effect_basic, card_effect, effect_trigger, effect_requirement, effect_option
// effect_stage, effect_advanced, with advanced being an id with x triggers, triggers have
// x req, advanced as with x options, x stages to be able to fine-tune fancy stuff
// combining all other effects, units, cards, colours, etc. Will be a lot of though,
// but better than hard coding anything more than basic effects and effect check logic
// TODO: effect (as above)
// request a deck in the format CURRENTLY used in the game
// decks will likely be changed around
// https://www.geeksforgeeks.org/how-to-wait-for-multiple-promises-in-javascript/
// https://medium.com/@nikolozz/using-socket-io-with-async-await-13fa8c2dc9d9
// using last example
// TODO: When this is functionally working, need to split up into other func/modules
// such as: playerMod, cardMod, deckMod, miscMod ?
function requestDeck(itemData = null){
return new Promise((resolve, reject) => {
(async () => {
@ -300,53 +271,73 @@ function requestDeck(itemData = null){
// Get the deck(s) requested.
// Not 100% on how to do two differening atm
// Besides all of playerId, and all of deckId. But 1,2/2,3 for instance
// Build array of decks to get
let deckIds = [];
for(let i = 0; i < itemData.players.length; i++){
let deckStuff = itemData.players[i][1].deck;
deckIds.push([deckStuff.playerId, deckStuff.deckId]);
// So should be array of [playerId, deckId] which is primary key in DB
}
// Get said decks, and their deckLists
const [decks, deckList] =
await Promise.all([
getDecks(),
getDeckList()
getDecks(deckIds),
getDeckList(deckIds)
]);
//console.log(decks);
//console.log(deckList);
/*
console.log('--- decks ---');
console.log(decks);
console.log('= deckLists =')
console.log(deckList);
console.log('------');
*/
// Now loop the deckList for the cardIds
let deckCardIds = [];
deckList.forEach((deckItem) => {
deckCardIds.push(deckItem.cardId);
});
//console.log(deckCardIds);
// Next, get the cards in the deck by their ID
// TODO: https://stackoverflow.com/a/65510676
// Change SQL to accept for just the cards passed
// Get each cards data, colourReqs, and classes
const [cards, cardClasses, cardColourRequirements, cardManaColours, cardPassives] =
await Promise.all([
getCards(),
getCardClasses(),
getCardColourRequirement(),
getCardManaColour(),
getCardPassive(),
getCards(deckCardIds),
getCardClasses(deckCardIds),
getCardColourRequirement(deckCardIds),
getCardManaColour(deckCardIds),
getCardPassive(deckCardIds),
]);
// ^^^^ Classes async? Can pass the cardsIds, then loop classes, if the class cardId
// matches the cardId in cards[] then push the class to cards[x].classes
// Return all effect data from DB
const [effects] =
await Promise.all([
database.dbGetEffect(deckCardIds), // Get effects
]);
// TODO: Build the card so far async for it's done alongside getting effects?
// Then when both done add the effects to the existing cardObjects? Yep good idea me
//console.log(cards);
//console.info(cardClasses);
//console.log(cardColourRequirements);
// Loop the effects for their effectIds to then get the steps/triggers from DB
let effectIds = [];
await effects.forEach((effect) => {
effectIds.push(effect.effectId);
});
// Return all effect data from DB
const [effects, effectSteps, effectTriggers] =
// Then pass the effectIds to get their steps/triggers
const [effectSteps, effectTriggers] =
await Promise.all([
database.dbGetEffect(),
database.dbGetEffectStep(),
database.dbGetEffectTrigger(),
database.dbGetEffectStep(effectIds),
database.dbGetEffectTrigger(effectIds),
]);
/*
console.log('--- Effects ---');
console.log(effects);
*/
// Build Effects
const [cardEffects] =
await Promise.all([
@ -460,6 +451,8 @@ function requestDeck(itemData = null){
// For each new card, loop to the cardCount (how many cards in deck)
// and add to the deck
// TODO: Associate player to deck differently (both could be using same deck
// via some kind of 'try a deck' or 'use friends deck' option)
for(let i = 0; i < deckListItem.cardCount; i++){
item.push(itemCount); // Add new item to add stuff for
// ^ not using item.length incase anything in future gets deleted

@ -0,0 +1,99 @@
// A seperate list for components, so they're easy to recall
// Done as object, so it can be added to different rooms with components = NEW component?
const component = {
// Entity Stuff
//item : [],
//itemCount : 0,
roomId : null,
turn : 0,
playerTurn : 0,
// Card Stuff
cardData : {},
cardFace : {},
cardStatus : {
tapped : {},
attacking : {},
inspected : {},
},
cardAttack : {},
cardColours : {}, // Replace with colour
colour : {
white : {}, // entityId, amountOfColour
blue : {},
red : {},
},
cardManaColour : {},
cardEffect : {}, // TODO: Split this into effect, trigger, step, targets.
cardCost : {},
cardSprite : {}, // id, position in spritesheet [0,4] e.g.
//cardPlayer = {},
// Deck Stuff?
deckIn : {},
deckData : {},
// UI (so users know what's been targetted)
selected : {},
selectable : {},
// Effect (break it up?)
effect : {},
effectTrigger : {},
// etc, etc.
// Board Elements
// loop component.shield for shield items
boardElement : {},
// Replace with following
realDeck : {},
inDeck : {},
hand : {},
board : {},
shield : {},
mana : {},
grave : {},
void : {},
//
listPosition : {},
// position (clientside)
// size (clientside)
// Passives
// component.passive.flight ?
passive : {
flight : {},
reach : {},
taunt : {},
},
type : {
unit : {},
spell : {},
token : {},
},
classes : {
orc : {},
human : {},
spirit : {},
},
};
// For front-end
// position, size
// These should be used as such (Not 100% as yet)
// For onBoard()... for player()... for passive.flight()...
// Check the board, items belonging to playerX, for flight passive?
module.exports = {
component
}

@ -17,7 +17,7 @@ function disconnect(){
}
// My DB stuffs
function dbGetDecks(){
function dbGetDecks(deckIds = false){
const dPromise = new Promise((resolve, reject) => {
let cards = [];
let sql = `SELECT
@ -25,8 +25,16 @@ function dbGetDecks(){
,playerId
,deckName
FROM deck
LIMIT 10
`; // TODO: Remove limit when happy/this accepts params
`;
// TODO: Jank, need to unjank it
if(deckIds){
for(let i = 0; i < deckIds.length; i++){
if(i == 0){ sql += ' WHERE '; }
else{ sql += ' OR '; }
sql += '(deckId = '+deckIds[i][1]+' AND playerId = '+deckIds[i][0]+')';
}
}
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
@ -35,7 +43,7 @@ function dbGetDecks(){
});
return dPromise;
}
function dbGetDeckList(){
function dbGetDeckList(deckIds = false){
const dPromise = new Promise((resolve, reject) => {
let cards = [];
let sql = `SELECT
@ -46,6 +54,15 @@ function dbGetDeckList(){
FROM deck_cards
`;
// TODO: Jank, need to unjank it
if(deckIds){
for(let i = 0; i < deckIds.length; i++){
if(i == 0){ sql += ' WHERE '; }
else{ sql += ' OR '; }
sql += '(deckId = '+deckIds[i][1]+' AND playerId = '+deckIds[i][0]+')';
}
}
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
resolve(result);
@ -53,7 +70,7 @@ function dbGetDeckList(){
});
return dPromise;
}
function dbGetCards(){
function dbGetCards(cardIds = false){
// Start with basic stuff in card table
const dPromise = new Promise((resolve, reject) => {
let sql = `SELECT
@ -65,6 +82,7 @@ function dbGetCards(){
,cardRarity
FROM card
`;
if(cardIds){ sql += 'WHERE card.id IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
@ -73,7 +91,7 @@ function dbGetCards(){
});
return dPromise;
}
function dbGetCardClasses(){
function dbGetCardClasses(cardIds = false){
// Get the classes assoc. on each card
const dPromise = new Promise((resolve, reject) => {
let sql = `SELECT
@ -81,6 +99,7 @@ function dbGetCardClasses(){
,classId
FROM card_class
`;
if(cardIds){ sql += 'WHERE cardId IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
@ -89,7 +108,7 @@ function dbGetCardClasses(){
});
return dPromise;
}
function dbGetCardColourRequirement(){
function dbGetCardColourRequirement(cardIds = false){
// Get the classes assoc. on each card
const dPromise = new Promise((resolve, reject) => {
let sql = `SELECT
@ -98,6 +117,7 @@ function dbGetCardColourRequirement(){
,cost
FROM card_colour_requirement
`;
if(cardIds){ sql += 'WHERE cardId IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
@ -107,7 +127,7 @@ function dbGetCardColourRequirement(){
return dPromise;
}
function dbGetCardManaColour(){
function dbGetCardManaColour(cardIds = false){
// Get the classes assoc. on each card
const cPromise = new Promise((resolve, reject) => {
let sql = `SELECT
@ -115,6 +135,7 @@ function dbGetCardManaColour(){
,colourId
FROM card_mana_colour
`;
if(cardIds){ sql += 'WHERE cardId IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
@ -125,7 +146,7 @@ function dbGetCardManaColour(){
}
// Effect stuff
function dbGetEffect(){
function dbGetEffect(cardIds = false){
const ePromise = new Promise((resolve, reject) => {
let sql = `SELECT
cardId
@ -136,6 +157,7 @@ function dbGetEffect(){
INNER JOIN effect
ON effect.id = card_effect.effectId
`;
if(cardIds){ sql += 'WHERE cardId IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
@ -144,7 +166,7 @@ function dbGetEffect(){
});
return ePromise;
}
function dbGetEffectStep(){
function dbGetEffectStep(effectIds = false){
const ePromise = new Promise((resolve, reject) => {
let sql = `SELECT
effectId,
@ -163,6 +185,7 @@ function dbGetEffectStep(){
effect_step_target
ON effect_step_target.effectStep = effect_step.id
`;
if(effectIds){ sql += 'WHERE effectId IN ('+effectIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
@ -172,7 +195,7 @@ function dbGetEffectStep(){
return ePromise;
}
// Effect Trigger stuff
function dbGetEffectTrigger(){
function dbGetEffectTrigger(effectIds = false){
const ePromise = new Promise((resolve, reject) => {
let sql = `SELECT
effect_trigger.id AS triggerId,
@ -196,6 +219,7 @@ function dbGetEffectTrigger(){
effect_trigger_target
ON effect_trigger_target.effectTriggerId = effect_trigger.triggerTypeId
`;
if(effectIds){ sql += 'WHERE effectId IN ('+effectIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }
@ -206,13 +230,14 @@ function dbGetEffectTrigger(){
}
// Passive stuff
function dbGetPassive(){
function dbGetPassive(cardIds = false){
const pPromise = new Promise((resolve, reject) => {
let sql = `SELECT
cardId
,passiveId
FROM card_passive
`;
if(cardIds){ sql += 'WHERE card.id IN ('+cardIds+')'; }
con.query(sql, function (err, result, fields) {
if (err) { throw err; reject(new Error(err)); }

@ -0,0 +1,25 @@
// For anything related to the actual game itself (kinda)
// this will be split into different bits, but should be what manages a rooms
// game states, and alladat
// Basically here to prevent circular dependencies (where I can)
// PlayerId is using array 0,1,2 for now, not the actual id
// actual Id would be better, but the player should be passed correctly
// from the client. They can edit data, but server-side validation SHOULD prevent
// in the future
function passTurn(roomId, playerId){
// Check playerId (not correct atm) before doing the stuff, to verify the user
// IS the user, and in the room
// Test alert so that different data/emits can be sent per-player
global.socketAlert(roomData[roomId].playerData[0].socketId, 'Pass', 'alert');
}
module.exports = {
passTurn
};

@ -42,6 +42,7 @@ let cardColours = {};
let cardManaColour = {};
let cardEffect = {};
let inEvent = null;
let roomId = null;
// To disable drawing each time something changes
let drawEachEvent = true; // For disabling draw each time and only occuring where I want to test
@ -1298,6 +1299,7 @@ function loadBoard(data) {
cardColours = data.cardColours;
cardManaColour = data.cardManaColour;
cardEffect = data.cardEffect;
roomId = data.roomId;
// Passives
flight = data.flight;

@ -17,6 +17,10 @@
</div>
<canvas id="canvas" width="1000" height="600"></canvas>
<hr>
<button onclick="passTurn()">Pass Turn</button>
<br><br>
<hr>
<button onclick="untapAllZones()">Untap all</button>
<button onclick="echoCards()">Print cardlist to console</button>

@ -182,3 +182,19 @@ socket.on('responseStartGame', function (data) {
loadBoard(data.message);
});
// ALERTS
socket.on('alert', function (data) {
console.log('<< alert');
alert(data.message);
});
// GAME SERVER STUFF
// PASS TURN
function passTurn(){
// TODO: Use itemData.player/itemData.room or whatnot here
console.log(roomId);
let playerId = prompt('PlayerId 0/1', 0); // TODO: very temp, will be playerId/arrayId
console.log('+ passTurn');
socket.emit('passTurn', roomId, playerId);
}

@ -1,41 +1,34 @@
// Build a room, fill will players, etc.
const cardGen = require('./cardGen');
const components = require('./components');
// Room should, setPlayers, add them to correct team (TODO), build their decks, and first shuffle
function startItemCount(){
let item = [];
let itemCount = 0;
returns = {'item': item, 'itemCount': itemCount};
return(returns);
}
function setPlayers(playerCount = 2, itemData){
// Add new item attribute for 'players'
// TODO: Maybe check if exists, and add to in that case (for replacing people?)
// Doubt that would ever make it into the game, but could still be worth
function setPlayers(playerData, itemData){
itemData.player = {}; //let player = {}; // Player item belongs to
itemData.players = []; // List of the players (an associated playerItem?)
//itemData.
// Can be done with just referring to itemData[x], but less readable
// Will likely redefine vars each new function. For now will keep this as-is
let playerNo = 0 + itemData['itemCount']; // Start loop from current itemCount
playerCount = playerCount + itemData['itemCount']; // End at playerCount diff from itemCount
playerCount = playerData.length + itemData['itemCount']; // End at playerCount diff from itemCount
let i = 0;
for(playerNo; playerNo < playerCount; playerNo++){
// REMOVED PLAYERS AS ITEM, BECAUSE THEY WERE BORKING
// TODO: Add back at some point, or don't bother
//itemData['item'].push(playerNo);
//itemData['player'][itemData['itemCount']] = playerNo; // The player belongs to itself
//itemData['itemCount']++;
itemData['players'].push(playerNo); // Add player no to array so can be looped
itemData['players'].push([playerNo, playerData[i]]); // Add player no to array so can be looped
i++;
}
// Return related item and item attributes
//returns = {'item': item, 'itemCount': itemCount, 'player': player};
return itemData;
//return([item, itemCount, player]);
}
// For future, when 2v2s, and 5v1 Raids, etc.
@ -43,26 +36,72 @@ function setTeams(){
}
function roomGeneration(playerCount, teamCount = null, playerTeams = null){
function roomGeneration(roomId){
return new Promise((resolve, reject) => {
(async () => {
// Player's sockets
console.log('--- Room for generation ---');
console.log(io.sockets.adapter.rooms.get(roomId));
let itemData = startItemCount();
// Create 2 players for the room
itemData = setPlayers(2, itemData);
// Player data with Sockets
let playerData = [];
let playerOrder = {}; // Need a better name
let i = 1;
let clients = global.io.sockets.adapter.rooms.get(roomId);
for (const clientId of clients) {
const clientSocket = global.io.sockets.sockets.get(clientId);
// TODO: Get their selected decks (will need to pass somewhere)
// Which order the player is? Just using the array
playerOrder[clientSocket.playerId] = playerData.length;
playerData.push({
'playerDataId': playerData.length
,'playerId': clientSocket.playerId
,'deck':{'playerId':i,'deckId':1}
,'socketId': clientSocket.id // TODO: ONLY FOR SERVERSIDE!!!
});
i++;
}
// Add players for the room (seperate to playerData, currently what's used)
// ??
itemData = setPlayers(playerData, itemData);
// TODO: Get their selected decks
// Add all the empty components to the room itemData
itemData.component = components.component;
// Generate the decks, and card within the deck cardLists
[itemData] = await Promise.all([ cardGen.requestDeck(itemData) ]);
//console.log('deckData');
//console.log(deckData);
// Some room stuff, likely change this
itemData.roomId = roomId;
itemData.turn = 0; // The turn count of the match
itemData.playersTurn = 0; // This means it's playerData[0] turn
// Room has just been created, so add the itemData and playerData to the room
// on server-side so it's easily accessible
roomData[roomId].itemData = itemData;
roomData[roomId].playerData = playerData;
roomData[roomId].playerOrder = playerOrder;
// Return the all the itemData to the client(s)
// TODO: This will need to give different data for each, or at least
// to differ the boardside
return resolve(itemData);
})()
});
}
// TODO: disconnect, reconnect, resume
module.exports = {
startItemCount
,setPlayers

@ -0,0 +1,229 @@
const roomMod = require('./roomMod');
// Variables for server overall
let numRooms = 0;
const maxRooms = 3;
const maxPlayersPerRoom = 2;
const maxSpectatorsPerRoom = 0;
function requestRooms(socket, filter){
console.log('+ requestRooms recieved');
console.log('- filter: '+filter);
let response = getRooms(filter, dump = true);
global.io.to(socket.id).emit('returnRooms', response);
console.log('');
}
function getRooms(filter = 'all', dump = false){
console.log('+ getRooms');
let response = {
random: 'randomStuff',
roomData: global.roomData,
};
if(dump){
console.log(response);
console.log('');
}
return response;
}
function requestCreateRoom(socket, playerName){
console.log('+ createRoom recieved');
console.log('- requested by: '+playerName);
response = createRoom(roomId = false, dump = true);
global.io.to(socket.id).emit('returnCreateRoom', response);
if(response.success){
let response = getRooms(filter = 'all', dump = true);
global.io.to(socket.id).emit('returnRooms', response);
}
console.log('');
}
function createRoom(roomId = false, dump = true){
let roomName = false;
if(roomId == false){
roomId = numRooms + 1;
}
console.log(roomId);
let response = {
success: false,
message: 'No idea bossman'
};
// Max room limit reached
console.log(numRooms);
console.log(maxRooms);
if(numRooms >= maxRooms){
console.log('- Room limit reached');
response = {
success: false,
message: 'No space '+numRooms+' out of '+maxRooms+' created.'
};
// Create room
}else{
console.log('- Creating room')
let room = {};
room['id'] = roomId;
room['name'] = 'Room:'+room['id'];
roomName = room['name'];
room['password'] = '';
room['timeout'] = {};
room['timeout']['s'] = 10;
room['people'] = 0;
room['playerIds'] = {};
global.roomData[roomId] = room;
numRooms = numRooms + 1;
response = {
success: true,
message: 'Room Created: '+roomName,
};
}
if(dump){
console.log(response);
console.log('');
}
return response;
}
function requestJoinRoom(socket, playerName, roomId){
console.log('+ requestJoinRoom recieved');
let room = global.roomData[roomId];
// https://stackoverflow.com/a/18096649
socket.playerId = playerName;
if(room === undefined){
console.log('>> Room does not exist');
return 'error';
}
let roomName = 'Room_' + roomId;
let people = room['people'];
if(isUserInRoom(playerName, roomId)){
console.log('>> Already in room');
return 'already in room';
}
if (people < maxPlayersPerRoom) {
// Update people in room count
people = room['people'] += 1;
// Add playerId to room (playerName for now while Ids don't exist TODO)
room['playerIds'][playerName] = playerName;
// https://socket.io/docs/v4/rooms/
// https://stackoverflow.com/a/25028953
socket.join(roomId);
console.log('>> User ' + playerName +
' connected on ' + roomName + ' (' + (people) + '/' + maxPlayersPerRoom + ')');
// Joined room (emit to the player that just joined)
global.io.to(socket.id).emit('responseRoom', response);
if (people >= maxPlayersPerRoom) {
console.log('- starting game');
// startGame for room
startGame(roomId);
}
}
}
// Will need to be different to playerName in future (in case dupes)
// would use playerId TODO
function isUserInRoom(playerName, roomId){
if(playerName in global.roomData[roomId]['playerIds']){
return true;
}
return false;
}
async function startGame(roomId){
console.log('>> Room: ' + roomId + ': Requesting game...');
let people = global.roomData[roomId].players;
/*
try {
//people = io.sockets.adapter.rooms.get(roomId).size;
} catch (e) {
console.log('>> Room: ' + roomId + ': No people here...');
return;
}
*/
// For now, if there's 2 people only. Will need changing for
// 3v1, 5v1, 2v2, etc...
let response = {success: false, message: 'Failed requestStartGame() server.js'};
if(people < maxPlayersPerRoom){
console.log('Too few people');
}
console.log('>> Room: ' + roomId + ': Starting');
// https://stackoverflow.com/a/25028953
//console.log(util.inspect(io.sockets.adapter.rooms.get(roomId), true, 4, true))
let clients = global.io.sockets.adapter.rooms.get(roomId);
// This should return the deck data, etc. for each client
// ideally only returning the items that the user can/should
// see i.e. shouldn't give them the inDeck card list just a counter
// shouldn't have opponent card data/their hand shouldn't be flipped
// Not sure how to catch errors for these await alls
// TODO: Look into error handling for await alls
const [itemData] =
await Promise.all([
roomMod.roomGeneration(roomId),
]);
// data is the 'itemData' not all the roomData
response.success = true;
response.message = itemData;
// Each player then gets sent the roomGeneration stuff
for (const clientId of clients) {
const clientSocket = global.io.sockets.sockets.get(clientId);
console.log('>> responseStartGame: '+clientSocket.playerId);
// TODO: TESTING STUFF, REMOVE WHEN SORTED
let message = 'You are player: '+roomData[roomId].playerOrder[clientSocket.playerId];
global.socketAlert(clientSocket.id, message, 'alert');
// Emit the itemData to client socket (TODO: only emit what each player should see/recieve)
global.io.to(clientSocket.id).emit('responseStartGame', response);
}
}
// TODO: Need a 'leave room'/disconnect
module.exports = {
requestRooms
,requestJoinRoom
,requestCreateRoom
};

@ -1,13 +1,21 @@
const express = require('express');
const database = require('./database');
const cardGen = require('./cardGen');
const roomMod = require('./roomMod');
const rooms = require('./rooms');
const gameMod = require('./gameMod');
const app = express();
const http = require('http').Server(app);
const port = process.env.PORT || 3000;
const io = require('socket.io')(http);
global.io = io;
// To log the player sockets, so they can be easily referred to
// maybe jank, but can't see alternative currently
global.playerSocket = {};
global.roomData = {}; // Made global for now, as to not replicate. Maybe sub-optimal?
// util is what nodejs uses for console.log, but has a depth of 2 set
// so console.logs show [Array]/[Object] instead of useful info.
// This can be overridden console.log(util.inspect(LOGDATA, true, 4, true))
@ -21,309 +29,38 @@ database.connect();
io.on('connection', onConnection);
// Variables
let numRooms = 0;
let numRoomsToPreGen = 1;
const maxRooms = 3;
const maxPlayersPerRoom = 2;
const maxSpectatorsPerRoom = 0;
// All the room
//let data = []; // Normal array
let data = {}; // Object array (this one for returning to player, and JSON stringify while keeping named ids)
let roomData = {};
for (let roomId = 1; roomId <= numRoomsToPreGen; roomId++) {
// Never have more rooms than max rooms!!!
if(numRooms > maxRooms){
break;
}
createRoom(roomId);
}
function onConnection(socket){
console.log('+ User connected');
console.log('');
// Rooms (joining, creating, etc)
socket.on('requestRooms', function(filter) {
requestRooms(socket, filter);
rooms.requestRooms(socket, filter);
});
socket.on('requestJoinRoom', function(playerName, roomId) {
requestJoinRoom(socket, playerName, roomId);
rooms.requestJoinRoom(socket, playerName, roomId);
});
socket.on('requestCreateRoom', function(playerName) {
requestCreateRoom(socket, playerName);
rooms.requestCreateRoom(socket, playerName);
});
}
function requestRooms(socket, filter){
console.log('+ requestRooms recieved');
console.log('- filter: '+filter);
let response = getRooms(filter, dump = true);
io.to(socket.id).emit('returnRooms', response);
console.log('');
}
function getRooms(filter = 'all', dump = false){
console.log('+ getRooms');
let response = {
random: 'randomStuff',
roomData: roomData,
};
if(dump){
console.log(response);
console.log('');
}
return response;
}
function requestCreateRoom(socket, playerName){
console.log('+ createRoom recieved');
console.log('- requested by: '+playerName);
response = createRoom(roomId = false, dump = true);
io.to(socket.id).emit('returnCreateRoom', response);
if(response.success){
let response = getRooms(filter = 'all', dump = true);
io.to(socket.id).emit('returnRooms', response);
}
console.log('');
}
function createRoom(roomId = false, dump = true){
let roomName = false;
if(roomId == false){
roomId = numRooms + 1;
}
console.log(roomId);
let response = {
success: false,
message: 'No idea bossman'
};
// Max room limit reached
console.log(numRooms);
console.log(maxRooms);
if(numRooms >= maxRooms){
console.log('- Room limit reached');
response = {
success: false,
message: 'No space '+numRooms+' out of '+maxRooms+' created.'
};
// Create room
}else{
console.log('- Creating room')
let room = {};
room['id'] = roomId;
room['name'] = 'Room:'+room['id'];
roomName = room['name'];
room['password'] = '';
room['timeout'] = {};
room['timeout']['s'] = 10;
room['people'] = 0;
room['playerIds'] = {};
//room['deck'] = [];
//room['turn'] = 0;
// Removed players for now, players may be seperate
// and back-end only with an assoc. to current room
//let players = {};
//for (let j = 0; j < maxPlayersPerRoom; j++) {
//let p = {};
//p['id'] = 0;
//p['name'] = "";
//p['hand'] = {};
//players[j] = p;
//}
//room['players'] = players;
roomData[roomId] = room;
numRooms = numRooms + 1;
response = {
success: true,
message: 'Room Created: '+roomName,
};
}
if(dump){
console.log(response);
console.log('');
}
return response;
}
// TODO: break into requestJoinRoom, and JoinRoom?
// Maybe not needed here? As won't be done via backend?
// TODO: Need a 'leave room'/disconnect
function requestJoinRoom(socket, playerName, roomId){
console.log('+ requestJoinRoom recieved');
let room = roomData[roomId];
// Add socket for playerName so that players in room get
// responses, etc. from the room (something like that)
// Add player to socket object, so it can be referred to
// as each socket is individual to a player, but rooms need to
// emit to multiple players. These .player can be used in loops
// https://socket.io/docs/v4/rooms/
// https://stackoverflow.com/a/18096649
socket.playerId = playerName;
if(room === undefined){
io.to(socket.id).emit('responseRoom', 'error');
console.log('>> Room does not exist');
}
let roomName = 'Room_' + roomId;
let people = room['people'];
// people = io.sockets.adapter.rooms[roomId].length; // This gets the sockets in the room (i.e. the players)
//console.log(util.inspect(io.sockets.adapter.rooms, true, 4, true))
//console.log('- people(socket: '+io.sockets.adapter.rooms[player]+')');
//console.log('- maxPlayersPerRoom: '+maxPlayersPerRoom);
if(isUserInRoom(playerName, roomId)){
console.log('Already in room');
return false;
}
if (people < maxPlayersPerRoom) {
// Update people in room count
people = room['people'] += 1;
// Add playerId to room (playerName for now while Ids don't exist TODO)
room['playerIds'][playerName] = playerName;
// https://socket.io/docs/v4/rooms/
// https://stackoverflow.com/a/25028953
socket.join(roomId);
// https://stackoverflow.com/a/25028953
//console.log(util.inspect(io.sockets.adapter.rooms.get(roomId), true, 4, true))
/*
let clients = io.sockets.adapter.rooms.get(roomId);
let numClients = clients ? clients.size : 0;
for (const clientId of clients) {
//this is the socket of each client in the room.
const clientSocket = io.sockets.sockets.get(clientId);
console.log(clientSocket.playerId); // The playerId set beggining of func.
}
*/
console.log('>> User ' + playerName +
' connected on ' + roomName + ' (' + (people) + '/' + maxPlayersPerRoom + ')');
// Joined room (emit to the player that just joined)
io.to(socket.id).emit('responseJoinRoom', roomName);
if (people >= maxPlayersPerRoom) {
console.log('- starting game');
// startGame for room
startGame(roomId);
}
}
}
// Will need to be different to playerName in future (in case dupes)
// would use playerId TODO
function isUserInRoom(playerName, roomId){
if(playerName in roomData[roomId]['playerIds']){
return true;
}
return false;
}
function startGame(roomId){
console.log('>> Room: ' + roomId + ': Requesting game...');
let people = roomData[roomId].players;
/*
try {
//people = io.sockets.adapter.rooms.get(roomId).size;
} catch (e) {
console.log('>> Room: ' + roomId + ': No people here...');
return;
}
*/
// For now, if there's 2 people only. Will need changing for
// 3v1, 5v1, 2v2, etc...
let response = {success: false, message: 'Failed requestStartGame() server.js'};
if(people < maxPlayersPerRoom){
console.log('Too few people');
}
console.log('>> Room: ' + roomId + ': Starting');
// https://stackoverflow.com/a/25028953
//console.log(util.inspect(io.sockets.adapter.rooms.get(roomId), true, 4, true))
let clients = io.sockets.adapter.rooms.get(roomId);
/*
for (const clientId of clients) {
//this is the socket of each client in the room.
const clientSocket = io.sockets.sockets.get(clientId);
console.log(clientSocket.playerId); // The playerId set in requestJoin
// Just so I know how to access stuff in future.
console.log(roomData[roomId].playerIds[clientSocket.playerId] + 'is in the game');
}
*/
// This should return the deck data, etc. for each client
// ideally only returning the items that the user can/should
// see i.e. shouldn't give them the inDeck card list just a counter
// shouldn't have opponent card data/their hand shouldn't be flipped
roomMod.roomGeneration().then(data => {
response.success = true;
response.message = data;
// Each player then gets the roomGeneration stuff
for (const clientId of clients) {
const clientSocket = io.sockets.sockets.get(clientId);
console.log('>> responseStartGame: '+clientSocket.playerId);
// Emit to client socket
io.to(clientSocket.id).emit('responseStartGame', response);
}
})
.catch(err => {
response.message = err;
// Each player then gets the error message
for (const clientId of clients) {
const clientSocket = io.sockets.sockets.get(clientId);
// Emit to client socket
io.to(clientSocket.id).emit('responseStartGame', err);
}
// Game (actual things relating to the game)
// The socket should only be in one game, so socket.on should
// do this, but passing room/player anyways as it's how I've written some
// roomData bits. TODO: Look if I can do this better...
socket.on('passTurn', function(roomId, playerId) {
gameMod.passTurn(roomId, playerId);
});
}
// Then do functions like this?
function shuffleDeck(roomId, playerId){
// Globals for easier clientside alerts/logs, etc.
global.socketAlert = function(socket, message, type = 'alert'){
global.io.to(socket).emit(
type, {'message': message}
);
}

Loading…
Cancel
Save