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

FREE NWGInfo : 1.0.0 1.0.0

Нет прав для скачивания
C#:
// Forced Recompile: 2026-02-07 11:15
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using Rust;
using Newtonsoft.Json;

namespace Oxide.Plugins
{
    [Info("NWG Info", "NWG Team", "1.0.0")]
    [Description("Unified Server Info UI and Map Marker Manager.")]
    public class NWGInfo : RustPlugin
    {
#region Config
        private class PluginConfig
        {
            public bool ShowOnJoin = true;
            public List<InfoTab> Tabs = new List<InfoTab>();
            public List<MapMarkerConfig> PermanentMarkers = new List<MapMarkerConfig>();
        }

        private class InfoTab
        {
            public string Name; // Button Text
            public string Title; // Header Text
            public List<string> Lines = new List<string>();
        }

        private class MapMarkerConfig
        {
            public string Name;
            public string DisplayName;
            public float X;
            public float Z;
            public float Radius;
            public string ColorHex; // RRGGBB
        }

        private PluginConfig _config;

        // Scroll state per player (reset on tab change or close)
        private readonly Dictionary<ulong, float> _playerScroll = new Dictionary<ulong, float>();
        private readonly Dictionary<ulong, int> _playerTabIndex = new Dictionary<ulong, int>();
        private const float ScrollStep = 0.2f;   // viewport units per click
        private const float LineHeight = 0.052f; // used for scroll range
        private const int LinesPerPage = 18;      // only this many lines rendered at once so content never overflows
#endregion

#region Lifecycle
        private void Init()
        {
            LoadConfigVariables();
        }

        private void LoadConfigVariables()
        {
            try
            {
                _config = Config.ReadObject<PluginConfig>();
                if (_config == null || _config.Tabs.Count == 0)
                {
                    LoadDefaultConfig();
                }
            }
            catch
            {
                LoadDefaultConfig();
            }
        }

        protected override void LoadDefaultConfig()
        {
            Puts("Creating new configuration file for NWG Info");
            _config = new PluginConfig();
            
            _config.Tabs.Add(new InfoTab 
            { 
                Name = "Welcome", 
                Title = "Welcome to NWG RUST", 
                Lines = new List<string> { 
                    "Welcome to our server!", 
                    "We provide a premium, customized experience.", 
                    "Check the 'Commands' tab to get started." 
                } 
            });

            _config.Tabs.Add(new InfoTab 
            { 
                Name = "Rules", 
                Title = "Server Rules", 
                Lines = new List<string> { 
                    "1. No cheating or scripting.", 
                    "2. No extreme toxicity or racism.", 
                    "3. Group limit: 8 per base/roam.",
                    "4. Respect staff decisions."
                } 
            });

            _config.Tabs.Add(new InfoTab 
            { 
                Name = "Commands", 
                Title = "Player Commands", 
                Lines = new List<string> { 
                    "<color=#b7d092>/shop</color> - Open the economics store",
                    "<color=#b7d092>/info</color> - Show this information menu",
                    "<color=#b7d092>/kit</color> - Claim a starting or reward kit",
                    "<color=#b7d092>/skin</color> - Change item skins (Hold item)",
                    "<color=#b7d092>/balance</color> - Check your wallet",
                    "<color=#b7d092>/sethome <name></color> - Set your current position as a home",
                    "<color=#b7d092>/home <name></color> - Teleport to your home",
                    "<color=#b7d092>/tpr <name></color> - Send a teleport request to a player",
                    "<color=#b7d092>/tpa</color> - Accept a pending teleport request",
                    "<color=#b7d092>/warp <name></color> - Teleport to a server location",
                    "<color=#b7d092>/setautocode <code></color> - Set your automatic lock code"
                } 
            });

            _config.Tabs.Add(new InfoTab 
            { 
                Name = "Admin", 
                Title = "Admin Commands", 
                Lines = new List<string> { 
                    "<color=#FF6B6B>/tools</color> - Open admin tool menu",
                    "<color=#FF6B6B>/setadminpass <pass></color> - Secure your admin session",
                    "<color=#FF6B6B>/adminduty</color> - Toggle Admin Duty",
                    "<color=#FF6B6B>/setbalance <player> <amt></color> - Set player balance",
                    "<color=#FF6B6B>/givemoney <player> <amt></color> - Give money to player",
                    "<color=#FF6B6B>/settime <0-24></color> - Set server time",
                    "<color=#FF6B6B>/setweather <type></color> - Set server weather",
                    "<color=#FF6B6B>/dungeon start global</color> - Start Global Dungeon",
                    "<color=#FF6B6B>/startraid</color> - Start Base Raid Event",
                    "<color=#FF6B6B>/spawnpiracy</color> - Spawn Pirate Tugboat",
                    "<color=#FF6B6B>/startrace</color> - Start Racing Event",
                    "<color=#FF6B6B>/tp <name></color> - Teleport to player",
                    "<color=#FF6B6B>/god</color> - Toggle god mode",
                    "<color=#FF6B6B>/vanish</color> - Toggle invisibility"
                } 
            });

            SaveConfig();
        }

#region Localization
        public static class Lang
        {
            public const string NoPermission = "NoPermission";
            public const string Title = "Title";
            public const string WelcomeTitle = "WelcomeTitle";
            public const string RulesTitle = "RulesTitle";
            public const string CommandsTitle = "CommandsTitle";
            public const string AdminTitle = "AdminTitle";
            public const string WelcomeBtn = "WelcomeBtn";
            public const string RulesBtn = "RulesBtn";
            public const string CommandsBtn = "CommandsBtn";
            public const string AdminBtn = "AdminBtn";
            public const string DefaultWelcome = "DefaultWelcome";
            public const string DefaultRules = "DefaultRules";
            public const string NoPlayerCmds = "NoPlayerCmds";
            public const string NoAdminCmds = "NoAdminCmds";
            
