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

FREE PlayerSkins : 2.0.21 2.0.21

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Game.Rust.Cui;
using Oxide.Core.Plugins;
using UnityEngine;
using Steamworks;
using System.Linq;
using System.Collections;
using System.Globalization;
namespace Oxide.Plugins {
    [Info("PlayerSkins", "k1lly0u", "2.0.21")]
    [Description("Fully Customization Skin Management Plugin - Sell Skinned items or Skins!")]
    class PlayerSkins : RustPlugin {
#region Fields
        [PluginReference]
        Plugin Economics, ImageLibrary, ServerRewards;
        private Dictionary<string, Dictionary<ulong, SkinData>> skinData = new Dictionary<string, Dictionary<ulong, SkinData>>();
        private Dictionary<ulong, UserData> userData = new Dictionary<ulong, UserData>();
        private List<ulong> excludedSkins = new List<ulong>();
        private DynamicConfigFile userdata, skindata, excludeddata;
        private Dictionary<string, Dictionary<ulong, WorkshopItem>> workshopItems = new Dictionary<string, Dictionary<ulong, WorkshopItem>>();
        private Dictionary<string, string> shortnameToDisplayname = new Dictionary<string, string>();
        private List<ulong> adminToggle = new List<ulong>();
        private List<ulong> ownedToggle = new List<ulong>();
        private List<ulong> approvedIds = new List<ulong>();
        private bool initialized = false;
        private bool workshopInitialized = false;
        private bool itemlistInitialized = false;
        private JsonSerializerSettings errorHandling = new JsonSerializerSettings {
            Error = (se, ev) => {
                ev.ErrorContext.Handled = true;
            }
        }
        ;
        private static Dictionary<Colors, string> uiColor;
        private static bool forceHttp = false;
        private TokenType purchaseType;
        private DisplayMode forcedMode;
        public enum TokenType {
            None, ServerRewards, Economics
        }
#endregion
#region Oxide Hooks
        private void Loaded() {
            skindata = Interface.Oxide.DataFileSystem.GetFile("PlayerSkins/skinlist");
            userdata = Interface.Oxide.DataFileSystem.GetFile("PlayerSkins/userdata");
            excludeddata = Interface.Oxide.DataFileSystem.GetFile("PlayerSkins/excludedskins");
            shortnameToDisplayname = Interface.Oxide.DataFileSystem.GetFile("PlayerSkins/itemDisplayNames").ReadObject<Dictionary<string, string>>();
            permission.RegisterPermission("playerskins.shop", this);
            permission.RegisterPermission("playerskins.reskin", this);
            permission.RegisterPermission("playerskins.admin", this);
            permission.RegisterPermission("playerskins.nocharge", this);
            lang.RegisterMessages(Messages, this);
        }
        private void OnServerInitialized() {
            LoadData();
            forceHttp = configData.Workshop.ForceHTTP;
            purchaseType = ParseType<TokenType>(configData.Purchase.Type);
            if (configData.Purchase.Enabled && purchaseType == TokenType.None) {
                PrintError("Invalid purchase plugin specified in config.Must be either 'ServerRewards' or 'Economics'!");
                return;
            }
            forcedMode = ParseType<DisplayMode>(configData.Shop.ForcedMode);
            foreach (string perm in configData.Shop.Permissions) {
                if (!perm.StartsWith("playerskins.")) permission.RegisterPermission($"playerskins.{perm}", this);
                else permission.RegisterPermission(perm, this);
            }
            uiColor = new Dictionary<Colors, string>();
            foreach (var color in configData.UI.Colors) uiColor.Add(color.Key, UI.Color(color.Value.Color, color.Value.Alpha));
            bool displayNameChanged = false;
            foreach (ItemDefinition item in ItemManager.itemList) {
                if (!shortnameToDisplayname.ContainsKey(item.shortname)) {
                    shortnameToDisplayname.Add(item.shortname, item.displayName.english);
                    displayNameChanged = true;
                }
                string workshopName = item.displayName.english.ToLower().Replace("skin", "").Replace(" ", "").Replace("-", "");
                if (!workshopNameToShortname.ContainsKey(workshopName)) workshopNameToShortname.Add(workshopName, item.shortname);
                if (!workshopNameToShortname.ContainsKey(item.shortname)) workshopNameToShortname.Add(item.shortname, item.shortname);
            }
            if (displayNameChanged) Interface.Oxide.DataFileSystem.WriteObject("PlayerSkins/itemDisplayNames", shortnameToDisplayname);
            if (string.IsNullOrEmpty(configData.Workshop.SteamAPIKey)) {
                PrintError("You must enter a Steam API key in your config in order to retrieve approved skin icons and/or access workshop items.Unable to continue...");
                return;
            }
            if ((Steamworks.SteamInventory.Definitions?.Length ?? 0) == 0) {
                PrintWarning("Waiting for Steamworks to update item definitions....");
                Steamworks.SteamInventory.OnDefinitionsUpdated += StartApprovedRequest;
            }
            else StartApprovedRequest();
        }
        private void OnServerSave() => SaveUserData();
        private void Unload() {
            foreach (BasePlayer player in BasePlayer.activePlayerList) DestroyUI(player);
            initialized = false;
        }
        private void OnActiveItemChanged(BasePlayer player, Item oldItem, Item newItem) {
            CuiHelper.DestroyUi(player, ReskinPanel);
        }
        private void OnUseNPC(BasePlayer npc, BasePlayer player) {
            if (player == null || npc == null) return;
            if (!userData.ContainsKey(player.userID)) userData.Add(player.userID, new UserData());
            if (configData.Shop.NPCs.Contains(npc.UserIDString)) OpenSkinMenu(player, "", 0, 0);
            else if (configData.Reskin.NPCs.Contains(npc.UserIDString) && !configData.Shop.GiveItemOnPurchase) CreateReskinMenu(player);
        }
        private void OnItemCraftFinished(ItemCraftTask task, Item item) {
            BasePlayer player = task?.owner;
            if (player == null || item == null) return;
            if (item.skin != 0) return;
            UserData data;
            if (!userData.TryGetValue(player.userID, out data)) return;
            if (data.defaultSkins.ContainsKey(item.info.shortname)) ChangeItemSkin(item, data.defaultSkins[item.info.shortname]);
        }
#endregion
#region Functions
        private T ParseType<T>(string type) {
            try {
                return (T)Enum.Parse(typeof(T), type, true);
            }
            catch {
                return default(T);
            }
        }
        private bool HasPermission(BasePlayer player, string perm) {
            if (!perm.StartsWith("playerskins.")) perm = $"playerskins.{perm}";
            return permission.UserHasPermission(player.UserIDString, perm);
        }
        private void BroadcastAnnouncement() {
            if (!configData.Announcements.Enabled && configData.Announcements.Interval > 0) return;
            foreach (BasePlayer player in BasePlayer.activePlayerList) {
                if (configData.Shop.DisableCommand) SendReply(player, msg("Help.Shop.NPC", player.userID));
                else SendReply(player, msg("Help.Shop.Command", player.userID));
                if (configData.Reskin.DisableCommand) SendReply(player, msg("Help.Reskin.NPC", player.userID));
                else SendReply(player, msg("Help.Reskin.Command", player.userID));
            }
            timer.In(configData.Announcements.Interval * 60, BroadcastAnnouncement);
        }
        private void ChangeItemSkin(BasePlayer player, ulong targetSkin) {
            Item item = player.GetActiveItem();
            if (item == null) {
                item = player.inventory.containerBelt.GetSlot(0);
                if (item == null) return;
            }
            ChangeItemSkin(item, targetSkin);
            int slot = item.position;
            item.SetParent(null);
            item.MarkDirty();
            timer.Once(0.15f, () => {
                if (item == null) return;
                item.SetParent(player.inventory.containerBelt);
                item.position = slot;
                item.MarkDirty();
            }
            );
        }
        private void ChangeItemSkin(Item item, ulong targetSkin) {
            item.skin = targetSkin;
            item.MarkDirty();
            BaseEntity heldEntity = item.GetHeldEntity();
            if (heldEntity != null) {
                heldEntity.skinID = targetSkin;
                heldEntity.SendNetworkUpdate(BasePlayer.NetworkQueue.Update);
            }
        }
#endregion
#region Skin List Initialization
        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"
            }
            , {
                "burlapgloves", "burlap.gloves"
            }
            , {
                "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"
            }
            , {
                "burlap.gloves", "burlap.gloves.new"
            }
            , {
                "leather.gloves", "burlap.gloves"
            }
            , {
                "python", "pistol.python"
            }
            , {
                "m39", "rifle.m39"
            }
            , {
                "woodendoubledoor", "door.double.hinged.wood"
            }
        }
        ;
        private string[] blockedItems = new string[] {
            "sign.", "jackolantern.", "xmas", "boots.frog", "skull_fire_pit", "scarecrow", "snowman"
        }
        ;
