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

FREE MjEntityLimiter : 1.1.2 1.1.2

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;


namespace Oxide.Plugins
{
    [Info("MjEntityLimter", "mjmfighter", "1.1.2")]
    [Description("Limits specified entities for players")]
    public class MjEntityLimiter : RustPlugin
    {
        #region Variables

        private LimitsConfig config = new LimitsConfig();
        private PlayerEntityLimits playerEntityLimitsCache = new PlayerEntityLimits();
        private ExpiringCache<string, LimitPermission> permissionCache;

        private Coroutine initialLookup = null;

        #endregion

        #region Hooks

        private void Init()
        {
            foreach (var value in config.limitPermissions)
            {
                if (!string.IsNullOrEmpty(value.permission) && !permission.PermissionExists(value.permission))
                {
                    permission.RegisterPermission(value.permission, this);
                }
            }
            this.permissionCache = new ExpiringCache<string, LimitPermission>(TimeSpan.FromMinutes(5));
            timer.Every(3f * 60, () => { permissionCache.CleanupExpiredItems(); });
        }

        private void OnServerInitialized()
        {
            timer.Once(3f, () =>
            {
                initialLookup = ServerMgr.Instance.StartCoroutine(InitialLookup());
            });
        }

        private object CanBuild(Planner planner, Construction prefab, Construction.Target target)
        {
            var player = planner.GetOwnerPlayer();
            if (player == null)
            {
                return null;
            }

            return CheckBuild(player, prefab.fullName);
        }

        private void OnEntitySpawned(BaseEntity entity)
        {
            UpdateEntity(entity, false);
        }

        private void OnEntityKill(BaseEntity entity)
        {
            UpdateEntity(entity, true);
        }

        #endregion

        #region Commands

        [Command("mjentitylimiter.clearcache"), Permission("mjentitylimiter.clearcache")]
        private void ClearCacheCommand(IPlayer player, string cmd, string[] args)
        {
            permissionCache.Clear();
            player.Message("Cache cleared");
        }

        [Command("mjentitylimiter.reload"), Permission("mjentitylimiter.reload")]
        private void ReloadCommand(IPlayer player, string cmd, string[] args)
        {
            LoadConfig();
            permissionCache.Clear();
            player.Message("Config reloaded");
        }

        #endregion

        #region Methods

        private IEnumerator InitialLookup()
        {
            yield return new WaitForEndOfFrame();
            Puts($"Processing entities.Server may lag while this is happening...");
            var entities = BaseNetworkable.serverEntities.OfType<BaseEntity>().ToArray();
            yield return new WaitForEndOfFrame();
            var total = entities.Length;
            var processed = 0;

            foreach (var entity in entities)
            {
                if (!entity.IsValid() || !entity.OwnerID.IsSteamId())
                {
                    continue;
                }

                // Fetch or create the playerData for the given OwnerID
                if (!playerEntityLimitsCache.TryGetValue(entity.OwnerID, out var playerData))
                {
                    playerData = new EntityDictionary();
                    playerEntityLimitsCache[entity.OwnerID] = playerData;
                }

                // Fetch or create the LimitEntityData for the given PrefabName
                if (!playerData.TryGetValue(entity.PrefabName, out var limitEntityData))
                {
                    limitEntityData = new LimitEntityData();
                    playerData[entity.PrefabName] = limitEntityData;
                }

                // Add the entity to the LimitEntityData
                limitEntityData.entities.Add(entity);

                if (config.Debug && processed > 0 && processed % 1000 == 0)
                {
                    Puts($"Entity processing: {processed}/{total}");
                    yield return new WaitForEndOfFrame();
                }

                processed++;
            }

            yield return new WaitForSecondsRealtime(1);
            Puts($"Finished processing {total} entities");
        }

        private object CheckBuild(BasePlayer player, string prefabFullName)
        {
            var perm = GetPlayerLimits(player.UserIDString);
            if (perm == null)
            {
                return null;
            }

            // Get the limit for the given prefab (for both long and short names), if it doesn't exist default to -1
            Debug($"Checking build for {player.displayName} - {GetShortname(prefabFullName)}");
            var limit = perm.GetLimit(prefabFullName);
            if (limit >= 0)
            {
                Debug($"Checking build for {player.displayName} - {prefabFullName} - {limit}");
                var playerData = playerEntityLimitsCache.GetByPlayer(player);
                var limitEntityData = playerData.Get(prefabFullName);
                var entityCount = limitEntityData.count;
                if (entityCount >= limit)
                {
                    SendMessage(player, MessageLimitType.Limit, entityCount);
                    return false;
                }

                // If the entity count is above the warning limit, send a warning message
                var warnLimit = limit * (100 - config.WarnPercentage) / 100;
                if (entityCount >= warnLimit)
                {
                    SendMessage(player, MessageLimitType.Warning, entityCount + 1, limit - entityCount - 1);
                }
                // Also send a warning message if periodic warnings are enabled and the entity count is 1 or a multiple of 10
                else if (config.PeriodicWarning && ((entityCount + 1) == 1 || (entityCount + 1) % 10 == 0))
                {
                    SendMessage(player, MessageLimitType.Warning, entityCount + 1, limit - entityCount - 1);
                }
            } else {
                Debug($"No limit for {prefabFullName}");
            }