            // Command Descriptions
            public const string DescInfo = "DescInfo";
            public const string DescHelp = "DescHelp";
            public const string DescShop = "DescShop";
            public const string DescBalance = "DescBalance";
            public const string DescKit = "DescKit";
            public const string DescSkin = "DescSkin";
            public const string DescSetHome = "DescSetHome";
            public const string DescHome = "DescHome";
            public const string DescTpr = "DescTpr";
            public const string DescTpa = "DescTpa";
            public const string DescWarp = "DescWarp";
            public const string DescSetAutoCode = "DescSetAutoCode";
            public const string DescClan = "DescClan";
            public const string DescQuests = "DescQuests";
            public const string DescSkills = "DescSkills";
            public const string DescRates = "DescRates";
            public const string DescEvent = "DescEvent";
            public const string DescZone = "DescZone";
            public const string DescTools = "DescTools";
            public const string DescSetAdminPass = "DescSetAdminPass";
            public const string DescAdminDuty = "DescAdminDuty";
            public const string DescSetBalance = "DescSetBalance";
            public const string DescGiveMoney = "DescGiveMoney";
            public const string DescSetTime = "DescSetTime";
            public const string DescSetWeather = "DescSetWeather";
            public const string DescDungeon = "DescDungeon";
            public const string DescStartRaid = "DescStartRaid";
            public const string DescSpawnPiracy = "DescSpawnPiracy";
            public const string DescStartRace = "DescStartRace";
            public const string DescTp = "DescTp";
            public const string DescGod = "DescGod";
            public const string DescVanish = "DescVanish";
            public const string DescKick = "DescKick";
            public const string DescBan = "DescBan";
            public const string DescUnban = "DescUnban";
            public const string DescMute = "DescMute";
            public const string DescUnmute = "DescUnmute";
            public const string DescBring = "DescBring";
            public const string DescHeal = "DescHeal";
            public const string DescInvsee = "DescInvsee";
            public const string DescRemove = "DescRemove";
            public const string DescSetWarp = "DescSetWarp";
        }

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                [Lang.NoPermission] = "<color=#d9534f>[NWG]</color> You do not have permission to use this command.",
                [Lang.Title] = "SERVER INFORMATION",
                [Lang.WelcomeTitle] = "Welcome to NWG RUST",
                [Lang.RulesTitle] = "Server Rules",
                [Lang.CommandsTitle] = "Player Commands",
                [Lang.AdminTitle] = "Admin Commands",
                [Lang.WelcomeBtn] = "WELCOME",
                [Lang.RulesBtn] = "RULES",
                [Lang.CommandsBtn] = "COMMANDS",
                [Lang.AdminBtn] = "ADMIN",
                [Lang.DefaultWelcome] = "Welcome to our server!\nWe provide a premium, customized experience.\nCheck the 'Commands' tab to get started.",
                [Lang.DefaultRules] = "1. No cheating or scripting.\n2. No extreme toxicity or racism.\n3. Group limit: 8 per base/roam.\n4. Respect staff decisions.",
                [Lang.NoPlayerCmds] = "<color=#b7d092>[NWG]</color> <color=#b7d092>(No player commands loaded)</color>",
                [Lang.NoAdminCmds] = "<color=#d9534f>[NWG]</color> <color=#FF6B6B>(No admin commands loaded)</color>",

