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

FREE ZLevelsRemastered : 3.0.9 3.0.9

Нет прав для скачивания
C#:
using UnityEngine;
using System.Collections.Generic;
using System;
using Oxide.Core;
using Oxide.Core.Plugins;
using System.Text;
using System.Reflection;
using Oxide.Core.Libraries.Covalence;
using System.Diagnostics;
using System.Linq;
using Newtonsoft.Json;
using System.ComponentModel;
using System.Text.RegularExpressions;
using Pool = Facepunch.Pool;
namespace Oxide.Plugins {
    [Info("Zeiser Levels REMASTERED", "Zeiser/Visagalis/Shady", "3.0.9", ResourceId = 1453)]
    [Description("Lets players level up as they harvest different resources and when crafting.")]
    public class ZLevelsRemastered : RustPlugin {
        /*
         * Copyright 2024 PRISM
         *
         * This file is part of PRISM's plugins.*
         * PRISM's plugins is free software: you can redistribute it and/or modify
         * it under the terms of the GNU General Public License as published by
         * the Free Software Foundation, either version 3 of the License, or
         * (at your option) any later version.*
         * PRISM's plugins is distributed in the hope that it will be useful,
         * but WITHOUT ANY WARRANTY; without even the implied warranty of
         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
         * GNU General Public License for more details.*
         * You should have received a copy of the GNU General Public License
         * along with PRISM's plugins.If not, see <https://www.gnu.org/licenses/>.*/
        /*
         * The below is not a license (that can be found above), but simply a notice to the reader of this code:
         * The development of PRISM has been gradual and started in 2014.* Some of the code provided in this repository may be outdated and may not be the best representation of the author's current coding practices.* Some of the code provided in this repository may have been initially developed in 2014.* Files not containing the above license are not uniquely part of PRISM's plugins and are subject to the license of the original plugin, where applicable.* No copyright infringement is ever intended and the author of PRISM's plugins will comply with any requests to remove code.* PRISM's plugins are provided as is and no functionality is guaranteed.* Many of these plugins will not work without significant changes as there are numerous instances of hard-coded functions and may rely on external API calls that are not a part of this project itself.* 
         * 
         * With those notices out of the way, I, Shady, the author of this plugin, would like you to read and acknowledge the following:
         * These plugins are part of a decade long passion project where we, PRISM, created a unique experience to all players on our Rust servers.* This was a significant part of my life.I dedicated a decade to developing and maintaining these plugins and the servers themselves.* I implore you that, should you use any of the code or plugins provided in this repository, where it belongs solely to PRISM, that you respect the time and effort put into it.* Please remember that I, a single human, invested a significant amount of time and effort into these plugins and the servers they were used on.* Please feel free to critique my code as it is written; I am aware it is not perfect.Much of it is old, and I'm capable of doing far better now.* Moreover, I ask, sincerely, that you do not use these plugins or code without acknowledging that someone dedicated themselves to this passion project.* In asking that, it is my simple desire that you do not let these plugins be used in a way that is inconsistent with my own desires and love.* Please do not use them and claim them as your own.I wish for you to use them on your server and make that server something of your own.* Something unique and beautiful.However, I ask that you do not use these plugins and claim them as your own work.* Should you make changes to them, you are, of course, the author of those changes.But, if your code is based on one of PRISM's original plugins, please do not claim it as your own.* I also request that you do not use the plugins in a way that would be detrimental to the Rust community or the community of server owners.* In doing so, I ask that you please do not monetize the functions within these plugins with any changes you should make.* Should you use any of PRISM's plugins or its code, please do not lock anything behind a paywall or in a way that is unfair to the community of Rust.* My origin is that of one where I saw, daily, very young players who only wished to enjoy a few hours of their life on a video game and in many cases had little or no expendable income.* For many people, even purchasing the game is significantly difficult.It is, in my eyes, unfair to create fun, custom content, and suggest that you care about the community while also charging for it or creating an unfair environment where players who pay are significantly advantaged compared to those who cannot afford to do so.* I cannot control what you do with this code, but I ask that you respect the spirit in which it was created:
         * That is one of sincere love, care, and appreciation for the people who played on PRISM's servers.* Our community, much like yours, is your entire server.Your people matter, just as you matter.Please remember that *everyone* deserves a fair, fun environment.* I ask that should you use these plugins, you do so with the same love and care that I put into them.I ask that you do so with the same respect, love, care, and appreciation for the people who will play on your server.*
         * One of my greatest helps over the years was MBR.He has been a wonderful person, friend, and developer; I am beyond grateful for his contributions to us, but moreover, his friendship.* Some of these plugins were authored solely by him, or with his help.Where this has occurred, it should be noted in the author field at the top of the plugin.* Worthy of note is that he is solely responsible for our top-tier Discord integration.* If you so wish to see his GitHub page, here it is linked below:
         * https://github.com/MBR-0001
         * 
         * 
         * Should you wish to support the work that I have put into this project of the past decade, please consider doing so here:
         * https://www.buymeacoffee.com/shady757
         * 
         * I neither expect nor anticipate any such donations.You are by no means obligated, it is truly a donation.It should be done out of the kindness of your heart, if you so choose.* 
         * PRISM, as a community, has not ceased and continues to exist.We have no plans of ceasing our community.We have, however, ceased our Rust servers and thus made these plugins open source.* If you ever wish to contact me, or simply join our community and become one of our beloved members, please join us here:
         * https://discord.gg/DUCnZhZ
         * 
         * To quote Rush: "There is magic at your fingers".* With love,
         * Shady and all of PRISM.Thank you for everything, always.* 
         */
        private readonly FieldInfo lastConsumeTime = typeof(PlayerMetabolism).GetField("lastConsumeTime", BindingFlags.Instance | BindingFlags.NonPublic);
        private readonly Dictionary<string, string> skillColors = new();
        private readonly Dictionary<string, List<string>> _skillsTop5 = new();
        private readonly Dictionary<BasePlayer, Item> _lastActiveItem = new();
        private readonly Dictionary<string, float> _lastGuiUpdate = new();
        //private readonly Dictionary<string, Dictionary<string, long>> lastXP = new Dictionary<string, Dictionary<string, long>>();
        private readonly List<string> xpHitOff = new();
        public const string LUCK_COLOR = "#5DC540";
        private const int RockID = 963906841;
        //pickaxes:
        private const int PICKAXE_ID = -1302129395;
        private const int STONE_PICKAXE_ID = 171931394;
        private const int ICE_PICK_ID = -1780802565;
        private const int JACKHAMMER_ID = 1488979457;
        private const int PROTO_PICK_ID = 236677901;
        private const int CONCRETE_PICK_ID = -1360171080;
        private const int ABYSS_PICK_ID = 1561022037;
        //axes:
        private const int CHAINSAW_ID = 1104520648;
        private const int HATCHET_ID = -1252059217;
        private const int SALVAGED_AXE_ID = -262590403;
        private const int STONE_AXE_ID = -1583967946;
        private const int PROTO_AXE_ID = -399173933;
        private const int CONCRETE_AXE_ID = 1176355476;
        private const int ABYSS_AXE_ID = 1046904719;
        private const int CactusFleshID = 1783512007;
        private const int ClothID = -858312878;
        private const int TroutID = -1878764039;
        private const int RAW_FISH_ITEM_ID = 989925924;
        private readonly HashSet<string> _forbiddenTags = new(6) {
            "</color>", "</size>", "<b>", "</b>", "<i>", "</i>"
        }
        ;
        private readonly Regex _colorRegex = new("(<color=.+?>)", RegexOptions.Compiled);
        private readonly Regex _sizeRegex = new("(<size=.+?>)", RegexOptions.Compiled);
        [PluginReference]
        private readonly Plugin LevelsGUI;
        [PluginReference]
        private readonly Plugin Luck;
        [PluginReference]
        private readonly Plugin PRISMAchievements;
        [PluginReference]
        private readonly Plugin PlayersByDatabase;
        [PluginReference]
        private readonly Plugin RadRain;
        private void OnPlayerConnected(BasePlayer player) {
            if (player == null) return;
            var hasAchievements = PRISMAchievements?.IsLoaded ?? false;
            for (int i = 0; i < Skills.ALL.Length; i++) {
                var skill = Skills.ALL[i];
                if (IsSkillDisabled(skill)) continue;
                if (hasAchievements && GetLevel(player.UserIDString, skill) >= 99) GrantMasteryAchievement(player, skill);
                NewLvlInfo(player.UserIDString, skill, 10, 1);
                //this only creates a new level info if one does not exist
            }
            player.Invoke(() => {
                if (player == null || player.IsDestroyed || !player.IsConnected) return;
                CreateGUIAllSkills(player);
            }
            , 0.125f);
        }
        private void GrantMasteryAchievement(BasePlayer player, string skill) {
            if (player == null) throw new ArgumentNullException(nameof(player));
            if (string.IsNullOrEmpty(skill)) throw new ArgumentNullException(nameof(skill));
            if (!(PRISMAchievements?.IsLoaded ?? false)) {
                PrintWarning(nameof(GrantMasteryAchievement) + " called but PA is null!!");
                return;
            }
            var foundSkill = false;
            for (int i = 0; i < Skills.ALL.Length; i++) {
                var skillName = Skills.ALL[i];
                if (skillName.Equals(skill, StringComparison.OrdinalIgnoreCase)) {
                    foundSkill = true;
                    break;
                }
            }
            if (!foundSkill) throw new ArgumentException($"Skill {skill} is not a valid skill.", nameof(skill));
            //auto generated code lol
            PrintWarning("Trying to grant achievement for >= 99: " + skill);
            var sb = Pool.Get<StringBuilder>();
            try {
                PRISMAchievements.Call("GiveAchievementByName", player, sb.Clear().Append(Name).Append("_").Append(skill).Append("_mastery").ToString());
            }
            finally {
                Pool.Free(ref sb);
            }
        }
        public bool IsDivisble(int x, int n) {
            return (x % n) == 0;
        }
        private void CelebrateEffects(BasePlayer player, int timesToRun = 1) {
            if (timesToRun < 1) throw new ArgumentOutOfRangeException(nameof(timesToRun));
            if (player == null || player.gameObject == null || player.IsDestroyed || player.transform == null) return;
            var eyePos = player?.eyes?.transform?.position ?? Vector3.zero;
            var eyeForward = player?.eyes?.HeadForward() ?? Vector3.zero;
            for (int j = 0; j < timesToRun; j++) {
                Effect.server.Run("assets/bundled/prefabs/fx/missing.prefab", SpreadVector2(eyePos + eyeForward * UnityEngine.Random.Range(1.5f, 1.9f), UnityEngine.Random.Range(1.35f, 2.2f)), Vector3.zero);
                Effect.server.Run("assets/prefabs/misc/orebonus/effects/bonus_hit.prefab", SpreadVector2(new Vector3(eyePos.x, eyePos.y + UnityEngine.Random.Range(0.5f, 1f), eyePos.z) + eyeForward * UnityEngine.Random.Range(0.6f, 1.2f), UnityEngine.Random.Range(0.8f, 2f)), Vector3.zero);
                Effect.server.Run("assets/prefabs/misc/orebonus/effects/hotspot_death.prefab", SpreadVector2(new Vector3(eyePos.x, eyePos.y + 0.6f, eyePos.z) + eyeForward * UnityEngine.Random.Range(0.6f, 1.2f), UnityEngine.Random.Range(1.1f, 3f)), Vector3.zero);
            }
            SendLocalEffect(player, "assets/prefabs/deployable/research table/effects/research-success.prefab");
            player.SignalBroadcast(BaseEntity.Signal.Gesture, "victory", null);
        }
        private Vector3 SpreadVector2(Vector3 vec, float spread) {
            return vec + UnityEngine.Random.insideUnitSphere * spread;
        }
        private void SendLocalEffect(BasePlayer player, string effect, Vector3 pos, float scale = 1f) {
            if (player == null || player?.net?.connection == null || !player.IsConnected || string.IsNullOrEmpty(effect) || pos == Vector3.zero) return;
            using (var fx = new Effect(effect, pos, Vector3.zero)) {
                fx.scale = scale;
                EffectNetwork.Send(fx, player?.net?.connection);
            }
        }
        private void SendLocalEffect(BasePlayer player, string effect, float scale = 1f, uint boneID = 0, Vector3 localPos = default(Vector3)) {
            if (player == null || player?.net?.connection == null || !player.IsConnected || string.IsNullOrEmpty(effect)) return;
            using (var fx = new Effect(effect, player, boneID, localPos, Vector3.zero)) {
                fx.scale = scale;
                EffectNetwork.Send(fx, player?.net?.connection);
            }
        }
        public static class Skills {
            public const string WOODCUTTING = "WC";
            public const string SURVIVAL = "S";
            public const string MINING = "M";
            public static string[] ALL = new[] {
                WOODCUTTING, MINING, SURVIVAL
            }
            ;
        }
        private readonly Dictionary<string, string> colors = new() {
            // {Skills.WOODCUTTING, "#CC6600"},
            {
                Skills.WOODCUTTING, "#977C46"
            }
            , {
                Skills.MINING, "#6DA7BF"
            }
            ,  //{Skills.MINING, "#167FCC"},
            {
                Skills.SURVIVAL, "#7F7B66"
            }
            // {Skills.SURVIVAL, "#CC1600"}
        }
        ;
        private class LevelInfo {
            [JsonProperty(NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
            [DefaultValue("")]
            public string Skill {
                get;
                private set;
            }
            = string.Empty;
            [JsonProperty(NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
            [DefaultValue(10L)]
            public long XP = 10;
            [JsonProperty(NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
            [DefaultValue(1L)]
            public long Level = 1;
            public LevelInfo(string skill, long xp, long level) {
                if (string.IsNullOrEmpty(skill)) throw new ArgumentNullException(nameof(skill));
                if (xp < 10) xp = 10;
                if (level < 1) level = 1;
                Skill = skill;
                XP = xp;
                Level = level;
            }
        }
        private class UserLevelInfo {
            public Dictionary<string, LevelInfo> _classNameToSkill;
        }
        private class XPData {
            public Dictionary<string, List<LevelInfo>> levelInfos = new();
            public XPData() {
            }
        }
        private XPData xpData;
        private LevelInfo NewLvlInfo(string userID, string skill, long xp = 0, long level = 0) {
            if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(skill)) return null;
            var lvlInfo = GetLvlInfo(userID, skill);
            if (lvlInfo != null) return lvlInfo;
            lvlInfo = new LevelInfo(skill, xp, level);
            if (!xpData.levelInfos.TryGetValue(userID, out var listInfo)) xpData.levelInfos[userID] = new List<LevelInfo>();
            if (!xpData.levelInfos[userID].Contains(lvlInfo)) xpData.levelInfos[userID].Add(lvlInfo);
            return lvlInfo;
        }
        private LevelInfo GetLvlInfo(string userID, string skill) {
            if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(skill) || xpData?.levelInfos == null) return null;
            if (!xpData.levelInfos.TryGetValue(userID, out var lvlInfos)) return null;
            if (lvlInfos == null || lvlInfos.Count < 1) return null;
            for (int i = 0; i < lvlInfos.Count; i++) {
                var lvl = lvlInfos[i];
                if (lvl?.Skill == skill) return lvl;
            }
            return null;
        }
        private void SetLvlInfo(string userID, string skill, long points) {
            if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(skill)) return;
            var pointsLvl = GetPointsLevel(points, skill);
            var lvlInfo = GetLvlInfo(userID, skill);
            if (points < 10) points = 10;
            if (lvlInfo != null) {
                var oldLvl = lvlInfo.Level;
                lvlInfo.Level = pointsLvl;
                lvlInfo.XP = points;
                if (pointsLvl != oldLvl) UpdateTop5Cache(skill);
            }
            else NewLvlInfo(userID, skill, points, pointsLvl);
        }
        private void ResetLvl(string userId, string skill) {
            if (string.IsNullOrEmpty(userId)) throw new ArgumentNullException(nameof(userId));
            if (string.IsNullOrEmpty(skill)) throw new ArgumentNullException(nameof(skill));
            var lvlInfo = GetLvlInfo(userId, skill);
            var newXp = GetLevelPoints(1);
            if (lvlInfo != null) {
                lvlInfo.Level = 1;
                lvlInfo.XP = newXp;
            }
            else NewLvlInfo(userId, skill, newXp, 1);
            if (ulong.TryParse(userId, out var userIdLong)) {
                var ply = BasePlayer.FindByID(userIdLong);
                if (ply != null && ply.IsConnected) GUIUpdateSkill(ply, skill);
            }
        }
        private double GetPointsPerHit(string skill) {
            if (string.IsNullOrEmpty(skill)) throw new ArgumentNullException(nameof(skill));
            return pointsPerHit.TryGetValue(skill, out var xp) ? xp : -1;
        }
#region Stats
        [HookMethod("SendHelpText")]
        private void SendHelpText(BasePlayer player) {
            if (player == null || !player.IsConnected) return;
            string text = "/stats - Displays your stats.\n/statsui - Displays/hides stats UI.\n/statinfo [statsname] - Displays information about stat.\n" + "/topskills - Display max levels reached so far.";
            SendReply(player, text);
        }
        private Dictionary<string, object> getMessages() {
            return messages;
        }
        private Dictionary<string, string> getColors() {
            return colors;
        }
        private string GetDisplayNameFromID(string userID) {
            if (string.IsNullOrEmpty(userID)) return string.Empty;
            return covalence.Players.FindPlayerById(userID)?.Name ?? string.Empty;
        }
        private void UpdateTop5AllSkills() {
            for (int i = 0; i < Skills.ALL.Length; i++) {
                var skill = Skills.ALL[i];
                if (!IsSkillDisabled(skill)) UpdateTop5Cache(skill);
            }
        }
        private List<string> UpdateTop5Cache(string skillName) {
            if (string.IsNullOrEmpty(skillName)) throw new ArgumentNullException(nameof(skillName));
            if (!_skillsTop5.TryGetValue(skillName, out var list)) list = new List<string>();
            else list.Clear();
            GetTop5NoAlloc(skillName, ref list);
            _skillsTop5[skillName] = list;
            return list;
        }
        private List<string> GetCachedTop5(string skillName) {
            if (string.IsNullOrEmpty(skillName)) throw new ArgumentNullException(nameof(skillName));
            if (!_skillsTop5.TryGetValue(skillName, out var list)) list = UpdateTop5Cache(skillName);
            return list;
        }
        private void GetTop5NoAlloc(string skillName, ref List<string> list, params string[] ignoreIds) {
            if (string.IsNullOrEmpty(skillName)) throw new ArgumentNullException(nameof(skillName));
            if (list == null) throw new ArgumentNullException(nameof(list));
            var watch = Pool.Get<Stopwatch>();
            try {
                watch.Restart();
                var skillFind = string.Empty;
                for (int i = 0; i < Skills.ALL.Length; i++) {
                    var skill = Skills.ALL[i];
                    if (skill.Equals(skillName, StringComparison.OrdinalIgnoreCase)) {
                        skillFind = skill;
                        break;
                    }
                }
                if (string.IsNullOrEmpty(skillFind)) return;
                var xps = Pool.Get<Dictionary<string, Dictionary<string, long>>>();
                try {
                    xps.Clear();
                    var top5Skill = Pool.Get<Dictionary<string, List<string>>>();
                    try {
                        top5Skill.Clear();
                        xps[skillFind] = new Dictionary<string, long>();
                        var players = Pool.GetList<string>();
                        try {
                            GetAllPlayerIDsNoAlloc(ref players);
                            for (int i = 0; i < players.Count; i++) {
                                var userId = players[i];
                                if (ignoreIds != null && ignoreIds.Contains(userId)) continue;
                                var points = GetPoints(userId, skillFind);
                                if (points < 15) continue;
                                //filter out extremely low level players
                                xps[skillFind][userId] = points;
                            }
                        }
                        finally {
                            Pool.FreeList(ref players);
                        }
                        if (xps[skillFind].Keys.Count < 1 || xps[skillFind].Values.Count < 5) return;
                        var top5 = (from entry in xps[skillFind] orderby entry.Value descending select entry).Take(5);
                        foreach (var kvp in top5) {
                            var findID = string.Empty;
                            foreach (var kvp2 in xps[skillFind]) {
                                if (kvp2.Value == kvp.Value) {
                                    findID = kvp.Key;
                                    break;
                                }
                            }
                            if (!string.IsNullOrEmpty(findID)) list.Add(findID);
                        }
                    }
                    finally {
                        Pool.Free(ref top5Skill);
                    }
                }
                finally {
                    Pool.Free(ref xps);
                }
            }
            finally {
                try {
                    if (watch.ElapsedMilliseconds >= 10) PrintWarning(nameof(GetTop5NoAlloc) + " took: " + watch.ElapsedMilliseconds + "ms");
                }
                finally {
                    Pool.Free(ref watch);
                }
            }
        }
        private void StatsTopCommand(IPlayer player, string command, string[] args) {
            var xps = new Dictionary<string, Dictionary<string, long>>();
            var top5Skill = new Dictionary<string, List<string>>();
            var topSkillsSB = new StringBuilder();
            for (int i = 0; i < Skills.ALL.Length; i++) {
                var skill = Skills.ALL[i];
                if (IsSkillDisabled(skill)) continue;
                if (!top5Skill.TryGetValue(skill, out var outList)) top5Skill[skill] = new List<string>();
                if (!xps.TryGetValue(skill, out var xpOut)) xps[skill] = new Dictionary<string, long>();
                var players = Pool.GetList<string>();
                try {
                    GetAllPlayerIDsNoAlloc(ref players);
                    for (int j = 0; j < players.Count; j++) {
                        var userId = players[j];
                        var points = GetPoints(userId, skill);
                        if (points < 15) continue;
                        //filter out extremely low level players
                        xps[skill][userId] = points;
                    }
                }
                finally {
                    Pool.FreeList(ref players);
                }
                if (xps[skill].Keys.Count < 1 || xps[skill].Values.Count < 1) continue;
                var max = xps[skill]?.Values?.Max() ?? 0f;
                var newXp = new KeyValuePair<string, long>();
                foreach (var kvp in xps[skill]) {
                    if (kvp.Value == max) {
                        newXp = kvp;
                        break;
                    }
                }
                var top5 = (from entry in xps[skill] orderby entry.Value descending select entry).Take(5);
                foreach (var kvp in top5) if (!top5Skill[skill].Contains(kvp.Key)) top5Skill[skill].Add(kvp.Key);
                var maxLvl = GetLevel(newXp.Key.ToString(), skill);
                var name = GetDisplayNameFromID(newXp.Key);
                if (string.IsNullOrEmpty(name) || name.Equals("Shady", StringComparison.OrdinalIgnoreCase)) name = "Null Player";
                topSkillsSB.AppendLine("<color=" + colors[skill] + ">" + messages[skill + "Skill"] + ": " + maxLvl + " (XP: " + newXp.Value.ToString("N0") + ")</color> <- " + name);
            }
            if (args.Length == 1) {
                var specSB = new StringBuilder();
                var skillFind = string.Empty;
                var arg0Lower = args[0].ToLower();
                if (arg0Lower == "wc" || arg0Lower == "woodcutting") skillFind = "WC";
                if (arg0Lower == "m" || arg0Lower == "mining") skillFind = "M";
                if (arg0Lower == "s" || arg0Lower == "skinning" || arg0Lower == "survival") skillFind = "S";
                if (string.IsNullOrEmpty(skillFind)) {
                    SendReply(player, "Bad skill: " + args[0] + ", try WC, M, or S");
                    return;
                }
                var top5spec = top5Skill.Where(p => p.Key == skillFind);
                if (top5spec == null || !top5spec.Any()) {
                    SendReply(player, "Bad skill: " + args[0] + ", try WC, M, or S");
                    return;
                }
                foreach (var kvp in top5spec) {
                    foreach (var entry in kvp.Value) {
                        var getLvl = GetLevel(entry, kvp.Key);
                        var getXP = GetPoints(entry, kvp.Key);
                        var name = GetDisplayNameFromID(entry);
                        if (string.IsNullOrEmpty(name)) name = "Null Player";
                        specSB.AppendLine("<color=" + colors[skillFind] + ">" + messages[skillFind + "Skill"] + ": " + getLvl.ToString("N0") + " (XP: " + getXP.ToString("N0") + ")</color> <- " + name);
                    }
                }
                if (specSB.Length > 0) SendReply(player, specSB.ToString().TrimEnd());
                else SendReply(player, "Failed to get skill info for: " + args[0]);
                return;
            }
            var finalMsg = "<color=#00b2c6>You can view the top 5 for specific skills by doing:</color> /" + command + " WC, /" + command + " M, or /" + command + " S\nYou can view top <color=" + LUCK_COLOR + ">Luck</color> levels by typing <color=" + LUCK_COLOR + ">/topluck</color>.";
            if (topSkillsSB.Length > 0) SendReply(player, topSkillsSB.ToString().TrimEnd() + Environment.NewLine + finalMsg);
            else SendReply(player, "No top skills yet!" + Environment.NewLine + finalMsg);
            if ((Luck?.IsLoaded ?? false)) Luck.Call("SendTopLuckText", player);
        }
        [ConsoleCommand("zlvls.arithmetic")]
        private void cmdMathTest(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) return;
            var args = arg?.Args ?? null;
            if (args == null || args.Length < 1) {
                SendReply(arg, "Please supply a points value (float)");
                return;
            }
            if (!float.TryParse(args[0], out var val)) {
                SendReply(arg, "Not a float: " + args[0]);
                return;
            }
            var watch = Stopwatch.StartNew();
            double x1 = (-100 - Math.Sqrt(100 * 100 - 4 * 110 * -val)) / (2 * 110);
            var x2 = (int)-x1;
            watch.Stop();
            PrintWarning("Negative math (twice) took: " + watch.Elapsed.TotalMilliseconds + "ms");
            watch.Reset();
            watch.Start();
            var x3 = (100 + Math.Sqrt(100 * 100 + 4 * 110 * val)) / (2 * 110);
            watch.Stop();
            PrintWarning("Positive math (once) took: " + watch.Elapsed.TotalMilliseconds + "ms");
            PrintWarning("Values: x1: " + x1 + Environment.NewLine + "x2: " + x2 + Environment.NewLine + "x3: " + x3);
        }
        [ConsoleCommand("zlvls.fix")]
        private void zlvlFix(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) return;
            var newDict = xpData?.levelInfos?.ToDictionary(p => p.Key, p => p.Value) ?? null;
            if (newDict == null || newDict.Count < 1) {
                SendReply(arg, "No zlvl infos!");
                return;
            }
            var removeSB = new StringBuilder();
            var removeCount = 0;
            foreach (var kvp in newDict) {
                var findLvl = kvp.Value?.Where(p => p.Level < 1)?.ToList() ?? null;
                if (findLvl != null && findLvl.Count > 0) {
                    for (int i = 0; i < findLvl.Count; i++) {
                        var lvl = findLvl[i];
                        if (lvl == null) continue;
                        SetLvlInfo(kvp.Key, lvl.Skill, 10);
                        removeSB.AppendLine(GetDisplayNameFromID(kvp.Key) + " (" + kvp.Key + ") : " + lvl.Skill);
                    }
                }
                //     var addCount = kvp.Value.RemoveAll(p => ((p?.Level ?? 0) <= 3));
                //   if (addCount > 0) removeSB.AppendLine(GetDisplayNameFromID(kvp.Key) + " (" + kvp.Key + ")");
                // removeCount += addCount;
                //       removeCount += kvp.Value.RemoveAll(p => ((p?.Level ?? 0) <= 1));
            }
            xpData.levelInfos = newDict;
            SaveXPData();
            SendReply(arg, "Fixed " + removeCount + " entries:\n" + removeSB.ToString().TrimEnd());
        }
        [ConsoleCommand("zlvls.purge")]
        private void lkPurge(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) return;
            var newDict = xpData?.levelInfos?.ToDictionary(p => p.Key, p => p.Value) ?? null;
            if (newDict == null || newDict.Count < 1) {
                SendReply(arg, "No zlvl infos!");
                return;
            }
            var removeSB = new StringBuilder();
            var removeCount = 0;
            foreach (var kvp in newDict) {
                if (FindConnectedPlayer(kvp.Key) != null) continue;
                var findLvl = kvp.Value?.Where(p => p.Level <= 1)?.ToList() ?? null;
                if (findLvl != null && findLvl.Count > 0) {
                    for (int i = 0; i < findLvl.Count; i++) {
                        var lvl = findLvl[i];
                        if (lvl == null) continue;
                        removeSB.AppendLine(GetDisplayNameFromID(kvp.Key) + " (" + kvp.Key + "), skill: " + lvl.Skill + ", " + lvl.Level + ", " + lvl.XP);
                        kvp.Value.Remove(lvl);
                    }
                }
                //     var addCount = kvp.Value.RemoveAll(p => ((p?.Level ?? 0) <= 3));
                //   if (addCount > 0) removeSB.AppendLine(GetDisplayNameFromID(kvp.Key) + " (" + kvp.Key + ")");
                // removeCount += addCount;
                //       removeCount += kvp.Value.RemoveAll(p => ((p?.Level ?? 0) <= 1));
            }
            xpData.levelInfos = newDict;
            SaveXPData();
            SendReply(arg, "Removed " + removeCount + " entries:\n" + removeSB.ToString().TrimEnd());
        }
        [ConsoleCommand("zlvl.transfer")]
        private void TransferCommand(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) return;
            var args = arg?.Args ?? null;
            if (args == null || args.Length < 2) {
                SendReply(arg, "Bad args, try: zlvl.transfer steamID newSteamID");
                return;
            }
            if (!ulong.TryParse(args[0], out var orgID)) {
                SendReply(arg, "Failed to parse: " + args[0] + " as steam ID!");
                return;
            }
            if (!ulong.TryParse(args[1], out var newID)) {
                SendReply(arg, "Failed to parse: " + args[1] + " as steam ID!");
                return;
            }
            if (orgID == newID) {
                SendReply(arg, "You cannot transfer stats to the same player!");
                return;
            }
            var newIDStr = newID.ToString();
            var orgIDStr = orgID.ToString();
            var setSB = new StringBuilder();
            for (int i = 0; i < Skills.ALL.Length; i++) {
                var skill = Skills.ALL[i];
                var oldLevel = GetLevel(orgIDStr, skill);
                var oldPoints = GetPoints(orgIDStr, skill);
                if (oldPoints > GetPoints(newIDStr, skill)) {
                    SetLvlInfo(newIDStr, skill, oldPoints);
                    setSB.AppendLine("Set: " + skill + " to level " + oldLevel + ", points: " + oldPoints);
                }
            }
            var newPlayer = covalence.Players?.FindPlayerById(newIDStr)?.Object as BasePlayer;
            if (newPlayer != null && newPlayer.IsConnected) CreateGUIAllSkills(newPlayer);
            SendReply(arg, setSB.ToString().TrimEnd());
        }
        [ConsoleCommand("zlvl.reset")]
        private void ResetCommand(ConsoleSystem.Arg arg) {
            if (arg == null || !arg.IsAdmin) return;
            var args = arg?.Args ?? null;
            var playerId = (args == null || args.Length < 1) ? (arg?.Player()?.UserIDString ?? string.Empty) : (FindConnectedPlayer(args[0], true)?.Id ?? string.Empty);
            if (string.IsNullOrWhiteSpace(playerId)) {
                SendReply(arg, "No player found!");
                return;
            }
            for (int i = 0; i < Skills.ALL.Length; i++) {
                var skill = Skills.ALL[i];
                SetLvlInfo(playerId, skill, 10);
            }
            for (int i = 0; i < BasePlayer.activePlayerList.Count; i++) {
                var ply = BasePlayer.activePlayerList[i];
                if (ply.UserIDString == playerId) {
                    CreateGUIAllSkills(ply);
                    PrintWarning("Called CreateGUIAllSkills for ply: " + ply?.displayName + " after stats reset");
                    break;
                }
            }
            SendReply(arg, "Reset all stats for " + playerId + "!");
        }
        [ConsoleCommand("zlvl.set")]
        private void SetLvlCommand(ConsoleSystem.Arg arg) {
            if (arg == null || !arg.IsAdmin) return;
            var args = arg?.Args ?? null;
            if (args?.Length < 3) {
                SendReply(arg, "You must supply a username, skill and level to set.First integer is skill index (0 = Woodcutting, 1 = Mining, 2 = Survival) Example: " + "zlvl.set Name 1 1");
                return;
            }
            var playerObj = FindConnectedPlayer(args[0], true)?.Object;
            if (playerObj == null) {
                SendReply(arg, "No player found!");
                return;
            }
            var pid = (playerObj as BasePlayer)?.UserIDString ?? (playerObj as IPlayer)?.Id ?? string.Empty;
            if (string.IsNullOrEmpty(pid)) {
                SendReply(arg, "No ID found on player object!");
                return;
            }
            if (!int.TryParse(args[1], out var index)) {
                SendReply(arg, "Not an integer: " + args[1]);
                return;
            }
            if (index < 0 || index > 2) {
                SendReply(arg, "Index is out of range, should be 0-2");
                return;
            }
            if (!int.TryParse(args[2], out var level)) {
                SendReply(arg, "Not an integer: " + args[2]);
                return;
            }
            SetLvlInfo(pid, Skills.ALL[index], GetLevelPoints(level));
            var ply = playerObj as BasePlayer;
            if (ply != null && ply.IsConnected) {
                CreateGUIAllSkills(ply);
                PrintWarning("Called CreateGUIAllSkills for ply: " + ply?.displayName + " after stats change");
            }
            SendReply(arg, "Changed stats!");
        }
        private void StatsCommand(IPlayer player, string command, string[] args) {
            if (player.IsServer) return;
            var textSB = Pool.Get<StringBuilder>();
            try {
                textSB.Clear();
                for (int i = 0; i < Skills.ALL.Length; i++) {
                    var skill = Skills.ALL[i];
                    if (IsSkillDisabled(skill)) continue;
                    textSB.Append(GetStatPrint(player.Id, skill)).Append(Environment.NewLine);
                }
                textSB.Length -= 1;
                var xpMult = GetXPMultiplier(player.Id);
                var itemMult = GetItemMultiplier(player.Id);
                textSB.Append("Your XP rates are: ").Append(xpMult.ToString("N0")).Append("%").Append(Environment.NewLine);
                textSB.Append("Your Item rates are: ").Append(itemMult.ToString("N0")).Append("%").Append(Environment.NewLine);
                for (int i = 0; i < Skills.ALL.Length; i++) {
                    var skill = Skills.ALL[i];
                    if (IsSkillDisabled(skill)) continue;
                    textSB.Append("Your <color=").Append(colors[skill]).Append(">").Append(messages[skill + "Skill"]).Append("</color> XP catch-up multiplier is: ").Append(GetCatchupMultiplier(player.Id, skill).ToString("N0")).Append("%").Append(Environment.NewLine);
                }
                textSB.Append("NOTE: The average of the top 5 highest player levels in a skill must be at least 40 for any catch-up bonuses");
                SendReply(player, textSB.ToString());
            }
            finally {
                Pool.Free(ref textSB);
            }
        }
        private void SendReply(IPlayer player, string msg, string userId = "0", bool keepTagsConsole = false) {
            if (player == null) return;
            msg = !player.IsServer ? msg : keepTagsConsole ? msg : RemoveTags(msg);
            if (player.IsServer) ConsoleSystem.CurrentArgs.ReplyWith(msg);
            else {
#if RUST
                player.Command("chat.add", string.Empty, userId, msg);
#else
                player.Reply(msg);
#endif
            }
        }
        private string RemoveTags(string phrase) {
            if (string.IsNullOrEmpty(phrase)) return phrase;
            //	Replace Color Tags
            phrase = _colorRegex.Replace(phrase, string.Empty);
            //	Replace Size Tags
            phrase = _sizeRegex.Replace(phrase, string.Empty);
            var phraseSB = Pool.Get<StringBuilder>();
            try {
                phraseSB.Clear().Append(phrase);
                foreach (var tag in _forbiddenTags) phraseSB.Replace(tag, string.Empty);
                return phraseSB.ToString();
            }
            finally {
                Pool.Free(ref phraseSB);
            }
        }
        [ChatCommand("statinfo")]
        private void StatInfoCommand(BasePlayer player, string command, string[] args) {
            string messagesText;
            long xpMultiplier = 100;
            if (args.Length == 1) {
                string statname = args[0].ToLower();
                switch (statname) {
                    case "mining" : messagesText = "<color=" + colors[Skills.MINING] + ">Mining</color>" + (IsSkillDisabled(Skills.MINING) ? "(DISABLED)" : "") + "\n";
                    messagesText += "XP per hit: <color=" + colors[Skills.MINING] + ">" + ((int)pointsPerHitObj[Skills.MINING] * (xpMultiplier / 100f)) + "</color>\n";
                    messagesText += "Bonus materials per level: <color=" + colors[Skills.MINING] + ">" + ((GetGathMult(2, Skills.MINING) - 1) * 100).ToString("0.##") + "%</color>\n";
                    break;
                    case "woodcutting" : messagesText = "<color=" + colors[Skills.WOODCUTTING] + ">Woodcutting</color>" + (IsSkillDisabled(Skills.WOODCUTTING) ? "(DISABLED)" : "") + "\n";
                    messagesText += "XP per hit: <color=" + colors[Skills.WOODCUTTING] + ">" + ((int)pointsPerHitObj[Skills.WOODCUTTING] * (xpMultiplier / 100f)) + "</color>\n";
                    messagesText += "Bonus materials per level: <color=" + colors[Skills.WOODCUTTING] + ">" + ((GetGathMult(2, Skills.WOODCUTTING) - 1) * 100).ToString("0.##") + "%</color>\n";
                    break;
                    case "survival" : messagesText = "<color=" + colors[Skills.SURVIVAL] + '>' + "Survival" + "</color>" + (IsSkillDisabled(Skills.SURVIVAL) ? "(DISABLED)" : "") + "\n";
                    messagesText += "XP per hit: <color=" + colors[Skills.SURVIVAL] + ">" + ((int)pointsPerHitObj[Skills.SURVIVAL] * (xpMultiplier / 100f)) + "</color>\n";
                    messagesText += "Bonus materials per level: <color=" + colors[Skills.SURVIVAL] + ">" + ((GetGathMult(2, Skills.SURVIVAL) - 1) * 100).ToString("0.##") + "%</color>\n";
                    break;
                    default : messagesText = "No such stat: " + args[0];
                    messagesText += "\nYou must choose from these stats: <color=" + colors[Skills.MINING] + ">Mining</color>, <color=" + colors[Skills.SURVIVAL] + ">Survival</color>, <color=" + colors[Skills.WOODCUTTING] + ">Woodcutting</color>";
                    break;
                }
            }
            else {
                messagesText = "You must choose from these stats: <color=" + colors[Skills.MINING] + ">Mining</color>, <color=" + colors[Skills.SURVIVAL] + ">Survival</color>, <color=" + colors[Skills.WOODCUTTING] + ">Woodcutting</color>";
            }
            PrintToChat(player, messagesText);
        }
        [ChatCommand("xphit")]
        private void XPHitCommand(BasePlayer player, string command, string[] args) {
            if (!xpHitOff.Contains(player.UserIDString)) xpHitOff.Add(player.UserIDString);
            else xpHitOff.Remove(player.UserIDString);
            SendReply(player, (xpHitOff.Contains(player.UserIDString) ? "Diabled" : "Enabled") + " XP GUI notifications");
        }
        private void GUIUpdateSkill(BasePlayer player, string skill, int points = 0, bool ignoreCooldown = false) {
            if (player == null) throw new ArgumentNullException(nameof(player));
            if (string.IsNullOrEmpty(skill)) throw new ArgumentNullException(nameof(skill));
            if (LevelsGUI == null || !LevelsGUI.IsLoaded) {
                PrintWarning("GUIUpdateSkill called but LevelsGUI not found/loaded!!");
                return;
            }
            var now = Time.realtimeSinceStartup;
            if (!ignoreCooldown) {
                if (_lastGuiUpdate.TryGetValue(player.UserIDString, out var lastTime) && now - lastTime < 0.2) return;
            }
            var percent = (float)GetExperiencePerc(player.UserIDString, skill);
            var level = GetLevel(player.UserIDString, skill);
            if (level < 0) level = 1;
            var sb = Pool.Get<StringBuilder>();
            try {
                var skillMsg = messages[sb.Clear().Append(skill).Append("Skill").ToString()].ToString();
                if (!skillColors.TryGetValue(skill, out var skillColor)) PrintWarning("SKILL WITH NO COLOR!!: " + skill);
                _lastGuiUpdate[player.UserIDString] = now;
                LevelsGUI.Call("GUIUpdateSkill", player, skillMsg, level, percent, points, skillColor);
            }
            finally {
                Pool.Free(ref sb);
            }
        }
        private void CreateGUIAllSkills(BasePlayer player) {
            if (player == null || !player.IsConnected) return;
            for (int i = 0; i < Skills.ALL.Length; i++) {
                var skill = Skills.ALL[i];
                if (!IsSkillDisabled(skill)) GUIUpdateSkill(player, skill, ignoreCooldown : true);
            }
        }
        private void DestroyGUIAllSkills() {
            if (LevelsGUI == null || !LevelsGUI.IsLoaded) {
                if (!ServerMgr.Instance.Restarting) PrintWarning("LevelsGUI is null or unloaded on DestroyGUIAllSkills()!");
                return;
            }
            for (int i = 0; i < Skills.ALL.Length; i++) {
                var skill = Skills.ALL[i];
                if (IsSkillDisabled(skill)) continue;
                var skillName = skill;
                if (messages.TryGetValue(skill + "Skill", out var fullNameObj)) skillName = fullNameObj.ToString();
                LevelsGUI?.Call("RemoveSkill", skillName);
            }
            PrintWarning("Called RemoveSkill in LevelsGUI for all non-disabled skills");
        }
        private void OnLevelsGUICreated(BasePlayer player) {
            if (player == null) {
                PrintWarning("OnLevelsGUICreated called with null player!!");
                return;
            }
            CreateGUIAllSkills(player);
            //delay to fix getting level 0
        }
        private string GetStatPrint(string userID, string skill) {
            if (string.IsNullOrEmpty(userID) || string.IsNullOrEmpty(skill) || IsSkillDisabled(skill)) return string.Empty;
            var cap = GetLevelCap(skill, userID);
            var skillMaxed = cap != 0 && GetLevel(userID, skill) == cap;
            var bonusText = ((GetGathMult(GetLevel(userID, skill), skill) - 1) * 100).ToString("0.##");
            var nextXp = GetLevelPoints(GetLevel(userID, skill) + 1);
            PrintWarning("nextXp: " + nextXp + ", current: " + GetPoints(userID, skill) + ", getLevel: " + GetLev
// ... [Code preview truncated due to length. Full source in attached file] ...

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