Загрузка данных


using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Kits", "Classic Ultimate Release", "1.3.0")]
    class Kits : RustPlugin
    {
        private List<Kit> kitsList = new List<Kit>();
        private Dictionary<ulong, Dictionary<string, KitData>> PlayersData = new Dictionary<ulong, Dictionary<string, KitData>>();
        
        // Словарь для отслеживания текущей страницы меню у каждого игрока
        private Dictionary<ulong, int> playerPages = new Dictionary<ulong, int>();

        class PluginConfig
        {
            [JsonProperty("Префикс чата")] public string DefaultPrefix = "[Kit]";
        }

        public class Kit
        {
            public string Name { get; set; }
            public string DisplayName { get; set; }
            public bool Hide { get; set; }
            public string Color { get; set; }
            public List<KitItem> Items { get; set; }

            public Kit()
            {
                Name = string.Empty;
                DisplayName = string.Empty;
                Color = "0.41 0.51 0.32 1.0";
                Items = new List<KitItem>();
            }
        }

        public class KitItem
        {
            public int ItemID { get; set; } 
            public int Amount { get; set; }
            public string Container { get; set; }
            public int Slot { get; set; }
            public float Condition { get; set; }

            public KitItem()
            {
                Container = string.Empty;
            }
        }

        public class KitData
        {
            public int Amount { get; set; }
            public double Cooldown { get; set; }
        }

        void Loaded()
        {
            try { kitsList = Interface.Oxide.DataFileSystem.ReadObject<List<Kit>>("Kits/KitsList"); } catch { kitsList = new List<Kit>(); }
            try { PlayersData = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, Dictionary<string, KitData>>>("Kits/PlayersData"); } catch { PlayersData = new Dictionary<ulong, Dictionary<string, KitData>>(); }
            
            if (kitsList == null) kitsList = new List<Kit>();
            if (PlayersData == null) PlayersData = new Dictionary<ulong, Dictionary<string, KitData>>();
        }

        void OnPlayerDisconnected(BasePlayer player, string reason)
        {
            if (player != null) playerPages.Remove(player.userID);
        }

        void OnPlayerRespawned(BasePlayer player)
        {
            if (player == null || player.IsDead() || player.IsBot) return;
            if (player.userID < 76561197960265728L && player.userID > 0) return;

            Kit autoKit = null;
            foreach (var k in kitsList)
            {
                if (k.Name != null && k.Name.ToLower() == "autokit")
                {
                    autoKit = k;
                    break;
                }
            }
            if (autoKit == null) return;

            timer.Once(0.5f, () =>
            {
                if (player == null || !player.IsConnected) return;
                
                player.inventory.Strip();
                GiveItems(player, autoKit);
                SendReply(player, "Вы автоматически получили стартовый набор!");
            });
        }

        [ChatCommand("kit")]
        void KitCommand(BasePlayer player, string command, string[] args)
        {
            if (player.IsAdmin && args != null && args.Length > 0 && args[0].ToLower() == "create")
            {
                if (args.Length < 2) { SendReply(player, "Использование: /kit create [имя]"); return; }
                
                string kitName = args[1].ToLower();
                string displayName = kitName.ToUpper();

                Kit newKit = new Kit
                {
                    Name = kitName,
                    DisplayName = displayName,
                    Hide = (kitName == "autokit"),
                    Items = GetPlayerItems(player)
                };

                for (int i = kitsList.Count - 1; i >= 0; i--)
                {
                    if (kitsList[i].Name != null && kitsList[i].Name.ToLower() == kitName)
                    {
                        kitsList.RemoveAt(i);
                    }
                }

                kitsList.Add(newKit);
                SaveKits();
                SendReply(player, $"Кит {kitName} успешно создан!");
                return;
            }
            
            playerPages[player.userID] = 0; // Сбрасываем на первую страницу при открытии через чат
            OpenKitMenu(player);
        }

        [ConsoleCommand("kit.closeui")]
        void CloseUiCommand(ConsoleSystem.Arg systemArg) 
        { 
            if (systemArg == null) return;
            BasePlayer p = systemArg.Player(); 
            if (p != null) { DestroyAllKitUi(p); playerPages.Remove(p.userID); }
        }

        [ConsoleCommand("kit.backtomenu")]
        void BackToMenuCommand(ConsoleSystem.Arg systemArg)
        {
            if (systemArg == null) return;
            BasePlayer p = systemArg.Player(); 
            if (p != null) OpenKitMenu(p);
        }

        // Консольная команда для переключения страниц меню наборов
        [ConsoleCommand("kit.changepage")]
        void ChangePageCommand(ConsoleSystem.Arg systemArg)
        {
            if (systemArg == null) return;
            BasePlayer p = systemArg.Player(); if (p == null) return;
            
            int targetPage = systemArg.GetInt(0, 0);
            playerPages[p.userID] = targetPage;
            OpenKitMenu(p);
        }

        [ConsoleCommand("kit.claim")]
        void ClaimKitCommand(ConsoleSystem.Arg systemArg)
        {
            if (systemArg == null) return;
            BasePlayer p = systemArg.Player(); if (p == null) return;
            
            string kitName = systemArg.GetString(0, "").ToLower();
            if (string.IsNullOrEmpty(kitName)) return;
            
            Kit kit = null;
            foreach (var k in kitsList)
            {
                if (k.Name != null && k.Name.ToLower() == kitName)
                {
                    kit = k;
                    break;
                }
            }

            if (kit != null) 
            { 
                GiveItems(p, kit); 
                SendReply(p, $"Вы успешно получили: {kit.DisplayName}"); 
            }
            DestroyAllKitUi(p);
            playerPages.Remove(p.userID);
        }

        [ConsoleCommand("kit.previewui")]
        void PreviewUiCommand(ConsoleSystem.Arg systemArg)
        {
            if (systemArg == null) return;
            BasePlayer p = systemArg.Player(); if (p == null) return;
            
            string kitName = systemArg.GetString(0, "").ToLower();
            if (string.IsNullOrEmpty(kitName)) return;
            
            OpenKitPreview(p, kitName);
        }

        private void DestroyAllKitUi(BasePlayer player)
        {
            CuiHelper.DestroyUi(player, "KitMenu");
            CuiHelper.DestroyUi(player, "KitPreviewMenu");
        }

        private List<KitItem> GetPlayerItems(BasePlayer player)
        {
            var items = new List<KitItem>();
            
            if (player.inventory.containerMain != null) AddItemsFromContainer(player.inventory.containerMain, "main", items);
            if (player.inventory.containerBelt != null) AddItemsFromContainer(player.inventory.containerBelt, "belt", items);
            if (player.inventory.containerWear != null) AddItemsFromContainer(player.inventory.containerWear, "wear", items);

            return items;
        }

        private void AddItemsFromContainer(ItemContainer container, string label, List<KitItem> list)
        {
            if (container.itemList == null) return;
            foreach (var item in container.itemList)
            {
                if (item == null || item.info == null) continue;
                list.Add(new KitItem
                {
                    ItemID = item.info.itemid,
                    Amount = item.amount,
                    Slot = item.position,
                    Condition = item.condition,
                    Container = label
                });
            }
        }

        private void GiveItems(BasePlayer player, Kit kit)
        {
            if (player == null || kit == null || kit.Items == null) return;
            
            foreach (var item in kit.Items)
            {
                if (item == null) continue;
                
                Item createdItem = ItemManager.CreateByItemID(item.ItemID, item.Amount);
                if (createdItem == null) continue;

                bool moved = false;
                if (item.Container == "wear" && player.inventory.containerWear != null)
                    moved = createdItem.MoveToContainer(player.inventory.containerWear, item.Slot, true);
                else if (item.Container == "belt" && player.inventory.containerBelt != null)
                    moved = createdItem.MoveToContainer(player.inventory.containerBelt, item.Slot, true);
                
                if (!moved && player.inventory.containerMain != null)
                {
                    createdItem.MoveToContainer(player.inventory.containerMain, -1, true);
                }
            }

            player.inventory.SendSnapshot();
            player.Command("inventory.update");
        }

        private void OpenKitMenu(BasePlayer player)
        {
            DestroyAllKitUi(player);
            CuiElementContainer container = new CuiElementContainer();
            
            string bgPanel = container.Add(new CuiPanel {
                Image = { Color = "0 0 0 0.4" },
                RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
                CursorEnabled = true
            }, "Overlay", "KitMenu");

            container.Add(new CuiButton {
                Button = { Command = "kit.closeui", Color = "0 0 0 0" },
                RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
                Text = { Text = "" }
            }, bgPanel, "KitMenuBackgroundButton");

            container.Add(new CuiPanel {
                Image = { Color = "0.18 0.18 0.18 0.75" },
                RectTransform = { AnchorMin = "0.08 0.44", AnchorMax = "0.92 0.56" }
            }, bgPanel, "KitMenuInner");

            List<Kit> visibleKits = new List<Kit>();
            foreach (var k in kitsList)
            {
                if (!k.Hide) visibleKits.Add(k);
            }

            // Логика постраничной пагинации наборов
            int currentPage = 0;
            playerPages.TryGetValue(player.userID, out currentPage);

            int itemsPerPage = 4;
            int totalKits = visibleKits.Count;
            int startIdx = currentPage * itemsPerPage;
            
            // Если вдруг страница уехала за пределы, сбрасываем
            if (startIdx >= totalKits && currentPage > 0)
            {
                currentPage = 0;
                playerPages[player.userID] = 0;
                startIdx = 0;
            }

            int countOnPage = Math.Min(itemsPerPage, totalKits - startIdx);
            bool hasNextPage = totalKits > (currentPage + 1) * itemsPerPage;
            bool hasPrevPage = currentPage > 0;

            if (totalKits == 0) { CuiHelper.AddUi(player, container); return; }

            // Высчитываем анкоры в зависимости от того, сколько наборов конкретно НА ДАННОЙ странице
            string[] minAnchors = new string[] { "0.38 0.35", "0.24 0.35", "0.10 0.35", "0.03 0.35" };
            string[] maxAnchors = new string[] { "0.62 0.90", "0.48 0.90", "0.34 0.90", "0.24 0.90" };

            if (countOnPage == 1) { minAnchors[0] = "0.38 0.35"; maxAnchors[0] = "0.62 0.90"; }
            else if (countOnPage == 2) { minAnchors[0] = "0.24 0.35"; maxAnchors[0] = "0.48 0.90"; minAnchors[1] = "0.52 0.35"; maxAnchors[1] = "0.76 0.90"; }
            else if (countOnPage == 3) {
                minAnchors[0] = "0.10 0.35"; maxAnchors[0] = "0.34 0.90";
                minAnchors[1] = "0.38 0.35"; maxAnchors[1] = "0.62 0.90";
                minAnchors[2] = "0.66 0.35"; maxAnchors[2] = "0.90 0.90";
            }
            else if (countOnPage == 4) {
                minAnchors[0] = "0.03 0.35"; maxAnchors[0] = "0.24 0.90";
                minAnchors[1] = "0.26 0.35"; maxAnchors[1] = "0.47 0.90";
                minAnchors[2] = "0.49 0.35"; maxAnchors[2] = "0.70 0.90";
                minAnchors[3] = "0.72 0.35"; maxAnchors[3] = "0.93 0.90";
            }

            for (int i = 0; i < countOnPage; i++)
            {
                var kit = visibleKits[startIdx + i];
                string btnColor = string.IsNullOrEmpty(kit.Color) ? "0.41 0.51 0.32 1.0" : kit.Color;

                string kitBtn = container.Add(new CuiButton {
                    Button = { Command = "kit.claim " + kit.Name, Color = btnColor },
                    RectTransform = { AnchorMin = minAnchors[i], AnchorMax = maxAnchors[i] },
                    Text = { Text = "" }
                }, "KitMenuInner", "KitBlock_" + kit.Name);

                string kitText = (kit.DisplayName != null) ? kit.DisplayName.ToUpper() : "";
                container.Add(new CuiLabel {
                    Text = { Text = kitText, FontSize = 14, Align = TextAnchor.MiddleCenter, Color = "1 1 1 1" },
                    RectTransform = { AnchorMin = "0.05 0.50", AnchorMax = "0.95 0.95" }
                }, kitBtn);

                container.Add(new CuiLabel {
                    Text = { Text = "МОЖНО БРАТЬ", FontSize = 13, Align = TextAnchor.MiddleCenter, Color = "1 1 1 0.6" },
                    RectTransform = { AnchorMin = "0.05 0.05", AnchorMax = "0.95 0.50" }
                }, kitBtn);

                string[] minParts = minAnchors[i].Split(' ');
                string[] maxParts = maxAnchors[i].Split(' ');
                
                string previewMin = minParts[0] + " 0.02";
                string previewMax = maxParts[0] + " 0.26";

                container.Add(new CuiButton {
                    Button = { Command = "kit.previewui " + kit.Name, Color = "0.11 0.11 0.11 0.95" },
                    RectTransform = { AnchorMin = previewMin, AnchorMax = previewMax },
                    Text = { Text = "ПОДРОБНЕЕ", FontSize = 10, Align = TextAnchor.MiddleCenter, Color = "1 1 1 0.9" }
                }, "KitMenuInner");
            }

            // Динамические кнопки переключения страниц
            if (hasNextPage)
            {
                container.Add(new CuiButton {
                    Button = { Command = $"kit.changepage {currentPage + 1}", Color = "0.25 0.25 0.25 1.0" },
                    RectTransform = { AnchorMin = "0.94 0.15", AnchorMax = "0.99 0.45" },
                    Text = { Text = "▶", FontSize = 12, Align = TextAnchor.MiddleCenter, Color = "1 1 1 0.8" }
                }, "KitMenuInner");
            }

            if (hasPrevPage)
            {
                container.Add(new CuiButton {
                    Button = { Command = $"kit.changepage {currentPage - 1}", Color = "0.25 0.25 0.25 1.0" },
                    RectTransform = { AnchorMin = "0.01 0.15", AnchorMax = "0.06 0.45" },
                    Text = { Text = "◀", FontSize = 12, Align = TextAnchor.MiddleCenter, Color = "1 1 1 0.8" }
                }, "KitMenuInner");
            }

            CuiHelper.AddUi(player, container);
        }

        private void OpenKitPreview(BasePlayer player, string kitName)
        {
            DestroyAllKitUi(player);
            Kit kit = null;
            foreach (var k in kitsList)
            {
                if (k.Name != null && k.Name.ToLower() == kitName) { kit = k; break; }
            }
            if (kit == null) return;

            CuiElementContainer container = new CuiElementContainer();
            
            string bgPanel = container.Add(new CuiPanel { 
                Image = { Color = "0 0 0 0.4" }, 
                RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }, 
                CursorEnabled = true 
            }, "Overlay", "KitPreviewMenu");
            
            container.Add(new CuiButton { Button = { Command = "kit.closeui", Color = "0 0 0 0" }, RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" } }, bgPanel);
            
            container.Add(new CuiPanel { 
                Image = { Color = "0.14 0.14 0.14 0.95" }, 
                RectTransform = { AnchorMin = "0.08 0.44", AnchorMax = "0.92 0.56" } 
            }, bgPanel, "KitPreviewInner");

            container.Add(new CuiButton {
                Button = { Command = "kit.backtomenu", Color = "0.21 0.21 0.21 1.0" },
                RectTransform = { AnchorMin = "0.02 0.25", AnchorMax = "0.10 0.75" },
                Text = { Text = "НАЗАД", FontSize = 11, Align = TextAnchor.MiddleCenter, Color = "1 1 1 0.9" }
            }, "KitPreviewInner");

            // Координатная сетка для двух рядов (по 6 предметов в ряд, всего до 12 предметов)
            string[] row1Min = new string[] { "0.13 0.53", "0.26 0.53", "0.39 0.53", "0.52 0.53", "0.65 0.53", "0.78 0.53" };
            string[] row1Max = new string[] { "0.23 0.91", "0.36 0.91", "0.49 0.91", "0.62 0.91", "0.75 0.91", "0.88 0.91" };
            
            string[] row2Min = new string[] { "0.13 0.11", "0.26 0.11", "0.39 0.11", "0.52 0.11", "0.65 0.11", "0.78 0.11" };
            string[] row2Max = new string[] { "0.23 0.49", "0.36 0.49", "0.49 0.49", "0.62 0.49", "0.75 0.49", "0.88 0.49" };

            int itemIndex = 0;
            int totalItems = kit.Items.Count;

            // Если предметов мало (до 6), выстраиваем их строго по центру по вертикали, как и раньше
            bool useTwoRows = totalItems > 6;

            foreach (var item in kit.Items) 
            {
                if (itemIndex >= 12) break; // Лимит отображения в превью — 12 предметов
                
                ItemDefinition def = ItemManager.FindItemDefinition(item.ItemID);
                if (def == null) continue;

                string minAnchor = "";
                string maxAnchor = "";
                string labelMin = "";
                string labelMax = "";

                if (useTwoRows)
                {
                    // Логика двух рядов
                    if (itemIndex < 6)
                    {
                        minAnchor = row1Min[itemIndex];
                        maxAnchor = row1Max[itemIndex];
                        
                        // Текст количества прижимаем к низу иконки внутри первого ряда
                        string[] pMin = minAnchor.Split(' ');
                        string[] pMax = maxAnchor.Split(' ');
                        labelMin = pMin[0] + " 0.53";
                        labelMax = pMax[0] + " 0.65";
                    }
                    else
                    {
                        minAnchor = row2Min[itemIndex - 6];
                        maxAnchor = row2Max[itemIndex - 6];

                        string[] pMin = minAnchor.Split(' ');
                        string[] pMax = maxAnchor.Split(' ');
                        labelMin = pMin[0] + " 0.11";
                        labelMax = pMax[0] + " 0.23";
                    }
                }
                else
                {
                    // Один ряд по центру (если предметов <= 6)
                    string[] singleRowMin = new string[] { "0.13 0.25", "0.25 0.25", "0.37 0.25", "0.49 0.25", "0.61 0.25", "0.73 0.25" };
                    string[] singleRowMax = new string[] { "0.22 0.75", "0.34 0.75", "0.46 0.75", "0.58 0.75", "0.70 0.75", "0.82 0.75" };

                    minAnchor = singleRowMin[itemIndex];
                    maxAnchor = singleRowMax[itemIndex];

                    string[] pMin = minAnchor.Split(' ');
                    string[] pMax = maxAnchor.Split(' ');
                    labelMin = pMin[0] + " 0.06";
                    labelMax = pMax[0] + " 0.24";
                }

                // Отрисовка самой иконки предмета
                container.Add(new CuiElement
                {
                    Parent = "KitPreviewInner",
                    Components = {
                        new CuiImageComponent { Sprite = "assets/content/textures/generic/fulltransparent.tga", ItemId = item.ItemID },
                        new CuiRectTransformComponent { AnchorMin = minAnchor, AnchorMax = maxAnchor }
                    }
                });

                // Отрисовка надписи количества (например: x25)
                container.Add(new CuiLabel {
                    Text = { Text = "x" + item.Amount, FontSize = 10, Align = TextAnchor.MiddleCenter, Color = "1 1 1 0.85" },
                    RectTransform = { AnchorMin = labelMin, AnchorMax = labelMax }
                }, "KitPreviewInner");

                itemIndex++;
            }

            CuiHelper.AddUi(player, container);
        }

        private void SaveKits() => Interface.Oxide.DataFileSystem.WriteObject("Kits/KitsList", kitsList);
        private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject("Kits/PlayersData", PlayersData);
        void OnServerSave() { SaveData(); SaveKits(); }
    }
}