                // Command Descriptions
                [Lang.DescInfo] = "Show this information menu",
                [Lang.DescHelp] = "Show commands tab",
                [Lang.DescShop] = "Open the economics store",
                [Lang.DescBalance] = "Check your wallet",
                [Lang.DescKit] = "Claim a starting or reward kit",
                [Lang.DescSkin] = "Change item skins (hold item)",
                [Lang.DescSetHome] = "Set your current position as a home",
                [Lang.DescHome] = "Teleport to your home",
                [Lang.DescTpr] = "Send a teleport request to a player",
                [Lang.DescTpa] = "Accept a pending teleport request",
                [Lang.DescWarp] = "Teleport to a server location",
                [Lang.DescSetAutoCode] = "Set your automatic lock code",
                [Lang.DescClan] = "Clan management",
                [Lang.DescQuests] = "View and manage quests",
                [Lang.DescSkills] = "View and upgrade skills",
                [Lang.DescRates] = "View gather and XP rates",
                [Lang.DescEvent] = "Event information",
                [Lang.DescZone] = "Zone information",
                [Lang.DescTools] = "Open admin tool menu",
                [Lang.DescSetAdminPass] = "Secure your admin session",
                [Lang.DescAdminDuty] = "Toggle Admin Duty",
                [Lang.DescSetBalance] = "Set player balance",
                [Lang.DescGiveMoney] = "Give money to player",
                [Lang.DescSetTime] = "Set server time (0-24)",
                [Lang.DescSetWeather] = "Set server weather",
                [Lang.DescDungeon] = "Dungeon events (e.g. start global)",
                [Lang.DescStartRaid] = "Start Base Raid Event",
                [Lang.DescSpawnPiracy] = "Spawn Pirate Tugboat",
                [Lang.DescStartRace] = "Start Racing Event",
                [Lang.DescTp] = "Teleport to player",
                [Lang.DescGod] = "Toggle god mode",
                [Lang.DescVanish] = "Toggle invisibility",
                [Lang.DescKick] = "Kick a player",
                [Lang.DescBan] = "Ban a player",
                [Lang.DescUnban] = "Unban a player",
                [Lang.DescMute] = "Mute a player",
                [Lang.DescUnmute] = "Unmute a player",
                [Lang.DescBring] = "Bring a player to you",
                [Lang.DescHeal] = "Heal a player",
                [Lang.DescInvsee] = "View player inventory",
                [Lang.DescRemove] = "Remove building (admin)",
                [Lang.DescSetWarp] = "Create a warp point"
            }, this);
        }

        private string GetMessage(string key, string userId, params object[] args) => string.Format(lang.GetMessage(key, this, userId), args);
#endregion

        private void OnServerInitialized()
        {
            SpawnPermanentMarkers();
        }

        private void Unload()
        {
            foreach (var player in BasePlayer.activePlayerList)
            {
                CuiHelper.DestroyUi(player, "NWG_Info_UI");
            }
            CleanupMarkers();
        }

        private void OnPlayerConnected(BasePlayer player)
        {
            if (_config.ShowOnJoin)
            {
                timer.Once(2f, () => 
                {
                    if (player != null && player.IsConnected) ShowInfoUI(player);
                });
            }
        }
#endregion

