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

FREE ServerRewards : 2.0.9 2.0.9

Нет прав для скачивания
C#:
using Facepunch;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Game.Rust.Cui;
using Oxide.Core.Plugins;
using UnityEngine;
using Oxide.Game.Rust.Libraries;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine.UI;
namespace Oxide.Plugins;
[Info("Server Rewards", "k1lly0u", "2.0.9")]
class ServerRewards : RustPlugin {
#region Fields
    [PluginReference]
    private Plugin Economics, HumanNPC, ImageLibrary, Kits, PlayerDLCAPI, PlaytimeTracker;
    private List<ItemDefinition> _sortedItemDefinitions;
    private readonly StringBuilder _stringBuilder = new StringBuilder();
    private static Func<string, string, string> _getMessage;
    private const string ADMIN_PERMISSION = "serverrewards.admin";
#endregion
#region Oxide Hooks
    private void Loaded() {
        LoadData();
        CreateCommonFilters();
        _getMessage = (key, userId) => lang.GetMessage(key, this, userId);
        permission.RegisterPermission(ADMIN_PERMISSION, this);
        _products.Data.RegisterPermissions(permission, this);
        Command command = Interface.Oxide.GetLibrary<Command>();
        command.AddChatCommand(Configuration.Options.StoreCommand, this, ChatOpenMenu);
        command.AddChatCommand(Configuration.Options.RPCommand, this, ChatPointsManagement);
        command.AddConsoleCommand(Configuration.Options.RPCommand, this, ConsolePointsManagement);
    }
    protected override void LoadDefaultMessages() => lang.RegisterMessages(_messages, this);
    private void OnServerInitialized() {
        CreateValidItemList();
        UpdateSellPriceList();
        RegisterImages();
        CreateKitsFunctions();
        if (!Configuration.Options.OwnedSkins) Debug.LogWarning("[ServerRewards] WARNING! As of August 7th 2025, granting access to paid skins that users do not own is against Rust's Terms of Service and can result in your server being delisted or worse.\n" + "If you continue to allow users to use paid skins, you do so at your own risk!\n" + "You can prevent users access to skins they do not own by enabling 'Only show/give players skins that they are allowed to use' in the config\n" + "https://facepunch.com/legal/servers");
        else if (!PlayerDLCAPI) Debug.LogWarning("[ServerRewards] - PlayerDLCAPI plugin is not loaded, skin ownership checks will not work!");
        foreach (BasePlayer player in BasePlayer.activePlayerList) SendPointNotification(player);
    }
    private void OnPlayerConnected(BasePlayer player) => SendPointNotification(player);
    private void OnServerSave() {
        _balances.Save();
        _cooldowns.Save();
    }
    private void Unload() {
        _balances.Save();
        _cooldowns.Save();
        UIUser.OnUnload();
    }
#endregion
#region Functions
    private readonly string[] _ignoreItems = new string[] {
        "ammo.snowballgun", "blueprintbase", "rhib", "attackhelicopter", "motorbike", "motorbike_sidecar", "bicycle", "trike", "kayak", "rowboat", "tugboat", "skidoo", "minihelicopter.repair", "scraptransportheli.repair", "mlrs", "snowmobile", "spraycandecal", "vehicle.chassis", "vehicle.module", "water", "water.salt"
    }
    ;
    private void CreateValidItemList() {
        _sortedItemDefinitions ??= new List<ItemDefinition>(ItemManager.itemList.Count);
        foreach (ItemDefinition itemDefinition in ItemManager.itemList) {
            if (_ignoreItems.Contains(itemDefinition.shortname)) continue;
            _sortedItemDefinitions.Add(itemDefinition);
        }
        _sortedItemDefinitions.Sort((a, b) => {
            if (string.IsNullOrEmpty(a.displayName.english) && string.IsNullOrEmpty(b.displayName.english)) return 0;
            if (string.IsNullOrEmpty(a.displayName.english)) return 1;
            if (string.IsNullOrEmpty(b.displayName.english)) return -1;
            return a.displayName.english.CompareTo(b.displayName.english);
        }
        );
    }
    private void SendPointNotification(BasePlayer player) {
        if (!player) return;
        if (!_balances.Data.TryGetValue(player.userID, out int balance) || balance <= 0) return;
        _stringBuilder.Clear();
        _stringBuilder.AppendLine(_getMessage("Message.Title", player.UserIDString));
        _stringBuilder.AppendLine(string.Format(_getMessage("Message.Notification.Unspent", player.UserIDString), balance));
        _stringBuilder.AppendLine(Configuration.Options.NpcOnly ? _getMessage("Message.Notification.Unspent.NPC", player.UserIDString) : string.Format(_getMessage("Message.Notification.Unspent.Command", player.UserIDString), Configuration.Options.StoreCommand));
        player.ChatMessage(_stringBuilder.ToString());
    }
    private static double CurrentTime() => DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds;
    private bool IsAdmin(BasePlayer player) => permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION) || (player.net?.connection != null && player.net.connection.authLevel >= 2);
    private bool IsAdminOrConsole(ConsoleSystem.Arg arg) {
        if (arg.Connection == null) return true;
        BasePlayer player = arg.Player();
        if (!player) return false;
        return IsAdmin(player);
    }
#endregion
#region Chat Commands
    private bool OpenBlockedByPlugin(BasePlayer player) {
        object success = Interface.Call("canShop", player);
        if (success == null) return false;
        string message = success as string ?? _getMessage("Message.ShopBlockedByPlugin", player.UserIDString);
        player.ChatMessage(message);
        return true;
    }
    private void ChatOpenMenu(BasePlayer player, string command, string[] args) {
        if (Configuration.Options.NpcOnly && !IsAdmin(player)) return;
        if (OpenBlockedByPlugin(player)) return;
        OpenStore(player);
    }