#endregion
#region Approved Skins
        private void StartApprovedRequest() {
            Steamworks.SteamInventory.OnDefinitionsUpdated -= StartApprovedRequest;
            if (configData.Workshop.ApprovedDisabled && !configData.Workshop.Enabled) {
                PrintError("You have approved skins and workshop skins disabled.This leaves no skins to be shown in the skin shop!");
                return;
            }
            if (configData.Workshop.ApprovedDisabled && configData.Workshop.Enabled) {
                itemlistInitialized = initialized = true;
                GetWorkshopSkins();
                return;
            }
            PrintWarning("Retrieving approved skin lists...");
            itemlistInitialized = true;
            GetApprovedItemSkins(BuildApprovedItemList(), 0);
        }
        private void GetApprovedItemSkins(List<ulong> itemsToDownload, int page) {
            if (itemsToDownload.Count < 1) {
                ValidateDataShortnames();
                initialized = true;
                Puts("Approved skins loaded");
                if (configData.Workshop.Enabled) GetWorkshopSkins();
                return;
            }
            int totalPages = Mathf.CeilToInt((float)itemsToDownload.Count / 100f) - 1;
            string details = BuildDetailsString(itemsToDownload, page);
            QueueFileQueryRequest(details, (PublishedFileQueryDetail[] items) => {
                ServerMgr.Instance.StartCoroutine(ProcessApprovedBlock(itemsToDownload, items, page, totalPages));
            }
            );
        }
        private IEnumerator ProcessApprovedBlock(List<ulong> itemsToDownload, PublishedFileQueryDetail[] items, int page, int totalPages) {
            PrintWarning($"Processing approved skins; Page {page + 1}/{totalPages + 1}");
            Dictionary<string, Dictionary<ulong, string>> loadOrder = new Dictionary<string, Dictionary<ulong, string>>();
            foreach (PublishedFileQueryDetail item in items) {
                if (!IsValid(item)) continue;
                foreach (PublishedFileQueryDetail.Tag tag in item.tags) {
                    if (string.IsNullOrEmpty(tag.tag)) continue;
                    ulong workshopid = Convert.ToUInt64(item.publishedfileid);
                    string adjTag = tag.tag.ToLower().Replace("skin", "").Replace(" ", "").Replace("-", "").Replace(".item", "");
                    if (workshopNameToShortname.ContainsKey(adjTag)) {
                        string shortname = workshopNameToShortname[adjTag];
                        if (!skinData.ContainsKey(shortname)) skinData.Add(shortname, new Dictionary<ulong, SkinData>());
                        if (!skinData[shortname].ContainsKey(workshopid)) skinData[shortname].Add(workshopid, new SkinData());
                        if (!workshopItems.ContainsKey(shortname)) workshopItems.Add(shortname, new Dictionary<ulong, WorkshopItem>());
                        if (!workshopItems[shortname].ContainsKey(workshopid)) {
                            WorkshopItem workshopItem = new WorkshopItem(item);
                            if (workshopItem == null) continue;
                            workshopItems[shortname].Add(workshopid, workshopItem);
                        }
                        if (!HasImage(shortname, workshopid)) {
                            if (!loadOrder.ContainsKey(shortname)) loadOrder.Add(shortname, new Dictionary<ulong, string>());
                            if (!loadOrder[shortname].ContainsKey(workshopid)) {
                                loadOrder[shortname].Add(workshopid, workshopItems[shortname][workshopid].imageUrl);
                            }
                        }
                    }
                }
            }
            if (loadOrder.Count > 0) {
                loadOrderCount++;
                Puts($"Creating load order for approved skins (Order #{loadOrderCount})");
                ImageLibrary.Call("ImportItemList", $"{Title} approved skin icons (Order #{loadOrderCount})", loadOrder);
            }
            yield return CoroutineEx.waitForEndOfFrame;
            yield return CoroutineEx.waitForEndOfFrame;
            if (page < totalPages) GetApprovedItemSkins(itemsToDownload, page + 1);
            else {
                itemsToDownload.Clear();
                ValidateDataShortnames();
                initialized = true;
                Puts("Approved skins loaded");
                if (configData.Workshop.Enabled) GetWorkshopSkins();
            }
        }
        private List<ulong> BuildApprovedItemList() {
            List<ulong> list = new List<ulong>();
            foreach (InventoryDef item in Steamworks.SteamInventory.Definitions) {
                string shortname = item.GetProperty("itemshortname");
                ulong workshopid;
                if (item == null || string.IsNullOrEmpty(shortname)) continue;
                if (workshopNameToShortname.ContainsKey(shortname)) shortname = workshopNameToShortname[shortname];
                if (item.Id < 100 || blockedItems.Any(x => shortname.StartsWith(x))) continue;
                if (!ulong.TryParse(item.GetProperty("workshopid"), out workshopid)) continue;
                approvedIds.Add(workshopid);
                if (excludedSkins.Contains(workshopid)) continue;
                if (!skinData.ContainsKey(shortname)) skinData.Add(shortname, new Dictionary<ulong, SkinData>());
                if (!skinData[shortname].ContainsKey(workshopid)) skinData[shortname].Add(workshopid, new SkinData());
                if (HasImage(shortname, workshopid)) {
                    if (!workshopItems.ContainsKey(shortname)) workshopItems.Add(shortname, new Dictionary<ulong, WorkshopItem>());
                    if (!workshopItems[shortname].ContainsKey(workshopid)) {
                        WorkshopItem workshopItem = new WorkshopItem(item, GetImageURL(shortname, workshopid));
                        if (workshopItem == null) continue;
                        workshopItems[shortname].Add(workshopid, workshopItem);
                    }
                    continue;
                }
                list.Add(workshopid);
            }
            return list;
        }
