All checks were successful
Test Asgard Runner / test (push) Successful in 2s
Standalone C# uMod plugin that provides a full-screen CUI teleport interface for Rust game servers, integrating with NTeleportation. Features: - /tpgui chat command opens tabbed overlay (Teleport, Homes, Warps, Settings) - 4x5 player grid with search filtering and pagination for TPR - Home management (teleport, set, delete) via NTeleportation API - Server warp list with teleport buttons - Incoming TPR accept/deny popup with 30s auto-dismiss - Settings tab showing cooldowns, limits, NTeleportation status - Oxide-orange color scheme matching Corrosion brand Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1556 lines
54 KiB
C#
1556 lines
54 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Oxide.Core;
|
|
using Oxide.Core.Plugins;
|
|
using Oxide.Game.Rust.Cui;
|
|
using UnityEngine;
|
|
|
|
namespace Oxide.Plugins
|
|
{
|
|
[Info("CorrosionTeleportGUI", "Corrosion", "1.0.0")]
|
|
[Description("Beautiful in-game teleport GUI that integrates with NTeleportation")]
|
|
public class CorrosionTeleportGUI : RustPlugin
|
|
{
|
|
#region Constants
|
|
|
|
private const string MainPanel = "CorrosionTP_Main";
|
|
private const string PopupPanel = "CorrosionTP_Popup";
|
|
|
|
private const int GridColumns = 4;
|
|
private const int GridRows = 5;
|
|
private const int PlayersPerPage = GridColumns * GridRows;
|
|
private const float PopupTimeout = 30f;
|
|
|
|
// Color scheme
|
|
private const string ColorOverlay = "0.05 0.05 0.05 0.95";
|
|
private const string ColorPanel = "0.1 0.1 0.1 0.98";
|
|
private const string ColorTabActive = "0.8 0.4 0.2 1";
|
|
private const string ColorTabInactive = "0.2 0.2 0.2 1";
|
|
private const string ColorButtonHover = "0.3 0.3 0.3 1";
|
|
private const string ColorText = "1 1 1 1";
|
|
private const string ColorTextMuted = "0.7 0.7 0.7 1";
|
|
private const string ColorAccept = "0.2 0.6 0.2 0.9";
|
|
private const string ColorDeny = "0.6 0.2 0.2 0.9";
|
|
private const string ColorClose = "0.6 0.2 0.2 0.8";
|
|
private const string ColorTransparent = "0 0 0 0";
|
|
private const string ColorInputBg = "0.15 0.15 0.15 1";
|
|
private const string ColorCardBg = "0.14 0.14 0.14 1";
|
|
private const string ColorDivider = "0.25 0.25 0.25 1";
|
|
private const string ColorSettingLabel = "0.5 0.5 0.5 1";
|
|
|
|
#endregion
|
|
|
|
#region Fields
|
|
|
|
[PluginReference]
|
|
private Plugin NTeleportation;
|
|
|
|
private Dictionary<ulong, int> playerPages = new Dictionary<ulong, int>();
|
|
private Dictionary<ulong, string> playerSearches = new Dictionary<ulong, string>();
|
|
private Dictionary<ulong, string> playerTabs = new Dictionary<ulong, string>();
|
|
private Dictionary<ulong, Timer> popupTimers = new Dictionary<ulong, Timer>();
|
|
private List<BasePlayer> cachedPlayers = new List<BasePlayer>();
|
|
|
|
#endregion
|
|
|
|
#region Lifecycle Hooks
|
|
|
|
private void OnServerInitialized()
|
|
{
|
|
if (NTeleportation == null)
|
|
{
|
|
PrintWarning("NTeleportation plugin not found! Teleport functionality will be limited.");
|
|
PrintWarning("Install NTeleportation from uMod for full functionality.");
|
|
}
|
|
else
|
|
{
|
|
Puts("NTeleportation detected — full integration enabled.");
|
|
}
|
|
|
|
RefreshPlayerCache();
|
|
Puts("CorrosionTeleportGUI initialized.");
|
|
}
|
|
|
|
private void Unload()
|
|
{
|
|
foreach (var player in BasePlayer.activePlayerList)
|
|
{
|
|
DestroyUI(player);
|
|
DestroyPopupUI(player);
|
|
}
|
|
|
|
foreach (var kvp in popupTimers)
|
|
{
|
|
kvp.Value?.Destroy();
|
|
}
|
|
|
|
popupTimers.Clear();
|
|
playerPages.Clear();
|
|
playerSearches.Clear();
|
|
playerTabs.Clear();
|
|
cachedPlayers.Clear();
|
|
}
|
|
|
|
private void OnPlayerConnected(BasePlayer player)
|
|
{
|
|
if (player == null) return;
|
|
if (!cachedPlayers.Contains(player))
|
|
cachedPlayers.Add(player);
|
|
}
|
|
|
|
private void OnPlayerDisconnected(BasePlayer player, string reason)
|
|
{
|
|
if (player == null) return;
|
|
cachedPlayers.Remove(player);
|
|
playerPages.Remove(player.userID);
|
|
playerSearches.Remove(player.userID);
|
|
playerTabs.Remove(player.userID);
|
|
|
|
if (popupTimers.TryGetValue(player.userID, out var popupTimer))
|
|
{
|
|
popupTimer?.Destroy();
|
|
popupTimers.Remove(player.userID);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Chat Command
|
|
|
|
[ChatCommand("tpgui")]
|
|
private void CmdTeleportGUI(BasePlayer player, string command, string[] args)
|
|
{
|
|
if (player == null) return;
|
|
|
|
playerPages[player.userID] = 0;
|
|
playerSearches[player.userID] = string.Empty;
|
|
playerTabs[player.userID] = "teleport";
|
|
|
|
ShowMainPanel(player);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Console Commands
|
|
|
|
[ConsoleCommand("tpgui.close")]
|
|
private void CmdClose(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
DestroyUI(player);
|
|
playerPages.Remove(player.userID);
|
|
playerSearches.Remove(player.userID);
|
|
playerTabs.Remove(player.userID);
|
|
}
|
|
|
|
[ConsoleCommand("tpgui.tab")]
|
|
private void CmdTab(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
string tab = arg.GetString(0, "teleport");
|
|
playerTabs[player.userID] = tab;
|
|
playerPages[player.userID] = 0;
|
|
playerSearches[player.userID] = string.Empty;
|
|
|
|
ShowMainPanel(player);
|
|
}
|
|
|
|
[ConsoleCommand("tpgui.search")]
|
|
private void CmdSearch(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
string search = arg.GetString(0, string.Empty);
|
|
playerSearches[player.userID] = search;
|
|
playerPages[player.userID] = 0;
|
|
|
|
ShowMainPanel(player);
|
|
}
|
|
|
|
[ConsoleCommand("tpgui.page")]
|
|
private void CmdPage(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
string direction = arg.GetString(0, "next");
|
|
int currentPage = GetPlayerPage(player);
|
|
|
|
if (direction == "next")
|
|
playerPages[player.userID] = currentPage + 1;
|
|
else if (direction == "prev" && currentPage > 0)
|
|
playerPages[player.userID] = currentPage - 1;
|
|
|
|
ShowMainPanel(player);
|
|
}
|
|
|
|
[ConsoleCommand("tpgui.tpr")]
|
|
private void CmdTPR(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
string targetName = arg.GetString(0, string.Empty);
|
|
if (string.IsNullOrEmpty(targetName))
|
|
{
|
|
player.ChatMessage("<color=#CD6632>[Corrosion TP]</color> No target specified.");
|
|
return;
|
|
}
|
|
|
|
DestroyUI(player);
|
|
player.SendConsoleCommand("chat.say", "/tpr " + targetName);
|
|
player.ChatMessage($"<color=#CD6632>[Corrosion TP]</color> Teleport request sent to <color=#FFFFFF>{targetName}</color>.");
|
|
}
|
|
|
|
[ConsoleCommand("tpgui.home")]
|
|
private void CmdHome(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
string homeName = arg.GetString(0, string.Empty);
|
|
if (string.IsNullOrEmpty(homeName))
|
|
{
|
|
player.ChatMessage("<color=#CD6632>[Corrosion TP]</color> No home specified.");
|
|
return;
|
|
}
|
|
|
|
DestroyUI(player);
|
|
player.SendConsoleCommand("chat.say", "/home " + homeName);
|
|
}
|
|
|
|
[ConsoleCommand("tpgui.sethome")]
|
|
private void CmdSetHome(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
string homeName = arg.GetString(0, "home");
|
|
DestroyUI(player);
|
|
player.SendConsoleCommand("chat.say", "/sethome " + homeName);
|
|
player.ChatMessage($"<color=#CD6632>[Corrosion TP]</color> Setting home '<color=#FFFFFF>{homeName}</color>' at current position...");
|
|
}
|
|
|
|
[ConsoleCommand("tpgui.removehome")]
|
|
private void CmdRemoveHome(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
string homeName = arg.GetString(0, string.Empty);
|
|
if (string.IsNullOrEmpty(homeName))
|
|
{
|
|
player.ChatMessage("<color=#CD6632>[Corrosion TP]</color> No home specified.");
|
|
return;
|
|
}
|
|
|
|
player.SendConsoleCommand("chat.say", "/removehome " + homeName);
|
|
player.ChatMessage($"<color=#CD6632>[Corrosion TP]</color> Removing home '<color=#FFFFFF>{homeName}</color>'...");
|
|
|
|
// Refresh the panel after a short delay to allow NTeleportation to process
|
|
timer.Once(0.5f, () =>
|
|
{
|
|
if (player != null && player.IsConnected)
|
|
ShowMainPanel(player);
|
|
});
|
|
}
|
|
|
|
[ConsoleCommand("tpgui.warp")]
|
|
private void CmdWarp(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
string warpName = arg.GetString(0, string.Empty);
|
|
if (string.IsNullOrEmpty(warpName))
|
|
{
|
|
player.ChatMessage("<color=#CD6632>[Corrosion TP]</color> No warp specified.");
|
|
return;
|
|
}
|
|
|
|
DestroyUI(player);
|
|
player.SendConsoleCommand("chat.say", "/warp " + warpName);
|
|
}
|
|
|
|
[ConsoleCommand("tpgui.accept")]
|
|
private void CmdAccept(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
DestroyPopupUI(player);
|
|
player.SendConsoleCommand("chat.say", "/tpa");
|
|
}
|
|
|
|
[ConsoleCommand("tpgui.deny")]
|
|
private void CmdDeny(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
DestroyPopupUI(player);
|
|
player.SendConsoleCommand("chat.say", "/tpc");
|
|
}
|
|
|
|
[ConsoleCommand("tpgui.popup.close")]
|
|
private void CmdPopupClose(ConsoleSystem.Arg arg)
|
|
{
|
|
var player = arg.Connection?.player as BasePlayer;
|
|
if (player == null) return;
|
|
|
|
DestroyPopupUI(player);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region NTeleportation Hooks
|
|
|
|
/// <summary>
|
|
/// Hook called by NTeleportation when a player receives a teleport request.
|
|
/// Shows the accept/deny popup to the target player.
|
|
/// </summary>
|
|
private void OnTeleportRequested(BasePlayer target, BasePlayer requester)
|
|
{
|
|
if (target == null || requester == null) return;
|
|
ShowTPRPopup(target, requester.displayName);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Main Panel
|
|
|
|
private void ShowMainPanel(BasePlayer player)
|
|
{
|
|
DestroyUI(player);
|
|
RefreshPlayerCache();
|
|
|
|
string activeTab = GetPlayerTab(player);
|
|
var container = new CuiElementContainer();
|
|
|
|
// Full-screen overlay background
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorOverlay },
|
|
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
|
|
CursorEnabled = true
|
|
}, "Overlay", MainPanel);
|
|
|
|
// Main panel body
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorPanel },
|
|
RectTransform = { AnchorMin = "0.15 0.1", AnchorMax = "0.85 0.9" }
|
|
}, MainPanel, MainPanel + "_Body");
|
|
|
|
// --- Header ---
|
|
AddHeader(ref container, player, activeTab);
|
|
|
|
// --- Tab Content ---
|
|
switch (activeTab)
|
|
{
|
|
case "teleport":
|
|
ShowTeleportTab(ref container, player);
|
|
break;
|
|
case "homes":
|
|
ShowHomesTab(ref container, player);
|
|
break;
|
|
case "warps":
|
|
ShowWarpsTab(ref container, player);
|
|
break;
|
|
case "settings":
|
|
ShowSettingsTab(ref container, player);
|
|
break;
|
|
}
|
|
|
|
CuiHelper.AddUi(player, container);
|
|
}
|
|
|
|
private void AddHeader(ref CuiElementContainer container, BasePlayer player, string activeTab)
|
|
{
|
|
string body = MainPanel + "_Body";
|
|
|
|
// Header background
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = "0.08 0.08 0.08 1" },
|
|
RectTransform = { AnchorMin = "0 0.88", AnchorMax = "1 1" }
|
|
}, body, body + "_Header");
|
|
|
|
// Title
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = "CORROSION TELEPORT",
|
|
FontSize = 18,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorTabActive,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.03 0", AnchorMax = "0.3 1" }
|
|
}, body + "_Header");
|
|
|
|
// Tab buttons
|
|
float tabStart = 0.32f;
|
|
float tabWidth = 0.12f;
|
|
float tabGap = 0.005f;
|
|
|
|
string[] tabs = { "teleport", "homes", "warps" };
|
|
string[] tabLabels = { "TELEPORT", "HOMES", "WARPS" };
|
|
|
|
for (int i = 0; i < tabs.Length; i++)
|
|
{
|
|
float xMin = tabStart + i * (tabWidth + tabGap);
|
|
float xMax = xMin + tabWidth;
|
|
string color = activeTab == tabs[i] ? ColorTabActive : ColorTabInactive;
|
|
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = color,
|
|
Command = $"tpgui.tab {tabs[i]}"
|
|
},
|
|
Text =
|
|
{
|
|
Text = tabLabels[i],
|
|
FontSize = 12,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = $"{xMin} 0.2", AnchorMax = $"{xMax} 0.8" }
|
|
}, body + "_Header");
|
|
}
|
|
|
|
// Settings gear button
|
|
float settingsX = tabStart + tabs.Length * (tabWidth + tabGap);
|
|
string settingsColor = activeTab == "settings" ? ColorTabActive : ColorTabInactive;
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = settingsColor,
|
|
Command = "tpgui.tab settings"
|
|
},
|
|
Text =
|
|
{
|
|
Text = "⚙",
|
|
FontSize = 16,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText
|
|
},
|
|
RectTransform = { AnchorMin = $"{settingsX} 0.2", AnchorMax = $"{settingsX + 0.05f} 0.8" }
|
|
}, body + "_Header");
|
|
|
|
// Close button
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = ColorClose,
|
|
Command = "tpgui.close"
|
|
},
|
|
Text =
|
|
{
|
|
Text = "✕",
|
|
FontSize = 16,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.93 0.2", AnchorMax = "0.98 0.8" }
|
|
}, body + "_Header");
|
|
|
|
// Divider line below header
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorTabActive },
|
|
RectTransform = { AnchorMin = "0 0.875", AnchorMax = "1 0.878" }
|
|
}, body);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Teleport Tab
|
|
|
|
private void ShowTeleportTab(ref CuiElementContainer container, BasePlayer player)
|
|
{
|
|
string body = MainPanel + "_Body";
|
|
|
|
// Content area
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorTransparent },
|
|
RectTransform = { AnchorMin = "0.02 0.02", AnchorMax = "0.98 0.86" }
|
|
}, body, body + "_TeleportContent");
|
|
|
|
string content = body + "_TeleportContent";
|
|
|
|
// Search bar background
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorInputBg },
|
|
RectTransform = { AnchorMin = "0 0.9", AnchorMax = "0.75 0.98" }
|
|
}, content, content + "_SearchBg");
|
|
|
|
// Search label
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = " 🔍 Search players...",
|
|
FontSize = 12,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorTextMuted,
|
|
Font = "robotocondensed-regular.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }
|
|
}, content + "_SearchBg");
|
|
|
|
// Search input field
|
|
container.Add(new CuiElement
|
|
{
|
|
Name = content + "_SearchInput",
|
|
Parent = content + "_SearchBg",
|
|
Components =
|
|
{
|
|
new CuiInputFieldComponent
|
|
{
|
|
Text = GetPlayerSearch(player),
|
|
FontSize = 12,
|
|
Color = ColorText,
|
|
Command = "tpgui.search",
|
|
Font = "robotocondensed-regular.ttf",
|
|
Align = TextAnchor.MiddleLeft
|
|
},
|
|
new CuiRectTransformComponent
|
|
{
|
|
AnchorMin = "0.03 0",
|
|
AnchorMax = "0.97 1"
|
|
}
|
|
}
|
|
});
|
|
|
|
// Online count label
|
|
int totalOnline = cachedPlayers.Count(p => p != null && p.IsConnected && p.userID != player.userID);
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = $"{totalOnline} ONLINE",
|
|
FontSize = 11,
|
|
Align = TextAnchor.MiddleRight,
|
|
Color = ColorTextMuted,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.78 0.9", AnchorMax = "0.98 0.98" }
|
|
}, content);
|
|
|
|
// Filter and paginate players
|
|
string search = GetPlayerSearch(player);
|
|
var filteredPlayers = cachedPlayers
|
|
.Where(p => p != null && p.IsConnected && p.userID != player.userID)
|
|
.Where(p => string.IsNullOrEmpty(search) ||
|
|
p.displayName.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0)
|
|
.OrderBy(p => p.displayName)
|
|
.ToList();
|
|
|
|
int currentPage = GetPlayerPage(player);
|
|
int totalPages = Math.Max(1, (int)Math.Ceiling((double)filteredPlayers.Count / PlayersPerPage));
|
|
|
|
// Clamp page
|
|
if (currentPage >= totalPages) currentPage = totalPages - 1;
|
|
if (currentPage < 0) currentPage = 0;
|
|
playerPages[player.userID] = currentPage;
|
|
|
|
var pagePlayers = filteredPlayers
|
|
.Skip(currentPage * PlayersPerPage)
|
|
.Take(PlayersPerPage)
|
|
.ToList();
|
|
|
|
// Player grid area
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorTransparent },
|
|
RectTransform = { AnchorMin = "0 0.08", AnchorMax = "1 0.88" }
|
|
}, content, content + "_Grid");
|
|
|
|
// Render player cards
|
|
float cardGap = 0.01f;
|
|
float cardWidth = (1f - (GridColumns + 1) * cardGap) / GridColumns;
|
|
float cardHeight = (1f - (GridRows + 1) * cardGap) / GridRows;
|
|
|
|
for (int i = 0; i < pagePlayers.Count; i++)
|
|
{
|
|
var target = pagePlayers[i];
|
|
int col = i % GridColumns;
|
|
int row = i / GridColumns;
|
|
|
|
// Invert row so first player appears at top-left
|
|
float xMin = cardGap + col * (cardWidth + cardGap);
|
|
float xMax = xMin + cardWidth;
|
|
float yMax = 1f - (cardGap + row * (cardHeight + cardGap));
|
|
float yMin = yMax - cardHeight;
|
|
|
|
string cardName = content + $"_Card_{i}";
|
|
|
|
// Card background
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorCardBg },
|
|
RectTransform = { AnchorMin = $"{xMin} {yMin}", AnchorMax = $"{xMax} {yMax}" }
|
|
}, content + "_Grid", cardName);
|
|
|
|
// Player name
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = TruncateString(target.displayName, 16),
|
|
FontSize = 11,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.05 0.5", AnchorMax = "0.95 0.9" }
|
|
}, cardName);
|
|
|
|
// Request button
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = ColorTabActive,
|
|
Command = $"tpgui.tpr {target.displayName}"
|
|
},
|
|
Text =
|
|
{
|
|
Text = "REQUEST",
|
|
FontSize = 10,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.1 0.08", AnchorMax = "0.9 0.42" }
|
|
}, cardName);
|
|
}
|
|
|
|
// Empty state
|
|
if (pagePlayers.Count == 0)
|
|
{
|
|
string emptyMsg = string.IsNullOrEmpty(search)
|
|
? "No other players online"
|
|
: $"No players found matching '{search}'";
|
|
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = emptyMsg,
|
|
FontSize = 14,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorTextMuted,
|
|
Font = "robotocondensed-regular.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0 0.3", AnchorMax = "1 0.7" }
|
|
}, content + "_Grid");
|
|
}
|
|
|
|
// --- Pagination controls ---
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorTransparent },
|
|
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 0.07" }
|
|
}, content, content + "_Pagination");
|
|
|
|
// Previous button
|
|
string prevColor = currentPage > 0 ? ColorTabInactive : "0.15 0.15 0.15 0.5";
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = prevColor,
|
|
Command = currentPage > 0 ? "tpgui.page prev" : ""
|
|
},
|
|
Text =
|
|
{
|
|
Text = "◀ PREV",
|
|
FontSize = 11,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = currentPage > 0 ? ColorText : ColorTextMuted,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.3 0", AnchorMax = "0.42 1" }
|
|
}, content + "_Pagination");
|
|
|
|
// Page indicator
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = $"Page {currentPage + 1} / {totalPages}",
|
|
FontSize = 11,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorTextMuted,
|
|
Font = "robotocondensed-regular.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.43 0", AnchorMax = "0.57 1" }
|
|
}, content + "_Pagination");
|
|
|
|
// Next button
|
|
string nextColor = currentPage < totalPages - 1 ? ColorTabInactive : "0.15 0.15 0.15 0.5";
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = nextColor,
|
|
Command = currentPage < totalPages - 1 ? "tpgui.page next" : ""
|
|
},
|
|
Text =
|
|
{
|
|
Text = "NEXT ▶",
|
|
FontSize = 11,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = currentPage < totalPages - 1 ? ColorText : ColorTextMuted,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.58 0", AnchorMax = "0.7 1" }
|
|
}, content + "_Pagination");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Homes Tab
|
|
|
|
private void ShowHomesTab(ref CuiElementContainer container, BasePlayer player)
|
|
{
|
|
string body = MainPanel + "_Body";
|
|
|
|
// Content area
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorTransparent },
|
|
RectTransform = { AnchorMin = "0.02 0.02", AnchorMax = "0.98 0.86" }
|
|
}, body, body + "_HomesContent");
|
|
|
|
string content = body + "_HomesContent";
|
|
|
|
// Header row
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorTransparent },
|
|
RectTransform = { AnchorMin = "0 0.9", AnchorMax = "1 0.98" }
|
|
}, content, content + "_HomeHeader");
|
|
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = "YOUR HOMES",
|
|
FontSize = 14,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0 0", AnchorMax = "0.5 1" }
|
|
}, content + "_HomeHeader");
|
|
|
|
// Set Home button
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = ColorAccept,
|
|
Command = "tpgui.sethome"
|
|
},
|
|
Text =
|
|
{
|
|
Text = "+ SET HOME",
|
|
FontSize = 11,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.78 0.1", AnchorMax = "0.98 0.9" }
|
|
}, content + "_HomeHeader");
|
|
|
|
// Divider
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorDivider },
|
|
RectTransform = { AnchorMin = "0 0.885", AnchorMax = "1 0.888" }
|
|
}, content);
|
|
|
|
// Get homes from NTeleportation
|
|
var homes = GetPlayerHomes(player);
|
|
|
|
if (homes == null || homes.Count == 0)
|
|
{
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = "You have no homes set.\nUse the '+ SET HOME' button to save your current location.",
|
|
FontSize = 13,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorTextMuted,
|
|
Font = "robotocondensed-regular.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0 0.3", AnchorMax = "1 0.7" }
|
|
}, content);
|
|
return;
|
|
}
|
|
|
|
// Scrollable home list area
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorTransparent },
|
|
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 0.87" }
|
|
}, content, content + "_HomeList");
|
|
|
|
float rowHeight = 0.08f;
|
|
float rowGap = 0.01f;
|
|
int index = 0;
|
|
|
|
foreach (var home in homes)
|
|
{
|
|
if (index >= 10) break; // Max 10 visible homes
|
|
|
|
float yMax = 1f - index * (rowHeight + rowGap);
|
|
float yMin = yMax - rowHeight;
|
|
string rowName = content + $"_HomeRow_{index}";
|
|
|
|
// Row background
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorCardBg },
|
|
RectTransform = { AnchorMin = $"0 {yMin}", AnchorMax = $"1 {yMax}" }
|
|
}, content + "_HomeList", rowName);
|
|
|
|
// Home name
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = home.Key,
|
|
FontSize = 13,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.03 0", AnchorMax = "0.4 1" }
|
|
}, rowName);
|
|
|
|
// Coordinates
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = $"({home.Value.x:F0}, {home.Value.y:F0}, {home.Value.z:F0})",
|
|
FontSize = 10,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorTextMuted,
|
|
Font = "robotocondensed-regular.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.4 0", AnchorMax = "0.65 1" }
|
|
}, rowName);
|
|
|
|
// Teleport button
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = ColorTabActive,
|
|
Command = $"tpgui.home {home.Key}"
|
|
},
|
|
Text =
|
|
{
|
|
Text = "TELEPORT",
|
|
FontSize = 10,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.68 0.15", AnchorMax = "0.83 0.85" }
|
|
}, rowName);
|
|
|
|
// Delete button
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = ColorDeny,
|
|
Command = $"tpgui.removehome {home.Key}"
|
|
},
|
|
Text =
|
|
{
|
|
Text = "DELETE",
|
|
FontSize = 10,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.85 0.15", AnchorMax = "0.98 0.85" }
|
|
}, rowName);
|
|
|
|
index++;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Warps Tab
|
|
|
|
private void ShowWarpsTab(ref CuiElementContainer container, BasePlayer player)
|
|
{
|
|
string body = MainPanel + "_Body";
|
|
|
|
// Content area
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorTransparent },
|
|
RectTransform = { AnchorMin = "0.02 0.02", AnchorMax = "0.98 0.86" }
|
|
}, body, body + "_WarpsContent");
|
|
|
|
string content = body + "_WarpsContent";
|
|
|
|
// Header
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = "SERVER WARPS",
|
|
FontSize = 14,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0 0.9", AnchorMax = "0.5 0.98" }
|
|
}, content);
|
|
|
|
// Divider
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorDivider },
|
|
RectTransform = { AnchorMin = "0 0.885", AnchorMax = "1 0.888" }
|
|
}, content);
|
|
|
|
// Get warps from NTeleportation
|
|
var warps = GetWarps();
|
|
|
|
if (warps == null || warps.Count == 0)
|
|
{
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = "No warps available on this server.",
|
|
FontSize = 13,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorTextMuted,
|
|
Font = "robotocondensed-regular.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0 0.3", AnchorMax = "1 0.7" }
|
|
}, content);
|
|
return;
|
|
}
|
|
|
|
// Warp list area
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorTransparent },
|
|
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 0.87" }
|
|
}, content, content + "_WarpList");
|
|
|
|
float rowHeight = 0.08f;
|
|
float rowGap = 0.01f;
|
|
int index = 0;
|
|
|
|
foreach (var warp in warps)
|
|
{
|
|
if (index >= 10) break; // Max 10 visible warps
|
|
|
|
float yMax = 1f - index * (rowHeight + rowGap);
|
|
float yMin = yMax - rowHeight;
|
|
string rowName = content + $"_WarpRow_{index}";
|
|
|
|
// Row background
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorCardBg },
|
|
RectTransform = { AnchorMin = $"0 {yMin}", AnchorMax = $"1 {yMax}" }
|
|
}, content + "_WarpList", rowName);
|
|
|
|
// Warp name
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = warp.Key,
|
|
FontSize = 13,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.03 0", AnchorMax = "0.5 1" }
|
|
}, rowName);
|
|
|
|
// Coordinates
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = $"({warp.Value.x:F0}, {warp.Value.y:F0}, {warp.Value.z:F0})",
|
|
FontSize = 10,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorTextMuted,
|
|
Font = "robotocondensed-regular.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.5 0", AnchorMax = "0.75 1" }
|
|
}, rowName);
|
|
|
|
// Teleport button
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = ColorTabActive,
|
|
Command = $"tpgui.warp {warp.Key}"
|
|
},
|
|
Text =
|
|
{
|
|
Text = "TELEPORT",
|
|
FontSize = 10,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.82 0.15", AnchorMax = "0.98 0.85" }
|
|
}, rowName);
|
|
|
|
index++;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Settings Tab
|
|
|
|
private void ShowSettingsTab(ref CuiElementContainer container, BasePlayer player)
|
|
{
|
|
string body = MainPanel + "_Body";
|
|
|
|
// Content area
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorTransparent },
|
|
RectTransform = { AnchorMin = "0.02 0.02", AnchorMax = "0.98 0.86" }
|
|
}, body, body + "_SettingsContent");
|
|
|
|
string content = body + "_SettingsContent";
|
|
|
|
// Header
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = "TELEPORT SETTINGS",
|
|
FontSize = 14,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0 0.9", AnchorMax = "0.5 0.98" }
|
|
}, content);
|
|
|
|
// Divider
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorDivider },
|
|
RectTransform = { AnchorMin = "0 0.885", AnchorMax = "1 0.888" }
|
|
}, content);
|
|
|
|
// Player info card
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorCardBg },
|
|
RectTransform = { AnchorMin = "0 0.6", AnchorMax = "1 0.87" }
|
|
}, content, content + "_InfoCard");
|
|
|
|
// Player name
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = player.displayName,
|
|
FontSize = 16,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.03 0.55", AnchorMax = "0.7 0.95" }
|
|
}, content + "_InfoCard");
|
|
|
|
// Steam ID
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = $"Steam ID: {player.UserIDString}",
|
|
FontSize = 10,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorTextMuted,
|
|
Font = "robotocondensed-regular.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.03 0.1", AnchorMax = "0.7 0.5" }
|
|
}, content + "_InfoCard");
|
|
|
|
// NTeleportation status badge
|
|
string ntpStatus = NTeleportation != null ? "CONNECTED" : "NOT FOUND";
|
|
string ntpColor = NTeleportation != null ? ColorAccept : ColorDeny;
|
|
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ntpColor },
|
|
RectTransform = { AnchorMin = "0.75 0.3", AnchorMax = "0.97 0.7" }
|
|
}, content + "_InfoCard", content + "_StatusBadge");
|
|
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = ntpStatus,
|
|
FontSize = 10,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }
|
|
}, content + "_StatusBadge");
|
|
|
|
// Teleport info section
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorCardBg },
|
|
RectTransform = { AnchorMin = "0 0.15", AnchorMax = "0.48 0.57" }
|
|
}, content, content + "_TprInfo");
|
|
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = "TELEPORT REQUESTS",
|
|
FontSize = 12,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorTabActive,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.04 0.78", AnchorMax = "0.96 0.96" }
|
|
}, content + "_TprInfo");
|
|
|
|
// TPR info rows
|
|
AddSettingRow(ref container, content + "_TprInfo", "Cooldown", GetNTPSetting("TPRCooldown", "300s"), 0.55f);
|
|
AddSettingRow(ref container, content + "_TprInfo", "Daily Limit", GetNTPSetting("TPRDailyLimit", "5"), 0.33f);
|
|
AddSettingRow(ref container, content + "_TprInfo", "Countdown", GetNTPSetting("TPRCountdown", "15s"), 0.11f);
|
|
|
|
// Homes info section
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorCardBg },
|
|
RectTransform = { AnchorMin = "0.52 0.15", AnchorMax = "1 0.57" }
|
|
}, content, content + "_HomesInfo");
|
|
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = "HOME TELEPORTS",
|
|
FontSize = 12,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorTabActive,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.04 0.78", AnchorMax = "0.96 0.96" }
|
|
}, content + "_HomesInfo");
|
|
|
|
var homes = GetPlayerHomes(player);
|
|
int homeCount = homes?.Count ?? 0;
|
|
|
|
AddSettingRow(ref container, content + "_HomesInfo", "Homes Set", $"{homeCount}", 0.55f);
|
|
AddSettingRow(ref container, content + "_HomesInfo", "Max Homes", GetNTPSetting("HomeMaxHomes", "3"), 0.33f);
|
|
AddSettingRow(ref container, content + "_HomesInfo", "Cooldown", GetNTPSetting("HomeCooldown", "300s"), 0.11f);
|
|
|
|
// Plugin version footer
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = "CorrosionTeleportGUI v1.0.0 — corrosionmgmt.com",
|
|
FontSize = 9,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = "0.3 0.3 0.3 1",
|
|
Font = "robotocondensed-regular.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 0.08" }
|
|
}, content);
|
|
}
|
|
|
|
private void AddSettingRow(ref CuiElementContainer container, string parent, string label, string value, float yCenter)
|
|
{
|
|
float rowHeight = 0.16f;
|
|
float yMin = yCenter - rowHeight / 2f;
|
|
float yMax = yCenter + rowHeight / 2f;
|
|
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = label,
|
|
FontSize = 11,
|
|
Align = TextAnchor.MiddleLeft,
|
|
Color = ColorSettingLabel,
|
|
Font = "robotocondensed-regular.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = $"0.04 {yMin}", AnchorMax = $"0.55 {yMax}" }
|
|
}, parent);
|
|
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = value,
|
|
FontSize = 11,
|
|
Align = TextAnchor.MiddleRight,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = $"0.55 {yMin}", AnchorMax = $"0.96 {yMax}" }
|
|
}, parent);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TPR Popup
|
|
|
|
private void ShowTPRPopup(BasePlayer target, string requesterName)
|
|
{
|
|
if (target == null) return;
|
|
|
|
DestroyPopupUI(target);
|
|
|
|
var container = new CuiElementContainer();
|
|
|
|
// Popup overlay (smaller, positioned at top-center)
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = "0.05 0.05 0.05 0.92" },
|
|
RectTransform = { AnchorMin = "0.3 0.75", AnchorMax = "0.7 0.95" },
|
|
CursorEnabled = true
|
|
}, "Overlay", PopupPanel);
|
|
|
|
// Inner panel
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorPanel },
|
|
RectTransform = { AnchorMin = "0.02 0.04", AnchorMax = "0.98 0.96" }
|
|
}, PopupPanel, PopupPanel + "_Inner");
|
|
|
|
string inner = PopupPanel + "_Inner";
|
|
|
|
// Accent bar at top
|
|
container.Add(new CuiPanel
|
|
{
|
|
Image = { Color = ColorTabActive },
|
|
RectTransform = { AnchorMin = "0 0.92", AnchorMax = "1 1" }
|
|
}, inner);
|
|
|
|
// Title
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = "INCOMING TELEPORT REQUEST",
|
|
FontSize = 13,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorTabActive,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0 0.62", AnchorMax = "1 0.88" }
|
|
}, inner);
|
|
|
|
// Requester name
|
|
container.Add(new CuiLabel
|
|
{
|
|
Text =
|
|
{
|
|
Text = $"<b>{requesterName}</b> wants to teleport to you",
|
|
FontSize = 12,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-regular.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0 0.38", AnchorMax = "1 0.62" }
|
|
}, inner);
|
|
|
|
// Accept button
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = ColorAccept,
|
|
Command = "tpgui.accept"
|
|
},
|
|
Text =
|
|
{
|
|
Text = "ACCEPT",
|
|
FontSize = 13,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.05 0.06", AnchorMax = "0.35 0.34" }
|
|
}, inner);
|
|
|
|
// Deny button
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = ColorDeny,
|
|
Command = "tpgui.deny"
|
|
},
|
|
Text =
|
|
{
|
|
Text = "DENY",
|
|
FontSize = 13,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.4 0.06", AnchorMax = "0.7 0.34" }
|
|
}, inner);
|
|
|
|
// Close button (X)
|
|
container.Add(new CuiButton
|
|
{
|
|
Button =
|
|
{
|
|
Color = ColorClose,
|
|
Command = "tpgui.popup.close"
|
|
},
|
|
Text =
|
|
{
|
|
Text = "✕",
|
|
FontSize = 12,
|
|
Align = TextAnchor.MiddleCenter,
|
|
Color = ColorText,
|
|
Font = "robotocondensed-bold.ttf"
|
|
},
|
|
RectTransform = { AnchorMin = "0.78 0.06", AnchorMax = "0.95 0.34" }
|
|
}, inner);
|
|
|
|
CuiHelper.AddUi(target, container);
|
|
|
|
// Auto-dismiss after timeout
|
|
if (popupTimers.TryGetValue(target.userID, out var existingTimer))
|
|
{
|
|
existingTimer?.Destroy();
|
|
}
|
|
|
|
popupTimers[target.userID] = timer.Once(PopupTimeout, () =>
|
|
{
|
|
if (target != null && target.IsConnected)
|
|
{
|
|
DestroyPopupUI(target);
|
|
target.ChatMessage("<color=#CD6632>[Corrosion TP]</color> Teleport request timed out.");
|
|
}
|
|
popupTimers.Remove(target.userID);
|
|
});
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Helpers
|
|
|
|
private void DestroyUI(BasePlayer player)
|
|
{
|
|
if (player == null) return;
|
|
CuiHelper.DestroyUi(player, MainPanel);
|
|
}
|
|
|
|
private void DestroyPopupUI(BasePlayer player)
|
|
{
|
|
if (player == null) return;
|
|
CuiHelper.DestroyUi(player, PopupPanel);
|
|
|
|
if (popupTimers.TryGetValue(player.userID, out var popupTimer))
|
|
{
|
|
popupTimer?.Destroy();
|
|
popupTimers.Remove(player.userID);
|
|
}
|
|
}
|
|
|
|
private void RefreshPlayerCache()
|
|
{
|
|
cachedPlayers = BasePlayer.activePlayerList?.ToList() ?? new List<BasePlayer>();
|
|
}
|
|
|
|
private int GetPlayerPage(BasePlayer player)
|
|
{
|
|
int page;
|
|
if (playerPages.TryGetValue(player.userID, out page))
|
|
return page;
|
|
return 0;
|
|
}
|
|
|
|
private string GetPlayerSearch(BasePlayer player)
|
|
{
|
|
string search;
|
|
if (playerSearches.TryGetValue(player.userID, out search))
|
|
return search;
|
|
return string.Empty;
|
|
}
|
|
|
|
private string GetPlayerTab(BasePlayer player)
|
|
{
|
|
string tab;
|
|
if (playerTabs.TryGetValue(player.userID, out tab))
|
|
return tab;
|
|
return "teleport";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the player's homes from NTeleportation via its API.
|
|
/// Returns an empty dictionary if NTeleportation is not loaded or data is unavailable.
|
|
/// </summary>
|
|
private Dictionary<string, Vector3> GetPlayerHomes(BasePlayer player)
|
|
{
|
|
if (NTeleportation == null || player == null)
|
|
return new Dictionary<string, Vector3>();
|
|
|
|
try
|
|
{
|
|
var result = NTeleportation.Call("API_GetHomes", player);
|
|
if (result is Dictionary<string, Vector3> homes)
|
|
return homes;
|
|
|
|
// Some versions may return a different type — attempt generic dictionary conversion
|
|
if (result != null)
|
|
{
|
|
var dict = new Dictionary<string, Vector3>();
|
|
var objDict = result as Dictionary<string, object>;
|
|
if (objDict != null)
|
|
{
|
|
foreach (var kvp in objDict)
|
|
{
|
|
if (kvp.Value is Vector3 vec)
|
|
dict[kvp.Key] = vec;
|
|
}
|
|
return dict;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
PrintError($"Failed to get homes for {player.displayName}: {ex.Message}");
|
|
}
|
|
|
|
return new Dictionary<string, Vector3>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves server warps from NTeleportation data files.
|
|
/// Returns an empty dictionary if unavailable.
|
|
/// </summary>
|
|
private Dictionary<string, Vector3> GetWarps()
|
|
{
|
|
if (NTeleportation == null)
|
|
return new Dictionary<string, Vector3>();
|
|
|
|
try
|
|
{
|
|
var result = NTeleportation.Call("API_GetWarps");
|
|
if (result is Dictionary<string, Vector3> warps)
|
|
return warps;
|
|
|
|
// Attempt to read from NTeleportation data file directly as fallback
|
|
var dataFile = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, object>>("NTeleportation");
|
|
if (dataFile != null && dataFile.ContainsKey("Warps"))
|
|
{
|
|
var warpsObj = dataFile["Warps"];
|
|
if (warpsObj is Dictionary<string, object> warpsDict)
|
|
{
|
|
var parsed = new Dictionary<string, Vector3>();
|
|
foreach (var kvp in warpsDict)
|
|
{
|
|
try
|
|
{
|
|
if (kvp.Value is Dictionary<string, object> posData)
|
|
{
|
|
float x = Convert.ToSingle(posData.ContainsKey("x") ? posData["x"] : 0);
|
|
float y = Convert.ToSingle(posData.ContainsKey("y") ? posData["y"] : 0);
|
|
float z = Convert.ToSingle(posData.ContainsKey("z") ? posData["z"] : 0);
|
|
parsed[kvp.Key] = new Vector3(x, y, z);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Skip malformed warp entries
|
|
}
|
|
}
|
|
return parsed;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
PrintError($"Failed to get warps: {ex.Message}");
|
|
}
|
|
|
|
return new Dictionary<string, Vector3>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets NTeleportation configuration values for display in settings.
|
|
/// Returns the default value if NTeleportation is not available or the setting can't be read.
|
|
/// </summary>
|
|
private string GetNTPSetting(string key, string defaultValue)
|
|
{
|
|
if (NTeleportation == null)
|
|
return defaultValue;
|
|
|
|
try
|
|
{
|
|
var result = NTeleportation.Call("API_GetConfig", key);
|
|
if (result != null)
|
|
return result.ToString();
|
|
}
|
|
catch
|
|
{
|
|
// Silently fall back to default — this is a cosmetic read
|
|
}
|
|
|
|
return defaultValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Truncates a string to the specified max length, appending "..." if truncated.
|
|
/// </summary>
|
|
private string TruncateString(string input, int maxLength)
|
|
{
|
|
if (string.IsNullOrEmpty(input) || input.Length <= maxLength)
|
|
return input;
|
|
return input.Substring(0, maxLength - 3) + "...";
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|