#endregion
#region Admin Commands
    private void ChatPointsManagement(BasePlayer player, string command, string[] args) {
        if (!IsAdmin(player)) return;
        if (args.Length >= 2) {
            bool isWildcard = args[1] == "*";
            IPlayer target = isWildcard ? null : covalence.Players.FindPlayer(args[1]);
            ulong targetID = target != null && ulong.TryParse(target.Id, out ulong u) ? u : 0UL;
            int amount = args.Length == 3 && int.TryParse(args[2], out int a) ? a : 0;
            if (!isWildcard) {
                if (target == null) {
                    player.ChatMessage("Player not found, please specify a valid username or user ID.");
                    return;
                }
                if (targetID == 0UL) {
                    player.ChatMessage("Player was found, but they have a invalid user ID.");
                    return;
                }
            }
            switch (args[0].ToLower()) {
                case "add" : player.ChatMessage(CommandAddPoints(isWildcard, target, targetID, amount));
                return;
                case "take" : player.ChatMessage(CommandTakePoints(isWildcard, target, targetID, amount));
                return;
                case "clear" : player.ChatMessage(CommandClearPoints(isWildcard, target, targetID));
                return;
                case "check" : if (isWildcard) {
                    player.ChatMessage("You can not check RP using the '*' wildcard, please specify a valid username or user ID.");
                    return;
                }
                player.ChatMessage(CommandCheckPoints(target, targetID));
                return;
                default : break;
            }
        }
        string hex = Configuration.UI.ButtonConfirmText.Hex;
        string cmd = Configuration.Options.RPCommand;
        player.ChatMessage($"<size=16><color=#{hex}>[{Title}]</color> Points Management</size>");
        player.ChatMessage($"<color=#{hex}>/{cmd} add <username|userid|*> <amount></color> - Add the specified amount of RP to a player");
        player.ChatMessage($"<color=#{hex}>/{cmd} take <username|userid|*> <amount></color> - Deduct the specified amount of RP from a player");
        player.ChatMessage($"<color=#{hex}>/{cmd} clear <username|userid|*></color> - Reset the specified players RP to 0");
        player.ChatMessage($"<color=#{hex}>/{cmd} check <username|userid></color> - Show the amount of RP a player has");
        player.ChatMessage($"Use the '<color=#{hex}>*</color>' wildcard in place of name or id to apply the command to all players.");
    }
    private bool ConsolePointsManagement(ConsoleSystem.Arg arg) {
        if (!IsAdminOrConsole(arg)) return false;
        if (arg.Args is {
            Length : >= 2
        }
        ) {
            bool isWildcard = arg.Args[1] == "*";
            IPlayer target = isWildcard ? null : covalence.Players.FindPlayer(arg.GetString(1));
            ulong targetID = target != null && ulong.TryParse(target.Id, out ulong u) ? u : 0UL;
            int amount = arg.Args.Length == 3 && int.TryParse(arg.GetString(2), out int a) ? a : 0;
            if (!isWildcard) {
                if (target == null) {
                    SendReply(arg, "Player not found, please specify a valid username or user ID.");
                    return true;
                }
                if (targetID == 0UL) {
                    SendReply(arg, "Player was found, but they have a invalid user ID.");
                    return true;
                }
            }
            switch (arg.GetString(0).ToLower()) {
                case "add" : SendReply(arg, CommandAddPoints(isWildcard, target, targetID, amount));
                return true;
                case "take" : SendReply(arg, CommandTakePoints(isWildcard, target, targetID, amount));
                return true;
                case "clear" : SendReply(arg, CommandClearPoints(isWildcard, target, targetID));
                return true;
                case "check" : if (isWildcard) {
                    SendReply(arg, "You can not check RP using the '*' wildcard, please specify a valid username or user ID.");
                    return true;
                }
                SendReply(arg, CommandCheckPoints(target, targetID));
                return true;
                default : break;
            }
        }
        SendReply(arg, $"{Configuration.Options.RPCommand} add <username|userid|*> <amount> - Add the specified amount of RP to a player");
        SendReply(arg, $"{Configuration.Options.RPCommand} take <username|userid|*> <amount> - Deduct the specified amount of RP from a player");
        SendReply(arg, $"{Configuration.Options.RPCommand} clear <username|userid|*> - Reset the specified players RP to 0");
        SendReply(arg, $"{Configuration.Options.RPCommand} check <username|userid> - Show the amount of RP a player has");
        SendReply(arg, "Use the '*' wildcard in place of name or id to apply the command to all players.");
        return true;
    }
    private string CommandAddPoints(bool isWildcard, IPlayer target, ulong targetID, int amount) {
        if (amount <= 0) return "Please specify a valid amount to add. Must be greater than 0.";
        if (isWildcard) {
            List<ulong> userIDs = Pool.Get<List<ulong>>();
            userIDs.AddRange(_balances.Data.Keys);
            foreach (ulong userID in userIDs) {
                _balances.Data[userID] += amount;
                SendPointsUpdated(userID);
            }
            Pool.FreeUnmanaged(ref userIDs);
            return $"You have added {amount}RP to every player!";
        }
        if (!_balances.Data.ContainsKey(targetID)) _balances.Data[targetID] = amount;
        else _balances.Data[targetID] += amount;
        SendPointsUpdated(targetID);
        return $"You have added {amount}RP to {target.Name} ({target.Id})!";
    }
    private string CommandTakePoints(bool isWildcard, IPlayer target, ulong targetID, int amount) {
        if (amount <= 0) return "Please specify a valid amount to add. Must be greater than 0.";
        if (isWildcard) {
            List<ulong> userIDs = Pool.Get<List<ulong>>();
            userIDs.AddRange(_balances.Data.Keys);
            foreach (ulong userID in userIDs) {
                _balances.Data[userID] = Mathf.Max(_balances.Data[userID] - amount, 0);
                SendPointsUpdated(userID);
            }
            Pool.FreeUnmanaged(ref userIDs);
            return $"You have deducted {amount}RP from every player!";
        }
        if (!_balances.Data.ContainsKey(targetID)) return $"Player {target.Name} ({target.Id}) does not have any RP to deduct from!";
        _balances.Data[targetID] = Mathf.Max(_balances.Data[targetID] - amount, 0);
        SendPointsUpdated(targetID);
        return $"You have deducted {amount}RP from {target.Name} ({target.Id})!";
    }
    private string CommandClearPoints(bool isWildcard, IPlayer target, ulong targetID) {
        if (isWildcard) {
            List<ulong> userIDs = Pool.Get<List<ulong>>();
            userIDs.AddRange(_balances.Data.Keys);
            foreach (ulong userID in userIDs) {
                _balances.Data[userID] = 0;
                SendPointsUpdated(userID);
            }
            Pool.FreeUnmanaged(ref userIDs);
            return "You have reset every players RP to 0!";
        }
        if (!_balances.Data.ContainsKey(targetID)) return $"Player {target.Name} ({target.Id}) does not have any RP!";
        _balances.Data[targetID] = 0;
        SendPointsUpdated(targetID);
        return $"You have reset {target.Name}'s ({target.Id}) RP to 0!";
    }
    private string CommandCheckPoints(IPlayer target, ulong targetID) => !_balances.Data.TryGetValue(targetID, out int balance) ? $"Player {target.Name} ({target.Id}) does not have any RP!" : $"{target.Name} ({target.Id}) has {balance}RP!";
