Binato/server/objects/User.ts

162 lines
4.4 KiB
TypeScript
Raw Normal View History

2023-09-10 12:59:22 +01:00
import LatLng from "./LatLng";
2022-11-16 15:25:46 +00:00
import { RankingModes } from "../enums/RankingModes";
2023-09-10 12:59:22 +01:00
import Match from "./Match";
import DataStream from "./DataStream";
import StatusUpdate from "../packets/StatusUpdate";
import Shared from "../objects/Shared";
import Slot from "./Slot";
2023-09-10 18:32:45 +01:00
import Channel from "./Channel";
2022-11-16 15:25:46 +00:00
const rankingModes = [
"pp_raw",
"ranked_score",
"avg_accuracy"
];
2023-09-10 12:59:22 +01:00
export default class User {
2022-11-16 15:25:46 +00:00
private static readonly EMPTY_BUFFER = Buffer.alloc(0);
2023-08-20 13:03:01 +01:00
public shared:Shared;
2022-11-19 01:06:03 +00:00
2022-11-16 15:25:46 +00:00
public id:number;
public username:string;
public uuid:string;
public readonly connectTime:number = Date.now();
public timeoutTime:number = Date.now() + 30000;
public queue:Buffer = User.EMPTY_BUFFER;
// Binato data
public rankingMode:RankingModes = RankingModes.PP;
2022-11-27 17:37:28 +00:00
public spectatorStream?:DataStream;
public spectatingUser?:User;
2022-11-16 15:25:46 +00:00
// osu! data
public playMode:number = 0;
public countryID:number = 0;
public location:LatLng = new LatLng(0, 0);
public joinedChannels:Array<string> = new Array<string>();
// Presence data
public actionID:number = 0;
public actionText:string = "";
public actionMods:number = 0;
public beatmapChecksum:string = "";
public beatmapID:number = 0;
public currentMods:number = 0;
// Cached db data
public rankedScore:number = 0;
public accuracy:number = 0;
public playCount:number = 0;
public totalScore:number = 0;
public rank:number = 0;
public pp:number = 0;
// Multiplayer data
2022-11-23 00:48:28 +00:00
public match?:Match;
public matchSlot?:Slot;
public get inMatch() {
return this.match instanceof Match;
}
2022-11-16 15:25:46 +00:00
// Tournament client flag
public isTourneyUser:boolean = false;
2022-11-23 00:48:28 +00:00
static Equals(user0:User, user1:User) {
return user0.uuid === user1.uuid;
}
2023-08-20 13:03:01 +01:00
public constructor(id:number, username:string, uuid:string, shared:Shared) {
2022-11-16 15:25:46 +00:00
this.id = id;
this.username = username;
this.uuid = uuid;
2023-08-20 13:03:01 +01:00
this.shared = shared;
2022-11-16 15:25:46 +00:00
}
// Concats new actions to the user's queue
public addActionToQueue(newData:Buffer) {
this.queue = Buffer.concat([this.queue, newData], this.queue.length + newData.length);
}
clearQueue() {
this.queue = User.EMPTY_BUFFER;
}
// Updates the user's current action
2023-08-20 13:03:01 +01:00
updatePresence(action:any) {
2022-11-16 15:25:46 +00:00
this.actionID = action.status;
this.actionText = action.statusText;
this.beatmapChecksum = action.beatmapChecksum;
this.currentMods = action.currentMods;
this.actionMods = action.currentMods;
if (action.playMode != this.playMode) {
this.updateUserInfo(true);
this.playMode = action.playMode;
}
this.beatmapID = action.beatmapId;
}
// Gets the user's score information from the database and caches it
2023-08-20 13:03:01 +01:00
async updateUserInfo(forceUpdate:boolean = false) {
const userScoreDB = await this.shared.database.query("SELECT * FROM users_modes_info WHERE user_id = ? AND mode_id = ? LIMIT 1", [this.id, this.playMode]);
2022-11-16 15:25:46 +00:00
const mappedRankingMode = rankingModes[this.rankingMode];
2023-08-20 13:03:01 +01:00
const userRankDB = await this.shared.database.query(`SELECT user_id, ${mappedRankingMode} FROM users_modes_info WHERE mode_id = ? ORDER BY ${mappedRankingMode} DESC`, [this.playMode]);
2022-11-16 15:25:46 +00:00
if (userScoreDB == null || userRankDB == null) throw "fuck";
// Handle "if we should update" checks for each rankingMode
let userScoreUpdate = false;
switch (this.rankingMode) {
case RankingModes.PP:
if (this.pp != userScoreDB.pp_raw)
userScoreUpdate = true;
break;
case RankingModes.RANKED_SCORE:
if (this.rankedScore != userScoreDB.ranked_score)
userScoreUpdate = true;
break;
case RankingModes.AVG_ACCURACY:
if (this.accuracy != userScoreDB.avg_accuracy)
userScoreUpdate = true;
break;
}
this.rankedScore = userScoreDB.ranked_score;
this.totalScore = userScoreDB.total_score;
this.accuracy = userScoreDB.avg_accuracy;
this.playCount = userScoreDB.playcount;
// Fetch rank
for (let i = 0; i < userRankDB.length; i++) {
if (userRankDB[i]["user_id"] == this.id) {
this.rank = i + 1;
break;
}
}
// Set PP to none if ranking mode is not PP
if (this.rankingMode == 0) this.pp = userScoreDB.pp_raw;
else this.pp = 0;
if (userScoreUpdate || forceUpdate) {
2022-11-19 15:06:03 +00:00
StatusUpdate(this, this.id);
2022-11-16 15:25:46 +00:00
}
}
2023-09-10 18:32:45 +01:00
joinChannel(channelName:string) {
const channel = this.shared.chatManager.GetChannelByName(channelName);
if (channel instanceof Channel) {
channel.Join(this);
}
}
leaveChannel(channelName:string) {
const channel = this.shared.chatManager.GetChannelByName(channelName);
if (channel instanceof Channel) {
channel.Leave(this);
}
}
2022-11-16 15:25:46 +00:00
}