#endregion
#region Workshop Items
        private const string publishedFileQuery = "https://api.steampowered.com/IPublishedFileService/QueryFiles/v1/?key={0}&page={1}&numperpage=100&appid=252490&requiredtags=version3%2Cskin&match_all_tags=1&return_tags=1&return_previews=1";
        private const string publishedFileDetails = "https://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1/";
        private int workshopPage = 0;
        private int totalPages = -1;
        private int totalCount = 0;
        private int loadOrderCount = 0;
        private void GetWorkshopSkins() {
            if (ImageLibrary == null || string.IsNullOrEmpty(configData.Workshop.SteamAPIKey)) return;
            loadOrderCount = 0;
            PrintWarning("Querying Steam for workshop items.This process can take a while!\nWorkshop skins will be unavailable in the skin shop and reskin menu until this process has completed.Once the workshop data has been loaded any registered workshop skins will appear.");
            WorkshopQuery(string.Format(publishedFileQuery, configData.Workshop.SteamAPIKey, workshopPage));
        }
        private void WorkshopQuery(string queryStr) {
            webrequest.Enqueue(queryStr, null, (code, response) => {
                try {
                    QueryResponse query = JsonConvert.DeserializeObject<QueryResponse>(response, errorHandling);
                    if (query == null || query.response == null || query.response.publishedfiledetails.Length == 0) {
                        if (code != 200) PrintError($"There was a error querying Steam for workshop data : Code ({code})");
                        workshopPage++;
                        if (workshopPage < totalPages) WorkshopQuery(string.Format(publishedFileQuery, configData.Workshop.SteamAPIKey, workshopPage));
                        else InitializeWorkshop();
                        return;
                    }
                    else {
                        if (totalPages == -1) totalPages = Mathf.CeilToInt((float)query.response.total / 100f);
                        ServerMgr.Instance.StartCoroutine(ProcessWorkshopResponse(query.response.publishedfiledetails));
                    }
                }
                catch (Exception ex) {
                    if (code != 200) PrintError($"There was a error querying Steam for workshop data : Code ({code})\n{ex.Message}");
                    workshopPage++;
                    if (workshopPage < totalPages) WorkshopQuery(string.Format(publishedFileQuery, configData.Workshop.SteamAPIKey, workshopPage));
                    else {
                        List<ulong> invalidSkins = FindMissingSkins();
                        if (invalidSkins.Count == 0) InitializeWorkshop();
                        else {
                            PrintWarning("Querying Steam for missing item icons...");
                            FindSkinsWithNoData(invalidSkins, 0);
                        }
                    }
                }
            }
            , this);
        }
        private IEnumerator ProcessWorkshopResponse(PublishedFileDetails[] response) {
            Dictionary<string, Dictionary<ulong, string>> loadOrder = new Dictionary<string, Dictionary<ulong, string>>();
            foreach (PublishedFileDetails item in response) {
                if (!IsValid(item)) continue;
                foreach (PublishedFileDetails.Tag tag in item.tags) {
                    if (string.IsNullOrEmpty(tag.tag)) continue;
                    ulong workshopId = Convert.ToUInt64(item.publishedfileid);
                    if (approvedIds.Contains(workshopId)) continue;
                    string adjTag = tag.tag.ToLower().Replace("skin", "").Replace(" ", "").Replace("-", "").Replace(".item", "");
                    if (workshopNameToShortname.ContainsKey(adjTag)) {
                        string shortname = workshopNameToShortname[adjTag];
                        if (!workshopItems.ContainsKey(shortname)) workshopItems.Add(shortname, new Dictionary<ulong, WorkshopItem>());
                        if (!workshopItems[shortname].ContainsKey(workshopId)) {
                            WorkshopItem workshopItem = new WorkshopItem(item);
                            if (workshopItem == null) continue;
                            workshopItems[shortname].Add(workshopId, workshopItem);
                            totalCount++;
                        }
                        if (skinData.ContainsKey(shortname)) {
                            if (skinData[shortname].ContainsKey(workshopId)) {
                                if (!HasImage(shortname, workshopId)) {
                                    Puts("needs download " + shortname + " " + workshopId);
                                    if (!loadOrder.ContainsKey(shortname)) loadOrder.Add(shortname, new Dictionary<ulong, string>());
                                    if (!loadOrder[shortname].ContainsKey(workshopId)) {
                                        loadOrder[shortname].Add(workshopId, workshopItems[shortname][workshopId].imageUrl);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (loadOrder.Count > 0) {
                Puts("create load order " + loadOrder.Count);
                loadOrderCount++;
                Puts($"Creating a load order for workshop skins (Order #{loadOrderCount})");
                ImageLibrary.Call("ImportItemList", $"{Title} workshop skin icons (Order #{loadOrderCount})", loadOrder);
            }
            workshopPage++;
            yield return CoroutineEx.waitForEndOfFrame;
            yield return CoroutineEx.waitForEndOfFrame;
            if (workshopPage < totalPages) {
                WorkshopQuery(string.Format(publishedFileQuery, configData.Workshop.SteamAPIKey, workshopPage));
            }
            else {
                List<ulong> invalidSkins = FindMissingSkins();
                if (invalidSkins.Count == 0) InitializeWorkshop();
                else {
                    PrintWarning("Querying Steam for missing item icons...");
                    FindSkinsWithNoData(invalidSkins, 0);
                }
            }
        }
#endregion
#region Find Missing Skins
        private List<ulong> FindMissingSkins() {
            List<ulong> invalidSkins = new List<ulong>();
            for (int i = skinData.Count - 1; i >= 0; i--) {
                KeyValuePair<string, Dictionary<ulong, SkinData>> skinInfo = skinData.ElementAt(i);
                for (int y = skinInfo.Value.Count - 1; y >= 0; y--) {
                    KeyValuePair<ulong, SkinData> skin = skinInfo.Value.ElementAt(y);
                    if (excludedSkins.Contains(skin.Key)) continue;
                    if (!workshopItems.ContainsKey(skinInfo.Key) || !workshopItems[skinInfo.Key].ContainsKey(skin.Key) || workshopItems[skinInfo.Key][skin.Key] == null) {
                        invalidSkins.Add(skin.Key);
                    }
                }
            }
            return invalidSkins;
        }
        private void FindSkinsWithNoData(List<ulong> invalidSkins, int page) {
            int totalPages = Mathf.CeilToInt((float)invalidSkins.Count / 100f) - 1;
            string details = BuildDetailsString(invalidSkins, page);
            QueueFileQueryRequest(details, (PublishedFileQueryDetail[] items) => {
                ServerMgr.Instance.StartCoroutine(ProcessMissingBlock(invalidSkins, items, page, totalPages));
            }
            );
        }
        private IEnumerator ProcessMissingBlock(List<ulong> invalidSkins, PublishedFileQueryDetail[] items, int page, int totalPages) {
            Dictionary<string, Dictionary<ulong, string>> loadOrder = new Dictionary<string, Dictionary<ulong, string>>();
            foreach (PublishedFileQueryDetail item in items) {
                if (!IsValid(item)) continue;
                foreach (PublishedFileQueryDetail.Tag tag in item.tags) {
                    if (string.IsNullOrEmpty(tag.tag)) continue;
                    ulong workshopId = Convert.ToUInt64(item.publishedfileid);
                    string adjTag = tag.tag.ToLower().Replace("skin", "").Replace(" ", "").Replace("-", "").Replace(".item", "");
                    if (workshopNameToShortname.ContainsKey(adjTag)) {
                        string shortname = workshopNameToShortname[adjTag];
                        if (!workshopItems.ContainsKey(shortname)) workshopItems.Add(shortname, new Dictionary<ulong, WorkshopItem>());
                        if (!workshopItems[shortname].ContainsKey(workshopId)) {
                            WorkshopItem workshopItem = new WorkshopItem(item);
                            if (workshopItem == null) continue;
                            workshopItems[shortname].Add(workshopId, workshopItem);
                            totalCount++;
                        }
                        if (skinData.ContainsKey(shortname)) {
                            if (skinData[shortname].ContainsKey(workshopId)) {
                                if (!HasImage(shortname, workshopId)) {
                                    if (!loadOrder.ContainsKey(shortname)) loadOrder.Add(shortname, new Dictionary<ulong, string>());
                                    if (!loadOrder[shortname].ContainsKey(workshopId)) {
                                        loadOrder[shortname].Add(workshopId, workshopItems[shortname][workshopId].imageUrl);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (loadOrder.Count > 0) {
                loadOrderCount++;
                Puts($"Creating a load order for missing skin icons (Order #{loadOrderCount})");
                ImageLibrary.Call("ImportItemList", $"{Title} missing workshop skin icons (Order #{loadOrderCount})", loadOrder);
            }
            invalidSkins.Clear();
            yield return CoroutineEx.waitForEndOfFrame;
            yield return CoroutineEx.waitForEndOfFrame;
            if (page < totalPages) FindSkinsWithNoData(invalidSkins, page + 1);
            else {
                invalidSkins.Clear();
                InitializeWorkshop();
            }
        }
        private void InitializeWorkshop() {
            foreach (KeyValuePair<string, Dictionary<ulong, WorkshopItem>> kvp in workshopItems) Interface.Oxide.DataFileSystem.WriteObject<Dictionary<ulong, WorkshopItem>>($"PlayerSkins/WorkshopData/{kvp.Key}", kvp.Value);
            Puts("Saved available workshop skin lists to \"/oxide/data/PlayerSkins/WorkshopData/\"");
            PrintWarning($"Workshop skin list retrieval completed.{totalCount} workshop skins are now available!");
            workshopInitialized = true;
        }
#endregion
#region API Helpers
        private bool ContainsKeyword(string title) {
            foreach (string keyword in configData.Workshop.Filter) {
                if (title.ToLower().Contains(keyword.ToLower())) return true;
            }
            return false;
        }
        private bool IsValid(PublishedFileDetails item) {
            if (ContainsKeyword(item.title)) return false;
            if (string.IsNullOrEmpty(item.preview_url)) return false;
            if (item.tags == null) return false;
            return true;
        }
        private bool IsValid(PublishedFileQueryDetail item) {
            if (ContainsKeyword(item.title)) return false;
            if (string.IsNullOrEmpty(item.preview_url)) return false;
            if (item.tags == null) return false;
            return true;
        }
        private string BuildDetailsString(List<ulong> list, int page) {
            int start = page * 100;
            int end = start + 100 > list.Count ? list.Count : start + 100;
            string details = string.Format("?key={0}&itemcount={1}", configData.Workshop.SteamAPIKey, end - start);
            for (int i = start; i < end; i++) details += string.Format("&publishedfileids[{0}]={1}", i - start, list[i]);
            return details;
        }
        private void QueueFileQueryRequest(string details, Action<PublishedFileQueryDetail[]> callback) {
            webrequest.Enqueue(publishedFileDetails, details, (code, response) => {
                try {
                    PublishedFileQueryResponse query = JsonConvert.DeserializeObject<PublishedFileQueryResponse>(response, errorHandling);
                    if (query == null || query.response == null || query.response.publishedfiledetails.Length == 0) {
                        if (code != 200) PrintError($"There was a error querying Steam for workshop item data : Code ({code})");
                        return;
                    }
                    else {
                        if (query?.response?.publishedfiledetails?.Length > 0) callback.Invoke(query.response.publishedfiledetails);
                    }
                }
                catch {
                }
            }
            , this, Core.Libraries.RequestMethod.POST);
        }
        private void ValidateDataShortnames() {
            bool flag = false;
            for (int i = skinData.Count - 1; i >= 0; i--) {
                string shortname = skinData.ElementAt(i).Key;
                if (!shortnameToDisplayname.ContainsKey(shortname)) {
                    skinData.Remove(shortname);
                    Puts($"Removing invalid item shortname from data file : {shortname}");
                    flag = true;
                }
            }
            if (flag) SaveSkinData();
        }
#endregion
#region Image Library
        private string GetImage(string shortname, ulong skin = 0) => (string)ImageLibrary.Call("GetImage", shortname, skin);
        private string GetImageURL(string shortname, ulong skin = 0) => (string)ImageLibrary.Call("GetImageURL", shortname, skin);
        private bool AddImage(string url, string shortname, ulong skin = 0) => (bool)ImageLibrary.Call("AddImage", url, shortname, skin);
        private bool HasImage(string shortname, ulong skin = 0) => (bool)ImageLibrary.Call("HasImage", shortname, skin);
        private bool IsReady() => (bool)ImageLibrary.Call("IsReady");
#endregion
#region Chat Commands
        [ChatCommand("skin")]
        private void cmdSkin(BasePlayer player, string command, string[] args) {
            if (!userData.ContainsKey(player.userID)) userData.Add(player.userID, new UserData());
            if (args.Length == 0) {
                if (!HasPermission(player, "reskin")) {
                    SendReply(player, "You do not have permission to use this command");
                    return;
                }
                if (configData.Shop.GiveItemOnPurchase) return;
                if (configData.Reskin.DisableCommand) {
                    SendReply(player, "You can only access the re-skin menu via a re-skin NPC");
                    return;
                }
                CreateReskinMenu(player);
            }
            else {
                if (args[0].ToLower() != "shop") {
                    SendReply(player, "/skin - Open the re-skin menu");
                    SendReply(player, "/skin shop - Open the skin shop");
                    return;
                }
                if (!HasPermission(player, "shop")) {
                    SendReply(player, "You do not have permission to use this command");
                    return;
                }
                if (configData.Shop.DisableCommand) {
                    SendReply(player, "You can only access the skin shop menu via a skin shop NPC");
                    return;
                }
                OpenSkinMenu(player, string.Empty, 0, 0);
            }
        }
#endregion
#region Console Commands
        [ConsoleCommand("playerskins.skins")]
        private void ccmdSkinManager(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) {
                if (arg.Connection.authLevel < 2) {
                    SendReply(arg, "You do not have permission to use this command");
                    return;
                }
            }
            if (arg.Args == null || arg.Args.Length < 3) {
                SendReply(arg, "playerskins.skins import <item shortname> <skin ID> - Import the specified workshop skin");
                SendReply(arg, "playerskins.skins import random <amount> - Import the specified amount of random skins for random items");
                SendReply(arg, "playerskins.skins import random <item shortname> <amount> - Import the specified amount of random skins for the specified item");
                SendReply(arg, "playerskins.skins remove <item shortname> <skin ID> - Remove the specified skin from the skin shop");
                return;
            }
            if (!configData.Workshop.Enabled) {
                SendReply(arg, "You have workshop disabled in your config.The playerskins.skins commands are unavailable when workshop is disabled");
                return;
            }
            if (!workshopInitialized) {
                SendReply(arg, "Workshop initialization has not yet finished.The playerskins.skins commands are unavailable until that process is complete");
                return;
            }
            switch (arg.GetString(0).ToLower()) {
                case "import" : if (arg.Args[1].ToLower() == "random") {
                    if (arg.Args.Length == 4) {
                        string shortname = arg.GetString(2).ToLower();
                        if (!ItemManager.itemList.Select(x => x.shortname).Contains(shortname) || !workshopItems.ContainsKey(shortname)) {
                            SendReply(arg, "The item shortname you have entered either does not have any skins, or is invalid");
                            return;
                        }
                        int amount;
                        if (!int.TryParse(arg.GetString(3), out amount)) {
                            SendReply(arg, "You must enter an amount of random skins to import");
                            return;
                        }
                        Dictionary<string, Dictionary<ulong, string>> loadOrder = new Dictionary<string, Dictionary<ulong, string>>();
                        int skinCount = 0;
                        int loadOrderCount = 0;
                        int actualCount = 0;
                        List<KeyValuePair<ulong, WorkshopItem>> newList = new List<KeyValuePair<ulong, WorkshopItem>>(workshopItems[shortname].ToList());
                        for (int i = 0; i < amount; i++) {
                            if (newList.Count == 0) break;
                            var skinInfo = newList.GetRandom();
                            newList.Remove(skinInfo);
                            if (skinInfo.Value == null || (skinData.ContainsKey(shortname) && skinData[shortname].ContainsKey(skinInfo.Key)) || string.IsNullOrEmpty(skinInfo.Value.imageUrl)) {
                                i--;
                                continue;
                            }
                            actualCount++;
                            if (!skinData.ContainsKey(shortname)) skinData.Add(shortname, new Dictionary<ulong, SkinData>());
                            skinData[shortname].Add(skinInfo.Key, new SkinData());
                            if (!HasImage(shortname, skinInfo.Key)) {
                                if (!loadOrder.ContainsKey(shortname)) loadOrder.Add(shortname, new Dictionary<ulong, string>());
                                if (!loadOrder[shortname].ContainsKey(skinInfo.Key)) {
                                    loadOrder[shortname].Add(skinInfo.Key, skinInfo.Value.imageUrl);
                                    skinCount++;
                                }
                            }
                            if (skinCount >= 500) {
                                loadOrderCount++;
                                Puts($"Creating a skin load order (Order #{loadOrderCount})");
                                ImageLibrary.Call("ImportItemList", $"{Title} skin icons (Order #{loadOrderCount})", loadOrder);
                                loadOrder = new Dictionary<string, Dictionary<ulong, string>>();
                                skinCount = 0;
                            }
                        }
                        if (skinCount > 0) {
                            loadOrderCount++;
                            Puts($"Creating a skin load order (Order #{loadOrderCount})");
                            ImageLibrary.Call("ImportItemList", $"{Title} skin icons (Order #{loadOrderCount})", loadOrder);
                        }
                        SendReply(arg, $"Importing {actualCount} random {shortname} workshop skins to ImageLibrary");
                        SaveSkinData();
                    }
                    else {
                        int amount;
                        if (!int.TryParse(arg.GetString(2), out amount)) {
                            SendReply(arg, "You must enter an amount of random skins to import");
                            return;
                        }
                        Dictionary<string, Dictionary<ulong, string>> loadOrder = new Dictionary<string, Dictionary<ulong, string>>();
                        int skinCount = 0;
                        int loadOrderCount = 0;
                        Dictionary<string, Dictionary<ulong, WorkshopItem>> newList = new Dictionary<string, Dictionary<ulong, WorkshopItem>>(workshopItems);
                        for (int i = 0; i < amount; i++) {
                            if (newList.Count == 0) break;
                            string shortname = newList.Keys.ToArray().GetRandom();
                            var skinInfo = newList[shortname].ToArray().GetRandom();
                            if (skinInfo.Value == null || (skinData.ContainsKey(shortname) && skinData[shortname].ContainsKey(skinInfo.Key)) || string.IsNullOrEmpty(skinInfo.Value.imageUrl)) {
                                i--;
                                continue;
                            }
                            if (!skinData.ContainsKey(shortname)) skinData.Add(shortname, new Dictionary<ulong, SkinData>());
                            skinData[shortname].Add(skinInfo.Key, new SkinData());
                            if (!HasImage(shortname, skinInfo.Key)) {
                                if (!loadOrder.ContainsKey(shortname)) loadOrder.Add(shortname, new Dictionary<ulong, string>());
                                if (!loadOrder[shortname].ContainsKey(skinInfo.Key)) {
                                    loadOrder[shortname].Add(skinInfo.Key, skinInfo.Value.imageUrl);
                                    skinCount++;
                                }
                            }
                            if (skinCount >= 500) {
                                loadOrderCount++;
                                Puts($"Creating a skin load order (Order #{loadOrderCount})");
                                ImageLibrary.Call("ImportItemList", $"{Title} skin icons (Order #{loadOrderCount})", loadOrder);
                                loadOrder = new Dictionary<string, Dictionary<ulong, string>>();
                                skinCount = 0;
                            }
                        }
                        if (skinCount > 0) {
                            loadOrderCount++;
                            Puts($"Creating a skin load order (Order #{loadOrderCount})");
                            ImageLibrary.Call("ImportItemList", $"{Title} skin icons (Order #{loadOrderCount})", loadOrder);
                        }
                        SendReply(arg, $"Importing {amount} random workshop skins to ImageLibrary");
                        SaveSkinData();
                    }
                }
                else {
                    string shortname = arg.GetString(1).ToLower();
                    if (!ItemManager.itemList.Select(x => x.shortname).Contains(shortname) || !workshopItems.ContainsKey(shortname)) {
                        SendReply(arg, "The item shortname you have entered either does not have any skins, or is invalid");
                        return;
                    }
                    ulong skinId = 0U;
                    if (!ulong.TryParse(arg.GetString(2), out skinId) || !workshopItems[shortname].ContainsKey(skinId)) {
                        SendReply(arg, "The skin ID you have entered is either invalid or there is no skin with that ID");
                        return;
                    }
                    WorkshopItem workshopItem = workshopItems[shortname][skinId];
                    if (workshopItem == null || string.IsNullOrEmpty(workshopItem.imageUrl)) {
                        SendReply(arg, "The specified workshop skin can not be imported");
                        return;
                    }
                    if (!skinData.ContainsKey(shortname)) skinData.Add(shortname, new Dictionary<ulong, SkinData>());
                    if (!skinData[shortname].ContainsKey(skinId)) skinData[shortname].Add(skinId, new SkinData());
                    if (!HasImage(shortname, skinId)) {
                        Dictionary<string, Dictionary<ulong, string>> loadOrder = new Dictionary<string, Dictionary<ulong, string>> {
                            [shortname]
                            = new Dictionary<ulong, string> {
                                [skinId]
                                = workshopItem.imageUrl
                            }
                        }
                        ;
                        ImageLibrary.Call("ImportItemList", $"{Title} - {shortname} {skinId}", loadOrder);
                    }
                    SendReply(arg, $"Importing skin ID {skinId} for {shortname} to ImageLibrary!");
                    SaveSkinData();
                }
                return;
                case "remove" : {
                    string shortname = arg.GetString(1).ToLower();
                    if (!ItemManager.itemList.Select(x => x.shortname).Contains(shortname) || !skinData.ContainsKey(shortname)) {
                        SendReply(arg, "The item shortname you have entered either does not have any available skins, or is invalid");
                        return;
                    }
                    ulong skinId = 0U;
                    if (!ulong.TryParse(arg.GetString(2), out skinId) || !skinData[shortname].ContainsKey(skinId)) {
                        SendReply(arg, "The skin ID you have entered is either invalid or has not been added to the list of available skins");
                        return;
                    }
                    skinData[shortname][skinId].isDisabled = true;
                    ImageLibrary.Call("RemoveImage", shortname, skinId);
                    SendReply(arg, $"You have removed skin ID {skinId} for {shortname}!");
                    SaveSkinData();
                }
                return;
                default : SendReply(arg, "Invalid syntax!");
                break;
            }
        }
        [ConsoleCommand("playerskins.setprice")]
        private void ccmdSetSkinPrice(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) {
                if (arg.Connection.authLevel < 2) {
                    SendReply(arg, "You do not have permission to use this command");
                    return;
                }
            }
            if (arg.Args == null || arg.Args.Length != 2) {
                SendReply(arg, "playerskins.setprice <item shortname> <amount> - Set the price for all skins for the specified item");
                SendReply(arg, "playerskins.setprice all <amount> - Set the price for all skins for all items");
                return;
            }
            int amount = 0;
            if (!int.TryParse(arg.GetString(1), out amount)) {
                SendReply(arg, "You must enter a number to set the price");
                return;
            }
            string shortname = arg.GetString(0);
            if (shortname.ToLower() == "all") {
                foreach (var item in skinData.Values) {
                    foreach (var skin in item.Values) skin.cost = amount;
                }
                SendReply(arg, $"You have set all skin costs to {amount}");
            }
            else {
                Dictionary<ulong, SkinData> data;
                if (!skinData.TryGetValue(shortname, out data)) {
                    SendReply(arg, $"Either an invalid shortname was entered, or there are no skins for the specified item : {shortname}");
                    return;
                }
                foreach (var skin in data.Values) skin.cost = amount;
                SendReply(arg, $"You have set all {shortname} skin costs to {amount}");
            }
            SaveSkinData();
        }
#endregion
#region UI Helper
        const string MainPanel = "PSMainPanel";
        const string SelectPanel = "PSSelectionPanel";
        const string PopupPanel = "PSPopupPanel";
        const string ReskinPanel = "PSReskinP
// ... [Code preview truncated due to length. Full source in attached file] ...

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