#endregion
#region Image Library
    private const string MagnifyIconUrl = "https://files.rusthq.com/images/magnifyingglass.png";
    private const string SearchIconIdentifier = "srui.search";
    private static string _magnifyIcon;
    private static string _dataDirectory;
    private void RegisterImages() {
        if (!ImageLibrary) {
            Debug.LogWarning("[ServerRewards] ImageLibrary plugin not found, custom images will not be loaded...");
            return;
        }
        Dictionary<string, string> loadOrder = new Dictionary<string, string>();
        _dataDirectory = Path.Combine($"file://{Interface.Oxide.DataDirectory}", "ServerRewards", "Images");
        loadOrder[SearchIconIdentifier] = MagnifyIconUrl;
        foreach (Products.Item item in _products.Data.Items) {
            if (string.IsNullOrEmpty(item.IconURL)) continue;
            string url = item.IconURL;
            if (!IsUrl(url)) url = Path.Combine(_dataDirectory, url);
            loadOrder[item.IconURL] = url;
        }
        foreach (Products.Kit kit in _products.Data.Kits) {
            if (string.IsNullOrEmpty(kit.IconURL)) continue;
            string url = kit.IconURL;
            if (!IsUrl(url)) url = Path.Combine(_dataDirectory, url);
            loadOrder[kit.IconURL] = url;
        }
        foreach (Products.Command command in _products.Data.Commands) {
            if (string.IsNullOrEmpty(command.IconURL)) continue;
            string url = command.IconURL;
            if (!IsUrl(url)) url = Path.Combine(_dataDirectory, url);
            loadOrder[command.IconURL] = url;
        }
        ImageLibrary.Call("ImportImageList", Title, loadOrder, 0UL, false, new Action(OnImagesLoaded));
    }
    private void OnImagesLoaded() => _magnifyIcon = GetImage(SearchIconIdentifier);
    private void AddImage(string iconUrl) {
        string url = iconUrl;
        if (!IsUrl(url)) url = Path.Combine(_dataDirectory, url);
        ImageLibrary?.Call("AddImage", url, iconUrl, 0UL);
    }
    private string GetImage(string name, ulong skinID = 0UL) {
        if (!ImageLibrary) return string.Empty;
        return ImageLibrary.Call<string>("GetImage", name, skinID);
    }
    private static bool IsUrl(string input) => Uri.TryCreate(input, UriKind.Absolute, out Uri result) && (result.Scheme == Uri.UriSchemeHttp || result.Scheme == Uri.UriSchemeHttps);
#endregion
#region Kits
    private static Func<string, bool> _isKit;
    private static Func<BasePlayer, string, object> _giveKit;
    private static Func<string, string> _getKitDescription;
    private static Func<string, string> _getKitImage;
    private static Func<string, JObject> _getKitData;
    private void CreateKitsFunctions() {
        _isKit = IsKit;
        _giveKit = GiveKit;
        _getKitDescription = GetKitDescription;
        _getKitImage = GetKitImage;
        _getKitData = GetKitObject;
    }
    private object GiveKit(BasePlayer player, string kit) => Kits?.Call("GiveKit", player, kit);
    private void GetAllKits(List<string> list) => Kits?.Call("GetAllKits", list);
    private bool IsKit(string name) => Kits && Kits.Call<bool>("IsKit", name);
    private string GetKitDescription(string name) => Kits ? Kits.Call<string>("GetKitDescription", name) : string.Empty;
    private string GetKitImage(string name) => Kits ? Kits.Call<string>("GetKitImage", name) : string.Empty;
    private JObject GetKitObject(string name) => Kits ? Kits.Call<JObject>("GetKitObject", name) : null;
    private class KitData {
        public ItemData[] MainItems {
            get;
            set;
        }
        public ItemData[] WearItems {
            get;
            set;
        }
        public ItemData[] BeltItems {
            get;
            set;
        }
        public class ItemData {
            public string Shortname {
                get;
                set;
            }
            public ulong SkinID {
                get;
                set;
            }
            public int Amount {
                get;
                set;
            }
            public bool IsBlueprint {
                get;
                set;
            }
            [JsonIgnore]
            private ItemDefinition _itemDefinition;
            [JsonIgnore]
            public ItemDefinition ItemDefinition {
                get {
                    if (!_itemDefinition) _itemDefinition = ItemManager.FindItemDefinition(Shortname);
                    return _itemDefinition;
                }
            }
        }
    }
#endregion
#region PlayerDLCAPI
    private bool IsOwnedOrFreeItem(BasePlayer player, int itemID, ulong skinID) {
        if (PlayerDLCAPI != null && Configuration.Options.OwnedSkins) return PlayerDLCAPI.Call<bool>("IsOwnedOrFreeItem", player, itemID, skinID);
        return true;
    }
    private bool CanUseSkin(BasePlayer player, ulong skinID) {
        if (skinID == 0UL) return true;
        if (PlayerDLCAPI != null && Configuration.Options.OwnedSkins) return PlayerDLCAPI.Call<bool>("IsOwnedOrFreeSkin", player, skinID);
        return true;
    }
    private int GetRedirectedItemIdIfNotOwned(BasePlayer player, int itemId) {
        if (PlayerDLCAPI != null && Configuration.Options.OwnedSkins) return PlayerDLCAPI.Call<int>("GetRedirectedItemIdIfNotOwned", player, itemId);
        return itemId;
    }
