Commit ae02c048 authored by Hugo Denizart's avatar Hugo Denizart
Browse files

Merge branch '25-add-multiplayer-scores-sorting' into 'master'

Resolve "Add multiplayer scores sorting"

Closes #25

See merge request !2
parents 411bcffc fd5c3b6e
Loading
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
const Banchojs = require(".."); // Replace .. by bancho.js when coding outside of the library
const client = new Banchojs.BanchoClient(require("../config.json"));
const threshold = new Date("2014-01-01");
const channelName = "#mp_43508978";

client.connect().then(async () => {
	console.log("We're online!");
	const channel = client.getChannel(channelName);
	await channel.join();
	const lobby = channel.lobby;
	if(lobby == null)
		throw new Error("missing api key");

	console.log("Multiplayer link: https://osu.ppy.sh/mp/"+lobby.id);

	lobby.on("beatmap", async (beatmap) => {
		if(beatmap != null && Math.max(beatmap.lastUpdate.getTime(), beatmap.approvedDate.getTime()) > threshold.getTime())
			await channel.sendMessage("This beatmap is too recent! Only beatmaps ranked in 2013 and before are accepted.");
	});
}).catch(console.error);

process.on("SIGINT", async () => {
	console.log("Disconnecting...");
	await client.disconnect();
});
 No newline at end of file
+28 −0
Original line number Diff line number Diff line
const Banchojs = require(".."); // Replace .. by bancho.js when coding outside of the library
const client = new Banchojs.BanchoClient(require("../config.json"));

client.connect().then(async () => {
	console.log("We're online!");
	const channel = client.getChannel("#mp_43508978");
	await channel.join();
	const lobby = channel.lobby;
	if(lobby == null)
		throw new Error("missing api key");

	console.log("Multiplayer link: https://osu.ppy.sh/mp/"+lobby.id);

	lobby.on("matchStart", () => {
		console.log("Match on "+lobby.beatmap.id+" started...");
	});

	lobby.on("matchFinished", (scores) => {
		console.log("Results are in!");
		for(let scoreId in scores)
			console.log("#"+(Number(scoreId)+1)+": "+scores[scoreId].player.user.username+" "+scores[scoreId].score+" "+scores[scoreId].pass);
	});
}).catch(console.error);

process.on("SIGINT", async () => {
	console.log("Disconnecting...");
	await client.disconnect();
});
 No newline at end of file
+9 −0
Original line number Diff line number Diff line
@@ -310,6 +310,10 @@ declare module "bancho.js" {
		 * Multiplayer lobby ID (used in multiplayer history links)
		 */
		id: number
		/**
		 * Multiplayer lobby ID (used in multiplayer history links)
		 */
		scores: Array<BanchoLobbyPlayerScore>
		/**
		 * Name of the lobby, as seein in-game
		 */
@@ -490,6 +494,11 @@ declare module "bancho.js" {
		 */
		getHistoryUrl(): string

		/**
		 * Sort scores by pass and score.
		 */
		sortScores(): void


		on(event: "allPlayersReady", listener: () => void): this
		/**
+40 −5
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ const Teams = require("./Enums/BanchoLobbyTeams");
 * @prop {Array<BanchoMod>} mods 
 * @prop {boolean} freemod
 * @prop {boolean} playing Whether we're currently playing or not
 * @prop {Array<BanchoLobbyPlayerScore>} scores Scores set during the currently ongoing match, or the previous match. Emptied when a new match starts. Sorted by pass and score once match is finished.
 */
class BanchoLobby extends EventEmitter {
	constructor(channel) {
@@ -30,6 +31,7 @@ class BanchoLobby extends EventEmitter {
		this.channel = channel;
		this.banchojs = this.channel.banchojs;
		this.id = Number(channel.name.substring("#mp_".length));
		this.scores = [];
		this._name = "";
		this._beatmapId = null;
		this._beatmap = null;
@@ -289,6 +291,7 @@ class BanchoLobby extends EventEmitter {
							player.score = null;
						}
					}
					this.scores.length = 0;
					this.playing = true;
					this.emit("matchStarted");
					break;
@@ -299,19 +302,33 @@ class BanchoLobby extends EventEmitter {
					 */
					this.getPlayerByName(ret.username).then((player) => {
						player.score = new BanchoLobbyPlayerScore(ret.score, ret.pass, player);
						this.scores.push(player.score);
						this.emit("playerFinished", player.score);
					}, (err) => this.banchojs.emit("error", err));
					break;
				case "matchFinished":
				case "matchAborted":
					/**
					 * @event BanchoLobby#matchFinished
					 */
					/**
					 * @event BanchoLobby#matchAborted
					 */
					this.playing = false;
					this.emit(regex.name);
					this.emit("matchAborted");
					break;
				case "matchFinished":
					/**
					 * @event BanchoLobby#matchFinished
					 * @type {Array.<BanchoLobbyPlayerScore>} Sorted scores array
					 */
					// Due to players resolving, matchFinished may be emitted and scores sorted before every playerFinished are done being processed.
					// For some reason, even though a Promise may not have anything async, the "then" functions may still be executed asynchronously...
					// However, they seem to be executed in order for some reason. So a workaround for this is to wait for the callback of a resolved Promise to be called.
					Promise.resolve().then(() => {
						// This ensures sorting/emitting is executed after all names are resolved.
						this.pushPlayerCreationQueue(() => {
							this.sortScores();
							this.emit(regex.name, this.scores);
							this.playersCreationCallback();
						});
					});					
					break;
				case "invalidBeatmapId":
				case "passwordRemoved":
@@ -944,6 +961,24 @@ class BanchoLobby extends EventEmitter {
		return Object.seal(slots);
	}

	/**
	 * Sort scores by pass and score.
	 */
	sortScores() {
		this.scores.sort((a, b) => {
			if(a.pass && !b.pass)
				return -1;
			else if(!a.pass && b.pass)
				return 1;
			else if(a.score > b.score)
				return -1;
			else if(b.score > a.score)
				return 1;
			else
				return 0;
		});
	}

	get beatmap() {
		return this._beatmap;
	}
+1 −1
Original line number Diff line number Diff line
@@ -185,7 +185,7 @@ module.exports = {
				const m = r.exec(str);
				return {
					username: m[1],
					score: m[2],
					score: Number(m[2]),
					pass: m[3] == "PASS"
				};
			}
Loading