Initial commit
This commit is contained in:
commit
65f47d0672
27 changed files with 2018 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
server/DatabaseHelper.js
|
49
Binato.js
Normal file
49
Binato.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
console.clear();
|
||||||
|
|
||||||
|
const app = require("express")(),
|
||||||
|
fs = require("fs"),
|
||||||
|
busboy = require("connect-busboy"),
|
||||||
|
osu = require("osu-packet");
|
||||||
|
|
||||||
|
const debugMode = true;
|
||||||
|
|
||||||
|
global.consoleHelper = require("./consoleHelper.js");
|
||||||
|
|
||||||
|
const serverHandler = require("./server/serverHandler.js"),
|
||||||
|
userManager = require("./server/userManager.js");
|
||||||
|
|
||||||
|
app.use(busboy());
|
||||||
|
|
||||||
|
app.use((req, res) => {
|
||||||
|
req.packet = new Buffer.alloc(0);
|
||||||
|
req.on("data", (chunk) => req.packet = Buffer.concat([req.packet, chunk], req.packet.length + chunk.length));
|
||||||
|
req.on("end", () => {
|
||||||
|
switch (req.method) {
|
||||||
|
case "GET":
|
||||||
|
fs.readFile("serverPage.html", (err, data) => {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
if (debugMode) data = data.toString().replace("|isdebug?|", '<b style="color:red;">DEBUG</b>');
|
||||||
|
else data = data.toString().replace("|isdebug?|", '');
|
||||||
|
res.send(data);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "POST":
|
||||||
|
// Make sure this address should respond to bancho requests
|
||||||
|
// Bancho addresses: c, c1, c2, c3, c4, c5, c6, ce
|
||||||
|
// Just looking for the first character being "c" *should* be enough
|
||||||
|
if (req.headers["host"].split(".")[0][0] == "c")
|
||||||
|
serverHandler(req, res);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
res.status(405).send("405 | Method not allowed!<hr>Binato");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Not have a predefined port,
|
||||||
|
// doesn't matter for me so not top priority
|
||||||
|
app.listen(5001, () => global.consoleHelper.printBancho("Binato is up! Listening at port 5001"));
|
33
consoleHelper.js
Normal file
33
consoleHelper.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
const chalk = require("chalk");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
printWebReq:function(s) {
|
||||||
|
console.log(`${chalk.green("["+this.getTime()+"]")} ${chalk.bgGreen((" WEBREQ "))} ${s}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
printBancho:function(s) {
|
||||||
|
console.log(`${chalk.green("["+this.getTime()+"]")} ${chalk.bgMagenta((" BANCHO "))} ${s}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
printChat:function(s) {
|
||||||
|
console.log(`${chalk.green("["+this.getTime()+"]")} ${chalk.bgCyan((" CHAT "))} ${s}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
printWarn:function(s) {
|
||||||
|
console.warn(`${chalk.green("["+this.getTime()+"]")} ${chalk.bgYellow((" WARN "))} ${chalk.yellow(s)}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
printError:function(s) {
|
||||||
|
console.error(`${chalk.green("["+this.getTime()+"]")} ${chalk.bgRed((" ERROR "))} ${chalk.red(s)}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
getTime:function() {
|
||||||
|
const time = new Date();
|
||||||
|
return `${correctValue(time.getHours())}:${correctValue(time.getMinutes())}:${correctValue(time.getSeconds())}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function correctValue(i) {
|
||||||
|
if (i <= 9) return "0"+i;
|
||||||
|
else return i;
|
||||||
|
}
|
22
package.json
Normal file
22
package.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"name": "Binato",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^4.0.0",
|
||||||
|
"connect-busboy": "0.0.2",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"fs": "0.0.1-security",
|
||||||
|
"osu-packet": "^4.1.2",
|
||||||
|
"request": "^2.88.2",
|
||||||
|
"sync-request": "^6.1.0",
|
||||||
|
"uuid": "^7.0.3"
|
||||||
|
}
|
||||||
|
}
|
13
server/BotCommandHandler.js
Normal file
13
server/BotCommandHandler.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
module.exports = function(User, Message) {
|
||||||
|
const command = Message.split(" ")[0];
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case "!help":
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "!lock":
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
528
server/Multiplayer.js
Normal file
528
server/Multiplayer.js
Normal file
|
@ -0,0 +1,528 @@
|
||||||
|
const osu = require("osu-packet"),
|
||||||
|
getUserById = require("./util/getUserById.js"),
|
||||||
|
DatabaseHelper = require("./DatabaseHelper.js"),
|
||||||
|
StatusUpdate = require("./Packets/StatusUpdate.js");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
userEnterLobby:function(currentUser) {
|
||||||
|
if (currentUser.currentMatch != null) {
|
||||||
|
this.leaveMatch(currentUser);
|
||||||
|
currentUser.currentMatch = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
global.StreamsHandler.addUserToStream("multiplayer_lobby", currentUser.id);
|
||||||
|
|
||||||
|
const osuPacketWriter1 = new osu.Bancho.Writer;
|
||||||
|
let userIds = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
userIds.push(global.users[i].id);
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter1.UserPresenceBundle(userIds);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter1.toBuffer, null);
|
||||||
|
|
||||||
|
for (let i = 0; i < global.matches.length; i++) {
|
||||||
|
for (let i1 = 0; i1 < global.matches[i][1].slots.length; i1++) {
|
||||||
|
const slot = global.matches[i][1].slots[i1];
|
||||||
|
if (slot.playerId == -1 || slot.status == 2) continue;
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
const User = getUserById(slot.playerId);
|
||||||
|
|
||||||
|
// Get user score info from the database
|
||||||
|
const userScoreDB = DatabaseHelper.getFromDB(`SELECT * FROM users_modes_info WHERE user_id = ${User.id} AND mode_id = ${User.playMode} LIMIT 1`);
|
||||||
|
|
||||||
|
let UserStatusObject = {
|
||||||
|
userId: User.id,
|
||||||
|
status: User.actionID,
|
||||||
|
statusText: User.actionText,
|
||||||
|
beatmapChecksum: User.beatmapChecksum,
|
||||||
|
currentMods: User.currentMods,
|
||||||
|
playMode: User.playMode,
|
||||||
|
beatmapId: User.beatmapID,
|
||||||
|
rankedScore: userScoreDB.ranked_score,
|
||||||
|
accuracy: userScoreDB.avg_accuracy / 100, // Scale of 0 to 1
|
||||||
|
playCount: userScoreDB.playcount,
|
||||||
|
totalScore: userScoreDB.total_score,
|
||||||
|
rank: 1,
|
||||||
|
performance: userScoreDB.pp_raw
|
||||||
|
};
|
||||||
|
|
||||||
|
osuPacketWriter.HandleOsuUpdate(UserStatusObject);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchNew(global.matches[i][1]);
|
||||||
|
|
||||||
|
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
}
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
osuPacketWriter.ChannelJoinSuccess("#lobby");
|
||||||
|
if (!global.StreamsHandler.isUserInStream("#lobby", currentUser.id))
|
||||||
|
global.StreamsHandler.addUserToStream("#lobby", currentUser.id);
|
||||||
|
|
||||||
|
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateMatchListing:function() {
|
||||||
|
const osuPacketWriter1 = new osu.Bancho.Writer;
|
||||||
|
let userIds = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
userIds.push(global.users[i].id);
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter1.UserPresenceBundle(userIds);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter1.toBuffer, null);
|
||||||
|
for (let i = 0; i < global.matches.length; i++) {
|
||||||
|
for (let i1 = 0; i1 < global.matches[i][1].slots.length; i1++) {
|
||||||
|
const slot = global.matches[i][1].slots[i1];
|
||||||
|
if (slot.playerId == -1 || slot.status == 2) continue;
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
const User = getUserById(slot.playerId);
|
||||||
|
|
||||||
|
// Get user score info from the database
|
||||||
|
const userScoreDB = DatabaseHelper.getFromDB(`SELECT * FROM users_modes_info WHERE user_id = ${User.id} AND mode_id = ${User.playMode} LIMIT 1`);
|
||||||
|
|
||||||
|
let UserStatusObject = {
|
||||||
|
userId: User.id,
|
||||||
|
status: User.actionID,
|
||||||
|
statusText: User.actionText,
|
||||||
|
beatmapChecksum: User.beatmapChecksum,
|
||||||
|
currentMods: User.currentMods,
|
||||||
|
playMode: User.playMode,
|
||||||
|
beatmapId: User.beatmapID,
|
||||||
|
rankedScore: userScoreDB.ranked_score,
|
||||||
|
accuracy: userScoreDB.avg_accuracy / 100, // Scale of 0 to 1
|
||||||
|
playCount: userScoreDB.playcount,
|
||||||
|
totalScore: userScoreDB.total_score,
|
||||||
|
rank: 1,
|
||||||
|
performance: userScoreDB.pp_raw
|
||||||
|
};
|
||||||
|
|
||||||
|
osuPacketWriter.HandleOsuUpdate(UserStatusObject);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchNew(global.matches[i][1]);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream("multiplayer_lobby", osuPacketWriter.toBuffer, null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
createMultiplayerMatch:function(currentUser, data) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
if (data.gamePassword == '') data.gamePassword == null;
|
||||||
|
|
||||||
|
let NewMatchObject = {
|
||||||
|
matchId: global.matches.length,
|
||||||
|
inProgress: false,
|
||||||
|
matchType: 0,
|
||||||
|
activeMods: 0,
|
||||||
|
gameName: data.gameName,
|
||||||
|
gamePassword: data.gamePassword,
|
||||||
|
beatmapName: data.beatmapName,
|
||||||
|
beatmapId: data.beatmapId,
|
||||||
|
beatmapChecksum: data.beatmapChecksum,
|
||||||
|
slots: data.slots,
|
||||||
|
host: currentUser.id,
|
||||||
|
playMode: 0,
|
||||||
|
matchScoringType: 0,
|
||||||
|
matchTeamType: 0,
|
||||||
|
specialModes: 0,
|
||||||
|
hidden: false,
|
||||||
|
seed: data.seed
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < NewMatchObject.slots.length; i++) {
|
||||||
|
let s = NewMatchObject.slots[i];
|
||||||
|
s.mods = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusUpdate(currentUser, currentUser.id);
|
||||||
|
osuPacketWriter.MatchNew(NewMatchObject);
|
||||||
|
|
||||||
|
// Queue match creation for user
|
||||||
|
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
|
||||||
|
global.StreamsHandler.addStream(`mp_${data.gameName.split(" ").join("-")}`, true, NewMatchObject.matchId);
|
||||||
|
|
||||||
|
global.matches.push([`mp_${data.gameName.split(" ").join("-")}`, NewMatchObject]);
|
||||||
|
|
||||||
|
this.updateMatchListing();
|
||||||
|
|
||||||
|
this.joinMultiplayerMatch(currentUser, {
|
||||||
|
matchId: NewMatchObject.matchId,
|
||||||
|
gamePassword: NewMatchObject.gamePassword
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
joinMultiplayerMatch:function(currentUser, data) {
|
||||||
|
try {
|
||||||
|
let osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
const osuPacketWriter1 = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
const streamName = global.matches[data.matchId][0];
|
||||||
|
const mpLobby = global.matches[data.matchId][1];
|
||||||
|
|
||||||
|
let full = true;
|
||||||
|
for (let i = 0; i < mpLobby.slots.length; i++) {
|
||||||
|
const slot = mpLobby.slots[i];
|
||||||
|
if (slot.playerId !== -1 || slot.status === 2) continue;
|
||||||
|
full = false;
|
||||||
|
slot.playerId = currentUser.id;
|
||||||
|
currentUser.matchSlotId = i;
|
||||||
|
slot.status = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter1.MatchUpdate(mpLobby);
|
||||||
|
osuPacketWriter.MatchJoinSuccess(mpLobby);
|
||||||
|
|
||||||
|
if (full) {
|
||||||
|
osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
osuPacketWriter.MatchJoinFail();
|
||||||
|
} else {
|
||||||
|
global.StreamsHandler.removeUserFromStream("multiplayer_lobby", currentUser.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentUser.currentMatch = data.matchId;
|
||||||
|
|
||||||
|
global.StreamsHandler.addUserToStream(streamName, currentUser.id);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(streamName, osuPacketWriter1.toBuffer, null);
|
||||||
|
|
||||||
|
osuPacketWriter.ChannelJoinSuccess("#multiplayer");
|
||||||
|
|
||||||
|
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
} catch (e) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchJoinFail();
|
||||||
|
|
||||||
|
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
|
||||||
|
this.updateMatchListing();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setReadyState:function(currentUser, state) {
|
||||||
|
const mpLobby = global.matches[currentUser.currentMatch][1];
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
for (let i = 0; i < mpLobby.slots.length; i++) {
|
||||||
|
const slot = mpLobby.slots[i];
|
||||||
|
if (slot.playerId == currentUser.id) {
|
||||||
|
if (state) slot.status = 8;
|
||||||
|
else slot.status = 4;
|
||||||
|
console.log("e");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(mpLobby);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
sendMatchUpdate:function(currentUser) {
|
||||||
|
const mpLobby = global.matches[currentUser.currentMatch][1];
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(mpLobby);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateMatch:function(currentUser, data) {
|
||||||
|
global.matches[currentUser.currentMatch][1] = data;
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(global.matches[currentUser.currentMatch][1]);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
moveToSlot:function(currentUser, data) {
|
||||||
|
const mpLobby = global.matches[currentUser.currentMatch][1];
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
let currentUserData, slotIndex;
|
||||||
|
for (let i = 0; i < mpLobby.slots.length; i++) {
|
||||||
|
const slot = mpLobby.slots[i];
|
||||||
|
if (slot.playerId != currentUser.id) continue;
|
||||||
|
|
||||||
|
currentUserData = slot;
|
||||||
|
slotIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpLobby.slots[data].playerId = currentUserData.playerId;
|
||||||
|
currentUser.matchSlotId = data;
|
||||||
|
mpLobby.slots[data].status = currentUserData.status;
|
||||||
|
|
||||||
|
mpLobby.slots[slotIndex].playerId = -1;
|
||||||
|
mpLobby.slots[slotIndex].status = 1;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(mpLobby);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
kickPlayer:function(currentUser, data) {
|
||||||
|
const mpLobby = global.matches[currentUser.currentMatch][1];
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
if (mpLobby.host != currentUser.id) return;
|
||||||
|
|
||||||
|
const slot = mpLobby.slots[data];
|
||||||
|
let cachedPlayerId = slot.playerId;
|
||||||
|
|
||||||
|
if (slot.playerId === -1) { // Slot is empty, lock it
|
||||||
|
if (slot.status === 1) slot.status = 2;
|
||||||
|
else slot.status = 1;
|
||||||
|
} else { // Slot isn't empty kick player
|
||||||
|
const kickedPlayer = getUserById(slot.playerId);
|
||||||
|
kickedPlayer.matchSlotId = -1;
|
||||||
|
slot.playerId = -1;
|
||||||
|
slot.status = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(mpLobby);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
if (cachedPlayerId !== null || cachedPlayerId !== -1) {
|
||||||
|
global.StreamsHandler.removeUserFromStream(global.matches[currentUser.currentMatch][0], cachedPlayerId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
missingBeatmap:function(currentUser, state) {
|
||||||
|
const mpLobby = global.matches[currentUser.currentMatch][1];
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
for (let i = 0; i < mpLobby.slots.length; i++) {
|
||||||
|
const slot = mpLobby.slots[i];
|
||||||
|
if (slot.playerId != currentUser.id) continue;
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
slot.status = 16;
|
||||||
|
} else {
|
||||||
|
slot.status = 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(mpLobby);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
transferHost:function(currentUser, data) {
|
||||||
|
const mpLobby = global.matches[currentUser.currentMatch][1];
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
const newUser = getUserById(mpLobby.slots[data].playerId);
|
||||||
|
|
||||||
|
mpLobby.host = newUser.id;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(mpLobby);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateMods(currentUser, data) { // TODO: Allow freemod to work
|
||||||
|
if (global.matches[currentUser.currentMatch][1].host !== currentUser.id) return;
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
global.matches[currentUser.currentMatch][1].activeMods = data;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(global.matches[currentUser.currentMatch][1]);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
startMatch(currentUser) {
|
||||||
|
const mpLobby = global.matches[currentUser.currentMatch][1];
|
||||||
|
if (mpLobby.inProgress) return;
|
||||||
|
mpLobby.inProgress = true;
|
||||||
|
global.matches[currentUser.currentMatch][2] = [];
|
||||||
|
const loadedSlots = global.matches[currentUser.currentMatch][2];
|
||||||
|
for (let i = 0; i < mpLobby.slots.length; i++) {
|
||||||
|
const slot = mpLobby.slots[i];
|
||||||
|
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
||||||
|
|
||||||
|
loadedSlots.push({playerId: slot.playerId, loaded: false});
|
||||||
|
}
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
for (let i = 0; i < mpLobby.slots.length; i++) {
|
||||||
|
const slot = mpLobby.slots[i];
|
||||||
|
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
||||||
|
|
||||||
|
slot.status = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchStart(mpLobby);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
this.sendMatchUpdate(currentUser);
|
||||||
|
},
|
||||||
|
|
||||||
|
setPlayerLoaded:function(currentUser) {
|
||||||
|
const loadedSlots = global.matches[currentUser.currentMatch][2];
|
||||||
|
|
||||||
|
for (let i = 0; i < loadedSlots.length; i++) {
|
||||||
|
if (loadedSlots[i].playerId == currentUser.id) {
|
||||||
|
loadedSlots[i].loaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allLoaded = true;
|
||||||
|
for (let i = 0; i < loadedSlots.length; i++) {
|
||||||
|
if (loadedSlots[i].loaded) continue;
|
||||||
|
|
||||||
|
allLoaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allLoaded) {
|
||||||
|
let osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
osuPacketWriter.MatchAllPlayersLoaded();
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
global.matches[currentUser.currentMatch][2] = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onPlayerFinishMatch:function(currentUser) {
|
||||||
|
const mpLobby = global.matches[currentUser.currentMatch][1];
|
||||||
|
if (global.matches[currentUser.currentMatch][2] == null) {
|
||||||
|
global.matches[currentUser.currentMatch][2] = [];
|
||||||
|
const loadedSlots = global.matches[currentUser.currentMatch][2];
|
||||||
|
for (let i = 0; i < mpLobby.slots.length; i++) {
|
||||||
|
const slot = mpLobby.slots[i];
|
||||||
|
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
||||||
|
|
||||||
|
loadedSlots.push({playerId: slot.playerId, loaded: false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadedSlots = global.matches[currentUser.currentMatch][2];
|
||||||
|
|
||||||
|
for (let i = 0; i < loadedSlots.length; i++) {
|
||||||
|
if (loadedSlots[i].playerId == currentUser.id) {
|
||||||
|
loadedSlots[i].loaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let allLoaded = true;
|
||||||
|
for (let i = 0; i < loadedSlots.length; i++) {
|
||||||
|
if (loadedSlots[i].loaded) continue;
|
||||||
|
|
||||||
|
allLoaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allLoaded) this.finishMatch(currentUser);
|
||||||
|
},
|
||||||
|
|
||||||
|
finishMatch:function(currentUser) {
|
||||||
|
const mpLobby = global.matches[currentUser.currentMatch][1];
|
||||||
|
if (!mpLobby.inProgress) return;
|
||||||
|
global.matches[currentUser.currentMatch][2] = [];
|
||||||
|
mpLobby.inProgress = false;
|
||||||
|
let osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
for (let i = 0; i < mpLobby.slots.length; i++) {
|
||||||
|
const slot = mpLobby.slots[i];
|
||||||
|
if (slot.playerId === -1 || slot.status === 1 || slot.status === 2) continue;
|
||||||
|
|
||||||
|
slot.status = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchComplete();
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
this.sendMatchUpdate(currentUser);
|
||||||
|
},
|
||||||
|
|
||||||
|
updatePlayerScore:function(currentUser, data) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
if (currentUser.matchSlotId == -1) return console.log("it did the big fuck");
|
||||||
|
|
||||||
|
data.id = currentUser.matchSlotId;
|
||||||
|
|
||||||
|
osuPacketWriter.MatchScoreUpdate(data);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
leaveMatch:function(currentUser) {
|
||||||
|
try {
|
||||||
|
const mpLobby = global.matches[currentUser.currentMatch][1];
|
||||||
|
let osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
for (let i = 0; i < mpLobby.slots.length; i++) {
|
||||||
|
const slot = mpLobby.slots[i];
|
||||||
|
if (slot.playerId != currentUser.id) continue;
|
||||||
|
|
||||||
|
slot.playerId = -1;
|
||||||
|
slot.status = 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.MatchUpdate(mpLobby);
|
||||||
|
|
||||||
|
global.StreamsHandler.sendToStream(global.matches[currentUser.currentMatch][0], osuPacketWriter.toBuffer, null);
|
||||||
|
|
||||||
|
osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
osuPacketWriter.ChannelRevoked("#multiplayer");
|
||||||
|
|
||||||
|
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
|
||||||
|
let empty = true;
|
||||||
|
for (let i = 0; i < mpLobby.slots.length; i++) {
|
||||||
|
const slot = mpLobby.slots[i];
|
||||||
|
if (slot.playerId === -1) continue;
|
||||||
|
|
||||||
|
empty = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty) {
|
||||||
|
let matchIndex;
|
||||||
|
for (let i = 0; i < global.matches.length; i++) {
|
||||||
|
if (global.matches[i][0] == global.matches[currentUser.currentMatch][0]) {
|
||||||
|
matchIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we got a match index
|
||||||
|
if (matchIndex == null) return;
|
||||||
|
|
||||||
|
global.matches.splice(matchIndex, 1);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (e) { }
|
||||||
|
this.updateMatchListing();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.updateMatchListing();
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
}
|
3
server/Packets/ChangeAction.js
Normal file
3
server/Packets/ChangeAction.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = function(currentUser, data) {
|
||||||
|
currentUser.updatePresence(data);
|
||||||
|
}
|
3
server/Packets/ChannelPart.js
Normal file
3
server/Packets/ChannelPart.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = function(userClass, data) {
|
||||||
|
global.StreamsHandler.removeUserFromStream(data, userClass.id);
|
||||||
|
}
|
35
server/Packets/Logout.js
Normal file
35
server/Packets/Logout.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
const osu = require("osu-packet");
|
||||||
|
|
||||||
|
module.exports = function(CurrentUser) {
|
||||||
|
const loginStartTime = new Date().getTime();
|
||||||
|
let userCurrentIndex;
|
||||||
|
// Find the index that the user's class is at
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
if (CurrentUser.uuid == global.users[i].uuid) {
|
||||||
|
userCurrentIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const streamList = global.StreamsHandler.getStreams();
|
||||||
|
|
||||||
|
for (let i = 0; i < streamList.length; i++) {
|
||||||
|
if (global.StreamsHandler.isUserInStream(streamList[i], CurrentUser.id)) {
|
||||||
|
global.StreamsHandler.removeUserFromStream(streamList[i], CurrentUser.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove that user from the list of users
|
||||||
|
global.users.splice(userCurrentIndex, 1);
|
||||||
|
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
osuPacketWriter.SendMessage({
|
||||||
|
sendingClient: "BanchoBot",
|
||||||
|
message: `User ${CurrentUser.username} has logged out.`,
|
||||||
|
target: "#userlog",
|
||||||
|
senderId: 3
|
||||||
|
});
|
||||||
|
global.StreamsHandler.sendToStream("#userlog", osuPacketWriter.toBuffer);
|
||||||
|
|
||||||
|
global.consoleHelper.printBancho(`User logged out, took ${new Date().getTime() - loginStartTime}ms. [User: ${CurrentUser.username}]`);
|
||||||
|
}
|
21
server/Packets/SendPublicMessage.js
Normal file
21
server/Packets/SendPublicMessage.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
const osu = require("osu-packet"),
|
||||||
|
userManager = require("../userManager.js");
|
||||||
|
|
||||||
|
module.exports = function(CurrentPacket, CurrentUser) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
osuPacketWriter.SendMessage({
|
||||||
|
sendingClient: CurrentUser.username,
|
||||||
|
message: CurrentPacket.data.message,
|
||||||
|
target: CurrentPacket.data.target,
|
||||||
|
senderId: CurrentUser.id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (CurrentPacket.data.target == "#multiplayer")
|
||||||
|
return global.StreamsHandler.sendToStream(global.matches[CurrentUser.currentMatch][0], osuPacketWriter.toBuffer, CurrentUser.id);
|
||||||
|
|
||||||
|
// Check the stream that we're sending to even exists
|
||||||
|
if (!global.StreamsHandler.doesStreamExist(CurrentPacket.data.target)) return;
|
||||||
|
|
||||||
|
// Write chat message to stream asociated with chat channel
|
||||||
|
return global.StreamsHandler.sendToStream(CurrentPacket.data.target, osuPacketWriter.toBuffer, CurrentUser.id);
|
||||||
|
}
|
35
server/Packets/StatusUpdate.js
Normal file
35
server/Packets/StatusUpdate.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
const osu = require("osu-packet"),
|
||||||
|
getUserById = require("../util/getUserById.js");
|
||||||
|
|
||||||
|
module.exports = function(currentUser, id) {
|
||||||
|
if (id == 3) return; // Ignore Bot
|
||||||
|
|
||||||
|
// Create new osu packet writer
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Get user's class
|
||||||
|
const User = getUserById(id);
|
||||||
|
|
||||||
|
if (User == null) return;
|
||||||
|
|
||||||
|
let UserStatusObject = {
|
||||||
|
userId: User.id,
|
||||||
|
status: User.actionID,
|
||||||
|
statusText: User.actionText,
|
||||||
|
beatmapChecksum: User.beatmapChecksum,
|
||||||
|
currentMods: User.currentMods,
|
||||||
|
playMode: User.playMode,
|
||||||
|
beatmapId: User.beatmapID,
|
||||||
|
rankedScore: User.rankedScore,
|
||||||
|
accuracy: User.accuracy / 100, // Scale of 0 to 1
|
||||||
|
playCount: User.playCount,
|
||||||
|
totalScore: User.totalScore,
|
||||||
|
rank: User.rank,
|
||||||
|
performance: User.pp
|
||||||
|
};
|
||||||
|
|
||||||
|
osuPacketWriter.HandleOsuUpdate(UserStatusObject);
|
||||||
|
|
||||||
|
// Send data to user's queue
|
||||||
|
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
}
|
27
server/Packets/UserPresence.js
Normal file
27
server/Packets/UserPresence.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
const osu = require("osu-packet"),
|
||||||
|
getUserById = require("../util/getUserById.js");
|
||||||
|
|
||||||
|
module.exports = function(currentUser, id) {
|
||||||
|
if (id == 3) return; // Bot
|
||||||
|
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
const User = getUserById(id);
|
||||||
|
|
||||||
|
if (User == null) return;
|
||||||
|
|
||||||
|
let UserPresenceObject = {
|
||||||
|
userId: id,
|
||||||
|
username: User.username,
|
||||||
|
timezone: 0,
|
||||||
|
countryId: User.countryID,
|
||||||
|
permissions: 4,
|
||||||
|
longitude: User.location[1],
|
||||||
|
latitude: User.location[0],
|
||||||
|
rank: User.rank
|
||||||
|
};
|
||||||
|
|
||||||
|
osuPacketWriter.UserPresence(UserPresenceObject);
|
||||||
|
|
||||||
|
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
}
|
16
server/Packets/UserPresenceBundle.js
Normal file
16
server/Packets/UserPresenceBundle.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
const osu = require("osu-packet"),
|
||||||
|
userManager = require("../userManager.js");
|
||||||
|
|
||||||
|
module.exports = function(currentUser) {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
let userIds = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
userIds.push(global.users[i].id);
|
||||||
|
}
|
||||||
|
|
||||||
|
osuPacketWriter.UserPresenceBundle(userIds);
|
||||||
|
|
||||||
|
currentUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
}
|
14
server/Packets/UserStatsRequest.js
Normal file
14
server/Packets/UserStatsRequest.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
const UserPresenceBundle = require("./UserPresenceBundle.js"),
|
||||||
|
UserPresence = require("./UserPresence.js"),
|
||||||
|
StatusUpdate = require("./StatusUpdate.js");
|
||||||
|
|
||||||
|
module.exports = function (currentUser, data) {
|
||||||
|
UserPresenceBundle(currentUser);
|
||||||
|
|
||||||
|
for (let i1 = 0; i1 < data.length; i1++) {
|
||||||
|
const CurrentUserID = data[i1];
|
||||||
|
|
||||||
|
UserPresence(currentUser, CurrentUserID);
|
||||||
|
StatusUpdate(currentUser, CurrentUserID);
|
||||||
|
}
|
||||||
|
}
|
75
server/Spectator.js
Normal file
75
server/Spectator.js
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
const osu = require("osu-packet"),
|
||||||
|
getUserById = require("./util/getUserById.js");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
startSpectatingUser:function(spectatedId, currentUser) {
|
||||||
|
// Get the user this user is trying to spectate
|
||||||
|
const User = getUserById(spectatedId);
|
||||||
|
if (global.StreamsHandler.doesStreamExist(`sp_${User.username}`)) {
|
||||||
|
// Just add user to stream since it already exists
|
||||||
|
global.StreamsHandler.addUserToStream(`sp_${User.username}`, currentUser.id);
|
||||||
|
} else {
|
||||||
|
// Stream doesn't exist, create it and add the spectator
|
||||||
|
global.StreamsHandler.addStream(`sp_${User.username}`, true, spectatedId);
|
||||||
|
global.StreamsHandler.addUserToStream(`sp_${User.username}`, currentUser.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We want to do this stuff regardless
|
||||||
|
// Create a new osu packet writer
|
||||||
|
let osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Set the user requesting to be spectating this user
|
||||||
|
currentUser.spectating = spectatedId;
|
||||||
|
|
||||||
|
// Tell the client of the user being spectated that they are being spectated
|
||||||
|
osuPacketWriter.SpectatorJoined(currentUser.id);
|
||||||
|
|
||||||
|
// Send the packet to the spectated user's queue
|
||||||
|
User.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
|
||||||
|
// Make a new clear osu packet writer
|
||||||
|
osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Tell everyone spectating this user that another user has started spectating
|
||||||
|
osuPacketWriter.FellowSpectatorJoined(currentUser.id);
|
||||||
|
|
||||||
|
// Send this packet to all the spectators
|
||||||
|
global.StreamsHandler.sendToStream(`sp_${User.username}`, osuPacketWriter.toBuffer);
|
||||||
|
},
|
||||||
|
|
||||||
|
sendSpectatorFrames(currentUser, data) {
|
||||||
|
// Create new osu packet writer
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Data containing the user's actions
|
||||||
|
osuPacketWriter.SpectateFrames(data);
|
||||||
|
|
||||||
|
// Send the frames to all the spectators
|
||||||
|
global.StreamsHandler.sendToStream(`sp_${currentUser.username}`, osuPacketWriter.toBuffer, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
stopSpectatingUser(currentUser) {
|
||||||
|
// Get the user this user is spectating
|
||||||
|
const spectatedUser = getUserById(currentUser.spectating);
|
||||||
|
// Create new osu packet writer
|
||||||
|
let osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Inform the client being spectated that this user has stopped spectating
|
||||||
|
osuPacketWriter.SpectatorLeft(currentUser.id);
|
||||||
|
|
||||||
|
// Add this packet to the spectated user's queue
|
||||||
|
spectatedUser.addActionToQueue(osuPacketWriter.toBuffer);
|
||||||
|
|
||||||
|
// Remove this user from the spectator stream
|
||||||
|
global.StreamsHandler.removeUserFromStream(`sp_${spectatedUser.username}`, currentUser.id);
|
||||||
|
|
||||||
|
// Make a new clear osu packet writer
|
||||||
|
osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
// Inform other users spectating that this spectator has left
|
||||||
|
osuPacketWriter.FellowSpectatorLeft(currentUser.id);
|
||||||
|
|
||||||
|
// Send this packet to all spectators
|
||||||
|
global.StreamsHandler.sendToStream(`sp_${spectatedUser.username}`, osuPacketWriter.toBuffer);
|
||||||
|
}
|
||||||
|
}
|
115
server/Streams.js
Normal file
115
server/Streams.js
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
const getUserById = require("./util/getUserById.js");
|
||||||
|
|
||||||
|
module.exports = class {
|
||||||
|
constructor() {
|
||||||
|
this.avaliableStreams = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
addStream(streamName, removeIfEmpty, spectatorHostId = null) {
|
||||||
|
// Add new stream to the list of streams
|
||||||
|
this.avaliableStreams[streamName] = {
|
||||||
|
streamUsers: [], // An array containing a list of user IDs of the users in a given stream
|
||||||
|
streamSpectatorHost: spectatorHostId, // null unless stream is for spectating
|
||||||
|
removeIfEmpty: removeIfEmpty
|
||||||
|
}
|
||||||
|
global.consoleHelper.printBancho(`Added stream [${streamName}]`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks if a stream has no users in it
|
||||||
|
streamChecker(interval) {
|
||||||
|
setInterval(() => {
|
||||||
|
// Get the names of all currently avaliable streams
|
||||||
|
const streams = global.StreamsHandler.getStreams();
|
||||||
|
// Loop through all streams
|
||||||
|
for (let i = 0; i < streams.length; i++) {
|
||||||
|
// Get the current stream
|
||||||
|
const currentStream = global.StreamsHandler.avaliableStreams[streams[i]];
|
||||||
|
// Check if the stream should be removed if there are no users in it
|
||||||
|
// And if the stream has no users in it
|
||||||
|
if (currentStream.removeIfEmpty && currentStream.streamUsers.length == 0) {
|
||||||
|
global.StreamsHandler.removeStream(streams[i]);
|
||||||
|
global.consoleHelper.printBancho(`Removed stream [${streams[i]}] There were no users in stream`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, interval);
|
||||||
|
global.consoleHelper.printBancho(`BinatoStream is running! Checks running at a ${interval}ms interval`);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendToStream(streamName, streamData, initUser = null) {
|
||||||
|
// Get the stream to send the data to
|
||||||
|
const currentStream = this.avaliableStreams[streamName];
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Loop through the users in this stream
|
||||||
|
for (let i = 0; i < currentStream.streamUsers.length; i++) {
|
||||||
|
// Get the user id of the user in the queue
|
||||||
|
const currentUserId = currentStream.streamUsers[i];
|
||||||
|
// Make sure we don't send this data back to the user requesting this data to be sent
|
||||||
|
if (initUser != null && currentUserId == initUser && (streamName[0] == "#" || streamName.includes("mp_"))) continue;
|
||||||
|
if (currentUserId == 3) continue; // Skip if user is bot
|
||||||
|
|
||||||
|
// Get user object
|
||||||
|
const currentUser = getUserById(currentUserId);
|
||||||
|
// Skip if user is nonexistant
|
||||||
|
if (currentUser == null) continue;
|
||||||
|
|
||||||
|
// Send stream data to user's own queue
|
||||||
|
currentUser.addActionToQueue(streamData);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
addUserToStream(streamName, userId) {
|
||||||
|
// Add user's id to the stream's user list
|
||||||
|
this.avaliableStreams[streamName].streamUsers.push(userId);
|
||||||
|
global.consoleHelper.printBancho(`Added user [${userId}] to stream ${streamName}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeUserFromStream(streamName, userId) {
|
||||||
|
// Make sure this isn't an invalid user
|
||||||
|
if (userId == -1 || userId == null) return;
|
||||||
|
try {
|
||||||
|
// Find index of user to remove
|
||||||
|
let userCurrentIndex;
|
||||||
|
for (let i = 0; i < this.avaliableStreams[streamName].streamUsers.length; i++) {
|
||||||
|
if (userId == this.avaliableStreams[streamName].streamUsers[i]) {
|
||||||
|
userCurrentIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove user from stream's user list
|
||||||
|
this.avaliableStreams[streamName].streamUsers.splice(userCurrentIndex, 1);
|
||||||
|
global.consoleHelper.printBancho(`Removed user [${userId}] from stream ${streamName}`);
|
||||||
|
} catch (e) { global.consoleHelper.printBancho(`Can't Remove user [${userId}] from stream ${streamName}`); }
|
||||||
|
}
|
||||||
|
|
||||||
|
doesStreamExist(streamName) {
|
||||||
|
let exist = false;
|
||||||
|
const streamList = Object.keys(this.avaliableStreams);
|
||||||
|
for (let i = 0; i < streamList.length; i++) {
|
||||||
|
if (streamList[i] == streamName) {
|
||||||
|
exist = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exist;
|
||||||
|
}
|
||||||
|
|
||||||
|
getStreams() {
|
||||||
|
// Return the names of all avaliable streams
|
||||||
|
return Object.keys(this.avaliableStreams);
|
||||||
|
}
|
||||||
|
|
||||||
|
isUserInStream(streamName, userId) {
|
||||||
|
if (this.avaliableStreams[streamName].streamUsers.includes(userId)) return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeStream(streamName) {
|
||||||
|
try {
|
||||||
|
delete this.avaliableStreams[streamName];
|
||||||
|
} catch (e) { global.consoleHelper.printError(`Was not able to remove stream [${streamName}]`) }
|
||||||
|
}
|
||||||
|
}
|
72
server/User.js
Normal file
72
server/User.js
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
const DatabaseHelper = require("./DatabaseHelper.js");
|
||||||
|
|
||||||
|
module.exports = class {
|
||||||
|
constructor(id, username, uuid, connectTime) {
|
||||||
|
this.id = id;
|
||||||
|
this.username = username;
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.connectTime = connectTime;
|
||||||
|
this.queue = new Buffer.alloc(0);
|
||||||
|
|
||||||
|
this.playMode = 0;
|
||||||
|
this.countryID = 0;
|
||||||
|
this.spectators = [];
|
||||||
|
this.spectating = 0;
|
||||||
|
this.location = [0,0];
|
||||||
|
this.joinedChannels = [];
|
||||||
|
this.currentMatch = null;
|
||||||
|
this.matchSlotId = -1;
|
||||||
|
|
||||||
|
// Presence data
|
||||||
|
this.actionID = 0;
|
||||||
|
this.actionText = "";
|
||||||
|
this.actionMods = 0;
|
||||||
|
this.beatmapChecksum = "";
|
||||||
|
this.beatmapID = 0;
|
||||||
|
this.currentMods = 0;
|
||||||
|
|
||||||
|
// Cached db data
|
||||||
|
this.rankedScore = 0;
|
||||||
|
this.accuracy = 0;
|
||||||
|
this.playCount = 0;
|
||||||
|
this.totalScore = 0;
|
||||||
|
this.rank = 0;
|
||||||
|
this.pp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds new actions to the user's queue
|
||||||
|
addActionToQueue(newData) {
|
||||||
|
this.queue = Buffer.concat([this.queue, newData], this.queue.length + newData.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates the user's current action
|
||||||
|
updatePresence(action) {
|
||||||
|
this.actionID = action.status;
|
||||||
|
this.actionText = action.statusText;
|
||||||
|
this.beatmapChecksum = action.beatmapChecksum;
|
||||||
|
this.currentMods = action.currentMods;
|
||||||
|
this.actionMods = action.currentMods;
|
||||||
|
this.playMode = action.playMode;
|
||||||
|
this.beatmapID = action.beatmapId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the user's score information from the database and caches it
|
||||||
|
getNewUserInformationFromDatabase() {
|
||||||
|
const userScoreDB = DatabaseHelper.getFromDB(`SELECT * FROM users_modes_info WHERE user_id = ${this.id} AND mode_id = ${this.playMode} LIMIT 1`);
|
||||||
|
const userRankDB = DatabaseHelper.getFromDB(`SELECT user_id, pp_raw, FIND_IN_SET( pp_raw, ( SELECT GROUP_CONCAT( pp_raw ORDER BY pp_raw DESC ) FROM users_modes_info WHERE mode_id = ${this.playMode} ) ) AS rank FROM users_modes_info WHERE user_id = ${this.id} AND mode_id = ${this.playMode}`);
|
||||||
|
|
||||||
|
if (userScoreDB == null || userRankDB == null) throw "fuck";
|
||||||
|
|
||||||
|
this.rankedScore = userScoreDB.ranked_score;
|
||||||
|
this.totalScore = userScoreDB.total_score;
|
||||||
|
this.accuracy = userScoreDB.avg_accuracy;
|
||||||
|
this.playCount = userScoreDB.playcount;
|
||||||
|
this.rank = userRankDB.rank;
|
||||||
|
this.pp = userScoreDB.pp_raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears out the user's queue
|
||||||
|
clearQueue() {
|
||||||
|
this.queue = new Buffer.alloc(0);
|
||||||
|
}
|
||||||
|
}
|
9
server/bakedResponses.js
Normal file
9
server/bakedResponses.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
module.exports = function(s) {
|
||||||
|
switch (s) {
|
||||||
|
case "reconnect":
|
||||||
|
return "\u0005\u0000\u0000\u0004\u0000\u0000\u0000<30><30><EFBFBD><EFBFBD>\u0018\u0000\u0000\u0011\u0000\u0000\u0000\u000b\u000fReconnecting...";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Buffer.alloc(0);
|
||||||
|
}
|
||||||
|
}
|
271
server/countryHelper.js
Normal file
271
server/countryHelper.js
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
const countryCodes = {
|
||||||
|
"LV": 132,
|
||||||
|
"AD": 3,
|
||||||
|
"LT": 130,
|
||||||
|
"KM": 116,
|
||||||
|
"QA": 182,
|
||||||
|
"VA": 0,
|
||||||
|
"PK": 173,
|
||||||
|
"KI": 115,
|
||||||
|
"SS": 0,
|
||||||
|
"KH": 114,
|
||||||
|
"NZ": 166,
|
||||||
|
"TO": 215,
|
||||||
|
"KZ": 122,
|
||||||
|
"GA": 76,
|
||||||
|
"BW": 35,
|
||||||
|
"AX": 247,
|
||||||
|
"GE": 79,
|
||||||
|
"UA": 222,
|
||||||
|
"CR": 50,
|
||||||
|
"AE": 0,
|
||||||
|
"NE": 157,
|
||||||
|
"ZA": 240,
|
||||||
|
"SK": 196,
|
||||||
|
"BV": 34,
|
||||||
|
"SH": 0,
|
||||||
|
"PT": 179,
|
||||||
|
"SC": 189,
|
||||||
|
"CO": 49,
|
||||||
|
"GP": 86,
|
||||||
|
"GY": 93,
|
||||||
|
"CM": 47,
|
||||||
|
"TJ": 211,
|
||||||
|
"AF": 5,
|
||||||
|
"IE": 101,
|
||||||
|
"AL": 8,
|
||||||
|
"BG": 24,
|
||||||
|
"JO": 110,
|
||||||
|
"MU": 149,
|
||||||
|
"PM": 0,
|
||||||
|
"LA": 0,
|
||||||
|
"IO": 104,
|
||||||
|
"KY": 121,
|
||||||
|
"SA": 187,
|
||||||
|
"KN": 0,
|
||||||
|
"OM": 167,
|
||||||
|
"CY": 54,
|
||||||
|
"BQ": 0,
|
||||||
|
"BT": 33,
|
||||||
|
"WS": 236,
|
||||||
|
"ES": 67,
|
||||||
|
"LR": 128,
|
||||||
|
"RW": 186,
|
||||||
|
"AQ": 12,
|
||||||
|
"PW": 180,
|
||||||
|
"JE": 250,
|
||||||
|
"TN": 214,
|
||||||
|
"ZW": 243,
|
||||||
|
"JP": 111,
|
||||||
|
"BB": 20,
|
||||||
|
"VN": 233,
|
||||||
|
"HN": 96,
|
||||||
|
"KP": 0,
|
||||||
|
"WF": 235,
|
||||||
|
"EC": 62,
|
||||||
|
"HU": 99,
|
||||||
|
"GF": 80,
|
||||||
|
"GQ": 87,
|
||||||
|
"TW": 220,
|
||||||
|
"MC": 135,
|
||||||
|
"BE": 22,
|
||||||
|
"PN": 176,
|
||||||
|
"SZ": 205,
|
||||||
|
"CZ": 55,
|
||||||
|
"LY": 0,
|
||||||
|
"IN": 103,
|
||||||
|
"FM": 0,
|
||||||
|
"PY": 181,
|
||||||
|
"PH": 172,
|
||||||
|
"MN": 142,
|
||||||
|
"GG": 248,
|
||||||
|
"CC": 39,
|
||||||
|
"ME": 242,
|
||||||
|
"DO": 60,
|
||||||
|
"KR": 0,
|
||||||
|
"PL": 174,
|
||||||
|
"MT": 148,
|
||||||
|
"MM": 141,
|
||||||
|
"AW": 17,
|
||||||
|
"MV": 150,
|
||||||
|
"BD": 21,
|
||||||
|
"NR": 164,
|
||||||
|
"AT": 15,
|
||||||
|
"GW": 92,
|
||||||
|
"FR": 74,
|
||||||
|
"LI": 126,
|
||||||
|
"CF": 41,
|
||||||
|
"DZ": 61,
|
||||||
|
"MA": 134,
|
||||||
|
"VG": 0,
|
||||||
|
"NC": 156,
|
||||||
|
"IQ": 105,
|
||||||
|
"BN": 0,
|
||||||
|
"BF": 23,
|
||||||
|
"BO": 30,
|
||||||
|
"GB": 77,
|
||||||
|
"CU": 51,
|
||||||
|
"LU": 131,
|
||||||
|
"YT": 238,
|
||||||
|
"NO": 162,
|
||||||
|
"SM": 198,
|
||||||
|
"GL": 83,
|
||||||
|
"IS": 107,
|
||||||
|
"AO": 11,
|
||||||
|
"MH": 138,
|
||||||
|
"SE": 191,
|
||||||
|
"ZM": 241,
|
||||||
|
"FJ": 70,
|
||||||
|
"SL": 197,
|
||||||
|
"CH": 43,
|
||||||
|
"RU": 0,
|
||||||
|
"CW": 0,
|
||||||
|
"CX": 53,
|
||||||
|
"TF": 208,
|
||||||
|
"NL": 161,
|
||||||
|
"AU": 16,
|
||||||
|
"FI": 69,
|
||||||
|
"MS": 147,
|
||||||
|
"GH": 81,
|
||||||
|
"BY": 36,
|
||||||
|
"IL": 102,
|
||||||
|
"VC": 0,
|
||||||
|
"NG": 159,
|
||||||
|
"HT": 98,
|
||||||
|
"LS": 129,
|
||||||
|
"MR": 146,
|
||||||
|
"YE": 237,
|
||||||
|
"MP": 144,
|
||||||
|
"SX": 0,
|
||||||
|
"RE": 183,
|
||||||
|
"RO": 184,
|
||||||
|
"NP": 163,
|
||||||
|
"CG": 0,
|
||||||
|
"FO": 73,
|
||||||
|
"CI": 0,
|
||||||
|
"TH": 210,
|
||||||
|
"HK": 94,
|
||||||
|
"TK": 212,
|
||||||
|
"XK": 0,
|
||||||
|
"DM": 59,
|
||||||
|
"LC": 0,
|
||||||
|
"ID": 100,
|
||||||
|
"MG": 137,
|
||||||
|
"JM": 109,
|
||||||
|
"IT": 108,
|
||||||
|
"CA": 38,
|
||||||
|
"TZ": 221,
|
||||||
|
"GI": 82,
|
||||||
|
"KG": 113,
|
||||||
|
"NU": 165,
|
||||||
|
"TV": 219,
|
||||||
|
"LB": 124,
|
||||||
|
"SY": 0,
|
||||||
|
"PR": 177,
|
||||||
|
"NI": 160,
|
||||||
|
"KE": 112,
|
||||||
|
"MO": 0,
|
||||||
|
"SR": 201,
|
||||||
|
"VI": 0,
|
||||||
|
"SV": 203,
|
||||||
|
"HM": 0,
|
||||||
|
"CD": 0,
|
||||||
|
"BI": 26,
|
||||||
|
"BM": 28,
|
||||||
|
"MW": 151,
|
||||||
|
"TM": 213,
|
||||||
|
"GT": 90,
|
||||||
|
"AG": 0,
|
||||||
|
"UM": 0,
|
||||||
|
"US": 225,
|
||||||
|
"AR": 13,
|
||||||
|
"DJ": 57,
|
||||||
|
"KW": 120,
|
||||||
|
"MY": 153,
|
||||||
|
"FK": 71,
|
||||||
|
"EG": 64,
|
||||||
|
"BA": 0,
|
||||||
|
"CN": 48,
|
||||||
|
"GN": 85,
|
||||||
|
"PS": 178,
|
||||||
|
"SO": 200,
|
||||||
|
"IM": 249,
|
||||||
|
"GS": 0,
|
||||||
|
"BR": 31,
|
||||||
|
"GM": 84,
|
||||||
|
"PF": 170,
|
||||||
|
"PA": 168,
|
||||||
|
"PG": 171,
|
||||||
|
"BH": 25,
|
||||||
|
"TG": 209,
|
||||||
|
"GU": 91,
|
||||||
|
"CK": 45,
|
||||||
|
"MF": 252,
|
||||||
|
"VE": 230,
|
||||||
|
"CL": 46,
|
||||||
|
"TR": 217,
|
||||||
|
"UG": 223,
|
||||||
|
"GD": 78,
|
||||||
|
"TT": 218,
|
||||||
|
"TL": 0,
|
||||||
|
"MD": 0,
|
||||||
|
"MK": 0,
|
||||||
|
"ST": 202,
|
||||||
|
"CV": 52,
|
||||||
|
"MQ": 145,
|
||||||
|
"GR": 88,
|
||||||
|
"HR": 97,
|
||||||
|
"BZ": 37,
|
||||||
|
"UZ": 227,
|
||||||
|
"DK": 58,
|
||||||
|
"SN": 199,
|
||||||
|
"ET": 68,
|
||||||
|
"VU": 234,
|
||||||
|
"ER": 66,
|
||||||
|
"BJ": 27,
|
||||||
|
"LK": 127,
|
||||||
|
"NA": 155,
|
||||||
|
"AS": 14,
|
||||||
|
"SG": 192,
|
||||||
|
"PE": 169,
|
||||||
|
"IR": 0,
|
||||||
|
"MX": 152,
|
||||||
|
"TD": 207,
|
||||||
|
"AZ": 18,
|
||||||
|
"AM": 9,
|
||||||
|
"BL": 0,
|
||||||
|
"SJ": 195,
|
||||||
|
"SB": 188,
|
||||||
|
"NF": 158,
|
||||||
|
"RS": 239,
|
||||||
|
"DE": 56,
|
||||||
|
"EH": 65,
|
||||||
|
"EE": 63,
|
||||||
|
"SD": 190,
|
||||||
|
"ML": 140,
|
||||||
|
"TC": 206,
|
||||||
|
"MZ": 154,
|
||||||
|
"BS": 32,
|
||||||
|
"UY": 226,
|
||||||
|
"SI": 194,
|
||||||
|
"AI": 7
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.countryCodes = countryCodes;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getCountryID:function(code) {
|
||||||
|
// Get id of a country from a 2 char code
|
||||||
|
const s = `${code}`.toUpperCase();
|
||||||
|
if (countryCodes[s] != null) return countryCodes[s];
|
||||||
|
else return 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
getCountryLetters:function(code) {
|
||||||
|
// Get country char code from id
|
||||||
|
for (var i = 0; i < countryCodes.length; i++) {
|
||||||
|
if (countryCodes[i] === code) return countryCodes[i];
|
||||||
|
}
|
||||||
|
return "XX";
|
||||||
|
}
|
||||||
|
}
|
159
server/loginHandler.js
Normal file
159
server/loginHandler.js
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
const osu = require("osu-packet"),
|
||||||
|
User = require("./User.js"),
|
||||||
|
{ v4: uuid } = require('uuid'),
|
||||||
|
request = require("sync-request"),
|
||||||
|
|
||||||
|
userManager = require("./userManager.js"),
|
||||||
|
DatabaseHelper = require("./DatabaseHelper.js"),
|
||||||
|
countryHelper = require("./countryHelper.js"),
|
||||||
|
loginHelper = require("./loginHelper.js");
|
||||||
|
|
||||||
|
module.exports = function(req, res, loginInfo) {
|
||||||
|
// Get time at the start of login
|
||||||
|
const loginStartTime = new Date().getTime();
|
||||||
|
|
||||||
|
// Check login
|
||||||
|
const loginCheck = loginHelper.checkLogin(loginInfo);
|
||||||
|
if (loginCheck != null) {
|
||||||
|
res.writeHead(200, loginCheck[1]);
|
||||||
|
return res.end(loginCheck[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get users IP for getting location
|
||||||
|
let requestIP = req.get('X-Real-IP');
|
||||||
|
if (requestIP == null) {
|
||||||
|
requestIP = req.remote_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
let userLocationData = [], userLocation;
|
||||||
|
// Check if it is a local IP
|
||||||
|
if (`${requestIP}`.includes("192.168.")) {
|
||||||
|
userLocationData.country = "GB"; // My country
|
||||||
|
userLocation = [53, -2]; // My rough location lol
|
||||||
|
} else {
|
||||||
|
// Get user's location from zxq
|
||||||
|
userLocationData = JSON.parse(request("GET", `http://ip.zxq.co/${requestIP}`).getBody());
|
||||||
|
userLocation = userLocationData.loc.split(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get information about the user from the database
|
||||||
|
const userDB = DatabaseHelper.getFromDB(`SELECT id FROM users_info WHERE username = "${loginInfo.username}" LIMIT 1`);
|
||||||
|
|
||||||
|
// Create a token for the client
|
||||||
|
const newClientToken = uuid();
|
||||||
|
|
||||||
|
// Make sure user is not already connected, kick off if so.
|
||||||
|
const checkForPreexistingUser = userManager.getUserFromUsername(loginInfo.username);
|
||||||
|
if (checkForPreexistingUser != null) {
|
||||||
|
if (checkForPreexistingUser.uuid != newClientToken) {
|
||||||
|
let userCurrentIndex;
|
||||||
|
// Find the index that the user's class is at
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
if (checkForPreexistingUser.uuid == global.users[i].uuid) {
|
||||||
|
userCurrentIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
global.users.splice(userCurrentIndex, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create user object
|
||||||
|
global.users.push(new User(userDB.id, loginInfo.username, newClientToken, new Date().getTime()));
|
||||||
|
|
||||||
|
// Retreive the newly created user
|
||||||
|
const userClass = userManager.getUserFromToken(newClientToken);
|
||||||
|
|
||||||
|
// Get user's data from the database
|
||||||
|
userClass.getNewUserInformationFromDatabase();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Save the user's location to their class for later use
|
||||||
|
userClass.location[0] = parseFloat(userLocation[0]);
|
||||||
|
userClass.location[1] = parseFloat(userLocation[1]);
|
||||||
|
|
||||||
|
// Save the country id for the same reason as above
|
||||||
|
userClass.countryID = countryHelper.getCountryID(userLocationData.country);
|
||||||
|
|
||||||
|
// We're ready to start putting together a login packet
|
||||||
|
// Create an osu! Packet 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
|
||||||
|
osuPacketWriter.LoginReply(userClass.id);
|
||||||
|
// Current bancho protocol version is 19
|
||||||
|
osuPacketWriter.ProtocolNegotiation(19);
|
||||||
|
// Permission level 4 is osu!supporter
|
||||||
|
osuPacketWriter.LoginPermissions(4);
|
||||||
|
// Send user's friends list
|
||||||
|
// TODO: friends? Haha, you have no friends!
|
||||||
|
// Set title screen image
|
||||||
|
osuPacketWriter.TitleUpdate("http://puu.sh/jh7t7/20c04029ad.png|https://osu.ppy.sh/news/123912240253");
|
||||||
|
|
||||||
|
// Construct user panel data
|
||||||
|
const presenceObject = {
|
||||||
|
userId: userClass.id,
|
||||||
|
username: userClass.username,
|
||||||
|
timezone: 0,
|
||||||
|
countryId: userClass.countryID,
|
||||||
|
permissions: 4,
|
||||||
|
longitude: userClass.location[1],
|
||||||
|
latitude: userClass.location[0],
|
||||||
|
rank: userClass.rank
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusObject = {
|
||||||
|
userId: userClass.id,
|
||||||
|
status: userClass.actionID,
|
||||||
|
statusText: userClass.actionText,
|
||||||
|
beatmapChecksum: userClass.beatmapChecksum,
|
||||||
|
currentMods: userClass.currentMods,
|
||||||
|
playMode: userClass.playMode,
|
||||||
|
beatmapId: userClass.beatmapID,
|
||||||
|
rankedScore: userClass.rankedScore,
|
||||||
|
accuracy: userClass.accuracy / 100, // Scale of 0 to 1
|
||||||
|
playCount: userClass.playCount,
|
||||||
|
totalScore: userClass.totalScore,
|
||||||
|
rank: userClass.rank,
|
||||||
|
performance: userClass.pp
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add user panel data packets
|
||||||
|
osuPacketWriter.UserPresence(presenceObject);
|
||||||
|
osuPacketWriter.HandleOsuUpdate(statusObject);
|
||||||
|
|
||||||
|
// peppy pls, why
|
||||||
|
osuPacketWriter.ChannelListingComplete();
|
||||||
|
|
||||||
|
// Add user to chat channels
|
||||||
|
osuPacketWriter.ChannelJoinSuccess("#osu");
|
||||||
|
if (!global.StreamsHandler.isUserInStream("#osu", userClass.id))
|
||||||
|
global.StreamsHandler.addUserToStream("#osu", userClass.id);
|
||||||
|
|
||||||
|
osuPacketWriter.ChannelJoinSuccess("#userlog");
|
||||||
|
if (!global.StreamsHandler.isUserInStream("#userlog", userClass.id))
|
||||||
|
global.StreamsHandler.addUserToStream("#userlog", userClass.id);
|
||||||
|
|
||||||
|
// List all channels out to the client
|
||||||
|
//for (let i = 0; i < global.channels.length; i++) {
|
||||||
|
// osuPacketWriter.ChannelAvailable(global.channels[i]);
|
||||||
|
//}
|
||||||
|
|
||||||
|
osuPacketWriter.Announce(`Welcome back ${loginInfo.username}!`);
|
||||||
|
|
||||||
|
// Complete login
|
||||||
|
res.writeHead(200, {
|
||||||
|
"cho-token": userClass.uuid,
|
||||||
|
"cho-protocol": 19,
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
"Keep-Alive": "timeout=5, max=100",
|
||||||
|
"Content-Type": "text/html; charset=UTF-8"
|
||||||
|
});
|
||||||
|
res.end(osuPacketWriter.toBuffer, () => {
|
||||||
|
global.consoleHelper.printBancho(`User login finished, took ${new Date().getTime() - loginStartTime}ms. [User: ${loginInfo.username}]`);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
37
server/loginHelper.js
Normal file
37
server/loginHelper.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
const DatabaseHelper = require("./DatabaseHelper.js"),
|
||||||
|
osu = require("osu-packet");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
checkLogin:function(loginInfo) {
|
||||||
|
// Queue up incorrect login response
|
||||||
|
const incorrectDetailsResponse = incorrectLoginResponse();
|
||||||
|
// Check if there is any login information provided
|
||||||
|
if (loginInfo == null) return incorrectDetailsResponse;
|
||||||
|
|
||||||
|
const userDBData = DatabaseHelper.getFromDB(`SELECT * FROM users_info WHERE username = "${loginInfo.username}" LIMIT 1`);
|
||||||
|
|
||||||
|
// Make sure a user was found in the database
|
||||||
|
if (Object.keys(userDBData).length < 1) return incorrectDetailsResponse;
|
||||||
|
// Make sure the username is the same as the login info
|
||||||
|
if (userDBData.username !== loginInfo.username) return incorrectDetailsResponse;
|
||||||
|
// Make sure the password is the same as the login info
|
||||||
|
if (userDBData.password !== loginInfo.password) return incorrectDetailsResponse;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function incorrectLoginResponse() {
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
osuPacketWriter.LoginReply(-1);
|
||||||
|
return [
|
||||||
|
osuPacketWriter.toBuffer,
|
||||||
|
{
|
||||||
|
'cho-token': 'No',
|
||||||
|
'cho-protocol': 19,
|
||||||
|
'Connection': 'keep-alive',
|
||||||
|
'Keep-Alive': 'timeout=5, max=100',
|
||||||
|
'Content-Type': 'text/html; charset=UTF-8'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
111
server/packetIDs.json
Normal file
111
server/packetIDs.json
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
{
|
||||||
|
"client_changeAction":0,
|
||||||
|
"client_sendPublicMessage":1,
|
||||||
|
"client_logout":2,
|
||||||
|
"client_requestStatusUpdate":3,
|
||||||
|
"client_pong":4,
|
||||||
|
"server_userID":5,
|
||||||
|
"server_commandError":6,
|
||||||
|
"server_sendMessage":7,
|
||||||
|
"server_ping":8,
|
||||||
|
"server_handleIRCUsernameChange":9,
|
||||||
|
"server_handleIRCQuit":10,
|
||||||
|
"server_userStats":11,
|
||||||
|
"server_userLogout":12,
|
||||||
|
"server_spectatorJoined":13,
|
||||||
|
"server_spectatorLeft":14,
|
||||||
|
"server_spectateFrames":15,
|
||||||
|
"client_startSpectating":16,
|
||||||
|
"client_stopSpectating":17,
|
||||||
|
"client_spectateFrames":18,
|
||||||
|
"server_versionUpdate":19,
|
||||||
|
"client_errorReport":20,
|
||||||
|
"client_cantSpectate":21,
|
||||||
|
"server_spectatorCantSpectate":22,
|
||||||
|
"server_getAttention":23,
|
||||||
|
"server_notification":24,
|
||||||
|
"client_sendPrivateMessage":25,
|
||||||
|
"server_updateMatch":26,
|
||||||
|
"server_newMatch":27,
|
||||||
|
"server_disposeMatch":28,
|
||||||
|
"client_partLobby":29,
|
||||||
|
"client_joinLobby":30,
|
||||||
|
"client_createMatch":31,
|
||||||
|
"client_joinMatch":32,
|
||||||
|
"client_partMatch":33,
|
||||||
|
"server_lobbyJoin_obsolete":34,
|
||||||
|
"server_lobbyPart_obsolete":35,
|
||||||
|
"server_matchJoinSuccess":36,
|
||||||
|
"server_matchJoinFail":37,
|
||||||
|
"client_matchChangeSlot":38,
|
||||||
|
"client_matchReady":39,
|
||||||
|
"client_matchLock":40,
|
||||||
|
"client_matchChangeSettings":41,
|
||||||
|
"server_fellowSpectatorJoined":42,
|
||||||
|
"server_fellowSpectatorLeft":43,
|
||||||
|
"client_matchStart":44,
|
||||||
|
"AllPlayersLoaded":45,
|
||||||
|
"server_matchStart":46,
|
||||||
|
"client_matchScoreUpdate":47,
|
||||||
|
"server_matchScoreUpdate":48,
|
||||||
|
"client_matchComplete":49,
|
||||||
|
"server_matchTransferHost":50,
|
||||||
|
"client_matchChangeMods":51,
|
||||||
|
"client_matchLoadComplete":52,
|
||||||
|
"server_matchAllPlayersLoaded":53,
|
||||||
|
"client_matchNoBeatmap":54,
|
||||||
|
"client_matchNotReady":55,
|
||||||
|
"client_matchFailed":56,
|
||||||
|
"server_matchComplete":58,
|
||||||
|
"client_matchHasBeatmap":59,
|
||||||
|
"client_matchSkipRequest":60,
|
||||||
|
"server_matchSkip":61,
|
||||||
|
"server_unauthorised":62,
|
||||||
|
"client_channelJoin":63,
|
||||||
|
"server_channelJoinSuccess":64,
|
||||||
|
"server_channelInfo":65,
|
||||||
|
"server_channelKicked":66,
|
||||||
|
"server_channelAvailableAutojoin":67,
|
||||||
|
"client_beatmapInfoRequest":68,
|
||||||
|
"server_beatmapInfoReply":69,
|
||||||
|
"client_matchTransferHost":70,
|
||||||
|
"server_supporterGMT":71,
|
||||||
|
"server_friendsList":72,
|
||||||
|
"client_friendAdd":73,
|
||||||
|
"client_friendRemove":74,
|
||||||
|
"server_protocolVersion":75,
|
||||||
|
"server_mainMenuIcon":76,
|
||||||
|
"client_matchChangeTeam":77,
|
||||||
|
"client_channelPart":78,
|
||||||
|
"client_receiveUpdates":79,
|
||||||
|
"server_topBotnet":80,
|
||||||
|
"server_matchPlayerSkipped":81,
|
||||||
|
"client_setAwayMessage":82,
|
||||||
|
"server_userPanel":83,
|
||||||
|
"IRC_only":84,
|
||||||
|
"client_userStatsRequest":85,
|
||||||
|
"server_restart":86,
|
||||||
|
"client_invite":87,
|
||||||
|
"server_invite":88,
|
||||||
|
"server_channelInfoEnd":89,
|
||||||
|
"client_matchChangePassword":90,
|
||||||
|
"server_matchChangePassword":91,
|
||||||
|
"server_silenceEnd":92,
|
||||||
|
"client_specialMatchInfoRequest":93,
|
||||||
|
"server_userSilenced":94,
|
||||||
|
"server_userPresenceSingle":95,
|
||||||
|
"server_userPresenceBundle":96,
|
||||||
|
"client_userPresenceRequest":97,
|
||||||
|
"client_userPresenceRequestAll":98,
|
||||||
|
"client_userToggleBlockNonFriendPM":99,
|
||||||
|
"server_userPMBlocked":100,
|
||||||
|
"server_targetIsSilenced":101,
|
||||||
|
"server_versionUpdateForced":102,
|
||||||
|
"server_switchServer":103,
|
||||||
|
"server_accountRestricted":104,
|
||||||
|
"server_jumpscare":105,
|
||||||
|
"client_matchAbort":106,
|
||||||
|
"server_switchTourneyServer":107,
|
||||||
|
"client_specialJoinMatchChannel":108,
|
||||||
|
"client_specialLeaveMatchChannel":109
|
||||||
|
}
|
253
server/serverHandler.js
Normal file
253
server/serverHandler.js
Normal file
|
@ -0,0 +1,253 @@
|
||||||
|
const osu = require("osu-packet"),
|
||||||
|
packetIDs = require("./packetIDs.json"),
|
||||||
|
loginHandler = require("./loginHandler.js"),
|
||||||
|
parseUserData = require("./util/parseUserData.js"),
|
||||||
|
userManager = require("./userManager.js"),
|
||||||
|
User = require("./User.js"),
|
||||||
|
bakedResponses = require("./bakedResponses.js"),
|
||||||
|
Streams = require("./Streams.js");
|
||||||
|
|
||||||
|
global.users = [
|
||||||
|
new User(3, "BeanchoBot", "BeanchoBot", new Date().getTime())
|
||||||
|
];
|
||||||
|
|
||||||
|
// Start a loop that gets new data for users from the database for use on the user panel
|
||||||
|
setInterval(() => {
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
const User = global.users[i];
|
||||||
|
if (User.id == 3) continue; // Ignore the bot
|
||||||
|
// Bot: :(
|
||||||
|
|
||||||
|
User.getNewUserInformationFromDatabase();
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
// Set the bot's position on the map
|
||||||
|
global.users[0].location[0] = 50;
|
||||||
|
global.users[0].location[1] = -32;
|
||||||
|
|
||||||
|
// An array containing all currently active multiplayer matches
|
||||||
|
global.matches = [];
|
||||||
|
// An array containing the last 15 messages in chat
|
||||||
|
// TODO: Bother making this
|
||||||
|
global.chatHistory = [];
|
||||||
|
global.StreamsHandler = new Streams();
|
||||||
|
|
||||||
|
// An array containing all chat channels
|
||||||
|
// TODO: Send user chat channels and not have osu! crash
|
||||||
|
global.channels = [
|
||||||
|
{ channelName:"#osu", channelTopic:"The main channel", channelUserCount: 0 },
|
||||||
|
{ channelName:"#userlog", channelTopic:"Log about stuff doing go on yes very", channelUserCount: 0 },
|
||||||
|
{ channelName:"#lobby", channelTopic:"Talk about multiplayer stuff", channelUserCount: 0 },
|
||||||
|
{ channelName:"#english", channelTopic:"Talk in exclusively English", channelUserCount: 0 },
|
||||||
|
{ channelName:"#japanese", channelTopic:"Talk in exclusively Japanese", channelUserCount: 0 },
|
||||||
|
];
|
||||||
|
|
||||||
|
// Create a stream for each chat channel
|
||||||
|
for (let i = 0; i < global.channels.length; i++) {
|
||||||
|
global.StreamsHandler.addStream(global.channels[i].channelName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a stream for the multiplayer lobby
|
||||||
|
global.StreamsHandler.addStream("multiplayer_lobby", false);
|
||||||
|
|
||||||
|
// Start stream checking interval
|
||||||
|
global.StreamsHandler.streamChecker(5000);
|
||||||
|
|
||||||
|
// Include packets
|
||||||
|
const ChangeAction = require("./Packets/ChangeAction.js"),
|
||||||
|
SendPublicMessage = require("./Packets/SendPublicMessage.js"),
|
||||||
|
Logout = require("./Packets/Logout.js"),
|
||||||
|
Spectator = require("./Spectator.js"),
|
||||||
|
Multiplayer = require("./Multiplayer.js"),
|
||||||
|
ChannelPart = require("./Packets/ChannelPart.js"),
|
||||||
|
UserPresenceBundle = require("./Packets/UserPresenceBundle.js"),
|
||||||
|
UserPresence = require("./Packets/UserPresence.js"),
|
||||||
|
UserStatsRequest = require("./Packets/UserStatsRequest.js");
|
||||||
|
|
||||||
|
module.exports = function(req, res) {
|
||||||
|
// Get the client's token string and request data
|
||||||
|
const requestTokenString = req.header("osu-token"),
|
||||||
|
requestData = req.packet;
|
||||||
|
|
||||||
|
// Server's response & new client token
|
||||||
|
let responseTokenString = "",
|
||||||
|
responseData = new Buffer.alloc(0);
|
||||||
|
|
||||||
|
// Check if the user is logged in
|
||||||
|
if (requestTokenString == null) {
|
||||||
|
// Client doesn't have a token yet, let's auth them!
|
||||||
|
const userData = parseUserData(requestData);
|
||||||
|
global.consoleHelper.printBancho(`New client connection. [User: ${userData.username}]`);
|
||||||
|
loginHandler(req, res, userData);
|
||||||
|
} else {
|
||||||
|
// Client has a token, let's see what they want.
|
||||||
|
try {
|
||||||
|
// Get the current user
|
||||||
|
const userClass = userManager.getUserFromToken(requestTokenString);
|
||||||
|
|
||||||
|
// Make sure the client's token isn't invalid
|
||||||
|
if (userClass != null) {
|
||||||
|
// Create a new osu! packet reader
|
||||||
|
const osuPacketReader = new osu.Client.Reader(requestData);
|
||||||
|
// Parse current bancho packet
|
||||||
|
const PacketData = osuPacketReader.Parse();
|
||||||
|
// Loop through parsed packet data
|
||||||
|
for (let i = 0; i < PacketData.length; i++) {
|
||||||
|
// Get current packet
|
||||||
|
let CurrentPacket = PacketData[i];
|
||||||
|
|
||||||
|
// Create a new bancho packet writer per packet
|
||||||
|
const osuPacketWriter = new osu.Bancho.Writer;
|
||||||
|
|
||||||
|
switch (CurrentPacket.id) {
|
||||||
|
case packetIDs.client_changeAction:
|
||||||
|
ChangeAction(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_sendPublicMessage:
|
||||||
|
SendPublicMessage(CurrentPacket, userClass);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_logout:
|
||||||
|
Logout(userClass);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_requestStatusUpdate:
|
||||||
|
UserPresenceBundle(userClass);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_pong:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_startSpectating:
|
||||||
|
Spectator.startSpectatingUser(CurrentPacket.data, userClass);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_spectateFrames:
|
||||||
|
Spectator.sendSpectatorFrames(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_stopSpectating:
|
||||||
|
Spectator.stopSpectatingUser(userClass);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_joinLobby:
|
||||||
|
Multiplayer.userEnterLobby(userClass);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_createMatch:
|
||||||
|
Multiplayer.createMultiplayerMatch(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_joinMatch:
|
||||||
|
Multiplayer.joinMultiplayerMatch(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchChangeSlot:
|
||||||
|
Multiplayer.moveToSlot(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchReady:
|
||||||
|
Multiplayer.setReadyState(userClass, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchChangeSettings:
|
||||||
|
Multiplayer.updateMatch(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchNotReady:
|
||||||
|
Multiplayer.setReadyState(userClass, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_partMatch:
|
||||||
|
Multiplayer.leaveMatch(userClass);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchLock: // Also handles user kick
|
||||||
|
Multiplayer.kickPlayer(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchNoBeatmap:
|
||||||
|
Multiplayer.missingBeatmap(userClass, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchHasBeatmap:
|
||||||
|
Multiplayer.missingBeatmap(userClass, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchTransferHost:
|
||||||
|
Multiplayer.transferHost(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchChangeMods:
|
||||||
|
Multiplayer.updateMods(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchStart:
|
||||||
|
Multiplayer.startMatch(userClass);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchLoadComplete:
|
||||||
|
Multiplayer.setPlayerLoaded(userClass);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchComplete:
|
||||||
|
Multiplayer.onPlayerFinishMatch(userClass);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchScoreUpdate:
|
||||||
|
Multiplayer.updatePlayerScore(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_matchFailed:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_channelJoin:
|
||||||
|
// TODO: Implement user channel joining
|
||||||
|
// Auto channel joining is already complete
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_channelPart:
|
||||||
|
ChannelPart(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_userStatsRequest:
|
||||||
|
UserStatsRequest(userClass, CurrentPacket.data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case packetIDs.client_userPresenceRequest:
|
||||||
|
UserPresence(userClass, userClass.id);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Ignore client_beatmapInfoRequest and client_receiveUpdates
|
||||||
|
if (CurrentPacket.id == 68 || CurrentPacket.id == 79) break;
|
||||||
|
// Print out unimplemented packet
|
||||||
|
console.dir(CurrentPacket);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put current user queue into response data
|
||||||
|
responseData = Buffer.concat([responseData, userClass.queue], responseData.length + userClass.queue.length);
|
||||||
|
userClass.clearQueue();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// User's token is invlid, force a reconnect
|
||||||
|
global.consoleHelper.printBancho(`Forced client re-login (Token is invalid)`);
|
||||||
|
responseData = bakedResponses("reconnect");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
} finally {
|
||||||
|
// Send the prepared packet to the client
|
||||||
|
res.writeHead(200, {
|
||||||
|
"cho-protocol": 19,
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
"Keep-Alive": "timeout=5, max=100",
|
||||||
|
"Content-Type": "text/html; charset=UTF-8"
|
||||||
|
});
|
||||||
|
res.end(responseData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
55
server/userManager.js
Normal file
55
server/userManager.js
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
module.exports = {
|
||||||
|
getUserFromID:function(id) {
|
||||||
|
let userToReturn;
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
if (global.users[i].id == id) {
|
||||||
|
userToReturn = global.users[i];
|
||||||
|
i = global.users.length;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return userToReturn;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUserFromUsername:function(username) {
|
||||||
|
let userToReturn;
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
if (global.users[i].username == username) {
|
||||||
|
userToReturn = global.users[i];
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return userToReturn;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUserFromToken:function(token) {
|
||||||
|
let userToReturn;
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
if (global.users[i].uuid == token) {
|
||||||
|
userToReturn = global.users[i];
|
||||||
|
i = global.users.length;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return userToReturn;
|
||||||
|
},
|
||||||
|
|
||||||
|
queueActionForAll:function(action) {
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
global.users[i].addActionToQueue(action);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
queueActionForAllWithoutCallingUser:function(action, token) {
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
if (global.users[i].uuid == token) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
global.users[i].addActionToQueue(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
server/util/getUserById.js
Normal file
10
server/util/getUserById.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
module.exports = function(id) {
|
||||||
|
let user = null;
|
||||||
|
for (let i = 0; i < global.users.length; i++) {
|
||||||
|
if (global.users[i].id == id) {
|
||||||
|
user = global.users[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user;
|
||||||
|
}
|
33
server/util/parseUserData.js
Normal file
33
server/util/parseUserData.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
module.exports = function(packet) {
|
||||||
|
try {
|
||||||
|
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 n = s[2].split('|'); // Split osuversion|blablabla|blablabla to a object.
|
||||||
|
const username = s[0]; // Username ofc
|
||||||
|
const password = s[1]; // Password ofc
|
||||||
|
const osuversion = n[0]; // OsuVersion ofc.
|
||||||
|
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
|
||||||
|
|
||||||
|
// If some data is not set OR is invailed throw errors
|
||||||
|
if (username == undefined) throw 'UserName';
|
||||||
|
if (password == undefined) throw 'password';
|
||||||
|
if (osuversion == undefined) throw 'osuversion';
|
||||||
|
if (TimeOffset == undefined) throw 'offset';
|
||||||
|
if (clientData == undefined) throw 'clientData';
|
||||||
|
|
||||||
|
// Everything alright? return parsed data.
|
||||||
|
const obj = {
|
||||||
|
username: String(username),
|
||||||
|
password: String(password),
|
||||||
|
osuversion: String(osuversion),
|
||||||
|
timeoffset: Number(TimeOffset),
|
||||||
|
clientdata: String(clientData)
|
||||||
|
};
|
||||||
|
// Here is the return.
|
||||||
|
return obj;
|
||||||
|
} catch (ex) {
|
||||||
|
// Else return undefined, that the login request got broke.
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
18
web/serverPage.html
Normal file
18
web/serverPage.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Binato</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre style="border-style:double;border-width:4px;width:376px;">
|
||||||
|
|
||||||
|
. o ..
|
||||||
|
o . o o.o |isdebug?|
|
||||||
|
...oo
|
||||||
|
__[]__ Binato
|
||||||
|
__|_o_o_o\__ A custom osu!Bancho
|
||||||
|
\""""""""""/
|
||||||
|
\. .. . / <a href="http://osu-tgp.ml">Website</a> | <a href="https://github.com/tgpethan">Github</a>
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue