diff --git a/server/BotCommandHandler.js b/server/BotCommandHandler.js index 0179d02..534f222 100644 --- a/server/BotCommandHandler.js +++ b/server/BotCommandHandler.js @@ -1,5 +1,6 @@ const osu = require("osu-packet"), maths = require("./util/Maths.js"), + Streams = require("./Streams.js"), OsuBattleRoyale = require("./MultiplayerExtras/OsuBattleRoyale.js"); module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false) { @@ -123,7 +124,7 @@ module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false target: "#multiplayer", senderId: global.botUser.id }); - global.StreamsHandler.sendToStream(Stream, local_osuPacketWriter.toBuffer, null); + Streams.sendToStream(Stream, local_osuPacketWriter.toBuffer, null); } else if (countdown == 0) { local_osuPacketWriter.SendMessage({ sendingClient: global.botUser.username, @@ -131,7 +132,7 @@ module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false target: "#multiplayer", senderId: global.botUser.id }); - global.StreamsHandler.sendToStream(Stream, local_osuPacketWriter.toBuffer, null); + Streams.sendToStream(Stream, local_osuPacketWriter.toBuffer, null); User.currentMatch.matchStartCountdownActive = false; setTimeout(() => User.currentMatch.startMatch(), 1000); clearInterval(intervalRef); @@ -159,7 +160,7 @@ module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false senderId: global.botUser.id }); User.currentMatch.multiplayerExtras = null; - global.StreamsHandler.sendToStream(Stream, commandBanchoPacketWriter.toBuffer, null); + Streams.sendToStream(Stream, commandBanchoPacketWriter.toBuffer, null); } else enableOBR(User, Stream, commandBanchoPacketWriter); } @@ -190,7 +191,7 @@ module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false }); } } - global.StreamsHandler.sendToStream(Stream, osuPacketWriter.toBuffer, null); + Streams.sendToStream(Stream, osuPacketWriter.toBuffer, null); } function enableOBR(User, Stream, commandBanchoPacketWriter) { @@ -208,5 +209,5 @@ function enableOBR(User, Stream, commandBanchoPacketWriter) { target: "#multiplayer", senderId: global.botUser.id }); - global.StreamsHandler.sendToStream(Stream, commandBanchoPacketWriter.toBuffer, null); + Streams.sendToStream(Stream, commandBanchoPacketWriter.toBuffer, null); } \ No newline at end of file diff --git a/server/DatabaseHelper.js b/server/DatabaseHelper.js index 60463f6..80e1253 100644 --- a/server/DatabaseHelper.js +++ b/server/DatabaseHelper.js @@ -1,7 +1,8 @@ const mysql = require("mysql2"); +const consoleHelper = require("../consoleHelper.js"); module.exports = class { - constructor(databaseAddress, databasePort = 3306, databaseUsername, databasePassword, databaseName) { + constructor(databaseAddress, databasePort = 3306, databaseUsername, databasePassword, databaseName, connectedCallback) { this.connectionPool = mysql.createPool({ connectionLimit: 128, host: databaseAddress, @@ -10,6 +11,24 @@ module.exports = class { password: databasePassword, database: databaseName }); + + const classCreationTime = Date.now(); + this.dbActive = false; + if (connectedCallback == null) { + this.dbActive = true; + } else { + const connectionCheckInterval = setInterval(() => { + this.query("SELECT name FROM osu_info LIMIT 1") + .then(data => { + consoleHelper.printBancho(`Connected to database. Took ${Date.now() - classCreationTime}ms`); + this.dbActive = true; + clearInterval(connectionCheckInterval); + + connectedCallback(); + }) + .catch(err => {}); + }, 167); // Roughly 6 times per sec + } } query(query = "", data) { diff --git a/server/MultiplayerExtras/OsuBattleRoyale.js b/server/MultiplayerExtras/OsuBattleRoyale.js index 93d59b6..9b9af4d 100644 --- a/server/MultiplayerExtras/OsuBattleRoyale.js +++ b/server/MultiplayerExtras/OsuBattleRoyale.js @@ -1,6 +1,7 @@ const osu = require("osu-packet"), MultiplayerMatch = require("../MultiplayerMatch.js"), - getUserById = require("../util/getUserById.js"); + getUserById = require("../util/getUserById.js"), + Streams = require("../Streams.js"); function sameScoreCheck(playerScores = [{playerId:0,slotId:0,score:0,isCurrentlyFailed:false}], lowestScore = 0) { for (let playerScore of playerScores) { @@ -27,8 +28,8 @@ function kickLowScorers(playerScores = [{playerId:0,slotId:0,score:0,isCurrently slot.playerId = -1; slot.status = 2; // Remove the kicked player from the match's stream - global.StreamsHandler.removeUserFromStream(MultiplayerMatch.matchStreamName, kickedPlayer.uuid); - global.StreamsHandler.removeUserFromStream(MultiplayerMatch.matchChatStreamName, kickedPlayer.uuid); + Streams.removeUserFromStream(MultiplayerMatch.matchStreamName, kickedPlayer.uuid); + Streams.removeUserFromStream(MultiplayerMatch.matchChatStreamName, kickedPlayer.uuid); // Remove the kicked player's referance this this match kickedPlayer.currentMatch = null; @@ -52,7 +53,7 @@ function kickLowScorers(playerScores = [{playerId:0,slotId:0,score:0,isCurrently senderId: global.botUser.id }); - global.StreamsHandler.sendToStream(MultiplayerMatch.matchChatStreamName, osuPacketWriter.toBuffer, null); + Streams.sendToStream(MultiplayerMatch.matchChatStreamName, osuPacketWriter.toBuffer, null); } } } diff --git a/server/MultiplayerManager.js b/server/MultiplayerManager.js index 58a9a10..844b5db 100644 --- a/server/MultiplayerManager.js +++ b/server/MultiplayerManager.js @@ -3,6 +3,7 @@ const osu = require("osu-packet"), UserPresence = require("./Packets/UserPresence.js"), StatusUpdate = require("./Packets/StatusUpdate.js"), MultiplayerMatch = require("./MultiplayerMatch.js"), + Streams = require("./Streams.js"), User = require("./User.js"); module.exports = class { @@ -16,10 +17,10 @@ module.exports = class { currentUser.currentMatch.leaveMatch(currentUser); // Add user to the stream for the lobby - global.StreamsHandler.addUserToStream("multiplayer_lobby", currentUser.uuid); + Streams.addUserToStream("multiplayer_lobby", currentUser.uuid); // Send user ids of all online users to all users in the lobby - global.StreamsHandler.sendToStream("multiplayer_lobby", UserPresenceBundle(currentUser, false), null); + Streams.sendToStream("multiplayer_lobby", UserPresenceBundle(currentUser, false), null); // Loop through all matches for (let i = 0; i < this.matches.length; i++) { @@ -30,8 +31,8 @@ module.exports = class { if (slot.playerId == -1 || slot.status == 2) continue; // Send information for this user to all users in the lobby - global.StreamsHandler.sendToStream("multiplayer_lobby", UserPresence(currentUser, slot.playerId, false), null); - global.StreamsHandler.sendToStream("multiplayer_lobby", StatusUpdate(currentUser, slot.playerId, false), null); + Streams.sendToStream("multiplayer_lobby", UserPresence(currentUser, slot.playerId, false), null); + Streams.sendToStream("multiplayer_lobby", StatusUpdate(currentUser, slot.playerId, false), null); } const osuPacketWriter = new osu.Bancho.Writer; @@ -40,11 +41,12 @@ module.exports = class { currentUser.addActionToQueue(osuPacketWriter.toBuffer); } + const osuPacketWriter = new osu.Bancho.Writer; // Add the user to the #lobby channel - if (!global.StreamsHandler.isUserInStream("#lobby", currentUser.uuid)) { - global.StreamsHandler.addUserToStream("#lobby", currentUser.uuid); + if (!Streams.isUserInStream("#lobby", currentUser.uuid)) { + Streams.addUserToStream("#lobby", currentUser.uuid); osuPacketWriter.ChannelJoinSuccess("#lobby"); } @@ -53,13 +55,13 @@ module.exports = class { userLeaveLobby(currentUser) { // Remove user from the stream for the multiplayer lobby if they are a part of it - if (global.StreamsHandler.isUserInStream("multiplayer_lobby", currentUser.uuid)) - global.StreamsHandler.removeUserFromStream("multiplayer_lobby", currentUser.uuid); + if (Streams.isUserInStream("multiplayer_lobby", currentUser.uuid)) + Streams.removeUserFromStream("multiplayer_lobby", currentUser.uuid); } updateMatchListing() { // Send user ids of all online users to all users in the lobby - global.StreamsHandler.sendToStream("multiplayer_lobby", UserPresenceBundle(null, false), null); + Streams.sendToStream("multiplayer_lobby", UserPresenceBundle(null, false), null); // List through all matches for (let i = 0; i < this.matches.length; i++) { @@ -70,8 +72,8 @@ module.exports = class { if (slot.playerId == -1 || slot.status == 2) continue; // Send information for this user to all users in the lobby - global.StreamsHandler.sendToStream("multiplayer_lobby", UserPresence(null, slot.playerId, false), null); - global.StreamsHandler.sendToStream("multiplayer_lobby", StatusUpdate(null, slot.playerId, false), null); + Streams.sendToStream("multiplayer_lobby", UserPresence(null, slot.playerId, false), null); + Streams.sendToStream("multiplayer_lobby", StatusUpdate(null, slot.playerId, false), null); } const osuPacketWriter = new osu.Bancho.Writer; @@ -79,13 +81,13 @@ module.exports = class { osuPacketWriter.MatchNew(this.matches[i].createOsuMatchJSON()); // Send this data back to every user in the lobby - global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null); + Streams.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null); } } - createMultiplayerMatch(MatchHost, MatchData) { + async createMultiplayerMatch(MatchHost, MatchData) { let matchClass = null; - this.matches.push(matchClass = new MultiplayerMatch(MatchHost, MatchData)); + this.matches.push(matchClass = await MultiplayerMatch.createMatch(MatchHost, MatchData)); // Join the user to the newly created match this.joinMultiplayerMatch(MatchHost, { @@ -139,11 +141,11 @@ module.exports = class { JoiningUser.inMatch = true; // Add user to the stream for the match - global.StreamsHandler.addUserToStream(streamName, JoiningUser.uuid); - global.StreamsHandler.addUserToStream(chatStreamName, JoiningUser.uuid); + Streams.addUserToStream(streamName, JoiningUser.uuid); + Streams.addUserToStream(chatStreamName, JoiningUser.uuid); // Inform all users in the match that a new user has joined - global.StreamsHandler.sendToStream(streamName, osuPacketWriter1.toBuffer, null); + Streams.sendToStream(streamName, osuPacketWriter1.toBuffer, null); osuPacketWriter.ChannelJoinSuccess("#multiplayer"); @@ -165,7 +167,7 @@ module.exports = class { } } - leaveMultiplayerMatch(MatchUser = new User) { + async leaveMultiplayerMatch(MatchUser = new User) { // Make sure the user is in a match if (MatchUser.currentMatch == null) return; @@ -202,6 +204,9 @@ module.exports = class { // Remove this match from the list of active matches this.matches.splice(matchIndex, 1); + + // Close the db match + global.DatabaseHelper.query("UPDATE mp_matches SET close_time = UNIX_TIMESTAMP() WHERE id = ?", [mpMatch.matchId]); } MatchUser.currentMatch = null; @@ -211,11 +216,6 @@ module.exports = class { // Update the match listing to reflect this change (either removal or user leaving) this.updateMatchListing(); - - // Delay a 2nd match listing update - setTimeout(() => { - this.updateMatchListing(); - }, 1000); } getMatch(MatchID) { diff --git a/server/MultiplayerMatch.js b/server/MultiplayerMatch.js index 0ca6082..29d54a5 100644 --- a/server/MultiplayerMatch.js +++ b/server/MultiplayerMatch.js @@ -1,13 +1,16 @@ const osu = require("osu-packet"), getUserById = require("./util/getUserById.js"), StatusUpdate = require("./Packets/StatusUpdate.js"), + Streams = require("./Streams.js"), User = require("./User.js"); // TODO: Cache the player's slot position in their user class for a small optimisation -module.exports = class { - constructor(MatchHost = new User, MatchData = {matchId: -1,inProgress: false,matchType: 0,activeMods: 0,gameName: "",gamePassword: '',beatmapName: '',beatmapId: 1250198,beatmapChecksum: '',slots: [],host: 0,playMode: 0,matchScoringType: 0,matchTeamType: 0,specialModes: 0,seed: 0}) { - this.matchId = global.getAndAddToHistoricalMultiplayerMatches(); +class MultiplayerMatch { + constructor(MatchData = {matchId: -1,inProgress: false,matchType: 0,activeMods: 0,gameName: "",gamePassword: '',beatmapName: '',beatmapId: 0,beatmapChecksum: '',slots: [],host: 0,playMode: 0,matchScoringType: 0,matchTeamType: 0,specialModes: 0,seed: 0}) { + this.matchId = MatchData.matchId; + + this.roundId = 0; this.inProgress = MatchData.inProgress; this.matchStartCountdownActive = false; @@ -51,21 +54,43 @@ module.exports = class { this.isTourneyMatch = false; this.tourneyClientUsers = []; + } - const osuPacketWriter = new osu.Bancho.Writer; + static createMatch(MatchHost = new User, MatchData = {matchId: -1,inProgress: false,matchType: 0,activeMods: 0,gameName: "",gamePassword: '',beatmapName: '',beatmapId: 0,beatmapChecksum: '',slots: [],host: 0,playMode: 0,matchScoringType: 0,matchTeamType: 0,specialModes: 0,seed: 0}) { + return new Promise(async (resolve, reject) => { + MatchData.matchId = (await global.DatabaseHelper.query( + "INSERT INTO mp_matches (id, name, open_time, close_time, seed) VALUES (NULL, ?, UNIX_TIMESTAMP(), NULL, ?) RETURNING id;", + [MatchData.gameName, MatchData.seed] + ))[0]["id"]; - // Update the status of the current user - StatusUpdate(MatchHost, MatchHost.id); - osuPacketWriter.MatchNew(this.createOsuMatchJSON()); + const matchInstance = new MultiplayerMatch(MatchData); - // Queue match creation for user - MatchHost.addActionToQueue(osuPacketWriter.toBuffer); + console.log(matchInstance.matchId); - global.StreamsHandler.addStream(this.matchStreamName, true, this.matchId); - global.StreamsHandler.addStream(this.matchChatStreamName, true, this.matchId); + // Update the status of the current user + StatusUpdate(MatchHost, MatchHost.id); - // Update the match listing for users in the multiplayer lobby - global.MultiplayerManager.updateMatchListing(); + const osuPacketWriter = new osu.Bancho.Writer; + + osuPacketWriter.MatchNew(matchInstance.createOsuMatchJSON()); + + MatchHost.addActionToQueue(osuPacketWriter.toBuffer); + + Streams.addStream(matchInstance.matchStreamName, true, matchInstance.matchId); + Streams.addStream(matchInstance.matchChatStreamName, true, matchInstance.matchId); + + // Update the match listing for users in the multiplayer lobby + global.MultiplayerManager.updateMatchListing(); + + resolve(matchInstance); + }); + } + + getSlotIdByPlayerId(playerId = 0) { + const player = getUserById(playerId); + + if (player != null) return player.matchSlotId; + else return null; } createOsuMatchJSON() { @@ -101,8 +126,8 @@ module.exports = class { slot.status = 1; // Remove the leaving user from the match's stream - global.StreamsHandler.removeUserFromStream(this.matchStreamName, MatchUser.uuid); - global.StreamsHandler.removeUserFromStream(this.matchChatStreamName, MatchUser.uuid); + Streams.removeUserFromStream(this.matchStreamName, MatchUser.uuid); + Streams.removeUserFromStream(this.matchChatStreamName, MatchUser.uuid); // Send this after removing the user from match streams to avoid a leave notification for self this.sendMatchUpdate(); @@ -115,7 +140,7 @@ module.exports = class { MatchUser.addActionToQueue(osuPacketWriter.toBuffer); } - updateMatch(MatchUser = new User, MatchData) { + async updateMatch(MatchUser = new User, MatchData) { // Update match with new data this.inProgress = MatchData.inProgress; @@ -123,7 +148,10 @@ module.exports = class { this.activeMods = MatchData.activeMods; - this.gameName = MatchData.gameName; + if (this.gameName !== MatchData.gameName) { + this.gameName = MatchData.gameName; + await global.DatabaseHelper.query("UPDATE mp_matches SET name = ? WHERE id = ?", [this.gameName, this.matchId]); + } if (MatchData.gamePassword == '') MatchData.gamePassword == null; this.gamePassword = MatchData.gamePassword; @@ -139,7 +167,10 @@ module.exports = class { this.matchTeamType = MatchData.matchTeamType; this.specialModes = MatchData.specialModes; - this.seed = MatchData.seed; + if (this.seed !== MatchData.seed) { + this.seed = MatchData.seed; + await global.DatabaseHelper.query("UPDATE mp_matches SET seed = ? WHERE id = ?", [this.seed, this.matchId]); + } this.sendMatchUpdate(); @@ -153,7 +184,8 @@ module.exports = class { osuPacketWriter.MatchUpdate(this.createOsuMatchJSON()); // Update all users in the match with new match information - global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); + if (Streams.exists(this.matchStreamName)) + Streams.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); } moveToSlot(MatchUser = new User, SlotToMoveTo) { @@ -234,7 +266,7 @@ module.exports = class { if (cachedPlayerToken !== null && cachedPlayerToken !== "") { // Remove the kicked user from the match stream - global.StreamsHandler.removeUserFromStream(this.matchStreamName, cachedPlayerToken); + Streams.removeUserFromStream(this.matchStreamName, cachedPlayerToken); } } } @@ -288,7 +320,7 @@ module.exports = class { osuPacketWriter.MatchPlayerSkipped(MatchUser.id); osuPacketWriter.MatchSkip(); - global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); + Streams.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); this.matchSkippedSlots = null; } else { @@ -296,7 +328,7 @@ module.exports = class { osuPacketWriter.MatchPlayerSkipped(MatchUser.id); - global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); + Streams.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); } } @@ -356,7 +388,7 @@ module.exports = class { osuPacketWriter.MatchStart(this.createOsuMatchJSON()); // Inform all users in the match that it has started - global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); + Streams.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); // Update all users in the match with new info this.sendMatchUpdate(); @@ -383,7 +415,7 @@ module.exports = class { if (allLoaded) { let osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.MatchAllPlayersLoaded(); - global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); + Streams.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); // Blank out user loading array this.matchLoadSlots = null; @@ -432,25 +464,42 @@ module.exports = class { if (allLoaded) this.finishMatch(); } - finishMatch() { + async finishMatch() { if (!this.inProgress) return; this.matchLoadSlots = null; this.inProgress = false; let osuPacketWriter = new osu.Bancho.Writer; + let queryData = [this.matchId, this.roundId++, this.playMode, this.matchType, this.matchScoringType, this.matchTeamType, this.activeMods, this.beatmapChecksum, (this.specialModes === 1) ? 1 : 0]; + // Loop through all slots in the match for (let slot of this.slots) { // Make sure the slot has a user - if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue; + if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) { + queryData.push(null); + continue; + } + + let score = null; + for (let _playerScore of this.playerScores) { + if (_playerScore.playerId === slot.playerId) { + score = _playerScore._raw; + break; + } + } + + queryData.push(`${slot.playerId}|${score.totalScore}|${score.maxCombo}|${score.count300}|${score.count100}|${score.count50}|${score.countGeki}|${score.countKatu}|${score.countMiss}|${(score.currentHp == 254) ? 1 : 0}${(this.specialModes === 1) ? `|${slot.mods}` : ""}|${score.usingScoreV2 ? 1 : 0}${score.usingScoreV2 ? `|${score.comboPortion}|${score.bonusPortion}` : ""}`); // Set the user's status back to normal from playing slot.status = 4; } + console.log(queryData); + osuPacketWriter.MatchComplete(); // Inform all users in the match that it is complete - global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); + Streams.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); // Update all users in the match with new info this.sendMatchUpdate(); @@ -460,6 +509,8 @@ module.exports = class { if (this.multiplayerExtras != null) this.multiplayerExtras.onMatchFinished(JSON.parse(JSON.stringify(this.playerScores))); + await global.DatabaseHelper.query("INSERT INTO mp_match_rounds (id, match_id, round_id, round_mode, match_type, round_scoring_type, round_team_type, round_mods, beatmap_md5, freemod, player0, player1, player2, player3, player4, player5, player6, player7, player8, player9, player10, player11, player12, player13, player14, player15) VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", queryData); + this.playerScores = null; } @@ -477,6 +528,7 @@ module.exports = class { if (playerScore.playerId == MatchPlayer.id) { playerScore.score = MatchScoreData.totalScore; playerScore.isCurrentlyFailed = MatchScoreData.currentHp == 254; + playerScore._raw = MatchScoreData; break; } } @@ -484,7 +536,7 @@ module.exports = class { osuPacketWriter.MatchScoreUpdate(MatchScoreData); // Send the newly updated score to all users in the match - global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); + Streams.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); } matchFailed(MatchUser = new User) { @@ -495,6 +547,8 @@ module.exports = class { osuPacketWriter.MatchPlayerFailed(MatchUser.id); - global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); + Streams.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null); } -} \ No newline at end of file +} + +module.exports = MultiplayerMatch; \ No newline at end of file diff --git a/server/Packets/ChangeAction.js b/server/Packets/ChangeAction.js index f4d71a0..1ce77a6 100644 --- a/server/Packets/ChangeAction.js +++ b/server/Packets/ChangeAction.js @@ -1,10 +1,11 @@ -const StatusUpdate = require("./StatusUpdate.js"); +const StatusUpdate = require("./StatusUpdate.js"), + Streams = require("../Streams.js"); module.exports = function(currentUser, data) { currentUser.updatePresence(data); - if (global.StreamsHandler.doesStreamExist(`sp_${currentUser.username}`)) { + if (Streams.exists(`sp_${currentUser.username}`)) { const statusUpdate = StatusUpdate(currentUser, currentUser.id, false); - global.StreamsHandler.sendToStream(`sp_${currentUser.username}`, statusUpdate, null); + Streams.sendToStream(`sp_${currentUser.username}`, statusUpdate, null); } } \ No newline at end of file diff --git a/server/Packets/ChannelJoin.js b/server/Packets/ChannelJoin.js index 7e6a1d1..e535754 100644 --- a/server/Packets/ChannelJoin.js +++ b/server/Packets/ChannelJoin.js @@ -1,16 +1,17 @@ const osu = require("osu-packet"), - consoleHelper = require("../../consoleHelper.js"); + consoleHelper = require("../../consoleHelper.js"), + Streams = require("../Streams.js"); module.exports = function(CurrentUser, channelName = "") { // Make sure the user is not already in the channel - if (global.StreamsHandler.isUserInStream(channelName, CurrentUser.uuid)) + if (Streams.isUserInStream(channelName, CurrentUser.uuid)) return consoleHelper.printBancho(`Did not add user to channel ${channelName} because they are already in it`); const osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.ChannelJoinSuccess(channelName); - if (!global.StreamsHandler.isUserInStream(channelName, CurrentUser.uuid)) - global.StreamsHandler.addUserToStream(channelName, CurrentUser.uuid); + if (!Streams.isUserInStream(channelName, CurrentUser.uuid)) + Streams.addUserToStream(channelName, CurrentUser.uuid); CurrentUser.addActionToQueue(osuPacketWriter.toBuffer); } \ No newline at end of file diff --git a/server/Packets/ChannelPart.js b/server/Packets/ChannelPart.js index 9632eca..02640dd 100644 --- a/server/Packets/ChannelPart.js +++ b/server/Packets/ChannelPart.js @@ -1,5 +1,7 @@ +const Streams = require("../Streams.js"); + module.exports = function(CurrentUser, data) { if (data == "#multiplayer") return; // Ignore requests for multiplayer - global.StreamsHandler.removeUserFromStream(data, CurrentUser.uuid); + Streams.removeUserFromStream(data, CurrentUser.uuid); } \ No newline at end of file diff --git a/server/Packets/Logout.js b/server/Packets/Logout.js index feea405..5ee25c4 100644 --- a/server/Packets/Logout.js +++ b/server/Packets/Logout.js @@ -1,21 +1,23 @@ -const osu = require("osu-packet"), - consoleHelper = require("../../consoleHelper.js"); +const consoleHelper = require("../../consoleHelper.js"), + Streams = require("../Streams.js"); module.exports = function(CurrentUser) { if (CurrentUser.uuid === "bot") throw "Tried to log bot out, WTF???"; const logoutStartTime = Date.now(); - const streamList = global.StreamsHandler.getStreams(); + const streamList = Streams.getStreams(); for (let i = 0; i < streamList.length; i++) { - if (global.StreamsHandler.isUserInStream(streamList[i], CurrentUser.uuid)) { - global.StreamsHandler.removeUserFromStream(streamList[i], CurrentUser.uuid); + if (Streams.isUserInStream(streamList[i], CurrentUser.uuid)) { + Streams.removeUserFromStream(streamList[i], CurrentUser.uuid); } } // Remove user from user list global.users.remove(CurrentUser.uuid); + global.DatabaseHelper.query("UPDATE osu_info SET value = ? WHERE name = 'online_now'", [global.users.getLength() - 1]); + consoleHelper.printBancho(`User logged out, took ${Date.now() - logoutStartTime}ms. [User: ${CurrentUser.username}]`); } \ No newline at end of file diff --git a/server/Packets/SendPublicMessage.js b/server/Packets/SendPublicMessage.js index f69c32b..0a3bf72 100644 --- a/server/Packets/SendPublicMessage.js +++ b/server/Packets/SendPublicMessage.js @@ -1,6 +1,7 @@ const osu = require("osu-packet"), botCommandHandler = require("../BotCommandHandler.js"), - consoleHelper = require("../../consoleHelper.js"); + consoleHelper = require("../../consoleHelper.js"), + Streams = require("../Streams.js"); module.exports = function(CurrentUser, CurrentPacket) { let isSendingChannelLocked = false; @@ -39,16 +40,16 @@ module.exports = function(CurrentUser, CurrentPacket) { }); if (CurrentPacket.target == "#multiplayer") { - global.StreamsHandler.sendToStream(CurrentUser.currentMatch.matchChatStreamName, osuPacketWriter.toBuffer, CurrentUser.uuid); + Streams.sendToStream(CurrentUser.currentMatch.matchChatStreamName, osuPacketWriter.toBuffer, CurrentUser.uuid); botCommandHandler(CurrentUser, CurrentPacket.message, CurrentUser.currentMatch.matchChatStreamName, true); return; } // Check the stream that we're sending to even exists - if (!global.StreamsHandler.doesStreamExist(CurrentPacket.target)) return; + if (!Streams.exists(CurrentPacket.target)) return; // Write chat message to stream asociated with chat channel - global.StreamsHandler.sendToStream(CurrentPacket.target, osuPacketWriter.toBuffer, CurrentUser.uuid); + Streams.sendToStream(CurrentPacket.target, osuPacketWriter.toBuffer, CurrentUser.uuid); if (CurrentPacket.target == "#osu") global.addChatMessage(`${CurrentUser.username}: ${CurrentPacket.message.replaceAll("<", "<").replaceAll(">", ">")}`); diff --git a/server/Packets/TourneyJoinMatchChannel.js b/server/Packets/TourneyJoinMatchChannel.js index be7b9aa..da30de3 100644 --- a/server/Packets/TourneyJoinMatchChannel.js +++ b/server/Packets/TourneyJoinMatchChannel.js @@ -1,5 +1,6 @@ const osu = require("osu-packet"), - consoleHelper = require("./consoleHelper.js"); + consoleHelper = require("./consoleHelper.js"), + Streams = require("../Streams.js"); module.exports = function(CurrentUser, MatchID) { const match = global.MultiplayerManager.getMatch(MatchID); @@ -13,14 +14,14 @@ module.exports = function(CurrentUser, MatchID) { } } - if (global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) + if (Streams.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) return consoleHelper.printBancho(`Did not add user to channel ${match.matchChatStreamName} because they are already in it`); const osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.ChannelJoinSuccess("#multiplayer"); - if (!global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) - global.StreamsHandler.addUserToStream(match.matchChatStreamName, CurrentUser.uuid); + if (!Streams.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) + Streams.addUserToStream(match.matchChatStreamName, CurrentUser.uuid); CurrentUser.addActionToQueue(osuPacketWriter.toBuffer); } diff --git a/server/Packets/TourneyLeaveMatchChannel.js b/server/Packets/TourneyLeaveMatchChannel.js index 8fed8e3..5a3950d 100644 --- a/server/Packets/TourneyLeaveMatchChannel.js +++ b/server/Packets/TourneyLeaveMatchChannel.js @@ -1,5 +1,6 @@ const osu = require("osu-packet"), - consoleHelper = require("../../consoleHelper.js"); + consoleHelper = require("../../consoleHelper.js"), + Streams = require("../Streams.js"); module.exports = function(CurrentUser, MatchID) { const match = global.MultiplayerManager.getMatch(MatchID); @@ -9,14 +10,14 @@ module.exports = function(CurrentUser, MatchID) { match.isTourneyMatch = false; match.tourneyClientUsers = []; - if (global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) + if (Streams.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) return consoleHelper.printBancho(`Did not add user to channel ${match.matchChatStreamName} because they are already in it`); const osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.ChannelRevoked("#multiplayer"); - if (!global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) - global.StreamsHandler.removeUserFromStream(match.matchChatStreamName, CurrentUser.uuid); + if (!Streams.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) + Streams.removeUserFromStream(match.matchChatStreamName, CurrentUser.uuid); CurrentUser.addActionToQueue(osuPacketWriter.toBuffer); } else { diff --git a/server/Spectator.js b/server/Spectator.js index 5989cf1..27fa6f4 100644 --- a/server/Spectator.js +++ b/server/Spectator.js @@ -1,17 +1,18 @@ const osu = require("osu-packet"), - getUserById = require("./util/getUserById.js"); + getUserById = require("./util/getUserById.js"), + Streams = require("./Streams.js"); module.exports = { startSpectatingUser:function(currentUser, spectatedId) { // Get the user this user is trying to spectate const User = getUserById(spectatedId); - if (global.StreamsHandler.doesStreamExist(`sp_${User.id}`)) { + if (Streams.exists(`sp_${User.id}`)) { // Just add user to stream since it already exists - global.StreamsHandler.addUserToStream(`sp_${User.id}`, currentUser.uuid); + Streams.addUserToStream(`sp_${User.id}`, currentUser.uuid); } else { // Stream doesn't exist, create it and add the spectator - global.StreamsHandler.addStream(`sp_${User.id}`, true, spectatedId); - global.StreamsHandler.addUserToStream(`sp_${User.id}`, currentUser.uuid); + Streams.addStream(`sp_${User.id}`, true, spectatedId); + Streams.addUserToStream(`sp_${User.id}`, currentUser.uuid); } // We want to do this stuff regardless @@ -34,7 +35,7 @@ module.exports = { osuPacketWriter.FellowSpectatorJoined(currentUser.id); // Send this packet to all the spectators - global.StreamsHandler.sendToStream(`sp_${User.id}`, osuPacketWriter.toBuffer); + Streams.sendToStream(`sp_${User.id}`, osuPacketWriter.toBuffer); }, sendSpectatorFrames(currentUser, data) { @@ -45,7 +46,7 @@ module.exports = { osuPacketWriter.SpectateFrames(data); // Send the frames to all the spectators - global.StreamsHandler.sendToStream(`sp_${currentUser.id}`, osuPacketWriter.toBuffer, null); + Streams.sendToStream(`sp_${currentUser.id}`, osuPacketWriter.toBuffer, null); }, stopSpectatingUser(currentUser) { @@ -61,7 +62,7 @@ module.exports = { spectatedUser.addActionToQueue(osuPacketWriter.toBuffer); // Remove this user from the spectator stream - global.StreamsHandler.removeUserFromStream(`sp_${spectatedUser.id}`, currentUser.uuid); + Streams.removeUserFromStream(`sp_${spectatedUser.id}`, currentUser.uuid); // Make a new clear osu packet writer osuPacketWriter = new osu.Bancho.Writer; @@ -70,6 +71,6 @@ module.exports = { osuPacketWriter.FellowSpectatorLeft(currentUser.id); // Send this packet to all spectators - global.StreamsHandler.sendToStream(`sp_${spectatedUser.id}`, osuPacketWriter.toBuffer); + Streams.sendToStream(`sp_${spectatedUser.id}`, osuPacketWriter.toBuffer); } } \ No newline at end of file diff --git a/server/Streams.js b/server/Streams.js index 8f5a174..36c796b 100644 --- a/server/Streams.js +++ b/server/Streams.js @@ -2,42 +2,42 @@ const getUserByToken = require("./util/getUserByToken.js"), consoleHelper = require("../consoleHelper.js"); module.exports = class { - constructor() { - this.avaliableStreams = {}; - this.avaliableStreamKeys = []; + static init() { + global.avaliableStreams = {}; + global.avaliableStreamKeys = []; } - addStream(streamName = "", removeIfEmpty = false, spectatorHostId = null) { + static addStream(streamName = "", removeIfEmpty = false, spectatorHostId = null) { // Make sure a stream with the same name doesn't exist already - if (this.avaliableStreamKeys.includes(streamName)) + if (global.avaliableStreamKeys.includes(streamName)) return consoleHelper.printBancho(`Did not add stream [${streamName}] A stream with the same name already exists`); // Add new stream to the list of streams - this.avaliableStreams[streamName] = { + global.avaliableStreams[streamName] = { streamUsers: [], // An array containing a list of user tokens of the users in a given stream streamSpectatorHost: spectatorHostId, // null unless stream is for spectating removeIfEmpty: removeIfEmpty } - this.avaliableStreamKeys = Object.keys(this.avaliableStreams); + global.avaliableStreamKeys = Object.keys(global.avaliableStreams); consoleHelper.printBancho(`Added stream [${streamName}]`); } - removeStream(streamName) { + static removeStream(streamName) { try { - delete this.avaliableStreams[streamName]; - this.avaliableStreamKeys = Object.keys(this.avaliableStreams); + delete global.avaliableStreams[streamName]; + global.avaliableStreamKeys = Object.keys(global.avaliableStreams); } catch (e) { consoleHelper.printError(`Was not able to remove stream [${streamName}]`); console.error(e); } } - addUserToStream(streamName, userToken) { + static addUserToStream(streamName, userToken) { // Make sure the stream we are attempting to add this user to even exists - if (!this.doesStreamExist(streamName)) + if (!this.exists(streamName)) return consoleHelper.printBancho(`Did not add user to stream [${streamName}] because it does not exist!`); // Make sure the user isn't already in the stream - if (this.avaliableStreams[streamName].streamUsers.includes(userToken)) + if (global.avaliableStreams[streamName].streamUsers.includes(userToken)) return consoleHelper.printBancho(`Did not add user to stream [${streamName}] because they are already in it!`); // Make sure this isn't an invalid user (userId can't be lower than 1) @@ -45,16 +45,16 @@ module.exports = class { return consoleHelper.printBancho(`Did not add user to stream [${streamName}] because their token is invalid!`); // Add user's token to the stream's user list - this.avaliableStreams[streamName].streamUsers.push(userToken); + global.avaliableStreams[streamName].streamUsers.push(userToken); consoleHelper.printBancho(`Added user [${userToken}] to stream ${streamName}`); } - removeUserFromStream(streamName, userToken) { + static removeUserFromStream(streamName, userToken) { // Make sure the stream we are attempting to add this user to even exists - if (!this.doesStreamExist(streamName)) + if (!this.exists(streamName)) return consoleHelper.printBancho(`Did not remove user from stream [${streamName}] because it does not exist!`); - const stream = this.avaliableStreams[streamName]; + const stream = global.avaliableStreams[streamName]; // Make sure the user isn't already in the stream if (!stream.streamUsers.includes(userToken)) @@ -82,18 +82,18 @@ module.exports = class { } if (stream.removeIfEmpty && stream.streamUsers.length == 0) { - this.removeStream(stream); + this.removeStream(streamName); consoleHelper.printBancho(`Removed stream [${streamName}] There were no users in stream`); } } - sendToStream(streamName, streamData, initUser = null) { + static sendToStream(streamName, streamData, initUser = null) { // Make sure the stream we are attempting to send to even exists - if (!this.doesStreamExist(streamName)) + if (!this.exists(streamName)) return consoleHelper.printBancho(`Did not send to stream [${streamName}] because it does not exist!`); // Get the stream to send the data to - const currentStream = this.avaliableStreams[streamName]; + const currentStream = global.avaliableStreams[streamName]; // Loop through the users in this stream for (let i = 0; i < currentStream.streamUsers.length; i++) { @@ -113,17 +113,17 @@ module.exports = class { } } - doesStreamExist(streamName) { - return this.avaliableStreamKeys.includes(streamName); + static exists(streamName) { + return global.avaliableStreamKeys.includes(streamName); } - getStreams() { + static getStreams() { // Return the names of all avaliable streams - return this.avaliableStreamKeys; + return global.avaliableStreamKeys; } - isUserInStream(streamName, userToken) { - if (this.avaliableStreams[streamName].streamUsers.includes(userToken)) return true; + static isUserInStream(streamName, userToken) { + if (global.avaliableStreams[streamName].streamUsers.includes(userToken)) return true; else return false; } } \ No newline at end of file diff --git a/server/loginHandler.js b/server/loginHandler.js index f1fec67..68b8f39 100644 --- a/server/loginHandler.js +++ b/server/loginHandler.js @@ -9,6 +9,7 @@ const osu = require("osu-packet"), countryHelper = require("./countryHelper.js"), loginHelper = require("./loginHelper.js"), Logout = require("./Packets/Logout.js"), + Streams = require("./Streams.js"), UserPresenceBundle = require("./Packets/UserPresenceBundle.js"), UserPresence = require("./Packets/UserPresence.js"), StatusUpdate = require("./Packets/StatusUpdate.js"); @@ -110,8 +111,8 @@ module.exports = async function(req, res, loginInfo) { // Add user to #osu osuPacketWriter.ChannelJoinSuccess("#osu"); - if (!global.StreamsHandler.isUserInStream("#osu", NewUser.uuid)) - global.StreamsHandler.addUserToStream("#osu", NewUser.uuid); + if (!Streams.isUserInStream("#osu", NewUser.uuid)) + Streams.addUserToStream("#osu", NewUser.uuid); // List all channels out to the client for (let i = 0; i < global.channels.length; i++) { diff --git a/server/serverHandler.js b/server/serverHandler.js index 91d2e09..f7ad279 100644 --- a/server/serverHandler.js +++ b/server/serverHandler.js @@ -22,7 +22,11 @@ global.botUser = global.users.add("bot", new User(3, "SillyBot", "bot")); global.botUser.location[0] = 50; global.botUser.location[1] = -32; -global.DatabaseHelper = new DatabaseHelperClass(config.database.address, config.database.port, config.database.username, config.database.password, config.database.name); +global.DatabaseHelper = new DatabaseHelperClass(config.database.address, config.database.port, config.database.username, config.database.password, config.database.name, async () => { + // Close any unclosed db matches on startup + global.DatabaseHelper.query("UPDATE mp_matches SET close_time = UNIX_TIMESTAMP() WHERE close_time IS NULL"); + global.DatabaseHelper.query("UPDATE osu_info SET value = 0 WHERE name = 'online_now'"); +}); async function subscribeToChannel(channelName = "", callback = function(message = "") {}) { // Dup and connect new client for channel subscription (required) @@ -81,7 +85,8 @@ global.addChatMessage = function(msg) { } } -global.StreamsHandler = new Streams(); +// Init stream class +Streams.init(); // An array containing all chat channels global.channels = [ @@ -94,19 +99,11 @@ global.channels = [ // Create a stream for each chat channel for (let i = 0; i < global.channels.length; i++) { - global.StreamsHandler.addStream(global.channels[i].channelName, false); + Streams.addStream(global.channels[i].channelName, false); } // Add a stream for the multiplayer lobby -global.StreamsHandler.addStream("multiplayer_lobby", false); - -if (!fs.existsSync("tHMM.ds")) fs.writeFileSync("tHMM.ds", "0"); -global.totalHistoricalMultiplayerMatches = parseInt(fs.readFileSync("tHMM.ds").toString()); -global.getAndAddToHistoricalMultiplayerMatches = function() { - global.totalHistoricalMultiplayerMatches++; - fs.writeFile("tHMM.ds", `${global.totalHistoricalMultiplayerMatches}`, () => {}); - return global.totalHistoricalMultiplayerMatches; -} +Streams.addStream("multiplayer_lobby", false); // Include packets const ChangeAction = require("./Packets/ChangeAction.js"), diff --git a/server/util/getUserByUsername.js b/server/util/getUserByUsername.js index fb0a4bf..d2e8f1b 100644 --- a/server/util/getUserByUsername.js +++ b/server/util/getUserByUsername.js @@ -1,6 +1,6 @@ module.exports = function(username) { for (let user of global.users.getIterableItems()) { - if (user.username == username) + if (user.username === username) return user; } } \ No newline at end of file