const osu = require("osu-packet"), getUserById = require("./util/getUserById.js"), StatusUpdate = require("./Packets/StatusUpdate.js"); module.exports = { userEnterLobby:function(currentUser) { if (currentUser.currentMatch != null) { this.leaveMatch(currentUser); currentUser.currentMatch = null; } global.StreamsHandler.addUserToStream("multiplayer_lobby", currentUser.id); const osuPacketWriter1 = new osu.Bancho.Writer; let userIds = []; for (let i = 0; i < global.users.length; i++) { userIds.push(global.users[i].id); } osuPacketWriter1.UserPresenceBundle(userIds); global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter1.toBuffer, null); for (let i = 0; i < global.matches.length; i++) { for (let i1 = 0; i1 < global.matches[i][1].slots.length; i1++) { const slot = global.matches[i][1].slots[i1]; if (slot.playerId == -1 || slot.status == 2) continue; const osuPacketWriter = new osu.Bancho.Writer; const User = getUserById(slot.playerId); // Get user score info from the database const userScoreDB = global.DatabaseHelper.getFromDB(`SELECT * FROM users_modes_info WHERE user_id = ${User.id} AND mode_id = ${User.playMode} LIMIT 1`); let UserStatusObject = { userId: User.id, status: User.actionID, statusText: User.actionText, beatmapChecksum: User.beatmapChecksum, currentMods: User.currentMods, playMode: User.playMode, beatmapId: User.beatmapID, rankedScore: userScoreDB.ranked_score, accuracy: userScoreDB.avg_accuracy / 100, // Scale of 0 to 1 playCount: userScoreDB.playcount, totalScore: userScoreDB.total_score, rank: 1, performance: userScoreDB.pp_raw }; osuPacketWriter.HandleOsuUpdate(UserStatusObject); global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null); } const osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.MatchNew(global.matches[i][1]); currentUser.addActionToQueue(osuPacketWriter.toBuffer); } const osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.ChannelJoinSuccess("#lobby"); if (!global.StreamsHandler.isUserInStream("#lobby", currentUser.id)) global.StreamsHandler.addUserToStream("#lobby", currentUser.id); currentUser.addActionToQueue(osuPacketWriter.toBuffer); }, updateMatchListing:function() { const osuPacketWriter1 = new osu.Bancho.Writer; let userIds = []; for (let i = 0; i < global.users.length; i++) { userIds.push(global.users[i].id); } osuPacketWriter1.UserPresenceBundle(userIds); global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter1.toBuffer, null); for (let i = 0; i < global.matches.length; i++) { for (let i1 = 0; i1 < global.matches[i][1].slots.length; i1++) { const slot = global.matches[i][1].slots[i1]; if (slot.playerId == -1 || slot.status == 2) continue; const osuPacketWriter = new osu.Bancho.Writer; const User = getUserById(slot.playerId); // Get user score info from the database const userScoreDB = global.DatabaseHelper.getFromDB(`SELECT * FROM users_modes_info WHERE user_id = ${User.id} AND mode_id = ${User.playMode} LIMIT 1`); let UserStatusObject = { userId: User.id, status: User.actionID, statusText: User.actionText, beatmapChecksum: User.beatmapChecksum, currentMods: User.currentMods, playMode: User.playMode, beatmapId: User.beatmapID, rankedScore: userScoreDB.ranked_score, accuracy: userScoreDB.avg_accuracy / 100, // Scale of 0 to 1 playCount: userScoreDB.playcount, totalScore: userScoreDB.total_score, rank: 1, performance: userScoreDB.pp_raw }; osuPacketWriter.HandleOsuUpdate(UserStatusObject); global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null); } const osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.MatchNew(global.matches[i][1]); global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null); } }, createMultiplayerMatch:function(currentUser, data) { const osuPacketWriter = new osu.Bancho.Writer; if (data.gamePassword == '') data.gamePassword == null; let NewMatchObject = { matchId: global.matches.length, inProgress: false, matchType: 0, activeMods: 0, gameName: data.gameName, gamePassword: data.gamePassword, beatmapName: data.beatmapName, beatmapId: data.beatmapId, beatmapChecksum: data.beatmapChecksum, slots: data.slots, host: currentUser.id, playMode: 0, matchScoringType: 0, matchTeamType: 0, specialModes: 0, hidden: false, seed: data.seed } for (let i = 0; i < NewMatchObject.slots.length; i++) { let s = NewMatchObject.slots[i]; s.mods = 0; } StatusUpdate(currentUser, currentUser.id); osuPacketWriter.MatchNew(NewMatchObject); // Queue match creation for user currentUser.addActionToQueue(osuPacketWriter.toBuffer); global.StreamsHandler.addStream(`mp_${data.gameName.split(" ").join("-")}`, true, NewMatchObject.matchId); global.matches.push([`mp_${data.gameName.split(" ").join("-")}`, NewMatchObject]); this.updateMatchListing(); this.joinMultiplayerMatch(currentUser, { matchId: NewMatchObject.matchId, gamePassword: NewMatchObject.gamePassword }); }, joinMultiplayerMatch:function(currentUser, data) { try { let osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter1 = new osu.Bancho.Writer; const streamName = global.matches[data.matchId][0]; const mpLobby = global.matches[data.matchId][1]; let full = true; for (let i = 0; i < mpLobby.slots.length; i++) { const slot = mpLobby.slots[i]; if (slot.playerId !== -1 || slot.status === 2) continue; full = false; slot.playerId = currentUser.id; currentUser.matchSlotId = i; slot.status = 4; break; } osuPacketWriter1.MatchUpdate(mpLobby); osuPacketWriter.MatchJoinSuccess(mpLobby); if (full) { osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.MatchJoinFail(); } else { global.StreamsHandler.removeUserFromStream("multiplayer_lobby", currentUser.id); } currentUser.currentMatch = data.matchId; global.StreamsHandler.addUserToStream(streamName, currentUser.id); global.StreamsHandler.sendToStream(streamName, osuPacketWriter1.toBuffer, null); osuPacketWriter.ChannelJoinSuccess("#multiplayer"); currentUser.addActionToQueue(osuPacketWriter.toBuffer); this.updateMatchListing(); } catch (e) { const osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.MatchJoinFail(); currentUser.addActionToQueue(osuPacketWriter.toBuffer); this.updateMatchListing(); } }, setReadyState:function(currentUser, state) { const mpLobby = global.matches[currentUser.currentMatch][1]; const osuPacketWriter = new osu.Bancho.Writer; for (let i = 0; i < mpLobby.slots.length; i++) { const slot = mpLobby.slots[i]; if (slot.playerId == currentUser.id) { if (state) slot.status = 8; else slot.status = 4; console.log("e"); break; } } osuPacketWriter.MatchUpdate(mpLobby); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); }, sendMatchUpdate:function(currentUser) { const mpLobby = global.matches[currentUser.currentMatch][1]; const osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.MatchUpdate(mpLobby); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); }, updateMatch:function(currentUser, data) { global.matches[currentUser.currentMatch][1] = data; const osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.MatchUpdate(global.matches[currentUser.currentMatch][1]); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); this.updateMatchListing(); }, moveToSlot:function(currentUser, data) { const mpLobby = global.matches[currentUser.currentMatch][1]; const osuPacketWriter = new osu.Bancho.Writer; let currentUserData, slotIndex; for (let i = 0; i < mpLobby.slots.length; i++) { const slot = mpLobby.slots[i]; if (slot.playerId != currentUser.id) continue; currentUserData = slot; slotIndex = i; break; } mpLobby.slots[data].playerId = currentUserData.playerId; currentUser.matchSlotId = data; mpLobby.slots[data].status = currentUserData.status; mpLobby.slots[slotIndex].playerId = -1; mpLobby.slots[slotIndex].status = 1; osuPacketWriter.MatchUpdate(mpLobby); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); this.updateMatchListing(); }, kickPlayer:function(currentUser, data) { const mpLobby = global.matches[currentUser.currentMatch][1]; const osuPacketWriter = new osu.Bancho.Writer; if (mpLobby.host != currentUser.id) return; const slot = mpLobby.slots[data]; let cachedPlayerId = slot.playerId; if (slot.playerId === -1) { // Slot is empty, lock it if (slot.status === 1) slot.status = 2; else slot.status = 1; } else { // Slot isn't empty kick player const kickedPlayer = getUserById(slot.playerId); kickedPlayer.matchSlotId = -1; slot.playerId = -1; slot.status = 1; } osuPacketWriter.MatchUpdate(mpLobby); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); this.updateMatchListing(); if (cachedPlayerId !== null || cachedPlayerId !== -1) { global.StreamsHandler.removeUserFromStream(global.matches[currentUser.currentMatch][0], cachedPlayerId); } }, missingBeatmap:function(currentUser, state) { const mpLobby = global.matches[currentUser.currentMatch][1]; const osuPacketWriter = new osu.Bancho.Writer; for (let i = 0; i < mpLobby.slots.length; i++) { const slot = mpLobby.slots[i]; if (slot.playerId != currentUser.id) continue; if (state) { slot.status = 16; } else { slot.status = 4; } break; } osuPacketWriter.MatchUpdate(mpLobby); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); }, transferHost:function(currentUser, data) { const mpLobby = global.matches[currentUser.currentMatch][1]; const osuPacketWriter = new osu.Bancho.Writer; const newUser = getUserById(mpLobby.slots[data].playerId); mpLobby.host = newUser.id; osuPacketWriter.MatchUpdate(mpLobby); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); }, updateMods(currentUser, data) { // TODO: Allow freemod to work if (global.matches[currentUser.currentMatch][1].host !== currentUser.id) return; const osuPacketWriter = new osu.Bancho.Writer; global.matches[currentUser.currentMatch][1].activeMods = data; osuPacketWriter.MatchUpdate(global.matches[currentUser.currentMatch][1]); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); this.updateMatchListing(); }, startMatch(currentUser) { const mpLobby = global.matches[currentUser.currentMatch][1]; if (mpLobby.inProgress) return; mpLobby.inProgress = true; global.matches[currentUser.currentMatch][2] = []; const loadedSlots = global.matches[currentUser.currentMatch][2]; for (let i = 0; i < mpLobby.slots.length; i++) { const slot = mpLobby.slots[i]; if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue; loadedSlots.push({playerId: slot.playerId, loaded: false}); } const osuPacketWriter = new osu.Bancho.Writer; for (let i = 0; i < mpLobby.slots.length; i++) { const slot = mpLobby.slots[i]; if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue; slot.status = 32; } osuPacketWriter.MatchStart(mpLobby); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); this.sendMatchUpdate(currentUser); this.updateMatchListing(); }, setPlayerLoaded:function(currentUser) { const loadedSlots = global.matches[currentUser.currentMatch][2]; for (let i = 0; i < loadedSlots.length; i++) { if (loadedSlots[i].playerId == currentUser.id) { loadedSlots[i].loaded = true; } } let allLoaded = true; for (let i = 0; i < loadedSlots.length; i++) { if (loadedSlots[i].loaded) continue; allLoaded = false; } if (allLoaded) { let osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.MatchAllPlayersLoaded(); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); global.matches[currentUser.currentMatch][2] = null; } }, onPlayerFinishMatch:function(currentUser) { const mpLobby = global.matches[currentUser.currentMatch][1]; if (global.matches[currentUser.currentMatch][2] == null) { global.matches[currentUser.currentMatch][2] = []; const loadedSlots = global.matches[currentUser.currentMatch][2]; for (let i = 0; i < mpLobby.slots.length; i++) { const slot = mpLobby.slots[i]; if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue; loadedSlots.push({playerId: slot.playerId, loaded: false}); } } const loadedSlots = global.matches[currentUser.currentMatch][2]; for (let i = 0; i < loadedSlots.length; i++) { if (loadedSlots[i].playerId == currentUser.id) { loadedSlots[i].loaded = true; } } let allLoaded = true; for (let i = 0; i < loadedSlots.length; i++) { if (loadedSlots[i].loaded) continue; allLoaded = false; } if (allLoaded) this.finishMatch(currentUser); }, finishMatch:function(currentUser) { const mpLobby = global.matches[currentUser.currentMatch][1]; if (!mpLobby.inProgress) return; global.matches[currentUser.currentMatch][2] = []; mpLobby.inProgress = false; let osuPacketWriter = new osu.Bancho.Writer; for (let i = 0; i < mpLobby.slots.length; i++) { const slot = mpLobby.slots[i]; if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue; slot.status = 4; } osuPacketWriter.MatchComplete(); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); this.sendMatchUpdate(currentUser); this.updateMatchListing(); }, updatePlayerScore:function(currentUser, data) { const osuPacketWriter = new osu.Bancho.Writer; if (currentUser.matchSlotId == -1) return console.log("it did the big fuck"); data.id = currentUser.matchSlotId; osuPacketWriter.MatchScoreUpdate(data); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); }, leaveMatch:function(currentUser) { try { const mpLobby = global.matches[currentUser.currentMatch][1]; let containsUser = false; for (let i = 0; i < mpLobby.slots.length; i++) { const slot = mpLobby.slots[i]; if (slot.playerId == currentUser.id) { containsUser = true; break; } } // Make sure we don't run more than once if (!containsUser) return; let osuPacketWriter = new osu.Bancho.Writer; for (let i = 0; i < mpLobby.slots.length; i++) { const slot = mpLobby.slots[i]; if (slot.playerId != currentUser.id) continue; slot.playerId = -1; slot.status = 1; break; } osuPacketWriter.MatchUpdate(mpLobby); global.StreamsHandler.removeUserFromStream(global.matches[currentUser.currentMatch][0], currentUser.id); global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null); osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter.ChannelRevoked("#multiplayer"); currentUser.addActionToQueue(osuPacketWriter.toBuffer); let empty = true; for (let i = 0; i < mpLobby.slots.length; i++) { const slot = mpLobby.slots[i]; if (slot.playerId === -1) continue; empty = false; break; } if (empty) { let matchIndex; for (let i = 0; i < global.matches.length; i++) { if (global.matches[i][0] == global.matches[currentUser.currentMatch][0]) { matchIndex = i; break; } } // Make sure we got a match index if (matchIndex == null) return; // Remove this match from the list of active matches global.matches.splice(matchIndex, 1); } } catch (e) { } this.updateMatchListing(); // Delay a 2nd match listing update setTimeout(() => { this.updateMatchListing(); }, 1000); } }