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

FREE TargetPractice : 0.1.55 0.1.55

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Collections.Generic;
using UnityEngine;
using Oxide.Core.Configuration;
using Oxide.Core;
using System.Linq;
using Oxide.Game.Rust.Cui;
using System.Reflection;
namespace Oxide.Plugins {
    [Info("TargetPractice", "k1lly0u", "0.1.55", ResourceId = 1731)]
    class TargetPractice : RustPlugin {
        TargetData shotData;
        private DynamicConfigFile ShotData;
        private static Vector2 position = new Vector2(0.75f, 0.2f);
        private static Vector2 dimension = new Vector2(0.25f, 0.07f);
        private Dictionary<ulong, PlayerMSG> currentHits = new Dictionary<ulong, PlayerMSG>();
        FieldInfo knockdownMaxValue = typeof(ReactiveTarget).GetField("knockdownHealth", (BindingFlags.Instance | BindingFlags.NonPublic));
#region oxide hooks
        void Loaded() {
            lang.RegisterMessages(messages, this);
            ShotData = Interface.Oxide.DataFileSystem.GetFile("targetpractice_scores");
        }
        void OnServerInitialized() {
            LoadVariables();
            LoadData();
            LoadTargets();
            timer.Once(saveTimer * 60, () => SaveLoop());
        }
        protected override void LoadDefaultConfig() {
            Puts("Creating a new config file");
            Config.Clear();
            LoadVariables();
        }
        void Unload() => SaveData();
        void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitinfo) {
            try {
                if (entity is ReactiveTarget && hitinfo.Initiator is BasePlayer) {
                    var target = (ReactiveTarget)entity;
                    var attacker = (BasePlayer)hitinfo.Initiator;
                    if (entity != null && attacker != null) {
                        float distance = GetPlayerDistance(entity.transform.position, attacker.transform.position);
                        string hit = lang.GetMessage("hit", this, attacker.UserIDString);
                        CheckPlayerData(attacker);
                        var data = shotData.longShot;
                        var time = data[attacker.userID].PopupTime;
                        string weapon = FormatWeapon(attacker.GetActiveItem());
                        if (weapon == "Flame Thrower" && disableFlamer) return;
                        if (hitinfo.HitBone == StringPool.Get("target_collider_bullseye")) {
                            hit = lang.GetMessage("bullseye", this, attacker.UserIDString);
                            if (data[attacker.userID].Bullseye < distance) {
                                data[attacker.userID].Bullseye = distance;
                                data[attacker.userID].Weapon = weapon;
                            }
                        }
                        else if (data[attacker.userID].Range < distance) {
                            data[attacker.userID].Range = distance;
                            data[attacker.userID].Weapon = weapon;
                        }
                        if (distance > shotData.bestHit.Range) {
                            shotData.bestHit.Name = attacker.displayName;
                            shotData.bestHit.Range = distance;
                            shotData.bestHit.Weapon = attacker.GetActiveItem().info.displayName.english;
                            if (broadcastNewScore) BroadcastToAll(attacker.displayName, distance.ToString(), weapon);
                        }
                        if (target.IsKnockedDown()) {
                            target.CancelInvoke("ResetTarget");
                            target.health = target.MaxHealth();
                            target.SendNetworkUpdate();
                            timer.Once(time, () => target.SetFlag(BaseEntity.Flags.On, true));
                        }
                        if (!currentHits.ContainsKey(attacker.userID)) currentHits.Add(attacker.userID, new PlayerMSG());
                        currentHits[attacker.userID].msg = hit;
                        currentHits[attacker.userID].distance = distance;
                        OverwriteDuplicate(attacker);
                    }
                }
            }
            catch (Exception ex) {
            }
        }
        private string FormatWeapon(Item weapon) {
            string weaponstring = weapon.info.displayName.english;
            string formattedWeapon = "";
            List<string> mods = new List<string>();
            if (weapon.contents != null) foreach (var mod in weapon.contents.itemList) mods.Add(mod.info.shortname);
            if (mods.Count > 0) {
                if (mods.Contains("weapon.mod.silencer")) formattedWeapon = "Silenced ";
                if (mods.Contains("weapon.mod.holosight")) formattedWeapon = formattedWeapon + "Sighted ";
                if (mods.Contains("weapon.mod.lasersight")) if (!formattedWeapon.Contains("Sighted")) formattedWeapon = formattedWeapon + "Laser Sighted ";
                if (mods.Contains("weapon.mod.small.scope")) formattedWeapon = formattedWeapon + "Scoped ";
            }
            formattedWeapon = formattedWeapon + weaponstring;
            return formattedWeapon;
        }
        void OnEntitySpawned(BaseNetworkable entity) {
            if (entity != null) if (entity.GetComponent<ReactiveTarget>()) ModifyTargetStats(entity);
        }
        private void ModifyTargetStats(BaseNetworkable entity) {
            if (entity != null) {
                knockdownMaxValue.SetValue((ReactiveTarget)entity, maxKnockdown);
                entity.SendNetworkUpdateImmediate(false);
            }
        }
        private void OverwriteDuplicate(BasePlayer player) {
            if (!currentHits[player.userID].time) {
                currentHits[player.userID].time = true;
                timer.Once(0.05f, () => GetMessage(player));
            }
        }
        private void GetMessage(BasePlayer player) {
            string hit = currentHits[player.userID].msg;
            float distance = currentHits[player.userID].distance;
            TPUI.GetPlayer(player).UseUI(fontColor2 + hit + "</color> " + fontColor1 + distance + "M</color>");
            currentHits[player.userID].time = false;
        }
        private void CheckPlayerData(BasePlayer player) {
            var data = shotData.longShot;
            if (!data.ContainsKey(player.userID)) data.Add(player.userID, new TargetInfo() {
                Name = player.displayName, Range = 0, Bullseye = 0
            }
            );
        }
#endregion
#region functions
        protected void LoadTargets() {
            ReactiveTarget[] targets = GameObject.FindObjectsOfType<ReactiveTarget>();
            if (targets.Length > 0) {
                foreach (ReactiveTarget target in targets.ToList()) ModifyTargetStats(target);
            }
        }
        private float GetPlayerDistance(Vector3 targetPos, Vector3 attackerPos) {
            var distance = Vector3.Distance(targetPos, attackerPos);
            var rounded = Mathf.Round(distance * 100f) / 100f;
            return rounded;
        }
        private void BroadcastToAll(string name, string range, string weapon) => PrintToChat(fontColor1 + "Target Practice: " + name + " </color>" + fontColor2 + "just set a new high score of " + "</color>" + fontColor1 + range + "M</color> " + fontColor2 + "using a</color> " + fontColor1 + weapon + "</color>");
        class TPUI : MonoBehaviour {
            public List<int> slots = new List<int>();
            int i;
            private BasePlayer player;
            void Awake() {
                player = GetComponent<BasePlayer>();
                i = 0;
            }
            public static TPUI GetPlayer(BasePlayer player) {
                TPUI p = player.GetComponent<TPUI>();
                if (p == null) p = player.gameObject.AddComponent<TPUI>();
                return p;
            }
            private int FindSlot() {
                for (int i = 0; i < maxUIMsg; i++) if (!slots.Contains(i)) return i;
                return -1;
            }
            public void UseUI(string msg) {
                i++;
                string uiNum = i.ToString();
                int slot = FindSlot();
                if (slot == -1) return;
                Vector2 offset = (new Vector2(0, dimension.y) + new Vector2(0, UIspacing)) * slot;
                Vector2 posMin = position + offset;
                Vector2 posMax = posMin + dimension;
                var elements = new CuiElementContainer();
                CuiElement textElement = new CuiElement {
                    Name = uiNum, Parent = "Overlay", FadeOut = 0.1f, Components = {
                        new CuiTextComponent {
                            Text = msg, FontSize = fontSize, Align = TextAnchor.MiddleCenter, FadeIn = 0.1f
                        }
                        , new CuiOutlineComponent {
                            Distance = "1.0 1.0", Color = "0.0 0.0 0.0 1.0"
                        }
                        , new CuiRectTransformComponent {
                            AnchorMin = posMin.x + " " + posMin.y, AnchorMax = posMax.x + " " + posMax.y
                        }
                    }
                }
                ;
                elements.Add(textElement);
                CuiHelper.AddUi(player, elements);
                slots.Add(slot);
                Interface.GetMod().CallHook("DestroyHitMsg", new object[] {
                    player, uiNum, slot, msgDuration
                }
                );
            }
        }
        private void DestroyNotification(BasePlayer player, string msgNum, int slot) {
            bool t = CuiHelper.DestroyUi(player, msgNum);
            if (!t) DestroyNotification(player, msgNum, slot);
            TPUI.GetPlayer(player).slots.Remove(slot);
        }
        private void DestroyHitMsg(BasePlayer player, string msgNum, int slot, float duration) {
            timer.Once(duration, () => DestroyNotification(player, msgNum, slot));
        }
#endregion
#region chat commands
        [ChatCommand("target")]
        void cmdTarget(BasePlayer player, string command, string[] args) {
            if (args == null || args.Length == 0) {
                SendReply(player, fontColor1 + lang.GetMessage("tp", this, player.UserIDString));
                SendReply(player, fontColor1 + lang.GetMessage("hit1", this, player.UserIDString) + fontColor2 + lang.GetMessage("hit2", this, player.UserIDString));
                SendReply(player, fontColor1 + lang.GetMessage("be1", this, player.UserIDString) + fontColor2 + lang.GetMessage("be2", this, player.UserIDString));
                SendReply(player, fontColor1 + lang.GetMessage("time1", this, player.UserIDString) + fontColor2 + lang.GetMessage("time2", this, player.UserIDString));
                SendReply(player, fontColor1 + lang.GetMessage("pb1", this, player.UserIDString) + fontColor2 + lang.GetMessage("pb2", this, player.UserIDString));
                if (isAuth(player)) SendReply(player, fontColor1 + lang.GetMessage("wipe1", this, player.UserIDString) + fontColor2 + lang.GetMessage("wipe2", this, player.UserIDString));
                return;
            }
            switch (args[0].ToLower()) {
                case "top" : if (args.Length >= 2) {
                    if (args[1].ToLower() == "hit") {
                        int amount = 5;
                        if (args.Length >= 3) int.TryParse(args[2], out amount);
                        Dictionary<ulong, TargetInfo> top5 = shotData.longShot.OrderByDescending(pair => pair.Value.Range).Take(amount).ToDictionary(pair => pair.Key, pair => pair.Value);
                        if (top5.Count > 0) {
                            SendReply(player, fontColor1 + lang.GetMessage("title", this, player.UserIDString) + "</color>" + fontColor2 + lang.GetMessage("bestHits", this, player.UserIDString) + "</color>");
                            foreach (var name in top5) SendReply(player, string.Format(fontColor2 + lang.GetMessage("topList1", this, player.UserIDString) + "</color>", name.Value.Name, name.Value.Range, name.Value.Weapon));
                        }
                        return;
                    }
                    else if (args[1].ToLower() == "bullseye") {
                        int amount = 5;
                        if (args.Length >= 4) int.TryParse(args[3], out amount);
                        Dictionary<ulong, TargetInfo> top5 = shotData.longShot.OrderByDescending(pair => pair.Value.Bullseye).Take(amount).ToDictionary(pair => pair.Key, pair => pair.Value);
                        if (top5.Count > 0) {
                            SendReply(player, fontColor1 + lang.GetMessage("title", this, player.UserIDString) + "</color>" + fontColor2 + lang.GetMessage("bestBullseye", this, player.UserIDString) + "</color>");
                            foreach (var name in top5) SendReply(player, string.Format(fontColor2 + lang.GetMessage("topList1", this, player.UserIDString) + "</color>", name.Value.Name, name.Value.Bullseye, name.Value.Weapon));
                        }
                        return;
                    }
                }
                return;
                case "wipe" : if (isAuth(player)) {
                    shotData.longShot.Clear();
                    SendReply(player, lang.GetMessage("wipe", this, player.UserIDString));
                }
                return;
                case "time" : if (args.Length >= 2) {
                    CheckPlayerData(player);
                    int time = popupTime;
                    int.TryParse(args[1], out time);
                    if (time != popupTime) shotData.longShot[player.userID].PopupTime = time;
                    SendReply(player, string.Format(fontColor1 + lang.GetMessage("title", this, player.UserIDString) + "</color>" + fontColor2 + lang.GetMessage("changeTime", this, player.UserIDString) + "</color>", time));
                }
                return;
                case "pb" : if (shotData.longShot.ContainsKey(player.userID)) {
                    SendReply(player, fontColor1 + lang.GetMessage("title", this, player.UserIDString) + "</color>" + fontColor2 + lang.GetMessage("pb3", this, player.UserIDString));
                    SendReply(player, fontColor2 + lang.GetMessage("hit", this, player.UserIDString) + "</color> " + fontColor1 + shotData.longShot[player.userID].Range + lang.GetMessage("m", this, player.UserIDString));
                    SendReply(player, fontColor2 + lang.GetMessage("bullseye", this, player.UserIDString) + "</color> " + fontColor1 + shotData.longShot[player.userID].Bullseye + lang.GetMessage("m", this, player.UserIDString));
                }
                return;
            }
        }
        bool isAuth(BasePlayer player) {
            if (player.net.connection != null) if (player.net.connection.authLevel < 1) return false;
            return true;
        }
#endregion
#region data
        class TargetData {
            public Dictionary<ulong, TargetInfo> longShot = new Dictionary<ulong, TargetInfo>();
            public BestHit bestHit = new BestHit();
            public TargetData() {
            }
        }
        class BestHit {
            public string Name = "";
            public float Range = 0;
            public string Weapon = "";
            public bool isBullseye = false;
        }
        class TargetInfo {
            public string Name;
            public float Range;
            public float Bullseye;
            public string Weapon;
            public bool UseUI = true;
            public int PopupTime = popupTime;
        }
        class PlayerMSG {
            public string msg;
            public float distance;
            public string weapon;
            public bool time = false;
        }
        void SaveLoop() {
            SaveData();
            timer.Once(saveTimer * 60, () => SaveLoop());
        }
        void SaveData() {
            ShotData.WriteObject(shotData);
        }
        void LoadData() {
            try {
                shotData = Interface.GetMod().DataFileSystem.ReadObject<TargetData>("targetpractice_scores");
            }
            catch {
                Puts("Couldn't load TargetPractice data, creating new datafile");
                shotData = new TargetData();
            }
        }
#endregion
#region config
        //////////////////////////////////////////////////////////////////////////////////////
        // Configuration /////////////////////////////////////////////////////////////////////
        //////////////////////////////////////////////////////////////////////////////////////
        private bool changed;
        private static int popupTime = 5;
        private static int msgDuration = 5;
        private static int fontSize = 20;
        private static int saveTimer = 10;
        private static int maxUIMsg = 11;
        private static bool broadcastNewScore = true;
        private static bool disableFlamer = true;
        private static string fontColor1 = "<color=orange>";
        private static string fontColor2 = "<color=#939393>";
        private static float maxKnockdown = 100f;
        private static float UIspacing = 0.01f;
        private void LoadVariables() {
            LoadConfigVariables();
            SaveConfig();
        }
        private void LoadConfigVariables() {
            CheckCfg("Target - Default time to reset target (seconds)", ref popupTime);
            CheckCfg("Disable Flamethrower", ref disableFlamer);
            CheckCfg("Messages - Duration (seconds)", ref popupTime);
            CheckCfg("Messages - Font size", ref fontSize);
            CheckCfg("Messages - Message color", ref fontColor2);
            CheckCfg("Messages - Main color", ref fontColor1);
            CheckCfg("Messages - Broadcast new high scores to all", ref broadcastNewScore);
            CheckCfg("Data - Save timer (minutes)", ref saveTimer);
            CheckCfgFloat("Target - Knockdown health", ref maxKnockdown);
        }
        private void CheckCfg<T>(string Key, ref T var) {
            if (Config[Key] is T) var = (T)Config[Key];
            else Config[Key] = var;
        }
        private void CheckCfgFloat(string Key, ref float var) {
            if (Config[Key] != null) var = Convert.ToSingle(Config[Key]);
            else Config[Key] = var;
        }
        object GetConfig(string menu, string datavalue, object defaultValue) {
            var data = Config[menu] as Dictionary<string, object>;
            if (data == null) {
                data = new Dictionary<string, object>();
                Config[menu] = data;
                changed = true;
            }
            object value;
            if (!data.TryGetValue(datavalue, out value)) {
                value = defaultValue;
                data[datavalue] = value;
                changed = true;
            }
            return value;
        }
#endregion
#region messages
        Dictionary<string, string> messages = new Dictionary<string, string>() {
            {
                "title", "TargetPractice: "
            }
            , {
                "hit", "Hit"
            }
            , {
                "bullseye", "Bullseye"
            }
            , {
                "wipe", "You have wiped all TargetPractice hit data!"
            }
            , {
                "bestBullseye", "--- Best Bullseye hits ---"
            }
            , {
                "bestHits", "--- Best Hits ---"
            }
            , {
                "topList1", "Name:</color><color=orange> {0}</color><color=#939393>, Distance:</color><color=orange> {1}</color><color=#939393>, Weapon:</color><color=orange> {2}"
            }
            , {
                "changeTime", "You have changed the reset time to {0}"
            }
            , {
                "tp", "Target Practice</color>"
            }
            , {
                "hit1", "/target top hit <opt:##></color>"
            }
            , {
                "hit2", " - Displays top 5 hit distances, optional number to change amount shown</color>"
            }
            , {
                "be2", " - Displays top 5 bullseye hit distances, optional number to change amount shown</color>"
            }
            , {
                "be1", "/target top bullseye <opt:##></color>"
            }
            , {
                "time1", "/target time <##></color>"
            }
            , {
                "time2", " - Change the target reset time</color>"
            }
            , {
                "wipe1", "/target wipe</color>"
            }
            , {
                "wipe2", " - Clear all hit data</color>"
            }
            , {
                "pb1", "/target pb</color>"
            }
            , {
                "pb2", " - Shows your best hits</color>"
            }
            , {
                "pb3", "--- Personal Best ---</color>"
            }
            , {
                "m", "M</color>"
            }
        }
        ;
#endregion
    }
}

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