#region Command Scraping
        // Commands that appear in the Admin tab (all others go to Player Commands)
        private static readonly HashSet<string> AdminCommandNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        {
            "setadminpass", "login", "vanish", "radar", "god", "kick", "ban", "unban", "mute", "unmute",
            "freeze", "unfreeze", "strip", "whois", "heal", "tp", "tphere", "up", "repair", "entkill",
            "settime", "setweather", "spawnhere", "rocket", "cmdlist", "testall", "tasks",
            "adminduty", "tools", "grantvip", "revokevip", "bring", "invsee",
            "startraid", "spawnpiracy", "startrace", "setbalance", "givemoney", "setwarp", "remove", "dungeon", "adminhelp"
        };

        private struct ScrapedCommand { public string Command; public string PluginName; }

        private List<ScrapedCommand> GetAllPluginChatCommands()
        {
            var list = new List<ScrapedCommand>();
            try
            {
                var plugins = Interface.Oxide.RootPluginManager.GetPlugins();
                if (plugins == null) return list;
                foreach (var plugin in plugins)
                {
                    if (plugin == null || !plugin.IsLoaded) continue;
                    var type = plugin.GetType();
                    if (type == null) continue;
                    string pluginName = plugin.Name ?? type.Name;
                    var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                    if (methods == null) continue;
                    foreach (var method in methods)
                    {
                        var attr = method.GetCustomAttributes(typeof(ChatCommandAttribute), true).FirstOrDefault() as ChatCommandAttribute;
                        if (attr != null && !string.IsNullOrEmpty(attr.Command))
                            list.Add(new ScrapedCommand { Command = attr.Command.Trim().ToLower(), PluginName = pluginName });
                    }
                }
                return list.GroupBy(x => x.Command).Select(g => g.First()).OrderBy(x => x.Command).ToList();
            }
            catch (Exception ex) { Puts($"NWGInfo command scrape error: {ex.Message}"); }
            return list;
        }

        private List<string> GetPlayerCommandLines()
        {
            const string color = "#b7d092";
            var lines = new List<string>();
            foreach (var c in GetAllPluginChatCommands())
            {
                if (AdminCommandNames.Contains(c.Command)) continue;
                lines.Add($"<color={color}>/{c.Command}</color> - {GetCommandDescription(c.Command, c.PluginName, false, Interface.Oxide.CallHook("GetPlayerUserId")?.ToString() ?? "0")}");
            }
            return lines.Count > 0 ? lines : new List<string> { GetMessage(Lang.NoPlayerCmds, "0") };
        }

        private List<string> GetAdminCommandLines()
        {
            const string color = "#FF6B6B";
            var lines = new List<string>();
            foreach (var c in GetAllPluginChatCommands())
            {
                if (!AdminCommandNames.Contains(c.Command)) continue;
                lines.Add($"<color={color}>/{c.Command}</color> - {GetCommandDescription(c.Command, c.PluginName, true, Interface.Oxide.CallHook("GetPlayerUserId")?.ToString() ?? "0")}");
            }
            return lines.Count > 0 ? lines : new List<string> { GetMessage(Lang.NoAdminCmds, "0") };
        }

        private string GetCommandDescription(string command, string pluginName, bool admin, string userId)
        {
            var desc = GetKnownDescription(command, userId);
            return !string.IsNullOrEmpty(desc) ? desc : (admin ? "Admin" : pluginName);
        }

        private string GetKnownDescription(string command, string userId)
        {
            switch (command.ToLowerInvariant())
            {
                case "info": return GetMessage(Lang.DescInfo, userId);
                case "help": return GetMessage(Lang.DescHelp, userId);
                case "shop": return GetMessage(Lang.DescShop, userId);
                case "balance": return GetMessage(Lang.DescBalance, userId);
                case "kit": return GetMessage(Lang.DescKit, userId);
                case "skin": return GetMessage(Lang.DescSkin, userId);
                case "sethome": return GetMessage(Lang.DescSetHome, userId);
                case "home": return GetMessage(Lang.DescHome, userId);
                case "tpr": return GetMessage(Lang.DescTpr, userId);
                case "tpa": return GetMessage(Lang.DescTpa, userId);
                case "warp": return GetMessage(Lang.DescWarp, userId);
                case "setautocode": return GetMessage(Lang.DescSetAutoCode, userId);
                case "clan": return GetMessage(Lang.DescClan, userId);
                case "quests": return GetMessage(Lang.DescQuests, userId);
                case "skills": return GetMessage(Lang.DescSkills, userId);
                case "rates": return GetMessage(Lang.DescRates, userId);
                case "event": return GetMessage(Lang.DescEvent, userId);
                case "zone": return GetMessage(Lang.DescZone, userId);
                case "tools": return GetMessage(Lang.DescTools, userId);
                case "setadminpass": return GetMessage(Lang.DescSetAdminPass, userId);
                case "adminduty": return GetMessage(Lang.DescAdminDuty, userId);
                case "setbalance": return GetMessage(Lang.DescSetBalance, userId);
                case "givemoney": return GetMessage(Lang.DescGiveMoney, userId);
                case "settime": return GetMessage(Lang.DescSetTime, userId);
                case "setweather": return GetMessage(Lang.DescSetWeather, userId);
                case "dungeon": return GetMessage(Lang.DescDungeon, userId);
                case "startraid": return GetMessage(Lang.DescStartRaid, userId);
                case "spawnpiracy": return GetMessage(Lang.DescSpawnPiracy, userId);
                case "startrace": return GetMessage(Lang.DescStartRace, userId);
                case "tp": return GetMessage(Lang.DescTp, userId);
                case "god": return GetMessage(Lang.DescGod, userId);
                case "vanish": return GetMessage(Lang.DescVanish, userId);
                case "kick": return GetMessage(Lang.DescKick, userId);
                case "ban": return GetMessage(Lang.DescBan, userId);
                case "unban": return GetMessage(Lang.DescUnban, userId);
                case "mute": return GetMessage(Lang.DescMute, userId);
                case "unmute": return GetMessage(Lang.DescUnmute, userId);
                case "bring": return GetMessage(Lang.DescBring, userId);
                case "heal": return GetMessage(Lang.DescHeal, userId);
                case "invsee": return GetMessage(Lang.DescInvsee, userId);
                case "remove": return GetMessage(Lang.DescRemove, userId);
                case "setwarp": return GetMessage(Lang.DescSetWarp, userId);
                default: return null;
            }
        }