#endregion
#region HumanNPC
    private void OnUseNPC(BasePlayer npc, BasePlayer player) {
        if (!player || !npc) return;
        if (!_npcStores.Data.TryGetValue(npc.userID, out NpcStore npcStore)) return;
        if (OpenBlockedByPlugin(player)) return;
        if (npcStore.Products != null) {
            UIUser user = UIUser.Get(player);
            user.NpcStore = npcStore;
        }
        OpenStore(player);
    }
    [ChatCommand("srnpc")]
    private void CommandNpc(BasePlayer player, string command, string[] args) {
        if (!IsAdmin(player)) return;
        if (!HumanNPC) {
            player.ChatMessage("HumanNPC plugin not found, please install it to use this command.");
            return;
        }
        string hex = Configuration.UI.ButtonConfirmText.Hex;
        if (args.Length >= 1) {
            BasePlayer target = FindPlayer(player);
            if (!target) {
                player.ChatMessage("Look at the HumanNPC you want to interact with.");
                return;
            }
            if (!HumanNPC.Call<bool>("IsHumanNpc", target.userID.Get())) {
                player.ChatMessage("The player you are looking at it not a HumanNPC.");
                return;
            }
            _npcStores.Data.TryGetValue(target.userID, out NpcStore npcStore);
            switch (args[0].ToLower()) {
                case "add" : if (npcStore != null) {
                    player.ChatMessage("The NPC you are looking at is already a store NPC.");
                    return;
                }
                _npcStores.Data[target.userID] = new NpcStore {
                    Products = new Products(), Navigation = new StoreNavigation(Configuration.Navigation), CustomStore = false
                }
                ;
                _npcStores.Save();
                player.ChatMessage($"You have turned the NPC <color=#{hex}>{target.displayName}</color> into a store NPC.");
                return;
                case "remove" : if (npcStore == null) {
                    player.ChatMessage("The NPC you are looking at is not a store NPC.");
                    return;
                }
                _npcStores.Data.Remove(target.userID);
                _npcStores.Save();
                player.ChatMessage($"You have removed the store from NPC <color=#{hex}>{target.displayName}</color>.");
                return;
                case "setname" : if (npcStore == null) {
                    player.ChatMessage("The NPC you are looking at is not a store NPC.");
                    return;
                }
                if (args.Length < 2) {
                    player.ChatMessage("Please specify a store name");
                    return;
                }
                string name = string.Join(" ", args.Skip(1));
                if (string.IsNullOrEmpty(name)) {
                    player.ChatMessage("Store name can not be empty.");
                    return;
                }
                npcStore.Name = name;
                _npcStores.Save();
                player.ChatMessage($"You have set the store name for NPC <color=#{hex}>{target.displayName}</color> to <color=#{hex}>{name}</color>.");
                return;
                case "nav" : if (npcStore == null) {
                    player.ChatMessage("The NPC you are looking at is not a store NPC.");
                    return;
                }
                if (args.Length < 2) {
                    player.ChatMessage($"Please specify a navigation type to toggle. Valid types: items, kits, commands, exchange, transfer, sell");
                    return;
                }
                if (!Enum.TryParse(args[1].ToLower(), true, out NavigationCategory category)) {
                    player.ChatMessage($"Invalid navigation type '{args[1]}'. Valid types: items, kits, commands, exchange, transfer, sell");
                    return;
                }
                bool result = false;
                switch (category) {
                    case NavigationCategory.Kits : result = npcStore.Navigation.Kits = !npcStore.Navigation.Kits;
                    break;
                    case NavigationCategory.Commands : result = npcStore.Navigation.Commands = !npcStore.Navigation.Commands;
                    break;
                    case NavigationCategory.Items : result = npcStore.Navigation.Items = !npcStore.Navigation.Items;
                    break;
                    case NavigationCategory.Exchange : result = npcStore.Navigation.Exchange = !npcStore.Navigation.Exchange;
                    break;
                    case NavigationCategory.Transfer : result = npcStore.Navigation.Transfer = !npcStore.Navigation.Transfer;
                    break;
                    case NavigationCategory.Sell : result = npcStore.Navigation.Seller = !npcStore.Navigation.Seller;
                    break;
                    default : player.ChatMessage("Invalid navigation type. Valid types: items, kits, commands, exchange, transfer, sell");
                    break;
                }
                _npcStores.Save();
                player.ChatMessage($"Navigation type <color=#{hex}>{category}</color> for NPC <color=#{hex}>{target.displayName}</color> is now <color=#{hex}>{(result ? "enabled" : "disabled")}</color>.");
                return;
                case "customstore" : if (npcStore == null) {
                    player.ChatMessage("The NPC you are looking at is not a store NPC.");
                    return;
                }
                npcStore.CustomStore = !npcStore.CustomStore;
                _npcStores.Save();
                player.ChatMessage($"Custom store mode for NPC <color=#{hex}>{target.displayName}</color> is now <color=#{hex}>{(npcStore.CustomStore ? "enabled" : "disabled")}</color>.");
                return;
                default : break;
            }
        }
        player.ChatMessage($"<size=16><color=#{hex}>[{Title}]</color> NPC Stores</size>");
        player.ChatMessage($"<color=#{hex}>/srnpc add</color> - Turn the NPC you are looking at into a store NPC");
        player.ChatMessage($"<color=#{hex}>/srnpc remove</color> - Remove the store from the NPC you are looking at");
        player.ChatMessage($"<color=#{hex}>/srnpc setname <name></color> - Sets a store name for the NPC you are looking at. This name is shown on the store page if custom store is enabled");
        player.ChatMessage($"<color=#{hex}>/srnpc nav <items|kits|commands|exchange|transfer|sell></color> - Toggles whether the specified navigation type is shown in the NPC store");
        player.ChatMessage($"<color=#{hex}>/srnpc customstore</color> - Toggles whether this NPC runs a custom store or just opens the global store");
    }
    private BasePlayer FindPlayer(BasePlayer player) {
        if (Physics.Raycast(player.eyes.HeadRay(), out RaycastHit raycastHit, 10f, 1 << (int)Rust.Layer.Player_Server)) return raycastHit.collider.ToBaseEntity() as BasePlayer;
        return null;
    }
#endregion
#region UI
    private const string UI_MENU = "sr.menu";
    private const string UI_TOAST = "sr.toast";
    private void OpenStore(BasePlayer player) {
        UIUser user = UIUser.Get(player);
        Products products = user.NpcStore is {
            CustomStore : true
        }
        ? user.NpcStore.Products : _products.Data;
        StoreNavigation navigation = user.NpcStore != null ? user.NpcStore.Navigation : Configuration.Navigation;
        user.UpdateAvailableCategories(navigation, products, Economics);
        if (user.NpcStore != null && user.Category == NavigationCategory.None) {
            List<NavigationCategory> categories = user.AvailableCategories;
            if (categories.Count == 0) {
                user.Player.ChatMessage(user.Translate("Message.Error.NoCategories"));
                user.CloseMenu();
                return;
            }
            if (!categories.Contains(NavigationCategory.Items) && !categories.Contains(NavigationCategory.Kits) && !categories.Contains(NavigationCategory.Commands) && !categories.Contains(NavigationCategory.Sell)) {
                if (categories.Contains(NavigationCategory.Transfer)) {
                    user.ExitToGame = true;
                    CreateTransferMenu(user);
                    return;
                }
                if (categories.Contains(NavigationCategory.Exchange)) {
                    user.ExitToGame = true;
                    CreateExchangeMenu(user);
                    return;
                }
            }
        }
        CuiElementContainer container = UI.Container(Layer.Overlay, UI_MENU, Configuration.UI.Background, Anchor.FullStretch, Offset.zero);
        CreateHeader(container, user);
        switch (user.Category) {
            case NavigationCategory.Kits : CreateKits(container, user);
            break;
            case NavigationCategory.Commands : CreateCommands(container, user);
            break;
            case NavigationCategory.Items : CreateItems(container, user);
            break;
            case NavigationCategory.Sell : CreateSellItems(container, user);
            break;
            default : break;
        }
        CreateFooter(container, user);
        user.SendUI(container);
    }
    private void CreateHeader(CuiElementContainer container, UIUser user) {
        string storeName = user.NpcStore is {
            CustomStore : true
        }
        && !string.IsNullOrEmpty(user.NpcStore.Name) ? user.NpcStore.Name : user.Translate("UI.Title");
        const string UI_HEADER = "sr.header";
        UI.Panel(container, UI_MENU, Configuration.UI.PanelPrimary, Anchor.TopStretch, new Offset(5f, -35f, -5f, -5f), UI_HEADER);
        UI.Text(container, UI_HEADER, storeName, Anchor.FullStretch, new Offset(5f, 0f, -5f, 0f), align : TextAnchor.MiddleLeft, size : 18);
        CreateNavigation(container, user, UI_HEADER);
        if (user.Category <= NavigationCategory.Items) {
            if (!string.IsNullOrEmpty(_magnifyIcon)) UI.PNG(container, UI_HEADER, _magnifyIcon, Anchor.CenterRight, new Offset(-225f, -10f, -205f, 10f));
            const string UI_INPUT = "sr.search";
            UI.Panel(container, UI_HEADER, Configuration.UI.PanelSecondary, Anchor.CenterRight, new Offset(-200f, -10f, -30f, 10f), UI_INPUT);
            UI.Input(container, UI_INPUT, user.SearchFilter, $"{Commands.Search} {(int)ReturnType.Store}", Anchor.FullStretch, new Offset(5f, 0f, -5f, 0f));
        }
        const string BUTTON_CLOSE = "sr.close";
        UI.Panel(container, UI_HEADER, Configuration.UI.ButtonReject, Anchor.CenterRight, new Offset(-25f, -10f, -5f, 10f), BUTTON_CLOSE);
        UI.Sprite(container, BUTTON_CLOSE, Sprites.Close, Configuration.UI.ButtonRejectText, Anchor.Center, new Offset(-7f, -7f, 7f, 7f));
        UI.Button(container, BUTTON_CLOSE, Commands.Close, Anchor.FullStretch, Offset.zero);
    }
#region Navigation
    private void CreateNavigation(CuiElementContainer container, UIUser user, string parent) {
        List<NavigationCategory> categories = user.AvailableCategories;
        const string NAVIGATION = "sr.navigation";
        UI.Panel(container, parent, Colors.Clear, Anchor.FullStretch, new Offset(250f, 0f, -250f, 0f), NAVIGATION);
        if (user.Category == 0 && categories.Count > 0) user.Category = categories[0];
        const float WIDTH = 100f;
        const float SPACING = 5f;
        float totalWidth = (WIDTH * categories.Count) + (SPACING * (categories.Count - 1));
        float left = -(totalWidth * 0.5f);
        for (int i = 0; i < categories.Count; i++) {
            NavigationCategory category = categories[i];
            string buttonName = $"{NAVIGATION}.{category}";
            string buttonColor = user.Category == category ? Configuration.UI.ButtonConfirm : Configuration.UI.Button;
            string textColor = user.Category == category ? Configuration.UI.ButtonConfirmText : Configuration.UI.ButtonText;
            float xMin = left + (i * (WIDTH + SPACING));
            UI.Panel(container, NAVIGATION, buttonColor, Anchor.Center, new Offset(xMin, -10f, xMin + WIDTH, 10f), buttonName);
            UI.Text(container, buttonName, user.Translate($"UI.Category.{category.ToString()}"), Anchor.FullStretch, Offset.zero, color : textColor);
            UI.Button(container, buttonName, $"{Commands.Navigation} {(int)category}", Anchor.FullStretch, Offset.zero);
        }
    }
    public enum NavigationCategory {
        None = 0, Kits, Commands, Items, Sell, Transfer, Exchange
    }
