Multiplayer Updates
This commit is contained in:
parent
cd257fe96b
commit
9489dfe2ea
7 changed files with 1032 additions and 788 deletions
|
@ -1,6 +1,7 @@
|
||||||
const osu = require("osu-packet"),
|
const osu = require("osu-packet"),
|
||||||
maths = require("./util/Maths.js"),
|
maths = require("./util/Maths.js"),
|
||||||
Multiplayer = require("./Multiplayer.js");
|
OsuBattleRoyale = require("./MultiplayerExtras/OsuBattleRoyale.js");
|
||||||
|
//Multiplayer = require("./Multiplayer.js");
|
||||||
|
|
||||||
module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false) {
|
module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false) {
|
||||||
if (Message[0] != "!") return;
|
if (Message[0] != "!") return;
|
||||||
|
@ -9,7 +10,7 @@ module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false
|
||||||
|
|
||||||
let responseMessage = "";
|
let responseMessage = "";
|
||||||
|
|
||||||
let gay = null;
|
let commandBanchoPacketWriter = null;
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case "!help":
|
case "!help":
|
||||||
|
@ -26,7 +27,8 @@ module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false
|
||||||
case "mp":
|
case "mp":
|
||||||
responseMessage = "Multiplayer Commands:" +
|
responseMessage = "Multiplayer Commands:" +
|
||||||
"\n!mp start - Starts a multiplayer match with a delay" +
|
"\n!mp start - Starts a multiplayer match with a delay" +
|
||||||
"\n!mp abort - Aborts the currently running multiplayer match";
|
"\n!mp abort - Aborts the currently running multiplayer match" +
|
||||||
|
"\n!mp obr - Enables Battle Royale mode";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "admin":
|
case "admin":
|
||||||
|
@ -69,29 +71,30 @@ module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "!msg":
|
case "!msg":
|
||||||
gay = new osu.Bancho.Writer;
|
commandBanchoPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
gay.RTX(args[1]);
|
commandBanchoPacketWriter.RTX(args[1]);
|
||||||
|
|
||||||
//User.addActionToQueue(gay.toBuffer());
|
global.StreamsHandler.sendToStream(Stream, commandBanchoPacketWriter.toBuffer, null);
|
||||||
global.StreamsHandler.sendToStream(Stream, gay.toBuffer, null);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "!fuckoff":
|
case "!fuckoff":
|
||||||
gay = new osu.Bancho.Writer;
|
commandBanchoPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
gay.Ping(0);
|
commandBanchoPacketWriter.Ping(0);
|
||||||
|
|
||||||
User.addActionToQueue(gay.toBuffer);
|
User.addActionToQueue(commandBanchoPacketWriter.toBuffer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "!mp":
|
case "!mp":
|
||||||
if (!IsCalledFromMultiplayer) return;
|
if (!IsCalledFromMultiplayer) return;
|
||||||
|
if (User.currentMatch.matchStartCountdownActive) return;
|
||||||
if (args.length == 1) return;
|
if (args.length == 1) return;
|
||||||
switch (args[1]) {
|
switch (args[1]) {
|
||||||
case "start":
|
case "start":
|
||||||
if (args.length > 3) return;
|
if (args.length > 3) return;
|
||||||
if (`${parseInt(args[2])}` != "NaN") {
|
if (`${parseInt(args[2])}` != "NaN") {
|
||||||
|
User.currentMatch.matchStartCountdownActive = true;
|
||||||
let countdown = parseInt(args[2]);
|
let countdown = parseInt(args[2]);
|
||||||
let intervalRef = setInterval(() => {
|
let intervalRef = setInterval(() => {
|
||||||
let local_osuPacketWriter = new osu.Bancho.Writer;
|
let local_osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
@ -112,19 +115,38 @@ module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false
|
||||||
senderId: global.users[0].id
|
senderId: global.users[0].id
|
||||||
});
|
});
|
||||||
global.StreamsHandler.sendToStream(Stream, local_osuPacketWriter.toBuffer, null);
|
global.StreamsHandler.sendToStream(Stream, local_osuPacketWriter.toBuffer, null);
|
||||||
setTimeout(() => Multiplayer.startMatch(User), 1000);
|
User.currentMatch.matchStartCountdownActive = false;
|
||||||
|
setTimeout(() => User.currentMatch.startMatch(), 1000);
|
||||||
clearInterval(intervalRef);
|
clearInterval(intervalRef);
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
} else {
|
} else {
|
||||||
responseMessage = "Good luck, have fun!";
|
responseMessage = "Good luck, have fun!";
|
||||||
setTimeout(() => Multiplayer.startMatch(User), 1000);
|
setTimeout(() => User.currentMatch.startMatch(), 1000);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "abort":
|
case "abort":
|
||||||
if (args.length > 2) return;
|
//if (args.length > 2) return;
|
||||||
Multiplayer.finishMatch(User);
|
User.currentMatch.finishMatch();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "obr":
|
||||||
|
if (User.currentMatch.multiplayerExtras != null) {
|
||||||
|
if (User.currentMatch.multiplayerExtras.name == "osu! Battle Royale") {
|
||||||
|
commandBanchoPacketWriter = new osu.Bancho.Writer;
|
||||||
|
commandBanchoPacketWriter.SendMessage({
|
||||||
|
sendingClient: global.users[0].username,
|
||||||
|
message: "osu! Battle Royale has been disabled!",
|
||||||
|
target: "#multiplayer",
|
||||||
|
senderId: global.users[0].id
|
||||||
|
});
|
||||||
|
User.currentMatch.multiplayerExtras = null;
|
||||||
|
global.StreamsHandler.sendToStream(Stream, commandBanchoPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
else enableOBR(User, Stream, commandBanchoPacketWriter);
|
||||||
|
}
|
||||||
|
else enableOBR(User, Stream, commandBanchoPacketWriter);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -152,4 +174,22 @@ module.exports = function(User, Message, Stream, IsCalledFromMultiplayer = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
global.StreamsHandler.sendToStream(Stream, osuPacketWriter.toBuffer, null);
|
global.StreamsHandler.sendToStream(Stream, osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableOBR(User, Stream, commandBanchoPacketWriter) {
|
||||||
|
User.currentMatch.multiplayerExtras = new OsuBattleRoyale(User.currentMatch);
|
||||||
|
commandBanchoPacketWriter = new osu.Bancho.Writer;
|
||||||
|
commandBanchoPacketWriter.SendMessage({
|
||||||
|
sendingClient: global.users[0].username,
|
||||||
|
message: "osu! Battle Royale has been enabled!",
|
||||||
|
target: "#multiplayer",
|
||||||
|
senderId: global.users[0].id
|
||||||
|
});
|
||||||
|
commandBanchoPacketWriter.SendMessage({
|
||||||
|
sendingClient: global.users[0].username,
|
||||||
|
message: "New Multiplayer Rules Added:\n - Players that are in a failed state by the end of the map get eliminated\n - The player(s) with the lowest score get eliminated",
|
||||||
|
target: "#multiplayer",
|
||||||
|
senderId: global.users[0].id
|
||||||
|
});
|
||||||
|
global.StreamsHandler.sendToStream(Stream, commandBanchoPacketWriter.toBuffer, null);
|
||||||
}
|
}
|
|
@ -1,756 +0,0 @@
|
||||||
const osu = require("osu-packet"),
|
|
||||||
getUserById = require("./util/getUserById.js"),
|
|
||||||
StatusUpdate = require("./Packets/StatusUpdate.js");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
userEnterLobby:function(currentUser) {
|
|
||||||
// If the user is currently already in a match force them to leave
|
|
||||||
if (currentUser.currentMatch != null) {
|
|
||||||
this.leaveMatch(currentUser);
|
|
||||||
currentUser.currentMatch = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add user to the stream for the lobby
|
|
||||||
global.StreamsHandler.addUserToStream("multiplayer_lobby", currentUser.id);
|
|
||||||
|
|
||||||
const osuPacketWriter1 = new osu.Bancho.Writer;
|
|
||||||
let userIds = [];
|
|
||||||
|
|
||||||
// Add the ID of every user connected to the server to an array
|
|
||||||
for (let i = 0; i < global.users.length; i++) {
|
|
||||||
userIds.push(global.users[i].id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send all user ids back to the client
|
|
||||||
osuPacketWriter1.UserPresenceBundle(userIds);
|
|
||||||
|
|
||||||
// Send user ids to all users in the lobby
|
|
||||||
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter1.toBuffer, null);
|
|
||||||
|
|
||||||
// Loop through all matches
|
|
||||||
for (let i = 0; i < global.matches.length; i++) {
|
|
||||||
// Loop through all the users in this match
|
|
||||||
for (let i1 = 0; i1 < global.matches[i][1].slots.length; i1++) {
|
|
||||||
const slot = global.matches[i][1].slots[i1];
|
|
||||||
// Make sure there is a player / the slot is not locked
|
|
||||||
if (slot.playerId == -1 || slot.status == 2) continue;
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// Get user in this slot
|
|
||||||
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: User.rank,
|
|
||||||
performance: userScoreDB.pp_raw
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send user status back for client display
|
|
||||||
osuPacketWriter.HandleOsuUpdate(UserStatusObject);
|
|
||||||
|
|
||||||
// Send this data back to every user in the lobby
|
|
||||||
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null);
|
|
||||||
}
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// List the match on the client
|
|
||||||
osuPacketWriter.MatchNew(global.matches[i][1]);
|
|
||||||
|
|
||||||
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
|
||||||
}
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// Add the user to the #lobby channel
|
|
||||||
osuPacketWriter.ChannelJoinSuccess("#lobby");
|
|
||||||
if (!global.StreamsHandler.isUserInStream("#lobby", currentUser.id))
|
|
||||||
global.StreamsHandler.addUserToStream("#lobby", currentUser.id);
|
|
||||||
|
|
||||||
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
|
||||||
},
|
|
||||||
|
|
||||||
userLeaveLobby:function(currentUser) {
|
|
||||||
// Remove user from the stream for the multiplayer lobby if they are a part of it
|
|
||||||
if (global.StreamsHandler.isUserInStream("multiplayer_lobby", currentUser.id))
|
|
||||||
global.StreamsHandler.removeUserFromStream("multiplayer_lobby", currentUser.id);
|
|
||||||
},
|
|
||||||
|
|
||||||
updateMatchListing:function() {
|
|
||||||
const osuPacketWriter1 = new osu.Bancho.Writer;
|
|
||||||
let userIds = [];
|
|
||||||
|
|
||||||
// Add the ID of every user connected to the server to an array
|
|
||||||
for (let i = 0; i < global.users.length; i++) {
|
|
||||||
userIds.push(global.users[i].id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send all user ids back to the client
|
|
||||||
osuPacketWriter1.UserPresenceBundle(userIds);
|
|
||||||
|
|
||||||
// Send user ids to all users in the lobby
|
|
||||||
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter1.toBuffer, null);
|
|
||||||
// List through all matches
|
|
||||||
for (let i = 0; i < global.matches.length; i++) {
|
|
||||||
// List through all users in the match
|
|
||||||
for (let i1 = 0; i1 < global.matches[i][1].slots.length; i1++) {
|
|
||||||
const slot = global.matches[i][1].slots[i1];
|
|
||||||
// Make sure the slot has a user in it / isn't locked
|
|
||||||
if (slot.playerId == -1 || slot.status == 2) continue;
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// Get the user in this slot
|
|
||||||
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: User.rank,
|
|
||||||
performance: userScoreDB.pp_raw
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send user status back for client display
|
|
||||||
osuPacketWriter.HandleOsuUpdate(UserStatusObject);
|
|
||||||
|
|
||||||
// Send this data back to every user in the lobby
|
|
||||||
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null);
|
|
||||||
}
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// List the match on the client
|
|
||||||
osuPacketWriter.MatchNew(global.matches[i][1]);
|
|
||||||
|
|
||||||
// Send this data back to every user in the lobby
|
|
||||||
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
createMultiplayerMatch:function(currentUser, data) {
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// If there is no password instead set the password param to null
|
|
||||||
if (data.gamePassword == '') data.gamePassword == null;
|
|
||||||
|
|
||||||
// Create a match with the data given by the creating client
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the status of the current user
|
|
||||||
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();
|
|
||||||
|
|
||||||
// Join the user to the newly created match
|
|
||||||
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;
|
|
||||||
// Loop through all slots to find an empty one
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Make sure the slot doesn't have a player in it / the slot is locked
|
|
||||||
if (slot.playerId !== -1 || slot.status === 2) continue;
|
|
||||||
|
|
||||||
// Slot is empty and not locked, we can join the match!
|
|
||||||
full = false;
|
|
||||||
slot.playerId = currentUser.id;
|
|
||||||
currentUser.matchSlotId = i;
|
|
||||||
slot.status = 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
osuPacketWriter1.MatchUpdate(mpLobby);
|
|
||||||
osuPacketWriter.MatchJoinSuccess(mpLobby);
|
|
||||||
|
|
||||||
if (full) {
|
|
||||||
// Inform the client that they can't join the match
|
|
||||||
osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
osuPacketWriter.MatchJoinFail();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the user's current match to this match
|
|
||||||
currentUser.currentMatch = data.matchId;
|
|
||||||
|
|
||||||
// Add user to the stream for the match
|
|
||||||
global.StreamsHandler.addUserToStream(streamName, currentUser.id);
|
|
||||||
|
|
||||||
// Inform all users in the match that a new user has joined
|
|
||||||
global.StreamsHandler.sendToStream(streamName, osuPacketWriter1.toBuffer, null);
|
|
||||||
|
|
||||||
osuPacketWriter.ChannelJoinSuccess("#multiplayer");
|
|
||||||
|
|
||||||
// Inform joining client they they have joined the match
|
|
||||||
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
|
||||||
|
|
||||||
// Update the match listing for all users in the lobby since
|
|
||||||
// A user has joined a match
|
|
||||||
this.updateMatchListing();
|
|
||||||
} catch (e) {
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
osuPacketWriter.MatchJoinFail();
|
|
||||||
|
|
||||||
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
|
||||||
|
|
||||||
this.updateMatchListing();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setReadyState:function(currentUser, state) {
|
|
||||||
// Get the match the user is in
|
|
||||||
const mpLobby = global.matches[currentUser.currentMatch][1];
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// Loop though all slots in the match
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Check if the player in this slot is this user
|
|
||||||
if (slot.playerId == currentUser.id) {
|
|
||||||
// Turn on or off the user's ready state
|
|
||||||
if (state) slot.status = 8;
|
|
||||||
else slot.status = 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
osuPacketWriter.MatchUpdate(mpLobby);
|
|
||||||
|
|
||||||
// Send this update to all users in the stream
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Update all users in the match with new match information
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
},
|
|
||||||
|
|
||||||
updateMatch:function(currentUser, data) {
|
|
||||||
// Update match with new data
|
|
||||||
global.matches[currentUser.currentMatch][1] = data;
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
osuPacketWriter.MatchUpdate(global.matches[currentUser.currentMatch][1]);
|
|
||||||
|
|
||||||
// Send this new match data to all users in the match
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
|
|
||||||
// Update the match listing in the lobby to reflect these changes
|
|
||||||
this.updateMatchListing();
|
|
||||||
},
|
|
||||||
|
|
||||||
moveToSlot:function(currentUser, data) {
|
|
||||||
const mpLobby = global.matches[currentUser.currentMatch][1];
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
let currentUserData, slotIndex;
|
|
||||||
// Loop through all slots in the match
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Make sure the user in this slot is the user we want
|
|
||||||
if (slot.playerId != currentUser.id) continue;
|
|
||||||
|
|
||||||
currentUserData = slot;
|
|
||||||
slotIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the new slot's data to the user's old slot data
|
|
||||||
mpLobby.slots[data].playerId = currentUserData.playerId;
|
|
||||||
currentUser.matchSlotId = data;
|
|
||||||
mpLobby.slots[data].status = currentUserData.status;
|
|
||||||
|
|
||||||
// Set the old slot's data to open
|
|
||||||
mpLobby.slots[slotIndex].playerId = -1;
|
|
||||||
mpLobby.slots[slotIndex].status = 1;
|
|
||||||
|
|
||||||
osuPacketWriter.MatchUpdate(mpLobby);
|
|
||||||
|
|
||||||
// Send this change to all users in the match
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
|
|
||||||
// Update the match listing in the lobby to reflect this change
|
|
||||||
this.updateMatchListing();
|
|
||||||
},
|
|
||||||
|
|
||||||
kickPlayer:function(currentUser, data) {
|
|
||||||
const mpLobby = global.matches[currentUser.currentMatch][1];
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// Make sure the user attempting to kick / lock is the host of the match
|
|
||||||
if (mpLobby.host != currentUser.id) return;
|
|
||||||
|
|
||||||
// Get the data of the slot at the index sent by the client
|
|
||||||
const slot = mpLobby.slots[data];
|
|
||||||
let cachedPlayerId = slot.playerId;
|
|
||||||
|
|
||||||
// If the slot is empty lock instead of kicking
|
|
||||||
if (slot.playerId === -1) { // Slot is empty, lock it
|
|
||||||
if (slot.status === 1) slot.status = 2;
|
|
||||||
else slot.status = 1;
|
|
||||||
}
|
|
||||||
// The slot isn't empty, prepare to kick the player
|
|
||||||
else {
|
|
||||||
const kickedPlayer = getUserById(slot.playerId);
|
|
||||||
kickedPlayer.matchSlotId = -1;
|
|
||||||
slot.playerId = -1;
|
|
||||||
slot.status = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
osuPacketWriter.MatchUpdate(mpLobby);
|
|
||||||
|
|
||||||
// Inform all users in the match of the change
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
|
|
||||||
// Update the match listing in the lobby listing to reflect this change
|
|
||||||
this.updateMatchListing();
|
|
||||||
|
|
||||||
if (cachedPlayerId !== null || cachedPlayerId !== -1) {
|
|
||||||
// Remove the kicked user from the match stream
|
|
||||||
global.StreamsHandler.removeUserFromStream(global.matches[currentUser.currentMatch][0], cachedPlayerId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
matchSkip:function(currentUser) {
|
|
||||||
const mpLobby = global.matches[currentUser.currentMatch][1];
|
|
||||||
|
|
||||||
if (global.matches[currentUser.currentMatch][2] == null) {
|
|
||||||
global.matches[currentUser.currentMatch][2] = [];
|
|
||||||
|
|
||||||
const skippedSlots = global.matches[currentUser.currentMatch][2];
|
|
||||||
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Make sure the slot has a user in it
|
|
||||||
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
|
||||||
|
|
||||||
// Add the slot's user to the loaded checking array
|
|
||||||
skippedSlots.push({playerId: slot.playerId, skipped: false});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const skippedSlots = global.matches[currentUser.currentMatch][2];
|
|
||||||
|
|
||||||
for (let i = 0; i < skippedSlots.length; i++) {
|
|
||||||
// If loadslot belongs to this user then set loaded to true
|
|
||||||
if (skippedSlots[i].playerId == currentUser.id) {
|
|
||||||
skippedSlots[i].skipped = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let allSkipped = true;
|
|
||||||
for (let i = 0; i < skippedSlots.length; i++) {
|
|
||||||
if (skippedSlots[i].skipped) continue;
|
|
||||||
|
|
||||||
// A user hasn't finished playing
|
|
||||||
allSkipped = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All players have finished playing, finish the match
|
|
||||||
if (allSkipped) {
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
osuPacketWriter.MatchPlayerSkipped(currentUser.id);
|
|
||||||
osuPacketWriter.MatchSkip();
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
|
|
||||||
global.matches[currentUser.currentMatch][2] = null;
|
|
||||||
} else {
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
osuPacketWriter.MatchPlayerSkipped(currentUser.id);
|
|
||||||
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
missingBeatmap:function(currentUser, state) {
|
|
||||||
const mpLobby = global.matches[currentUser.currentMatch][1];
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// Loop through all slots in the match
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Make sure the user in the slot is the user we want to update
|
|
||||||
if (slot.playerId != currentUser.id) continue;
|
|
||||||
|
|
||||||
// If the user is missing the beatmap set the status to reflect it
|
|
||||||
if (state) slot.status = 16;
|
|
||||||
// The user is not missing the beatmap, set the status to normal
|
|
||||||
else slot.status = 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
osuPacketWriter.MatchUpdate(mpLobby);
|
|
||||||
|
|
||||||
// Inform all users in the match of this change
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Get the information of the user that the host is being transfered to
|
|
||||||
const newUser = getUserById(mpLobby.slots[data].playerId);
|
|
||||||
|
|
||||||
// Set the lobby's host to the new user
|
|
||||||
mpLobby.host = newUser.id;
|
|
||||||
|
|
||||||
osuPacketWriter.MatchUpdate(mpLobby);
|
|
||||||
|
|
||||||
// Inform all clients in the match of the change
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
},
|
|
||||||
|
|
||||||
// TODO: Allow freemod to work
|
|
||||||
updateMods(currentUser, data) {
|
|
||||||
// Make sure the person updating mods is the host of the match
|
|
||||||
// TODO: Add a check here for is freemod is enabled
|
|
||||||
console.log(global.matches[currentUser.currentMatch][1]);
|
|
||||||
console.log(data);
|
|
||||||
if (Object.keys(global.matches[currentUser.currentMatch][1].slots[0]).includes("mods")) {
|
|
||||||
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) {
|
|
||||||
slot.mods = data;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
osuPacketWriter.MatchUpdate(global.matches[currentUser.currentMatch][1]);
|
|
||||||
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
} else {
|
|
||||||
if (global.matches[currentUser.currentMatch][1].host !== currentUser.id) return;
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// Change the matches mods to these new mods
|
|
||||||
// TODO: Do this per user if freemod is enabled
|
|
||||||
global.matches[currentUser.currentMatch][1].activeMods = data;
|
|
||||||
|
|
||||||
osuPacketWriter.MatchUpdate(global.matches[currentUser.currentMatch][1]);
|
|
||||||
|
|
||||||
// Inform all users in the match of the change
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update match listing in the lobby to reflect this change
|
|
||||||
this.updateMatchListing();
|
|
||||||
},
|
|
||||||
|
|
||||||
startMatch(currentUser) {
|
|
||||||
const mpLobby = global.matches[currentUser.currentMatch][1];
|
|
||||||
// Make sure the match is not already in progress
|
|
||||||
// The client sometimes double fires the start packet
|
|
||||||
if (mpLobby.inProgress) return;
|
|
||||||
mpLobby.inProgress = true;
|
|
||||||
// Create array for monitoring users until they are ready to play
|
|
||||||
global.matches[currentUser.currentMatch][2] = [];
|
|
||||||
const loadedSlots = global.matches[currentUser.currentMatch][2];
|
|
||||||
// Loop through all slots in the match
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Make sure the slot has a user in it
|
|
||||||
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
|
||||||
|
|
||||||
// Add the slot's user to the loaded checking array
|
|
||||||
loadedSlots.push({playerId: slot.playerId, loaded: false});
|
|
||||||
}
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// Loop through all slots in the match
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Make sure the slot has a user in it
|
|
||||||
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
|
||||||
|
|
||||||
// Set the user's status to playing
|
|
||||||
slot.status = 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
osuPacketWriter.MatchStart(mpLobby);
|
|
||||||
|
|
||||||
// Inform all users in the match that it has started
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
|
|
||||||
// Update all users in the match with new info
|
|
||||||
this.sendMatchUpdate(currentUser);
|
|
||||||
|
|
||||||
// Update match listing in lobby to show the game is in progress
|
|
||||||
this.updateMatchListing();
|
|
||||||
},
|
|
||||||
|
|
||||||
setPlayerLoaded:function(currentUser) {
|
|
||||||
const loadedSlots = global.matches[currentUser.currentMatch][2];
|
|
||||||
|
|
||||||
// Loop through all user load check items
|
|
||||||
for (let i = 0; i < loadedSlots.length; i++) {
|
|
||||||
// If loadslot belongs to this user then set loaded to true
|
|
||||||
if (loadedSlots[i].playerId == currentUser.id) {
|
|
||||||
loadedSlots[i].loaded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through all loaded slots and check if all users are loaded
|
|
||||||
let allLoaded = true;
|
|
||||||
for (let i = 0; i < loadedSlots.length; i++) {
|
|
||||||
if (loadedSlots[i].loaded) continue;
|
|
||||||
|
|
||||||
// A user wasn't loaded, keep waiting.
|
|
||||||
allLoaded = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All players have loaded the beatmap, start playing.
|
|
||||||
if (allLoaded) {
|
|
||||||
let osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
osuPacketWriter.MatchAllPlayersLoaded();
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
|
|
||||||
// Blank out user loading array
|
|
||||||
global.matches[currentUser.currentMatch][2] = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onPlayerFinishMatch:function(currentUser) {
|
|
||||||
const mpLobby = global.matches[currentUser.currentMatch][1];
|
|
||||||
// If user loading slots do not exist
|
|
||||||
if (global.matches[currentUser.currentMatch][2] == null) {
|
|
||||||
global.matches[currentUser.currentMatch][2] = [];
|
|
||||||
// Repopulate user loading slots again
|
|
||||||
const loadedSlots = global.matches[currentUser.currentMatch][2];
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Make sure the slot has a user
|
|
||||||
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
|
||||||
|
|
||||||
// Populate user loading slots with this user's id and load status
|
|
||||||
loadedSlots.push({playerId: slot.playerId, loaded: false});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadedSlots = global.matches[currentUser.currentMatch][2];
|
|
||||||
|
|
||||||
// Loop through all loaded slots to make sure all users have finished playing
|
|
||||||
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;
|
|
||||||
|
|
||||||
// A user hasn't finished playing
|
|
||||||
allLoaded = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All players have finished playing, finish the match
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Loop through all slots in the match
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Make sure the slot has a user
|
|
||||||
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
|
||||||
|
|
||||||
// Set the user's status back to normal from playing
|
|
||||||
slot.status = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
osuPacketWriter.MatchComplete();
|
|
||||||
|
|
||||||
// Inform all users in the match that it is complete
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
|
|
||||||
// Update all users in the match with new info
|
|
||||||
this.sendMatchUpdate(currentUser);
|
|
||||||
|
|
||||||
// Update match info in the lobby to reflect that the match has finished
|
|
||||||
this.updateMatchListing();
|
|
||||||
},
|
|
||||||
|
|
||||||
updatePlayerScore:function(currentUser, data) {
|
|
||||||
const osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// Make sure the user's slot ID is not invalid
|
|
||||||
if (currentUser.matchSlotId == -1) return;
|
|
||||||
|
|
||||||
// Get the user's current slotID and append it to the givien data, just incase.
|
|
||||||
data.id = currentUser.matchSlotId;
|
|
||||||
|
|
||||||
osuPacketWriter.MatchScoreUpdate(data);
|
|
||||||
|
|
||||||
// Send the newly updated score to all users in the match
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
},
|
|
||||||
|
|
||||||
leaveMatch:function(currentUser) {
|
|
||||||
try {
|
|
||||||
const mpLobby = global.matches[currentUser.currentMatch][1];
|
|
||||||
|
|
||||||
let userInMatch = false;
|
|
||||||
// Loop through all slots in the match
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Check if the user is in this slot
|
|
||||||
if (slot.playerId == currentUser.id) {
|
|
||||||
userInMatch = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we don't run more than once
|
|
||||||
// Again, client double firing packets.
|
|
||||||
if (!userInMatch) return;
|
|
||||||
|
|
||||||
let osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// Loop through all slots in the match
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Make sure the user is in this slot
|
|
||||||
if (slot.playerId != currentUser.id) continue;
|
|
||||||
|
|
||||||
// Set the slot's status to avaliable
|
|
||||||
slot.playerId = -1;
|
|
||||||
slot.status = 1;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
osuPacketWriter.MatchUpdate(mpLobby);
|
|
||||||
|
|
||||||
// Remove the leaving user from the match's stream
|
|
||||||
global.StreamsHandler.removeUserFromStream(global.matches[currentUser.currentMatch][0], currentUser.id);
|
|
||||||
|
|
||||||
// Inform all users in the match that the leaving user has left
|
|
||||||
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
|
||||||
|
|
||||||
osuPacketWriter = new osu.Bancho.Writer;
|
|
||||||
|
|
||||||
// Remove user from the multiplayer channel for the match
|
|
||||||
osuPacketWriter.ChannelRevoked("#multiplayer");
|
|
||||||
|
|
||||||
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
|
||||||
|
|
||||||
let empty = true;
|
|
||||||
// Check if the match is empty
|
|
||||||
for (let i = 0; i < mpLobby.slots.length; i++) {
|
|
||||||
const slot = mpLobby.slots[i];
|
|
||||||
// Check if the slot is avaliable
|
|
||||||
if (slot.playerId === -1) continue;
|
|
||||||
|
|
||||||
// There is a user in the match
|
|
||||||
empty = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The match is empty, proceed to remove it.
|
|
||||||
if (empty) {
|
|
||||||
let matchIndex;
|
|
||||||
// Loop through all matches
|
|
||||||
for (let i = 0; i < global.matches.length; i++) {
|
|
||||||
// If the match matches the match the user has left
|
|
||||||
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) { }
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
126
server/MultiplayerExtras/OsuBattleRoyale.js
Normal file
126
server/MultiplayerExtras/OsuBattleRoyale.js
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
const osu = require("osu-packet"),
|
||||||
|
MultiplayerMatch = require("../MultiplayerMatch.js"),
|
||||||
|
getUserById = require("../util/getUserById.js");
|
||||||
|
|
||||||
|
module.exports = class {
|
||||||
|
constructor(MultiplayerMatchClass = new MultiplayerMatch()) {
|
||||||
|
this.name = "osu! Battle Royale";
|
||||||
|
this.MultiplayerMatch = MultiplayerMatchClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMatchFinished(playerScores = [{playerId:0,slotId:0,score:0,isCurrentlyFailed:false}]) {
|
||||||
|
let lowestScore = 9999999999999999;
|
||||||
|
for (let i = 0; i < playerScores.length; i++) {
|
||||||
|
const playerScore = playerScores[i];
|
||||||
|
if (playerScore.score < lowestScore) lowestScore = playerScore.score;
|
||||||
|
}
|
||||||
|
|
||||||
|
let everyoneHasTheSameScore = true;
|
||||||
|
for (let i = 0; i < playerScores.length; i++) {
|
||||||
|
if (playerScores[i].score != lowestScore) everyoneHasTheSameScore = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everyone has the same score, we don't need to kick anyone
|
||||||
|
if (everyoneHasTheSameScore) return;
|
||||||
|
|
||||||
|
// Kick everyone with the lowest score
|
||||||
|
for (let i = 0; i < playerScores.length; i++) {
|
||||||
|
// Kick players if they have the lowest score or they are in a failed state
|
||||||
|
if (playerScores[i].score == lowestScore || playerScores[i].isCurrentlyFailed) {
|
||||||
|
let osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
// Get the slot this player is in
|
||||||
|
const slot = this.MultiplayerMatch.slots[playerScores[i].slotId];
|
||||||
|
// Get the kicked player's user class
|
||||||
|
const kickedPlayer = getUserById(slot.playerId);
|
||||||
|
// Remove the kicked player's referance to the slot they were in
|
||||||
|
kickedPlayer.matchSlotId = -1;
|
||||||
|
// Lock the slot the kicked player was in
|
||||||
|
slot.playerId = -1;
|
||||||
|
slot.status = 2;
|
||||||
|
// Remove the kicked player from the match's stream
|
||||||
|
global.StreamsHandler.removeUserFromStream(this.MultiplayerMatch.matchStreamName, kickedPlayer.id);
|
||||||
|
// Remove the kicked player's referance this this match
|
||||||
|
kickedPlayer.currentMatch = null;
|
||||||
|
|
||||||
|
// Inform the kicked user's client that they were kicked
|
||||||
|
osuPacketWriter.MatchUpdate(this.MultiplayerMatch.createOsuMatchJSON());
|
||||||
|
osuPacketWriter.SendMessage({
|
||||||
|
sendingClient: global.users[0].username,
|
||||||
|
message: "You were eliminated from the match!",
|
||||||
|
target: global.users[0].username,
|
||||||
|
senderId: global.users[0].id
|
||||||
|
});
|
||||||
|
|
||||||
|
kickedPlayer.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
|
||||||
|
osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
osuPacketWriter.SendMessage({
|
||||||
|
sendingClient: global.users[0].username,
|
||||||
|
message: `${kickedPlayer.username} was eliminated from the match!`,
|
||||||
|
target: "#multiplayer",
|
||||||
|
senderId: global.users[0].id
|
||||||
|
});
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(this.MultiplayerMatch.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let numberOfPlayersRemaining = 0;
|
||||||
|
for (let i = 0; i < playerScores.length; i++) {
|
||||||
|
const slot = this.MultiplayerMatch.slots[playerScores[i].slotId];
|
||||||
|
|
||||||
|
if (slot.playerId !== -1 && slot.status !== 2) {
|
||||||
|
numberOfPlayersRemaining++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let playerClassContainer = null;
|
||||||
|
let remainingWriterContainer = null;
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
if (numberOfPlayersRemaining == 1) {
|
||||||
|
for (let i1 = 0; i1 < playerScores.length; i++) {
|
||||||
|
const slot = this.MultiplayerMatch.slots[playerScores[i].slotId];
|
||||||
|
if (slot.playerId !== -1 && slot.status !== 2) {
|
||||||
|
playerClassContainer = getUserById(slot.playerId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (numberOfPlayersRemaining) {
|
||||||
|
case 0:
|
||||||
|
remainingWriterContainer = new osu.Bancho.Writer;
|
||||||
|
remainingWriterContainer.SendMessage({
|
||||||
|
sendingClient: global.users[0].username,
|
||||||
|
message: "Everyone was eliminated from the match! Nobody wins.",
|
||||||
|
target: global.users[0].username,
|
||||||
|
senderId: global.users[0].id
|
||||||
|
});
|
||||||
|
for (i = 0; i < playerScores.length; i++) {
|
||||||
|
playerClassContainer = getUserById(playerScores[i].playerId);
|
||||||
|
playerClassContainer.addActionToQueue(remainingWriterContainer.toBuffer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
remainingWriterContainer = new osu.Bancho.Writer;
|
||||||
|
remainingWriterContainer.SendMessage({
|
||||||
|
sendingClient: global.users[0].username,
|
||||||
|
message: "You are the last one remaining, you win!",
|
||||||
|
target: global.users[0].username,
|
||||||
|
senderId: global.users[0].id
|
||||||
|
});
|
||||||
|
playerClassContainer.addActionToQueue(remainingWriterContainer.toBuffer);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.MultiplayerMatch.sendMatchUpdate();
|
||||||
|
// Update the match listing for users in the multiplayer lobby
|
||||||
|
global.MultiplayerManager.updateMatchListing();
|
||||||
|
}
|
||||||
|
}
|
215
server/MultiplayerManager.js
Normal file
215
server/MultiplayerManager.js
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
const osu = require("osu-packet"),
|
||||||
|
getUserById = require("./util/getUserById.js"),
|
||||||
|
UserPresenceBundle = require("./Packets/UserPresenceBundle.js"),
|
||||||
|
UserPresence = require("./Packets/UserPresence.js"),
|
||||||
|
StatusUpdate = require("./Packets/StatusUpdate.js"),
|
||||||
|
MultiplayerMatch = require("./MultiplayerMatch.js");
|
||||||
|
|
||||||
|
module.exports = class {
|
||||||
|
constructor() {
|
||||||
|
this.matches = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
userEnterLobby(currentUser) {
|
||||||
|
// If the user is currently already in a match force them to leave
|
||||||
|
if (currentUser.currentMatch != null)
|
||||||
|
currentUser.currentMatch.leaveMatch(currentUser);
|
||||||
|
|
||||||
|
// Add user to the stream for the lobby
|
||||||
|
global.StreamsHandler.addUserToStream("multiplayer_lobby", currentUser.id);
|
||||||
|
|
||||||
|
// Send user ids of all online users to all users in the lobby
|
||||||
|
global.StreamsHandler.sendToStream("multiplayer_lobby", UserPresenceBundle(currentUser, false), null);
|
||||||
|
|
||||||
|
// Loop through all matches
|
||||||
|
for (let i = 0; i < this.matches.length; i++) {
|
||||||
|
// Loop through all the users in this match
|
||||||
|
for (let i1 = 0; i1 < this.matches[i].slots.length; i1++) {
|
||||||
|
const slot = this.matches[i].slots[i1];
|
||||||
|
// Make sure there is a player / the slot is not locked
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// List the match on the client
|
||||||
|
osuPacketWriter.MatchNew(this.matches[i].createOsuMatchJSON());
|
||||||
|
|
||||||
|
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
}
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Add the user to the #lobby channel
|
||||||
|
if (!global.StreamsHandler.isUserInStream("#lobby", currentUser.id)) {
|
||||||
|
global.StreamsHandler.addUserToStream("#lobby", currentUser.id);
|
||||||
|
osuPacketWriter.ChannelJoinSuccess("#lobby");
|
||||||
|
}
|
||||||
|
|
||||||
|
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.id))
|
||||||
|
global.StreamsHandler.removeUserFromStream("multiplayer_lobby", currentUser.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMatchListing() {
|
||||||
|
// Send user ids of all online users to all users in the lobby
|
||||||
|
global.StreamsHandler.sendToStream("multiplayer_lobby", UserPresenceBundle(null, false), null);
|
||||||
|
|
||||||
|
// List through all matches
|
||||||
|
for (let i = 0; i < this.matches.length; i++) {
|
||||||
|
// List through all users in the match
|
||||||
|
for (let i1 = 0; i1 < this.matches[i].slots.length; i1++) {
|
||||||
|
const slot = this.matches[i].slots[i1];
|
||||||
|
// Make sure the slot has a user in it / isn't locked
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// List the match on the client
|
||||||
|
osuPacketWriter.MatchNew(this.matches[i].createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Send this data back to every user in the lobby
|
||||||
|
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createMultiplayerMatch(MatchHost, MatchData) {
|
||||||
|
let matchClass = null;
|
||||||
|
this.matches.push(matchClass = new MultiplayerMatch(MatchHost, MatchData));
|
||||||
|
|
||||||
|
// Join the user to the newly created match
|
||||||
|
this.joinMultiplayerMatch(MatchHost, {
|
||||||
|
matchId: matchClass.matchId,
|
||||||
|
gamePassword: matchClass.gamePassword
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
joinMultiplayerMatch(JoiningUser, JoinInfo) {
|
||||||
|
try {
|
||||||
|
let osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
const osuPacketWriter1 = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
let matchIndex = 0;
|
||||||
|
for (let i = 0; i < this.matches.length; i++) {
|
||||||
|
if (this.matches[i].matchId == JoinInfo.matchId) {
|
||||||
|
matchIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const streamName = this.matches[matchIndex].matchStreamName;
|
||||||
|
const match = this.matches[matchIndex];
|
||||||
|
|
||||||
|
let full = true;
|
||||||
|
// Loop through all slots to find an empty one
|
||||||
|
for (let i = 0; i < match.slots.length; i++) {
|
||||||
|
const slot = match.slots[i];
|
||||||
|
// Make sure the slot doesn't have a player in it / the slot is locked
|
||||||
|
if (slot.playerId !== -1 || slot.status === 2) continue;
|
||||||
|
|
||||||
|
// Slot is empty and not locked, we can join the match!
|
||||||
|
full = false;
|
||||||
|
slot.playerId = JoiningUser.id;
|
||||||
|
JoiningUser.matchSlotId = i;
|
||||||
|
slot.status = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const matchJSON = match.createOsuMatchJSON();
|
||||||
|
osuPacketWriter1.MatchUpdate(matchJSON);
|
||||||
|
osuPacketWriter.MatchJoinSuccess(matchJSON);
|
||||||
|
|
||||||
|
if (full) {
|
||||||
|
// Inform the client that they can't join the match
|
||||||
|
osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
osuPacketWriter.MatchJoinFail();
|
||||||
|
|
||||||
|
return JoiningUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the user's current match to this match
|
||||||
|
JoiningUser.currentMatch = match;
|
||||||
|
|
||||||
|
// Add user to the stream for the match
|
||||||
|
global.StreamsHandler.addUserToStream(streamName, JoiningUser.id);
|
||||||
|
|
||||||
|
// Inform all users in the match that a new user has joined
|
||||||
|
global.StreamsHandler.sendToStream(streamName, osuPacketWriter1.toBuffer, null);
|
||||||
|
|
||||||
|
osuPacketWriter.ChannelJoinSuccess("#multiplayer");
|
||||||
|
|
||||||
|
// Inform joining client they they have joined the match
|
||||||
|
JoiningUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
|
||||||
|
// Update the match listing for all users in the lobby since
|
||||||
|
// A user has joined a match
|
||||||
|
this.updateMatchListing();
|
||||||
|
} catch (e) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchJoinFail();
|
||||||
|
|
||||||
|
JoiningUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
|
||||||
|
this.updateMatchListing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leaveMultiplayerMatch(MatchUser) {
|
||||||
|
// Make sure the user is in a match
|
||||||
|
if (MatchUser.currentMatch == null) return;
|
||||||
|
|
||||||
|
const mpLobby = MatchUser.currentMatch.leaveMatch(MatchUser);
|
||||||
|
|
||||||
|
let empty = true;
|
||||||
|
// Check if the match is empty
|
||||||
|
for (let i = 0; i < mpLobby.slots.length; i++) {
|
||||||
|
const slot = mpLobby.slots[i];
|
||||||
|
// Check if the slot is avaliable
|
||||||
|
if (slot.playerId === -1) continue;
|
||||||
|
|
||||||
|
// There is a user in the match
|
||||||
|
empty = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The match is empty, proceed to remove it.
|
||||||
|
if (empty) {
|
||||||
|
let matchIndex;
|
||||||
|
// Loop through all matches
|
||||||
|
for (let i = 0; i < this.matches.length; i++) {
|
||||||
|
// If the match matches the match the user has left
|
||||||
|
if (this.matches[i].matchStreamName == MatchUser.currentMatch.matchStreamName) {
|
||||||
|
matchIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we got a match index
|
||||||
|
if (matchIndex == null) return;
|
||||||
|
|
||||||
|
// Remove this match from the list of active matches
|
||||||
|
this.matches.splice(matchIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
MatchUser.currentMatch = null;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
603
server/MultiplayerMatch.js
Normal file
603
server/MultiplayerMatch.js
Normal file
|
@ -0,0 +1,603 @@
|
||||||
|
const osu = require("osu-packet"),
|
||||||
|
getUserById = require("./util/getUserById.js"),
|
||||||
|
StatusUpdate = require("./Packets/StatusUpdate.js");
|
||||||
|
|
||||||
|
// TODO: Cache the player's slot position in their user class for a small optimisation
|
||||||
|
|
||||||
|
module.exports = class {
|
||||||
|
constructor(MatchHost, 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();
|
||||||
|
|
||||||
|
this.inProgress = MatchData.inProgress;
|
||||||
|
this.matchStartCountdownActive = false;
|
||||||
|
|
||||||
|
this.matchType = MatchData.matchType;
|
||||||
|
|
||||||
|
this.activeMods = MatchData.activeMods;
|
||||||
|
|
||||||
|
this.gameName = MatchData.gameName;
|
||||||
|
if (MatchData.gamePassword == '') MatchData.gamePassword == null;
|
||||||
|
this.gamePassword = MatchData.gamePassword;
|
||||||
|
|
||||||
|
this.beatmapName = MatchData.beatmapName;
|
||||||
|
this.beatmapId = MatchData.beatmapId;
|
||||||
|
this.beatmapChecksum = MatchData.beatmapChecksum;
|
||||||
|
|
||||||
|
this.slots = MatchData.slots;
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
this.slots[i].mods = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.host = MatchData.host;
|
||||||
|
|
||||||
|
this.playMode = MatchData.playMode;
|
||||||
|
|
||||||
|
this.matchScoringType = MatchData.matchScoringType;
|
||||||
|
this.matchTeamType = MatchData.matchTeamType;
|
||||||
|
this.specialModes = MatchData.specialModes;
|
||||||
|
|
||||||
|
this.seed = MatchData.seed;
|
||||||
|
|
||||||
|
this.matchStreamName = `mp_${this.matchId}`;
|
||||||
|
|
||||||
|
this.matchLoadSlots = null;
|
||||||
|
this.matchSkippedSlots = null;
|
||||||
|
|
||||||
|
this.playerScores = null;
|
||||||
|
|
||||||
|
this.multiplayerExtras = null;
|
||||||
|
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Update the status of the current user
|
||||||
|
StatusUpdate(MatchHost, MatchHost.id);
|
||||||
|
osuPacketWriter.MatchNew(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Queue match creation for user
|
||||||
|
MatchHost.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
|
||||||
|
global.StreamsHandler.addStream(this.matchStreamName, true, this.matchId);
|
||||||
|
|
||||||
|
// Update the match listing for users in the multiplayer lobby
|
||||||
|
global.MultiplayerManager.updateMatchListing();
|
||||||
|
}
|
||||||
|
|
||||||
|
createOsuMatchJSON() {
|
||||||
|
return {
|
||||||
|
matchId: this.matchId,
|
||||||
|
inProgress: this.inProgress,
|
||||||
|
matchType: this.matchType,
|
||||||
|
activeMods: this.activeMods,
|
||||||
|
gameName: this.gameName,
|
||||||
|
gamePassword: this.gamePassword,
|
||||||
|
beatmapName: this.beatmapName,
|
||||||
|
beatmapId: this.beatmapId,
|
||||||
|
beatmapChecksum: this.beatmapChecksum,
|
||||||
|
slots: this.slots,
|
||||||
|
host: this.host,
|
||||||
|
playMode: this.playMode,
|
||||||
|
matchScoringType: this.matchScoringType,
|
||||||
|
matchTeamType: this.matchTeamType,
|
||||||
|
specialModes: this.specialModes,
|
||||||
|
seed: this.seed
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
leaveMatch(MatchUser) {
|
||||||
|
try {
|
||||||
|
let userInMatch = false;
|
||||||
|
// Loop through all slots in the match
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
// Check if the user is in this slot
|
||||||
|
if (slot.playerId == MatchUser.id) {
|
||||||
|
userInMatch = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we don't run more than once
|
||||||
|
// Again, client double firing packets.
|
||||||
|
if (!userInMatch) return;
|
||||||
|
|
||||||
|
let osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Loop through all slots in the match
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
// Make sure the user is in this slot
|
||||||
|
if (slot.playerId != MatchUser.id) continue;
|
||||||
|
|
||||||
|
// Set the slot's status to avaliable
|
||||||
|
slot.playerId = -1;
|
||||||
|
slot.status = 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Remove the leaving user from the match's stream
|
||||||
|
global.StreamsHandler.removeUserFromStream(this.matchStreamName, MatchUser.id);
|
||||||
|
|
||||||
|
// Inform all users in the match that the leaving user has left
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Remove user from the multiplayer channel for the match
|
||||||
|
osuPacketWriter.ChannelRevoked("#multiplayer");
|
||||||
|
|
||||||
|
MatchUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMatch(MatchData) {
|
||||||
|
// Update match with new data
|
||||||
|
this.inProgress = MatchData.inProgress;
|
||||||
|
|
||||||
|
this.matchType = MatchData.matchType;
|
||||||
|
|
||||||
|
this.activeMods = MatchData.activeMods;
|
||||||
|
|
||||||
|
this.gameName = MatchData.gameName;
|
||||||
|
if (MatchData.gamePassword == '') MatchData.gamePassword == null;
|
||||||
|
this.gamePassword = MatchData.gamePassword;
|
||||||
|
|
||||||
|
this.beatmapName = MatchData.beatmapName;
|
||||||
|
this.beatmapId = MatchData.beatmapId;
|
||||||
|
this.beatmapChecksum = MatchData.beatmapChecksum;
|
||||||
|
|
||||||
|
this.host = MatchData.host;
|
||||||
|
|
||||||
|
this.playMode = MatchData.playMode;
|
||||||
|
|
||||||
|
this.matchScoringType = MatchData.matchScoringType;
|
||||||
|
this.matchTeamType = MatchData.matchTeamType;
|
||||||
|
this.specialModes = MatchData.specialModes;
|
||||||
|
|
||||||
|
this.seed = MatchData.seed;
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Send this new match data to all users in the match
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
// Update the match listing in the lobby to reflect these changes
|
||||||
|
global.MultiplayerManager.updateMatchListing();
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMatchUpdate() {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Update all users in the match with new match information
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
moveToSlot(MatchUser, SlotToMoveTo) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
let currentUserData, slotIndex;
|
||||||
|
// Loop through all slots in the match
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
// Make sure the user in this slot is the user we want
|
||||||
|
if (slot.playerId != MatchUser.id) continue;
|
||||||
|
|
||||||
|
currentUserData = slot;
|
||||||
|
slotIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the new slot's data to the user's old slot data
|
||||||
|
this.slots[SlotToMoveTo].playerId = currentUserData.playerId;
|
||||||
|
MatchUser.matchSlotId = SlotToMoveTo;
|
||||||
|
this.slots[SlotToMoveTo].status = currentUserData.status;
|
||||||
|
|
||||||
|
// Set the old slot's data to open
|
||||||
|
this.slots[slotIndex].playerId = -1;
|
||||||
|
this.slots[slotIndex].status = 1;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Send this change to all users in the match
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
// Update the match listing in the lobby to reflect this change
|
||||||
|
global.MultiplayerManager.updateMatchListing();
|
||||||
|
}
|
||||||
|
|
||||||
|
setReadyState(MatchUser, ReadyState) {
|
||||||
|
// Get the match the user is in
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Loop though all slots in the match
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
// Check if the player in this slot is this user
|
||||||
|
if (slot.playerId == MatchUser.id) {
|
||||||
|
// Turn on or off the user's ready state
|
||||||
|
if (ReadyState) slot.status = 8; // Ready
|
||||||
|
else slot.status = 4; // Not Ready
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Send this update to all users in the stream
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
lockMatchSlot(MatchUser, MatchUserToKick) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Make sure the user attempting to kick / lock is the host of the match
|
||||||
|
if (this.host != MatchUser.id) return;
|
||||||
|
|
||||||
|
// Make sure the user that is attempting to be kicked is not the host
|
||||||
|
if (this.slots[MatchUserToKick].playerId === this.host) return;
|
||||||
|
|
||||||
|
// Get the data of the slot at the index sent by the client
|
||||||
|
const slot = this.slots[MatchUserToKick];
|
||||||
|
let cachedPlayerId = slot.playerId;
|
||||||
|
|
||||||
|
// If the slot is empty lock instead of kicking
|
||||||
|
if (slot.playerId === -1) { // Slot is empty, lock it
|
||||||
|
if (slot.status === 1) slot.status = 2;
|
||||||
|
else slot.status = 1;
|
||||||
|
}
|
||||||
|
// The slot isn't empty, prepare to kick the player
|
||||||
|
else {
|
||||||
|
const kickedPlayer = getUserById(slot.playerId);
|
||||||
|
kickedPlayer.matchSlotId = -1;
|
||||||
|
slot.playerId = -1;
|
||||||
|
slot.status = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Inform all users in the match of the change
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
// Update the match listing in the lobby listing to reflect this change
|
||||||
|
global.MultiplayerManager.updateMatchListing();
|
||||||
|
|
||||||
|
if (cachedPlayerId !== null && cachedPlayerId !== -1) {
|
||||||
|
// Remove the kicked user from the match stream
|
||||||
|
global.StreamsHandler.removeUserFromStream(this.matchStreamName, cachedPlayerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
missingBeatmap(MatchUser) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Loop through all slots in the match
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
// Make sure the user in the slot is the user we want to update
|
||||||
|
if (slot.playerId != MatchUser.id) continue;
|
||||||
|
|
||||||
|
// User is missing the beatmap set the status to reflect it
|
||||||
|
slot.status = 16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Inform all users in the match of this change
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
notMissingBeatmap(MatchUser) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Loop through all slots in the match
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
// Make sure the user in the slot is the user we want to update
|
||||||
|
if (slot.playerId != MatchUser.id) continue;
|
||||||
|
|
||||||
|
// The user is not missing the beatmap, set the status to normal
|
||||||
|
else slot.status = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Inform all users in the match of this change
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
matchSkip(MatchUser) {
|
||||||
|
if (this.matchSkippedSlots == null) {
|
||||||
|
this.matchSkippedSlots = [];
|
||||||
|
|
||||||
|
const skippedSlots = this.matchSkippedSlots;
|
||||||
|
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
// Make sure the slot has a user in it
|
||||||
|
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
||||||
|
|
||||||
|
// Add the slot's user to the loaded checking array
|
||||||
|
skippedSlots.push({playerId: slot.playerId, skipped: false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const skippedSlots = this.matchSkippedSlots;
|
||||||
|
|
||||||
|
for (let i = 0; i < skippedSlots.length; i++) {
|
||||||
|
// If loadslot belongs to this user then set loaded to true
|
||||||
|
if (skippedSlots[i].playerId == MatchUser.id) {
|
||||||
|
skippedSlots[i].skipped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allSkipped = true;
|
||||||
|
for (let i = 0; i < skippedSlots.length; i++) {
|
||||||
|
if (skippedSlots[i].skipped) continue;
|
||||||
|
|
||||||
|
// A user hasn't finished playing
|
||||||
|
allSkipped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All players have finished playing, finish the match
|
||||||
|
if (allSkipped) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
osuPacketWriter.MatchPlayerSkipped(MatchUser.id);
|
||||||
|
osuPacketWriter.MatchSkip();
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
this.matchSkippedSlots = null;
|
||||||
|
} else {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
osuPacketWriter.MatchPlayerSkipped(MatchUser.id);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transferHost(MatchUserToTransferHostTo) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Set the lobby's host to the new user
|
||||||
|
this.host = this.slots[MatchUserToTransferHostTo].playerId;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Inform all clients in the match of the change
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Fix not being able to add DT when freemod is active
|
||||||
|
updateMods(MatchUser, MatchMods) {
|
||||||
|
// Check if freemod is enabled
|
||||||
|
if (this.specialModes === 1) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
if (slot.playerId === MatchUser.id) {
|
||||||
|
slot.mods = MatchMods;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
} else {
|
||||||
|
// Make sure the person updating mods is the host of the match
|
||||||
|
if (this.host !== MatchUser.id) return;
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Change the matches mods to these new mods
|
||||||
|
// TODO: Do this per user if freemod is enabled
|
||||||
|
this.activeMods = MatchMods;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Inform all users in the match of the change
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update match listing in the lobby to reflect this change
|
||||||
|
global.MultiplayerManager.updateMatchListing();
|
||||||
|
}
|
||||||
|
|
||||||
|
startMatch() {
|
||||||
|
// Make sure the match is not already in progress
|
||||||
|
// The client sometimes double fires the start packet
|
||||||
|
if (this.inProgress) return;
|
||||||
|
this.inProgress = true;
|
||||||
|
// Create array for monitoring users until they are ready to play
|
||||||
|
this.matchLoadSlots = [];
|
||||||
|
const loadedSlots = this.matchLoadSlots;
|
||||||
|
// Loop through all slots in the match
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
// Make sure the slot has a user in it
|
||||||
|
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
||||||
|
|
||||||
|
// Add the slot's user to the loaded checking array
|
||||||
|
loadedSlots.push({
|
||||||
|
playerId: slot.playerId,
|
||||||
|
loaded: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Loop through all slots in the match
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
// Make sure the slot has a user in it
|
||||||
|
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
||||||
|
|
||||||
|
// Set the user's status to playing
|
||||||
|
slot.status = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchStart(this.createOsuMatchJSON());
|
||||||
|
|
||||||
|
// Inform all users in the match that it has started
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
// Update all users in the match with new info
|
||||||
|
this.sendMatchUpdate();
|
||||||
|
|
||||||
|
// Update match listing in lobby to show the game is in progress
|
||||||
|
global.MultiplayerManager.updateMatchListing();
|
||||||
|
}
|
||||||
|
|
||||||
|
matchPlayerLoaded(MatchUser) {
|
||||||
|
const loadedSlots = this.matchLoadSlots;
|
||||||
|
|
||||||
|
// Loop through all user load check items
|
||||||
|
for (let i = 0; i < loadedSlots.length; i++) {
|
||||||
|
// If loadslot belongs to this user then set loaded to true
|
||||||
|
if (loadedSlots[i].playerId == MatchUser.id) {
|
||||||
|
loadedSlots[i].loaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through all loaded slots and check if all users are loaded
|
||||||
|
let allLoaded = true;
|
||||||
|
for (let i = 0; i < loadedSlots.length; i++) {
|
||||||
|
if (loadedSlots[i].loaded) continue;
|
||||||
|
|
||||||
|
// A user wasn't loaded, keep waiting.
|
||||||
|
allLoaded = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All players have loaded the beatmap, start playing.
|
||||||
|
if (allLoaded) {
|
||||||
|
let osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
osuPacketWriter.MatchAllPlayersLoaded();
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
// Blank out user loading array
|
||||||
|
this.matchLoadSlots = null;
|
||||||
|
|
||||||
|
this.playerScores = [];
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
||||||
|
|
||||||
|
this.playerScores.push({playerId: slot.playerId, slotId: i, score: 0, isCurrentlyFailed: false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPlayerFinishMatch(MatchUser) {
|
||||||
|
// If user loading slots do not exist
|
||||||
|
if (this.matchLoadSlots == null) {
|
||||||
|
this.matchLoadSlots = [];
|
||||||
|
// Repopulate user loading slots again
|
||||||
|
const loadedSlots = this.matchLoadSlots;
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
// Make sure the slot has a user
|
||||||
|
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
||||||
|
|
||||||
|
// Populate user loading slots with this user's id and load status
|
||||||
|
loadedSlots.push({
|
||||||
|
playerId: slot.playerId,
|
||||||
|
loaded: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadedSlots = this.matchLoadSlots;
|
||||||
|
|
||||||
|
// Loop through all loaded slots to make sure all users have finished playing
|
||||||
|
for (let i = 0; i < loadedSlots.length; i++) {
|
||||||
|
if (loadedSlots[i].playerId == MatchUser.id) {
|
||||||
|
loadedSlots[i].loaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allLoaded = true;
|
||||||
|
for (let i = 0; i < loadedSlots.length; i++) {
|
||||||
|
if (loadedSlots[i].loaded) continue;
|
||||||
|
|
||||||
|
// A user hasn't finished playing
|
||||||
|
allLoaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All players have finished playing, finish the match
|
||||||
|
if (allLoaded) this.finishMatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
finishMatch() {
|
||||||
|
if (!this.inProgress) return;
|
||||||
|
this.matchLoadSlots = null;
|
||||||
|
this.inProgress = false;
|
||||||
|
let osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Loop through all slots in the match
|
||||||
|
for (let i = 0; i < this.slots.length; i++) {
|
||||||
|
const slot = this.slots[i];
|
||||||
|
// Make sure the slot has a user
|
||||||
|
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
||||||
|
|
||||||
|
// Set the user's status back to normal from playing
|
||||||
|
slot.status = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchComplete();
|
||||||
|
|
||||||
|
// Inform all users in the match that it is complete
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
// Update all users in the match with new info
|
||||||
|
this.sendMatchUpdate();
|
||||||
|
|
||||||
|
// Update match info in the lobby to reflect that the match has finished
|
||||||
|
global.MultiplayerManager.updateMatchListing();
|
||||||
|
|
||||||
|
if (this.multiplayerExtras != null) this.multiplayerExtras.onMatchFinished(JSON.parse(JSON.stringify(this.playerScores)));
|
||||||
|
|
||||||
|
this.playerScores = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePlayerScore(MatchPlayer, MatchScoreData) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Make sure the user's slot ID is not invalid
|
||||||
|
if (this.matchSlotId == -1) return;
|
||||||
|
|
||||||
|
// Get the user's current slotID and append it to the givien data, just incase.
|
||||||
|
MatchScoreData.id = MatchPlayer.matchSlotId;
|
||||||
|
|
||||||
|
// Update the playerScores array accordingly
|
||||||
|
for (let i = 0; i < this.playerScores.length; i++) {
|
||||||
|
if (this.playerScores[i].playerId == MatchPlayer.id) {
|
||||||
|
this.playerScores[i].score = MatchScoreData.totalScore;
|
||||||
|
this.playerScores[i].isCurrentlyFailed = MatchScoreData.currentHp == 254;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchScoreUpdate(MatchScoreData);
|
||||||
|
|
||||||
|
// Send the newly updated score to all users in the match
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
matchFailed(MatchUser) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Make sure the user's slot ID is not invalid
|
||||||
|
if (MatchUser.matchSlotId == -1) return;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchPlayerFailed(MatchUser.id);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(this.matchStreamName, osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ module.exports = function(CurrentUser, InvitedUser) {
|
||||||
|
|
||||||
osuPacketWriter.SendMessage({
|
osuPacketWriter.SendMessage({
|
||||||
sendingClient: CurrentUser.username,
|
sendingClient: CurrentUser.username,
|
||||||
message: `Come join my multiplayer match: [osump://${CurrentUser.currentMatch}/ ${global.matches[CurrentUser.currentMatch][1].gameName}]`,
|
message: `Come join my multiplayer match: [osump://${CurrentUser.currentMatch.matchId}/ ${CurrentUser.currentMatch.gameName}]`,
|
||||||
target: CurrentUser.username,
|
target: CurrentUser.username,
|
||||||
senderId: CurrentUser.id
|
senderId: CurrentUser.id
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,22 +3,25 @@ const getUserById = require("./util/getUserById.js");
|
||||||
module.exports = class {
|
module.exports = class {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.avaliableStreams = {};
|
this.avaliableStreams = {};
|
||||||
|
this.avaliableStreamKeys = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
addStream(streamName, removeIfEmpty, spectatorHostId = null) {
|
addStream(streamName = "", removeIfEmpty = false, spectatorHostId = null) {
|
||||||
const streamNames = Object.keys(this.avaliableStreams);
|
// Make sure a stream with the same name doesn't exist already
|
||||||
if (streamNames.includes(streamName)) return global.consoleHelper.printBancho(`Did not add stream [${streamName}] A stream with the same name already exists`);
|
if (this.avaliableStreamKeys.includes(streamName))
|
||||||
|
return global.consoleHelper.printBancho(`Did not add stream [${streamName}] A stream with the same name already exists`);
|
||||||
// Add new stream to the list of streams
|
// Add new stream to the list of streams
|
||||||
this.avaliableStreams[streamName] = {
|
this.avaliableStreams[streamName] = {
|
||||||
streamUsers: [], // An array containing a list of user IDs of the users in a given stream
|
streamUsers: [], // An array containing a list of user IDs of the users in a given stream
|
||||||
streamSpectatorHost: spectatorHostId, // null unless stream is for spectating
|
streamSpectatorHost: spectatorHostId, // null unless stream is for spectating
|
||||||
removeIfEmpty: removeIfEmpty
|
removeIfEmpty: removeIfEmpty
|
||||||
}
|
}
|
||||||
|
this.avaliableStreamKeys = Object.keys(this.avaliableStreams);
|
||||||
global.consoleHelper.printBancho(`Added stream [${streamName}]`);
|
global.consoleHelper.printBancho(`Added stream [${streamName}]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if a stream has no users in it
|
// Checks if a stream has no users in it
|
||||||
streamChecker(interval) {
|
streamChecker(interval = 5000) {
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
// Get the names of all currently avaliable streams
|
// Get the names of all currently avaliable streams
|
||||||
const streams = global.StreamsHandler.getStreams();
|
const streams = global.StreamsHandler.getStreams();
|
||||||
|
@ -62,14 +65,35 @@ module.exports = class {
|
||||||
}
|
}
|
||||||
|
|
||||||
addUserToStream(streamName, userId) {
|
addUserToStream(streamName, userId) {
|
||||||
|
// Make sure the stream we are attempting to add this user to even exists
|
||||||
|
if (!this.doesStreamExist(streamName))
|
||||||
|
return global.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(userId))
|
||||||
|
return global.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)
|
||||||
|
if (userId <= 0 || userId == null)
|
||||||
|
return global.consoleHelper.printBancho(`Did not add user to stream [${streamName}] because their userId is invalid!`);
|
||||||
|
|
||||||
// Add user's id to the stream's user list
|
// Add user's id to the stream's user list
|
||||||
this.avaliableStreams[streamName].streamUsers.push(userId);
|
this.avaliableStreams[streamName].streamUsers.push(userId);
|
||||||
global.consoleHelper.printBancho(`Added user [${userId}] to stream ${streamName}`);
|
global.consoleHelper.printBancho(`Added user [${userId}] to stream ${streamName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUserFromStream(streamName, userId) {
|
removeUserFromStream(streamName, userId) {
|
||||||
// Make sure this isn't an invalid user
|
// Make sure the stream we are attempting to add this user to even exists
|
||||||
if (userId == -1 || userId == null) return;
|
if (!this.doesStreamExist(streamName))
|
||||||
|
return global.consoleHelper.printBancho(`Did not remove user from stream [${streamName}] because it does not exist!`);
|
||||||
|
|
||||||
|
// Make sure the user isn't already in the stream
|
||||||
|
if (!this.avaliableStreams[streamName].streamUsers.includes(userId))
|
||||||
|
return global.consoleHelper.printBancho(`Did not remove user from stream [${streamName}] because they are not in it!`);
|
||||||
|
|
||||||
|
// Make sure this isn't an invalid user (userId can't be lower than 1)
|
||||||
|
if (userId <= 0 || userId == null)
|
||||||
|
return global.consoleHelper.printBancho(`Did not remove user from stream [${streamName}] because their userId is invalid!`);
|
||||||
try {
|
try {
|
||||||
// Find index of user to remove
|
// Find index of user to remove
|
||||||
let userCurrentIndex;
|
let userCurrentIndex;
|
||||||
|
@ -87,21 +111,12 @@ module.exports = class {
|
||||||
}
|
}
|
||||||
|
|
||||||
doesStreamExist(streamName) {
|
doesStreamExist(streamName) {
|
||||||
let exist = false;
|
return this.avaliableStreamKeys.includes(streamName);
|
||||||
const streamList = Object.keys(this.avaliableStreams);
|
|
||||||
for (let i = 0; i < streamList.length; i++) {
|
|
||||||
if (streamList[i] == streamName) {
|
|
||||||
exist = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return exist;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getStreams() {
|
getStreams() {
|
||||||
// Return the names of all avaliable streams
|
// Return the names of all avaliable streams
|
||||||
return Object.keys(this.avaliableStreams);
|
return this.avaliableStreamKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
isUserInStream(streamName, userId) {
|
isUserInStream(streamName, userId) {
|
||||||
|
@ -112,6 +127,7 @@ module.exports = class {
|
||||||
removeStream(streamName) {
|
removeStream(streamName) {
|
||||||
try {
|
try {
|
||||||
delete this.avaliableStreams[streamName];
|
delete this.avaliableStreams[streamName];
|
||||||
|
this.avaliableStreamKeys = Object.keys(this.avaliableStreams);
|
||||||
} catch (e) { global.consoleHelper.printError(`Was not able to remove stream [${streamName}]`) }
|
} catch (e) { global.consoleHelper.printError(`Was not able to remove stream [${streamName}]`) }
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue