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

FREE SkinBox : 2.0.14 2.0.14

Нет прав для скачивания
C#:
using Newtonsoft.Json;
using Oxide.Core;
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.0.14"), 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<string, HashSet<ulong>> _skinList = new Hash<string, HashSet<ulong>>();
        private Hash<ulong, string> _skinPermissions = new Hash<ulong, string>();
        private Hash<ulong, LootHandler> _activeSkinBoxes = new Hash<ulong, LootHandler>();
        private Hash<string, string> _shortnameToDisplayname = new Hash<string, string>();
        private Hash<ulong, string> _skinNameLookup = new Hash<ulong, string>();
        private Hash<ulong, double> _cooldownTimes = new Hash<ulong, double>();
        private bool _apiKeyMissing = false;
        private bool _skinsLoaded = false;
        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);
            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", ["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",
            }
            , this);
        }
        private void OnServerInitialized() {
            UnsubscribeHooks();
            if (string.IsNullOrEmpty(Configuration.Skins.APIKey)) {
                _apiKeyMissing = true;
                SendAPIMissingWarning();
                return;
            }
            if ((Steamworks.SteamInventory.Definitions?.Length ?? 0) == 0) {
                PrintWarning("Waiting for Steamworks to update item definitions....");
                Steamworks.SteamInventory.OnDefinitionsUpdated += StartSkinRequest;
            }
            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;
            }
            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.Destroy(lootHandler);
        }
        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) {
            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);
            }
            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();
            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);
                }
            }
        }
        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 StartSkinRequest() {
            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;
                }
                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 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 {
            }
        }
        private void SendWorkshopCollectionQuery(ulong collectionId, bool add, 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(code, response, add, 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;
                                    }
                                    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 (!_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(int code, string response, bool add, int success, ConsoleSystem.Arg arg, string perm) {
            if (response != null && code == 200) {
                SendResponse("Processing collection response", 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 {
                        _skinsToVerify.Add(Convert.ToUInt64(child.publishedfileid));
                    }
                    catch {
                    }
                }
                if (_skinsToVerify.Count == 0) {
                    SendResponse("No valid skin ID's in the specified collection", arg);
                    yield break;
                }
                if (add) SendWorkshopQuery(0, success, arg, perm);
                else RemoveSkins(arg, perm);
            }
            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");
        }
        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);
                    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 LootHandler : MonoBehaviour {
            internal StorageContainer Entity {
                get;
                private set;
            }
            internal BasePlayer Looter {
                get;
                set;
            }
            internal bool HasItem {
                get;
                private set;
            }
            internal int InputAmount => inputItem?.amount ?? 0;
            private InputItem inputItem;
            private int _currentPage = 0;
            private int _maximumPages = 0;
            private int _itemsPerPage;
            private List<ulong> _availableSkins;
            private bool _isFillingContainer;
            private void Awake() {
                _availableSkins = 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);
            }
            private void OnDestroy() {
                CuiHelper.DestroyUi(Looter, UI_PANEL);
                Instance?._activeSkinBoxes?.Remove(Looter.userID);
                if (HasItem && inputItem != null) Looter.GiveItem(inputItem.Create(), BaseEntity.GiveItemReason.PickedUp);
                Facepunch.Pool.FreeList(ref _availableSkins);
                if (Entity != null && !Entity.IsDestroyed) {
                    if (Entity.inventory.itemList.Count > 0) ClearContainer();
                    Entity.Kill(BaseNetworkable.DestroyMode.None);
                }
                Instance?.ToggleHooks();
            }
            internal void OnItemAdded(Item item) {
                if (HasItem) return;
                HasItem = true;
                string shortname = Instance.GetRedirectedShortname(item.info.shortname);
                Instance.GetSkinsFor(Looter, shortname, ref _availableSkins);
                _availableSkins.Remove(0UL);
                if (item.skin != 0UL) _availableSkins.Remove(item.skin);
                inputItem = new InputItem(shortname, item);
                _itemsPerPage = inputItem.skin == 0UL ? 41 : 40;
                _currentPage = 0;
                _maximumPages = Mathf.Min(Configuration.Skins.MaximumPages, Mathf.CeilToInt((float)_availableSkins.Count / (float)_itemsPerPage));
                if (_currentPage > 0 || _maximumPages > 1) CreateOverlay();
                RemoveItem(item);
                ClearContainer();
                StartCoroutine(FillContainer());
            }
            internal void OnItemRemoved(Item item) {
                if (!HasItem) return;
                CuiHelper.DestroyUi(Looter, UI_PANEL);
                bool skinChanged = item.skin != 0UL && item.skin != inputItem.skin;
                inputItem.CloneTo(item);
                if (skinChanged && !Instance.ChargePlayer(Looter, inputItem.itemDefinition.category)) {
                    item.skin = inputItem.skin;
                    if (item.GetHeldEntity() != null) item.GetHeldEntity().skinID = inputItem.skin;
                    PopupMessage(string.Format(GetMessage("NotEnoughBalanceTake", Looter.userID), item.info.displayName.english, Instance.GetCostType(Looter.userID)));
                }
                if (item.skin != 0UL && Configuration.Skins.ShowSkinIDs) Instance._skinNameLookup.TryGetValue(item.skin, out item.name);
                item.MarkDirty();
                ClearContainer();
                Entity.inventory.MarkDirty();
                inputItem.Dispose();
                inputItem = null;
                HasItem = false;
                if (Configuration.Cooldown.ActivateOnTake) Instance.ApplyCooldown(Looter);
                if (Instance.IsOnCooldown(Looter)) Looter.EndLooting();
            }
            internal void ChangePage(int change) {
                if (_isFillingContainer) return;
                _currentPage = Mathf.Clamp(_currentPage + change, 0, _maximumPages);
                StartCoroutine(RefillContainer());
            }
            private IEnumerator RefillContainer() {
                ClearContainer();
                yield return StartCoroutine(FillContainer());
                if (HasItem) CreateOverlay();
            }
            private IEnumerator FillContainer() {
                _isFillingContainer = true;
                CreateItem(0UL);
                if (inputItem.skin != 0UL) CreateItem(inputItem.skin);
                for (int i = _currentPage * _itemsPerPage; i < Mathf.Min(_availableSkins.Count, (_currentPage + 1) * _itemsPerPage);
                i++) {
                    if (!HasItem) break;
                    CreateItem(_availableSkins[i]);
                    if (i % 2 == 0) yield return null;
                }
                _isFillingContainer = false;
            }
            private void ClearContainer() {
                for (int i = Entity.inventory.itemList.Count - 1; i >= 0; i--) RemoveItem(Entity.inventory.itemList[i]);
            }
            private Item CreateItem(ulong skinId) {
                Item item = ItemManager.Create(inputItem.itemDefinition, 1, skinId);
                item.contents?.SetFlag(ItemContainer.Flag.IsLocked, true);
                item.contents?.SetFlag(ItemContainer.Flag.NoItemInput, true);
                if (skinId != 0UL) {
                    Instance._skinNameLookup.TryGetValue(skinId, out item.name);
                    if (Configuration.Skins.ShowSkinIDs && Looter.IsAdmin) item.name = $"{item.name} ({skinId})";
                }
                if (!InsertItem(item)) item.Remove(0f);
                else item.MarkDirty();
                return item;
            }
            private bool InsertItem(Item item) {
                if (Entity.inventory.itemList.Contains(item)) return false;
                if (Entity.inventory.IsFull()) return false;
                Entity.inventory.itemList.Add(item);
                item.parent = Entity.inventory;
                if (!Entity.inventory.FindPosition(item)) return false;
                Entity.inventory.MarkDirty();
                Entity.inventory.onItemAddedRemoved?.Invoke(item, true);
                return true;
            }
            private void RemoveItem(Item item) {
                if (!Entity.inventory.itemList.Contains(item)) return;
                Entity.inventory.onPreItemRemove?.Invoke(item);
                Entity.inventory.itemList.Remove(item);
                item.parent = null;
                Entity.inventory.MarkDirty();
                Entity.inventory.onItemAddedRemoved?.Invoke(item, false);
                item.Remove(0f);
            }
            internal void CheckItemHasSplit(Item item) => StartCoroutine(CheckItemHasSplit(item, item.amount));
            // Item split dupe solution?
            private IEnumerator CheckItemHasSplit(Item item, int originalAmount) {
                yield return null;
                if (item != null && item.amount != originalAmount) {
                    int splitAmount = originalAmount - item.amount;
                    Looter.inventory.Take(null, item.info.itemid, splitAmount);
                    item.amount += splitAmount;
                }
            }
            private class InputItem {
                public ItemDefinition itemDefinition;
                public int amount;
                public ulong skin;
                public float condition;
                public float maxCondition;
                public int magazineContents;
                public int magazineCapacity;
                public ItemDefinition ammoType;
                public List<InputItem> contents;
                internal InputItem(string shortname, Item item) {
                    if (!item.info.shortname.Equals(shortname)) itemDefinition = ItemManager.FindItemDefinition(shortname);
                    else itemDefinition = item.info;
                    amount = item.amount;
                    skin = item.skin;
                    if (item.hasCondition) {
                        condition = item.condition;
                        maxCondition = item.maxCondition;
                    }
                    BaseProjectile baseProjectile = item.GetHeldEntity() as BaseProjectile;
                    if (baseProjectile != null) {
                        magazineContents = baseProjectile.primaryMagazine.contents;
                        magazineCapacity = baseProjectile.primaryMagazine.capacity;
                        ammoType = baseProjectile.primaryMagazine.ammoType;
              
// ... [Code preview truncated due to length. Full source in attached file] ...

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