using System; using System.Linq; using System.Globalization; using System.Collections.Generic; using UnityEngine; using Oxide.Core; using Oxide.Core.Plugins; using Oxide.Game.Rust.Cui; using Oxide.Core.Libraries.Covalence; namespace Oxide.Plugins { [Info("CPlayerStats", "Crazy", "1.1.1")] [Description("Simple players PVP data on wipe.")] class CPlayerStats : RustPlugin { #region Fields [PluginReference] private Plugin ImageLibrary; private static CPlayerStats _ins; private static string permView = "cplayerstats.view"; private string imgKill = "https://i49.servimg.com/u/f49/14/08/21/53/kill12.png"; private string imgDeath = "https://i49.servimg.com/u/f49/14/08/21/53/death12.png"; private string imgDiscord = "https://i49.servimg.com/u/f49/14/08/21/53/discor10.png"; private static string discord = "discord.gg/5NtNRhU"; private static Dictionary pStats = new Dictionary(); private static Dictionary data = new Dictionary(); #endregion #region Server private void OnServerInitialized() { _ins = this; if (!ImageLibrary) { PrintError("ImageLibrary not found, plugin will not work!"); return; } ImageLibrary.Call("AddImage", imgKill, "cplayerstats.img.kill"); ImageLibrary.Call("AddImage", imgDeath, "cplayerstats.img.death"); ImageLibrary.Call("AddImage", imgDiscord, "cplayerstats.img.discord"); permission.RegisterPermission(permView, this); foreach (BasePlayer player in BasePlayer.activePlayerList) OnPlayerConnected(player); } private void OnPlayerConnected(BasePlayer player) { if (player.IsReceivingSnapshot || player.IsSleeping()) { timer.In(2, () => OnPlayerConnected(player)); return; } PStats.TryLoad(player.userID); if (!player.GetComponent()) data[player.userID] = player.gameObject.AddComponent(); } private void OnPlayerDeath(BasePlayer victim, HitInfo info) { BasePlayer killer = info?.Initiator as BasePlayer; if (killer == null || killer == victim) return; if (victim.IsNpc || killer.IsNpc) return; if (pStats.ContainsKey(killer.userID)) pStats[killer.userID].kills++; if (pStats.ContainsKey(victim.userID)) pStats[victim.userID].deaths++; return; } private void OnServerShutDown() => Unload(); private void Unload() { foreach (var s in pStats) s.Value.Save(s.Key); if (BasePlayer.activePlayerList.Count == 0) return; UIStats[] objects = UnityEngine.Object.FindObjectsOfType(); if (objects != null) { foreach (var obj in objects) UnityEngine.Object.Destroy(obj); } } private void OnPlayerDisconnected(BasePlayer player) { if(data.ContainsKey(player.userID)) UnityEngine.Object.Destroy(data[player.userID]); } private void OnNewSave(string filename) => GetAllPlayers().ForEach(ID => PStats.Reset(ID)); #endregion #region Component private class UIStats : FacepunchBehaviour { public int kills; public int deaths; public bool needUpdate; private BasePlayer player; private void Awake() { player = GetComponent(); Instance(); InvokeRepeating(Refresh, 0f, 1); } private void Instance() { kills = pStats[player.userID].kills; deaths = pStats[player.userID].deaths; needUpdate = false; DestroyUI(); CreateUI(); } private void Refresh() { if(kills != pStats[player.userID].kills || deaths != pStats[player.userID].deaths) needUpdate = true; if(needUpdate && player.IPlayer.HasPermission(permView)) { Instance(); return; } } private void CreateUI() { if(player.IPlayer.HasPermission(permView)) { var containerKill = UI.CreateElementContainer("cplayerstats.kills", "1 1 1 0.1", "0.045 0.003", "0.075 0.025"); UI.AddImage(ref containerKill, "cplayerstats.kills", 0.3f, "cplayerstats.img.kill", "1 1 1 0.3", "0 -0.1", "0.5 1", "0 1", "0 1"); UI.AddImageColor(ref containerKill, "cplayerstats.kills", HexToRustFormat("#aabf7daf"), "0.55 0.1", "0.955 0.9", "0 0", "0 0"); UI.AddText(ref containerKill, "cplayerstats.kills", kills.ToString(), 9, "robotocondensed-regular.ttf", "1 1 1 0.8", TextAnchor.MiddleCenter, "0.50 0.0", "1.0 1"); CuiHelper.AddUi(player, containerKill); var containerDeath = UI.CreateElementContainer("cplayerstats.deaths", "1 1 1 0.1", "0.08 0.003", "0.11 0.025"); UI.AddImage(ref containerDeath, "cplayerstats.deaths", 0.3f, "cplayerstats.img.death", "1 1 1 0.3", "0 -0.1", "0.5 1", "0 1", "0 1"); UI.AddImageColor(ref containerDeath, "cplayerstats.deaths", HexToRustFormat("#d8453daf"), "0.55 0.1", "0.955 0.9", "0 0", "0 0"); UI.AddText(ref containerDeath, "cplayerstats.deaths", deaths.ToString(), 9, "robotocondensed-regular.ttf", "1 1 1 0.8", TextAnchor.MiddleCenter, "0.50 0.0", "1.0 1"); CuiHelper.AddUi(player, containerDeath); } else { var containerDiscord = UI.CreateElementContainer("cplayerstats.discord", "1 1 1 0.1", "0.045 0.003", "0.12 0.025"); UI.AddImage(ref containerDiscord, "cplayerstats.discord", 0.3f, "cplayerstats.img.discord", "1 1 1 0.3", "0 -0.1", "0.17 1", "0 1", "0 1"); UI.AddImageColor(ref containerDiscord, "cplayerstats.discord", HexToRustFormat("#bf8e51a1"), "0.20 0.1", "0.98 0.9", "0 0", "0 0"); UI.AddText(ref containerDiscord, "cplayerstats.discord", discord, 9, "robotocondensed-regular.ttf", "1 1 1 0.8", TextAnchor.MiddleCenter, "0.18 0.0", "1.0 1"); CuiHelper.AddUi(player, containerDiscord); } } private void DestroyUI() { CuiHelper.DestroyUi(player, "cplayerstats.kills"); CuiHelper.DestroyUi(player, "cplayerstats.deaths"); CuiHelper.DestroyUi(player, "cplayerstats.discord"); } private void OnDestroy() => DestroyUI(); } #endregion #region UI static class UI { static public CuiElementContainer CreateElementContainer(string panel, string color, string aMin, string aMax) { var NewElement = new CuiElementContainer() { { new CuiPanel { Image = {Color = color}, RectTransform = {AnchorMin = aMin, AnchorMax = aMax} }, new CuiElement().Parent = "Hud", panel } }; return NewElement; } static public void AddText(ref CuiElementContainer container, string panel, string text, int size, string font, string color, TextAnchor align, string aMin, string aMax) { container.Add(new CuiElement { Name = CuiHelper.GetGuid(), Parent = panel, Components = { new CuiTextComponent { Text = text, FontSize = size, Font = font, Color = color, Align = align }, new CuiRectTransformComponent { AnchorMin = aMin, AnchorMax = aMax } } }); } static public void AddImageColor(ref CuiElementContainer container, string panel, string color, string aMin, string aMax, string oMin, string oMax) { container.Add(new CuiElement { Name = CuiHelper.GetGuid(), Parent = panel, Components = { new CuiImageComponent { Color = color }, new CuiRectTransformComponent { AnchorMin = aMin, AnchorMax = aMax, OffsetMin = oMin, OffsetMax = oMax } } }); } static public void AddImage(ref CuiElementContainer container, string panel, float fade, string imgName, string color, string aMin, string aMax, string oMin, string oMax) { container.Add(new CuiElement { Name = CuiHelper.GetGuid(), Parent = panel, Components = { new CuiRawImageComponent { FadeIn = fade, Color = color, Png = (string) _ins.ImageLibrary.Call("GetImage", imgName), Sprite = "assets/content/textures/generic/fulltransparent.tga", }, new CuiRectTransformComponent { AnchorMin = aMin, AnchorMax = aMax, OffsetMin = oMin, OffsetMax = oMax } } }); } } #endregion #region Helpers private static string HexToRustFormat(string hex) { if (string.IsNullOrEmpty(hex)) hex = "#FFFFFFFF"; var str = hex.Trim('#'); if (str.Length == 6) str += "FF"; if (str.Length != 8) { throw new Exception(hex); throw new InvalidOperationException("Cannot convert a wrong format."); } var r = byte.Parse(str.Substring(0, 2), NumberStyles.HexNumber); var g = byte.Parse(str.Substring(2, 2), NumberStyles.HexNumber); var b = byte.Parse(str.Substring(4, 2), NumberStyles.HexNumber); var a = byte.Parse(str.Substring(6, 2), NumberStyles.HexNumber); Color color = new Color32(r, g, b, a); return string.Format("{0:F2} {1:F2} {2:F2} {3:F2}", color.r, color.g, color.b, color.a); } #endregion #region Functions public List GetAllPlayers() { List playerID = new List(); covalence.Players.All.ToList().ForEach(IPlayer => playerID.Add(ulong.Parse(IPlayer.Id))); return playerID; } #endregion #region Data private class PStats { public int kills; public int deaths; internal static void TryLoad(ulong id) { if(pStats.ContainsKey(id)) return; PStats data = Interface.Oxide.DataFileSystem.ReadObject($"CPlayerStats/{id}"); if(data == null) data = new PStats(); pStats.Add(id, data); } internal static void Reset(ulong id) { PStats data = Interface.Oxide.DataFileSystem.ReadObject($"CPlayerStats/{id}"); if(data == null) return; data = new PStats(); data.Save(id); } internal void Save(ulong id) => Interface.Oxide.DataFileSystem.WriteObject(($"CPlayerStats/{id}"), this, true); } #endregion } }