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

FREE MinigunReloadAnywhere : 1.4.1 1.4.1

Нет прав для скачивания
C#:
/*
 * Copyright (C) 2024 Game4Freak.io
 * This mod is provided under the Game4Freak EULA.* Full legal terms can be found at https://game4freak.io/eula/
 */

using Network;
using Newtonsoft.Json;
using Oxide.Game.Rust.Cui;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Minigun Reload Anywhere", "VisEntities", "1.4.1")]
    [Description("Allows reloading the minigun anywhere without needing a workbench.")]
    public class MinigunReloadAnywhere : RustPlugin
    {
        #region Fields

        private static MinigunReloadAnywhere _plugin;
        private static Configuration _config;

        private const string FX_RELOAD = "assets/prefabs/weapons/minigun/effects/minigun-reload.prefab";
        private Dictionary<BasePlayer, GunReloaderComponent> _gunReloaders = new Dictionary<BasePlayer, GunReloaderComponent>();

        #endregion Fields

        #region Configuration

        private class Configuration
        {
            [JsonProperty("Version")]
            public string Version { get; set; }

            [JsonProperty("Reload Duration Seconds")]
            public float ReloadDurationSeconds { get; set; }

            [JsonProperty("Reload Cooldown Seconds")]
            public float ReloadCooldownSeconds { get; set; }

            [JsonProperty("Enable Toast Notifications")]
            public bool EnableToastNotifications { get; set; }
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            _config = Config.ReadObject<Configuration>();

            if (string.Compare(_config.Version, Version.ToString()) < 0)
                UpdateConfig();

            SaveConfig();
        }

        protected override void LoadDefaultConfig()
        {
            _config = GetDefaultConfig();
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(_config, true);
        }

        private void UpdateConfig()
        {
            PrintWarning("Config changes detected! Updating...");

            Configuration defaultConfig = GetDefaultConfig();

            if (string.Compare(_config.Version, "1.0.0") < 0)
                _config = defaultConfig;

            if (string.Compare(_config.Version, "1.3.0") < 0)
            {
                _config.ReloadDurationSeconds = defaultConfig.ReloadDurationSeconds;
                _config.EnableToastNotifications = defaultConfig.EnableToastNotifications;
            }

            PrintWarning("Config update complete! Updated from version " + _config.Version + " to " + Version.ToString());
            _config.Version = Version.ToString();
        }

        private Configuration GetDefaultConfig()
        {
            return new Configuration
            {
                Version = Version.ToString(),
                ReloadCooldownSeconds = 10f,
                ReloadDurationSeconds = 5f,
                EnableToastNotifications = true
            };
        }

        #endregion Configuration

        #region Oxide Hooks

        private void Init()
        {
            _plugin = this;
            PermissionUtil.RegisterPermissions();
        }

        private void Unload()
        {
            UnloadAllGunReloaders();
            _config = null;
            _plugin = null;
        }

        private void OnActiveItemChanged(BasePlayer player, Item oldItem, Item newItem)
        {
            if (player == null)
                return;

            if (!PermissionUtil.HasPermission(player, PermissionUtil.USE))
                return;

            if (oldItem != null && oldItem.info.shortname.Contains("minigun"))
            {
                DestroyGunReloader(player);
            }

            if (newItem != null && newItem.info.shortname.Contains("minigun"))
            {
                GetOrAddGunReloader(player, newItem);
            }
        }

        #endregion Oxide Hooks

        #region Gun Reloader Management

        public GunReloaderComponent GetOrAddGunReloader(BasePlayer player, Item item)
        {
            if (_gunReloaders.TryGetValue(player, out GunReloaderComponent existingGunReloader))
                return existingGunReloader;

            GunReloaderComponent gunReloader = GunReloaderComponent.Install(player, item);
            _gunReloaders[player] = gunReloader;
            return gunReloader;
        }

        public void HandleGunReloaderDestroyed(BasePlayer player)
        {
            if (_gunReloaders.ContainsKey(player))
                _gunReloaders.Remove(player);
        }
        
        public void UnloadAllGunReloaders()
        {
            foreach (GunReloaderComponent gunReloader in _gunReloaders.Values.ToArray())
            {
                if (gunReloader != null)
                    gunReloader.DestroySelf();
            }

            _gunReloaders.Clear();
        }

        public void DestroyGunReloader(BasePlayer player)
        {
            if (_gunReloaders.TryGetValue(player, out GunReloaderComponent gunReloader) && gunReloader != null)
            {
                ReloadUi.Hide(player);
                gunReloader.DestroySelf();
                _gunReloaders.Remove(player);
            }
        }

        public GunReloaderComponent GetGunReloader(BasePlayer player)
        {
            if (_gunReloaders.TryGetValue(player, out GunReloaderComponent gunReloader))
                return gunReloader;

            return null;
        }

        public bool PlayerHasGunReloader(BasePlayer player)
        {
            return _gunReloaders.ContainsKey(player);
        }

        #endregion Gun Reloader Management

        #region Gun Reloader Component

        public class GunReloaderComponent : FacepunchBehaviour
        {
            private Item _item;
            private BasePlayer _player;
            private InputState _playerInput;

            private bool _buttonHeld;
            private float _heldTime;
            private float _nextReloadTime = float.NegativeInfinity;
            private bool _warnSent;
            private float _holdStart;

            public static GunReloaderComponent Install(BasePlayer player, Item item)
            {
                GunReloaderComponent component = player.gameObject.AddComponent<GunReloaderComponent>();
                component.Initialize(item);
                return component;
            }

            public GunReloaderComponent Initialize(Item item)
            {
                _player = GetComponent<BasePlayer>();
                _playerInput = _player.serverInput;
                _item = item;

                return this;
            }
            
            public static GunReloaderComponent Get(BasePlayer player)
            {
                return player.gameObject.GetComponent<GunReloaderComponent>();
            }

            public void DestroySelf()
            {
                DestroyImmediate(this);
            }

            private void Update()
            {
                Item active = _player.GetActiveItem();
                if (active == null || active.uid != _item.uid)
                {
                    DestroySelf();
                    return;
                }

                if (_playerInput.IsDown(BUTTON.RELOAD) && !_buttonHeld)
                {
                    if (Time.realtimeSinceStartup < _nextReloadTime)
                    {
                        if (!_warnSent)
                        {
                            float remaining = _nextReloadTime - Time.realtimeSinceStartup;
                            string txt = FormatTime(remaining, true);

                            MessagePlayer(_player, Lang.ReloadCooldown, txt);

                            if (_config.EnableToastNotifications)
                                ShowToast(_player, Lang.ReloadCooldown, GameTip.Styles.Blue_Normal, txt);

                            _warnSent = true;
                        }
                        return;
                    }

                    BaseProjectile weapon = _item.GetHeldEntity()?.GetComponent<BaseProjectile>();
                    if (weapon == null) return;

                    int need = weapon.primaryMagazine.capacity - weapon.primaryMagazine.contents;
                    if (need <= 0)
                    {
                        if (!_warnSent)
                        {
                            MessagePlayer(_player, Lang.MagazineFull);

                            if (_config.EnableToastNotifications)
                                ShowToast(_player, Lang.MagazineFull, GameTip.Styles.Blue_Normal);

                            _warnSent = true;
                        }
                        return;
                    }

                    ItemDefinition ammoDef = weapon.primaryMagazine.ammoType;
                    int ammoCount = _player.inventory.GetAmount(ammoDef.itemid);
                    if (ammoCount <= 0)
                    {
                        if (!_warnSent)
                        {
                            MessagePlayer(_player, Lang.NoAmmo);

                            if (_config.EnableToastNotifications)
                                ShowToast(_player, Lang.NoAmmo, GameTip.Styles.Blue_Normal);

                            _warnSent = true;
                        }
                        return;
                    }

                    if (_config.ReloadDurationSeconds <= 0f)
                    {
                        DoReload();
                        _nextReloadTime = Time.realtimeSinceStartup + _config.ReloadCooldownSeconds;
                        return;
                    }

                    _buttonHeld = true;
                    _holdStart = Time.realtimeSinceStartup;
                    ReloadUi.Show(_player, 0f);
                    return;
                }

                if (_buttonHeld && _playerInput.IsDown(BUTTON.RELOAD))
                {
                    float held = Time.realtimeSinceStartup - _holdStart;
                    float ratio = held / _config.ReloadDurationSeconds;
                    ReloadUi.Show(_player, ratio);

                    if (held >= _config.ReloadDurationSeconds)
                    {
                        DoReload();
                        ReloadUi.Hide(_player);
                        _buttonHeld = false;
                        _nextReloadTime = Time.realtimeSinceStartup + _config.ReloadCooldownSeconds;
                    }
                    return;
                }

                if (_buttonHeld && _playerInput.WasJustReleased(BUTTON.RELOAD))
                {
                    _buttonHeld = false;
                    _warnSent = false;
                    ReloadUi.Hide(_player);
                }
            }

            private void OnDestroy()
            {
                ReloadUi.Hide(_player);
                _plugin.HandleGunReloaderDestroyed(_player);
            }

            private void DoReload()
            {
                BaseEntity heldEntity = _item.GetHeldEntity();
                if (heldEntity == null) return;

                BaseProjectile weapon = heldEntity.GetComponent<BaseProjectile>();
                if (weapon == null) return;

                int need = weapon.primaryMagazine.capacity - weapon.primaryMagazine.contents;
                if (need == 0) return;

                if (weapon.TryReloadMagazine(_player.inventory, need))
                    RunEffectAttachedToEntity(FX_RELOAD, _player);
            }
        }

        #endregion Gun Reloader Component

        #region Helper Functions

        public static string FormatTime(float time, bool compactFormat = true)
        {
            int hours = Mathf.FloorToInt(time / 3600f);
            int minutes = Mathf.FloorToInt((time % 3600) / 60f);
            int seconds = Mathf.FloorToInt(time % 60);

            if (compactFormat)
            {
                if (hours > 0)
                {
                    return $"{hours}h {minutes}m";
                }
                else if (minutes > 0)
                {
                    return $"{minutes}m {seconds}s";
                }
                else
                {
                    return $"{seconds}s";
                }
            }
            else
            {
                if (hours > 0)
                {
                    return $"{hours:D2}:{minutes:D2}:{seconds:D2}";
                }
                else if (minutes > 0)
                {
                    return $"{minutes:D2}:{seconds:D2}";
                }
                else
                {
                    return $"{seconds:D2}";
                }
            }
        }

        public static void RunEffectAttachedToEntity(string effectName, BaseEntity attachedEntity, uint entityBoneID = 0u, Vector3 localPosition = default(Vector3),
                Vector3 localNormal = default(Vector3), Connection suppressFor = null, bool sendToAll = false, List<Connection> recipients = null)
        {
            Effect.server.Run(effectName, attachedEntity, entityBoneID, localPosition, localNormal, suppressFor, sendToAll, recipients);
        }

        #endregion Helper Functions

        #region Permissions

        private static class PermissionUtil
        {
            public const string USE = "minigunreloadanywhere.use";
            private static readonly List<string> _permissions = new List<string>
            {
                USE,
            };

            public static void RegisterPermissions()
            {
                foreach (var permission in _permissions)
                {
                    _plugin.permission.RegisterPermission(permission, _plugin);
                }
            }

            public static bool HasPermission(BasePlayer player, string permissionName)
            {
                return _plugin.permission.UserHasPermission(player.UserIDString, permissionName);
            }
        }

        #endregion Permissions

        #region Localization

        private class Lang
        {
            public const string ReloadCooldown = "ReloadCooldown";
            public const string MagazineFull = "MagazineFull";
            public const string NoAmmo = "NoAmmo";
        }

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                [Lang.ReloadCooldown] = "You can reload again in {0} seconds.",
                [Lang.MagazineFull] = "Your minigun is already fully loaded.",
                [Lang.NoAmmo] = "You have no ammo to reload your minigun.",

            }, this, "en");
        }

        private static string GetMessage(BasePlayer player, string messageKey, params object[] args)
        {
            string message = _plugin.lang.GetMessage(messageKey, _plugin, player.UserIDString);

            if (args.Length > 0)
                message = string.Format(message, args);

            return message;
        }

        public static void MessagePlayer(BasePlayer player, string messageKey, params object[] args)
        {
            string message = GetMessage(player, messageKey, args);

            if (!string.IsNullOrWhiteSpace(message))
                _plugin.SendReply(player, message);
        }

        public static void ShowToast(BasePlayer player, string messageKey, GameTip.Styles style = GameTip.Styles.Blue_Normal, params object[] args)
        {
            string message = GetMessage(player, messageKey, args);

            if (!string.IsNullOrWhiteSpace(message))
                player.SendConsoleCommand("gametip.showtoast", (int)style, message);
        }

        #endregion Localization

        #region UI

        public static class ReloadUi
        {
            private const string UI_ROOT = "mra-reload-root";
            private const string UI_BG = "mra-reload-bar-bg";
            private const string UI_FILL = "mra-reload-bar-fill";

            public static void Show(BasePlayer player, float ratio, string header = "Reloading…")
            {
                var ui = new CuiElementContainer();

                ui.Add(new CuiElement
                {
                    Name = UI_ROOT,
                    Parent = "Under",
                    DestroyUi = UI_ROOT,
                    Components =
                    {
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0.5 0.5",
                            AnchorMax = "0.5 0.5",
                            OffsetMin = "-266.6667 -93.3333",
                            OffsetMax = "266.6667 -66.6667"
                        },
                        new CuiTextComponent
                        {
                            Text     = header,
                            Font     = "robotocondensed-bold.ttf",
                            FontSize = 15,
                            Align    = TextAnchor.MiddleCenter,
                            Color    = HexToColor("D2F1FF")
                        },
                        new CuiOutlineComponent
                        {
                            Color    = HexToColor("020E19"),
                            Distance = "1.3 1.3"
                        }
                    }
                });

                ui.Add(new CuiElement
                {
                    Name = UI_BG,
                    Parent = UI_ROOT,
                    DestroyUi = UI_BG,
                    Components =
                    {
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0.5 0.5",
                            AnchorMax = "0.5 0.5",
                            OffsetMin = "-153.3333 -25.5",
                            OffsetMax = "153.3333 -13.5"
                        },
                        new CuiImageComponent { Color = HexToColor("03193A") },
                        new CuiOutlineComponent
                        {
                            Color    = HexToColor("020E19"),
                            Distance = "2.0 2.0"
                        }
                    }
                });

                const float left = -152f;
                const float right = 152f;
                float fillRight = Mathf.Lerp(left, right, Mathf.Clamp01(ratio));

                ui.Add(new CuiElement
                {
                    Name = UI_FILL,
                    Parent = UI_BG,
                    DestroyUi = UI_FILL,
                    Components =
                    {
                        new CuiRectTransformComponent
                        {
                            AnchorMin = "0.5 0.5",
                            AnchorMax = "0.5 0.5",
                            OffsetMin = $"{left} -4.333333",
                            OffsetMax = $"{fillRight} 4.833333"
                        },
                        new CuiImageComponent { Color = HexToColor("1192D2") }
                    }
                });

                CuiHelper.AddUi(player, ui);
            }

            public static void Hide(BasePlayer player)
            {
                CuiHelper.DestroyUi(player, UI_ROOT);
            }

            private static string HexToColor(string hex, float opacity = 100f)
            {
                if (string.IsNullOrEmpty(hex) || hex.Length < 6) hex = "FFFFFF";
                hex = hex.TrimStart('#');

                int r = int.Parse(hex.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
                int g = int.Parse(hex.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
                int b = int.Parse(hex.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);

                return $"{r / 255f:F3} {g / 255f:F3} {b / 255f:F3} {opacity / 100f:F3}";
            }
        }

        #endregion UI
    }
}

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