#endregion

#region Info UI
        [ChatCommand("info")]
        private void CmdInfo(BasePlayer player)
        {
            ShowInfoUI(player);
        }

        [ChatCommand("help")]
        private void CmdHelp(BasePlayer player)
        {
            int cmdTab = _config.Tabs.FindIndex(t => t.Name.Equals("Commands", StringComparison.OrdinalIgnoreCase));
            ShowInfoUI(player, cmdTab >= 0 ? cmdTab : 0);
        }

        [ChatCommand("adminhelp")]
        private void CmdAdminHelp(BasePlayer player)
        {
            if (!player.IsAdmin)
            {
                SendReply(player, GetMessage(Lang.NoPermission, player.UserIDString));
                return;
            }
            int adminTab = _config.Tabs.FindIndex(t => t.Name.Equals("Admin", StringComparison.OrdinalIgnoreCase));
            ShowInfoUI(player, adminTab >= 0 ? adminTab : 0);
        }

        [ConsoleCommand("nwg_info.close")]
        private void ConsoleClose(ConsoleSystem.Arg arg)
        {
            var player = arg.Player();
            if (player != null)
            {
                CuiHelper.DestroyUi(player, "NWG_Info_UI");
                _playerScroll.Remove(player.userID);
                _playerTabIndex.Remove(player.userID);
            }
        }

        [ConsoleCommand("nwg_info.tab")]
        private void ConsoleTab(ConsoleSystem.Arg arg)
        {
            var player = arg.Player();
            if (player == null) return;
            int index = arg.GetInt(0);
            ShowInfoUI(player, index);
        }

        [ConsoleCommand("nwg_info.scroll")]
        private void ConsoleScroll(ConsoleSystem.Arg arg)
        {
            var player = arg.Player();
            if (player == null) return;
            int direction = arg.GetInt(0); // 1 = scroll down (see more below), -1 = scroll up
            if (direction == 0) return;
            if (!_playerTabIndex.TryGetValue(player.userID, out int tabIndex)) return;
            int lineCount = GetContentLineCountForTab(tabIndex);
            float maxScroll = Math.Max(0f, (lineCount - LinesPerPage) * LineHeight);
            float scroll = _playerScroll.TryGetValue(player.userID, out float s) ? s : 0f;
            scroll += direction * ScrollStep;
            scroll = Math.Max(0f, Math.Min(scroll, maxScroll));
            _playerScroll[player.userID] = scroll;
            ShowInfoUI(player, tabIndex);
        }

        private int GetContentLineCountForTab(int tabIndex)
        {
            if (tabIndex < 0 || tabIndex >= _config.Tabs.Count) return 0;
            var tab = _config.Tabs[tabIndex];
            if (tab.Name != null && tab.Name.Equals("Commands", StringComparison.OrdinalIgnoreCase))
                return GetPlayerCommandLines().Count;
            if (tab.Name != null && tab.Name.Equals("Admin", StringComparison.OrdinalIgnoreCase))
                return GetAdminCommandLines().Count;
            return (tab.Lines ?? new List<string>()).Count;
        }

        private void ShowInfoUI(BasePlayer player, int tabIndex = 0)
        {
            CuiHelper.DestroyUi(player, "NWG_Info_UI");

            if (_playerTabIndex.TryGetValue(player.userID, out int prevTab) && prevTab != tabIndex)
                _playerScroll.Remove(player.userID);
            _playerTabIndex[player.userID] = tabIndex;

            var elements = new CuiElementContainer();
            var root = elements.Add(new CuiPanel {
                Image = { Color = "0.05 0.05 0.05 0.95" },
                RectTransform = { AnchorMin = "0.1 0.1", AnchorMax = "0.9 0.9" },
                CursorEnabled = true
            }, "Overlay", "NWG_Info_UI");

            // Header Background
            elements.Add(new CuiPanel {
                Image = { Color = "0.4 0.6 0.2 0.3" },
                RectTransform = { AnchorMin = "0 0.9", AnchorMax = "1 1" }
            }, root);

            // Header Title
            elements.Add(new CuiLabel {
                Text = { Text = GetMessage(Lang.Title, player.UserIDString), FontSize = 28, Align = TextAnchor.MiddleLeft, Font = "robotocondensed-bold.ttf" },
                RectTransform = { AnchorMin = "0.02 0.9", AnchorMax = "0.5 1" }
            }, root);

            // Sidebar Background
            elements.Add(new CuiPanel {
                Image = { Color = "0.1 0.1 0.1 0.5" },
                RectTransform = { AnchorMin = "0 0.08", AnchorMax = "0.2 0.9" }
            }, root);

            // Tabs
            float btnHeight = 0.07f;
            float btnGap = 0.01f;
            float startY = 0.82f;

            for(int i=0; i<_config.Tabs.Count; i++)
            {
                var tab = _config.Tabs[i];
                bool active = (i == tabIndex);
                string color = active ? "0.4 0.6 0.2 0.8" : "0.2 0.2 0.2 0.5";

                elements.Add(new CuiButton {
                    Button = { Command = $"nwg_info.tab {i}", Color = color },
                    RectTransform = { AnchorMin = $"0.01 {startY - btnHeight}", AnchorMax = $"0.19 {startY}" },
                    Text = { Text = tab.Name.ToUpper(), Align = TextAnchor.MiddleCenter, FontSize = 13, Font = "robotocondensed-bold.ttf" }
                }, root);

                startY -= (btnHeight + btnGap);
            }

            // Close Button (Standardized Position)
            elements.Add(new CuiButton {
                Button = { Command = "nwg_info.close", Color = "0.8 0.1 0.1 0.9" },
                RectTransform = { AnchorMin = "0.95 0.925", AnchorMax = "0.985 0.975" },
                Text = { Text = "✕", FontSize = 20, Align = TextAnchor.MiddleCenter }
            }, root);

            // Content Area
            if (tabIndex >= 0 && tabIndex < _config.Tabs.Count)
            {
                var tab = _config.Tabs[tabIndex];
                List<string> contentLines;
                if (tab.Name != null && tab.Name.Equals("Commands", StringComparison.OrdinalIgnoreCase))
                    contentLines = GetPlayerCommandLines();
                else if (tab.Name != null && tab.Name.Equals("Admin", StringComparison.OrdinalIgnoreCase))
                    contentLines = GetAdminCommandLines();
                else
                    contentLines = tab.Lines ?? new List<string>();

                var contentPanel = elements.Add(new CuiPanel {
                    Image = { Color = "0.15 0.15 0.15 0.8" },
                    RectTransform = { AnchorMin = "0.22 0.05", AnchorMax = "0.98 0.88" }
                }, root);

                elements.Add(new CuiLabel {
                    Text = { Text = tab.Title, FontSize = 22, Align = TextAnchor.UpperCenter, Font = "robotocondensed-bold.ttf", Color = "#b7d092" },
                    RectTransform = { AnchorMin = "0 0.9", AnchorMax = "1 1" }
                }, contentPanel);

                int lineCount = contentLines.Count > 0 ? contentLines.Count : 1;
                float maxScroll = Math.Max(0f, (lineCount - LinesPerPage) * LineHeight);
                float scroll = _playerScroll.TryGetValue(player.userID, out float s) ? Math.Max(0f, Math.Min(s, maxScroll)) : 0f;
                _playerScroll[player.userID] = scroll;

                // Only render visible lines so content stays inside the UI (no overflow)
                int startIndex = (int)(scroll / LineHeight);
                if (startIndex > lineCount - LinesPerPage) startIndex = Math.Max(0, lineCount - LinesPerPage);
                int endIndex = Math.Min(startIndex + LinesPerPage, lineCount);
                var visibleLines = new List<string>();
                for (int i = startIndex; i < endIndex; i++) visibleLines.Add(contentLines[i]);
                string fullText = visibleLines.Count > 0 ? string.Join("\n", visibleLines) : "";

                var viewport = elements.Add(new CuiPanel {
                    Image = { Color = "0 0 0 0" },
                    RectTransform = { AnchorMin = "0.05 0.05", AnchorMax = "0.92 0.88" }
                }, contentPanel);

                var scrollContent = elements.Add(new CuiPanel {
                    Image = { Color = "0 0 0 0" },
                    RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }
                }, viewport);

                elements.Add(new CuiLabel {
                    Text = { Text = fullText, FontSize = 16, Align = TextAnchor.UpperLeft, Font = "robotocondensed-regular.ttf" },
                    RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }
                }, scrollContent);

                if (maxScroll > 0.001f)
                {
                    elements.Add(new CuiButton {
                        Button = { Command = "nwg_info.scroll -1", Color = "0.25 0.25 0.25 0.9" },
                        RectTransform = { AnchorMin = "0.93 0.75", AnchorMax = "0.98 0.88" },
                        Text = { Text = "â–²", FontSize = 18, Align = TextAnchor.MiddleCenter }
                    }, contentPanel);
                    elements.Add(new CuiButton {
                        Button = { Command = "nwg_info.scroll 1", Color = "0.25 0.25 0.25 0.9" },
                        RectTransform = { AnchorMin = "0.93 0.05", AnchorMax = "0.98 0.18" },
                        Text = { Text = "â–¼", FontSize = 18, Align = TextAnchor.MiddleCenter }
                    }, contentPanel);
                }
            }

            CuiHelper.AddUi(player, elements);
        }
