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

FREE RustPay : 1.0.12 1.0.12

Нет прав для скачивания
C#:
using System.Collections.Generic;
using System.Globalization;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using System;
using Oxide.Core;
using System.Collections;
using UnityEngine.Networking;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WebSocketSharp;
using System.Linq;
using Oxide.Core.Libraries;
using System.Text.RegularExpressions;
using System.Net.Mail;
namespace Oxide.Plugins {
    [Info("RustPay", "[LimePlugin] Chibubrik", "1.0.12")]
    public class RustPay : RustPlugin {
#region Вар
        private string Layer = "RustPay_UI";
        private string LogoUrl = "";
        private string BackgroundUrl = "";
        private static RustPay _ins;
        private WS _ws;
        private BannerImage banner = new BannerImage();
        private List<Categories> categories = new List<Categories>();
        private List<ItemsList> items = new List<ItemsList>();
        private List<Discounts> discounts = new List<Discounts>();
        private List<Bonus> bonusList = new List<Bonus>();
        private List<PaymentMethods> paymentMethods = new List<PaymentMethods>();
        private Dictionary<ulong, List<string>> DBFavorites = new Dictionary<ulong, List<string>>();
        private Dictionary<ulong, int> activeCategory = new Dictionary<ulong, int>();
        private Dictionary<ulong, string> promoPlayer = new Dictionary<ulong, string>();
        private Dictionary<ulong, int> inputBalancePlayer = new Dictionary<ulong, int>();
        private Dictionary<ulong, string> emailPlayer = new Dictionary<ulong, string>();
        List<ulong> spamBlock = new List<ulong>();
        List<ulong> spamBlockPayment = new List<ulong>();
        private bool _serverDataReady = false;
        private int _pendingImages = 0;
        private HashSet<string> _cachedImages = new HashSet<string>();
        private const string ImageCachePath = "RustPay/cache/images";
        private List<string> ImageDownloadList = new() {
            "back", "discount", "scan", "exit", "inventory", "promo_w", "promo", "promo_gift", "topup", "url", "notify", "sbp", "card", "crypto", "skin"
        }
        ;
        private string privacy_policy = "";
        private string user_agreement = "";
#endregion
#region Конфиг
        private Configuration config;
        private class Configuration {
            [JsonProperty("Настройки магазина")]
            public Settings settings = new Settings();
            public static Configuration GetNewCong() {
                return new Configuration {
                    settings = new Settings() {
                        SecretKey = "123",
                    }
                }
                ;
            }
        }
        protected override void LoadConfig() {
            base.LoadConfig();
            try {
                config = Config.ReadObject<Configuration>();
                if (config?.settings == null) LoadDefaultConfig();
            }
            catch {
                PrintWarning($"Что то с этим конфигом не так! 'oxide/config/{Name}', создаём новую конфигурацию!");
                LoadDefaultConfig();
            }
            NextTick(SaveConfig);
        }
        protected override void LoadDefaultConfig() => config = Configuration.GetNewCong();
        protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Класс
        private class Settings {
            [JsonProperty("Секретный ключ магазина")]
            public string SecretKey;
        }
        private class BannerImage {
            public string Banner_1 {
                get;
                set;
            }
            public string Command_1 {
                get;
                set;
            }
            public string Banner_2 {
                get;
                set;
            }
            public string Command_2 {
                get;
                set;
            }
        }
        private class Categories {
            public int ID {
                get;
                set;
            }
            public string Name {
                get;
                set;
            }
            public string IconUrl {
                get;
                set;
            }
        }
        public class ItemsList {
            public int CategoryID {
                get;
                set;
            }
            public int ID {
                get;
                set;
            }
            public string Type {
                get;
                set;
            }
            public string DisplayName {
                get;
                set;
            }
            public string Description {
                get;
                set;
            }
            public string ShortName {
                get;
                set;
            }
            public ulong SkinID {
                get;
                set;
            }
            public string Command {
                get;
                set;
            }
            public string Image {
                get;
                set;
            }
            public float Price {
                get;
                set;
            }
            public int Amount {
                get;
                set;
            }
            public bool Blueprint {
                get;
                set;
            }
            public List<Items> contentItems = new List<Items>();
            public List<Kits> kits = new List<Kits>();
        }
        public class Kits {
            public string DisplayName {
                get;
                set;
            }
            public int Cooldown {
                get;
                set;
            }
            public List<Items> kitItems = new List<Items>();
        }
        public class Items {
            public int ID {
                get;
                set;
            }
            public string Type {
                get;
                set;
            }
            public string DisplayName {
                get;
                set;
            }
            public string ShortName {
                get;
                set;
            }
            public ulong SkinID {
                get;
                set;
            }
            public string Command {
                get;
                set;
            }
            public string Image {
                get;
                set;
            }
            public float Price {
                get;
                set;
            }
            public int Amount {
                get;
                set;
            }
            public bool Blueprint {
                get;
                set;
            }
        }
        public class InventoryResponse {
            public bool success {
                get;
                set;
            }
            public List<ItemInventory> items {
                get;
                set;
            }
        }
        public class ItemInventory {
            public int id {
                get;
                set;
            }
            public bool from_set {
                get;
                set;
            }
            public int purchase_id {
                get;
                set;
            }
            public string name {
                get;
                set;
            }
            public string type {
                get;
                set;
            }
            public int amount {
                get;
                set;
            }
            public ulong skin_id {
                get;
                set;
            }
            public string image_url {
                get;
                set;
            }
            public string shortname {
                get;
                set;
            }
            public string description {
                get;
                set;
            }
            public string command_text {
                get;
                set;
            }
            public bool is_blueprint {
                get;
                set;
            }
        }
        private class Discounts {
            public int ID {
                get;
                set;
            }
            public string Type {
                get;
                set;
            }
            public int ProductID {
                get;
                set;
            }
            public int Discount {
                get;
                set;
            }
        }
        private class Bonus {
            public int BonusText {
                get;
                set;
            }
            public int BonusPercent {
                get;
                set;
            }
            public string ColorBonus {
                get;
                set;
            }
        }
        private class PaymentMethods {
            public int ID {
                get;
                set;
            }
            public string PaymentText {
                get;
                set;
            }
            public string PaymentIcon {
                get;
                set;
            }
            public string PaymentColor {
                get;
                set;
            }
        }
#endregion
#region Хуки
        private void Init() {
            _ins = this;
            string url = $"wss://socket.rustpay.org";
            _ws = new WS(url);
            LoadDataBase();
        }
        private void OnServerInitialized() {
            _ws?.connect();
            foreach (BasePlayer player in BasePlayer.activePlayerList) InitPlayer(player);
            foreach (string image in ImageDownloadList) {
                LoadImage(image, $"https://cdn.rustpay.org/uploads/icons/{image}.png");
            }
        }
        private void OnPlayerConnected(BasePlayer player, bool load = false) {
            InitPlayer(player);
            _ws?.SendWhenReady(() => _ws.PlayerConnected(player.userID, player.displayName));
        }
        private void InitPlayer(BasePlayer player) {
            LoadSteamAvatar(player.UserIDString);
            if (!DBFavorites.ContainsKey(player.userID)) DBFavorites[player.userID] = new List<string>();
        }
        private void SetPlayerCategory(BasePlayer player) {
            if (!activeCategory.ContainsKey(player.userID)) {
                int startID = categories.Skip(1).FirstOrDefault()?.ID ?? 0;
                if (DBFavorites.ContainsKey(player.userID) && DBFavorites[player.userID].Count > 0) startID = 0;
                activeCategory[player.userID] = startID;
            }
        }
        private void Unload() {
            foreach (var player in BasePlayer.activePlayerList) CuiHelper.DestroyUi(player, Layer);
            SaveDataBase();
            _ws?.close();
        }
        private void LoadDataBase() {
            if (Interface.Oxide.DataFileSystem.ExistsDatafile($"{Name}/data/FavoritesList")) DBFavorites = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, List<string>>>($"{Name}/data/FavoritesList");
            else DBFavorites = new Dictionary<ulong, List<string>>();
            LoadImageCache();
        }
        private void SaveDataBase() {
            Interface.Oxide.DataFileSystem.WriteObject($"{Name}/data/FavoritesList", DBFavorites);
            SaveImageCache();
        }
#endregion
#region Подключение и обработка
        public class WS {
            private WebSocket socket;
            private bool isConnected = false;
            public bool hasUnloaded = false;
            public bool criticalError = false;
            private IEnumerator coroutineRoutine;
            private List<Action> _pendingQueue = new List<Action>();
            private bool _verified = false;
            public WS(string url) {
                socket = new WebSocket(url);
                socket.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12;
                socket.OnMessage += OnSocketMessage;
                socket.OnOpen += OnSocketOpen;
                socket.OnClose += OnSocketClose;
                socket.OnError += OnSocketError;
            }
            public bool IsConnected() {
                return isConnected && socket != null && socket.ReadyState == WebSocketState.Open;
            }
            public void SendWhenReady(Action action) {
                if (_verified && IsConnected()) action?.Invoke();
                else _pendingQueue.Add(action);
            }
            private void OnSocketMessage(object sender, MessageEventArgs e) {
                JObject obj = JObject.Parse(e.Data);
                if (obj.TryGetValue("action", out var action)) {
                    switch (action?.ToString()) {
                        case "verified" : if (this.coroutineRoutine == null) {
                            this.coroutineRoutine = this.ping();
                            ServerMgr.Instance.StartCoroutine(this.coroutineRoutine);
                        }
                        _ins.PrintWarning($"[WS] Авторизация пройдена! Начинаем работу");
                        _verified = true;
                        this.GetInfo();
                        Dictionary<ulong, string> onlinePlayers = new Dictionary<ulong, string>();
                        foreach (BasePlayer p in BasePlayer.activePlayerList) onlinePlayers.Add(p.userID, p.displayName);
                        if (onlinePlayers.Count > 0) this.PlayersArray(onlinePlayers);
                        foreach (var pending in _pendingQueue) pending?.Invoke();
                        _pendingQueue.Clear();
                        break;
                        case "pong" : Console.WriteLine(obj["data"]);
                        break;
                        case "serverInfo" : _ins.StoreAppearance(obj);
                        _ins.StoreCategories(obj);
                        _ins.StoreItems(obj);
                        _ins.StoreDocuments(obj);
                        _ins.StoreDiscounts(obj);
                        _ins.StoreBonus(obj);
                        _ins.StorePayments(obj);
                        _ins._serverDataReady = true;
                        break;
                        case "playerBalance" : ulong userIDbalance = (ulong)obj["steam_id"];
                        float balance = (float)obj["balance"];
                        string email = (string)obj["email"];
                        if (email != null) _ins.emailPlayer[userIDbalance] = email;
                        _ins.UpdateBalance(userIDbalance, balance);
                        break;
                        case "update_appearance" : _ins.StoreAppearance(obj);
                        break;
                        case "update_store" : _ins.StoreCategories(obj);
                        _ins.StoreItems(obj);
                        break;
                        case "update_discounts" : _ins.StoreDiscounts(obj);
                        break;
                        case "update_bonus" : _ins.StoreBonus(obj);
                        break;
                        case "update_paymentMethods" : _ins.StorePayments(obj);
                        break;
                        case "created_payment" : ulong userID = (ulong)obj["data"]["steam_id"];
                        string iconQR = (string)obj["data"]["url_qr"];
                        string url = (string)obj["data"]["short_link"];
                        _ins.LoadImage(iconQR, report : false);
                        _ins.PaymentWindowUI(userID, iconQR, url);
                        break;
                        case "payment_made" : BasePlayer player = BasePlayer.FindByID((ulong)obj["data"]["steam_id"]);
                        if (player == null || !player.IsConnected) break;
                        CuiHelper.DestroyUi(player, "PaymentWindow_UI");
                        float amount = (float)obj["data"]["amount"];
                        _ins.NotificationPaymentUI(player, amount);
                        _ins.UpdateBalance(player.userID, (float)obj["data"]["balance"]);
                        _ins.SendReply(player, $"Вы успешно пополнили свой баланс: {amount}₽");
                        Effect x = new Effect("assets/prefabs/deployable/vendingmachine/effects/vending-machine-purchase-human.prefab", player, 0, new Vector3(), new Vector3());
                        EffectNetwork.Send(x, player.Connection);
                        break;
                        case "clear_cache" : _ins.ClearCacheInternal();
                        break;
                        case "update_documents" : _ins.StoreDocuments(obj);
                        break;
                        case "error" : _ins.PrintWarning($"{obj["message"]}");
                        this.criticalError = true;
                        break;
                        default : _ins.PrintWarning($"action неизвестен!\n{JsonConvert.SerializeObject(obj, Formatting.Indented)}");
                        break;
                    }
                }
            }
            private void OnSocketOpen(object sender, EventArgs e) {
                this.isConnected = true;
                _ins.PrintWarning($"[WS] Соединение открыто. Проходим авторизацию...");
                this.Send(new {
                    action = "verification", key = _ins.config.settings.SecretKey, timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
                }
                );
            }
            private void OnSocketClose(object sender, CloseEventArgs e) {
                if (e == null) _ins.PrintError("[WS] Соединение закрыто, но аргументы события были null.");
                else if (string.IsNullOrEmpty(e.Reason)) _ins.PrintWarning("[WS] Соединение закрыто.");
                else _ins.PrintError($"[WS] Соединение закрыто: {e.Reason}");
                isConnected = false;
                _verified = false;
                if (this.coroutineRoutine != null) {
                    ServerMgr.Instance.StopCoroutine(this.coroutineRoutine);
                    this.coroutineRoutine = null;
                }
                if (!this.hasUnloaded && !this.criticalError) {
                    _ins.timer.Once(20, this.connect);
                }
            }
            private void OnSocketError(object sender, ErrorEventArgs e) {
                isConnected = false;
                if (e == null) {
                    _ins.PrintError("[WS] Ошибка WebSocket: аргументы события были null.");
                    return;
                }
                _ins.PrintError($"[WS] Ошибка WebSocket: {e.Message}");
                if (e.Exception != null) {
                    _ins.PrintError($"[WS] Исключение: {e.Exception}");
                }
            }
            public void connect() {
                if (!this.hasUnloaded) {
                    _ins.PrintWarning($"[WS] Попытка подключения");
                    try {
                        socket.ConnectAsync();
                    }
                    catch (Exception ex) {
                    }
                }
            }
            public void close() {
                this.hasUnloaded = true;
                socket?.CloseAsync();
            }
            private IEnumerator ping() {
                while (true) {
                    this.Send(new {
                        action = "ping"
                    }
                    );
                    yield return CoroutineEx.waitForSeconds(10f);
                }
            }
            public void Send(object data) {
                if (!isConnected || socket == null || hasUnloaded) return;
                _ins.RunInWorker(() => {
                    try {
                        if (isConnected && socket != null && socket.ReadyState == WebSocketState.Open) {
                            string json = JsonConvert.SerializeObject(data);
                            socket.SendAsync(json, (_) => {
                            }
                            );
                        }
                    }
                    catch (Exception ex) {
                        _ins.PrintError($"[WS] Ошибка отправки: {ex.Message}");
                    }
                }
                );
            }
            public void GetInfo() {
                this.Send(new {
                    action = "getServerInfo"
                }
                );
            }
            public void PlayersArray(Dictionary<ulong, string> userID) {
                this.Send(new {
                    action = "playerConnect", type = "array", players = userID
                }
                );
            }
            public void PlayerConnected(ulong userID, string displayName) {
                this.Send(new {
                    action = "playerConnect", type = "one", steam_id = userID, name = displayName
                }
                );
            }
            public void GetPlayerBalance(ulong userID) {
                this.Send(new {
                    action = "getPlayerBalance", steam_id = userID
                }
                );
            }
        }
        public void RunInWorker(Action action) {
            QueueWorkerThread(_ => action());
        }
#endregion
#region Image Cache
        private void LoadImageCache() {
            try {
                if (Interface.Oxide.DataFileSystem.ExistsDatafile($"{Name}/cache/ImageCache")) _cachedImages = Interface.Oxide.DataFileSystem.ReadObject<HashSet<string>>($"{Name}/cache/ImageCache");
                else _cachedImages = new HashSet<string>();
            }
            catch {
                PrintWarning("Кэш изображений повреждён или устарел, создаём новый");
                _cachedImages = new HashSet<string>();
                SaveImageCache();
            }
            if (_cachedImages == null) _cachedImages = new HashSet<string>();
        }
        private void SaveImageCache() {
            Interface.Oxide.DataFileSystem.WriteObject($"{Name}/cache/ImageCache", _cachedImages);
        }
        private bool ShouldCache(string key) {
            if (string.IsNullOrEmpty(key)) return false;
            if (key.ToLower().Contains("qr") || key.Contains("payment_qr")) return false;
            if (key.Length == 17 && key.StartsWith("765") && key.All(char.IsDigit)) return false;
            if (key.Contains("steamcommunity") || key.Contains("akamaihd.net")) return false;
            return true;
        }
        private string GetCachedFilePath(string key) {
            string safeKey = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(key)) .Replace("/", "_") .Replace("+", "-") .Replace("=", "");
            return $"{Interface.Oxide.DataDirectory}/{ImageCachePath}/{safeKey}.png";
        }
        private bool TryLoadFromCache(string key) {
            if (!ShouldCache(key)) return false;
            if (!_cachedImages.Contains(key)) return false;
            string fullPath = GetCachedFilePath(key);
            if (!System.IO.File.Exists(fullPath)) {
                _cachedImages.Remove(key);
                return false;
            }
            try {
                byte[] data = System.IO.File.ReadAllBytes(fullPath);
                uint crc = FileStorage.server.Store(data, FileStorage.Type.png, CommunityEntity.ServerInstance.net.ID);
                images[key] = crc;
                return true;
            }
            catch (Exception ex) {
                PrintError($"Ошибка загрузки из кэша: {key} - {ex.Message}");
                _cachedImages.Remove(key);
                return false;
            }
        }
        private void SaveToCache(string key, byte[] data) {
            if (!ShouldCache(key)) return;
            try {
                string fullPath = GetCachedFilePath(key);
                string directory = System.IO.Path.GetDirectoryName(fullPath);
                if (!System.IO.Directory.Exists(directory)) System.IO.Directory.CreateDirectory(directory);
                System.IO.File.WriteAllBytes(fullPath, data);
                _cachedImages.Add(key);
            }
            catch (Exception ex) {
                PrintError($"Ошибка сохранения в кэш: {key} - {ex.Message}");
            }
        }
#endregion
        private Dictionary<string, uint?> images = new Dictionary<string, uint?>();
        private void LoadImage(string key, string url = null, Action callback = null, bool report = true) {
            if (url == null) url = key;
            if (string.IsNullOrEmpty(url)) {
                callback?.Invoke();
                return;
            }
            if (HasImage(key)) {
                callback?.Invoke();
                return;
            }
            if (TryLoadFromCache(key)) {
                callback?.Invoke();
                return;
            }
            _pendingImages++;
            ServerMgr.Instance.StartCoroutine(DownloadImage(key, url, () => {
                _pendingImages--;
                callback?.Invoke();
            }
            , report));
        }
        private void LoadSteamAvatar(string steamId, Action callback = null) {
            string apiUrl = $"http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=B18F4869325C455B96C6801D486FB8EA&steamids={steamId}";
            webrequest.Enqueue(apiUrl, null, (code, response) => {
                if (code != 200) {
                    callback?.Invoke();
                    return;
                }
                string avatarUrl = (string)JObject.Parse(response)["response"]?["players"]?[0]?["avatarfull"];
                if (string.IsNullOrEmpty(avatarUrl)) {
                    callback?.Invoke();
                    return;
                }
                LoadImage(steamId, avatarUrl, callback);
            }
            , this);
        }
        private IEnumerator DownloadImage(string key, string url, Action callback, bool report, int maxAttempts = 5) {
            if (!url.StartsWith("http://") && !url.StartsWith("https://")) url = "https://" + url;
            else url = url.Replace("http://", "https://");
            for (int attempt = 1; attempt <= maxAttempts; attempt++) {
                UnityWebRequest www = null;
                try {
                    www = UnityWebRequest.Get(url);
                }
                catch (Exception e) {
                    PrintError($"Bad URL: {url} | ex: {e.Message}");
                    images[key] = null;
                    callback?.Invoke();
                    yield break;
                }
                using (www) {
                    www.timeout = 10;
                    yield return www.SendWebRequest();
                    bool failed = www.isNetworkError || www.isHttpError;
                    if (!failed) {
                        if (attempt > 1 && report) Puts($"Загрузили: {key}");
                        byte[] data = www.downloadHandler.data;
                        uint crc = FileStorage.server.Store(data, FileStorage.Type.png, CommunityEntity.ServerInstance.net.ID);
                        images[key] = crc;
                        SaveToCache(key, data);
                        callback?.Invoke();
                        yield break;
                    }
                    if (report) PrintError($"Ошибка загрузки ({attempt}/{maxAttempts}): {www.error} | URL: {url}");
                    if (attempt < maxAttempts) yield return new WaitForSeconds(2f * attempt);
                }
            }
            if (report) PrintError($"Не смогли загрузить: {key} / {url}");
            images[key] = null;
            callback?.Invoke();
        }
        private string GetImage(string key) {
            if (string.IsNullOrEmpty(key)) return null;
            return images.TryGetValue(key, out uint? crc) && crc.HasValue ? crc.Value.ToString() : null;
        }
        private bool HasImage(string key) => !string.IsNullOrEmpty(key) && GetImage(key) != null;
#region Методы создания и обновления логотипа, баннеров, предметов, категорий, скидок
        private void StoreAppearance(JObject obj) {
            var msg = obj["data"] as JObject;
            if (msg == null) {
                PrintWarning($"[WS] StoreAppearance: message не объект. Type={obj["data"]?.Type}");
                return;
            }
            LogoUrl = msg.Value<string>("logo_url") ?? "";
            BackgroundUrl = msg.Value<string>("background_url") ?? "";
            LoadImage(LogoUrl);
            LoadImage(BackgroundUrl);
            var banners = msg["banners"] as JObject;
            var b1 = banners?["banner_1"] as JObject;
            banner.Banner_1 = b1?.Value<string>("url") ?? "";
            banner.Command_1 = b1?.Value<string>("command") ?? "";
            var b2 = banners?["banner_2"] as JObject;
            banner.Banner_2 = b2?.Value<string>("url") ?? "";
            banner.Command_2 = b2?.Value<string>("command") ?? "";
            LoadImage(banner.Banner_1);
            LoadImage(banner.Banner_2);
        }
        private void StoreCategories(JObject obj) {
            var categoryList = obj["data"]["categories"];
            if (categoryList is JArray category) {
                categories.Clear();
                categories.Add(new Categories {
                    ID = 0, Name = "Избранное", IconUrl = "https://cdn.rustpay.org/uploads/favorite.category.png"
                }
                );
                foreach (JObject cat in category) {
                    categories.Add(new Categories {
                        ID = cat.Value<int>("id"), Name = cat.Value<string>("name"), IconUrl = cat.Value<string>("icon_url")
                    }
                    );
                }
            }
            foreach (Categories check in categories) {
                if (string.IsNullOrEmpty(check.IconUrl)) continue;
                LoadImage(check.IconUrl);
            }
        }
        private void StoreDocuments(JObject obj) {
            var documents = obj["data"]["documents"];
            privacy_policy = (string) documents["policy"];
            user_agreement = (string) documents["agreement"];
        }
        private void StoreItems(JObject obj) {
            var itemList = obj["data"]["store"];
            if (itemList is JArray checkItemsList) {
                items.Clear();
                foreach (JObject check in checkItemsList) {
                    int catId = check.Value<int?>("id") ?? 0;
                    if (check["items"] is not JArray itemsListArray) continue;
                    foreach (JObject item in itemsListArray) {
                        List<Items> contents = new List<Items>();
                        if (item.Value<string>("type") == "set" && item["content"] is JArray contentsList) {
                            foreach (JObject content in contentsList) {
                                contents.Add(new Items {
                                    ID = content.Value<int?>("id") ?? 0, Type = content.Value<string>("type"), DisplayName = content.Value<string>("name"), ShortName = content.Value<string>("shortname"), SkinID = content.Value<ulong?>("skin_id") ?? 0, Command = content.Value<string>("command"), Image = content.Value<string>("image"), Amount = content.Value<int?>("amount") ?? 1, Blueprint = content.Value<bool?>("is_blueprint") ?? false,
                                }
                                );
                            }
                        }
                        List<Kits> kitsInfo = new List<Kits>();
                        if (item.Value<string>("type") == "command" && item["kits"] is JArray kitsList) {
                            foreach (JObject kit in kitsList) {
                                List<Items> kitItemsList = new List<Items>();
                                if (kit["items"] is JArray itemsList) {
                                    foreach (JObject itemKit in itemsList) {
                                        kitItemsList.Add(new Items {
                                            ID = itemKit.Value<int?>("id") ?? 0, DisplayName = itemKit.Value<string>("name"), ShortName = itemKit.Value<string>("shortname"), SkinID = itemKit.Value<ulong?>("skin_id") ?? 0, Image = itemKit.Value<string>("image"), Amount = itemKit.Value<int?>("amount") ?? 1
                                        }
                                        );
                                    }
                                }
                                kitsInfo.Add(new Kits {
                                    DisplayName = kit.Value<string>("name"), Cooldown = kit.Value<int>("cooldown"), kitItems = kitItemsList
                                }
                                );
                            }
                        }
                        items.Add(new ItemsList {
                            CategoryID = catId, ID = item.Value<int?>("id") ?? 0, Type = item.Value<string>("type"), DisplayName = item.Value<string>("name"), Description = item.Value<string>("description"), ShortName = item.Value<string>("shortname"), SkinID = item.Value<ulong?>("skin_id") ?? 0, Command = item.Value<string>("command"), Image = item.Value<string>("image"), Price = item.Value<float?>("price") ?? 0f, Amount = item.Value<int?>("amount") ?? 1, Blueprint = item.Value<bool?>("is_blueprint") ?? false, contentItems = contents, kits = kitsInfo
                        }
                        );
                    }
                }
            }
            LoadImage("https://cdn.rustpay.org/images/rust/blueprintbase.png");
            foreach (ItemsList check in items) {
                if (!HasImage(check.Image) && !string.IsNullOrEmpty(check.Image)) LoadImage(check.Image);
                foreach (Items content in check.contentItems) if (!HasImage(content.Image)) LoadImage(content.Image);
                foreach (var kit in check.kits.SelectMany(i => i.kitItems)) if (!HasImage(kit.Image)) LoadImage(kit.Image);
            }
        }
        private void StoreDiscounts(JObject obj) {
            var discountList = obj["data"]["discounts"];
            if (discountList is JArray itemDiscounts) {
                discounts.Clear();
                foreach (JObject check in itemDiscounts) {
                    discounts.Add(new Discounts {
                        ID = check.Value<int?>("id") ?? 0, Type = check.Value<string>("product_type"), ProductID = check.Value<int?>("product_id") ?? 0, Discount = check.Value<int>("discount"),
                    }
                    );
                }
            }
        }
        private void StoreBonus(JObject obj) {
            var bonusesList = obj["data"]["bonuses"];
            if (bonusesList is JArray bonus) {
                bonusList.Clear();
                foreach (JObject check in bonus) {
                    int random = UnityEngine.Random.Range(0, BonusColorList.Count());
                    bonusList.Add(new Bonus() {
                        BonusText = check.Value<int?>("min_amount") ?? 0, BonusPercent = check.Value<int?>("bonus_percent") ?? 0, ColorBonus = BonusColorList[random]
                    }
                    );
                }
            }
        }
        private void StorePayments(JObject obj) {
            var payments = obj["data"]["paymentMethods"];
            if (payments is JArray paymentList) {
                paymentMethods.Clear();
                foreach (JObject check in paymentList) {
                    string name = check.Value<string>("method_code");
                    paymentMethods.Add(new PaymentMethods() {
                        ID = check.Value<int?>("id") ?? 0, PaymentText = check.Value<string>("method_name"), PaymentIcon = check.Value<string>("method_code").ToLower(), PaymentColor = "979797ff"
                    }
                    );
                }
            }
        }
#endregion
#region Команды
        [ConsoleCommand("rustpay.clearcache")]
        private void ClearCacheCommand(ConsoleSystem.Arg arg) {
            if (!arg.IsServerside || arg.Connection != null) {
                arg.ReplyWith("Команда доступна только из серверной консоли");
                return;
            }
            ClearCacheInternal();
            arg.ReplyWith("Кэш изображений очищен");
        }
        [ConsoleCommand("rustpay.balance")]
        private void CmdBalance(ConsoleSystem.Arg arg) {
            if (!arg.IsAdmin) {
                return;
            }
            if (arg.Args == null || arg.Args.Length < 3) {
                arg.ReplyWith("Пример: rustpay.balance <steamId> <amount> <credit|debit> [reason]");
                return;
            }
            ulong steamId;
            if (!ulong.TryParse(arg.Args[0], out steamId)) {
                arg.ReplyWith("Неверный SteamID");
                return;
            }
            int amount;
            if (!int.TryParse(arg.Args[1], out amount) || amount <= 0) {
                arg.ReplyWith("Неверный amount");
                return;
            }
            string type = arg.Args[2].ToLower();
            if (type != "credit" && type != "debit") {
                arg.ReplyWith("Доступные способы 'credit' или 'debit'");
                return;
            }
            string reason = arg.Args.Length > 3 ? string.Join(" ", arg.Args.Skip(3)) : "console";
            API_ChangeBalance(steamId, amount, type, reason, success => {
                arg.ReplyWith(success ? $"[RustPay] {type} {amount} for {steamId} - SUCCESS" : $"[RustPay] {type} {amount} for {steamId} - FAILED");
            }
            );
        }
        private void ClearCacheInternal() {
            try {
                string cachePath = $"{Interface.Oxide.DataDirectory}/{ImageCachePath}";
                if (System.IO.Directory.Exists(cachePath)) System.IO.Directory.Delete(cachePath, true);
                _cachedImages.Clear();
                SaveImageCache();
                SaveDataBase();
            }
            catch (Exception ex) {
                PrintError($"Ошибка очистки кэша: {ex.Message}");
            }
        }
        [ChatCommand("pay")]
        private void ChatRustPay(BasePlayer player) => RustPayUI(player);
        [ConsoleCommand("rustpay")]
        private void ConsoleRustPay(ConsoleSystem.Arg arg) {
            BasePlayer player = arg.Player();
            if (player != null && arg.HasArgs(1)) {
                string command = arg.Args[0];
                if (command == "openpromo") {
                    PromocodeUI(player);
                    EffectBtn(player);
                }
                if (command == "promo") {
                    string promo = string.Join(" ", arg.Args.Skip(1));
                    promoPlayer[player.userID] = promo;
                }
                if (command == "email") {
                    string email = string.Join(" ", arg.Args.Skip(1));
                    if (IsValidEmail(email)) {
                        emailPlayer[player.userID] = email;
                    }
                }
                if (command == "back") {
                    StoreUI(player);
                    EffectBtn(player);
                }
                if (command == "inventory") {
                    StoreUI(player, "inv");
                    EffectBtn(player);
                }
                if (command == "privacypolicy") {
                    StoreUI(player, "privacy");
                    EffectBtn(player);
                }
                if (command == "useragreement") {
                    StoreUI(player, "agreement");
                    EffectBtn(player);
                }
                if (command == "send.promo") {
                    string promo = promoPlayer[player.userID];
                    PromocodeUI(player);
                    if (promo != "") SendPromo(player, promo);
                    else NotificationUI(player, "promo", "Вы не указали промокод", true);
                }
                if (command == "balanceup") {
                    BalanceReplenishmentUI(player);
                    EffectBtn(player);
                }
                if (command == "category") {
                    int id = int.Parse(arg.Args[1]);
                    if (activeCategory[player.userID] != id) {
                        activeCategory[player.userID] = id;
                        ButtonCategoriesUI(player);
                        EffectBtn(player);
                    }
                }
                if (command == "fav.toggle") {
                    string id = arg.Args[1];
                    string type = arg.Args[2];
                    List<string> list = DBFavorites[player.userID];
                    if (list.Contains(type + id)) {
                        list.Remove(type + id);
                        if (activeCategory[player.userID] == 0) ItemsUI(player);
                        else UpdateItemUI(player, int.Parse(id), type);
                    }
                    else {
                        list.Add(type + id);
                        UpdateItemUI(player, int.Parse(id), type);
                    }
                    EffectBtn(player);
                }
                if (command == "openitem") {
                    if (arg.Args[2] == "item") OpenItemUI(player, int.Parse(arg.Args[1]));
                    else OpenSetAndKitsUI(player, int.Parse(arg.Args[1]), arg.Args[2]);
                    EffectBtn(player);
                }
                if (command == "change") {
                    int change = int.Parse(arg.Args[3]);
                    if (change <= 0) return;
                    ChangeItemCount(player, int.Parse(arg.Args[1]), arg.Args[2], change);
                    EffectBtn(player);
                }
                if (command == "buy") {
                    EffectBtn(player);
                    if (spamBlock.Contains(player.userID)) {
                        NotificationUI(player, arg.Args[2], "Подождите, слишком быстро!", true);
                        return;
                    }
                    spamBlock.Add(player.userID);
                    UpdateBuyButtonText(player, arg.Args[2], "Обработка..", true);
                    SendBuy(player, int.Parse(arg.Args[1]), arg.Args[2], float.Parse(arg.Args[3]), int.Parse(arg.Args[4]));
                }
                if (command == "take") {
                    TakeItem(player, int.Parse(arg.Args[1]), arg.Args[2], int.Parse(arg.Args[3]));
                    EffectBtn(player, "assets/bundled/prefabs/fx/weapons/survey_charge/survey_charge_stick.prefab");
                }
                if (command == "bonusvalue") {
                    string input = arg.Args[1];
                    CuiHelper.DestroyUi(player, "InputValue");
                    CuiElementContainer container = new CuiElementContainer();
                    container.Add(new CuiElement {
                        Parent = "BalanceInput", Name = "InputValue", Components = {
                            new CuiInputFieldComponent {
                                Command = "rustpay inputbalance", Text = input, FontSize = 12, Align = TextAnchor.MiddleLeft, Font = "robotocondensed-bold.ttf", Color = HexToCuiColor("#ffffff", 60), NeedsKeyboard = true, CharsLimit = 60
                            }
                            , new CuiRectTransformComponent {
                                AnchorMin = "0.05 0", AnchorMax = "0.86 1"
                            }
                        }
                    }
                    );
                    CuiHelper.AddUi(player, container);
                    inputBalancePlayer[player.userID] = int.Parse(arg.Args[1]);
                    EffectBtn(player);
                }
                if (command == "inputbalance") {
                    inputBalancePlayer[player.userID] = int.Parse(arg.Args[1]);
                }
                if (command == "payment") {
                    if (spamBlockPayment.Contains(player.userID)) return;
                    spamBlockPayment.Add(player.userID);
                    timer.Once(0.5f, () => spamBlockPayment.Remove(player.userID));
                    if (emailPlayer.ContainsKey(player.userID)) RequestUpBalance(player, int.Parse(arg.Args[1]), inputBalancePlayer[player.userID]);
                    EffectBtn(player);
                }
                if (command == "updateQR") {
                    UpdateIconQR(player, arg.Args[1]);
                }
            }
        }
#endregion
#region Интерфейс
        private void RustPayUI(BasePlayer player) {
            if (!_serverDataReady) {
                SendReply(player, "Магазин загружается, подождите...");
                return;
            }
            if (_pendingImages > 0) {
                SendReply(player, $"Загрузка изображений ({_pendingImages} осталось), подождите...");
                return;
            }
            SetPlayerCategory(player);
            _ws.GetPlayerBalance(player.userID);
            CuiHelper.DestroyUi(player, Layer);
            CuiElementContainer container = new CuiElementContainer();
            container.Add(new CuiPanel {
                CursorEnabled = true, RectTransform = {
                    AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
                }
                , Image = {
                    Color = "0 0 0 0.9", Material = "assets/content/ui/uibackgroundblur.mat"
                }
            }
            , "Overlay", Layer);
            container.Add(new CuiPanel {
                RectTransform = {
                    AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
                }
                , Image = {
                    Sprite = "assets/content/ui/ui.background.transparent.radial.psd", Color = HexToCuiColor("#363636", 60)
                }
            }
            , Layer);
            container.Add(new CuiElement {
                Parent = Layer, Components = {
                    new CuiRawImageComponent {
                        Png = GetImage(BackgroundUrl), Color = "1 1 1 1"
                    }
                    , new CuiRectTransformComponent {
                        AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
                    }
                }
            }
            );
            container.Add(new CuiPanel {
                RectTransform = {
                    AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-640 -360", OffsetMax = "640 360"
                }
                , Image = {
                    Color = "0 0 0 0"
                }
            }
            , Layer, "MainStore");
            container.Add(new CuiButton {
                RectTransform = {
                    AnchorMin = "0.924 0.945", AnchorMax = "0.989 0.981", OffsetMax = "0 0"
                }
                , Button = {
                    Color = HexToCuiColor("#cccccc", 5), Close = Layer, Material = "assets/content/ui/uibackgroundblur.mat"
                }
            }
            , "MainStore"
// ... [Code preview truncated due to length. Full source in attached file] ...

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