            return null;
        }

        // Update the entity data for the given player
        private void UpdateEntity(BaseEntity entity, bool destroyed)
        {
            if (!entity.OwnerID.IsSteamId())
            {
                return;
            }

            Debug($"Updating entity {GetShortname(entity.PrefabName)} for {entity.OwnerID} - {destroyed}");

            var owner = entity.OwnerID;
            var prefabName = entity.PrefabName;

            NextTick(() =>
            {
                if (!destroyed && !entity.IsValid())
                {
                    return;
                }

                var playerData = playerEntityLimitsCache.Get(owner);
                var limitEntityData = playerData.Get(prefabName);

                if (destroyed)
                {
                    limitEntityData.entities.Remove(entity);
                }
                else
                {
                    limitEntityData.entities.Add(entity);
                }

            });
        }

        private static string GetShortname(string original)
        {
            var index = original.LastIndexOf("/", StringComparison.Ordinal) + 1;
            var name = original.Substring(index);
            return name.Replace(".prefab", string.Empty);
        }

        // Check to see if the original string is equal to either the short or long name
        private bool EqualShortLongName(string original, string prefabShortName, string prefabFullName)
        {
            return original.Equals(prefabShortName, StringComparison.OrdinalIgnoreCase) ||
                   original.Equals(prefabFullName, StringComparison.OrdinalIgnoreCase);
        }

        private void Debug(string message)
        {
            if (config.Debug)
            {
                Puts(message);
            }
        }

        private void Debug(string message, params object[] args)
        {
            if (config.Debug)
            {
                Puts(message, args);
            }
        }

        #endregion

        #region Configuration

        private class LimitPermission
        {
            [JsonProperty(PropertyName = "Permission")]
            public string permission;

            [JsonProperty(PropertyName = "Priority")]
            public int priority;

            [JsonProperty(PropertyName = "Entity Limits")]
            public Dictionary<string, int> limits = new Dictionary<string, int>();

            public int GetLimit(string prefabName)
            {
                if (limits.TryGetValue(prefabName, out var limit))
                {
                    return limit;
                }

                var shortName = GetShortname(prefabName);
                if (limits.TryGetValue(shortName, out limit))
                {
                    return limit;
                }

                return -1;
            }
        }

        private class LimitsConfig
        {
            [JsonProperty(PropertyName = "Enable more debugging messages")]
            public bool Debug = false;

            [JsonProperty(PropertyName = "Chat Prefix")]
            public string ChatPrefix = "<color=red>[MjEntityLimiter]</color> ";

            [JsonProperty(PropertyName = "Periodic Warn Players About Limits")]
            public bool PeriodicWarning = true;

            [JsonProperty(PropertyName = "Warn about limits below x percent")]
            public int WarnPercentage = 10;

            [JsonProperty(PropertyName = "Default Entity Limits")]
            public Dictionary<string, int> DefaultLimits = new Dictionary<string, int>
            {
                {"generator.wind.scrap", 1}
            };

            [JsonProperty(PropertyName = "Limit Permissions")]
            public LimitPermission[] limitPermissions = new LimitPermission[]
            {
                new LimitPermission
                {
                    permission = nameof(MjEntityLimiter) + ".vip",
                    priority = 0,
                    limits = new Dictionary<string, int>
                    {
                        {"generator.wind.scrap", 0}
                    }
                }
            };
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();

            try
            {
                config = Config.ReadObject<LimitsConfig>();
                if (config == null)
                {
                    LoadDefaultConfig();
                    SaveConfig();
                }
            }
            catch
            {
                PrintError("Configuration file is corrupt.Please check your config file's syntax!");

                LoadDefaultConfig();
                return;
            }
            LoadLimitPermissions();
        }

        protected override void LoadDefaultConfig()
        {
            config = new LimitsConfig();
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(config);
        }

        #endregion

        #region Messages