#endregion
#region Footer
    private void CreateFooter(CuiElementContainer container, UIUser user) {
        const string FOOTER = "sr.footer";
        UI.Panel(container, UI_MENU, Configuration.UI.PanelPrimary, Anchor.BottomStretch, new Offset(5f, 5f, -5f, 35f), FOOTER);
        // Admin Toggle
        if (IsAdmin(user.Player)) {
            const string TOGGLE = "sr.admin.toggle";
            string buttonColor = user.AdminMode ? Configuration.UI.ButtonConfirm : Configuration.UI.Button;
            string textColor = user.AdminMode ? Configuration.UI.ButtonConfirmText : Configuration.UI.ButtonText;
            UI.Panel(container, FOOTER, buttonColor, Anchor.CenterLeft, new Offset(5f, -10f, 135f, 10f), TOGGLE);
            UI.Text(container, TOGGLE, user.Translate("UI.AdminMode"), Anchor.FullStretch, Offset.zero, color : textColor);
            UI.Button(container, TOGGLE, Commands.AdminToggle, Anchor.FullStretch, Offset.zero);
            if (user.AdminMode && user.Category <= NavigationCategory.Items) {
                const string ADD_PRODUCT = "sr.admin.addproduct";
                UI.Panel(container, FOOTER, Configuration.UI.ButtonConfirm, Anchor.Center, new Offset(-75f, -10f, 75f, 10f), ADD_PRODUCT);
                UI.Sprite(container, ADD_PRODUCT, Sprites.Authorize, Configuration.UI.ButtonConfirmText, Anchor.CenterLeft, new Offset(7f, -6f, 19f, 6f));
                UI.Text(container, ADD_PRODUCT, user.Translate("UI.AddProduct"), Anchor.FullStretch, new Offset(11f, 0f, 0f, 0f), color : textColor);
                UI.Button(container, ADD_PRODUCT, Commands.AddProduct, Anchor.FullStretch, Offset.zero);
            }
        }
        const string BALANCE = "sr.balance";
        _balances.Data.TryGetValue(user.UserId, out int balance);
        UI.Panel(container, FOOTER, Configuration.UI.ButtonConfirm, Anchor.CenterRight, new Offset(-130f, -10f, -5f, 10f), BALANCE);
        UI.Text(container, BALANCE, user.Translate("UI.RP", balance), Anchor.FullStretch, Offset.zero, color : Configuration.UI.ButtonConfirmText);
        if (Configuration.UI.ShowPlaytime && PlaytimeTracker != null) {
            object t = Interface.CallHook("GetPlayTime", user.Player.UserIDString);
            if (t is double time) {
                const string PLAYTIME = "sr.playtime";
                UI.Panel(container, FOOTER, Configuration.UI.ButtonPurchase, Anchor.CenterRight, new Offset(-280f, -10f, -135f, 10f), PLAYTIME);
                UI.Countdown(container, PLAYTIME, user.Translate("UI.Playtime", "%TIME_LEFT%"), (int)time, int.MaxValue, Anchor.FullStretch, Offset.zero, color : Configuration.UI.ButtonPurchaseText);
            }
        }
    }