#endregion

#region Map Markers
        private List<BaseEntity> _spawnedMarkers = new List<BaseEntity>();

        private void SpawnPermanentMarkers()
        {
            CleanupMarkers();
            foreach(var markerCfg in _config.PermanentMarkers)
            {
                CreateMarker(new Vector3(markerCfg.X, 0, markerCfg.Z), markerCfg.Radius, markerCfg.DisplayName, markerCfg.ColorHex);
            }
        }

        private void CleanupMarkers()
        {
            foreach(var ent in _spawnedMarkers)
            {
                if (ent != null && !ent.IsDestroyed) ent.Kill();
            }
            _spawnedMarkers.Clear();
        }

        // Public API
        public void CreateMarker(Vector3 pos, float radius, string label, string colorHex)
        {
            // Vending Machine Marker
            var vmPrefab = "assets/prefabs/deployable/vendingmachine/vending_mapmarker.prefab";
            var vm = GameManager.server.CreateEntity(vmPrefab, pos) as VendingMachineMapMarker;
            if (vm == null) return;
            
            vm.markerShopName = label;
            vm.enableSaving = false;
            vm.Spawn();
            _spawnedMarkers.Add(vm);

            // Radius (Generic)
            var radiusPrefab = "assets/prefabs/tools/map/genericradiusmarker.prefab";
            var rad = GameManager.server.CreateEntity(radiusPrefab, pos) as MapMarkerGenericRadius;
            if (rad == null) return;

            rad.alpha = 0.5f;
            rad.radius = radius;
            Color color = Color.cyan;
            ColorUtility.TryParseHtmlString("#" + colorHex, out color);
            rad.color1 = color;
            rad.color2 = color;
            rad.enableSaving = false;
            rad.SetParent(vm); // Bind location
            rad.Spawn();
            // Note: MapMarkerGenericRadius usually needs to be updated or sent? 
            // VendingMachineMapMarker handles the map dot.
            // GenericRadius handles the circle.
        }
#endregion
    }
}

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