Make everything tabs instead of spaces & don't rely on a global consoleHelper

This commit is contained in:
Holly Stubbs 2022-01-04 03:39:53 +00:00
parent 26806438b7
commit e65fc13419
Signed by: tgpholly
GPG key ID: B8583C4B7D18119E
38 changed files with 2432 additions and 2422 deletions

133
Binato.js
View file

@ -1,86 +1,87 @@
console.clear(); console.clear();
// Globals // Globals
global.consoleHelper = require("./consoleHelper.js");
global.protocolVersion = 19; global.protocolVersion = 19;
const app = require("express")(), const app = require("express")(),
prometheusApp = require("express")(), consoleHelper = require("./consoleHelper.js"),
compression = require("compression"), prometheusApp = require("express")(),
fs = require("fs"), fs = require("fs"),
prom = require("prom-client"), serverHandler = require("./server/serverHandler.js"),
serverHandler = require("./server/serverHandler.js"), config = require("./config.json");
config = require("./config.json");
const debugMode = true; const debugMode = true;
if (config.prometheusEnabled) { if (config.prometheusEnabled) {
const register = new prom.Registry(); // We only need to require this if prom metrics are on.
const prom = require("prom-client");
register.setDefaultLabels({ app: "nodejs_binato" }); const register = new prom.Registry();
prom.collectDefaultMetrics({ register }); register.setDefaultLabels({ app: "nodejs_binato" });
prometheusApp.get("*", async (req, res) => { prom.collectDefaultMetrics({ register });
if (req.url.split("?")[0] != "/metrics") return res.status(404).end("");
prometheusApp.get("*", async (req, res) => {
res.end(await register.metrics()); if (req.url.split("?")[0] != "/metrics") return res.status(404).end("");
});
res.end(await register.metrics());
prometheusApp.listen(config.prometheusPort, () => global.consoleHelper.printBancho(`Prometheus metrics listening at port ${config.prometheusPort}`)); });
} else global.consoleHelper.printWarn("Prometheus is disabled!");
prometheusApp.listen(config.prometheusPort, () => consoleHelper.printBancho(`Prometheus metrics listening at port ${config.prometheusPort}`));
} else consoleHelper.printWarn("Prometheus is disabled!");
if (config.compression) { if (config.compression) {
app.use(compression()); app.use(require("compression")());
global.consoleHelper.printBancho("Gzip Compression is enabled."); consoleHelper.printBancho("Gzip Compression is enabled.");
} else global.consoleHelper.printWarn("Gzip Compression is disabled!"); } else consoleHelper.printWarn("Gzip Compression is disabled!");
app.use((req, res) => { app.use((req, res) => {
req.packet = new Buffer.alloc(0); req.packet = new Buffer.alloc(0);
req.on("data", (chunk) => req.packet = Buffer.concat([req.packet, chunk], req.packet.length + chunk.length)); req.on("data", (chunk) => req.packet = Buffer.concat([req.packet, chunk], req.packet.length + chunk.length));
req.on("end", () => { req.on("end", () => {
switch (req.method) { switch (req.method) {
case "GET": case "GET":
if (req.url == "/" || req.url == "/index.html" || req.url == "/index.html") { if (req.url == "/" || req.url == "/index.html" || req.url == "/index.html") {
fs.readFile("./web/serverPage.html", (err, data) => { fs.readFile("./web/serverPage.html", (err, data) => {
if (err) throw err; if (err) throw err;
if (debugMode) data = data.toString().replace("|isdebug?|", '<b style="color:red;">DEBUG</b>'); if (debugMode) data = data.toString().replace("|isdebug?|", '<b style="color:red;">DEBUG</b>');
else data = data.toString().replace("|isdebug?|", ''); else data = data.toString().replace("|isdebug?|", '');
res.send(data); res.send(data);
}); });
} else if (req.url == "/chat") { } else if (req.url == "/chat") {
fs.readFile("./web/chatPageTemplate.html", (err, data) => { fs.readFile("./web/chatPageTemplate.html", (err, data) => {
if (err) throw err; if (err) throw err;
let lines = "", flip = false; let lines = "", flip = false;
const limit = global.chatHistory.length < 10 ? 10 : global.chatHistory.length; const limit = global.chatHistory.length < 10 ? 10 : global.chatHistory.length;
for (let i = global.chatHistory.length - 10; i < limit; i++) { for (let i = global.chatHistory.length - 10; i < limit; i++) {
if (i < 0) i = 0; if (i < 0) i = 0;
lines += `<div class="line line${flip ? 1 : 0}">${global.chatHistory[i] == null ? "<hidden>blank</hidden>" : global.chatHistory[i]}</div>` lines += `<div class="line line${flip ? 1 : 0}">${global.chatHistory[i] == null ? "<hidden>blank</hidden>" : global.chatHistory[i]}</div>`
flip = !flip; flip = !flip;
} }
res.send(data.toString().replace("|content|", lines)); res.send(data.toString().replace("|content|", lines));
}); });
} }
break; break;
case "POST": case "POST":
// Make sure this address should respond to bancho requests // Make sure this address should respond to bancho requests
// Bancho addresses: c, c1, c2, c3, c4, c5, c6, ce // Bancho addresses: c, c1, c2, c3, c4, c5, c6, ce
// Just looking for the first character being "c" *should* be enough // Just looking for the first character being "c" *should* be enough
if (req.headers["host"].split(".")[0][0] == "c") if (req.headers["host"].split(".")[0][0] == "c")
serverHandler(req, res); serverHandler(req, res);
else else
res.status(400).send("400 | Bad Request!<br>Binato only accepts post requests on bancho subdomains.<hr>Binato"); res.status(400).send("400 | Bad Request!<br>Binato only accepts post requests on bancho subdomains.<hr>Binato");
break; break;
default: default:
res.status(405).send("405 | Method not allowed!<hr>Binato"); res.status(405).send("405 | Method not allowed!<hr>Binato");
break; break;
} }
}); });
}); });
app.listen(config.port, () => global.consoleHelper.printBancho(`Binato is up! Listening at port ${config.port}`)); app.listen(config.port, () => consoleHelper.printBancho(`Binato is up! Listening at port ${config.port}`));

View file

@ -1,33 +1,33 @@
const chalk = require("chalk"); const chalk = require("chalk");
module.exports = { module.exports = {
printWebReq:function(s) { printWebReq:function(s) {
console.log(`${this.getTime()} ${chalk.bgGreen(chalk.black(" WEBREQ "))} ${s}`); console.log(`${this.getTime()} ${chalk.bgGreen(chalk.black(" WEBREQ "))} ${s}`);
}, },
printBancho:function(s) { printBancho:function(s) {
console.log(`${this.getTime()} ${chalk.bgMagenta(chalk.black(" BANCHO "))} ${s}`); console.log(`${this.getTime()} ${chalk.bgMagenta(chalk.black(" BANCHO "))} ${s}`);
}, },
printChat:function(s) { printChat:function(s) {
console.log(`${this.getTime()} ${chalk.bgCyan(chalk.black(" CHATTO "))} ${s}`); console.log(`${this.getTime()} ${chalk.bgCyan(chalk.black(" CHATTO "))} ${s}`);
}, },
printWarn:function(s) { printWarn:function(s) {
console.warn(`${this.getTime()} ${chalk.bgYellow(chalk.black(" WARNIN "))} ${chalk.yellow(s)}`); console.warn(`${this.getTime()} ${chalk.bgYellow(chalk.black(" WARNIN "))} ${chalk.yellow(s)}`);
}, },
printError:function(s) { printError:function(s) {
console.error(`${this.getTime()} ${chalk.bgRed((" ERROR! "))} ${chalk.red(s)}`); console.error(`${this.getTime()} ${chalk.bgRed((" ERROR! "))} ${chalk.red(s)}`);
}, },
getTime:function() { getTime:function() {
const time = new Date(); const time = new Date();
return chalk.green(`[${correctValue(time.getHours())}:${correctValue(time.getMinutes())}:${correctValue(time.getSeconds())}]`); return chalk.green(`[${correctValue(time.getHours())}:${correctValue(time.getMinutes())}:${correctValue(time.getSeconds())}]`);
} }
} }
function correctValue(i) { function correctValue(i) {
if (i <= 9) return "0"+i; if (i <= 9) return "0"+i;
else return i; else return i;
} }

View file

@ -1,211 +1,211 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
maths = require("./util/Maths.js"), maths = require("./util/Maths.js"),
OsuBattleRoyale = require("./MultiplayerExtras/OsuBattleRoyale.js"); OsuBattleRoyale = require("./MultiplayerExtras/OsuBattleRoyale.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;
const command = Message.split(" ")[0]; const command = Message.split(" ")[0];
const args = Message.split(" "); const args = Message.split(" ");
let responseMessage = ""; let responseMessage = "";
let commandBanchoPacketWriter = null; let commandBanchoPacketWriter = null;
switch (command) { switch (command) {
case "!help": case "!help":
// This is terrible // This is terrible
if (args.length == 1) { if (args.length == 1) {
responseMessage = "Commands with an * next to them have a sub help section" + responseMessage = "Commands with an * next to them have a sub help section" +
"\n!help - Shows this message" + "\n!help - Shows this message" +
"\n!roll - Rolls a random number or a number between 0 and a given number" + "\n!roll - Rolls a random number or a number between 0 and a given number" +
"\n!ranking* - Sets your perfered ranking type" + "\n!ranking* - Sets your perfered ranking type" +
"\n!mp* - Shows information about all multiplayer commands" + "\n!mp* - Shows information about all multiplayer commands" +
"\n!admin* - Shows information about all admin commands"; "\n!admin* - Shows information about all admin commands";
} else { } else {
switch (args[1]) { switch (args[1]) {
case "ranking": case "ranking":
responseMessage = "Ranking Commands:" + responseMessage = "Ranking Commands:" +
"\n!ranking pp - Sets your ranking type to pp" + "\n!ranking pp - Sets your ranking type to pp" +
"\n!ranking score - Sets your ranking type to score" + "\n!ranking score - Sets your ranking type to score" +
"\n!ranking acc - Sets your ranking type to accuracy"; "\n!ranking acc - Sets your ranking type to accuracy";
break; break;
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"; "\n!mp obr - Enables Battle Royale mode";
break; break;
case "admin": case "admin":
responseMessage = "Admin Commands:" + responseMessage = "Admin Commands:" +
"\n!lock - Locks/Unlocks a channel and limits conversation to mods and above only"; "\n!lock - Locks/Unlocks a channel and limits conversation to mods and above only";
break; break;
default: default:
break; break;
} }
} }
break; break;
case "!ranking": case "!ranking":
if (args.length == 1) { if (args.length == 1) {
responseMessage = "You need to select a ranking mode! use \"!help ranking\" to see the options."; responseMessage = "You need to select a ranking mode! use \"!help ranking\" to see the options.";
} else { } else {
switch (args[1]) { switch (args[1]) {
case "pp": case "pp":
responseMessage = "Set ranking mode to pp"; responseMessage = "Set ranking mode to pp";
User.rankingMode = 0; User.rankingMode = 0;
User.getNewUserInformationFromDatabase(); User.getNewUserInformationFromDatabase();
break; break;
case "score": case "score":
responseMessage = "Set ranking mode to score"; responseMessage = "Set ranking mode to score";
User.rankingMode = 1; User.rankingMode = 1;
User.getNewUserInformationFromDatabase(); User.getNewUserInformationFromDatabase();
break; break;
case "acc": case "acc":
responseMessage = "Set ranking mode to accuracy"; responseMessage = "Set ranking mode to accuracy";
User.rankingMode = 2; User.rankingMode = 2;
User.getNewUserInformationFromDatabase(); User.getNewUserInformationFromDatabase();
break; break;
} }
} }
break; break;
case "!roll": case "!roll":
if (args.length == 1) { if (args.length == 1) {
responseMessage = User.username + " rolled " + maths.randInt(0, 65535); responseMessage = User.username + " rolled " + maths.randInt(0, 65535);
} else { } else {
if (`${parseInt(args[1])}` == "NaN") responseMessage = User.username + " rolled " + maths.randInt(0, 65535); if (`${parseInt(args[1])}` == "NaN") responseMessage = User.username + " rolled " + maths.randInt(0, 65535);
else responseMessage = User.username + " rolled " + maths.randInt(0, parseInt(args[1])); else responseMessage = User.username + " rolled " + maths.randInt(0, parseInt(args[1]));
} }
break; break;
case "!lock": case "!lock":
if (!Stream.includes("#")) responseMessage = "Multiplayer channels and private channels cannot be locked!"; if (!Stream.includes("#")) responseMessage = "Multiplayer channels and private channels cannot be locked!";
else { else {
for (let i = 0; i < global.channels.length; i++) { for (let i = 0; i < global.channels.length; i++) {
// Find the channel that pertains to this stream // Find the channel that pertains to this stream
if (global.channels[i].channelName == Stream) { if (global.channels[i].channelName == Stream) {
if (global.channels[i].locked) { if (global.channels[i].locked) {
global.channels[i].locked = false; global.channels[i].locked = false;
responseMessage = "Channel is now unlocked."; responseMessage = "Channel is now unlocked.";
} else { } else {
global.channels[i].locked = true; global.channels[i].locked = true;
responseMessage = "Channel is now locked, chat restricted to mods and above."; responseMessage = "Channel is now locked, chat restricted to mods and above.";
} }
break; break;
} }
} }
} }
break; break;
case "!mp": case "!mp":
if (!IsCalledFromMultiplayer) return; if (!IsCalledFromMultiplayer) return;
if (User.currentMatch.matchStartCountdownActive) 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; 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;
if (countdown != 0 && countdown > 0) countdown--; if (countdown != 0 && countdown > 0) countdown--;
if (countdown <= 10 && countdown > 0) { if (countdown <= 10 && countdown > 0) {
local_osuPacketWriter.SendMessage({ local_osuPacketWriter.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: "Starting in " + countdown, message: "Starting in " + countdown,
target: "#multiplayer", target: "#multiplayer",
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
global.StreamsHandler.sendToStream(Stream, local_osuPacketWriter.toBuffer, null); global.StreamsHandler.sendToStream(Stream, local_osuPacketWriter.toBuffer, null);
} else if (countdown == 0) { } else if (countdown == 0) {
local_osuPacketWriter.SendMessage({ local_osuPacketWriter.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: "Good luck, have fun!", message: "Good luck, have fun!",
target: "#multiplayer", target: "#multiplayer",
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
global.StreamsHandler.sendToStream(Stream, local_osuPacketWriter.toBuffer, null); global.StreamsHandler.sendToStream(Stream, local_osuPacketWriter.toBuffer, null);
User.currentMatch.matchStartCountdownActive = false; User.currentMatch.matchStartCountdownActive = false;
setTimeout(() => User.currentMatch.startMatch(), 1000); setTimeout(() => User.currentMatch.startMatch(), 1000);
clearInterval(intervalRef); clearInterval(intervalRef);
} }
}, 1000); }, 1000);
} else { } else {
responseMessage = "Good luck, have fun!"; responseMessage = "Good luck, have fun!";
setTimeout(() => User.currentMatch.startMatch(), 1000); setTimeout(() => User.currentMatch.startMatch(), 1000);
} }
break; break;
case "abort": case "abort":
//if (args.length > 2) return; //if (args.length > 2) return;
User.currentMatch.finishMatch(); User.currentMatch.finishMatch();
break; break;
case "obr": case "obr":
if (User.currentMatch.multiplayerExtras != null) { if (User.currentMatch.multiplayerExtras != null) {
if (User.currentMatch.multiplayerExtras.name == "osu! Battle Royale") { if (User.currentMatch.multiplayerExtras.name == "osu! Battle Royale") {
commandBanchoPacketWriter = new osu.Bancho.Writer; commandBanchoPacketWriter = new osu.Bancho.Writer;
commandBanchoPacketWriter.SendMessage({ commandBanchoPacketWriter.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: "osu! Battle Royale has been disabled!", message: "osu! Battle Royale has been disabled!",
target: "#multiplayer", target: "#multiplayer",
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
User.currentMatch.multiplayerExtras = null; User.currentMatch.multiplayerExtras = null;
global.StreamsHandler.sendToStream(Stream, commandBanchoPacketWriter.toBuffer, null); global.StreamsHandler.sendToStream(Stream, commandBanchoPacketWriter.toBuffer, null);
} }
else enableOBR(User, Stream, commandBanchoPacketWriter); else enableOBR(User, Stream, commandBanchoPacketWriter);
} }
else enableOBR(User, Stream, commandBanchoPacketWriter); else enableOBR(User, Stream, commandBanchoPacketWriter);
break; break;
default: default:
break; break;
} }
break; break;
} }
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
if (responseMessage != "") { if (responseMessage != "") {
if (Stream.includes("#")) { if (Stream.includes("#")) {
osuPacketWriter.SendMessage({ osuPacketWriter.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: responseMessage, message: responseMessage,
target: Stream, target: Stream,
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
} else { } else {
osuPacketWriter.SendMessage({ osuPacketWriter.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: responseMessage, message: responseMessage,
target: "#multiplayer", target: "#multiplayer",
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
} }
} }
global.StreamsHandler.sendToStream(Stream, osuPacketWriter.toBuffer, null); global.StreamsHandler.sendToStream(Stream, osuPacketWriter.toBuffer, null);
} }
function enableOBR(User, Stream, commandBanchoPacketWriter) { function enableOBR(User, Stream, commandBanchoPacketWriter) {
User.currentMatch.multiplayerExtras = new OsuBattleRoyale(User.currentMatch); User.currentMatch.multiplayerExtras = new OsuBattleRoyale(User.currentMatch);
commandBanchoPacketWriter = new osu.Bancho.Writer; commandBanchoPacketWriter = new osu.Bancho.Writer;
commandBanchoPacketWriter.SendMessage({ commandBanchoPacketWriter.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: "osu! Battle Royale has been enabled!", message: "osu! Battle Royale has been enabled!",
target: "#multiplayer", target: "#multiplayer",
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
commandBanchoPacketWriter.SendMessage({ commandBanchoPacketWriter.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].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", 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", target: "#multiplayer",
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
global.StreamsHandler.sendToStream(Stream, commandBanchoPacketWriter.toBuffer, null); global.StreamsHandler.sendToStream(Stream, commandBanchoPacketWriter.toBuffer, null);
} }

View file

@ -1,36 +1,36 @@
const mysql = require("mysql"); const mysql = require("mysql");
module.exports = class { module.exports = class {
constructor(databaseAddress, databasePort = 3306, databaseUsername, databasePassword, databaseName) { constructor(databaseAddress, databasePort = 3306, databaseUsername, databasePassword, databaseName) {
this.connectionPool = mysql.createPool({ this.connectionPool = mysql.createPool({
connectionLimit: 128, connectionLimit: 128,
host: databaseAddress, host: databaseAddress,
port: databasePort, port: databasePort,
user: databaseUsername, user: databaseUsername,
password: databasePassword, password: databasePassword,
database: databaseName database: databaseName
}); });
} }
async query(sqlQuery) { async query(sqlQuery) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.connectionPool.getConnection((err, connection) => { this.connectionPool.getConnection((err, connection) => {
if (err) { if (err) {
reject(err); reject(err);
connection.release(); connection.release();
} else { } else {
connection.query(sqlQuery, (err, data) => { connection.query(sqlQuery, (err, data) => {
if (err) { if (err) {
reject(err); reject(err);
connection.release(); connection.release();
} else { } else {
if (sqlQuery.includes("LIMIT 1")) resolve(data[0]); if (sqlQuery.includes("LIMIT 1")) resolve(data[0]);
else resolve(data); else resolve(data);
connection.release(); connection.release();
} }
}); });
} }
}); });
}); });
} }
} }

View file

@ -1,130 +1,130 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
MultiplayerMatch = require("../MultiplayerMatch.js"), MultiplayerMatch = require("../MultiplayerMatch.js"),
getUserById = require("../util/getUserById.js"); getUserById = require("../util/getUserById.js");
module.exports = class { module.exports = class {
constructor(MultiplayerMatchClass = new MultiplayerMatch()) { constructor(MultiplayerMatchClass = new MultiplayerMatch()) {
this.name = "osu! Battle Royale"; this.name = "osu! Battle Royale";
this.MultiplayerMatch = MultiplayerMatchClass; this.MultiplayerMatch = MultiplayerMatchClass;
} }
onMatchFinished(playerScores = [{playerId:0,slotId:0,score:0,isCurrentlyFailed:false}]) { onMatchFinished(playerScores = [{playerId:0,slotId:0,score:0,isCurrentlyFailed:false}]) {
let lowestScore = 9999999999999999; let lowestScore = 9999999999999999;
for (let i = 0; i < playerScores.length; i++) { for (let i = 0; i < playerScores.length; i++) {
const playerScore = playerScores[i]; const playerScore = playerScores[i];
if (playerScore.score < lowestScore) lowestScore = playerScore.score; if (playerScore.score < lowestScore) lowestScore = playerScore.score;
} }
let everyoneHasTheSameScore = true; let everyoneHasTheSameScore = true;
for (let i = 0; i < playerScores.length; i++) { for (let i = 0; i < playerScores.length; i++) {
if (playerScores[i].score != lowestScore) { if (playerScores[i].score != lowestScore) {
everyoneHasTheSameScore = false; everyoneHasTheSameScore = false;
break; break;
} }
} }
// Everyone has the same score, we don't need to kick anyone // Everyone has the same score, we don't need to kick anyone
if (everyoneHasTheSameScore) return; if (everyoneHasTheSameScore) return;
// Kick everyone with the lowest score // Kick everyone with the lowest score
for (let i = 0; i < playerScores.length; i++) { for (let i = 0; i < playerScores.length; i++) {
// Kick players if they have the lowest score or they are in a failed state // Kick players if they have the lowest score or they are in a failed state
if (playerScores[i].score == lowestScore || playerScores[i].isCurrentlyFailed) { if (playerScores[i].score == lowestScore || playerScores[i].isCurrentlyFailed) {
let osuPacketWriter = new osu.Bancho.Writer; let osuPacketWriter = new osu.Bancho.Writer;
// Get the slot this player is in // Get the slot this player is in
const slot = this.MultiplayerMatch.slots[playerScores[i].slotId]; const slot = this.MultiplayerMatch.slots[playerScores[i].slotId];
// Get the kicked player's user class // Get the kicked player's user class
const kickedPlayer = getUserById(slot.playerId); const kickedPlayer = getUserById(slot.playerId);
// Remove the kicked player's referance to the slot they were in // Remove the kicked player's referance to the slot they were in
kickedPlayer.matchSlotId = -1; kickedPlayer.matchSlotId = -1;
// Lock the slot the kicked player was in // Lock the slot the kicked player was in
slot.playerId = -1; slot.playerId = -1;
slot.status = 2; slot.status = 2;
// Remove the kicked player from the match's stream // Remove the kicked player from the match's stream
global.StreamsHandler.removeUserFromStream(this.MultiplayerMatch.matchStreamName, kickedPlayer.uuid); global.StreamsHandler.removeUserFromStream(this.MultiplayerMatch.matchStreamName, kickedPlayer.uuid);
global.StreamsHandler.removeUserFromStream(this.MultiplayerMatch.matchChatStreamName, kickedPlayer.uuid); global.StreamsHandler.removeUserFromStream(this.MultiplayerMatch.matchChatStreamName, kickedPlayer.uuid);
// Remove the kicked player's referance this this match // Remove the kicked player's referance this this match
kickedPlayer.currentMatch = null; kickedPlayer.currentMatch = null;
// Inform the kicked user's client that they were kicked // Inform the kicked user's client that they were kicked
osuPacketWriter.MatchUpdate(this.MultiplayerMatch.createOsuMatchJSON()); osuPacketWriter.MatchUpdate(this.MultiplayerMatch.createOsuMatchJSON());
osuPacketWriter.SendMessage({ osuPacketWriter.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: "You were eliminated from the match!", message: "You were eliminated from the match!",
target: global.users["bot"].username, target: global.users["bot"].username,
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
kickedPlayer.addActionToQueue(osuPacketWriter.toBuffer); kickedPlayer.addActionToQueue(osuPacketWriter.toBuffer);
osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.SendMessage({ osuPacketWriter.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: `${kickedPlayer.username} was eliminated from the match!`, message: `${kickedPlayer.username} was eliminated from the match!`,
target: "#multiplayer", target: "#multiplayer",
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
global.StreamsHandler.sendToStream(this.MultiplayerMatch.matchChatStreamName, osuPacketWriter.toBuffer, null); global.StreamsHandler.sendToStream(this.MultiplayerMatch.matchChatStreamName, osuPacketWriter.toBuffer, null);
} }
} }
let numberOfPlayersRemaining = 0; let numberOfPlayersRemaining = 0;
for (let i = 0; i < playerScores.length; i++) { for (let i = 0; i < playerScores.length; i++) {
const slot = this.MultiplayerMatch.slots[playerScores[i].slotId]; const slot = this.MultiplayerMatch.slots[playerScores[i].slotId];
if (slot.playerId !== -1 && slot.status !== 2) { if (slot.playerId !== -1 && slot.status !== 2) {
numberOfPlayersRemaining++; numberOfPlayersRemaining++;
} }
} }
let playerClassContainer = null; let playerClassContainer = null;
let remainingWriterContainer = null; let remainingWriterContainer = null;
let i = 0; let i = 0;
if (numberOfPlayersRemaining == 1) { if (numberOfPlayersRemaining == 1) {
for (let i1 = 0; i1 < playerScores.length; i++) { for (let i1 = 0; i1 < playerScores.length; i++) {
const slot = this.MultiplayerMatch.slots[playerScores[i].slotId]; const slot = this.MultiplayerMatch.slots[playerScores[i].slotId];
if (slot.playerId !== -1 && slot.status !== 2) { if (slot.playerId !== -1 && slot.status !== 2) {
playerClassContainer = getUserById(slot.playerId); playerClassContainer = getUserById(slot.playerId);
break; break;
} }
} }
} }
switch (numberOfPlayersRemaining) { switch (numberOfPlayersRemaining) {
case 0: case 0:
remainingWriterContainer = new osu.Bancho.Writer; remainingWriterContainer = new osu.Bancho.Writer;
remainingWriterContainer.SendMessage({ remainingWriterContainer.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: "Everyone was eliminated from the match! Nobody wins.", message: "Everyone was eliminated from the match! Nobody wins.",
target: global.users["bot"].username, target: global.users["bot"].username,
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
for (i = 0; i < playerScores.length; i++) { for (i = 0; i < playerScores.length; i++) {
playerClassContainer = getUserById(playerScores[i].playerId); playerClassContainer = getUserById(playerScores[i].playerId);
playerClassContainer.addActionToQueue(remainingWriterContainer.toBuffer); playerClassContainer.addActionToQueue(remainingWriterContainer.toBuffer);
} }
break; break;
case 1: case 1:
remainingWriterContainer = new osu.Bancho.Writer; remainingWriterContainer = new osu.Bancho.Writer;
remainingWriterContainer.SendMessage({ remainingWriterContainer.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: "You are the last one remaining, you win!", message: "You are the last one remaining, you win!",
target: global.users["bot"].username, target: global.users["bot"].username,
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
playerClassContainer.addActionToQueue(remainingWriterContainer.toBuffer); playerClassContainer.addActionToQueue(remainingWriterContainer.toBuffer);
break; break;
default: default:
break; break;
} }
this.MultiplayerMatch.sendMatchUpdate(); this.MultiplayerMatch.sendMatchUpdate();
// Update the match listing for users in the multiplayer lobby // Update the match listing for users in the multiplayer lobby
global.MultiplayerManager.updateMatchListing(); global.MultiplayerManager.updateMatchListing();
} }
} }

View file

@ -1,220 +1,220 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
UserPresenceBundle = require("./Packets/UserPresenceBundle.js"), UserPresenceBundle = require("./Packets/UserPresenceBundle.js"),
UserPresence = require("./Packets/UserPresence.js"), UserPresence = require("./Packets/UserPresence.js"),
StatusUpdate = require("./Packets/StatusUpdate.js"), StatusUpdate = require("./Packets/StatusUpdate.js"),
MultiplayerMatch = require("./MultiplayerMatch.js"); MultiplayerMatch = require("./MultiplayerMatch.js");
module.exports = class { module.exports = class {
constructor() { constructor() {
this.matches = []; this.matches = [];
} }
userEnterLobby(currentUser) { userEnterLobby(currentUser) {
// If the user is currently already in a match force them to leave // If the user is currently already in a match force them to leave
if (currentUser.currentMatch != null) if (currentUser.currentMatch != null)
currentUser.currentMatch.leaveMatch(currentUser); currentUser.currentMatch.leaveMatch(currentUser);
// Add user to the stream for the lobby // Add user to the stream for the lobby
global.StreamsHandler.addUserToStream("multiplayer_lobby", currentUser.uuid); global.StreamsHandler.addUserToStream("multiplayer_lobby", currentUser.uuid);
// Send user ids of all online users to all users in the lobby // Send user ids of all online users to all users in the lobby
global.StreamsHandler.sendToStream("multiplayer_lobby", UserPresenceBundle(currentUser, false), null); global.StreamsHandler.sendToStream("multiplayer_lobby", UserPresenceBundle(currentUser, false), null);
// Loop through all matches // Loop through all matches
for (let i = 0; i < this.matches.length; i++) { for (let i = 0; i < this.matches.length; i++) {
// Loop through all the users in this match // Loop through all the users in this match
for (let i1 = 0; i1 < this.matches[i].slots.length; i1++) { for (let i1 = 0; i1 < this.matches[i].slots.length; i1++) {
const slot = this.matches[i].slots[i1]; const slot = this.matches[i].slots[i1];
// Make sure there is a player / the slot is not locked // Make sure there is a player / the slot is not locked
if (slot.playerId == -1 || slot.status == 2) continue; if (slot.playerId == -1 || slot.status == 2) continue;
// Send information for this user to all users in the lobby // 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", UserPresence(currentUser, slot.playerId, false), null);
global.StreamsHandler.sendToStream("multiplayer_lobby", StatusUpdate(currentUser, slot.playerId, false), null); global.StreamsHandler.sendToStream("multiplayer_lobby", StatusUpdate(currentUser, slot.playerId, false), null);
} }
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
// List the match on the client // List the match on the client
osuPacketWriter.MatchNew(this.matches[i].createOsuMatchJSON()); osuPacketWriter.MatchNew(this.matches[i].createOsuMatchJSON());
currentUser.addActionToQueue(osuPacketWriter.toBuffer); currentUser.addActionToQueue(osuPacketWriter.toBuffer);
} }
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
// Add the user to the #lobby channel // Add the user to the #lobby channel
if (!global.StreamsHandler.isUserInStream("#lobby", currentUser.uuid)) { if (!global.StreamsHandler.isUserInStream("#lobby", currentUser.uuid)) {
global.StreamsHandler.addUserToStream("#lobby", currentUser.uuid); global.StreamsHandler.addUserToStream("#lobby", currentUser.uuid);
osuPacketWriter.ChannelJoinSuccess("#lobby"); osuPacketWriter.ChannelJoinSuccess("#lobby");
} }
currentUser.addActionToQueue(osuPacketWriter.toBuffer); currentUser.addActionToQueue(osuPacketWriter.toBuffer);
} }
userLeaveLobby(currentUser) { userLeaveLobby(currentUser) {
// Remove user from the stream for the multiplayer lobby if they are a part of it // Remove user from the stream for the multiplayer lobby if they are a part of it
if (global.StreamsHandler.isUserInStream("multiplayer_lobby", currentUser.uuid)) if (global.StreamsHandler.isUserInStream("multiplayer_lobby", currentUser.uuid))
global.StreamsHandler.removeUserFromStream("multiplayer_lobby", currentUser.uuid); global.StreamsHandler.removeUserFromStream("multiplayer_lobby", currentUser.uuid);
} }
updateMatchListing() { updateMatchListing() {
// Send user ids of all online users to all users in the lobby // Send user ids of all online users to all users in the lobby
global.StreamsHandler.sendToStream("multiplayer_lobby", UserPresenceBundle(null, false), null); global.StreamsHandler.sendToStream("multiplayer_lobby", UserPresenceBundle(null, false), null);
// List through all matches // List through all matches
for (let i = 0; i < this.matches.length; i++) { for (let i = 0; i < this.matches.length; i++) {
// List through all users in the match // List through all users in the match
for (let i1 = 0; i1 < this.matches[i].slots.length; i1++) { for (let i1 = 0; i1 < this.matches[i].slots.length; i1++) {
const slot = this.matches[i].slots[i1]; const slot = this.matches[i].slots[i1];
// Make sure the slot has a user in it / isn't locked // Make sure the slot has a user in it / isn't locked
if (slot.playerId == -1 || slot.status == 2) continue; if (slot.playerId == -1 || slot.status == 2) continue;
// Send information for this user to all users in the lobby // 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", UserPresence(null, slot.playerId, false), null);
global.StreamsHandler.sendToStream("multiplayer_lobby", StatusUpdate(null, slot.playerId, false), null); global.StreamsHandler.sendToStream("multiplayer_lobby", StatusUpdate(null, slot.playerId, false), null);
} }
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
// List the match on the client // List the match on the client
osuPacketWriter.MatchNew(this.matches[i].createOsuMatchJSON()); osuPacketWriter.MatchNew(this.matches[i].createOsuMatchJSON());
// Send this data back to every user in the lobby // Send this data back to every user in the lobby
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null); global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null);
} }
} }
createMultiplayerMatch(MatchHost, MatchData) { createMultiplayerMatch(MatchHost, MatchData) {
let matchClass = null; let matchClass = null;
this.matches.push(matchClass = new MultiplayerMatch(MatchHost, MatchData)); this.matches.push(matchClass = new MultiplayerMatch(MatchHost, MatchData));
// Join the user to the newly created match // Join the user to the newly created match
this.joinMultiplayerMatch(MatchHost, { this.joinMultiplayerMatch(MatchHost, {
matchId: matchClass.matchId, matchId: matchClass.matchId,
gamePassword: matchClass.gamePassword gamePassword: matchClass.gamePassword
}); });
} }
joinMultiplayerMatch(JoiningUser, JoinInfo) { joinMultiplayerMatch(JoiningUser, JoinInfo) {
try { try {
let osuPacketWriter = new osu.Bancho.Writer; let osuPacketWriter = new osu.Bancho.Writer;
const osuPacketWriter1 = new osu.Bancho.Writer; const osuPacketWriter1 = new osu.Bancho.Writer;
let matchIndex = 0; let matchIndex = 0;
for (let i = 0; i < this.matches.length; i++) { for (let i = 0; i < this.matches.length; i++) {
if (this.matches[i].matchId == JoinInfo.matchId) { if (this.matches[i].matchId == JoinInfo.matchId) {
matchIndex = i; matchIndex = i;
break; break;
} }
} }
const streamName = this.matches[matchIndex].matchStreamName; const streamName = this.matches[matchIndex].matchStreamName;
const chatStreamName = this.matches[matchIndex].matchChatStreamName; const chatStreamName = this.matches[matchIndex].matchChatStreamName;
const match = this.matches[matchIndex]; const match = this.matches[matchIndex];
let full = true; let full = true;
// Loop through all slots to find an empty one // Loop through all slots to find an empty one
for (let i = 0; i < match.slots.length; i++) { for (let i = 0; i < match.slots.length; i++) {
const slot = match.slots[i]; const slot = match.slots[i];
// Make sure the slot doesn't have a player in it / the slot is locked // Make sure the slot doesn't have a player in it / the slot is locked
if (slot.playerId !== -1 || slot.status === 2) continue; if (slot.playerId !== -1 || slot.status === 2) continue;
// Slot is empty and not locked, we can join the match! // Slot is empty and not locked, we can join the match!
full = false; full = false;
slot.playerId = JoiningUser.id; slot.playerId = JoiningUser.id;
JoiningUser.matchSlotId = i; JoiningUser.matchSlotId = i;
slot.status = 4; slot.status = 4;
break; break;
} }
const matchJSON = match.createOsuMatchJSON(); const matchJSON = match.createOsuMatchJSON();
osuPacketWriter1.MatchUpdate(matchJSON); osuPacketWriter1.MatchUpdate(matchJSON);
osuPacketWriter.MatchJoinSuccess(matchJSON); osuPacketWriter.MatchJoinSuccess(matchJSON);
if (full) { if (full) {
throw "MatchFullException"; throw "MatchFullException";
} }
// Set the user's current match to this match // Set the user's current match to this match
JoiningUser.currentMatch = match; JoiningUser.currentMatch = match;
// Add user to the stream for the match // Add user to the stream for the match
global.StreamsHandler.addUserToStream(streamName, JoiningUser.uuid); global.StreamsHandler.addUserToStream(streamName, JoiningUser.uuid);
global.StreamsHandler.addUserToStream(chatStreamName, JoiningUser.uuid); global.StreamsHandler.addUserToStream(chatStreamName, JoiningUser.uuid);
// Inform all users in the match that a new user has joined // Inform all users in the match that a new user has joined
global.StreamsHandler.sendToStream(streamName, osuPacketWriter1.toBuffer, null); global.StreamsHandler.sendToStream(streamName, osuPacketWriter1.toBuffer, null);
osuPacketWriter.ChannelJoinSuccess("#multiplayer"); osuPacketWriter.ChannelJoinSuccess("#multiplayer");
// Inform joining client they they have joined the match // Inform joining client they they have joined the match
JoiningUser.addActionToQueue(osuPacketWriter.toBuffer); JoiningUser.addActionToQueue(osuPacketWriter.toBuffer);
// Update the match listing for all users in the lobby since // Update the match listing for all users in the lobby since
// A user has joined a match // A user has joined a match
this.updateMatchListing(); this.updateMatchListing();
} catch (e) { } catch (e) {
// Inform the client that there was an issue joining the match // Inform the client that there was an issue joining the match
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.MatchJoinFail(); osuPacketWriter.MatchJoinFail();
JoiningUser.addActionToQueue(osuPacketWriter.toBuffer); JoiningUser.addActionToQueue(osuPacketWriter.toBuffer);
this.updateMatchListing(); this.updateMatchListing();
} }
} }
leaveMultiplayerMatch(MatchUser) { leaveMultiplayerMatch(MatchUser) {
// Make sure the user is in a match // Make sure the user is in a match
if (MatchUser.currentMatch == null) return; if (MatchUser.currentMatch == null) return;
const mpLobby = MatchUser.currentMatch.leaveMatch(MatchUser); const mpLobby = MatchUser.currentMatch.leaveMatch(MatchUser);
let empty = true; let empty = true;
// Check if the match is empty // Check if the match is empty
for (let i = 0; i < mpLobby.slots.length; i++) { for (let i = 0; i < mpLobby.slots.length; i++) {
const slot = mpLobby.slots[i]; const slot = mpLobby.slots[i];
// Check if the slot is avaliable // Check if the slot is avaliable
if (slot.playerId === -1) continue; if (slot.playerId === -1) continue;
// There is a user in the match // There is a user in the match
empty = false; empty = false;
break; break;
} }
// The match is empty, proceed to remove it. // The match is empty, proceed to remove it.
if (empty) { if (empty) {
let matchIndex; let matchIndex;
// Loop through all matches // Loop through all matches
for (let i = 0; i < this.matches.length; i++) { for (let i = 0; i < this.matches.length; i++) {
// If the match matches the match the user has left // If the match matches the match the user has left
if (this.matches[i].matchStreamName == MatchUser.currentMatch.matchStreamName) { if (this.matches[i].matchStreamName == MatchUser.currentMatch.matchStreamName) {
matchIndex = i; matchIndex = i;
break; break;
} }
} }
// Make sure we got a match index // Make sure we got a match index
if (matchIndex == null) return; if (matchIndex == null) return;
// Remove this match from the list of active matches // Remove this match from the list of active matches
this.matches.splice(matchIndex, 1); this.matches.splice(matchIndex, 1);
} }
MatchUser.currentMatch = null; MatchUser.currentMatch = null;
// Update the match listing to reflect this change (either removal or user leaving) // Update the match listing to reflect this change (either removal or user leaving)
this.updateMatchListing(); this.updateMatchListing();
// Delay a 2nd match listing update // Delay a 2nd match listing update
setTimeout(() => { setTimeout(() => {
this.updateMatchListing(); this.updateMatchListing();
}, 1000); }, 1000);
} }
getMatch(MatchID) { getMatch(MatchID) {
for (let match in this.matches) { for (let match in this.matches) {
if (match.matchId == MatchID) return match; if (match.matchId == MatchID) return match;
} }
return null; return null;
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,3 @@
module.exports = function(CurrentUser, FriendToAdd) { module.exports = function(CurrentUser, FriendToAdd) {
global.DatabaseHelper.query(`INSERT INTO friends (user, friendsWith) VALUES (${CurrentUser.id}, ${FriendToAdd});`); global.DatabaseHelper.query(`INSERT INTO friends (user, friendsWith) VALUES (${CurrentUser.id}, ${FriendToAdd});`);
} }

View file

@ -1,10 +1,10 @@
const StatusUpdate = require("./StatusUpdate.js"); const StatusUpdate = require("./StatusUpdate.js");
module.exports = function(currentUser, data) { module.exports = function(currentUser, data) {
currentUser.updatePresence(data); currentUser.updatePresence(data);
if (global.StreamsHandler.doesStreamExist(`sp_${currentUser.username}`)) { if (global.StreamsHandler.doesStreamExist(`sp_${currentUser.username}`)) {
const statusUpdate = StatusUpdate(currentUser, currentUser.id, false); const statusUpdate = StatusUpdate(currentUser, currentUser.id, false);
global.StreamsHandler.sendToStream(`sp_${currentUser.username}`, statusUpdate, null); global.StreamsHandler.sendToStream(`sp_${currentUser.username}`, statusUpdate, null);
} }
} }

View file

@ -1,15 +1,16 @@
const osu = require("osu-packet"); const osu = require("osu-packet"),
consoleHelper = require("../../consoleHelper.js");
module.exports = function(CurrentUser, channelName = "") { module.exports = function(CurrentUser, channelName = "") {
// Make sure the user is not already in the channel // Make sure the user is not already in the channel
if (global.StreamsHandler.isUserInStream(channelName, CurrentUser.uuid)) if (global.StreamsHandler.isUserInStream(channelName, CurrentUser.uuid))
return global.consoleHelper.printBancho(`Did not add user to channel ${channelName} because they are already in it`); return consoleHelper.printBancho(`Did not add user to channel ${channelName} because they are already in it`);
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.ChannelJoinSuccess(channelName); osuPacketWriter.ChannelJoinSuccess(channelName);
if (!global.StreamsHandler.isUserInStream(channelName, CurrentUser.uuid)) if (!global.StreamsHandler.isUserInStream(channelName, CurrentUser.uuid))
global.StreamsHandler.addUserToStream(channelName, CurrentUser.uuid); global.StreamsHandler.addUserToStream(channelName, CurrentUser.uuid);
CurrentUser.addActionToQueue(osuPacketWriter.toBuffer); CurrentUser.addActionToQueue(osuPacketWriter.toBuffer);
} }

View file

@ -1,5 +1,5 @@
module.exports = function(CurrentUser, data) { module.exports = function(CurrentUser, data) {
if (data == "#multiplayer") return; // Ignore requests for multiplayer if (data == "#multiplayer") return; // Ignore requests for multiplayer
global.StreamsHandler.removeUserFromStream(data, CurrentUser.uuid); global.StreamsHandler.removeUserFromStream(data, CurrentUser.uuid);
} }

View file

@ -1,27 +1,28 @@
const osu = require("osu-packet"); const osu = require("osu-packet"),
consoleHelper = require("../../consoleHelper.js");
module.exports = function(CurrentUser) { module.exports = function(CurrentUser) {
const logoutStartTime = new Date().getTime(); const logoutStartTime = Date.now();
const streamList = global.StreamsHandler.getStreams(); const streamList = global.StreamsHandler.getStreams();
for (let i = 0; i < streamList.length; i++) { for (let i = 0; i < streamList.length; i++) {
if (global.StreamsHandler.isUserInStream(streamList[i], CurrentUser.uuid)) { if (global.StreamsHandler.isUserInStream(streamList[i], CurrentUser.uuid)) {
global.StreamsHandler.removeUserFromStream(streamList[i], CurrentUser.uuid); global.StreamsHandler.removeUserFromStream(streamList[i], CurrentUser.uuid);
} }
} }
// Remove user from user list // Remove user from user list
global.removeUser(CurrentUser); global.removeUser(CurrentUser);
const osuPacketWriter = new osu.Bancho.Writer(); const osuPacketWriter = new osu.Bancho.Writer();
osuPacketWriter.SendMessage({ osuPacketWriter.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: `User ${CurrentUser.username} has logged out.`, message: `User ${CurrentUser.username} has logged out.`,
target: "#userlog", target: "#userlog",
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
global.StreamsHandler.sendToStream("#userlog", osuPacketWriter.toBuffer); global.StreamsHandler.sendToStream("#userlog", osuPacketWriter.toBuffer);
global.consoleHelper.printBancho(`User logged out, took ${new Date().getTime() - logoutStartTime}ms. [User: ${CurrentUser.username}]`); consoleHelper.printBancho(`User logged out, took ${Date.now() - logoutStartTime}ms. [User: ${CurrentUser.username}]`);
} }

View file

@ -1,17 +1,17 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
getUserById = require("../util/getUserById.js"); getUserById = require("../util/getUserById.js");
module.exports = function(CurrentUser, InvitedUser) { module.exports = function(CurrentUser, InvitedUser) {
let osuPacketWriter = new osu.Bancho.Writer; let osuPacketWriter = new osu.Bancho.Writer;
const InvitedUserClass = getUserById(InvitedUser); const InvitedUserClass = getUserById(InvitedUser);
osuPacketWriter.SendMessage({ osuPacketWriter.SendMessage({
sendingClient: CurrentUser.username, sendingClient: CurrentUser.username,
message: `Come join my multiplayer match: [osump://${CurrentUser.currentMatch.matchId}/ ${CurrentUser.currentMatch.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
}); });
InvitedUserClass.addActionToQueue(osuPacketWriter.toBuffer); InvitedUserClass.addActionToQueue(osuPacketWriter.toBuffer);
} }

View file

@ -1,3 +1,3 @@
module.exports = function(CurrentUser, FriendToRemove) { module.exports = function(CurrentUser, FriendToRemove) {
global.DatabaseHelper.query(`DELETE FROM friends WHERE user = ${CurrentUser.id} AND friendsWith = ${FriendToRemove} LIMIT 1`); global.DatabaseHelper.query(`DELETE FROM friends WHERE user = ${CurrentUser.id} AND friendsWith = ${FriendToRemove} LIMIT 1`);
} }

View file

@ -1,19 +1,19 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
getUserByUsername = require("../util/getUserByUsername.js"); getUserByUsername = require("../util/getUserByUsername.js");
module.exports = function(CurrentUser, CurrentPacket) { module.exports = function(CurrentUser, CurrentPacket) {
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
const userSentTo = getUserByUsername(CurrentPacket.target); const userSentTo = getUserByUsername(CurrentPacket.target);
if (userSentTo == null) return; if (userSentTo == null) return;
osuPacketWriter.SendMessage({ osuPacketWriter.SendMessage({
sendingClient: CurrentUser.username, sendingClient: CurrentUser.username,
message: CurrentPacket.message, message: CurrentPacket.message,
target: CurrentUser.username, target: CurrentUser.username,
senderId: CurrentUser.id senderId: CurrentUser.id
}); });
// Write chat message to stream asociated with chat channel // Write chat message to stream asociated with chat channel
return userSentTo.addActionToQueue(osuPacketWriter.toBuffer); return userSentTo.addActionToQueue(osuPacketWriter.toBuffer);
} }

View file

@ -1,56 +1,57 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
botCommandHandler = require("../BotCommandHandler.js"); botCommandHandler = require("../BotCommandHandler.js"),
consoleHelper = require("../../consoleHelper.js");
module.exports = function(CurrentUser, CurrentPacket) { module.exports = function(CurrentUser, CurrentPacket) {
let isSendingChannelLocked = false; let isSendingChannelLocked = false;
for (let i = 0; i < global.channels.length; i++) { for (let i = 0; i < global.channels.length; i++) {
if (!CurrentPacket.target.includes("#")) break; if (!CurrentPacket.target.includes("#")) break;
if (global.channels[i].channelName == CurrentPacket.target) { if (global.channels[i].channelName == CurrentPacket.target) {
isSendingChannelLocked = global.channels[i].locked; isSendingChannelLocked = global.channels[i].locked;
break; break;
} }
} }
if (isSendingChannelLocked) { if (isSendingChannelLocked) {
if (CurrentPacket.message.includes("!")) { if (CurrentPacket.message.includes("!")) {
botCommandHandler(CurrentUser, CurrentPacket.message, CurrentPacket.target); botCommandHandler(CurrentUser, CurrentPacket.message, CurrentPacket.target);
} else { } else {
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.SendMessage({ osuPacketWriter.SendMessage({
sendingClient: global.users["bot"].username, sendingClient: global.users["bot"].username,
message: "The channel you are currently trying to send to is locked, please check back later!", message: "The channel you are currently trying to send to is locked, please check back later!",
target: CurrentPacket.target, target: CurrentPacket.target,
senderId: global.users["bot"].id senderId: global.users["bot"].id
}); });
CurrentUser.addActionToQueue(osuPacketWriter.toBuffer); CurrentUser.addActionToQueue(osuPacketWriter.toBuffer);
} }
return; return;
} }
global.consoleHelper.printChat(`${CurrentUser.username} in ${CurrentPacket.target} sent: ${CurrentPacket.message}`); consoleHelper.printChat(`${CurrentUser.username} in ${CurrentPacket.target} sent: ${CurrentPacket.message}`);
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.SendMessage({ osuPacketWriter.SendMessage({
sendingClient: CurrentUser.username, sendingClient: CurrentUser.username,
message: CurrentPacket.message, message: CurrentPacket.message,
target: CurrentPacket.target, target: CurrentPacket.target,
senderId: CurrentUser.id senderId: CurrentUser.id
}); });
if (CurrentPacket.target == "#multiplayer") { if (CurrentPacket.target == "#multiplayer") {
global.StreamsHandler.sendToStream(CurrentUser.currentMatch.matchChatStreamName, osuPacketWriter.toBuffer, CurrentUser.uuid); global.StreamsHandler.sendToStream(CurrentUser.currentMatch.matchChatStreamName, osuPacketWriter.toBuffer, CurrentUser.uuid);
botCommandHandler(CurrentUser, CurrentPacket.message, CurrentUser.currentMatch.matchChatStreamName, true); botCommandHandler(CurrentUser, CurrentPacket.message, CurrentUser.currentMatch.matchChatStreamName, true);
return; return;
} }
// Check the stream that we're sending to even exists // Check the stream that we're sending to even exists
if (!global.StreamsHandler.doesStreamExist(CurrentPacket.target)) return; if (!global.StreamsHandler.doesStreamExist(CurrentPacket.target)) return;
// Write chat message to stream asociated with chat channel // Write chat message to stream asociated with chat channel
global.StreamsHandler.sendToStream(CurrentPacket.target, osuPacketWriter.toBuffer, CurrentUser.uuid); global.StreamsHandler.sendToStream(CurrentPacket.target, osuPacketWriter.toBuffer, CurrentUser.uuid);
if (CurrentPacket.target == "#osu") if (CurrentPacket.target == "#osu")
global.addChatMessage(`${CurrentUser.username}: ${CurrentPacket.message}`); global.addChatMessage(`${CurrentUser.username}: ${CurrentPacket.message}`);
botCommandHandler(CurrentUser, CurrentPacket.message, CurrentPacket.target); botCommandHandler(CurrentUser, CurrentPacket.message, CurrentPacket.target);
return; return;
} }

View file

@ -1,36 +1,36 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
getUserById = require("../util/getUserById.js"); getUserById = require("../util/getUserById.js");
module.exports = function(currentUser, id = 0, sendImmidiate = true) { module.exports = function(currentUser, id = 0, sendImmidiate = true) {
if (id == 3) return; // Ignore Bot if (id == 3) return; // Ignore Bot
// Create new osu packet writer // Create new osu packet writer
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
// Get user's class // Get user's class
const User = getUserById(id); const User = getUserById(id);
if (User == null) return; if (User == null) return;
let UserStatusObject = { let UserStatusObject = {
userId: User.id, userId: User.id,
status: User.actionID, status: User.actionID,
statusText: User.actionText, statusText: User.actionText,
beatmapChecksum: User.beatmapChecksum, beatmapChecksum: User.beatmapChecksum,
currentMods: User.currentMods, currentMods: User.currentMods,
playMode: User.playMode, playMode: User.playMode,
beatmapId: User.beatmapID, beatmapId: User.beatmapID,
rankedScore: User.rankedScore, rankedScore: User.rankedScore,
accuracy: User.accuracy / 100, // Scale of 0 to 1 accuracy: User.accuracy / 100, // Scale of 0 to 1
playCount: User.playCount, playCount: User.playCount,
totalScore: User.totalScore, totalScore: User.totalScore,
rank: User.rank, rank: User.rank,
performance: (User.rankingMode == 0 ? User.pp : 0) performance: (User.rankingMode == 0 ? User.pp : 0)
}; };
osuPacketWriter.HandleOsuUpdate(UserStatusObject); osuPacketWriter.HandleOsuUpdate(UserStatusObject);
// Send data to user's queue // Send data to user's queue
if (sendImmidiate) currentUser.addActionToQueue(osuPacketWriter.toBuffer); if (sendImmidiate) currentUser.addActionToQueue(osuPacketWriter.toBuffer);
else return osuPacketWriter.toBuffer; else return osuPacketWriter.toBuffer;
} }

View file

@ -1,26 +1,27 @@
const osu = require("osu-packet"); const osu = require("osu-packet"),
consoleHelper = require("./consoleHelper.js");
module.exports = function(CurrentUser, MatchID) { module.exports = function(CurrentUser, MatchID) {
const match = global.MultiplayerManager.getMatch(MatchID); const match = global.MultiplayerManager.getMatch(MatchID);
if (match != null) { if (match != null) {
match.isTourneyMatch = true; match.isTourneyMatch = true;
for (let i = 0; i < global.userKeys.length; i++) { for (let i = 0; i < global.userKeys.length; i++) {
if (global.users[global.userKeys[i]].id == CurrentUser.id) { if (global.users[global.userKeys[i]].id == CurrentUser.id) {
match.tourneyClientUsers.push(global.users[global.userKeys[i]]); match.tourneyClientUsers.push(global.users[global.userKeys[i]]);
} }
} }
if (global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) if (global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid))
return global.consoleHelper.printBancho(`Did not add user to channel ${match.matchChatStreamName} because they are already in it`); return consoleHelper.printBancho(`Did not add user to channel ${match.matchChatStreamName} because they are already in it`);
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.ChannelJoinSuccess("#multiplayer"); osuPacketWriter.ChannelJoinSuccess("#multiplayer");
if (!global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) if (!global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid))
global.StreamsHandler.addUserToStream(match.matchChatStreamName, CurrentUser.uuid); global.StreamsHandler.addUserToStream(match.matchChatStreamName, CurrentUser.uuid);
CurrentUser.addActionToQueue(osuPacketWriter.toBuffer); CurrentUser.addActionToQueue(osuPacketWriter.toBuffer);
} }
} }

View file

@ -1,30 +1,31 @@
const osu = require("osu-packet"); const osu = require("osu-packet"),
consoleHelper = require("../../consoleHelper.js");
module.exports = function(CurrentUser, MatchID) { module.exports = function(CurrentUser, MatchID) {
const match = global.MultiplayerManager.getMatch(MatchID); const match = global.MultiplayerManager.getMatch(MatchID);
if (match != null) { if (match != null) {
match.isTourneyMatch = false; match.isTourneyMatch = false;
match.tourneyClientUsers = []; match.tourneyClientUsers = [];
if (global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) if (global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid))
return global.consoleHelper.printBancho(`Did not add user to channel ${match.matchChatStreamName} because they are already in it`); return consoleHelper.printBancho(`Did not add user to channel ${match.matchChatStreamName} because they are already in it`);
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.ChannelRevoked("#multiplayer"); osuPacketWriter.ChannelRevoked("#multiplayer");
if (!global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid)) if (!global.StreamsHandler.isUserInStream(match.matchChatStreamName, CurrentUser.uuid))
global.StreamsHandler.removeUserFromStream(match.matchChatStreamName, CurrentUser.uuid); global.StreamsHandler.removeUserFromStream(match.matchChatStreamName, CurrentUser.uuid);
CurrentUser.addActionToQueue(osuPacketWriter.toBuffer); CurrentUser.addActionToQueue(osuPacketWriter.toBuffer);
} else { } else {
// Still provide feedback just in case // Still provide feedback just in case
// TODO: Check if this has any effect, if not then remove this. // TODO: Check if this has any effect, if not then remove this.
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.ChannelRevoked("#multiplayer"); osuPacketWriter.ChannelRevoked("#multiplayer");
CurrentUser.addActionToQueue(osuPacketWriter.toBuffer); CurrentUser.addActionToQueue(osuPacketWriter.toBuffer);
} }
} }

View file

@ -1,22 +1,22 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
UserPresence = require("./UserPresence.js"), UserPresence = require("./UserPresence.js"),
StatusUpdate = require("./StatusUpdate.js"); StatusUpdate = require("./StatusUpdate.js");
module.exports = function(CurrentUser, MatchID) { module.exports = function(CurrentUser, MatchID) {
const matchData = global.MultiplayerManager.getMatch(MatchID); const matchData = global.MultiplayerManager.getMatch(MatchID);
if (matchData != null) { if (matchData != null) {
const osuPacketWriter = new osu.Bancho.Writer(); const osuPacketWriter = new osu.Bancho.Writer();
osuPacketWriter.MatchUpdate(matchData.createOsuMatchJSON()); osuPacketWriter.MatchUpdate(matchData.createOsuMatchJSON());
// Queue info on all the users in the match to the client // Queue info on all the users in the match to the client
for (let slot in matchData.slots) { for (let slot in matchData.slots) {
CurrentUser.addActionToQueue(UserPresence(CurrentUser, slot.playerId, false)); CurrentUser.addActionToQueue(UserPresence(CurrentUser, slot.playerId, false));
CurrentUser.addActionToQueue(StatusUpdate(CurrentUser, slot.playerId, false)); CurrentUser.addActionToQueue(StatusUpdate(CurrentUser, slot.playerId, false));
} }
// Queue data // Queue data
CurrentUser.addActionToQueue(osuPacketWriter.toBuffer); CurrentUser.addActionToQueue(osuPacketWriter.toBuffer);
} }
} }

View file

@ -1,24 +1,24 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
getUserById = require("../util/getUserById.js"); getUserById = require("../util/getUserById.js");
module.exports = function(currentUser, id = 0, sendImmidiate = true) { module.exports = function(currentUser, id = 0, sendImmidiate = true) {
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
const User = getUserById(id); const User = getUserById(id);
if (User == null) return; if (User == null) return;
osuPacketWriter.UserPresence({ osuPacketWriter.UserPresence({
userId: id, userId: id,
username: User.username, username: User.username,
timezone: 0, timezone: 0,
countryId: User.countryID, countryId: User.countryID,
permissions: 4, permissions: 4,
longitude: User.location[1], longitude: User.location[1],
latitude: User.location[0], latitude: User.location[0],
rank: User.rank rank: User.rank
}); });
if (sendImmidiate) currentUser.addActionToQueue(osuPacketWriter.toBuffer); if (sendImmidiate) currentUser.addActionToQueue(osuPacketWriter.toBuffer);
else return osuPacketWriter.toBuffer; else return osuPacketWriter.toBuffer;
} }

View file

@ -1,16 +1,16 @@
const osu = require("osu-packet"); const osu = require("osu-packet");
module.exports = function(currentUser, sendImmidiate = true) { module.exports = function(currentUser, sendImmidiate = true) {
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
let userIds = []; let userIds = [];
for (let i = 0; i < global.userKeys.length; i++) { for (let i = 0; i < global.userKeys.length; i++) {
userIds.push(global.users[global.userKeys[i]].id); userIds.push(global.users[global.userKeys[i]].id);
} }
osuPacketWriter.UserPresenceBundle(userIds); osuPacketWriter.UserPresenceBundle(userIds);
if (sendImmidiate) currentUser.addActionToQueue(osuPacketWriter.toBuffer); if (sendImmidiate) currentUser.addActionToQueue(osuPacketWriter.toBuffer);
else return osuPacketWriter.toBuffer; else return osuPacketWriter.toBuffer;
} }

View file

@ -1,14 +1,14 @@
const UserPresenceBundle = require("./UserPresenceBundle.js"), const UserPresenceBundle = require("./UserPresenceBundle.js"),
UserPresence = require("./UserPresence.js"), UserPresence = require("./UserPresence.js"),
StatusUpdate = require("./StatusUpdate.js"); StatusUpdate = require("./StatusUpdate.js");
module.exports = function (currentUser, data = [0]) { module.exports = function (currentUser, data = [0]) {
UserPresenceBundle(currentUser); UserPresenceBundle(currentUser);
for (let i1 = 0; i1 < data.length; i1++) { for (let i1 = 0; i1 < data.length; i1++) {
const CurrentUserID = data[i1]; const CurrentUserID = data[i1];
UserPresence(currentUser, CurrentUserID); UserPresence(currentUser, CurrentUserID);
StatusUpdate(currentUser, CurrentUserID); StatusUpdate(currentUser, CurrentUserID);
} }
} }

View file

@ -1,75 +1,75 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
getUserById = require("./util/getUserById.js"); getUserById = require("./util/getUserById.js");
module.exports = { module.exports = {
startSpectatingUser:function(currentUser, spectatedId) { startSpectatingUser:function(currentUser, spectatedId) {
// Get the user this user is trying to spectate // Get the user this user is trying to spectate
const User = getUserById(spectatedId); const User = getUserById(spectatedId);
if (global.StreamsHandler.doesStreamExist(`sp_${User.id}`)) { if (global.StreamsHandler.doesStreamExist(`sp_${User.id}`)) {
// Just add user to stream since it already exists // Just add user to stream since it already exists
global.StreamsHandler.addUserToStream(`sp_${User.id}`, currentUser.uuid); global.StreamsHandler.addUserToStream(`sp_${User.id}`, currentUser.uuid);
} else { } else {
// Stream doesn't exist, create it and add the spectator // Stream doesn't exist, create it and add the spectator
global.StreamsHandler.addStream(`sp_${User.id}`, true, spectatedId); global.StreamsHandler.addStream(`sp_${User.id}`, true, spectatedId);
global.StreamsHandler.addUserToStream(`sp_${User.id}`, currentUser.uuid); global.StreamsHandler.addUserToStream(`sp_${User.id}`, currentUser.uuid);
} }
// We want to do this stuff regardless // We want to do this stuff regardless
// Create a new osu packet writer // Create a new osu packet writer
let osuPacketWriter = new osu.Bancho.Writer; let osuPacketWriter = new osu.Bancho.Writer;
// Set the user requesting to be spectating this user // Set the user requesting to be spectating this user
currentUser.spectating = spectatedId; currentUser.spectating = spectatedId;
// Tell the client of the user being spectated that they are being spectated // Tell the client of the user being spectated that they are being spectated
osuPacketWriter.SpectatorJoined(currentUser.id); osuPacketWriter.SpectatorJoined(currentUser.id);
// Send the packet to the spectated user's queue // Send the packet to the spectated user's queue
User.addActionToQueue(osuPacketWriter.toBuffer); User.addActionToQueue(osuPacketWriter.toBuffer);
// Make a new clear osu packet writer // Make a new clear osu packet writer
osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter = new osu.Bancho.Writer;
// Tell everyone spectating this user that another user has started spectating // Tell everyone spectating this user that another user has started spectating
osuPacketWriter.FellowSpectatorJoined(currentUser.id); osuPacketWriter.FellowSpectatorJoined(currentUser.id);
// Send this packet to all the spectators // Send this packet to all the spectators
global.StreamsHandler.sendToStream(`sp_${User.id}`, osuPacketWriter.toBuffer); global.StreamsHandler.sendToStream(`sp_${User.id}`, osuPacketWriter.toBuffer);
}, },
sendSpectatorFrames(currentUser, data) { sendSpectatorFrames(currentUser, data) {
// Create new osu packet writer // Create new osu packet writer
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
// Data containing the user's actions // Data containing the user's actions
osuPacketWriter.SpectateFrames(data); osuPacketWriter.SpectateFrames(data);
// Send the frames to all the spectators // Send the frames to all the spectators
global.StreamsHandler.sendToStream(`sp_${currentUser.id}`, osuPacketWriter.toBuffer, null); global.StreamsHandler.sendToStream(`sp_${currentUser.id}`, osuPacketWriter.toBuffer, null);
}, },
stopSpectatingUser(currentUser) { stopSpectatingUser(currentUser) {
// Get the user this user is spectating // Get the user this user is spectating
const spectatedUser = getUserById(currentUser.spectating); const spectatedUser = getUserById(currentUser.spectating);
// Create new osu packet writer // Create new osu packet writer
let osuPacketWriter = new osu.Bancho.Writer; let osuPacketWriter = new osu.Bancho.Writer;
// Inform the client being spectated that this user has stopped spectating // Inform the client being spectated that this user has stopped spectating
osuPacketWriter.SpectatorLeft(currentUser.id); osuPacketWriter.SpectatorLeft(currentUser.id);
// Add this packet to the spectated user's queue // Add this packet to the spectated user's queue
spectatedUser.addActionToQueue(osuPacketWriter.toBuffer); spectatedUser.addActionToQueue(osuPacketWriter.toBuffer);
// Remove this user from the spectator stream // Remove this user from the spectator stream
global.StreamsHandler.removeUserFromStream(`sp_${spectatedUser.id}`, currentUser.uuid); global.StreamsHandler.removeUserFromStream(`sp_${spectatedUser.id}`, currentUser.uuid);
// Make a new clear osu packet writer // Make a new clear osu packet writer
osuPacketWriter = new osu.Bancho.Writer; osuPacketWriter = new osu.Bancho.Writer;
// Inform other users spectating that this spectator has left // Inform other users spectating that this spectator has left
osuPacketWriter.FellowSpectatorLeft(currentUser.id); osuPacketWriter.FellowSpectatorLeft(currentUser.id);
// Send this packet to all spectators // Send this packet to all spectators
global.StreamsHandler.sendToStream(`sp_${spectatedUser.id}`, osuPacketWriter.toBuffer); global.StreamsHandler.sendToStream(`sp_${spectatedUser.id}`, osuPacketWriter.toBuffer);
} }
} }

View file

@ -1,135 +1,136 @@
const getUserByToken = require("./util/getUserByToken.js"); const getUserByToken = require("./util/getUserByToken.js"),
consoleHelper = require("../consoleHelper.js");
module.exports = class { module.exports = class {
constructor() { constructor() {
this.avaliableStreams = {}; this.avaliableStreams = {};
this.avaliableStreamKeys = []; this.avaliableStreamKeys = [];
} }
addStream(streamName = "", removeIfEmpty = false, spectatorHostId = null) { addStream(streamName = "", removeIfEmpty = false, spectatorHostId = null) {
// Make sure a stream with the same name doesn't exist already // Make sure a stream with the same name doesn't exist already
if (this.avaliableStreamKeys.includes(streamName)) if (this.avaliableStreamKeys.includes(streamName))
return global.consoleHelper.printBancho(`Did not add stream [${streamName}] A stream with the same name already exists`); return 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 tokens of the users in a given stream streamUsers: [], // An array containing a list of user tokens 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); this.avaliableStreamKeys = Object.keys(this.avaliableStreams);
global.consoleHelper.printBancho(`Added stream [${streamName}]`); 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 = 5000) { 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();
// Loop through all streams // Loop through all streams
for (let i = 0; i < streams.length; i++) { for (let i = 0; i < streams.length; i++) {
// Get the current stream // Get the current stream
const currentStream = global.StreamsHandler.avaliableStreams[streams[i]]; const currentStream = global.StreamsHandler.avaliableStreams[streams[i]];
// Check if the stream should be removed if there are no users in it // Check if the stream should be removed if there are no users in it
// And if the stream has no users in it // And if the stream has no users in it
if (currentStream.removeIfEmpty && currentStream.streamUsers.length == 0) { if (currentStream.removeIfEmpty && currentStream.streamUsers.length == 0) {
global.StreamsHandler.removeStream(streams[i]); global.StreamsHandler.removeStream(streams[i]);
global.consoleHelper.printBancho(`Removed stream [${streams[i]}] There were no users in stream`); consoleHelper.printBancho(`Removed stream [${streams[i]}] There were no users in stream`);
} }
} }
}, interval); }, interval);
global.consoleHelper.printBancho(`BinatoStream is running! Checks running at a ${interval}ms interval`); consoleHelper.printBancho(`BinatoStream is running! Checks running at a ${interval}ms interval`);
} }
sendToStream(streamName, streamData, initUser = null) { sendToStream(streamName, streamData, initUser = null) {
// Make sure the stream we are attempting to send to even exists // Make sure the stream we are attempting to send to even exists
if (!this.doesStreamExist(streamName)) if (!this.doesStreamExist(streamName))
return global.consoleHelper.printBancho(`Did not send to stream [${streamName}] because it does not exist!`); return consoleHelper.printBancho(`Did not send to stream [${streamName}] because it does not exist!`);
// Get the stream to send the data to // Get the stream to send the data to
const currentStream = this.avaliableStreams[streamName]; const currentStream = this.avaliableStreams[streamName];
// Loop through the users in this stream // Loop through the users in this stream
for (let i = 0; i < currentStream.streamUsers.length; i++) { for (let i = 0; i < currentStream.streamUsers.length; i++) {
// Get the user token of the user in the queue // Get the user token of the user in the queue
const currentUserToken = currentStream.streamUsers[i]; const currentUserToken = currentStream.streamUsers[i];
// Make sure we don't send this data back to the user requesting this data to be sent // Make sure we don't send this data back to the user requesting this data to be sent
if (initUser != null && currentUserToken == initUser && (streamName[0] == "#" || streamName.includes("mp_"))) continue; if (initUser != null && currentUserToken == initUser && (streamName[0] == "#" || streamName.includes("mp_"))) continue;
if (currentUserToken == 3) continue; // Skip if user is bot if (currentUserToken == 3) continue; // Skip if user is bot
// Get user object // Get user object
const currentUser = getUserByToken(currentUserToken); const currentUser = getUserByToken(currentUserToken);
// Skip if user is nonexistant // Skip if user is nonexistant
if (currentUser == null) continue; if (currentUser == null) continue;
// Send stream data to user's own queue // Send stream data to user's own queue
currentUser.addActionToQueue(streamData); currentUser.addActionToQueue(streamData);
} }
} }
addUserToStream(streamName, userToken) { addUserToStream(streamName, userToken) {
// Make sure the stream we are attempting to add this user to even exists // Make sure the stream we are attempting to add this user to even exists
if (!this.doesStreamExist(streamName)) if (!this.doesStreamExist(streamName))
return global.consoleHelper.printBancho(`Did not add user to stream [${streamName}] because it does not exist!`); return consoleHelper.printBancho(`Did not add user to stream [${streamName}] because it does not exist!`);
// Make sure the user isn't already in the stream // Make sure the user isn't already in the stream
if (this.avaliableStreams[streamName].streamUsers.includes(userToken)) if (this.avaliableStreams[streamName].streamUsers.includes(userToken))
return global.consoleHelper.printBancho(`Did not add user to stream [${streamName}] because they are already in it!`); return consoleHelper.printBancho(`Did not add user to stream [${streamName}] because they are already in it!`);
// Make sure this isn't an invalid user (userId can't be lower than 1) // Make sure this isn't an invalid user (userId can't be lower than 1)
if (userToken == "" || userToken == null) if (userToken == "" || userToken == null)
return global.consoleHelper.printBancho(`Did not add user to stream [${streamName}] because their token is invalid!`); return consoleHelper.printBancho(`Did not add user to stream [${streamName}] because their token is invalid!`);
// Add user's token to the stream's user list // Add user's token to the stream's user list
this.avaliableStreams[streamName].streamUsers.push(userToken); this.avaliableStreams[streamName].streamUsers.push(userToken);
global.consoleHelper.printBancho(`Added user [${userToken}] to stream ${streamName}`); consoleHelper.printBancho(`Added user [${userToken}] to stream ${streamName}`);
} }
removeUserFromStream(streamName, userToken) { removeUserFromStream(streamName, userToken) {
// Make sure the stream we are attempting to add this user to even exists // Make sure the stream we are attempting to add this user to even exists
if (!this.doesStreamExist(streamName)) if (!this.doesStreamExist(streamName))
return global.consoleHelper.printBancho(`Did not remove user from stream [${streamName}] because it does not exist!`); return consoleHelper.printBancho(`Did not remove user from stream [${streamName}] because it does not exist!`);
// Make sure the user isn't already in the stream // Make sure the user isn't already in the stream
if (!this.avaliableStreams[streamName].streamUsers.includes(userToken)) if (!this.avaliableStreams[streamName].streamUsers.includes(userToken))
return global.consoleHelper.printBancho(`Did not remove user from stream [${streamName}] because they are not in it!`); return 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) // Make sure this isn't an invalid user (userId can't be lower than 1)
if (userToken == "" || userToken == null) if (userToken == "" || userToken == null)
return global.consoleHelper.printBancho(`Did not remove user from stream [${streamName}] because their userId is invalid!`); return 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;
for (let i = 0; i < this.avaliableStreams[streamName].streamUsers.length; i++) { for (let i = 0; i < this.avaliableStreams[streamName].streamUsers.length; i++) {
if (userToken == this.avaliableStreams[streamName].streamUsers[i]) { if (userToken == this.avaliableStreams[streamName].streamUsers[i]) {
userCurrentIndex = i; userCurrentIndex = i;
break; break;
} }
} }
// Remove user from stream's user list // Remove user from stream's user list
this.avaliableStreams[streamName].streamUsers.splice(userCurrentIndex, 1); this.avaliableStreams[streamName].streamUsers.splice(userCurrentIndex, 1);
global.consoleHelper.printBancho(`Removed user [${userToken}] from stream ${streamName}`); consoleHelper.printBancho(`Removed user [${userToken}] from stream ${streamName}`);
} catch (e) { global.consoleHelper.printBancho(`Can't Remove user [${userToken}] from stream ${streamName}`); } } catch (e) { consoleHelper.printBancho(`Can't Remove user [${userToken}] from stream ${streamName}`); }
} }
doesStreamExist(streamName) { doesStreamExist(streamName) {
return this.avaliableStreamKeys.includes(streamName); return this.avaliableStreamKeys.includes(streamName);
} }
getStreams() { getStreams() {
// Return the names of all avaliable streams // Return the names of all avaliable streams
return this.avaliableStreamKeys; return this.avaliableStreamKeys;
} }
isUserInStream(streamName, userToken) { isUserInStream(streamName, userToken) {
if (this.avaliableStreams[streamName].streamUsers.includes(userToken)) return true; if (this.avaliableStreams[streamName].streamUsers.includes(userToken)) return true;
else return false; else return false;
} }
removeStream(streamName) { removeStream(streamName) {
try { try {
delete this.avaliableStreams[streamName]; delete this.avaliableStreams[streamName];
this.avaliableStreamKeys = Object.keys(this.avaliableStreams); this.avaliableStreamKeys = Object.keys(this.avaliableStreams);
} catch (e) { global.consoleHelper.printError(`Was not able to remove stream [${streamName}]`) } } catch (e) { consoleHelper.printError(`Was not able to remove stream [${streamName}]`) }
} }
} }

View file

@ -1,9 +1,9 @@
module.exports = function(s) { module.exports = function(s) {
switch (s) { switch (s) {
case "reconnect": case "reconnect":
return "\u0005\u0000\u0000\u0004\u0000\u0000\u0000<30><30><EFBFBD><EFBFBD>\u0018\u0000\u0000\u0011\u0000\u0000\u0000\u000b\u000fReconnecting..."; return "\u0005\u0000\u0000\u0004\u0000\u0000\u0000<30><30><EFBFBD><EFBFBD>\u0018\u0000\u0000\u0011\u0000\u0000\u0000\u000b\u000fReconnecting...";
default: default:
return Buffer.alloc(0); return Buffer.alloc(0);
} }
} }

View file

@ -1,274 +1,274 @@
const countryCodes = { const countryCodes = {
"LV": 132, "LV": 132,
"AD": 3, "AD": 3,
"LT": 130, "LT": 130,
"KM": 116, "KM": 116,
"QA": 182, "QA": 182,
"VA": 0, "VA": 0,
"PK": 173, "PK": 173,
"KI": 115, "KI": 115,
"SS": 0, "SS": 0,
"KH": 114, "KH": 114,
"NZ": 166, "NZ": 166,
"TO": 215, "TO": 215,
"KZ": 122, "KZ": 122,
"GA": 76, "GA": 76,
"BW": 35, "BW": 35,
"AX": 247, "AX": 247,
"GE": 79, "GE": 79,
"UA": 222, "UA": 222,
"CR": 50, "CR": 50,
"AE": 0, "AE": 0,
"NE": 157, "NE": 157,
"ZA": 240, "ZA": 240,
"SK": 196, "SK": 196,
"BV": 34, "BV": 34,
"SH": 0, "SH": 0,
"PT": 179, "PT": 179,
"SC": 189, "SC": 189,
"CO": 49, "CO": 49,
"GP": 86, "GP": 86,
"GY": 93, "GY": 93,
"CM": 47, "CM": 47,
"TJ": 211, "TJ": 211,
"AF": 5, "AF": 5,
"IE": 101, "IE": 101,
"AL": 8, "AL": 8,
"BG": 24, "BG": 24,
"JO": 110, "JO": 110,
"MU": 149, "MU": 149,
"PM": 0, "PM": 0,
"LA": 0, "LA": 0,
"IO": 104, "IO": 104,
"KY": 121, "KY": 121,
"SA": 187, "SA": 187,
"KN": 0, "KN": 0,
"OM": 167, "OM": 167,
"CY": 54, "CY": 54,
"BQ": 0, "BQ": 0,
"BT": 33, "BT": 33,
"WS": 236, "WS": 236,
"ES": 67, "ES": 67,
"LR": 128, "LR": 128,
"RW": 186, "RW": 186,
"AQ": 12, "AQ": 12,
"PW": 180, "PW": 180,
"JE": 250, "JE": 250,
"TN": 214, "TN": 214,
"ZW": 243, "ZW": 243,
"JP": 111, "JP": 111,
"BB": 20, "BB": 20,
"VN": 233, "VN": 233,
"HN": 96, "HN": 96,
"KP": 0, "KP": 0,
"WF": 235, "WF": 235,
"EC": 62, "EC": 62,
"HU": 99, "HU": 99,
"GF": 80, "GF": 80,
"GQ": 87, "GQ": 87,
"TW": 220, "TW": 220,
"MC": 135, "MC": 135,
"BE": 22, "BE": 22,
"PN": 176, "PN": 176,
"SZ": 205, "SZ": 205,
"CZ": 55, "CZ": 55,
"LY": 0, "LY": 0,
"IN": 103, "IN": 103,
"FM": 0, "FM": 0,
"PY": 181, "PY": 181,
"PH": 172, "PH": 172,
"MN": 142, "MN": 142,
"GG": 248, "GG": 248,
"CC": 39, "CC": 39,
"ME": 242, "ME": 242,
"DO": 60, "DO": 60,
"KR": 0, "KR": 0,
"PL": 174, "PL": 174,
"MT": 148, "MT": 148,
"MM": 141, "MM": 141,
"AW": 17, "AW": 17,
"MV": 150, "MV": 150,
"BD": 21, "BD": 21,
"NR": 164, "NR": 164,
"AT": 15, "AT": 15,
"GW": 92, "GW": 92,
"FR": 74, "FR": 74,
"LI": 126, "LI": 126,
"CF": 41, "CF": 41,
"DZ": 61, "DZ": 61,
"MA": 134, "MA": 134,
"VG": 0, "VG": 0,
"NC": 156, "NC": 156,
"IQ": 105, "IQ": 105,
"BN": 0, "BN": 0,
"BF": 23, "BF": 23,
"BO": 30, "BO": 30,
"GB": 77, "GB": 77,
"CU": 51, "CU": 51,
"LU": 131, "LU": 131,
"YT": 238, "YT": 238,
"NO": 162, "NO": 162,
"SM": 198, "SM": 198,
"GL": 83, "GL": 83,
"IS": 107, "IS": 107,
"AO": 11, "AO": 11,
"MH": 138, "MH": 138,
"SE": 191, "SE": 191,
"ZM": 241, "ZM": 241,
"FJ": 70, "FJ": 70,
"SL": 197, "SL": 197,
"CH": 43, "CH": 43,
"RU": 0, "RU": 0,
"CW": 0, "CW": 0,
"CX": 53, "CX": 53,
"TF": 208, "TF": 208,
"NL": 161, "NL": 161,
"AU": 16, "AU": 16,
"FI": 69, "FI": 69,
"MS": 147, "MS": 147,
"GH": 81, "GH": 81,
"BY": 36, "BY": 36,
"IL": 102, "IL": 102,
"VC": 0, "VC": 0,
"NG": 159, "NG": 159,
"HT": 98, "HT": 98,
"LS": 129, "LS": 129,
"MR": 146, "MR": 146,
"YE": 237, "YE": 237,
"MP": 144, "MP": 144,
"SX": 0, "SX": 0,
"RE": 183, "RE": 183,
"RO": 184, "RO": 184,
"NP": 163, "NP": 163,
"CG": 0, "CG": 0,
"FO": 73, "FO": 73,
"CI": 0, "CI": 0,
"TH": 210, "TH": 210,
"HK": 94, "HK": 94,
"TK": 212, "TK": 212,
"XK": 0, "XK": 0,
"DM": 59, "DM": 59,
"LC": 0, "LC": 0,
"ID": 100, "ID": 100,
"MG": 137, "MG": 137,
"JM": 109, "JM": 109,
"IT": 108, "IT": 108,
"CA": 38, "CA": 38,
"TZ": 221, "TZ": 221,
"GI": 82, "GI": 82,
"KG": 113, "KG": 113,
"NU": 165, "NU": 165,
"TV": 219, "TV": 219,
"LB": 124, "LB": 124,
"SY": 0, "SY": 0,
"PR": 177, "PR": 177,
"NI": 160, "NI": 160,
"KE": 112, "KE": 112,
"MO": 0, "MO": 0,
"SR": 201, "SR": 201,
"VI": 0, "VI": 0,
"SV": 203, "SV": 203,
"HM": 0, "HM": 0,
"CD": 0, "CD": 0,
"BI": 26, "BI": 26,
"BM": 28, "BM": 28,
"MW": 151, "MW": 151,
"TM": 213, "TM": 213,
"GT": 90, "GT": 90,
"AG": 0, "AG": 0,
"UM": 0, "UM": 0,
"US": 225, "US": 225,
"AR": 13, "AR": 13,
"DJ": 57, "DJ": 57,
"KW": 120, "KW": 120,
"MY": 153, "MY": 153,
"FK": 71, "FK": 71,
"EG": 64, "EG": 64,
"BA": 0, "BA": 0,
"CN": 48, "CN": 48,
"GN": 85, "GN": 85,
"PS": 178, "PS": 178,
"SO": 200, "SO": 200,
"IM": 249, "IM": 249,
"GS": 0, "GS": 0,
"BR": 31, "BR": 31,
"GM": 84, "GM": 84,
"PF": 170, "PF": 170,
"PA": 168, "PA": 168,
"PG": 171, "PG": 171,
"BH": 25, "BH": 25,
"TG": 209, "TG": 209,
"GU": 91, "GU": 91,
"CK": 45, "CK": 45,
"MF": 252, "MF": 252,
"VE": 230, "VE": 230,
"CL": 46, "CL": 46,
"TR": 217, "TR": 217,
"UG": 223, "UG": 223,
"GD": 78, "GD": 78,
"TT": 218, "TT": 218,
"TL": 0, "TL": 0,
"MD": 0, "MD": 0,
"MK": 0, "MK": 0,
"ST": 202, "ST": 202,
"CV": 52, "CV": 52,
"MQ": 145, "MQ": 145,
"GR": 88, "GR": 88,
"HR": 97, "HR": 97,
"BZ": 37, "BZ": 37,
"UZ": 227, "UZ": 227,
"DK": 58, "DK": 58,
"SN": 199, "SN": 199,
"ET": 68, "ET": 68,
"VU": 234, "VU": 234,
"ER": 66, "ER": 66,
"BJ": 27, "BJ": 27,
"LK": 127, "LK": 127,
"NA": 155, "NA": 155,
"AS": 14, "AS": 14,
"SG": 192, "SG": 192,
"PE": 169, "PE": 169,
"IR": 0, "IR": 0,
"MX": 152, "MX": 152,
"TD": 207, "TD": 207,
"AZ": 18, "AZ": 18,
"AM": 9, "AM": 9,
"BL": 0, "BL": 0,
"SJ": 195, "SJ": 195,
"SB": 188, "SB": 188,
"NF": 158, "NF": 158,
"RS": 239, "RS": 239,
"DE": 56, "DE": 56,
"EH": 65, "EH": 65,
"EE": 63, "EE": 63,
"SD": 190, "SD": 190,
"ML": 140, "ML": 140,
"TC": 206, "TC": 206,
"MZ": 154, "MZ": 154,
"BS": 32, "BS": 32,
"UY": 226, "UY": 226,
"SI": 194, "SI": 194,
"AI": 7 "AI": 7
} }
const countryCodeKeys = Object.keys(countryCodes); const countryCodeKeys = Object.keys(countryCodes);
module.exports = { module.exports = {
getCountryID:function(code = "") { getCountryID:function(code = "") {
// Get id of a country from a 2 char code // Get id of a country from a 2 char code
code = code.toUpperCase(); code = code.toUpperCase();
if (countryCodes[code] != null) return countryCodes[code]; if (countryCodes[code] != null) return countryCodes[code];
else return 0; else return 0;
}, },
getCountryLetters:function(code) { getCountryLetters:function(code) {
// Get country char code from id // Get country char code from id
for (var i = 0; i < countryCodes.length; i++) { for (var i = 0; i < countryCodes.length; i++) {
const countryId = countryCodes[countryCodeKeys[i]]; const countryId = countryCodes[countryCodeKeys[i]];
if (countryId === code) return countryId; if (countryId === code) return countryId;
} }
return "XX"; return "XX";
} }
} }
module.exports.countryCodes = countryCodes; module.exports.countryCodes = countryCodes;

View file

@ -1,158 +1,160 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
User = require("./User.js"), User = require("./User.js"),
uuid = require("./util/shortUUID.js"), uuid = require("./util/shortUUID.js"),
ahttp = require("./util/AsyncHttpRequest.js"), ahttp = require("./util/AsyncHttpRequest.js"),
RequestType = require("./util/RequestType.json"), RequestType = require("./util/RequestType.json"),
consoleHelper = require("../consoleHelper.js"),
getUserByUsername = require("./util/getUserByUsername.js"),
getUserByToken = require("./util/getUserByToken.js"), // Packets
countryHelper = require("./countryHelper.js"), getUserByUsername = require("./util/getUserByUsername.js"),
loginHelper = require("./loginHelper.js"), getUserByToken = require("./util/getUserByToken.js"),
UserPresenceBundle = require("./Packets/UserPresenceBundle.js"), countryHelper = require("./countryHelper.js"),
UserPresence = require("./Packets/UserPresence.js"), loginHelper = require("./loginHelper.js"),
StatusUpdate = require("./Packets/StatusUpdate.js"); UserPresenceBundle = require("./Packets/UserPresenceBundle.js"),
UserPresence = require("./Packets/UserPresence.js"),
StatusUpdate = require("./Packets/StatusUpdate.js");
module.exports = async function(req, res, loginInfo) { module.exports = async function(req, res, loginInfo) {
// Get time at the start of login // Get time at the start of login
const loginStartTime = new Date().getTime(), const loginStartTime = Date.now(),
isTourneyClient = loginInfo.osuversion.includes("tourney"); isTourneyClient = loginInfo.osuversion.includes("tourney");
// Check login // Check login
const loginCheck = await loginHelper.checkLogin(loginInfo); const loginCheck = await loginHelper.checkLogin(loginInfo);
if (loginCheck != null) { if (loginCheck != null) {
res.writeHead(200, loginCheck[1]); res.writeHead(200, loginCheck[1]);
return res.end(loginCheck[0]); return res.end(loginCheck[0]);
} }
// Get users IP for getting location // Get users IP for getting location
// Get cloudflare requestee IP first // Get cloudflare requestee IP first
let requestIP = req.get("cf-connecting-ip"); let requestIP = req.get("cf-connecting-ip");
// Get IP of requestee since we are probably behind a reverse proxy // Get IP of requestee since we are probably behind a reverse proxy
if (requestIP == null) if (requestIP == null)
requestIP = req.get("X-Real-IP"); requestIP = req.get("X-Real-IP");
// Just get the requestee IP (we are not behind a reverse proxy) // Just get the requestee IP (we are not behind a reverse proxy)
if (requestIP == null) if (requestIP == null)
requestIP = req.remote_addr; requestIP = req.remote_addr;
// Make sure requestIP is never null // Make sure requestIP is never null
if (requestIP == null) if (requestIP == null)
requestIP = ""; requestIP = "";
let userLocationData = [], userLocation; let userLocationData = [], userLocation;
// Check if it is a local or null IP // Check if it is a local or null IP
if (requestIP.includes("192.168.") || requestIP.includes("127.0.") || requestIP == "") { if (requestIP.includes("192.168.") || requestIP.includes("127.0.") || requestIP == "") {
// Set location to null island // Set location to null island
userLocationData.country = "XX"; userLocationData.country = "XX";
userLocation = [0, 0]; userLocation = [0, 0];
} else { } else {
// Get user's location using zxq // Get user's location using zxq
userLocationData = await ahttp(`http://ip.zxq.co/${requestIP}`, RequestType.JSON); userLocationData = await ahttp(`http://ip.zxq.co/${requestIP}`, RequestType.JSON);
userLocation = userLocationData.loc.split(","); userLocation = userLocationData.loc.split(",");
} }
// Get information about the user from the database // Get information about the user from the database
const userDB = await global.DatabaseHelper.query(`SELECT id FROM users_info WHERE username = "${loginInfo.username}" LIMIT 1`); const userDB = await global.DatabaseHelper.query(`SELECT id FROM users_info WHERE username = "${loginInfo.username}" LIMIT 1`);
// Create a token for the client // Create a token for the client
const newClientToken = uuid(); const newClientToken = uuid();
// Make sure user is not already connected, kick off if so. // Make sure user is not already connected, kick off if so.
const checkForPreexistingUser = getUserByUsername(loginInfo.username); const checkForPreexistingUser = getUserByUsername(loginInfo.username);
if (checkForPreexistingUser != null && !isTourneyClient) { if (checkForPreexistingUser != null && !isTourneyClient) {
for (let i = 0; i < global.userKeys.length; i++) { for (let i = 0; i < global.userKeys.length; i++) {
const user = global.users[global.userKeys[i]]; const user = global.users[global.userKeys[i]];
// Make sure they are not a tourney user // Make sure they are not a tourney user
if (!user.isTourneyUser && user.uuid != newClientToken) { if (!user.isTourneyUser && user.uuid != newClientToken) {
global.removeUser(user); global.removeUser(user);
} }
} }
} }
// Create user object // Create user object
global.addUser(newClientToken, new User(userDB.id, loginInfo.username, newClientToken, new Date().getTime(), isTourneyClient)); global.addUser(newClientToken, new User(userDB.id, loginInfo.username, newClientToken, Date.now(), isTourneyClient));
// Retreive the newly created user // Retreive the newly created user
const NewUser = getUserByToken(newClientToken); const NewUser = getUserByToken(newClientToken);
// Get user's data from the database // Get user's data from the database
NewUser.getNewUserInformationFromDatabase(); NewUser.getNewUserInformationFromDatabase();
try { try {
// Save the user's location to their class for later use // Save the user's location to their class for later use
NewUser.location[0] = parseFloat(userLocation[0]); NewUser.location[0] = parseFloat(userLocation[0]);
NewUser.location[1] = parseFloat(userLocation[1]); NewUser.location[1] = parseFloat(userLocation[1]);
// Save the country id for the same reason as above // Save the country id for the same reason as above
NewUser.countryID = countryHelper.getCountryID(userLocationData.country); NewUser.countryID = countryHelper.getCountryID(userLocationData.country);
// We're ready to start putting together a login packet // We're ready to start putting together a login packet
// Create an osu! Packet writer // Create an osu! Packet writer
let osuPacketWriter = new osu.Bancho.Writer; let osuPacketWriter = new osu.Bancho.Writer;
// The reply id is the user's id in any other case than an error in which case negative numbers are used // The reply id is the user's id in any other case than an error in which case negative numbers are used
osuPacketWriter.LoginReply(NewUser.id); osuPacketWriter.LoginReply(NewUser.id);
// Current bancho protocol version. Defined in Binato.js // Current bancho protocol version. Defined in Binato.js
osuPacketWriter.ProtocolNegotiation(global.protocolVersion); osuPacketWriter.ProtocolNegotiation(global.protocolVersion);
// Permission level 4 is osu!supporter // Permission level 4 is osu!supporter
osuPacketWriter.LoginPermissions(4); osuPacketWriter.LoginPermissions(4);
// After sending the user their friends list send them the online users // After sending the user their friends list send them the online users
UserPresenceBundle(NewUser); UserPresenceBundle(NewUser);
// Set title screen image // Set title screen image
//osuPacketWriter.TitleUpdate("http://puu.sh/jh7t7/20c04029ad.png|https://osu.ppy.sh/news/123912240253"); //osuPacketWriter.TitleUpdate("http://puu.sh/jh7t7/20c04029ad.png|https://osu.ppy.sh/news/123912240253");
// Add user panel data packets // Add user panel data packets
UserPresence(NewUser, NewUser.id); UserPresence(NewUser, NewUser.id);
StatusUpdate(NewUser, NewUser.id); StatusUpdate(NewUser, NewUser.id);
// peppy pls, why // peppy pls, why
osuPacketWriter.ChannelListingComplete(); osuPacketWriter.ChannelListingComplete();
// Add user to chat channels // Add user to chat channels
osuPacketWriter.ChannelJoinSuccess("#osu"); osuPacketWriter.ChannelJoinSuccess("#osu");
if (!global.StreamsHandler.isUserInStream("#osu", NewUser.uuid)) if (!global.StreamsHandler.isUserInStream("#osu", NewUser.uuid))
global.StreamsHandler.addUserToStream("#osu", NewUser.uuid); global.StreamsHandler.addUserToStream("#osu", NewUser.uuid);
osuPacketWriter.ChannelJoinSuccess("#userlog"); osuPacketWriter.ChannelJoinSuccess("#userlog");
if (!global.StreamsHandler.isUserInStream("#userlog", NewUser.uuid)) if (!global.StreamsHandler.isUserInStream("#userlog", NewUser.uuid))
global.StreamsHandler.addUserToStream("#userlog", NewUser.uuid); global.StreamsHandler.addUserToStream("#userlog", NewUser.uuid);
// List all channels out to the client // List all channels out to the client
for (let i = 0; i < global.channels.length; i++) { for (let i = 0; i < global.channels.length; i++) {
osuPacketWriter.ChannelAvailable({ osuPacketWriter.ChannelAvailable({
channelName: global.channels[i].channelName, channelName: global.channels[i].channelName,
channelTopic: global.channels[i].channelTopic, channelTopic: global.channels[i].channelTopic,
channelUserCount: global.channels[i].channelUserCount channelUserCount: global.channels[i].channelUserCount
}); });
} }
// Construct user's friends list // Construct user's friends list
const userFriends = await global.DatabaseHelper.query(`SELECT friendsWith FROM friends WHERE user = ${NewUser.id}`); const userFriends = await global.DatabaseHelper.query(`SELECT friendsWith FROM friends WHERE user = ${NewUser.id}`);
let friendsArray = []; let friendsArray = [];
for (let i = 0; i < userFriends.length; i++) { for (let i = 0; i < userFriends.length; i++) {
friendsArray.push(userFriends[i].friendsWith); friendsArray.push(userFriends[i].friendsWith);
} }
// Send user's friends list // Send user's friends list
osuPacketWriter.FriendsList(friendsArray); osuPacketWriter.FriendsList(friendsArray);
osuPacketWriter.Announce(`Welcome back ${loginInfo.username}!`); osuPacketWriter.Announce(`Welcome back ${loginInfo.username}!`);
// Complete login // Complete login
res.writeHead(200, { res.writeHead(200, {
"cho-token": NewUser.uuid, "cho-token": NewUser.uuid,
"cho-protocol": global.protocolVersion, "cho-protocol": global.protocolVersion,
"Connection": "keep-alive", "Connection": "keep-alive",
"Keep-Alive": "timeout=5, max=100", "Keep-Alive": "timeout=5, max=100",
"Content-Type": "text/html; charset=UTF-8" "Content-Type": "text/html; charset=UTF-8"
}); });
res.end(osuPacketWriter.toBuffer, () => { res.end(osuPacketWriter.toBuffer, () => {
global.consoleHelper.printBancho(`User login finished, took ${new Date().getTime() - loginStartTime}ms. [User: ${loginInfo.username}]`); consoleHelper.printBancho(`User login finished, took ${Date.now() - loginStartTime}ms. [User: ${loginInfo.username}]`);
}); });
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
} }

View file

@ -1,59 +1,59 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
aes256 = require("aes256"), aes256 = require("aes256"),
config = require("../config.json"); config = require("../config.json");
module.exports = { module.exports = {
checkLogin:async function(loginInfo) { checkLogin:async function(loginInfo) {
// Check if there is any login information provided // Check if there is any login information provided
if (loginInfo == null) return incorrectLoginResponse(); if (loginInfo == null) return incorrectLoginResponse();
const userDBData = await global.DatabaseHelper.query(`SELECT * FROM users_info WHERE username = "${loginInfo.username}" LIMIT 1`); const userDBData = await global.DatabaseHelper.query(`SELECT * FROM users_info WHERE username = "${loginInfo.username}" LIMIT 1`);
// Make sure a user was found in the database // Make sure a user was found in the database
if (Object.keys(userDBData).length < 1) return incorrectLoginResponse(); if (Object.keys(userDBData).length < 1) return incorrectLoginResponse();
// Make sure the username is the same as the login info // Make sure the username is the same as the login info
if (userDBData.username !== loginInfo.username) return incorrectLoginResponse(); if (userDBData.username !== loginInfo.username) return incorrectLoginResponse();
// If the user has an old md5 password // If the user has an old md5 password
if (userDBData.has_old_password == 1) { if (userDBData.has_old_password == 1) {
// Make sure the password is the same as the login info // Make sure the password is the same as the login info
if (userDBData.password !== loginInfo.password) return incorrectLoginResponse(); if (userDBData.password !== loginInfo.password) return incorrectLoginResponse();
return requiredPWChangeResponse(); return requiredPWChangeResponse();
} else { } else {
if (aes256.decrypt(config.databaseKey, userDBData.password) !== loginInfo.password) return incorrectLoginResponse(); if (aes256.decrypt(config.databaseKey, userDBData.password) !== loginInfo.password) return incorrectLoginResponse();
} }
return null; return null;
} }
} }
function incorrectLoginResponse() { function incorrectLoginResponse() {
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.LoginReply(-1); osuPacketWriter.LoginReply(-1);
return [ return [
osuPacketWriter.toBuffer, osuPacketWriter.toBuffer,
{ {
'cho-token': 'No', 'cho-token': 'No',
'cho-protocol': global.protocolVersion, 'cho-protocol': global.protocolVersion,
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Keep-Alive': 'timeout=5, max=100', 'Keep-Alive': 'timeout=5, max=100',
'Content-Type': 'text/html; charset=UTF-8' 'Content-Type': 'text/html; charset=UTF-8'
} }
]; ];
} }
function requiredPWChangeResponse() { function requiredPWChangeResponse() {
const osuPacketWriter = new osu.Bancho.Writer; const osuPacketWriter = new osu.Bancho.Writer;
osuPacketWriter.Announce("As part of migration to a new password system you are required to change your password. Please login on the website and change your password."); osuPacketWriter.Announce("As part of migration to a new password system you are required to change your password. Please login on the website and change your password.");
osuPacketWriter.LoginReply(-1); osuPacketWriter.LoginReply(-1);
return [ return [
osuPacketWriter.toBuffer, osuPacketWriter.toBuffer,
{ {
'cho-token': 'No', 'cho-token': 'No',
'cho-protocol': global.protocolVersion, 'cho-protocol': global.protocolVersion,
'Connection': 'keep-alive', 'Connection': 'keep-alive',
'Keep-Alive': 'timeout=5, max=100', 'Keep-Alive': 'timeout=5, max=100',
'Content-Type': 'text/html; charset=UTF-8' 'Content-Type': 'text/html; charset=UTF-8'
} }
]; ];
} }

View file

@ -1,111 +1,111 @@
module.exports = { module.exports = {
"client_changeAction":0, "client_changeAction":0,
"client_sendPublicMessage":1, "client_sendPublicMessage":1,
"client_logout":2, "client_logout":2,
"client_requestStatusUpdate":3, "client_requestStatusUpdate":3,
"client_pong":4, "client_pong":4,
"server_userID":5, "server_userID":5,
"server_commandError":6, "server_commandError":6,
"server_sendMessage":7, "server_sendMessage":7,
"server_ping":8, "server_ping":8,
"server_handleIRCUsernameChange":9, "server_handleIRCUsernameChange":9,
"server_handleIRCQuit":10, "server_handleIRCQuit":10,
"server_userStats":11, "server_userStats":11,
"server_userLogout":12, "server_userLogout":12,
"server_spectatorJoined":13, "server_spectatorJoined":13,
"server_spectatorLeft":14, "server_spectatorLeft":14,
"server_spectateFrames":15, "server_spectateFrames":15,
"client_startSpectating":16, "client_startSpectating":16,
"client_stopSpectating":17, "client_stopSpectating":17,
"client_spectateFrames":18, "client_spectateFrames":18,
"server_versionUpdate":19, "server_versionUpdate":19,
"client_errorReport":20, "client_errorReport":20,
"client_cantSpectate":21, "client_cantSpectate":21,
"server_spectatorCantSpectate":22, "server_spectatorCantSpectate":22,
"server_getAttention":23, "server_getAttention":23,
"server_notification":24, "server_notification":24,
"client_sendPrivateMessage":25, "client_sendPrivateMessage":25,
"server_updateMatch":26, "server_updateMatch":26,
"server_newMatch":27, "server_newMatch":27,
"server_disposeMatch":28, "server_disposeMatch":28,
"client_partLobby":29, "client_partLobby":29,
"client_joinLobby":30, "client_joinLobby":30,
"client_createMatch":31, "client_createMatch":31,
"client_joinMatch":32, "client_joinMatch":32,
"client_partMatch":33, "client_partMatch":33,
"server_lobbyJoin_obsolete":34, "server_lobbyJoin_obsolete":34,
"server_lobbyPart_obsolete":35, "server_lobbyPart_obsolete":35,
"server_matchJoinSuccess":36, "server_matchJoinSuccess":36,
"server_matchJoinFail":37, "server_matchJoinFail":37,
"client_matchChangeSlot":38, "client_matchChangeSlot":38,
"client_matchReady":39, "client_matchReady":39,
"client_matchLock":40, "client_matchLock":40,
"client_matchChangeSettings":41, "client_matchChangeSettings":41,
"server_fellowSpectatorJoined":42, "server_fellowSpectatorJoined":42,
"server_fellowSpectatorLeft":43, "server_fellowSpectatorLeft":43,
"client_matchStart":44, "client_matchStart":44,
"AllPlayersLoaded":45, "AllPlayersLoaded":45,
"server_matchStart":46, "server_matchStart":46,
"client_matchScoreUpdate":47, "client_matchScoreUpdate":47,
"server_matchScoreUpdate":48, "server_matchScoreUpdate":48,
"client_matchComplete":49, "client_matchComplete":49,
"server_matchTransferHost":50, "server_matchTransferHost":50,
"client_matchChangeMods":51, "client_matchChangeMods":51,
"client_matchLoadComplete":52, "client_matchLoadComplete":52,
"server_matchAllPlayersLoaded":53, "server_matchAllPlayersLoaded":53,
"client_matchNoBeatmap":54, "client_matchNoBeatmap":54,
"client_matchNotReady":55, "client_matchNotReady":55,
"client_matchFailed":56, "client_matchFailed":56,
"server_matchComplete":58, "server_matchComplete":58,
"client_matchHasBeatmap":59, "client_matchHasBeatmap":59,
"client_matchSkipRequest":60, "client_matchSkipRequest":60,
"server_matchSkip":61, "server_matchSkip":61,
"server_unauthorised":62, "server_unauthorised":62,
"client_channelJoin":63, "client_channelJoin":63,
"server_channelJoinSuccess":64, "server_channelJoinSuccess":64,
"server_channelInfo":65, "server_channelInfo":65,
"server_channelKicked":66, "server_channelKicked":66,
"server_channelAvailableAutojoin":67, "server_channelAvailableAutojoin":67,
"client_beatmapInfoRequest":68, "client_beatmapInfoRequest":68,
"server_beatmapInfoReply":69, "server_beatmapInfoReply":69,
"client_matchTransferHost":70, "client_matchTransferHost":70,
"server_supporterGMT":71, "server_supporterGMT":71,
"server_friendsList":72, "server_friendsList":72,
"client_friendAdd":73, "client_friendAdd":73,
"client_friendRemove":74, "client_friendRemove":74,
"server_protocolVersion":75, "server_protocolVersion":75,
"server_mainMenuIcon":76, "server_mainMenuIcon":76,
"client_matchChangeTeam":77, "client_matchChangeTeam":77,
"client_channelPart":78, "client_channelPart":78,
"client_receiveUpdates":79, "client_receiveUpdates":79,
"server_topBotnet":80, "server_topBotnet":80,
"server_matchPlayerSkipped":81, "server_matchPlayerSkipped":81,
"client_setAwayMessage":82, "client_setAwayMessage":82,
"server_userPanel":83, "server_userPanel":83,
"IRC_only":84, "IRC_only":84,
"client_userStatsRequest":85, "client_userStatsRequest":85,
"server_restart":86, "server_restart":86,
"client_invite":87, "client_invite":87,
"server_invite":88, "server_invite":88,
"server_channelInfoEnd":89, "server_channelInfoEnd":89,
"client_matchChangePassword":90, "client_matchChangePassword":90,
"server_matchChangePassword":91, "server_matchChangePassword":91,
"server_silenceEnd":92, "server_silenceEnd":92,
"client_specialMatchInfoRequest":93, "client_specialMatchInfoRequest":93,
"server_userSilenced":94, "server_userSilenced":94,
"server_userPresenceSingle":95, "server_userPresenceSingle":95,
"server_userPresenceBundle":96, "server_userPresenceBundle":96,
"client_userPresenceRequest":97, "client_userPresenceRequest":97,
"client_userPresenceRequestAll":98, "client_userPresenceRequestAll":98,
"client_userToggleBlockNonFriendPM":99, "client_userToggleBlockNonFriendPM":99,
"server_userPMBlocked":100, "server_userPMBlocked":100,
"server_targetIsSilenced":101, "server_targetIsSilenced":101,
"server_versionUpdateForced":102, "server_versionUpdateForced":102,
"server_switchServer":103, "server_switchServer":103,
"server_accountRestricted":104, "server_accountRestricted":104,
"server_jumpscare":105, "server_jumpscare":105,
"client_matchAbort":106, "client_matchAbort":106,
"server_switchTourneyServer":107, "server_switchTourneyServer":107,
"client_specialJoinMatchChannel":108, "client_specialJoinMatchChannel":108,
"client_specialLeaveMatchChannel":109 "client_specialLeaveMatchChannel":109
} }

View file

@ -1,34 +1,35 @@
const osu = require("osu-packet"), const osu = require("osu-packet"),
fs = require("fs"), fs = require("fs"),
packetIDs = require("./packetIDs.js"), consoleHelper = require("../consoleHelper.js"),
loginHandler = require("./loginHandler.js"), packetIDs = require("./packetIDs.js"),
parseUserData = require("./util/parseUserData.js"), loginHandler = require("./loginHandler.js"),
User = require("./User.js"), parseUserData = require("./util/parseUserData.js"),
getUserFromToken = require("./util/getUserByToken.js"), User = require("./User.js"),
bakedResponses = require("./bakedResponses.js"), getUserFromToken = require("./util/getUserByToken.js"),
Streams = require("./Streams.js"), bakedResponses = require("./bakedResponses.js"),
DatabaseHelperClass = require("./DatabaseHelper.js"), Streams = require("./Streams.js"),
config = require("../config.json"); DatabaseHelperClass = require("./DatabaseHelper.js"),
config = require("../config.json");
global.users = {}; global.users = {};
global.userKeys = Object.keys(global.users); global.userKeys = Object.keys(global.users);
global.addUser = function(uuid, userToAdd) { global.addUser = function(uuid, userToAdd) {
global.users[uuid] = userToAdd; global.users[uuid] = userToAdd;
global.refreshUserKeys(); global.refreshUserKeys();
} }
global.removeUser = function(userToRemove) { global.removeUser = function(userToRemove) {
delete userToRemove; delete userToRemove;
global.refreshUserKeys(); global.refreshUserKeys();
} }
global.refreshUserKeys = function() { global.refreshUserKeys = function() {
global.userKeys = Object.keys(global.users); global.userKeys = Object.keys(global.users);
} }
// Add the bot user // Add the bot user
global.addUser("bot", new User(3, "SillyBot", "bot", new Date().getTime())); global.addUser("bot", new User(3, "SillyBot", "bot", Date.now()));
// Set the bot's position on the map // Set the bot's position on the map
global.users["bot"].location[0] = 50; global.users["bot"].location[0] = 50;
global.users["bot"].location[1] = -32; global.users["bot"].location[1] = -32;
@ -40,25 +41,25 @@ global.DatabaseHelper = new DatabaseHelperClass(config.databaseAddress, config.d
// TODO: Some way of informing bancho that a user has set a score so details can be pulled down quickly // TODO: Some way of informing bancho that a user has set a score so details can be pulled down quickly
// Possible solution, TCP socket between the score submit server and bancho? redis? (score submit is on a different server, redis probably wouldn't work) // Possible solution, TCP socket between the score submit server and bancho? redis? (score submit is on a different server, redis probably wouldn't work)
setInterval(() => { setInterval(() => {
for (let i = 0; i < global.userKeys.length; i++) { for (let i = 0; i < global.userKeys.length; i++) {
const User = global.users[global.userKeys[i]]; const User = global.users[global.userKeys[i]];
if (User.id == 3) continue; // Ignore the bot if (User.id == 3) continue; // Ignore the bot
// Bot: :( // Bot: :(
User.getNewUserInformationFromDatabase(); User.getNewUserInformationFromDatabase();
} }
}, 10000); }, 10000);
// An array containing the last 15 messages in chat // An array containing the last 15 messages in chat
// TODO: Bother making this // TODO: Bother making this
global.chatHistory = []; global.chatHistory = [];
global.addChatMessage = function(msg) { global.addChatMessage = function(msg) {
if (global.chatHistory.length == 15) { if (global.chatHistory.length == 15) {
global.chatHistory.splice(0, 1); global.chatHistory.splice(0, 1);
global.chatHistory.push(msg); global.chatHistory.push(msg);
} else { } else {
global.chatHistory.push(msg); global.chatHistory.push(msg);
} }
} }
global.StreamsHandler = new Streams(); global.StreamsHandler = new Streams();
@ -66,16 +67,16 @@ global.StreamsHandler = new Streams();
// An array containing all chat channels // An array containing all chat channels
// TODO: Send user chat channels and not have osu! crash // TODO: Send user chat channels and not have osu! crash
global.channels = [ global.channels = [
{ channelName:"#osu", channelTopic:"The main channel", channelUserCount: 0, locked: false }, { channelName:"#osu", channelTopic:"The main channel", channelUserCount: 0, locked: false },
{ channelName:"#userlog", channelTopic:"Log about stuff doing go on yes very", channelUserCount: 0, locked: false }, { channelName:"#userlog", channelTopic:"Log about stuff doing go on yes very", channelUserCount: 0, locked: false },
{ channelName:"#lobby", channelTopic:"Talk about multiplayer stuff", channelUserCount: 0, locked: false }, { channelName:"#lobby", channelTopic:"Talk about multiplayer stuff", channelUserCount: 0, locked: false },
{ channelName:"#english", channelTopic:"Talk in exclusively English", channelUserCount: 0, locked: false }, { channelName:"#english", channelTopic:"Talk in exclusively English", channelUserCount: 0, locked: false },
{ channelName:"#japanese", channelTopic:"Talk in exclusively Japanese", channelUserCount: 0, locked: false }, { channelName:"#japanese", channelTopic:"Talk in exclusively Japanese", channelUserCount: 0, locked: false },
]; ];
// Create a stream for each chat channel // Create a stream for each chat channel
for (let i = 0; i < global.channels.length; i++) { for (let i = 0; i < global.channels.length; i++) {
global.StreamsHandler.addStream(global.channels[i].channelName, false); global.StreamsHandler.addStream(global.channels[i].channelName, false);
} }
// Add a stream for the multiplayer lobby // Add a stream for the multiplayer lobby
@ -92,44 +93,44 @@ global.httpRequestsPerLogInterval = 0;
const logInterval = 10; // Secs const logInterval = 10; // Secs
setInterval(() => { setInterval(() => {
global.usersOnline = (global.userKeys.length - 1); global.usersOnline = (global.userKeys.length - 1);
global.multiplayerMatches = [global.MultiplayerManager.matches.length, 0]; // TODO: Respect private matches global.multiplayerMatches = [global.MultiplayerManager.matches.length, 0]; // TODO: Respect private matches
fs.appendFile( fs.appendFile(
"server-stats.log", "server-stats.log",
`${global.usersOnline}|${global.multiplayerMatches[0]},${global.multiplayerMatches[1]}|${global.httpRequestsPerLogInterval}|${new Date().getTime()}@`, `${global.usersOnline}|${global.multiplayerMatches[0]},${global.multiplayerMatches[1]}|${global.httpRequestsPerLogInterval}|${Date.now()}@`,
() => {} () => {}
); );
global.httpRequestsPerLogInterval = 0; global.httpRequestsPerLogInterval = 0;
}, logInterval * 1000); }, logInterval * 1000);
if (!fs.existsSync("tHMM.ds")) fs.writeFileSync("tHMM.ds", "0"); if (!fs.existsSync("tHMM.ds")) fs.writeFileSync("tHMM.ds", "0");
global.totalHistoricalMultiplayerMatches = parseInt(fs.readFileSync("tHMM.ds").toString()); global.totalHistoricalMultiplayerMatches = parseInt(fs.readFileSync("tHMM.ds").toString());
global.getAndAddToHistoricalMultiplayerMatches = function() { global.getAndAddToHistoricalMultiplayerMatches = function() {
global.totalHistoricalMultiplayerMatches++; global.totalHistoricalMultiplayerMatches++;
fs.writeFile("tHMM.ds", `${global.totalHistoricalMultiplayerMatches}`, () => {}); fs.writeFile("tHMM.ds", `${global.totalHistoricalMultiplayerMatches}`, () => {});
return global.totalHistoricalMultiplayerMatches; return global.totalHistoricalMultiplayerMatches;
} }
// Include packets // Include packets
const ChangeAction = require("./Packets/ChangeAction.js"), const ChangeAction = require("./Packets/ChangeAction.js"),
SendPublicMessage = require("./Packets/SendPublicMessage.js"), SendPublicMessage = require("./Packets/SendPublicMessage.js"),
Logout = require("./Packets/Logout.js"), Logout = require("./Packets/Logout.js"),
Spectator = require("./Spectator.js"), Spectator = require("./Spectator.js"),
SendPrivateMessage = require("./Packets/SendPrivateMessage.js"), SendPrivateMessage = require("./Packets/SendPrivateMessage.js"),
MultiplayerManager = require("./MultiplayerManager.js"), MultiplayerManager = require("./MultiplayerManager.js"),
ChannelJoin = require("./Packets/ChannelJoin.js"), ChannelJoin = require("./Packets/ChannelJoin.js"),
ChannelPart = require("./Packets/ChannelPart.js"), ChannelPart = require("./Packets/ChannelPart.js"),
AddFriend = require("./Packets/AddFriend.js"), AddFriend = require("./Packets/AddFriend.js"),
RemoveFriend = require("./Packets/RemoveFriend.js"), RemoveFriend = require("./Packets/RemoveFriend.js"),
UserPresenceBundle = require("./Packets/UserPresenceBundle.js"), UserPresenceBundle = require("./Packets/UserPresenceBundle.js"),
UserPresence = require("./Packets/UserPresence.js"), UserPresence = require("./Packets/UserPresence.js"),
UserStatsRequest = require("./Packets/UserStatsRequest.js"), UserStatsRequest = require("./Packets/UserStatsRequest.js"),
MultiplayerInvite = require("./Packets/MultiplayerInvite.js"), MultiplayerInvite = require("./Packets/MultiplayerInvite.js"),
TourneyMatchSpecialInfo = require("./Packets/TourneyMatchSpecialInfo.js"), TourneyMatchSpecialInfo = require("./Packets/TourneyMatchSpecialInfo.js"),
TourneyMatchJoinChannel = require("./Packets/TourneyMatchSpecialInfo.js"), TourneyMatchJoinChannel = require("./Packets/TourneyMatchSpecialInfo.js"),
TourneyMatchLeaveChannel = require("./Packets/TourneyLeaveMatchChannel.js"); TourneyMatchLeaveChannel = require("./Packets/TourneyLeaveMatchChannel.js");
const emptyBuffer = Buffer.alloc(0); const emptyBuffer = Buffer.alloc(0);
@ -137,231 +138,231 @@ const emptyBuffer = Buffer.alloc(0);
global.MultiplayerManager = new MultiplayerManager(); global.MultiplayerManager = new MultiplayerManager();
module.exports = async function(req, res) { module.exports = async function(req, res) {
// Add to requests for logging // Add to requests for logging
global.httpRequestsPerLogInterval++; global.httpRequestsPerLogInterval++;
// Get the client's token string and request data // Get the client's token string and request data
const requestTokenString = req.header("osu-token"), const requestTokenString = req.header("osu-token"),
requestData = req.packet; requestData = req.packet;
// Server's response & new client token // Server's response & new client token
let responseData = emptyBuffer; let responseData = emptyBuffer;
// Check if the user is logged in // Check if the user is logged in
if (requestTokenString == null) { if (requestTokenString == null) {
// Client doesn't have a token yet, let's auth them! // Client doesn't have a token yet, let's auth them!
const userData = parseUserData(requestData); const userData = parseUserData(requestData);
global.consoleHelper.printBancho(`New client connection. [User: ${userData.username}]`); consoleHelper.printBancho(`New client connection. [User: ${userData.username}]`);
await loginHandler(req, res, userData); await loginHandler(req, res, userData);
} else { } else {
// Client has a token, let's see what they want. // Client has a token, let's see what they want.
try { try {
// Get the current user // Get the current user
const PacketUser = getUserFromToken(requestTokenString); const PacketUser = getUserFromToken(requestTokenString);
// Make sure the client's token isn't invalid // Make sure the client's token isn't invalid
if (PacketUser != null) { if (PacketUser != null) {
// Create a new osu! packet reader // Create a new osu! packet reader
const osuPacketReader = new osu.Client.Reader(requestData); const osuPacketReader = new osu.Client.Reader(requestData);
// Parse current bancho packet // Parse current bancho packet
const PacketData = osuPacketReader.Parse(); const PacketData = osuPacketReader.Parse();
// Loop through parsed packet data // Loop through parsed packet data
for (let i = 0; i < PacketData.length; i++) { for (let i = 0; i < PacketData.length; i++) {
// Get current packet // Get current packet
let CurrentPacket = PacketData[i]; let CurrentPacket = PacketData[i];
// This is getting a little big, swap this out for mapped functions? // This is getting a little big, swap this out for mapped functions?
// Would require some standardisation // Would require some standardisation
switch (CurrentPacket.id) { switch (CurrentPacket.id) {
case packetIDs.client_changeAction: case packetIDs.client_changeAction:
ChangeAction(PacketUser, CurrentPacket.data); ChangeAction(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_sendPublicMessage: case packetIDs.client_sendPublicMessage:
SendPublicMessage(PacketUser, CurrentPacket.data); SendPublicMessage(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_logout: case packetIDs.client_logout:
Logout(PacketUser); Logout(PacketUser);
break; break;
case packetIDs.client_requestStatusUpdate: case packetIDs.client_requestStatusUpdate:
UserPresenceBundle(PacketUser); UserPresenceBundle(PacketUser);
break; break;
case packetIDs.client_pong: // Pretty sure this is just a client ping case packetIDs.client_pong: // Pretty sure this is just a client ping
// so we probably don't do anything here // so we probably don't do anything here
break; // It's probably just the client wanting to pull data down. break; // It's probably just the client wanting to pull data down.
case packetIDs.client_startSpectating: case packetIDs.client_startSpectating:
Spectator.startSpectatingUser(PacketUser, CurrentPacket.data); Spectator.startSpectatingUser(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_spectateFrames: case packetIDs.client_spectateFrames:
Spectator.sendSpectatorFrames(PacketUser, CurrentPacket.data); Spectator.sendSpectatorFrames(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_stopSpectating: case packetIDs.client_stopSpectating:
Spectator.stopSpectatingUser(PacketUser); Spectator.stopSpectatingUser(PacketUser);
break; break;
case packetIDs.client_sendPrivateMessage: case packetIDs.client_sendPrivateMessage:
SendPrivateMessage(PacketUser, CurrentPacket.data); SendPrivateMessage(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_joinLobby: case packetIDs.client_joinLobby:
global.MultiplayerManager.userEnterLobby(PacketUser); global.MultiplayerManager.userEnterLobby(PacketUser);
break; break;
case packetIDs.client_partLobby: case packetIDs.client_partLobby:
global.MultiplayerManager.userLeaveLobby(PacketUser); global.MultiplayerManager.userLeaveLobby(PacketUser);
break; break;
case packetIDs.client_createMatch: case packetIDs.client_createMatch:
global.MultiplayerManager.createMultiplayerMatch(PacketUser, CurrentPacket.data); global.MultiplayerManager.createMultiplayerMatch(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_joinMatch: case packetIDs.client_joinMatch:
global.MultiplayerManager.joinMultiplayerMatch(PacketUser, CurrentPacket.data); global.MultiplayerManager.joinMultiplayerMatch(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_matchChangeSlot: case packetIDs.client_matchChangeSlot:
PacketUser.currentMatch.moveToSlot(PacketUser, CurrentPacket.data); PacketUser.currentMatch.moveToSlot(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_matchReady: case packetIDs.client_matchReady:
PacketUser.currentMatch.setStateReady(PacketUser); PacketUser.currentMatch.setStateReady(PacketUser);
break; break;
case packetIDs.client_matchChangeSettings: case packetIDs.client_matchChangeSettings:
PacketUser.currentMatch.updateMatch(PacketUser, CurrentPacket.data); PacketUser.currentMatch.updateMatch(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_matchNotReady: case packetIDs.client_matchNotReady:
PacketUser.currentMatch.setStateNotReady(PacketUser); PacketUser.currentMatch.setStateNotReady(PacketUser);
break; break;
case packetIDs.client_partMatch: case packetIDs.client_partMatch:
global.MultiplayerManager.leaveMultiplayerMatch(PacketUser); global.MultiplayerManager.leaveMultiplayerMatch(PacketUser);
break; break;
// Also handles user kick if the slot has a user // Also handles user kick if the slot has a user
case packetIDs.client_matchLock: case packetIDs.client_matchLock:
PacketUser.currentMatch.lockMatchSlot(PacketUser, CurrentPacket.data); PacketUser.currentMatch.lockMatchSlot(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_matchNoBeatmap: case packetIDs.client_matchNoBeatmap:
PacketUser.currentMatch.missingBeatmap(PacketUser); PacketUser.currentMatch.missingBeatmap(PacketUser);
break; break;
case packetIDs.client_matchSkipRequest: case packetIDs.client_matchSkipRequest:
PacketUser.currentMatch.matchSkip(PacketUser); PacketUser.currentMatch.matchSkip(PacketUser);
break; break;
case packetIDs.client_matchHasBeatmap: case packetIDs.client_matchHasBeatmap:
PacketUser.currentMatch.notMissingBeatmap(PacketUser); PacketUser.currentMatch.notMissingBeatmap(PacketUser);
break; break;
case packetIDs.client_matchTransferHost: case packetIDs.client_matchTransferHost:
PacketUser.currentMatch.transferHost(PacketUser, CurrentPacket.data); PacketUser.currentMatch.transferHost(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_matchChangeMods: case packetIDs.client_matchChangeMods:
PacketUser.currentMatch.updateMods(PacketUser, CurrentPacket.data); PacketUser.currentMatch.updateMods(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_matchStart: case packetIDs.client_matchStart:
PacketUser.currentMatch.startMatch(); PacketUser.currentMatch.startMatch();
break; break;
case packetIDs.client_matchLoadComplete: case packetIDs.client_matchLoadComplete:
PacketUser.currentMatch.matchPlayerLoaded(PacketUser); PacketUser.currentMatch.matchPlayerLoaded(PacketUser);
break; break;
case packetIDs.client_matchComplete: case packetIDs.client_matchComplete:
PacketUser.currentMatch.onPlayerFinishMatch(PacketUser); PacketUser.currentMatch.onPlayerFinishMatch(PacketUser);
break; break;
case packetIDs.client_matchScoreUpdate: case packetIDs.client_matchScoreUpdate:
PacketUser.currentMatch.updatePlayerScore(PacketUser, CurrentPacket.data); PacketUser.currentMatch.updatePlayerScore(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_matchFailed: case packetIDs.client_matchFailed:
PacketUser.currentMatch.matchFailed(PacketUser); PacketUser.currentMatch.matchFailed(PacketUser);
break; break;
case packetIDs.client_matchChangeTeam: case packetIDs.client_matchChangeTeam:
PacketUser.currentMatch.changeTeam(PacketUser); PacketUser.currentMatch.changeTeam(PacketUser);
break; break;
case packetIDs.client_channelJoin: case packetIDs.client_channelJoin:
ChannelJoin(PacketUser, CurrentPacket.data); ChannelJoin(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_channelPart: case packetIDs.client_channelPart:
ChannelPart(PacketUser, CurrentPacket.data); ChannelPart(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_friendAdd: case packetIDs.client_friendAdd:
AddFriend(PacketUser, CurrentPacket.data); AddFriend(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_friendRemove: case packetIDs.client_friendRemove:
RemoveFriend(PacketUser, CurrentPacket.data); RemoveFriend(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_userStatsRequest: case packetIDs.client_userStatsRequest:
UserStatsRequest(PacketUser, CurrentPacket.data); UserStatsRequest(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_specialMatchInfoRequest: case packetIDs.client_specialMatchInfoRequest:
TourneyMatchSpecialInfo(PacketUser, CurrentPacket.data); TourneyMatchSpecialInfo(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_specialJoinMatchChannel: case packetIDs.client_specialJoinMatchChannel:
TourneyMatchJoinChannel(PacketUser, CurrentPacket.data); TourneyMatchJoinChannel(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_specialLeaveMatchChannel: case packetIDs.client_specialLeaveMatchChannel:
TourneyMatchLeaveChannel(PacketUser, CurrentPacket.data); TourneyMatchLeaveChannel(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_invite: case packetIDs.client_invite:
MultiplayerInvite(PacketUser, CurrentPacket.data); MultiplayerInvite(PacketUser, CurrentPacket.data);
break; break;
case packetIDs.client_userPresenceRequest: case packetIDs.client_userPresenceRequest:
UserPresence(PacketUser, PacketUser.id); // Can't really think of a way to generalize this? UserPresence(PacketUser, PacketUser.id); // Can't really think of a way to generalize this?
break; break;
default: default:
// Ignore client_beatmapInfoRequest and client_receiveUpdates // Ignore client_beatmapInfoRequest and client_receiveUpdates
if (CurrentPacket.id == 68 || CurrentPacket.id == 79) break; if (CurrentPacket.id == 68 || CurrentPacket.id == 79) break;
// Print out unimplemented packet // Print out unimplemented packet
console.dir(CurrentPacket); console.dir(CurrentPacket);
break; break;
} }
// Concat current user queue into response data // Concat current user queue into response data
responseData = Buffer.concat([responseData, PacketUser.queue], responseData.length + PacketUser.queue.length); responseData = Buffer.concat([responseData, PacketUser.queue], responseData.length + PacketUser.queue.length);
PacketUser.clearQueue(); PacketUser.clearQueue();
} }
} else { } else {
// User's token is invlid, force a reconnect // User's token is invlid, force a reconnect
global.consoleHelper.printBancho(`Forced client re-login (Token is invalid)`); consoleHelper.printBancho(`Forced client re-login (Token is invalid)`);
responseData = bakedResponses("reconnect"); responseData = bakedResponses("reconnect");
} }
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} finally { } finally {
// Send the prepared packet to the client // Send the prepared packet to the client
res.writeHead(200, { res.writeHead(200, {
"cho-protocol": global.protocolVersion, "cho-protocol": global.protocolVersion,
"Connection": "keep-alive", "Connection": "keep-alive",
"Keep-Alive": "timeout=5, max=100", "Keep-Alive": "timeout=5, max=100",
"Content-Type": "text/html; charset=UTF-8" "Content-Type": "text/html; charset=UTF-8"
}); });
res.end(responseData); res.end(responseData);
} }
} }
}; };

View file

@ -1,16 +1,16 @@
const request = require("request"), RequestType = require("./RequestType.json"); const request = require("request"), RequestType = require("./RequestType.json");
const functionMap = { const functionMap = {
0: (resolve, body) => resolve(body), 0: (resolve, body) => resolve(body),
1: (resolve, body) => resolve(JSON.parse(body)), 1: (resolve, body) => resolve(JSON.parse(body)),
2: null 2: null
}; };
module.exports = async function(url, reqType = RequestType.Text) { module.exports = async function(url, reqType = RequestType.Text) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request(url, (err, res, body) => { request(url, (err, res, body) => {
if (err) reject(err); if (err) reject(err);
else functionMap[reqType](resolve, body); else functionMap[reqType](resolve, body);
}); });
}); });
} }

View file

@ -1,3 +1,3 @@
module.exports = function(bitwiseMods = 0) { module.exports = function(bitwiseMods = 0) {
} }

View file

@ -1,15 +1,15 @@
module.exports = { module.exports = {
map:function(input, inputMin, inputMax, outputMin, outputMax) { map:function(input, inputMin, inputMax, outputMin, outputMax) {
const newv = (input - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin; const newv = (input - inputMin) / (inputMax - inputMin) * (outputMax - outputMin) + outputMin;
if (outputMin < outputMax) return this.constrain(newv, outputMin, outputMax); if (outputMin < outputMax) return this.constrain(newv, outputMin, outputMax);
else return this.constrain(newv, outputMax, outputMin); else return this.constrain(newv, outputMax, outputMin);
}, },
constrain:function(input, low, high) { constrain:function(input, low, high) {
return Math.max(Math.min(input, high), low); return Math.max(Math.min(input, high), low);
}, },
randInt:function(from, to) { randInt:function(from, to) {
return Math.round(this.map(Math.random(), 0, 1, from, to)); return Math.round(this.map(Math.random(), 0, 1, from, to));
} }
} }

View file

@ -1,6 +1,6 @@
module.exports = function(id) { module.exports = function(id) {
for (let i = 0; i < global.userKeys.length; i++) { for (let i = 0; i < global.userKeys.length; i++) {
if (global.users[global.userKeys[i]].id == id) if (global.users[global.userKeys[i]].id == id)
return global.users[userKeys[i]]; return global.users[userKeys[i]];
} }
} }

View file

@ -1,4 +1,4 @@
module.exports = function(token) { module.exports = function(token) {
if (global.userKeys.includes(token)) return global.users[token]; if (global.userKeys.includes(token)) return global.users[token];
else return null; else return null;
} }

View file

@ -1,6 +1,6 @@
module.exports = function(username) { module.exports = function(username) {
for (let i = 0; i < global.userKeys.length; i++) { for (let i = 0; i < global.userKeys.length; i++) {
if (global.users[global.userKeys[i]].username == username) if (global.users[global.userKeys[i]].username == username)
return global.users[global.userKeys[i]]; return global.users[global.userKeys[i]];
} }
} }

View file

@ -1,33 +1,33 @@
module.exports = function(packet) { module.exports = function(packet) {
try { try {
const p = packet.toString(); // Convert our buffer to a String const p = packet.toString(); // Convert our buffer to a String
const s = p.split('\n'); // Split our Login Data to Username Password Osuversion|blabla|bla const s = p.split('\n'); // Split our Login Data to Username Password Osuversion|blabla|bla
const n = s[2].split('|'); // Split osuversion|blablabla|blablabla to a object. const n = s[2].split('|'); // Split osuversion|blablabla|blablabla to a object.
const username = s[0]; // Username ofc const username = s[0]; // Username ofc
const password = s[1]; // Password ofc const password = s[1]; // Password ofc
const osuversion = n[0]; // OsuVersion ofc. const osuversion = n[0]; // OsuVersion ofc.
const TimeOffset = Number(n[1]); // Comeon, i dont realy have to tell you what this is. const TimeOffset = Number(n[1]); // Comeon, i dont realy have to tell you what this is.
const clientData = n[3].split(':')[2]; // Some system information. such as MacAdress or DiskID const clientData = n[3].split(':')[2]; // Some system information. such as MacAdress or DiskID
// If some data is not set OR is invailed throw errors // If some data is not set OR is invailed throw errors
if (username == undefined) throw 'UserName'; if (username == undefined) throw 'UserName';
if (password == undefined) throw 'password'; if (password == undefined) throw 'password';
if (osuversion == undefined) throw 'osuversion'; if (osuversion == undefined) throw 'osuversion';
if (TimeOffset == undefined) throw 'offset'; if (TimeOffset == undefined) throw 'offset';
if (clientData == undefined) throw 'clientData'; if (clientData == undefined) throw 'clientData';
// Everything alright? return parsed data. // Everything alright? return parsed data.
const obj = { const obj = {
username: String(username), username: String(username),
password: String(password), password: String(password),
osuversion: String(osuversion), osuversion: String(osuversion),
timeoffset: Number(TimeOffset), timeoffset: Number(TimeOffset),
clientdata: String(clientData) clientdata: String(clientData)
}; };
// Here is the return. // Here is the return.
return obj; return obj;
} catch (ex) { } catch (ex) {
// Else return undefined, that the login request got broke. // Else return undefined, that the login request got broke.
return undefined; return undefined;
} }
} }