        private enum MessageLimitType
        {
            Warning,
            Limit,
        }

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
      {
        {MessageLimitType.Warning.ToString(), "You used {0} of that entity type; you have {1} remaining..." },
        {MessageLimitType.Limit.ToString(), "You have reached your limit of that entity type!  You have used: {0}" }
      }, this, "en");
        }

        private void SendMessage(object receiver, MessageLimitType type, params object[] args)
        {
            var message = String.Format(lang.GetMessage(type.ToString(), this, null), args);
            SendMessage(receiver, message);
        }

        private void SendMessage(object receiver, string message)
        {
            if (receiver == null)
            {
                Puts(message);
                return;
            }

            var console = receiver as ConsoleSystem.Arg;
            if (console != null)
            {
                SendReply(console, message);
                return;
            }

            var player = receiver as BasePlayer;
            if (player != null)
            {
                Player.Message(player, message, config.ChatPrefix);
                return;
            }
        }

        #endregion

        #region Plugin Data

        private class LimitEntityData
        {
            public int count => entities.Count;
            public HashSet<BaseEntity> entities = new HashSet<BaseEntity>();
        }

        private class EntityDictionary : Dictionary<string, LimitEntityData>
        {
            public LimitEntityData Get(string prefabName)
            {
                if (!ContainsKey(prefabName))
                {
                    this[prefabName] = new LimitEntityData();
                }
                return this[prefabName];
            }
        }

        private class PlayerEntityLimits : Dictionary<ulong, EntityDictionary>
        {
            public EntityDictionary GetByPlayer(BasePlayer player)
            {
                return Get(player.userID);
            }

            public EntityDictionary Get(ulong id)
            {
                if (!ContainsKey(id))
                {
                    this[id] = new EntityDictionary();
                }
                return this[id];
            }
        }

        #endregion

        #region Permissions

        private Dictionary<string, LimitPermission> permissionLimits = new Dictionary<string, LimitPermission>();

        private void LoadLimitPermissions()
        {
            permissionLimits["default"] = new LimitPermission
            {
                permission = null,
                priority = -1,
                limits = config.DefaultLimits
            };

            // Load all the permissions and save them in permissionLimits.Add the default permissions to the permission limits if they don't already exist
            foreach (var perm in config.limitPermissions)
            {
                if (!string.IsNullOrEmpty(perm.permission) && !permission.PermissionExists(perm.permission))
                {
                    permission.RegisterPermission(perm.permission, this);
                }

                if (!permissionLimits.ContainsKey(perm.permission))
                {
                    permissionLimits[perm.permission] = perm;
                }
                // Add all the default limits to the player's limits if they don't already exist
                foreach (var pair in config.DefaultLimits)
                {
                    if (!permissionLimits[perm.permission].limits.ContainsKey(pair.Key) || permissionLimits[perm.permission].limits[pair.Key] != pair.Value)
                    {
                        permissionLimits[perm.permission].limits[pair.Key] = pair.Value;
                    }
                }
            }
        }

        private LimitPermission GetPlayerLimits(string playerID)
        {
            if (permissionCache.TryGetValue(playerID, out var lastPermission))
            {
                return lastPermission;
            }

            var lastPriority = -1;
            foreach (var perm in permissionLimits.Values)
            {
                if (perm.permission == null)
                {
                    continue;
                }

                if (perm.priority > lastPriority && permission.UserHasPermission(playerID, perm.permission))
                {
                    lastPriority = perm.priority;
                    lastPermission = perm;
                }
            }

            if (lastPermission == null)
            {
                lastPermission = permissionLimits["default"];
            }
            permissionCache.Set(playerID, lastPermission);

            return lastPermission;
        }

        public class ExpiringCache<TKey, TValue>
        {
            private class CacheItem
            {
                public TValue Value { get; set; }
                public DateTime Expiry { get; set; }
            }

            private Dictionary<TKey, CacheItem> _cache = new Dictionary<TKey, CacheItem>();
            private TimeSpan _expiryDuration;

            public ExpiringCache(TimeSpan expiryDuration)
            {
                _expiryDuration = expiryDuration;
                //_cleanupTimer = new Timer(CleanupExpiredItems, null, cleanupInterval, cleanupInterval);
            }

            public void Set(TKey key, TValue value)
            {
                lock (_cache)
                {
                    _cache[key] = new CacheItem
                    {
                        Value = value,
                        Expiry = DateTime.UtcNow.Add(_expiryDuration)
                    };
                }
            }

            public bool TryGetValue(TKey key, out TValue value)
            {
                lock (_cache)
                {
                    if (_cache.TryGetValue(key, out CacheItem item) && item.Expiry > DateTime.UtcNow)
                    {
                        value = item.Value;
                        return true;
                    }
                }

                value = default;
                return false;
            }

            public void CleanupExpiredItems()
            {
                lock (_cache)
                {
                    var keysToRemove = new List<TKey>();
                    foreach (var pair in _cache)
                    {
                        if (pair.Value.Expiry <= DateTime.UtcNow)
                        {
                            keysToRemove.Add(pair.Key);
                        }
                    }

                    foreach (var key in keysToRemove)
                    {
                        _cache.Remove(key);
                    }
                }
            }

            public void Clear()
            {
                lock (_cache)
                {
                    _cache.Clear();
                }
            }
        }

        #endregion
    }
}

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