Files
Vanadium-2023-2025-Leak-Server/Classes/DBs/LeaderboardDB.cs
T
skidfire fe3468c65d yikes,
2026-09-06 19:59:27 -04:00

342 lines
13 KiB
C#

using LiteDB;
using Vanadium.Classes.DBs.DBClasses;
using static Vanadium.Classes.DBs.DBClasses.LeaderboardDBClasses;
using static Vanadium.Classes.DBs.DBClasses.PlayerDBClasses;
using Vanadium.Controllers;
using Vanadium.Utils.NotiController;
namespace Vanadium.Classes.DBs
{
public class LeaderboardDB
{
public static LiteDatabase LeaderboardDBFile = new LiteDatabase("Filename=" + Path.Join(Program.dataDir, "DBs", "Leaderboard.db") + ";Connection=shared");
public static readonly ILiteCollection<LeaderboardEntry> Entries = LeaderboardDBFile.GetCollection<LeaderboardEntry>("Entries");
public static void Setup()
{
Entries.EnsureIndex(x => x.PlayerId);
Entries.EnsureIndex(x => x.RoomId);
Entries.EnsureIndex(x => x.StatChannel);
Entries.EnsureIndex(x => x.FilterType);
}
private static long GetNextEntryId()
{
if (Entries.Count() == 0) return 1;
return Entries.Max(x => x.EntryId) + 1;
}
private static int ComputeRank(long roomId, int statChannel, long playerId, int score)
{
return Entries.Count(x =>
x.RoomId == roomId &&
x.StatChannel == statChannel &&
(x.Score > score || (x.Score == score && x.PlayerId < playerId)));
}
private static bool IsRRORoom(long roomId)
{
var room = RoomDB.Rooms.FindById(roomId);
if (room == null) return false;
if (room.IsRRO) return true;
return room.Tags != null && room.Tags.Any(t =>
t.Tag.Equals("rro", StringComparison.OrdinalIgnoreCase) ||
t.Tag.Equals("recroomoriginal", StringComparison.OrdinalIgnoreCase));
}
public static int ClearRoomLeaderboard(long roomId)
{
return Entries.DeleteMany(x => x.RoomId == roomId);
}
private static async Task BanPlayerForLeaderboardAbuse(long playerId, int type = 0)
{
var player = PlayerDB.Players.FindById(playerId);
if (player == null) return;
var msg = "Cheating";
var mbd = new ModerationBlockDetails
{
IsBan = true,
ReportCategory = ReportCategory.Moderator,
Duration = 2147483647,
Message = msg,
ModerationSetUnixTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
};
player.Player ??= new Player();
player.Player.PlayerExtra ??= new PlayerExtra();
player.Player.PlayerExtra.ModerationBlockDetails = mbd;
player.Player.PlayerExtra.Heartbeat = new Heartbeat
{
playerId = playerId,
isOnline = false,
roomInstance = null,
errorCode = 0
};
PlayerDB.Players.Update(player);
await NotiController.SendPresenceUpdate(playerId, player.Player.PlayerExtra.Heartbeat);
await NotiController.SendAccountUpdate(playerId, PlayerDB.GetAccountMe(playerId));
await NotificationsController.SendBanned(playerId, mbd);
}
public static GetRanksResponse GetRanks(GetRanksRequest request)
{
int rankStart = request.RankStart < 0 ? 0 : request.RankStart;
int limit = request.RankEnd - rankStart + 1;
if (limit <= 0)
return new GetRanksResponse { rows = new List<LeaderboardRow>() };
var entries = Entries
.Find(x => x.RoomId == request.RoomId && x.StatChannel == request.StatChannel)
.OrderBy(x => request.SortAscending ? x.Score : -x.Score)
.ThenBy(x => x.PlayerId)
.Skip(rankStart)
.Take(limit)
.ToList();
var rows = entries.Select((e, i) => new LeaderboardRow
{
playerId = e.PlayerId,
rank = rankStart + i,
score = e.Score
}).ToList();
return new GetRanksResponse { rows = rows };
}
public static LeaderboardRow GetPlayerRank(GetRanksRequest request)
{
var entry = Entries.FindOne(x =>
x.PlayerId == request.PlayerId &&
x.RoomId == request.RoomId &&
x.StatChannel == request.StatChannel);
if (entry != null)
{
return new LeaderboardRow
{
playerId = request.PlayerId,
rank = ComputeRank(request.RoomId, request.StatChannel, request.PlayerId, entry.Score),
score = entry.Score
};
}
int total = Entries.Count(x => x.RoomId == request.RoomId && x.StatChannel == request.StatChannel);
return new LeaderboardRow
{
playerId = request.PlayerId,
rank = total,
score = 0
};
}
public static GetNearbyScoresResponse GetNearbyScores(GetNearbyScoresRequest request)
{
int windowSize = request.WindowSize <= 0 ? 10 : request.WindowSize;
var all = Entries
.Find(x => x.RoomId == request.RoomId && x.StatChannel == request.StatChannel)
.OrderBy(x => request.SortAscending ? x.Score : -x.Score)
.ThenBy(x => x.PlayerId)
.ToList();
if (all.Count == 0)
return new GetNearbyScoresResponse { rows = new List<LeaderboardRow>() };
int center = all.Count;
for (int i = 0; i < all.Count; i++)
{
if (all[i].PlayerId == request.PlayerId)
{
center = i;
break;
}
}
int half = windowSize / 2;
int start = center - half;
int end = start + windowSize;
if (start < 0)
{
end -= start;
start = 0;
}
if (end > all.Count)
{
end = all.Count;
start = end - windowSize;
if (start < 0)
start = 0;
}
var rows = new List<LeaderboardRow>();
for (int i = start; i < end; i++)
{
rows.Add(new LeaderboardRow
{
playerId = all[i].PlayerId,
rank = i,
score = all[i].Score
});
}
return new GetNearbyScoresResponse { rows = rows };
}
public static async Task<CheckAndSetStatResponse> CheckAndSetStat(long playerId, CheckAndSetStatRequest request)
{
//Console.WriteLine($"[LeaderboardDB] CheckAndSetStat called for playerId: {playerId}, roomId: {request.RoomId}, statChannel: {request.StatChannel}, statValue: {request.StatValue}, currentStatValue: {request.CurrentStatValue}");
const int RROSuspiciousMin = 1147483647;
const int RROSuspiciousMax = 2147383647;
if (IsRRORoom(request.RoomId) && request.StatValue >= RROSuspiciousMin && request.StatValue <= RROSuspiciousMax)
{
await BanPlayerForLeaderboardAbuse(playerId);
var existing = Entries.FindOne(x =>
x.PlayerId == playerId &&
x.RoomId == request.RoomId &&
x.StatChannel == request.StatChannel);
if (existing == null)
{
existing = new LeaderboardEntry
{
EntryId = GetNextEntryId(),
PlayerId = playerId,
RoomId = request.RoomId,
StatChannel = request.StatChannel,
FilterType = 0,
Score = 0,
UpdatedAt = DateTime.UtcNow
};
Entries.Insert(existing);
}
else
{
existing.Score = 0;
existing.UpdatedAt = DateTime.UtcNow;
Entries.Update(existing);
}
int bannedRank = ComputeRank(request.RoomId, request.StatChannel, playerId, 0);
return new CheckAndSetStatResponse
{
error = null,
success = true,
value = new LeaderboardRow
{
playerId = playerId,
rank = bannedRank,
score = 0
}
};
}
Console.WriteLine($"[LeaderboardDB] Proceeding with normal stat update for playerId: {playerId}, roomId: {request.RoomId}, statChannel: {request.StatChannel}, statValue: {request.StatValue}, currentStatValue: {request.CurrentStatValue}");
var entry = Entries.FindOne(x =>
x.PlayerId == playerId &&
x.RoomId == request.RoomId &&
x.StatChannel == request.StatChannel);
int msg;
switch (request.StatChannel)
{
case 0:
msg = 0;
break;
case 1:
msg = 3;
break;
default:
msg = 0;
break;
}
Console.WriteLine($"[LeaderboardDB] RoomId: {request.RoomId}, typeof: {request.RoomId.GetType()}");
if (request.RoomId == 4974)
{
Console.WriteLine($"[LeaderboardDB] PlayerId: {playerId}, typeof: {playerId.GetType()}");
int tokensToGrant = request.StatValue - request.CurrentStatValue;
Console.WriteLine($"[LeaderboardDB] Granting {tokensToGrant} tokens to player {playerId} for leaderboard performance.");
await APIController.SendTokenEarningWebhook(playerId, tokensToGrant.ToString(), msg);
if (tokensToGrant >= 1200)
{
PlayerDB.UpdatePlayerHeartbeat(playerId, null, online: false);
APIController.SendNonHileWebhook(playerId, "Tried to claim " + tokensToGrant + " tokens");
return new CheckAndSetStatResponse
{
error = null,
success = false,
value = null
};
}
var gift = GiftsDB.CreateGift(
toPlayerId: playerId,
fromPlayerId: 1,
currency: tokensToGrant,
currencyType: 2,
balanceType: -2,
giftContext: enums.GiftType.GameRewards_Tokens,
giftRarity: 50,
message: "Great job! You earned " + tokensToGrant + " tokens for your performance in the leaderboard!",
platform: -1,
platformsToSpawnOn: -1
);
Console.WriteLine($"[LeaderboardDB] Created gift for player {playerId}.");
await NotiController.SendEvent(playerId, "31", GiftsDB.MapToDTO(gift));
Console.WriteLine($"[LeaderboardDB] Sent event notification to player {playerId} for the gift JSON: {GiftsDB.MapToDTO(gift)}");
}
if (entry == null)
{
entry = new LeaderboardEntry
{
EntryId = GetNextEntryId(),
PlayerId = playerId,
RoomId = request.RoomId,
StatChannel = request.StatChannel,
FilterType = 0,
Score = request.StatValue,
UpdatedAt = DateTime.UtcNow
};
Entries.Insert(entry);
}
else
{
entry.Score = request.StatValue;
entry.UpdatedAt = DateTime.UtcNow;
Entries.Update(entry);
}
Console.WriteLine($"[LeaderboardDB] Updated leaderboard entry for playerId: {playerId}, roomId: {request.RoomId}, statChannel: {request.StatChannel}, newScore: {entry.Score}");
int rank = ComputeRank(request.RoomId, request.StatChannel, playerId, entry.Score);
return new CheckAndSetStatResponse
{
error = null,
success = true,
value = new LeaderboardRow
{
playerId = playerId,
rank = rank,
score = entry.Score
}
};
}
}
}