Иконка ресурса

FREE PlayerRanks : 2.3.4 2.3.4

Нет прав для скачивания
C#:
using Rust;
using System;
using System.Text;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using UnityEngine;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Oxide.Core.Database;
using Oxide.Core.Libraries;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries.Covalence;
using Rust.Ai.Gen2;
//Suggestion MikeTheVike - Add "use /command to see full leaderboard" after the chat top X
//To do
//  Ping leaders or title holders to discord.
//  Auto-wipe PTT
//  Prioritise titles
//  Add TeamID for SQL use
//  Add API for David
//  Changed sql columns to allow for 4 byte unicode characters
//  Look into firebase save
//  Add PVPDeaths and use it (optionally) to calculate KDR
//  Add TeamID
//  TO DO
//  New data file with commands to run for top 1/2/3 per category.
//  Auto run these commands OnNewSave, prior to wipe.
//  Allow option to run these commands on user command, either by category or for all at once.
//  Added TakeLBSnapShotAtWipe for auto snapshot taking
//  Added support for new wolves.
//  Remove Remote/RF C4 (others?) from PVE Distance.
//  Perma store SaveRestore.WipeId and compare, instead of using OnNewSave();
//  OnCollectiblePickup NRE fix.
//  Shark and snakes now contribute to PVE_Kills.
//  All other new animals should already contribute.
//  Made PlaytimeTracker update on player disconnect, as well as existing connect check.
//  Added update titles when individual player info is updated - Should address issues with PlaytimeTracker title order.
//  V2.3.4
//  Fix for July wipe.
namespace Oxide.Plugins {
    [Info("PlayerRanks", "Steenamaroo", "2.3.4", ResourceId = 14)]
    class PlayerRanks : RustPlugin {
        //void APITest()
        //{
        //    var result = PlayerRanks.CallHook("GetTop", "PVPKills", 10, new List<ulong>() { 76561198025512345 }) as Dictionary<ulong, Dictionary<string, object>>;
        //    foreach (var entry in result)
        //        foreach (var stat in result[entry.Key])
        //            Puts(stat.Key + " " + stat.Value.ToString());
        //    var playerscore = PlayerRanks.CallHook("GetPlayerScore", (ulong)76561198025512345, "PVPKills");
        //    Puts(playerscore.ToString());
        //}
#region Declarations
        [PluginReference]
        Plugin Clans, Friends, EventManager, PlaytimeTracker, Economics, ServerRewards, Arena;
        Core.MySql.Libraries.MySql Sql = Interface.Oxide.GetLibrary<Core.MySql.Libraries.MySql>();
        Connection Sql_conn;
        bool loaded = false;
        List<string> intenseOptions = new List<string>() {
            "StructuresBuilt", "StructuresDemolished", "ItemsDeployed", "ItemsCrafted", "EntitiesRepaired", "ResourcesGathered", "StructuresUpgraded"
        }
        ;
        Dictionary<ulong, Dictionary<ulong, float>> BradleyAttackers = new Dictionary<ulong, Dictionary<ulong, float>>();
        Dictionary<ulong, Dictionary<ulong, int>> HeliAttackers = new Dictionary<ulong, Dictionary<ulong, int>>();
        Dictionary<ulong, WoundedData> woundedData = new Dictionary<ulong, WoundedData>();
        Dictionary<ulong, string> MenuOpen = new Dictionary<ulong, string>();
        List<ulong> airdrops = new List<ulong>();
        const string font = "robotocondensed-regular.ttf";
        bool HasPermission(string id, string perm) => permission.UserHasPermission(id, perm);
        const string permUse = "playerranks.use";
        const string permAdmin = "playerranks.admin";
        const string permExcludeFromStats = "playerranks.excludefromstats";
        const string permExcludedFromStats = "playerranks.excludedfromstats";
        const string permOptOut = "playerranks.optout";
        List<string> Broadcast = new List<string>();
        Timer BroadcastTimer;
#endregion
#region RustIO
        Library lib;
        MethodInfo isInstalled;
        MethodInfo hasFriend;
        bool IsInstalled() => lib != null && isInstalled != null && (bool)isInstalled.Invoke(lib, new object[] {
        }
        );
        bool HasFriend(string playerId, string friendId) => lib != null && hasFriend != null && (bool)hasFriend.Invoke(lib, new object[] {
            playerId, friendId
        }
        );
#endregion
#region Titles
        private void OnPluginLoaded(Plugin plugin) {
            if (loaded && conf.Titles.EnablePlayerTitles && plugin.Title == "Better Chat") Interface.CallHook("API_RegisterThirdPartyTitle", this, new Func<IPlayer, string>(GetBCTitle));
        }
        public class Top {
            public ulong id = 0;
            public double score = 0;
        }
        public Dictionary<string, Top> TitleList = new Dictionary<string, Top>() {
            {
                "PVPKills", new Top()
            }
            , {
                "PVPDistance", new Top()
            }
            , {
                "PVEKills", new Top()
            }
            , {
                "PVEDistance", new Top()
            }
            , {
                "NPCKills", new Top()
            }
            , {
                "NPCDistance", new Top()
            }
            , {
                "SleepersKilled", new Top()
            }
            , {
                "HeadShots", new Top()
            }
            , {
                "Deaths", new Top()
            }
            , {
                "Suicides", new Top()
            }
            , {
                "KDR", new Top()
            }
            , {
                "SDR", new Top()
            }
            , {
                "SkullsCrushed", new Top()
            }
            , {
                "TimesWounded", new Top()
            }
            , {
                "TimesHealed", new Top()
            }
            , {
                "HeliHits", new Top()
            }
            , {
                "HeliKills", new Top()
            }
            , {
                "APCHits", new Top()
            }
            , {
                "APCKills", new Top()
            }
            , {
                "BarrelsDestroyed", new Top()
            }
            , {
                "ExplosivesThrown", new Top()
            }
            , {
                "ArrowsFired", new Top()
            }
            , {
                "BulletsFired", new Top()
            }
            , {
                "RocketsLaunched", new Top()
            }
            , {
                "MLRSFired", new Top()
            }
            , {
                "WeaponTrapsDestroyed", new Top()
            }
            , {
                "DropsLooted", new Top()
            }
            , {
                "FishCaught", new Top()
            }
            , {
                "Economics", new Top()
            }
            , {
                "ServerRewards", new Top()
            }
            , {
                "StructuresBuilt", new Top()
            }
            , {
                "StructuresDemolished", new Top()
            }
            , {
                "ItemsDeployed", new Top()
            }
            , {
                "ItemsCrafted", new Top()
            }
            , {
                "EntitiesRepaired", new Top()
            }
            , {
                "ResourcesGathered", new Top()
            }
            , {
                "PlantsGathered", new Top()
            }
            , {
                "StructuresUpgraded", new Top()
            }
            , {
                "TimePlayed", new Top()
            }
        }
        ;
        public Dictionary<string, Timer> CoolDowns = new Dictionary<string, Timer>();
        void DoTitle(ulong id, string category) {
            if (!conf.Titles.EnablePlayerTitles || IntenseBlock(category)) return;
            if (HasPermission(id.ToString(), permExcludedFromStats) || (bool)data.PlayerRankData[id]["OptOut"] == true || (conf.Options.allowadmin == false && (bool)data.PlayerRankData[id]["Admin"] == true)) return;
            var path = data.PlayerRankData[id];
            if (D(path[category]) > TitleList[category].score && TitleList[category].id != id) {
                if (conf.CategorySettings[category].BroadcastTitleChanges) {
                    BasePlayer taker = BasePlayer.FindByID(id);
                    if (taker != null) {
                        if (!CoolDowns.ContainsKey(category)) CoolDowns.Add(category, timer.Once(1f, () => {
                        }
                        ));
                        if (conf.CategorySettings[category].Title != string.Empty) {
                            ulong loser = TitleList[category].id;
                            CoolDowns[category] = timer.Once(5f, () => {
                                foreach (var player in BasePlayer.activePlayerList.Where(player => (bool)data.PlayerRankData[player.userID]["PrintToChat"] == true)) if (conf.Options.GlobalTitleBroadcast || (taker == player || player.userID == loser)) SendReply(player, lang.GetMessage(player.userID == loser ? "losttitle" : "tooktitle", this), taker.displayName, conf.CategorySettings[category].Title);
                            }
                            );
                        }
                    }
                }
                if (conf.Titles.AddTitleHoldersToGroup) {
                    ClearGroup(category);
                    permission.AddUserGroup(id.ToString(), category);
                }
                TitleList[category] = new Top() {
                    id = id, score = D(path[category])
                }
                ;
            }
        }
        private string GetBCTitle(IPlayer player) => GetTitle(player, true);
        private string GetPlayerTitle(IPlayer player) => GetTitle(player, false);
        private string GetTitle(IPlayer player, bool BetterChat) {
            string title = conf.Titles.TitleStart;
            int added = 0;
            foreach (var entry in TitleList) {
                if (BetterChat && !conf.CategorySettings[entry.Key].ShowTitleInPlayerChatMessages) continue;
                if (added < conf.Titles.MaxDisplayedTitles && entry.Value.id == Convert.ToUInt64(player.Id) && conf.CategorySettings[entry.Key].Title != string.Empty) {
                    if (added > 0) title += " ";
                    title += $"{conf.CategorySettings[entry.Key].Title}";
                    added++;
                }
            }
            title += conf.Titles.TitleEnd;
            if (added > conf.Titles.MaxTitlesBeforeLineBreak) title += "\n";
            return added == 0 ? "" : title;
        }
        void LoadTitles() {
            if (!loaded) return;
            if (!conf.Titles.EnablePlayerTitles || conf.Titles.AddTitleHoldersToGroup) foreach (var cat in conf.CategorySettings) permission.RemoveGroup(cat.Key);
            if (!conf.Titles.EnablePlayerTitles) return;
            var dictToUse = data.PlayerRankData.Where(pair => !HasPermission(pair.Key.ToString(), permExcludedFromStats) && (bool)pair.Value["OptOut"] == false && (conf.Options.allowadmin == true || (bool)pair.Value["Admin"] == false)).ToDictionary(val => val.Key, val => val.Value);
            foreach (var cat in conf.CategorySettings.Where(cat => conf.CategorySettings[cat.Key].Title != string.Empty && !IntenseBlock(cat.Key))) {
                if (NoPlug(cat.Key) || dictToUse.Count == 0) continue;
                var top = dictToUse.Aggregate((l, r) => D(l.Value[cat.Key]) > D(r.Value[cat.Key]) ? l : r);
                if (D(top.Value[cat.Key]) > 0) {
                    if (conf.Titles.AddTitleHoldersToGroup) {
                        ClearGroup(cat.Key);
                        permission.AddUserGroup(top.Key.ToString(), cat.Key);
                    }
                    TitleList[cat.Key] = new Top() {
                        id = top.Key, score = D(top.Value[cat.Key])
                    }
                    ;
                }
                else if(conf.Titles.AddTitleHoldersToGroup) ClearGroup(cat.Key);
            }
            Interface.CallHook("API_RegisterThirdPartyTitle", this, new Func<IPlayer, string>(GetBCTitle));
        }
        void ClearGroup(string cat) {
            if (permission.GroupExists(cat)) {
                foreach (string member in permission.GetUsersInGroup(cat).ToList()) permission.RemoveUserGroup(member, cat);
            }
            else permission.CreateGroup(cat, cat, 0);
        }
#endregion
#region DataStorage
        public DelayRewards dr;
        public class DelayRewards {
            public Dictionary<ulong, List<DelayedRewards>> DR = new Dictionary<ulong, List<DelayedRewards>>();
        }
        public class DelayedRewards {
            public string category;
            public string score;
            public string commands;
            public string message;
        }
        public Rewards rewards;
        public class Rewards {
            public Dictionary<string, RewardInfo> RewardInfo = new Dictionary<string, RewardInfo>();
        }
        public class RewardInfo {
            public bool IssueAtWipe = true;
            public bool WaitUntilPlayerIsOnline = false;
            public string First = "";
            public string FirstMessage = "You received a reward for ranking #1 in {category}";
            public string Second = "";
            public string SecondMessage = "You received a reward for ranking #2 in {category}";
            public string Third = "";
            public string ThirdMessage = "You received a reward for ranking #3 in {category}";
        }
        public class DataStorage {
            public Dictionary<ulong, Dictionary<string, object>> PlayerRankData = new Dictionary<ulong, Dictionary<string, object>>();
            public Dictionary<DateTime, Dictionary<string, LeaderBoardData>> leaderBoards = new Dictionary<DateTime, Dictionary<string, LeaderBoardData>>();
        }
        public class LeaderBoardData {
            public ulong UserID;
            public string UserName;
            public double Score;
        }
        public readonly Dictionary<string, object> PRDATA = new Dictionary<string, object>() {
            {
                "PrintToChat", true
            }
            , {
                "Admin", false
            }
            , {
                "OptOut", false
            }
            , {
                "Changed", true
            }
            , {
                "UserID", (ulong)0
            }
            , {
                "Name", ""
            }
            , {
                "Clan", "None"
            }
            , {
                "TimePlayed", "0"
            }
            , {
                "Status", "offline"
            }
            , {
                "Economics", 0
            }
            , {
                "ServerRewards", 0
            }
            , {
                "ActiveDate", new DateTime()
            }
            , {
                "PVPKills", 0
            }
            , {
                "PVPDistance", 0.0
            }
            , {
                "PVEKills", 0
            }
            , {
                "PVEDistance", 0.0
            }
            , {
                "NPCKills", 0
            }
            , {
                "NPCDistance", 0.0
            }
            , {
                "SleepersKilled", 0
            }
            , {
                "HeadShots", 0
            }
            , {
                "Deaths", 0
            }
            , {
                "Suicides", 0
            }
            , {
                "KDR", 0.0
            }
            , {
                "SDR", 0.0
            }
            , {
                "SkullsCrushed", 0
            }
            , {
                "TimesWounded", 0
            }
            , {
                "TimesHealed", 0
            }
            , {
                "HeliHits", 0
            }
            , {
                "HeliKills", 0
            }
            , {
                "APCHits", 0
            }
            , {
                "APCKills", 0
            }
            , {
                "BarrelsDestroyed", 0
            }
            , {
                "ExplosivesThrown", 0
            }
            , {
                "ArrowsFired", 0
            }
            , {
                "BulletsFired", 0
            }
            , {
                "RocketsLaunched", 0
            }
            , {
                "MLRSFired", 0
            }
            , {
                "WeaponTrapsDestroyed", 0
            }
            , {
                "DropsLooted", 0
            }
            , {
                "FishCaught", 0
            }
            , {
                "PlantsGathered", 0
            }
            ,  //intense options
            {
                "StructuresBuilt", 0
            }
            , {
                "StructuresDemolished", 0
            }
            , {
                "ItemsDeployed", 0
            }
            , {
                "ItemsCrafted", 0
            }
            , {
                "EntitiesRepaired", 0
            }
            , {
                "ResourcesGathered", 0
            }
            , {
                "StructuresUpgraded", 0
            }
        }
        ;
        class WoundedData {
            public float distance;
            public ulong attackerId;
        }
        DataStorage data;
        private Dictionary<ulong, Dictionary<string, object>> LiveData() => data.PlayerRankData;
        private DynamicConfigFile PRData;
#endregion
#region SetupTakeDown
        void Init() {
            lang.RegisterMessages(Messages, this);
            permission.RegisterPermission(permExcludeFromStats, this);
            permission.RegisterPermission(permExcludedFromStats, this);
            permission.RegisterPermission(permAdmin, this);
            permission.RegisterPermission(permUse, this);
            permission.RegisterPermission(permOptOut, this);
        }
        void OnServerInitialized() {
            LoadConfigVariables();
            TitleList = TitleList.OrderBy(x => conf.CategorySettings[x.Key].ChatPriority).ToDictionary(pair => pair.Key, pair => pair.Value);
            foreach (var entry in conf.Options.chatCommandAliases) cmd.AddChatCommand($"{entry}", this, "CmdTarget");
            Sql_conn = Sql.OpenDb(conf.MySQL.sql_host, conf.MySQL.sql_port, conf.MySQL.sql_db, conf.MySQL.sql_user, conf.MySQL.sql_pass + ";Connection Timeout = 10; CharSet=utf8mb4", this);
            CheckDependencies();
            SetUp(true);
            dr = Interface.Oxide.DataFileSystem.ReadObject<DelayRewards>("PlayerRanksDelayedRewards") ?? new DelayRewards();
            if (ServerRewards) timer.Repeat(600, 0, () => {
                foreach (var entry in data.PlayerRankData) entry.Value["ServerRewards"] = ServerRewards?.Call("CheckPoints", entry.Key);
            }
            );
            foreach (var lb in data.leaderBoards.ToDictionary(pair => pair.Key, pair => pair.Value)) foreach (var entry in PRDATA) if (!lb.Value.ContainsKey(entry.Key)) data.leaderBoards[lb.Key].Add(entry.Key, new LeaderBoardData {
                UserID = 0, UserName = "No Record", Score = 0
            }
            );
            if (newsave) DoNewMap();
            loaded = true;
            LoadTitles();
        }
        void DoNewMap() {
            timer.Once(10f, () => {
                if (conf.Options.IssueRewardsAtWipe) {
                    dr.DR.Clear();
                    IssueRewards(true, null);
                }
                if (conf.Options.TakeLBSnapShotAtWipe) SaveLB();
                if (!conf.Options.WipeOnNewMap) return;
                ClearData();
                SetUp(true);
                if (conf.MySQL.useMySQL) LoadMySQL(true);
            }
            );
        }
        void ClearData() {
            data.PlayerRankData.Clear();
            PRData.WriteObject(data);
            foreach (var entry in TitleList.ToDictionary(val => val.Key, val => val.Value)) TitleList[entry.Key] = new Top();
            LoadTitles();
        }
        void CheckDependencies() {
            if (Friends == null && !conf.Options.record_FriendsAPI_Kills) PrintWarning(lang.GetMessage("noFriends", this));
            if (Clans == null && (!conf.Options.record_ClanMate_Kills || conf.Options.displayClanStats)) {
                PrintWarning(lang.GetMessage("noClans", this));
                conf.Options.record_ClanMate_Kills = true;
                SaveConfig(conf);
            }
            lib = Interface.GetMod().GetLibrary<Library>("RustIO");
            if (conf.Options.record_RustIO_Friend_Kills && (lib == null || (isInstalled = lib.GetFunction("IsInstalled")) == null || (hasFriend = lib.GetFunction("HasFriend")) == null)) PrintWarning(lang.GetMessage("noRustio", this));
            if (PlaytimeTracker == null) PrintWarning(lang.GetMessage("noPTT", this));
            if (Economics == null) PrintWarning(lang.GetMessage("noEconomics", this));
            if (ServerRewards == null) PrintWarning(lang.GetMessage("noServerRewards", this));
            ;
        }
        void Unload() {
            if (!loaded) return;
            Sql_conn?.Con?.Dispose();
            foreach (BasePlayer player in BasePlayer.activePlayerList) DestroyMenu(String.Empty, player);
            SaveData(false);
            foreach (var cat in conf.CategorySettings) {
                if (permission.GroupExists(cat.Key)) foreach (string member in permission.GetUsersInGroup(cat.Key).ToList()) permission.RemoveUserGroup(member, cat.Key);
                if (conf.Titles.DestroyGroupsOnUnload) permission.RemoveGroup(cat.Key);
            }
            permission.SaveData();
        }
        bool newsave = false;
        void OnNewSave(string filename) => newsave = true;
        void OnPlayerDisconnected(BasePlayer player) {
            if (ServerUsers.Is(player.userID, ServerUsers.UserGroup.Banned)) return;
            //if (!data.PlayerRankData.ContainsKey(player.userID)) //// removed 2.3.3
            OnPlayerConnected(player);
            data.PlayerRankData[player.userID]["Status"] = "offline";
            data.PlayerRankData[player.userID]["Changed"] = true;
            DestroyMenu(String.Empty, player);
        }
        Timer SaveTimer;
        void SetUp(bool offline) {
            PRData = Interface.Oxide.DataFileSystem.GetFile("PlayerRanks");
            LoadData();
            List<ulong> online = new List<ulong>();
            foreach (BasePlayer player in BasePlayer.activePlayerList) {
                OnPlayerConnected(player);
                online.Add(player.userID);
            }
            if (offline) foreach (var entry in data.PlayerRankData.Where(x => !online.Contains(x.Key))) UpdateOfflinePlayer(entry.Key);
            SaveTimer?.Destroy();
            SaveTimer = timer.Every(Mathf.Max(1, conf.Options.saveTimer) * 60, () => {
                SaveData(true);
                PrintWarning(lang.GetMessage("save", this));
            }
            );
            SetUpBroadcast();
            LoadTitles();
            SetupRewards();
        }
        void SetupRewards() {
            rewards = Interface.Oxide.DataFileSystem.ReadObject<Rewards>("PlayerRanksRewards");
            foreach (var entry in CatsDict) if (!rewards.RewardInfo.ContainsKey(entry.Key)) rewards.RewardInfo.Add(entry.Key, new RewardInfo());
            Interface.Oxide.DataFileSystem.WriteObject("PlayerRanksRewards", rewards);
        }
        void IssueRewards(bool newsave = false, string category = null) {
            Dictionary<ulong, string> TopThree = new Dictionary<ulong, string>();
            Dictionary<ulong, Dictionary<string, object>> dictToUse = new Dictionary<ulong, Dictionary<string, object>>();
            foreach (var entry in rewards.RewardInfo) {
                if (category != null && entry.Key != category || entry.Value == new RewardInfo() || (newsave && !entry.Value.IssueAtWipe)) continue;
                TopThree.Clear();
                dictToUse.Clear();
                dictToUse = data.PlayerRankData.Where(pair => !HasPermission(pair.Key.ToString(), permExcludedFromStats) && (bool)pair.Value["OptOut"] == false && (conf.Options.allowadmin == true || (bool)pair.Value["Admin"] == false)).ToDictionary(val => val.Key, val => val.Value);
                dictToUse = dictToUse.OrderByDescending(pair => D(pair.Value[entry.Key])).Where(x => D(x.Value[entry.Key]) > 0).Take(3).ToDictionary(val => val.Key, val => val.Value);
                foreach (var e in dictToUse) if (!TopThree.ContainsKey(e.Key) && !NoPlug(entry.Key)) TopThree[e.Key] = GetPlaytimeClock(entry.Key, D(e.Value[entry.Key]), true) + (entry.Key.Contains("Distance") ? "m" : "");
                for (int i = 0; i < TopThree.Count; i++) {
                    var winner = TopThree.ElementAt(i);
                    if (entry.Value.WaitUntilPlayerIsOnline) {
                        if (BasePlayer.FindByID(winner.Key)) IssueReward(winner.Key, entry.Key, winner.Value, i == 0 ? entry.Value.First : i == 1 ? entry.Value.Second : entry.Value.Third, i == 0 ? entry.Value.FirstMessage : i == 1 ? entry.Value.SecondMessage : entry.Value.ThirdMessage);
                        else {
                            if (!dr.DR.ContainsKey(winner.Key)) dr.DR.Add(winner.Key, new List<DelayedRewards>());
                            dr.DR[winner.Key].Add(new DelayedRewards() {
                                category = entry.Key, score = winner.Value, commands = i == 0 ? entry.Value.First : i == 1 ? entry.Value.Second : entry.Value.Third, message = i == 0 ? entry.Value.FirstMessage : i == 1 ? entry.Value.SecondMessage : entry.Value.ThirdMessage,
                            }
                            );
                            ;
                        }
                    }
                    else IssueReward(winner.Key, entry.Key, winner.Value, i == 0 ? entry.Value.First : i == 1 ? entry.Value.Second : entry.Value.Third, i == 0 ? entry.Value.FirstMessage : i == 1 ? entry.Value.SecondMessage : entry.Value.ThirdMessage);
                }
            }
        }
        void IssueReward(ulong user, string category, string score, string commands, string message) {
            if (commands != string.Empty) {
                commands = commands.Replace(", ", ",");
                foreach (var command in commands.Split(',')) Server.Command(command.Replace("{id}", user.ToString()));
                if (message != string.Empty) {
                    var player = BasePlayer.FindByID(user);
                    if (player != null) SendReply(player, message.Replace("{category}", category));
                }
            }
        }
        void SetUpBroadcast() {
            if (conf.Options.useTimedTopList) {
                if (BroadcastTimer != null) BroadcastTimer.Destroy();
                Broadcast.Clear();
                foreach (var cat in conf.CategorySettings) {
                    if (conf.CategorySettings[cat.Key].IncludeInChatBroadcast == true && !IntenseBlock(cat.Key)) Broadcast.Add(cat.Key);
                }
                if (Broadcast.Count != 0) BroadcastLooper(0);
            }
        }
        void BroadcastLooper(int counter) {
            var time = 10;
            if (BroadcastMethod(Broadcast[counter])) time = conf.Options.TimedTopListTimer * 60;
            counter++;
            if (counter == Broadcast.Count) counter = 0;
            BroadcastTimer = timer.Once(time, () => BroadcastLooper(counter));
        }
        void OnClanCreate(string clanName) => UpdateClans();
        void OnClanUpdate(string clanName) => UpdateClans();
        void OnClanDestroy(string clanName) => UpdateClans();
        void UpdateClans() {
            NextTick(() => {
                foreach (var entry in data.PlayerRankData) {
                    var getClan = Clans?.CallHook("GetClanOf", entry.Key);
                    if (getClan != null) entry.Value["Clan"] = (string)getClan;
                    else entry.Value["Clan"] = "None";
                }
            }
            );
        }
        void OnPlayerConnected(BasePlayer player) {
            ulong id = player.userID.Get();
            if (ServerUsers.Is(id, ServerUsers.UserGroup.Banned)) {
                if (conf.Options.deleteOnBan && data.PlayerRankData.ContainsKey(id)) data.PlayerRankData.Remove(id);
                return;
            }
            DestroyMenu(String.Empty, player);
            if (!data.PlayerRankData.ContainsKey(id)) {
                data.PlayerRankData.Add(id, new Dictionary<string, object>());
                foreach (var entry in PRDATA) data.PlayerRankData[id].Add(entry.Key, entry.Value);
            }
            UpdatePlayer(player);
            GiveDelayedRewards(player);
        }
        public void GiveDelayedRewards(BasePlayer player) {
            if (dr == null || player.IsReceivingSnapshot || player.IsDead()) {
                timer.Once(1f, () => {
                    if (player?.net?.connection != null) GiveDelayedRewards(player);
                }
                );
                return;
            }
            List<DelayedRewards> drs;
            if (dr.DR.TryGetValue(player.userID, out drs)) {
                foreach (var entry in drs) IssueReward(player.userID, entry.category, entry.score, entry.commands, entry.message);
                dr.DR.Remove(player.userID);
            }
        }
        public void UpdateOfflinePlayer(ulong userID) {
            var path = data.PlayerRankData[userID];
            bool gotClan = (Clans?.CallHook("GetClanOf", userID) != null);
            var time = PlaytimeTracker?.Call("GetPlayTime", userID.ToString());
            path["Status"] = "offline";
            path["Economics"] = Economics ? Economics?.Call("Balance", userID) : path["Economics"];
            path["ServerRewards"] = ServerRewards ? ServerRewards?.Call("CheckPoints", userID) : path["ServerRewards"];
            path["Clan"] = gotClan ? (string)Clans?.CallHook("GetClanOf", userID) : "None";
            path["TimePlayed"] = (time == null) ? "0" : time;
        }
        public void UpdatePlayer(BasePlayer player) {
            var path = data.PlayerRankData[player.userID];
            var clan = Clans?.CallHook("GetClanOf", player.userID.Get());
            var time = PlaytimeTracker?.Call("GetPlayTime", player.UserIDString);
            path["UserID"] = player.userID.Get();
            path["Admin"] = IsAuth(player);
            path["Changed"] = true;
            path["Name"] = CleanString(player.displayName, "");
            path["Status"] = "online";
            path["ActiveDate"] = DateTime.UtcNow;
            path["Economics"] = Economics ? Economics?.Call("Balance", player.userID.Get()) : path["Economics"];
            path["ServerRewards"] = ServerRewards ? ServerRewards?.Call("CheckPoints", player.userID.Get()) : path["ServerRewards"];
            path["Clan"] = clan != null ? (string)clan : "None";
            path["TimePlayed"] = (time == null) ? "0" : time;
            path["OptOut"] = HasPermission(player.UserIDString, permOptOut);
            DoTitle(player.userID, "TimePlayed");
            //// Added in 2.3.3 - Needs tested.
        }
        void OnEconomicsBalanceUpdated(string userID, double amount) {
            var id = Convert.ToUInt64(userID);
            if (Economics && data.PlayerRankData.ContainsKey(id)) {
                data.PlayerRankData[id]["Economics"] = Economics?.Call("Balance", id);
                DoTitle(Convert.ToUInt64(userID), "Economics");
            }
        }
        void OnSrChanged(ulong userID, double amount)  //Doesn't exist
        {
            if (ServerRewards && data.PlayerRankData.ContainsKey(userID)) {
                data.PlayerRankData[userID]["ServerRewards"] = ServerRewards?.Call("CheckPoints", (ulong)userID);
                DoTitle(userID, "ServerRewards");
            }
        }
        private string GetPlaytimeClock(string name, double time, bool friendly) {
            if (name.Contains("TimePlayed")) {
                TimeSpan dateDifference = TimeSpan.FromSeconds((float)time);
                var days = dateDifference.Days.ToString("00");
                var hours = friendly ? dateDifference.Hours.ToString("0") : dateDifference.Hours.ToString("00");
                var mins = friendly ? dateDifference.Minutes.ToString("0") : dateDifference.Minutes.ToString("00");
                var secs = dateDifference.Seconds.ToString("00");
                if (conf.Options.PlayTime_HH_MM) {
                    hours = friendly ? Math.Floor(dateDifference.TotalHours).ToString("0") : Math.Floor(dateDifference.TotalHours).ToString("00");
                    return string.Format("{0}:{1}", hours, mins);
                }
                if (friendly) {
                    if (days == "00" && hours == "00") return string.Format("{0}:{1}", mins, secs);
                    if (days == "00") return string.Format("{0}:{1}:{2}", hours, mins, secs);
                }
                return string.Format("{0}:{1}:{2}:{3}", days, hours, mins, secs);
            }
            return time.ToString();
        }
#endregion
#region Hooks
        void OnPlayerBanned(string name, ulong id, string address, string reason) {
            if (conf.Options.deleteOnBan) data.PlayerRankData.Remove(id);
        }
        void OnEntityTakeDamage(BaseEntity entity, HitInfo hitinfo) {
            if (!loaded || hitinfo == null || entity?.net?.ID == null || entity.IsDestroyed) return;
            var player = hitinfo?.InitiatorPlayer;
            if (player == null) return;
            if (conf.Options.blockEvents && CheckEvents(player)) return;
            if (entity is PatrolHelicopter) {
                if (!HeliAttackers.ContainsKey(entity.net.ID.Value)) HeliAttackers.Add(entity.net.ID.Value, new Dictionary<ulong, int>());
                if (!HeliAttackers[entity.net.ID.Value].ContainsKey(player.userID)) HeliAttackers[entity.net.ID.Value].Add(player.userID, 1);
                else {
                    HeliAttackers[entity.net.ID.Value][player.userID]++;
                    Plus(player, "HeliHits", 1);
                }
            }
            if (entity is BradleyAPC) {
                float amount = hitinfo.damageTypes?.Total() ?? 0;
                if (amount > 0) {
                    if (!BradleyAttackers.ContainsKey(entity.net.ID.Value)) //explosive ammo does get this far, because two damage types are processed.
                    BradleyAttackers.Add(entity.net.ID.Value, new Dictionary<ulong, float>());
                    if (!BradleyAttackers[entity.net.ID.Value].ContainsKey(player.userID)) BradleyAttackers[entity.net.ID.Value].Add(player.userID, amount);
                    else {
                        BradleyAttackers[entity.net.ID.Value][player.userID] += amount;
                        Plus(player, "APCHits", 1);
                    }
                }
            }
            var playerEntity = entity as BasePlayer;
            if (playerEntity == null || (conf.Options.PVPHeadshotsOnly && playerEntity.IsNpc)) return;
            if (hitinfo.isHeadshot && !FriendCheck(player, playerEntity) && !playerEntity.IsSleeping()) {
                var health = entity.Health();
                NextTick(() => {
                    if (conf.Options.CountHeadshotsOnlyIfKill) {
                        if (entity == null || entity.Health() < 0.5f) Plus(player, "HeadShots", 1);
                    }
                    else {
                        if (entity == null || entity.Health() < health - 1f) Plus(player, "HeadShots", 1);
                    }
                }
                );
            }
        }
        private ulong GetMajorityAttacker(ulong id) {
            if (HeliAttackers.ContainsKey(id)) return HeliAttackers[id].OrderByDescending(pair => pair.Value).First().Key;
            if (BradleyAttackers.ContainsKey(id)) return BradleyAttackers[id].OrderByDescending(pair => pair.Value).First().Key;
            return 0U;
        }
        void OnEntityDeath(BaseEntity entity, HitInfo hitinfo) {
            if (entity == null || entity.name.Contains("corpse")) return;
            var victim = entity as BasePlayer;
            bool npcVic = victim != null && (victim.IsNpc || victim.Categorize() == "Zombie" || IsHumanNPC(victim));
            var attacker = hitinfo?.Initiator as BasePlayer;
            if (attacker == null && victim != null) {
                if (woundedData.ContainsKey(victim.userID)) {
                    attacker = BasePlayer.FindByID(woundedData[victim.userID].attackerId);
                    if (attacker == null || !data.PlayerRankData.ContainsKey(attacker.userID)) return;
                    if (conf.Options.blockEvents) if (CheckEvents(attacker)) return;
                    var distance = woundedData[victim.userID].distance;
                    if (npcVic) {
                        data.PlayerRankData[attacker.userID]["NPCKills"] = D(data.PlayerRankData[attacker.userID]["NPCKills"]) + 1;
                        if (distance > D(data.PlayerRankData[attacker.userID]["NPCDistance"])) data.PlayerRankData[attacker.userID]["NPCDistance"] = Math.Round(distance, 2);
                    }
                    else {
                        data.PlayerRankData[attacker.userID]["PVPKills"] = D(data.PlayerRankData[attacker.userID]["PVPKills"]) + 1;
                        if (distance > D(data.PlayerRankData[attacker.userID]["PVPDistance"])) data.PlayerRankData[attacker.userID]["PVPDistance"] = Math.Round(distance, 2);
                        ProcessDeath(victim);
                    }
                    woundedData.Remove(victim.userID);
                }
                else if (!npcVic) {
                    string[] stringArray = {
                        "Cold", "Drowned", "Heat", "Suicide", "Generic", "Posion", "Radiation", "Thirst", "Hunger", "Fall"
                    }
                    ;
                    if (stringArray.Any(victim.lastDamage.ToString().Contains)) ProcessSuicide(victim);
                    ProcessDeath(victim);
                }
                return;
            }
            if (entity is PatrolHelicopter) {
                BasePlayer plyr = BasePlayer.FindByID(GetMajorityAttacker(entity.net.ID.Value));
                if (plyr != null) Plus(plyr, "HeliKills", 1);
                HeliAttackers.Remove(entity.net.ID.Value);
                return;
            }
            if (entity is BradleyAPC) {
                BasePlayer plyr = BasePlayer.FindByID(GetMajorityAttacker(entity.net.ID.Value));
                if (plyr != null) Plus(plyr, "APCKills", 1);
                BradleyAttackers.Remove(entity.net.ID.Value);
                return;
            }
            if (attacker != null) {
                bool explosion = hitinfo.damageTypes.GetMajorityDamageType() == DamageType.Explosion || hitinfo.damageTypes.GetMajorityDamageType() == DamageType.Heat;
                if (!attacker.IsNpc && attacker.Categorize() != "Zombie" && !IsHumanNPC(attacker)) {
                    if (entity is SimpleShark || entity is WildlifeHazard || entity is BaseNPC2 || entity.PrefabName.Contains("agents/") && !(entity is NPCPlayer)) PlusKill(attacker, entity, "PVEKills", "PVEDistance", 1, explosion);
                    else if (entity.name.Contains("barrel")) Plus(attacker, "BarrelsDestroyed", 1);
                    else if (victim == null && (entity.name.Contains("turret") || entity.name.Contains("guntrap"))) Plus(attacker, "WeaponTrapsDestroyed", 1);
                    else if (victim != null) {
                        if (attacker == victim) ProcessSuicide(attacker);
                        else if (npcVic) PlusKill(attacker, victim, "NPCKills", "NPCDistance", 1, explosion);
                        else {
                            if (victim.IsSleeping()) {
                                if (conf.Options.PVPKillsCountsSleeperKills) ProcessPVPKill(attacker, victim);
                                PlusKill(attacker, victim, "SleepersKilled", "PVPDistance", 1, explosion);
                            }
                            else ProcessPVPKill(attacker, victim);
                        }
                    }
                }
            }
            if (victim == null) return;
            if (!npcVic) ProcessDeath(victim);
            if (woundedData.ContainsKey(victim.userID)) woundedData.Remove(victim.userID);
        }
        public bool IsHumanNPC(BasePlayer player) {
            foreach (var comp in player?.GetComponents<Component>()) if (comp?.GetType()?.Name == "HumanPlayer") return true;
            return false;
        }
        void OnExplosiveThrown(BasePlayer player, BaseEntity exp, ThrownWeapon item) {
            if (exp != null && !(exp is SupplySignal)) Plus(player, "ExplosivesThrown", 1);
        }
        void OnWeaponFired(BaseProjectile projectile, BasePlayer player, ItemModProjectile mod) {
            if (mod.ToString().Contains("arrow"))  //Check ammo type instead
            Plus(player, "ArrowsFired", 1);
            if (mod.ToString().Contains("ammo")) Plus(player, "BulletsFired", 1);
        }
        void OnRocketLaunched(BasePlayer player) {
            var held = player.GetHeldEntity();
            if (held != null && held.ShortPrefabName.Contains("mgl") && !conf.Options.Include_MGL_In_RocketsLaunched) return;
            Plus(player, "RocketsLaunched", 1);
        }
        void OnEntityBuilt(Planner plan, GameObject objectBlock) {
            if (conf.Options.useIntenseOptions) {
                BasePlayer player = plan?.GetOwnerPlayer();
                if (player == null) return;
                if (player.GetActiveItem()?.info?.displayName?.english == "Building Plan") Plus(player, "StructuresBuilt", 1);
                else Plus(player, "ItemsDeployed", 1);
            }
        }
        void OnStructureDemolish(BaseCombatEntity entity, BasePlayer player) => Plus(player, "StructuresDemolished", 1);
        void OnItemCraft(ItemCraftTask item, BasePlayer crafter) {
            if (conf.Options.useIntenseOptions && crafter != null) Plus(crafter, "ItemsCrafted", item.amount);
        }
        void OnStructureRepair(BaseCombatEntity entity, BasePlayer player) {
            if (conf.Options.useIntenseOptions) Plus(player, "EntitiesRepaired", 1);
        }
        void OnHealingItemUse(HeldEntity item, BasePlayer target) {
            if (target?.net?.connection == null) return;
            Plus(target, "TimesHealed", 1);
        }
        void OnItemUse(Item item) {
            BasePlayer player = item?.GetOwnerPlayer();
            if (player?.net?.connection == null) return;
            if (item.GetOwnerPlayer() == null) return;
            if (player != null && item.info.displayName.english == "Large Medkit") Plus(player, "TimesHealed", 1);
            if (item.info.shortname != "skull.human" || item.name == null || !item.name.Contains("Skull of")) return;
            if (!player.displayName.Contains($"{item.name.Substring(10, item.name.Length - 11)}")) Plus(player, "SkullsCrushed", 1);
        }
        void CanBeWounded(BasePlayer player, HitInfo hitInfo) {
            if (player == null || hitInfo == null) return;
            if (player.net?.connection == null) return;
            var attacker = hitInfo.InitiatorPlayer;
            if (attacker != null) {
                if (attacker == player || FriendCheck(player, attacker)) return;
                woundedData[player.userID] = new WoundedData {
                    distance = Vector3.Distance(player.transform.position, attacker.transform.position), attackerId = attacker.userID
                }
                ;
                NextTick(() => {
                    if (player.IsWounded()) Plus(player, "TimesWounded", 1);
                }
                );
            }
        }
        void OnPlayerRecover(BasePlayer player) {
            if (woundedData.ContainsKey(player.userID)) woundedData.Remove(player.userID);
        }
        void OnStructureUpgrade(BaseCombatEntity entity, BasePlayer player, BuildingGrade.Enum grade) => Plus(player, "StructuresUpgraded", 1);
        void OnDispenserBonus(ResourceDispenser d, BaseEntity e, Item i) => OnDispenserGather(d, e, i);
        void OnDispenserGather(ResourceDispenser dispenser, BaseEntity entity, Item item) {
            if (entity == null || item == null) return;
            BasePlayer player = entity.ToPlayer();
            if (player != null) UpCollect(player, item.amount);
        }
        void OnGrowableGathered(GrowableEntity plant, Item item, BasePlayer p) {
            if (plant != null && p != null && item != null) {
                if (plant?.planter == null && conf.Options.CountPlantsOnlyFromPlanters) return;
                Plus(p, "PlantsGathered", item.amount);
            }
        }
        List<ulong> UsedIDs = new List<ulong>();
        void OnCollectiblePickup(CollectibleEntity item, BasePlayer player) {
            if (item?.net?.ID == null || item.itemList == null || item.itemList[0] == null) return;
            if (UsedIDs.Contains(item.net.ID.Value)) return;
            UsedIDs.Add(item.net.ID.Value);
            UpCollect(player, (int)item.itemList[0].amount);
        }
        void UpCollect(BasePlayer p, int amount) {
            if (!conf.Options.useIntenseOptions || amount < 1) return;
            NextTick(() => {
                if (p != null) Plus(p, "ResourcesGathered", amount);
            }
            );
        }
        void OnFishCatch(Item item, BaseFishingRod rod, BasePlayer player) {
            if (player == null || item?.info?.shortname == null) return;
            if (item?.info?.category == ItemCategory.Food && !item.info.shortname.Contains("water")) Plus(player, "FishCaught", 1);
        }
        void OnMlrsFired(MLRS mlrs, BasePlayer player) => Plus(player, "MLRSFired", 1);
        void OnEntitySpawned(SupplyDrop entity) {
            NextTick(() => {
                if (entity != null) airdrops.Add(entity.net.ID.Value);
            }
            );
        }
        void OnLootEntity(BasePlayer player, SupplyDrop entity) {
            if (player == null || entity?.net?.ID == null) return;
            if (airdrops.Contains(entity.net.ID.Value)) {
                airdrops.Remove(entity.net.ID.Value);
                Plus(player, "DropsLooted", 1);
            }
        }
#endregion
#region Processes
        bool ProcessChecks(BasePlayer player) {
            if (!loaded) return false;
            if ((!conf.Options.statCollection) || (conf.Options.blockEvents && CheckEvents(player))) return false;
            return data.PlayerRankData.ContainsKey(player.userID);
        }
        bool FriendCheck(BasePlayer player, BasePlayer victim) {
            if (player?.net?.connection == null || victim?.net?.connection == null) return false;
            if (Clans && !conf.Options.record_ClanMate_Kills) if (IsClanmate(player.userID, victim.userID)) return true;
            if (Friends && !conf.Options.record_FriendsAPI_Kills) if (IsFriend(player.userID, victim.us
// ... [Code preview truncated due to length. Full source in attached file] ...

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху