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

FREE SkinBox : 2.1.19 2.1.19

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
namespace Oxide.Plugins {
    [Info("SkinBox", "k1lly0u", "2.1.19"), Description("Allows you to reskin item's by placing it in the SkinBox and selecting a new skin")]
    class SkinBox : RustPlugin {
#region Fields
        [PluginReference]
        private Plugin ServerRewards, Economics;
        private Hash<ulong, string> _skinPermissions = new Hash<ulong, string>();
        private readonly Hash<string, HashSet<ulong>> _skinList = new Hash<string, HashSet<ulong>>();
        private readonly Hash<ulong, LootHandler> _activeSkinBoxes = new Hash<ulong, LootHandler>();
        private readonly Hash<string, string> _shortnameToDisplayname = new Hash<string, string>();
        private readonly Hash<ulong, string> _skinSearchLookup = new Hash<ulong, string>();
        private readonly Hash<ulong, string> _skinNameLookup = new Hash<ulong, string>();
        private readonly Hash<ulong, double> _cooldownTimes = new Hash<ulong, double>();
        private bool _apiKeyMissing = false;
        private bool _skinsLoaded = false;
        private Timer _approvedTimeout;
        private CostType _costType;
        private SortBy _sorting;
        private static SkinBox Instance {
            get;
            set;
        }
        private static Func<string, ulong, string> GetMessage;
        private const string COFFIN_PREFAB = "assets/prefabs/misc/halloween/coffin/coffinstorage.prefab";
        private const string LOOT_PANEL = "generic_resizable";
        private const int SCRAP_ITEM_ID = -932201673;
        private enum CostType {
            Scrap, ServerRewards, Economics
        }
        public enum SortBy {
            Config = 0, ConfigReversed = 1, Alphabetical = 2
        }
#endregion
#region Oxide Hooks
        private void Loaded() {
            Instance = this;
            Configuration.Permission.RegisterPermissions(permission, this);
            Configuration.Permission.ReverseCustomSkinPermissions(ref _skinPermissions);
            Configuration.Command.RegisterCommands(cmd, this);
            _costType = ParseType<CostType>(Configuration.Cost.Currency);
            _sorting = ParseType<SortBy>(Configuration.Skins.Sorting);
            if (Configuration.Favourites.Enabled) StoredData.Load();
            GetMessage = (string key, ulong userId) => lang.GetMessage(key, this, userId.ToString());
        }
        protected override void LoadDefaultMessages() {
            lang.RegisterMessages(new Dictionary<string, string> {
                ["NoAPIKey"]
                = "The server owner has not entered a Steam API key in the config.Unable to continue!", ["SkinsLoading"] = "SkinBox is still gathering skins.Please try again soon", ["NoPermission"] = "You don't have permission to use the SkinBox", ["ToNearPlayer"] = "The SkinBox is currently not usable at this place", ["CooldownTime"] = "You need to wait {0} seconds to use the SkinBox again", ["NotEnoughBalanceOpen"] = "You need at least {0} {1} to open the SkinBox", ["NotEnoughBalanceUse"] = "You would need at least {0} {1} to skin {2}", ["NotEnoughBalanceTake"] = "{0} was not skinned.You do not have enough {1}", ["CostToUse"] = "Skinning a item is not free!\n{0} {3} to skin a deployable\n{1} {3} to skin a weapon\n{2} {3} to skin attire", ["TargetSkinNotInList"] = "That skin is not defined in the skin list for that item", ["TargetSkinIsCurrentSkin"] = "The target item is already skinned with that skin ID", ["ApplyingSkin"] = "Applying skin {0}", ["NoItemInHands"] = "You must have a item in your hands to use the quick skin method", ["NoSkinsForItem"] = "There are no skins setup for that item", ["BrokenItem"] = "You can not skin broken items", ["HasItem"] = "The skin box already contains an item", ["RedirectsDisabled"] = "Redirected skins are disabled on this server", ["InsufficientItemPermission"] = "You do not have permission to skin this type of item", ["Cost.Scrap"] = "Scrap", ["Cost.ServerRewards"] = "RP", ["Cost.Economics"] = "Eco", ["ReskinError.InvalidResourcePath"] = "Failed to find resource path for deployed item", ["ReskinError.TargetNull"] = "The target deployable has been destroyed", ["ReskinError.MountBlocked"] = "You can not skin this while a player is mounted", ["ReskinError.IOConnected"] = "You can not skin this while it is connected", ["ReskinError.NoAuth"] = "You need building auth to reskin deployed items", ["ReskinError.NoTarget"] = "Unable to find a valid deployed item", ["NoDefinitionForEntity"] = "Failed to find the definition for the target item", ["FavouritesEnabled"] = "Favourites system enabled\nYour most used skins will be displayed first", ["ClearFavourites"] = "Clear favourites for {0}"
            }
            , this);
        }
        private void OnServerInitialized() {
            UnsubscribeHooks();
            if (string.IsNullOrEmpty(Configuration.Skins.APIKey)) {
                _apiKeyMissing = true;
                SendAPIMissingWarning();
                return;
            }
            if ((Steamworks.SteamInventory.Definitions?.Length ?? 0) == 0 && Configuration.Skins.UseApproved) {
                PrintWarning("Waiting for Steamworks to update item definitions....");
                Steamworks.SteamInventory.OnDefinitionsUpdated += StartSkinRequest;
                if (Configuration.Skins.ApprovedTimeout > 0) _approvedTimeout = timer.Once(Configuration.Skins.ApprovedTimeout, AbortApprovedSkinRequest);
            }
            else StartSkinRequest();
        }
        private object CanAcceptItem(ItemContainer container, Item item) {
            if (container.entityOwner == null) return null;
            LootHandler lootHandler = container.entityOwner.GetComponent<LootHandler>();
            if (lootHandler == null) return null;
            if (item.isBroken) {
                lootHandler.PopupMessage(GetMessage("BrokenItem", lootHandler.Looter.userID));
                return ItemContainer.CanAcceptResult.CannotAccept;
            }
            if (lootHandler.HasItem) {
                lootHandler.PopupMessage(GetMessage("HasItem", lootHandler.Looter.userID));
                return ItemContainer.CanAcceptResult.CannotAccept;
            }
            if (!HasItemPermissions(lootHandler.Looter, item)) {
                lootHandler.PopupMessage(GetMessage("InsufficientItemPermission", lootHandler.Looter.userID));
                return ItemContainer.CanAcceptResult.CannotAccept;
            }
            string shortname = GetRedirectedShortname(item.info.shortname);
            if (!Configuration.Skins.UseRedirected && !shortname.Equals(item.info.shortname, StringComparison.OrdinalIgnoreCase)) {
                lootHandler.PopupMessage(GetMessage("RedirectsDisabled", lootHandler.Looter.userID));
                return ItemContainer.CanAcceptResult.CannotAccept;
            }
            HashSet<ulong> skins;
            if (!_skinList.TryGetValue(shortname, out skins) || skins.Count == 0) {
                lootHandler.PopupMessage(GetMessage("NoSkinsForItem", lootHandler.Looter.userID));
                return ItemContainer.CanAcceptResult.CannotAccept;
            }
            int reskinCost = GetReskinCost(item);
            if (reskinCost > 0 && !CanAffordToUse(lootHandler.Looter, reskinCost)) {
                lootHandler.PopupMessage(string.Format(GetMessage("NotEnoughBalanceUse", lootHandler.Looter.userID), reskinCost, GetCostType(lootHandler.Looter.userID), item.info.displayName.english));
                return ItemContainer.CanAcceptResult.CannotAccept;
            }
            string result = Interface.Call<string>("SB_CanAcceptItem", lootHandler.Looter, item);
            if (!string.IsNullOrEmpty(result)) {
                lootHandler.PopupMessage(result);
                return ItemContainer.CanAcceptResult.CannotAccept;
            }
            return null;
        }
        private void OnItemSplit(Item item, int amount) {
            LootHandler lootHandler = item.parent?.entityOwner?.GetComponent<LootHandler>();
            if (lootHandler != null) lootHandler.CheckItemHasSplit(item);
        }
        private object CanMoveItem(Item item, PlayerInventory inventory, uint targetContainerID, int targetSlot, int amount) {
            if (item.parent?.entityOwner != null) {
                LootHandler lootHandler = item.parent != null && item.parent.entityOwner != null ? item.parent.entityOwner.GetComponent<LootHandler>() : null;
                if (lootHandler != null && lootHandler.InputAmount > 1) {
                    if (targetContainerID == 0 || targetSlot == -1) return false;
                    ItemContainer targetContainer = inventory.FindContainer(targetContainerID);
                    if (targetContainer != null && targetContainer.GetSlot(targetSlot) != null) return false;
                }
            }
            return null;
        }
        private object OnItemAction(Item item, string action, BasePlayer player) {
            LootHandler lootHandler;
            if (!_activeSkinBoxes.TryGetValue(player.userID, out lootHandler)) return null;
            const string DROP_ACTION = "drop";
            if (!action.Equals(DROP_ACTION, StringComparison.OrdinalIgnoreCase)) return null;
            if (lootHandler.Entity.inventory?.itemList?.Contains(item) ?? false) return true;
            return null;
        }
        private void OnItemAddedToContainer(ItemContainer container, Item item) {
            if (container?.entityOwner == null || container.entityOwner.IsDestroyed) return;
            LootHandler lootHandler = container.entityOwner.GetComponent<LootHandler>();
            if (lootHandler != null) lootHandler.OnItemAdded(item);
        }
        private void OnItemRemovedFromContainer(ItemContainer container, Item item) {
            if (container?.entityOwner == null || container.entityOwner.IsDestroyed) return;
            LootHandler lootHandler = container.entityOwner.GetComponent<LootHandler>();
            if (lootHandler != null) lootHandler.OnItemRemoved(item);
        }
        private void OnLootEntityEnd(BasePlayer player, StorageContainer storageContainer) {
            LootHandler lootHandler;
            if (_activeSkinBoxes.TryGetValue(player.userID, out lootHandler)) UnityEngine.Object.DestroyImmediate(lootHandler);
        }
        private void OnPlayerDeath(BasePlayer player, HitInfo hitInfo) {
            LootHandler lootHandler;
            if (!_activeSkinBoxes.TryGetValue(player.userID, out lootHandler)) return;
            lootHandler.ReturnItemInstantly();
            player.EndLooting();
            UnityEngine.Object.DestroyImmediate(lootHandler);
        }
        private void OnServerSave() {
            if (Configuration.Favourites.Enabled) StoredData.Save();
        }
        private void Unload() {
            LootHandler[] lootHandlers = UnityEngine.Object.FindObjectsOfType<LootHandler>();
            for (int i = 0; i < lootHandlers.Length; i++) {
                LootHandler lootHandler = lootHandlers[i];
                if (lootHandler.Looter != null) lootHandler.Looter.EndLooting();
                UnityEngine.Object.Destroy(lootHandler);
            }
            Configuration = null;
            Instance = null;
        }
#endregion
#region Functions
        private void SendAPIMissingWarning() {
            Debug.LogWarning("You must enter a Steam API key in the config!\nYou can get a API key here -> https://steamcommunity.com/dev/apikey \nOnce you have your API key copy it to the 'Skin Options/Steam API Key' field in your SkinBox.json config file");
        }
        private void ChatMessage(BasePlayer player, string key, params object[] args) {
            if (args == null) player.ChatMessage(lang.GetMessage(key, this, player.UserIDString));
            else player.ChatMessage(string.Format(lang.GetMessage(key, this, player.UserIDString), args));
        }
        private void CreateSkinBox(BasePlayer player, DeployableHandler.ReskinTarget reskinTarget) {
            StorageContainer container = GameManager.server.CreateEntity(COFFIN_PREFAB, player.transform.position + (Vector3.down * 250f)) as StorageContainer;
            container.limitNetworking = true;
            container.enableSaving = false;
            UnityEngine.Object.Destroy(container.GetComponent<DestroyOnGroundMissing>());
            UnityEngine.Object.Destroy(container.GetComponent<GroundWatch>());
            container.Spawn();
            LootHandler lootHandler;
            if (_activeSkinBoxes.TryGetValue(player.userID, out lootHandler)) {
                player.EndLooting();
                UnityEngine.Object.Destroy(lootHandler);
            }
            if (reskinTarget != null) {
                lootHandler = container.gameObject.AddComponent<DeployableHandler>();
                lootHandler.Looter = player;
                (lootHandler as DeployableHandler).Target = reskinTarget;
            }
            else {
                lootHandler = container.gameObject.AddComponent<LootHandler>();
                lootHandler.Looter = player;
            }
            player.inventory.loot.Clear();
            player.inventory.loot.PositionChecks = false;
            player.inventory.loot.entitySource = container;
            player.inventory.loot.itemSource = null;
            player.inventory.loot.MarkDirty();
            player.inventory.loot.AddContainer(container.inventory);
            player.inventory.loot.SendImmediate();
            player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", LOOT_PANEL);
            container.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
            if (Configuration.Cost.Enabled && !permission.UserHasPermission(player.UserIDString, Configuration.Permission.NoCost)) {
                lootHandler.PopupMessage(string.Format(GetMessage("CostToUse", lootHandler.Looter.userID), Configuration.Cost.Deployable, Configuration.Cost.Weapon, Configuration.Cost.Attire, GetCostType(player.userID)));
            }
            _activeSkinBoxes[player.userID] = lootHandler;
            ToggleHooks();
        }
#endregion
#region Hook Subscriptions
        private void ToggleHooks() {
            if (_activeSkinBoxes.Count > 0) SubscribeHooks();
            else UnsubscribeHooks();
        }
        private void SubscribeHooks() {
            Subscribe(nameof(OnLootEntityEnd));
            Subscribe(nameof(OnItemRemovedFromContainer));
            Subscribe(nameof(OnItemAddedToContainer));
            Subscribe(nameof(CanMoveItem));
            Subscribe(nameof(OnItemSplit));
            Subscribe(nameof(CanAcceptItem));
        }
        private void UnsubscribeHooks() {
            Unsubscribe(nameof(OnLootEntityEnd));
            Unsubscribe(nameof(OnItemRemovedFromContainer));
            Unsubscribe(nameof(OnItemAddedToContainer));
            Unsubscribe(nameof(CanMoveItem));
            Unsubscribe(nameof(OnItemSplit));
            Unsubscribe(nameof(CanAcceptItem));
        }
#endregion
#region Helpers
        private void GetSkinsFor(BasePlayer player, string shortname, ref List<ulong> list) {
            list.Clear();
            List<ulong> skinOverrides = Interface.Call<List<ulong>>("SB_GetSkinOverrides", player, shortname);
            if (skinOverrides != null && skinOverrides.Count > 0) {
                list.AddRange(skinOverrides);
                goto SORT_FAVOURITES;
            }
            HashSet<ulong> skins;
            if (_skinList.TryGetValue(shortname, out skins)) {
                foreach(ulong skinId in skins) {
                    string perm;
                    if (_skinPermissions.TryGetValue(skinId, out perm) && !permission.UserHasPermission(player.UserIDString, perm)) continue;
                    if (Configuration.Blacklist.Contains(skinId) && player.net.connection.authLevel < Configuration.Other.BlacklistAuth) continue;
                    list.Add(skinId);
                }
            }
            SORT_FAVOURITES : if (Configuration.Favourites.Enabled) Favourites.SortForPlayer(player, shortname, ref list);
        }
        private bool HasItemPermissions(BasePlayer player, Item item) {
            switch (item.info.category) {
                case ItemCategory.Weapon : case ItemCategory.Tool : return permission.UserHasPermission(player.UserIDString, Configuration.Permission.Weapon);
                case ItemCategory.Construction : case ItemCategory.Items : return permission.UserHasPermission(player.UserIDString, Configuration.Permission.Deployable);
                case ItemCategory.Attire : return permission.UserHasPermission(player.UserIDString, Configuration.Permission.Attire);
                default : return true;
            }
        }
        private T ParseType<T>(string type) {
            try {
                return (T)Enum.Parse(typeof(T), type, true);
            }
            catch {
                return default(T);
            }
        }
        private double CurrentTime => DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
#endregion
#region Usage Costs
        private string GetCostType(ulong playerId) => GetMessage($"Cost.{_costType}", playerId);
        private int GetReskinCost(Item item) {
            if (!Configuration.Cost.Enabled) return 0;
            switch (item.info.category) {
                case ItemCategory.Weapon : case ItemCategory.Tool : return Configuration.Cost.Weapon;
                case ItemCategory.Construction : case ItemCategory.Items : return Configuration.Cost.Deployable;
                case ItemCategory.Attire : return Configuration.Cost.Attire;
                default : return 0;
            }
        }
        private bool CanAffordToUse(BasePlayer player, int amount) {
            if (!Configuration.Cost.Enabled || amount == 0 || permission.UserHasPermission(player.UserIDString, Configuration.Permission.NoCost)) return true;
            switch (_costType) {
                case CostType.Scrap : return player.inventory.GetAmount(SCRAP_ITEM_ID) >= amount;
                case CostType.ServerRewards : return (int)ServerRewards?.Call("CheckPoints", player.userID) >= amount;
                case CostType.Economics : return (double)Economics?.Call("Balance", player.UserIDString) >= amount;
            }
            return false;
        }
        private bool ChargePlayer(BasePlayer player, ItemCategory itemCategory) {
            if (!Configuration.Cost.Enabled || permission.UserHasPermission(player.UserIDString, Configuration.Permission.NoCost)) return true;
            int amount = itemCategory == ItemCategory.Weapon || itemCategory == ItemCategory.Tool ? Configuration.Cost.Weapon : itemCategory == ItemCategory.Items || itemCategory == ItemCategory.Construction ? Configuration.Cost.Deployable : itemCategory == ItemCategory.Attire ? Configuration.Cost.Attire : 0;
            return ChargePlayer(player, amount);
        }
        private bool ChargePlayer(BasePlayer player, int amount) {
            if (amount == 0 || !Configuration.Cost.Enabled || permission.UserHasPermission(player.UserIDString, Configuration.Permission.NoCost)) return true;
            switch (_costType) {
                case CostType.Scrap : if (amount <= player.inventory.GetAmount(SCRAP_ITEM_ID)) {
                    player.inventory.Take(null, SCRAP_ITEM_ID, amount);
                    return true;
                }
                return false;
                case CostType.ServerRewards : return (bool)ServerRewards?.Call("TakePoints", player.userID, amount);
                case CostType.Economics : return (bool)Economics?.Call("Withdraw", player.UserIDString, (double)amount);
            }
            return false;
        }
#endregion
#region Cooldown
        private void ApplyCooldown(BasePlayer player) {
            if (!Configuration.Cooldown.Enabled || permission.UserHasPermission(player.UserIDString, Configuration.Permission.NoCooldown)) return;
            _cooldownTimes[player.userID] = CurrentTime + Configuration.Cooldown.Time;
        }
        private bool IsOnCooldown(BasePlayer player) {
            if (!Configuration.Cooldown.Enabled || permission.UserHasPermission(player.UserIDString, Configuration.Permission.NoCooldown)) return false;
            double time;
            if (_cooldownTimes.TryGetValue(player.userID, out time) && time > CurrentTime) return true;
            return false;
        }
        private bool IsOnCooldown(BasePlayer player, out double remaining) {
            remaining = 0;
            if (!Configuration.Cooldown.Enabled || permission.UserHasPermission(player.UserIDString, Configuration.Permission.NoCooldown)) return false;
            double time;
            if (_cooldownTimes.TryGetValue(player.userID, out time) && time > CurrentTime) {
                remaining = time - CurrentTime;
                return true;
            }
            return false;
        }
#endregion
#region Approved Skins
        private void AbortApprovedSkinRequest() {
            Debug.LogWarning("[SkinBox] - Aborting approved skin processing.Server has not yet downloaded approved manifest.Only workshop skins will be available");
            Steamworks.SteamInventory.OnDefinitionsUpdated -= StartSkinRequest;
            if (!Configuration.Skins.UseWorkshop) {
                PrintError("You have workshop skins disabled.This leaves no skins available to use in SkinBox!");
                return;
            }
            VerifyWorkshopSkins();
        }
        private void StartSkinRequest() {
            _approvedTimeout?.Destroy();
            Steamworks.SteamInventory.OnDefinitionsUpdated -= StartSkinRequest;
            UpdateWorkshopNameConversionList();
            FindItemRedirects();
            FixLR300InvalidShortname();
            if (!Configuration.Skins.UseApproved && !Configuration.Skins.UseWorkshop) {
                PrintError("You have approved skins and workshop skins disabled.This leaves no skins available to use in SkinBox!");
                return;
            }
            if (!Configuration.Skins.UseApproved && Configuration.Skins.UseWorkshop) {
                VerifyWorkshopSkins();
                return;
            }
            PrintWarning("Retrieving approved skin lists...");
            CollectApprovedSkins();
        }
        private void CollectApprovedSkins() {
            int count = 0;
            bool addApprovedPermission = Configuration.Permission.Approved != Configuration.Permission.Use;
            bool updateConfig = false;
            List<ulong> list = Facepunch.Pool.GetList<ulong>();
            List<int> itemSkinDirectory = Facepunch.Pool.GetList<int>();
            itemSkinDirectory.AddRange(ItemSkinDirectory.Instance.skins.Select(x => x.id));
            foreach (ItemDefinition itemDefinition in ItemManager.itemList) {
                list.Clear();
                foreach (Steamworks.InventoryDef item in Steamworks.SteamInventory.Definitions) {
                    string shortname = item.GetProperty("itemshortname");
                    if (string.IsNullOrEmpty(shortname) || item.Id < 100) continue;
                    if (_workshopNameToShortname.ContainsKey(shortname)) shortname = _workshopNameToShortname[shortname];
                    if (!shortname.Equals(itemDefinition.shortname, StringComparison.OrdinalIgnoreCase)) continue;
                    ulong skinId;
                    if (itemSkinDirectory.Contains(item.Id)) skinId = (ulong)item.Id;
                    else if (!ulong.TryParse(item.GetProperty("workshopid"), out skinId)) continue;
                    if (list.Contains(skinId) || Configuration.Skins.ApprovedLimit > 0 && list.Count >= Configuration.Skins.ApprovedLimit) continue;
                    list.Add(skinId);
                    _skinNameLookup[skinId] = item.Name;
                    _skinSearchLookup[skinId] = $"{skinId} {item.Name}";
                }
                if (list.Count > 1) {
                    count += list.Count;
                    HashSet<ulong> skins;
                    if (!_skinList.TryGetValue(itemDefinition.shortname, out skins)) skins = _skinList[itemDefinition.shortname] = new HashSet<ulong>();
                    int removeCount = 0;
                    list.ForEach((ulong skin) => {
                        if (Configuration.Skins.RemoveApproved && Configuration.SkinList.ContainsKey(itemDefinition.shortname) && Configuration.SkinList[itemDefinition.shortname].Contains(skin)) {
                            Configuration.SkinList[itemDefinition.shortname].Remove(skin);
                            removeCount++;
                            updateConfig = true;
                        }
                        skins.Add(skin);
                        if (addApprovedPermission) _skinPermissions[skin] = Configuration.Permission.Approved;
                    }
                    );
                    if (removeCount > 0) Debug.Log($"[SkinBox] Removed {removeCount} approved skin ID's for {itemDefinition.shortname} from the config skin list");
                }
            }
            if (updateConfig) SaveConfig();
            Facepunch.Pool.FreeList(ref list);
            Facepunch.Pool.FreeList(ref itemSkinDirectory);
            Debug.Log($"[SkinBox] - Loaded {count} approved skins");
            if (Configuration.Skins.UseWorkshop && Configuration.SkinList.Sum(x => x.Value.Count) > 0) VerifyWorkshopSkins();
            else {
                SortSkinLists();
                _skinsLoaded = true;
                Interface.Oxide.CallHook("OnSkinBoxSkinsLoaded", _skinList);
                Debug.Log($"[SkinBox] - SkinBox has loaded all required skins and is ready to use! ({_skinList.Values.Sum(x => x.Count)} skins acrosss {_skinList.Count} items)");
            }
        }
        private void SortSkinLists() {
            List<ulong> list = Facepunch.Pool.GetList<ulong>();
            foreach (KeyValuePair<string, HashSet<ulong>> kvp in _skinList) {
                list.AddRange(kvp.Value);
                SortSkinList(kvp.Key, ref list);
                kvp.Value.Clear();
                list.ForEach((ulong skinId) => kvp.Value.Add(skinId));
                list.Clear();
            }
            Facepunch.Pool.FreeList(ref list);
        }
        private void SortSkinList(string shortname, ref List<ulong> list) {
            if (_sorting == SortBy.Alphabetical) {
                list.Sort((ulong a, ulong b) => {
                    string nameA = string.Empty;
                    string nameB = string.Empty;
                    _skinNameLookup.TryGetValue(a, out nameA);
                    _skinNameLookup.TryGetValue(b, out nameB);
                    return nameA.CompareTo(nameB);
                }
                );
                return;
            }
            else {
                HashSet<ulong> configList;
                Configuration.SkinList.TryGetValue(shortname, out configList);
                if (configList != null) {
                    List<ulong> l = configList.ToList();
                    list.Sort((ulong a, ulong b) => {
                        int indexA = l.IndexOf(a);
                        int indexB = l.IndexOf(b);
                        return _sorting == SortBy.Config ? indexA.CompareTo(indexB) : indexA.CompareTo(indexB) * -1;
                    }
                    );
                }
            }
        }
#endregion
#region Workshop Skins
        private List<ulong> _skinsToVerify = new List<ulong>();
        private Queue<ulong> _collectionsToVerify = new Queue<ulong>();
        private const string PUBLISHED_FILE_DETAILS = "https://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1/";
        private const string COLLECTION_DETAILS = "https://api.steampowered.com/ISteamRemoteStorage/GetCollectionDetails/v1/";
        private const string ITEMS_BODY = "?key={0}&itemcount={1}";
        private const string ITEM_ENTRY = "&publishedfileids[{0}]={1}";
        private const string COLLECTION_BODY = "?key={0}&collectioncount=1&publishedfileids[0]={1}";
        private void VerifyWorkshopSkins() {
            foreach (HashSet<ulong> list in Configuration.SkinList.Values) _skinsToVerify.AddRange(list);
            SendWorkshopQuery();
        }
        private void SendWorkshopQuery(int page = 0, int success = 0, ConsoleSystem.Arg arg = null, string perm = null) {
            int totalPages = Mathf.CeilToInt((float)_skinsToVerify.Count / 100f);
            int index = page * 100;
            int limit = Mathf.Min((page + 1) * 100, _skinsToVerify.Count);
            string details = string.Format(ITEMS_BODY, Configuration.Skins.APIKey, (limit - index));
            for (int i = index; i < limit; i++) {
                details += string.Format(ITEM_ENTRY, i - index, _skinsToVerify[i]);
            }
            try {
                webrequest.Enqueue(PUBLISHED_FILE_DETAILS, details, (code, response) => ServerMgr.Instance.StartCoroutine(ValidateRequiredSkins(code, response, page + 1, totalPages, success, arg, perm)), this, RequestMethod.POST);
            }
            catch {
            }
        }
        public enum CollectionAction {
            AddSkin, RemoveSkin, ExcludeSkin, RemoveExludeSkin
        }
        private void SendWorkshopCollectionQuery(ulong collectionId, CollectionAction action, int success, ConsoleSystem.Arg arg = null, string perm = null) {
            string details = string.Format(COLLECTION_BODY, Configuration.Skins.APIKey, collectionId);
            try {
                webrequest.Enqueue(COLLECTION_DETAILS, details, (code, response) => ServerMgr.Instance.StartCoroutine(ProcessCollectionRequest(collectionId, code, response, action, success, arg, perm)), this, RequestMethod.POST);
            }
            catch {
            }
        }
        private IEnumerator ValidateRequiredSkins(int code, string response, int page, int totalPages, int success, ConsoleSystem.Arg arg, string perm) {
            bool hasChanged = false;
            int newSkins = 0;
            if (response != null && code == 200) {
                QueryResponse queryRespone = JsonConvert.DeserializeObject<QueryResponse>(response);
                if (queryRespone != null && queryRespone.response != null && queryRespone.response.publishedfiledetails?.Length > 0) {
                    SendResponse($"Processing workshop response.Page: {page} / {totalPages}", arg);
                    foreach (PublishedFileDetails publishedFileDetails in queryRespone.response.publishedfiledetails) {
                        if (publishedFileDetails.tags != null) {
                            foreach (PublishedFileDetails.Tag tag in publishedFileDetails.tags) {
                                if (string.IsNullOrEmpty(tag.tag)) continue;
                                ulong workshopid = Convert.ToUInt64(publishedFileDetails.publishedfileid);
                                string adjTag = tag.tag.ToLower().Replace("skin", "").Replace(" ", "").Replace("-", "").Replace(".item", "");
                                if (_workshopNameToShortname.ContainsKey(adjTag)) {
                                    string shortname = _workshopNameToShortname[adjTag];
                                    if (shortname == "ammo.snowballgun") continue;
                                    HashSet<ulong> skins;
                                    if (!_skinList.TryGetValue(shortname, out skins)) skins = _skinList[shortname] = new HashSet<ulong>();
                                    if (!skins.Contains(workshopid)) {
                                        skins.Add(workshopid);
                                        _skinNameLookup[workshopid] = publishedFileDetails.title;
                                        _skinSearchLookup[workshopid] = $"{workshopid} {publishedFileDetails.title}";
                                    }
                                    HashSet<ulong> configSkins;
                                    if (!Configuration.SkinList.TryGetValue(shortname, out configSkins)) configSkins = Configuration.SkinList[shortname] = new HashSet<ulong>();
                                    if (!configSkins.Contains(workshopid)) {
                                        hasChanged = true;
                                        configSkins.Add(workshopid);
                                        newSkins += 1;
                                    }
                                    if (!string.IsNullOrEmpty(perm) && !Configuration.Permission.Custom[perm].Contains(workshopid)) {
                                        hasChanged = true;
                                        Configuration.Permission.Custom[perm].Add(workshopid);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            yield return CoroutineEx.waitForEndOfFrame;
            yield return CoroutineEx.waitForEndOfFrame;
            if (hasChanged) SaveConfig();
            if (page < totalPages) SendWorkshopQuery(page, success + newSkins);
            else {
                if (_collectionsToVerify.Count != 0) {
                    SendWorkshopCollectionQuery(_collectionsToVerify.Dequeue(), CollectionAction.AddSkin, success + newSkins, arg, perm);
                    yield break;
                }
                if (!_skinsLoaded) {
                    SortSkinLists();
                    _skinsLoaded = true;
                    Interface.Oxide.CallHook("OnSkinBoxSkinsLoaded", _skinList);
                    Debug.Log($"[SkinBox] - SkinBox has loaded all required skins and is ready to use! ({_skinList.Values.Sum(x => x.Count)} skins acrosss {_skinList.Count} items)");
                }
                else SendResponse($"{success + newSkins} new skins have been added!", arg);
            }
        }
        private IEnumerator ProcessCollectionRequest(ulong collectionId, int code, string response, CollectionAction action, int success, ConsoleSystem.Arg arg, string perm) {
            if (response != null && code == 200) {
                SendResponse($"Processing response for collection {collectionId}", arg);
                CollectionQueryResponse collectionQuery = JsonConvert.DeserializeObject<CollectionQueryResponse>(response);
                if (collectionQuery == null || !(collectionQuery is CollectionQueryResponse)) {
                    SendResponse("Failed to receive a valid workshop collection response", arg);
                    yield break;
                }
                if (collectionQuery.response.resultcount == 0 || collectionQuery.response.collectiondetails == null || collectionQuery.response.collectiondetails.Length == 0 || collectionQuery.response.collectiondetails[0].result != 1) {
                    SendResponse("Failed to receive a valid workshop collection response", arg);
                    yield break;
                }
                _skinsToVerify.Clear();
                foreach (CollectionChild child in collectionQuery.response.collectiondetails[0].children) {
                    try {
                        switch (child.filetype) {
                            case 1 : _skinsToVerify.Add(Convert.ToUInt64(child.publishedfileid));
                            break;
                            case 2 : _collectionsToVerify.Enqueue(Convert.ToUInt64(child.publishedfileid));
                            SendResponse($"Collection {collectionId} contains linked collection {child.publishedfileid}", arg);
                            break;
                            default : break;
                        }
                    }
                    catch {
                    }
                }
                if (_skinsToVerify.Count == 0) {
                    if (_collectionsToVerify.Count != 0) {
                        SendWorkshopCollectionQuery(_collectionsToVerify.Dequeue(), action, success, arg, perm);
                        yield break;
                    }
                    SendResponse("No valid skin ID's in the specified collection", arg);
                    yield break;
                }
                switch (action) {
                    case CollectionAction.AddSkin : SendWorkshopQuery(0, success, arg, perm);
                    break;
                    case CollectionAction.RemoveSkin : RemoveSkins(arg, perm);
                    break;
                    case CollectionAction.ExcludeSkin : AddSkinExclusions(arg);
                    break;
                    case CollectionAction.RemoveExludeSkin : RemoveSkinExclusions(arg);
                    break;
                }
            }
            else SendResponse($"[SkinBox] Collection response failed.Error code {code}", arg);
        }
        private void RemoveSkins(ConsoleSystem.Arg arg, string perm = null) {
            int removedCount = 0;
            for (int y = _skinList.Count - 1; y >= 0; y--) {
                KeyValuePair<string, HashSet<ulong>> skin = _skinList.ElementAt(y);
                for (int i = 0; i < _skinsToVerify.Count; i++) {
                    ulong skinId = _skinsToVerify[i];
                    if (skin.Value.Contains(skinId)) {
                        skin.Value.Remove(skinId);
                        Configuration.SkinList[skin.Key].Remove(skinId);
                        removedCount++;
                        if (!string.IsNullOrEmpty(perm)) Configuration.Permission.Custom[perm].Remove(skinId);
                    }
                }
            }
            if (removedCount > 0) SaveConfig();
            SendReply(arg, $"[SkinBox] - Removed {removedCount} skins");
            if (_collectionsToVerify.Count != 0) SendWorkshopCollectionQuery(_collectionsToVerify.Dequeue(), CollectionAction.RemoveSkin, 0, arg, perm);
        }
        private void AddSkinExclusions(ConsoleSystem.Arg arg) {
            int count = 0;
            foreach (ulong skinId in _skinsToVerify) {
                if (!Configuration.Blacklist.Contains(skinId)) {
                    Configuration.Blacklist.Add(skinId);
                    count++;
                }
            }
            if (count > 0) {
                SendResponse($"Added {count} new skin ID's to the excluded list", arg);
                SaveConfig();
            }
        }
        private void RemoveSkinExclusions(ConsoleSystem.Arg arg) {
            int count = 0;
            foreach (ulong skinId in _skinsToVerify) {
                if (Configuration.Blacklist.Contains(skinId)) {
                    Configuration.Blacklist.Remove(skinId);
                    count++;
                }
            }
            if (count > 0) {
                SendResponse($"Removed {count} skin ID's from the excluded list", arg);
                SaveConfig();
            }
        }
        private void SendResponse(string message, ConsoleSystem.Arg arg) {
            if (arg != null) SendReply(arg, message);
            else Debug.Log($"[SkinBox] - {message}");
        }
#endregion
#region Workshop Name Conversions
        private Dictionary<string, string> _workshopNameToShortname = new Dictionary<string, string> {
            {
                "longtshirt", "tshirt.long"
            }
            , {
                "cap", "hat.cap"
            }
            , {
                "beenie", "hat.beenie"
            }
            , {
                "boonie", "hat.boonie"
            }
            , {
                "balaclava", "mask.balaclava"
            }
            , {
                "pipeshotgun", "shotgun.waterpipe"
            }
            , {
                "woodstorage", "box.wooden"
            }
            , {
                "ak47", "rifle.ak"
            }
            , {
                "bearrug", "rug.bear"
            }
            , {
                "boltrifle", "rifle.bolt"
            }
            , {
                "bandana", "mask.bandana"
            }
            , {
                "hideshirt", "attire.hide.vest"
            }
            , {
                "snowjacket", "jacket.snow"
            }
            , {
                "buckethat", "bucket.helmet"
            }
            , {
                "semiautopistol", "pistol.semiauto"
            }
            , {
                "roadsignvest", "roadsign.jacket"
            }
            , {
                "roadsignpants", "roadsign.kilt"
            }
            , {
                "burlappants", "burlap.trousers"
            }
            , {
                "collaredshirt", "shirt.collared"
            }
            , {
                "mp5", "smg.mp5"
            }
            , {
                "sword", "salvaged.sword"
            }
            , {
                "workboots", "shoes.boots"
            }
            , {
                "vagabondjacket", "jacket"
            }
            , {
                "hideshoes", "attire.hide.boots"
            }
            , {
                "deerskullmask", "deer.skull.mask"
            }
            , {
                "minerhat", "hat.miner"
            }
            , {
                "lr300", "rifle.lr300"
            }
            , {
                "lr300.item", "rifle.lr300"
            }
            , {
                "burlapgloves", "burlap.gloves"
            }
            , {
                "burlap.gloves", "burlap.gloves"
            }
            , {
                "leather.gloves", "burlap.gloves"
            }
            , {
                "python", "pistol.python"
            }
            , {
                "m39", "rifle.m39"
            }
            , {
                "l96", "rifle.l96"
            }
            , {
                "woodendoubledoor", "door.double.hinged.wood"
            }
        }
        ;
        private void UpdateWorkshopNameConversionList() {
            foreach (ItemDefinition item in ItemManager.itemList) {
                _shortnameToDisplayname[item.shortname] = item.displayName.english;
                string workshopName = item.displayName.english.ToLower().Replace("skin", "").Replace(" ", "").Replace("-", "");
                if (!_workshopNameToShortname.ContainsKey(workshopName)) _workshopNameToShortname[workshopName] = item.shortname;
                if (!_workshopNameToShortname.ContainsKey(item.shortname)) _workshopNameToShortname[item.shortname] = item.shortname;
                if (!_workshopNameToShortname.ContainsKey(item.shortname.Replace(".", ""))) _workshopNameToShortname[item.shortname.Replace(".", "")] = item.shortname;
            }
            foreach (Skinnable skin in Skinnable.All.ToList()) {
                if (string.IsNullOrEmpty(skin.Name) || string.IsNullOrEmpty(skin.ItemName) || _workshopNameToShortname.ContainsKey(skin.Name.ToLower())) continue;
                _workshopNameToShortname[skin.Name.ToLower()] = skin.ItemName.ToLower();
            }
        }
        private void FixLR300InvalidShortname() {
            const string LR300_ITEM = "lr300.item";
            const string LR300 = "rifle.lr300";
            HashSet<ulong> list;
            if (Configuration.SkinList.TryGetValue(LR300_ITEM, out list)) {
                Configuration.SkinList.Remove(LR300_ITEM);
                Configuration.SkinList[LR300] = list;
                SaveConfig();
            }
        }
#endregion
#region Item Skin Redirects
        private Hash<string, string> _itemSkinRedirects = new Hash<string, string>();
        private void FindItemRedirects() {
            bool addApprovedPermission = Configuration.Permission.Approved != Configuration.Permission.Use;
            foreach (ItemSkinDirectory.Skin skin in ItemSkinDirectory.Instance.skins) {
                ItemSkin itemSkin = skin.invItem as ItemSkin;
                if (itemSkin == null || itemSkin.Redirect == null) continue;
                _itemSkinRedirects[itemSkin.Redirect.shortname] = itemSkin.itemDefinition.shortname;
                if (Configuration.Skins.UseRedirected) {
                    HashSet<ulong> skins;
                    if (!_skinList.TryGetValue(itemSkin.itemDefinition.shortname, out skins)) skins = _skinList[itemSkin.itemDefinition.shortname] = new HashSet<ulong>();
                    skins.Add((ulong)skin.id);
                    _skinNameLookup[(ulong)skin.id] = itemSkin.displayName.english;
                    _skinSearchLookup[(ulong)skin.id] = $"{(ulong)skin.id} {itemSkin.displayName.english}";
                    if (addApprovedPermission) _skinPermissions[(ulong)skin.id] = Configuration.Permission.Approved;
                }
            }
        }
        private string GetRedirectedShortname(string shortname) {
            string redirectedName;
            if (_itemSkinRedirects.TryGetValue(shortname, out redirectedName)) return redirectedName;
            return shortname;
        }
#endregion
#region SkinBox Component
        private class DeployableHandler : LootHandler {
            internal ReskinTarget Target {
                set {
                    reskinTarget = value;
                    Populate();
                }
            }
            protected override ItemDefinition Definition => reskinTarget.itemDefinition.isRedirectOf ?? reskinTarget.itemDefinition;
            protected override ulong InputSkin => reskinTarget.entity.skinID;
            private ReskinTarget reskinTarget;
            protected override void Awake() {
                _filteredSkins = Facepunch.Pool.GetList<ulong>();
                Entity = GetComponent<StorageContainer>();
                if (!Configuration.Other.AllowStacks) {
                    Entity.maxStackSize = 1;
                    Entity.inventory.maxStackSize = 1;
                }
                Entity.SetFlag(BaseEntity.Flags.Open, true, false);
            }
            internal void Populate() {
                if (HasItem) return;
                HasItem = true;
                InputShortname = reskinTarget.itemDefinition.isRedirectOf != null ? reskinTarget.itemDefinition.isRedirectOf.shortname : reskinTarget.itemDefinition.shortname;
                _availableSkins = reskinTarget.skins;
                _availableSkins.Remove(0UL);
                if (InputSkin != 0UL) _availableSkins.Remove(InputSkin);
                _filteredSkins.AddRange(_availableSkins);
                _itemsPerPage = InputSkin == 0UL ? Entity.inventory.capacity - 1 : Entity.inventory.capacity - 2;
                _currentPage = 0;
                _maximumPages = Mathf.Min(Configuration.Skins.MaximumPages, Mathf.CeilToInt((float)_filteredSkins.Count / (float)_itemsPerPage));
                if (_currentPage > 0 || _maximumPages > 1) CreateOverlay();
                CreateSearchBar();
                if (Configuration.Favourites.Enabled && Favourites.UserHasFavouritesFor(Looter, InputShortname)) 
// ... [Code preview truncated due to length. Full source in attached file] ...

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