#endregion
#region Items
    private void CreateItems(CuiElementContainer container, UIUser user) {
        Products products = user.NpcStore is {
            CustomStore : true
        }
        ? user.NpcStore.Products : _products.Data;
        const string ITEMS = "sr.items";
        UI.Panel(container, UI_MENU, Colors.Clear, Anchor.FullStretch, new Offset(5f, 40f, -5f, -40f), ITEMS);
        CreateItemsNavigation(container, ITEMS, user, products);
        CreateItemsLayout(container, ITEMS, user, products);
    }
    private void CreateItemsNavigation(CuiElementContainer container, string parent, UIUser user, Products products) {
        const string NAVIGATION = "sr.items.navigation";
        UI.Panel(container, parent, Configuration.UI.PanelPrimary, Anchor.LeftStretch, new Offset(0f, 0f, 140f, 0f), NAVIGATION);
        const float HEIGHT = 20f;
        const float SPACING = 5f;
        for (int i = 0; i < products.ItemCategories.Length; i++) {
            ItemCategory category = products.ItemCategories[i];
            string buttonName = $"{NAVIGATION}.{category}";
            string buttonColor = user.ItemCategory == category ? Configuration.UI.ButtonConfirm : Configuration.UI.Button;
            string textColor = user.ItemCategory == category ? Configuration.UI.ButtonConfirmText : Configuration.UI.ButtonText;
            float yMax = -5f - (i * (HEIGHT + SPACING));
            UI.Panel(container, NAVIGATION, buttonColor, Anchor.TopStretch, new Offset(5f, yMax - HEIGHT, -5f, yMax), buttonName);
            UI.Text(container, buttonName, user.Translate($"UI.ItemCategory.{category.ToString()}"), Anchor.FullStretch, Offset.zero, color : textColor);
            UI.Button(container, buttonName, $"{Commands.ItemCategory} {(int)category}", Anchor.FullStretch, Offset.zero);
        }
    }
    private void CreateItemsLayout(CuiElementContainer container, string parent, UIUser user, Products products) {
        const string LAYOUT = "sr.items.layout";
        UI.Panel(container, parent, Configuration.UI.PanelPrimary, Anchor.FullStretch, new Offset(145f, 0f, 0f, 0f), LAYOUT);
        UI.Text(container, LAYOUT, user.Translate("UI.Items"), Anchor.FullStretch, Offset.zero, color : Colors.BarelyVisible, size : 120);
        const string SCROLL = "sr.items.scroll";
        CuiScrollbar scrollbar = UI.Scrollbar(Configuration.UI.ScrollbarHandle, Configuration.UI.ScrollbarHighlight, Configuration.UI.ScrollbarPressed, Configuration.UI.Scrollbar);
        CuiRectTransformComponent contentRect = UI.ScrollView(container, LAYOUT, Anchor.FullStretch, new Offset(5f, 5f, -5f, -5f), Anchor.FullStretch, Offset.zero, null, scrollbar, SCROLL);
        int count = 0;
        _itemsGrid ??= new HorizontalGrid(new Vector2(133f, 155.5f), new Vector2(5f, 5f), 8, 630f);
        _balances.Data.TryGetValue(user.UserId, out int balance);
        List<Products.Item> items = Pool.Get<List<Products.Item>>();
        FilterList(products.Items, items, user, _itemProductsContainsFilter);
        items.Sort((a, b) => {
            ItemDefinition aDefinition = a.ItemDefinition;
            ItemDefinition bDefinition = b.ItemDefinition;
            if (!aDefinition && !bDefinition) return 0;
            if (!aDefinition) return 1;
            if (!bDefinition) return -1;
            string aName = string.IsNullOrEmpty(a.DisplayName) ? (aDefinition.displayName?.english ?? "") : a.DisplayName;
            string bName = string.IsNullOrEmpty(b.DisplayName) ? (bDefinition.displayName?.english ?? "") : b.DisplayName;
            return string.Compare(aName, bName, StringComparison.Ordinal);
        }
        );
        for (int index = 0; index < items.Count; index++) {
            Products.Item item = items[index];
            if (item.Category != user.ItemCategory && user.ItemCategory != ItemCategory.All) continue;
            if (!string.IsNullOrEmpty(item.Permission) && !permission.UserHasPermission(user.Player.UserIDString, item.Permission) && !IsAdmin(user.Player)) continue;
            ItemDefinition itemDefinition = item.ItemDefinition;
            if (!itemDefinition) continue;
            bool isOwnedOrFree = IsOwnedOrFreeItem(user.Player, itemDefinition.itemid, item.SkinId);
            if (Configuration.Options.HideDlc && !user.AdminMode && !isOwnedOrFree) continue;
            string itemName = $"{LAYOUT}.{item.ID}";
            UI.Panel(container, SCROLL, Configuration.UI.PanelSecondary, Anchor.TopLeft, _itemsGrid.Get(count), itemName);
            CreateItemElement(container, itemName, item, user, balance, isOwnedOrFree);
            count++;
        }
        Pool.FreeUnmanaged(ref items);
        _itemsGrid.ResizeToFit(count, contentRect);
    }
    private void CreateItemElement(CuiElementContainer container, string parent, Products.Item item, UIUser user, int balance, bool isOwnedOrFree) {
        bool isDlcRestricted = !item.IgnoreDlcCheck && !isOwnedOrFree;
        string iconName = $"{parent}.icon";
        UI.Panel(container, parent, Colors.Clear, Anchor.TopCenter, new Offset(-64f, -130.5f, 64f, -2.5f), iconName);
        if (!string.IsNullOrEmpty(item.IconURL)) UI.PNG(container, iconName, GetImage(item.IconURL), Anchor.FullStretch, new Offset(16f, 8f, -16f, -24f));
        else UI.Icon(container, iconName, item.ItemDefinition.itemid, item.SkinId, Anchor.FullStretch, new Offset(16f, 8f, -16f, -24f));
        string name = string.IsNullOrEmpty(item.DisplayName) ? item.ItemDefinition.displayName.english : item.DisplayName;
        string titleName = $"{parent}.title";
        UI.Panel(container, iconName, Colors.BarelyVisibleDark, Anchor.TopStretch, new Offset(0f, -20f, 0f, 0f), titleName);
        UI.Text(container, titleName, name, Anchor.FullStretch, Offset.zero, size : 12);
        if (item.IsBp) UI.Icon(container, iconName, Products.Item.BlueprintBase.itemid, 0UL, Anchor.BottomLeft, new Offset(2.5f, 2.5f, 26.5f, 26.5f));
        if (item.Amount > 1) UI.Text(container, iconName, $"x{item.Amount}", Anchor.BottomStretch, new Offset(2.5f, 0f, -2.5f, 20f), align : TextAnchor.LowerRight);
        if (user.AdminMode) CreateAdminButtons(container, parent, user, ProductType.Item, item.ID);
        else CreatePurchaseButton(container, parent, user, ProductType.Item, item.ID, item.Cost, balance, isDlcRestricted);
    }
