From 3dbfac2a4e3433343a0653c7e528ab4803160dd4 Mon Sep 17 00:00:00 2001 From: Daniel Willett Date: Sat, 4 Jan 2025 10:13:34 -0500 Subject: [PATCH] Added points section to leaderboard --- .../UI/Leaderboards/DualSidedLeaderboardUI.cs | 42 ++++++++++++++++++ .../Stats/PlayerGameStatsComponent.cs | 44 ++++++++++++++++++- UncreatedWarfare/Stats/PointsService.cs | 11 ++++- 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/UncreatedWarfare/Layouts/UI/Leaderboards/DualSidedLeaderboardUI.cs b/UncreatedWarfare/Layouts/UI/Leaderboards/DualSidedLeaderboardUI.cs index 7d0febbe..aba579fa 100644 --- a/UncreatedWarfare/Layouts/UI/Leaderboards/DualSidedLeaderboardUI.cs +++ b/UncreatedWarfare/Layouts/UI/Leaderboards/DualSidedLeaderboardUI.cs @@ -2,6 +2,7 @@ using SDG.NetTransport; using System; using System.Diagnostics.CodeAnalysis; +using System.Linq; using Uncreated.Framework.UI; using Uncreated.Framework.UI.Patterns; using Uncreated.Framework.UI.Reflection; @@ -16,7 +17,9 @@ using Uncreated.Warfare.Players; using Uncreated.Warfare.Players.Management; using Uncreated.Warfare.Services; +using Uncreated.Warfare.Stats; using Uncreated.Warfare.Translations; +using Uncreated.Warfare.Translations.Util; using Uncreated.Warfare.Util; namespace Uncreated.Warfare.Layouts.UI.Leaderboards; @@ -149,6 +152,7 @@ private void SendToPlayers(LanguageSet set) while (set.MoveNext()) { LayoutName.SetText(set.Next.Connection, _layout.LayoutInfo.DisplayName); + SendPointsSection(set.Next); } set.Reset(); @@ -182,6 +186,44 @@ private void SendToPlayers(LanguageSet set) } } + private void SendPointsSection(WarfarePlayer player) + { + Team team = player.Team; + LeaderboardSet? set = _sets!.FirstOrDefault(x => x.Team == team); + WarfareRank rank = _pointsService.GetRankFromExperience(player.CachedPoints.XP); + if (set == null) + { + PointsCreditsGained.SetText(player, string.Empty); + PointsExperienceGained.SetText(player, string.Empty); + PointsDowngradeArrow.SetVisibility(player, false); + PointsUpgradeArrow.SetVisibility(player, false); + PointsCurrentRank.SetText(player, string.Empty); + PointsNextRank.SetText(player, string.Empty); + PointsProgressBar.SetVisibility(player, false); + return; + } + + PointsProgressBar.SetVisibility(player, true); + PointsProgressBar.SetProgress(player.Connection, (float)rank.GetProgress(player.CachedPoints.XP)); + + double deltaCredits = set.GetStatisticValue(KnownStatNames.Credits, player.Steam64); + double deltaXP = set.GetStatisticValue(KnownStatNames.XP, player.Steam64); + + PointsCreditsGained.SetText(player, deltaCredits > 0 + ? $"+{deltaCredits.ToString("F0", player.Locale.CultureInfo)} {TranslationFormattingUtility.Colorize("C", _pointsService.CreditsColor)}" + : $"{deltaCredits.ToString("F0", player.Locale.CultureInfo)} {TranslationFormattingUtility.Colorize("C", _pointsService.CreditsColor)}"); + PointsExperienceGained.SetText(player, deltaXP > 0 + ? $"+{deltaXP.ToString("F0", player.Locale.CultureInfo)} {TranslationFormattingUtility.Colorize("XP", _pointsService.ExperienceColor)}" + : $"{deltaXP.ToString("F0", player.Locale.CultureInfo)} {TranslationFormattingUtility.Colorize("XP", _pointsService.ExperienceColor)}"); + + PointsCurrentRank.SetText(player, rank.Name); + PointsNextRank.SetText(player, rank.Next?.Name ?? string.Empty); + + WarfareRank startingRank = _pointsService.GetRankFromExperience(player.CachedPoints.XP - deltaXP); + PointsDowngradeArrow.SetVisibility(player, startingRank.RankIndex > rank.RankIndex); + PointsUpgradeArrow.SetVisibility(player, startingRank.RankIndex < rank.RankIndex); + } + public void UpdateSort(WarfarePlayer player, int setIndex, int column) { DualSidedLeaderboardPlayerData data = GetOrAddData(player.Steam64, _createData); diff --git a/UncreatedWarfare/Stats/PlayerGameStatsComponent.cs b/UncreatedWarfare/Stats/PlayerGameStatsComponent.cs index 88cdc094..5c5d2bff 100644 --- a/UncreatedWarfare/Stats/PlayerGameStatsComponent.cs +++ b/UncreatedWarfare/Stats/PlayerGameStatsComponent.cs @@ -1,20 +1,23 @@ using Microsoft.Extensions.DependencyInjection; using System; using System.Linq; +using Uncreated.Warfare.Configuration; using Uncreated.Warfare.Layouts; using Uncreated.Warfare.Layouts.Phases; using Uncreated.Warfare.Players; using Uncreated.Warfare.Players.Management; +using Uncreated.Warfare.Util; namespace Uncreated.Warfare.Stats; [PlayerComponent] -public class PlayerGameStatsComponent : IPlayerComponent +public class PlayerGameStatsComponent : IPlayerComponent, IDisposable { private LeaderboardPhase? _phase; public double[] Stats { get; private set; } = Array.Empty(); public WarfarePlayer Player { get; private set; } + public LongestShot LongestShot { get; set; } void IPlayerComponent.Init(IServiceProvider serviceProvider, bool isOnJoin) { @@ -22,6 +25,29 @@ void IPlayerComponent.Init(IServiceProvider serviceProvider, bool isOnJoin) _phase = layout.Phases.OfType().FirstOrDefault(); Stats = _phase == null ? Array.Empty() : new double[_phase.PlayerStats.Length]; + + if (isOnJoin) + UseableGun.onBulletHit += OnBulletHit; + } + + private void OnBulletHit(UseableGun gun, BulletInfo bullet, InputInfo hit, ref bool shouldallow) + { + if (!shouldallow || hit.type != ERaycastInfoType.PLAYER) + return; + + InteractableVehicle? vehicle = gun.player.movement.getVehicle(); + if (vehicle != null) + { + byte seat = gun.player.movement.getSeat(); + if (vehicle.passengers[seat].turret != null && vehicle.passengers[seat].turret.itemID == gun.equippedGunAsset.id) + return; + } + + Vector3 gunPoint = gun.player.look.aim.transform.position; + + float sqrDistance = MathUtility.SquaredDistance(in hit.point, in gunPoint, false); + if (LongestShot.SquaredDistance < sqrDistance) + LongestShot = new LongestShot(sqrDistance, AssetLink.Create(gun.equippedGunAsset)); } public void AddToStat(string statName, int value) @@ -75,4 +101,20 @@ public void TryAddToStat(int index, double value) } WarfarePlayer IPlayerComponent.Player { get => Player; set => Player = value; } + + void IDisposable.Dispose() + { + UseableGun.onBulletHit -= OnBulletHit; + } } + +public readonly struct LongestShot +{ + public readonly float SquaredDistance; + public readonly IAssetLink? Gun; + public LongestShot(float squaredDistance, IAssetLink gun) + { + SquaredDistance = squaredDistance; + Gun = gun; + } +} \ No newline at end of file diff --git a/UncreatedWarfare/Stats/PointsService.cs b/UncreatedWarfare/Stats/PointsService.cs index 7df97c5f..b35e52af 100644 --- a/UncreatedWarfare/Stats/PointsService.cs +++ b/UncreatedWarfare/Stats/PointsService.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -12,6 +12,7 @@ using Uncreated.Warfare.Translations; using Uncreated.Warfare.Translations.Addons; using Uncreated.Warfare.Translations.Util; +using Uncreated.Warfare.Util; using Uncreated.Warfare.Vehicles.WarfareVehicles; namespace Uncreated.Warfare.Stats; @@ -32,6 +33,14 @@ public class PointsService : IEventListener // todo player eq public double DefaultCredits => _configuration.GetValue("DefaultCredits"); public double GlobalMultiplier => _configuration.GetValue("GlobalPointMultiplier", 1d); + public Color32 CreditsColor => HexStringHelper.TryParseColor32(_configuration["CreditsColor"], CultureInfo.InvariantCulture, out Color32 color) + ? color with { a = 255 } + : new Color32(184, 255, 193, 255); + + public Color32 ExperienceColor => HexStringHelper.TryParseColor32(_configuration["ExperienceColor"], CultureInfo.InvariantCulture, out Color32 color) + ? color with { a = 255 } + : new Color32(244, 205, 87, 255); + /// /// Ordered list of all configured ranks.