#endregion
#region Kits
    private void CreateKits(CuiElementContainer container, UIUser user) {
        Products products = user.NpcStore is {
            CustomStore : true
        }
        ? user.NpcStore.Products : _products.Data;
        const string KITS = "sr.kits";
        UI.Panel(container, UI_MENU, Configuration.UI.PanelPrimary, Anchor.FullStretch, new Offset(5f, 40f, -5f, -40f), KITS);
        UI.Text(container, KITS, user.Translate("UI.Kits"), Anchor.FullStretch, Offset.zero, color : Colors.BarelyVisible, size : 120);
        const string SCROLL = "sr.kits.scroll";
        CuiScrollbar scrollbar = UI.Scrollbar(Configuration.UI.ScrollbarHandle, Configuration.UI.ScrollbarHighlight, Configuration.UI.ScrollbarPressed, Configuration.UI.Scrollbar);
        CuiRectTransformComponent contentRect = UI.ScrollView(container, KITS, Anchor.FullStretch, new Offset(5f, 5f, -5f, -5f), Anchor.FullStretch, Offset.zero, null, scrollbar, SCROLL);
        int count = 0;
        _kitsGrid ??= new HorizontalGrid(new Vector2(307.5f, 361.5f), new Vector2(5f, 5f), 4, 630f);
        _balances.Data.TryGetValue(user.UserId, out int balance);
        List<Products.Kit> kits = Pool.Get<List<Products.Kit>>();
        FilterList(products.Kits, kits, user, _kitProductsContainsFilter);
        kits.Sort((a, b) => a.DisplayName.CompareTo(b.DisplayName));
        for (int index = 0; index < kits.Count; index++) {
            Products.Kit kit = kits[index];
            if (!IsKit(kit.KitName)) continue;
            if (!string.IsNullOrEmpty(kit.Permission) && !permission.UserHasPermission(user.Player.UserIDString, kit.Permission) && !IsAdmin(user.Player)) continue;
            string kitName = $"sr.kits.{kit.ID}";
            UI.Panel(container, SCROLL, Configuration.UI.PanelSecondary, Anchor.TopLeft, _kitsGrid.Get(count), kitName);
            if (CreateKitElement(container, kitName, kit, user, balance)) count++;
        }
        Pool.FreeUnmanaged(ref kits);
        _kitsGrid.ResizeToFit(count, contentRect);
    }
    private bool CreateKitElement(CuiElementContainer container, string parent, Products.Kit kit, UIUser user, int balance) {
        KitData kitData = kit.KitData;
        if (kitData == null) return false;
        string icon = !string.IsNullOrEmpty(kit.IconURL) ? GetImage(kit.IconURL) : string.Empty;
        bool hasIcon = !string.IsNullOrEmpty(icon);
        UI.Text(container, parent, kit.DisplayName, Anchor.TopStretch, new Offset(5f, -22.5f, hasIcon ? -55f : -5f, -2.5f), size : 12, align : TextAnchor.MiddleLeft);
        if (!string.IsNullOrEmpty(kit.Description)) UI.Text(container, parent, kit.Description, Anchor.TopStretch, new Offset(5f, -55f, hasIcon ? -55f : -5f, -25f), size : 10, align : TextAnchor.UpperLeft);
        if (hasIcon) UI.PNG(container, parent, GetImage(kit.IconURL), Anchor.TopRight, new Offset(-52.5f, -52.5f, -2.5f, -2.5f));
        _kitsBeltGrid ??= new HorizontalGrid(new Vector2(32, 32), new Vector2(5f, 5f), 8, 0f);
        _kitsWearGrid ??= new HorizontalGrid(new Vector2(32, 32), new Vector2(5f, 5f), 8, 0f);
        _kitsMainGrid ??= new HorizontalGrid(new Vector2(32, 32), new Vector2(5f, 5f), 6, 0f);
        // Belt Layout
        string beltName = $"{parent}.belt";
        UI.Panel(container, parent, Colors.Clear, Anchor.TopStretch, new Offset(2.5f, -110.75f, -2.5f, -56.25f), beltName);
        UI.Panel(container, beltName, Colors.BarelyVisibleDark, Anchor.TopStretch, new Offset(0f, -20f, 0f, 0f));
        UI.Text(container, beltName, user.Translate("UI.Kit.Belt"), Anchor.TopStretch, new Offset(5f, -20f, 5f, 0f), size : 12, align : TextAnchor.MiddleLeft);
        LayoutKitContainer(container, beltName, user, kitData.BeltItems, 6, _kitsBeltGrid);
        // Wear Layout
        string wearName = $"{parent}.wear";
        UI.Panel(container, parent, Colors.Clear, Anchor.TopStretch, new Offset(2.5f, -167.75f, -2.5f, -113.25f), wearName);
        UI.Panel(container, wearName, Colors.BarelyVisibleDark, Anchor.TopStretch, new Offset(0f, -20f, 0f, 0f));
        UI.Text(container, wearName, user.Translate("UI.Kit.Wear"), Anchor.TopStretch, new Offset(5f, -20f, 5f, 0f), size : 12, align : TextAnchor.MiddleLeft);
        LayoutKitContainer(container, wearName, user, kitData.WearItems, 8, _kitsWearGrid);
        // Main Layout
        string mainName = $"{parent}.main";
        UI.Panel(container, parent, Colors.Clear, Anchor.TopStretch, new Offset(2.5f, -338.25f, -2.5f, -170.25f), mainName);
        UI.Panel(container, mainName, Colors.BarelyVisibleDark, Anchor.TopStretch, new Offset(0f, -20f, 0f, 0f));
        UI.Text(container, mainName, user.Translate("UI.Kit.Main"), Anchor.TopStretch, new Offset(5f, -20f, 5f, 0f), size : 12, align : TextAnchor.MiddleLeft);
        LayoutKitContainer(container, mainName, user, kitData.MainItems, 24, _kitsMainGrid);
        if (user.AdminMode) CreateAdminButtons(container, parent, user, ProductType.Kit, kit.ID);
        else CreatePurchaseButton(container, parent, user, ProductType.Kit, kit.ID, kit.Cost, balance);
        return true;
    }
    private void LayoutKitContainer(CuiElementContainer container, string parent, UIUser user, KitData.ItemData[] items, int minCount, HorizontalGrid grid) {
        string layout = $"{parent}.layout";
        UI.Panel(container, parent, Colors.Clear, Anchor.FullStretch, new Offset(2.5f, 0f, -2.5f, -22.5f), layout);
        for (int i = 0; i < minCount; i++) {
            KitData.ItemData itemData = items != null && i < items.Length ? items[i] : null;
            string item = $"{layout}.{i}";
            Offset offset = grid.Get(i);
            UI.Panel(container, layout, Colors.BarelyVisibleDark, Anchor.TopLeft, offset, item);
            if (itemData != null) {
                ItemDefinition itemDefinition = itemData.ItemDefinition;
                if (!itemDefinition) continue;
                int itemId = GetRedirectedItemIdIfNotOwned(user.Player, itemDefinition.itemid);
                ulong skinId = CanUseSkin(user.Player, itemData.SkinID) ? itemData.SkinID : 0UL;
                UI.Icon(container, item, itemId, skinId, Anchor.FullStretch, Offset.zero);
                if (itemData.Amount > 1) UI.Text(container, item, $"x{itemData.Amount}", Anchor.FullStretch, Offset.zero, size : 8, align : TextAnchor.LowerRight);
                if (itemData.IsBlueprint) UI.Icon(container, item, Products.Item.BlueprintBase.itemid, 0UL, Anchor.TopLeft, new Offset(0f
// ... [Code preview truncated due to length. Full source in attached file] ...

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