C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System.Collections.Generic;
using System.Linq;
using HarmonyLib;
using System;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("EventControlUI", "Naked", "1.0.0")]
[Description("Plugin to manage teams, permissions, and teleportation for events in Rust via a UI.")]
public class EventControlUI : RustPlugin
{
private const string PermissionManageTeams = "eventcontrolui.manage.teams";
private const string PermissionManagePerms = "eventcontrolui.manage.perms";
private const string PermissionManageTp = "eventcontrolui.manage.tp";
private const string PermissionHideHud = "eventcontrolui.hidehud";
private const string PermissionBypass = "kits.bypass";
private Dictionary<string, string> playerTeams = new Dictionary<string, string>(); // Player ID -> Team
private Dictionary<string, string> teamColors = new Dictionary<string, string>
{
{ "TeamOne", "0.2 0.8 0.2 1.0" },
{ "TeamTwo", "0.2 0.5 0.8 1.0" },
{ "TeamThree", "0.8 0.2 0.2 1.0" },
{ "TeamFour", "0.8 0.8 0.2 1.0" }
};
// --- UI Tracking ---
// Global loot flag – true means players are allowed to loot by default.private bool lootAllowed = true;
// Dictionary to store per-team loot settings.private Dictionary<string, bool> teamLootStatus = new Dictionary<string, bool>();
private Dictionary<string, List<string>> playerPerms = new Dictionary<string, List<string>>(); // Player ID -> Permissions
private Dictionary<string, ulong> teamMapping = new Dictionary<string, ulong>();
private Vector3? worldSpawnLocation = null;
private List<string> teamNames = new List<string> { "TeamOne", "TeamTwo", "TeamThree", "TeamFour" };
private List<string> availablePerms = new List<string> { "none" }; // Configurable
private bool allowTeamLeave = true; // Toggle for allowing players to leave teams
private string defaultTeam = null; // Default team players join automatically
private Harmony harmony; // Add this at the top of the class
public static EventControlUI Instance;
private bool friendlyFire = true; // Default value
private List<string> defaultTeams = new List<string>(); // Allow multiple default teams
private void Init()
{
Instance = this; // Set the static reference
// Register permissions
permission.RegisterPermission(PermissionManageTeams, this);
permission.RegisterPermission(PermissionManagePerms, this);
permission.RegisterPermission(PermissionManageTp, this);
permission.RegisterPermission(PermissionHideHud, this);
// Initialize Kits plugin reference
Kits = plugins.Find("Kits"); // Ensure the plugin name matches exactly
if (Kits == null)
{
PrintError("Kits plugin not found! Ensure that the Kits plugin is installed and loaded before EventControlUI.");
}
// Load the configuration
LoadConfig();
// Initialize Harmony for patching
harmony = new Harmony("com.yourname.eventcontrolui");
harmony.PatchAll();
// Initialize team-specific states if not already set
foreach (var team in teamNames)
{
if (!teamFreezeStatus.ContainsKey(team))
teamFreezeStatus[team] = false;
if (!teamRaidingStatus.ContainsKey(team))
teamRaidingStatus[team] = raidingEnabled;
if (!teamPvPStatus.ContainsKey(team))
teamPvPStatus[team] = pvpEnabled;
if (!teamGodModeStatus.ContainsKey(team))
teamGodModeStatus[team] = godModeEnabled;
if (!teamBuildingStatus.ContainsKey(team))
teamBuildingStatus[team] = buildingEnabled;
}
// Initialize timers for Global and each team
timers["Global"] = new TimerData
{
TeamName = "Global",
RemainingTime = 0f,
IsRunning = false,
BuildingOnZero = false,
RaidingOnZero = false,
PvPOnZero = false,
CustomText = ""
};
foreach (var team in teamNames)
{
timers[team] = new TimerData
{
TeamName = team,
RemainingTime = 0f,
IsRunning = false,
BuildingOnZero = false,
RaidingOnZero = false,
PvPOnZero = false,
CustomText = ""
};
}
}
protected override void LoadDefaultConfig()
{
Config["AvailablePerms"] = new List<string> { "atlasvanish.use",
"bgrade.all"};
SaveConfig();
Config["WorldSpawnLocation"] = null;
Config["AvailablePerms"] = availablePerms;
Config["AllowTeamLeave"] = allowTeamLeave;
Config["DefaultTeams"] = new List<string>();
Config["FriendlyFire"] = true;
Config["RaidingEnabled"] = true;
Config["BuildingEnabled"] = true; // Default state
Config["GodModeEnabled"] = false; // Default state
Config["Timers"] = new Dictionary<string, object>();
SaveConfig();
}
private void LoadConfig()
{
// Load Building Enabled setting
buildingEnabled = Config["BuildingEnabled"] != null && (bool)Config["BuildingEnabled"];
godModeEnabled = Config["GodModeEnabled"] != null && (bool)Config["GodModeEnabled"];
// Load Friendly Fire setting
friendlyFire = Config["FriendlyFire"] != null && (bool)Config["FriendlyFire"];
// Load Available Permissions
if (Config["AvailablePerms"] is List<object> permsFromConfig)
{
availablePerms = permsFromConfig.Cast<string>().ToList();
}
else
{
availablePerms = new List<string>(); // Default empty list if not in config
}
// Load Allow Team Leave setting
allowTeamLeave = Config["AllowTeamLeave"] != null && (bool)Config["AllowTeamLeave"];
// Load Default Teams (multiple teams)
if (Config["DefaultTeams"] is List<object> teamsFromConfig)
{
defaultTeams = teamsFromConfig.Cast<string>().ToList();
}
else
{
defaultTeams = new List<string>(); // Ensure it initializes even if config is missing
}
if (Config["WorldSpawnLocation"] != null)
{
worldSpawnLocation = Config["WorldSpawnLocation"] as Vector3?;
}
// Load Team-Specific Freeze Status
if (Config["TeamFreezeStatus"] is Dictionary<string, object> freezeStatusConfig)
{
foreach (var kvp in freezeStatusConfig)
{
teamFreezeStatus[kvp.Key] = Convert.ToBoolean(kvp.Value);
}
}
// Load Team-Specific Raiding Status
if (Config["TeamRaidingStatus"] is Dictionary<string, object> raidingStatusConfig)
{
foreach (var kvp in raidingStatusConfig)
{
teamRaidingStatus[kvp.Key] = Convert.ToBoolean(kvp.Value);
}
}
// Load Team-Specific PvP Status
if (Config["TeamPvPStatus"] is Dictionary<string, object> pvpStatusConfig)
{
foreach (var kvp in pvpStatusConfig)
{
teamPvPStatus[kvp.Key] = Convert.ToBoolean(kvp.Value);
}
}
// Load Team-Specific God Mode Status
if (Config["TeamGodModeStatus"] is Dictionary<string, object> godModeStatusConfig)
{
foreach (var kvp in godModeStatusConfig)
{
teamGodModeStatus[kvp.Key] = Convert.ToBoolean(kvp.Value);
}
}
// Load Team-Specific Building Status
if (Config["TeamBuildingStatus"] is Dictionary<string, object> buildingStatusConfig)
{
foreach (var kvp in buildingStatusConfig)
{
teamBuildingStatus[kvp.Key] = Convert.ToBoolean(kvp.Value);
}
}
// Ensure all teams have an entry
foreach (var team in teamNames)
{
if (!teamFreezeStatus.ContainsKey(team)) teamFreezeStatus[team] = false;
if (!teamRaidingStatus.ContainsKey(team)) teamRaidingStatus[team] = raidingEnabled;
if (!teamPvPStatus.ContainsKey(team)) teamPvPStatus[team] = pvpEnabled;
if (!teamGodModeStatus.ContainsKey(team)) teamGodModeStatus[team] = godModeEnabled;
if (!teamBuildingStatus.ContainsKey(team)) teamBuildingStatus[team] = buildingEnabled;
}
if (Config["Timers"] is Dictionary<string, object> timersConfig)
{
foreach (var kvp in timersConfig)
{
string teamName = kvp.Key;
var timerObj = kvp.Value as Dictionary<string, object>;
if (timerObj == null) continue;
if (!timers.ContainsKey(teamName))
timers[teamName] = new TimerData { TeamName = teamName };
TimerData timerData = timers[teamName];
timerData.RemainingTime = timerObj.ContainsKey("RemainingTime") ? Convert.ToSingle(timerObj["RemainingTime"]) : 0f;
timerData.IsRunning = timerObj.ContainsKey("IsRunning") ? Convert.ToBoolean(timerObj["IsRunning"]) : false;
timerData.BuildingOnZero = timerObj.ContainsKey("BuildingOnZero") ? Convert.ToBoolean(timerObj["BuildingOnZero"]) : false;
timerData.RaidingOnZero = timerObj.ContainsKey("RaidingOnZero") ? Convert.ToBoolean(timerObj["RaidingOnZero"]) : false;
timerData.PvPOnZero = timerObj.ContainsKey("PvPOnZero") ? Convert.ToBoolean(timerObj["PvPOnZero"]) : false;
timerData.CustomText = timerObj.ContainsKey("CustomText") ? timerObj["CustomText"].ToString() : "";
if (timerData.IsRunning && timerData.RemainingTime > 0f)
{
timerData.TimerInstance = timer.Once(timerData.RemainingTime, () => OnTimerEnd(teamName));
}
}
}
SaveConfig();
}
private HashSet<ulong> uiOpenPlayers = new HashSet<ulong>();
// HashSet to track players with the Timers tab open
private HashSet<ulong> timersTabOpenPlayers = new HashSet<ulong>();
[ChatCommand("eventui")]
private void EventUICommand(BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, PermissionManageTeams))
{
SendReply(player, "You don't have permission to use this command.");
return;
}
OpenMainMenu(player, "teams");
uiOpenPlayers.Add(player.userID);
}
void OnPlayerDisconnected(BasePlayer player, string reason)
{
uiOpenPlayers.Remove(player.userID);
timersTabOpenPlayers.Remove(player.userID);
}
private void OpenMainMenu(BasePlayer player, string activeTab, string selectedPlayerId = null, string selectedTeam = null, int page = 0)
{
// Destroy existing UI
CuiHelper.DestroyUi(player, "EventControlUI");
CuiElementContainer container = new CuiElementContainer();
// Background panel
string panelName = "EventControlUI";
container.Add(new CuiPanel
{
RectTransform = { AnchorMin = "0.05 0.05", AnchorMax = "0.95 0.95" },
Image = { Color = "0.1 0.1 0.1 0.8" }
}, "Overlay", panelName);
// Tabs including the new "Timers" tab
string[] tabs = { "Teams", "Permissions", "Global", "Teleport", "Timers", "Kits" };
float tabWidth = 0.16f; // Adjusted width to accommodate 5 tabs within the panel
for (int i = 0; i < tabs.Length; i++)
{
container.Add(new CuiButton
{
RectTransform = { AnchorMin = $"{0.05f + i * tabWidth} 0.95", AnchorMax = $"{0.05f + (i + 1) * tabWidth - 0.02f} 1.0" },
Button = { Command = $"eventui.tab {tabs[i].ToLower()}", Color = activeTab == tabs[i].ToLower() ? "0.8 0.8 0.8 1.0" : "0.2 0.5 0.8 1.0" },
Text = { Text = tabs[i], FontSize = 20, Align = UnityEngine.TextAnchor.MiddleCenter }
}, panelName);
}
// Main Content based on the active tab
switch (activeTab)
{
case "teams":
AddTeamTabContent(container, panelName, selectedPlayerId, selectedTeam, page);
break;
case "permissions":
AddPermissionsTabContent(container, panelName, page);
break;
case "global":
AddGlobalTabContent(container, panelName);
break;
case "teleport":
AddTeleportTabContent(container, panelName, page);
break;
case "timers":
AddTimersTabContent(container, panelName);
break;
case "kits":
AddKitsTabContent(container, panelName, page);
break;
default:
// Default to Teams tab if an unknown tab is specified
AddTeamTabContent(container, panelName, selectedPlayerId, selectedTeam, page);
break;
}
// Close button
container.Add(new CuiButton
{
RectTransform = { AnchorMin = "0.85 0.05", AnchorMax = "0.95 0.1" },
Button = { Command = "eventui.close", Color = "0.8 0.2 0.2 1.0" },
Text = { Text = "Close", FontSize = 20, Align = UnityEngine.TextAnchor.MiddleCenter }
}, panelName);
// Add the constructed UI to the player
CuiHelper.AddUi(player, container);
}
[ConsoleCommand("team.page")]
private void HandleTeamPageCommand(ConsoleSystem.Arg args)
{
BasePlayer player = args.Connection?.player as BasePlayer;
if (player == null) return;
int page = args.Args.Length > 0 ? int.Parse(args.Args[0]) : 0;
OpenMainMenu(player, "teams", null, null, page);
}
private void AddTeamTabContent(CuiElementContainer container, string parent, string selectedPlayerId = null, string selectedTeam = null, int page = 0)
{
// --- Allow Leave Toggle ---
container.Add(new CuiLabel {
RectTransform = { AnchorMin = "0.1 0.88", AnchorMax = "0.3 0.93" },
Text = { Text = "Allow Leave", FontSize = 24, Align = TextAnchor.MiddleLeft }
}, parent);
container.Add(new CuiButton {
RectTransform = { AnchorMin = "0.3 0.88", AnchorMax = "0.4 0.93" },
Button = { Command = "team.toggleleave", Color = allowTeamLeave ? "0.2 0.8 0.2 1.0" : "0.8 0.2 0.2 1.0" },
Text = { Text = allowTeamLeave ? "True" : "False", FontSize = 24, Align = TextAnchor.MiddleCenter }
}, parent);
// --- Friendly Fire Toggle ---
container.Add(new CuiLabel {
RectTransform = { AnchorMin = "0.5 0.88", AnchorMax = "0.7 0.93" },
Text = { Text = "Friendly Fire", FontSize = 24, Align = TextAnchor.MiddleLeft }
}, parent);
container.Add(new CuiButton {
RectTransform = { AnchorMin = "0.7 0.88", AnchorMax = "0.8 0.93" },
Button = { Command = "team.togglefriendlyfire", Color = friendlyFire ? "0.2 0.8 0.2 1.0" : "0.8 0.2 0.2 1.0" },
Text = { Text = friendlyFire ? "True" : "False", FontSize = 24, Align = TextAnchor.MiddleCenter }
}, parent);
// --- Default Teams Row ---
container.Add(new CuiLabel {
RectTransform = { AnchorMin = "0.1 0.82", AnchorMax = "0.3 0.87" },
Text = { Text = "Default Teams", FontSize = 24, Align = TextAnchor.MiddleLeft }
}, parent);
int index = 0;
foreach (var teamName in teamNames)
{
container.Add(new CuiButton {
RectTransform = { AnchorMin = $"{0.35f + index * 0.12f} 0.82", AnchorMax = $"{0.45f + index * 0.12f} 0.87" },
Button = { Command = $"team.toggleddefault {teamName}", Color = defaultTeams.Contains(teamName) ? "0.2 0.8 0.2 1.0" : "0.8 0.2 0.2 1.0" },
Text = { Text = teamName, FontSize = 24, Align = TextAnchor.MiddleCenter }
}, parent);
index++;
}
// --- Player Grid (Team Assignment) ---
int playersPerPage = 6 * 10; // 60 players per page
var players = BasePlayer.activePlayerList.Skip(page * playersPerPage).Take(playersPerPage).ToList();
// Adjust grid starting position to be below the default teams row.float gridStartX = 0.1f;
float gridStartY = 0.75f;
float buttonWidth = 0.13f;
float buttonHeight = 0.06f;
float hSpacing = 0.02f;
float vSpacing = 0.01f;
int cols = 6;
for (int i = 0; i < players.Count; i++)
{
int col = i % cols;
int row = i / cols;
float xMin = gridStartX + col * (buttonWidth + hSpacing);
float xMax = xMin + buttonWidth;
float yMax = gridStartY - row * (buttonHeight + vSpacing);
float yMin = yMax - buttonHeight;
BasePlayer p = players[i];
string playerId = p.UserIDString;
// Set button color based on assigned team (gray if none)
string boxColor = "0.5 0.5 0.5 1.0";
if (playerTeams.ContainsKey(playerId))
{
string team = playerTeams[playerId];
if (teamColors.ContainsKey(team))
boxColor = teamColors[team];
}
container.Add(new CuiButton
{
RectTransform = { AnchorMin = $"{xMin} {yMin}", AnchorMax = $"{xMax} {yMax}" },
Button = { Command = $"team.openselect {playerId} {page}", Color = boxColor },
Text = { Text = p.displayName, FontSize = 14, Align = TextAnchor.MiddleCenter }
}, parent);
}
// --- Pagination Arrows ---
int totalPlayers = BasePlayer.activePlayerList.Count;
int totalPages = (int)Math.Ceiling((double)totalPlayers / playersPerPage);
if (totalPages > 1)
{
if (page > 0)
{
container.Add(new CuiButton
{
RectTransform = { AnchorMin = "0.1 0.05", AnchorMax = "0.2 0.1" },
Button = { Command = $"team.paginate {page - 1}", Color = "0.2 0.5 0.8 1.0" },
Text = { Text = "<< Previous", FontSize = 20, Align = TextAnchor.MiddleCenter }
}, parent);
}
if (page < totalPages - 1)
{
container.Add(new CuiButton
{
RectTransform = { AnchorMin = "0.8 0.05", AnchorMax = "0.9 0.1" },
Button = { Command = $"team.paginate {page + 1}", Color = "0.2 0.5 0.8 1.0" },
Text = { Text = "Next >>", FontSize = 20, Align = TextAnchor.MiddleCenter }
}, parent);
}
}
}
private void OpenTeamSelectionMenu(BasePlayer admin, string targetPlayerId, int page)
{
// Destroy any existing team selection UI
CuiHelper.DestroyUi(admin, "TeamSelectionUI");
var container = new CuiElementContainer();
// Create a centered panel for team selection
container.Add(new CuiPanel
{
RectTransform = { AnchorMin = "0.3 0.3", AnchorMax = "0.7 0.7" },
Image = { Color = "0.1 0.1 0.1 0.9" }
}, "Overlay", "TeamSelectionUI");
// Title label
container.Add(new CuiLabel
{
RectTransform = { AnchorMin = "0.32 0.65", AnchorMax = "0.68 0.75" },
Text = { Text = "Select a Team", FontSize = 24, Align = TextAnchor.MiddleCenter }
}, "TeamSelectionUI");
// Show one button per team from teamNames.int teamCount = teamNames.Count;
float buttonWidth = 0.15f;
float spacing = 0.05f;
float totalWidth = teamCount * buttonWidth + (teamCount - 1) * spacing;
float startX = 0.5f - totalWidth / 2;
for (int i = 0; i < teamCount; i++)
{
string teamName = teamNames[i];
float xMin = startX + i * (buttonWidth + spacing);
float xMax = xMin + buttonWidth;
container.Add(new CuiButton
{
RectTransform = { AnchorMin = $"{xMin} 0.45", AnchorMax = $"{xMax} 0.55" },
Button = { Command = $"team.assignplayer {targetPlayerId} {teamName} {page}", Color = teamColors.ContainsKey(teamName) ? teamColors[teamName] : "0.2 0.2 0.2 1.0" },
Text = { Text = teamName, FontSize = 18, Align = TextAnchor.MiddleCenter }
}, "TeamSelectionUI");
}
// A close button to cancel team selection and return to the teams tab.container.Add(new CuiButton
{
RectTransform = { AnchorMin = "0.45 0.35", AnchorMax = "0.55 0.4" },
Button = { Command = $"team.closeSelect {page}", Color = "0.8 0.2 0.2 1.0" },
Text = { Text = "Close", FontSize = 18, Align = TextAnchor.MiddleCenter }
}, "TeamSelectionUI");
CuiHelper.AddUi(admin, container);
}
// Pagination command for teams tab.[ConsoleCommand("team.paginate")]
private void HandleTeamPagination(ConsoleSystem.Arg args)
{
BasePlayer admin = args.Connection?.player as BasePlayer;
if (admin == null) return;
int page = 0;
if (args.Args != null && args.Args.Length > 0)
int.TryParse(args.Args[0], out page);
OpenMainMenu(admin, "teams");
}
// Command triggered when a player name button is clicked.// It opens the team selection menu for that player.[ConsoleCommand("team.openselect")]
private void OpenTeamSelectCommand(ConsoleSystem.Arg args)
{
BasePlayer admin = args.Connection?.player as BasePlayer;
if (admin == null) return;
if (args.Args == null || args.Args.Length < 2) return;
string targetPlayerId = args.Args[0];
int page = 0;
int.TryParse(args.Args[1], out page);
OpenTeamSelectionMenu(admin, targetPlayerId, page);
}
// Command to close the team selection menu and return to the teams tab.[ConsoleCommand("team.closeSelect")]
private void CloseTeamSelectCommand(ConsoleSystem.Arg args)
{
BasePlayer admin = args.Connection?.player as BasePlayer;
if (admin == null) return;
int page = 0;
if (args.Args != null && args.Args.Length > 0)
int.TryParse(args.Args[0], out page);
CuiHelper.DestroyUi(admin, "TeamSelectionUI");
OpenMainMenu(admin, "teams");
}
// Command that is run when a team button is clicked in the team selection menu.// It assigns the target player to the chosen team.[ConsoleCommand("team.assignplayer")]
private void AssignPlayerToTeamCommand(ConsoleSystem.Arg args)
{
BasePlayer admin = args.Connection?.player as BasePlayer;
if (admin == null) return;
if (args.Args == null || args.Args.Length < 3) return;
string targetPlayerId = args.Args[0];
string newTeamName = args.Args[1];
int page = 0;
int.TryParse(args.Args[2], out page);
// Validate team name.if (!teamNames.Contains(newTeamName))
{
SendReply(admin, $"Team {newTeamName} does not exist.");
return;
}
// Update our internal dictionary.if (playerTeams.ContainsKey(targetPlayerId))
playerTeams[targetPlayerId] = newTeamName;
else
playerTeams.Add(targetPlayerId, newTeamName);
// Find the target player.var targetPlayer = BasePlayer.FindByID(ulong.Parse(targetPlayerId));
if (targetPlayer == null)
{
SendReply(admin, "Player not found.");
return;
}
// If the player is already in a team, remove them from it.if (targetPlayer.currentTeam != 0)
{
var oldTeam = RelationshipManager.ServerInstance.FindTeam(targetPlayer.currentTeam);
if (oldTeam != null)
{
oldTeam.RemovePlayer(targetPlayer.userID);
UpdateTeamMembers(oldTeam);
}
}
// Find or create the new team.RelationshipManager.PlayerTeam newTeam;
if (!teamMapping.ContainsKey(newTeamName))
{
newTeam = RelationshipManager.ServerInstance.CreateTeam();
newTeam.teamName = newTeamName;
teamMapping[newTeamName] = newTeam.teamID;
}
else
{
newTeam = RelationshipManager.ServerInstance.FindTeam(teamMapping[newTeamName]);
}
// Add the player to the new team.newTeam.AddPlayer(targetPlayer);
targetPlayer.currentTeam = newTeam.teamID;
UpdateTeamMembers(newTeam);
// Notify the player.targetPlayer.ChatMessage($"You have been added to the team: {newTeamName}");
// Close the team selection UI and refresh the Teams tab.CuiHelper.DestroyUi(admin, "TeamSelectionUI");
OpenMainMenu(admin, "teams", page: page);
}
[ConsoleCommand("team.togglefriendlyfire")]
private void ToggleFriendlyFire(ConsoleSystem.Arg args)
{
BasePlayer player = args.Connection?.player as BasePlayer;
if (player == null) return;
// Toggle the friendly fire setting
friendlyFire = !friendlyFire;
Config["FriendlyFire"] = friendlyFire;
SaveConfig();
// Notify the admin
player.ChatMessage($"Friendly Fire is now {(friendlyFire ? "Enabled" : "Disabled")}");
// Refresh the UI
OpenMainMenu(player, "teams");
}
[ConsoleCommand("team.toggleddefault")]
private void ToggleDefaultTeam(ConsoleSystem.Arg args)
{
BasePlayer player = args.Connection?.player as BasePlayer;
if (player == null || args.Args.Length < 1) return;
string teamName = args.Args[0];
if (defaultTeams.Contains(teamName))
defaultTeams.Remove(teamName);
else
defaultTeams.Add(teamName);
Config["DefaultTeams"] = defaultTeams;
SaveConfig();
player.ChatMessage($"Default teams updated: {string.Join(", ", defaultTeams)}");
OpenMainMenu(player, "teams");
}
void OnPlayerConnected(BasePlayer player)
{
// Check if the player is already assigned to a team
if (playerTeams.ContainsKey(player.UserIDString))
{
string team = playerTeams[player.UserIDString];
player.ChatMessage($"Welcome back! You are in team {team}.");
return;
}
// Handle players who are excluded from auto-team assignment
if (defaultTeams == null || defaultTeams.Count == 0)
{
player.ChatMessage("You are not assigned to any team.");
return;
}
// Find the least populated default team
string assignedTeam = defaultTeams.OrderBy(t =>
{
// Ensure the team exists in the teamMapping dictionary
if (!teamMapping.ContainsKey(t))
{
CreateTeamIfNotExists(t);
}
return BasePlayer.activePlayerList.Count(p => playerTeams.ContainsKey(p.UserIDString) && playerTeams[p.UserIDString] == t);
}).First();
// Assign the player to the selected team
playerTeams[player.UserIDString] = assignedTeam;
var newTeam = RelationshipManager.ServerInstance.FindTeam(teamMapping[assignedTeam]);
if (newTeam == null)
{
newTeam = CreateTeamIfNotExists(assignedTeam);
}
newTeam.AddPlayer(player);
player.currentTeam = newTeam.teamID;
player.ChatMessage($"You have been added to the default team: {assignedTeam}.");
}
// Helper Method to Create a Team If It Doesn't Exist
private RelationshipManager.PlayerTeam CreateTeamIfNotExists(string teamName)
{
if (!teamMapping.ContainsKey(teamName))
{
var newTeam = RelationshipManager.ServerInstance.CreateTeam();
newTeam.teamName = teamName;
teamMapping[teamName] = newTeam.teamID;
return newTeam;
}
return RelationshipManager.ServerInstance.FindTeam(teamMapping[teamName]);
}
private void ShowLeaveTeamBlockUI(BasePlayer player)
{
// Destroy any existing blocking UI
CuiHelper.DestroyUi(player, "LeaveTeamBlockUI");
// Only show the UI if leaving teams is not allowed
if (allowTeamLeave) return;
// Create a blocking UI
var container = new CuiElementContainer();
string panelName = "LeaveTeamBlockUI";
container.Add(new CuiPanel
{
RectTransform = { AnchorMin = "0.15 0.05", AnchorMax = "0.3.12" }, // Position over the in-game Leave Team button
Image = { Color = "0 0 0 0" } // Semi-transparent black
}, "Overlay", panelName);
CuiHelper.AddUi(player, container);
}
private void RemoveLeaveTeamBlockUI(BasePlayer player)
{
CuiHelper.DestroyUi(player, "LeaveTeamBlockUI");
}
[ConsoleCommand("team.toggleleave")]
private void ToggleAllowLeave(ConsoleSystem.Arg args)
{
BasePlayer player = args.Connection?.player as BasePlayer;
if (player == null) return;
allowTeamLeave = !allowTeamLeave; // Toggle the value
Config["AllowTeamLeave"] = allowTeamLeave;
SaveConfig();
// Notify the admin about the current status
player.ChatMessage($"Allow Leave is now {(allowTeamLeave ? "enabled" : "disabled")}.");
// Update the UI for all active players
foreach (var activePlayer in BasePlayer.activePlayerList)
{
if (allowTeamLeave)
{
RemoveLeaveTeamBlockUI(activePlayer);
}
else
{
ShowLeaveTeamBlockUI(activePlayer);
}
}
OpenMainMenu(player, "teams");
}
[ConsoleCommand("team.setdefault")]
private void SetDefaultTeam(ConsoleSystem.Arg args)
{
BasePlayer admin = args.Connection?.player as BasePlayer;
if (admin == null || args.Args.Length < 1) return;
string teamName = args.Args[0];
// Validate the team name
if (!teamNames.Contains(teamName)) return;
// Update the default team
defaultTeam = teamName;
// Save the default team in the configuration
Config["DefaultTeam"] = defaultTeam;
SaveConfig();
// Refresh the UI for the admin
OpenMainMenu(admin, "teams");
}
[ConsoleCommand("team.assign")]
private void AssignPlayerToTeam(ConsoleSystem.Arg args)
{
BasePlayer admin = args.Connection?.player as BasePlayer;
if (admin == null || args.Args.Length < 2) return;
string playerId = args.Args[0];
string newTeamName = args.Args[1];
// Validate the team name
if (!teamNames.Contains(newTeamName)) return;
// Find the target player
var targetPlayer = BasePlayer.activePlayerList.FirstOrDefault(p => p.UserIDString == playerId);
if (targetPlayer == null) return;
// Update the player's team (admins bypass allowTeamLeave)
if (playerTeams.ContainsKey(playerId))
{
playerTeams[playerId] = newTeamName;
}
else
{
playerTeams.Add(playerId, newTeamName);
}
// Check if the player is already in a team
if (targetPlayer.currentTeam != 0)
{
var oldTeam = RelationshipManager.ServerInstance.FindTeam(targetPlayer.currentTeam);
if (oldTeam != null)
{
oldTeam.RemovePlayer(targetPlayer.userID);
UpdateTeamMembers(oldTeam);
}
}
// Find or create the new team
RelationshipManager.PlayerTeam newTeam;
if (!teamMapping.ContainsKey(newTeamName))
{
newTeam = RelationshipManager.ServerInstance.CreateTeam();
newTeam.teamName = newTeamName;
teamMapping[newTeamName] = newTeam.teamID;
}
else
{
newTeam = RelationshipManager.ServerInstance.FindTeam(teamMapping[newTeamName]);
}
// Add the player to the new team
newTeam.AddPlayer(targetPlayer);
targetPlayer.currentTeam = newTeam.teamID;
UpdateTeamMembers(newTeam);
// Notify the player
targetPlayer.ChatMessage($"You have been added to the team: {newTeamName}");
// Refresh the UI for the admin
OpenMainMenu(admin, "teams");
}
private void UpdateTeamMembers(RelationshipManager.PlayerTeam team)
{
foreach (var memberId in team.members)
{
var member = BasePlayer.FindByID(memberId);
if (member != null)
{
member.SendNetworkUpdateImmediate();
SendTeamInfo(member, team);
}
}
}
private void SendTeamInfo(BasePlayer player, RelationshipManager.PlayerTeam team)
{
var members = new List<object>();
foreach (var memberId in team.members)
{
var member = BasePlayer.FindByID(memberId);
if (member != null)
{
members.Add(new
{
userid = memberId,
username = member.displayName,
online = true,
avatar = string.Empty // You can add avatar URL logic if needed
});
}
}
var teamInfo = new
{
teamID = team.teamID,
teamName = team.teamName,
members
};
player.ClientRPCPlayer(null, player, "CLIENT_ReceiveTeamInfo", teamInfo);
}
private void AddPermissionsTabContent(CuiElementContainer container, string parent, int currentPage = 0)
{
const float buttonHeight = 0.05f;
const float fullButtonWidth = 0.15f; // Full width for individual player buttons
const float halfButtonWidth = fullButtonWidth / 2; // Half width for Grant/Revoke buttons
const float spacingBetweenPairs = 0.02f; // Space between revoke -> next grant
const float rowSpacing = 0.06f;
const float startY = 0.85f;
const int rowsPerPage = 10;
var entries = new List<string>();
entries.AddRange(teamNames); // Add teams
entries.AddRange(BasePlayer.activePlayerList.Select(p => p.UserIDString)); // Add players
int totalPages = (int)Math.Ceiling((double)entries.Count / rowsPerPage);
int startRow = currentPage * rowsPerPage;
// GLOBAL ROW (Handles all players)
float yMinGlobal = startY;
float yMaxGlobal = yMinGlobal + buttonHeight;
container.Add(new CuiLabel
{
RectTransform = { AnchorMin = $"0.1 {yMinGlobal}", AnchorMax = $"0.3 {yMaxGlobal}" },
Text = { Text = "Global", FontSize = 20, Align = UnityEngine.TextAnchor.MiddleLeft }
}, parent);
for (int j = 0; j < availablePerms.Count; j++)
{
float xStart = 0.35f + j * (fullButtonWidth + spacingBetweenPairs);
container.Add(new CuiButton
{
RectTransform = { AnchorMin = $"{xStart} {yMinGlobal}", AnchorMax = $"{xStart + halfButtonWidth} {yMaxGlobal}" },
Button = { Command = $"perm.globalgrant {availablePerms[j]}", Color = "0.2 0.8 0.2 1.0" },
Text = { Text = $"Grant", FontSize = 14, Align = UnityEngine.TextAnchor.MiddleCenter }
}, parent);
container.Add(new CuiButton
{
RectTransform = { AnchorMin = $"{xStart + halfButtonWidth} {yMinGlobal}", AnchorMax = $"{xStart + fullButtonWidth} {yMaxGlobal}" },
Button = { Command = $"perm.globalrevoke {availablePerms[j]}", Color = "0.8 0.2 0.2 1.0" },
Text = { Text = $"Revoke", FontSize = 14, Align = UnityEngine.TextAnchor.MiddleCenter }
}, parent);
}
// TEAM AND PLAYER ROWS
for (int i = 0; i < rowsPerPage; i++)
{
int index = startRow + i;
if (index >= entries.Count) break;
string entry = entries[index];
float yMin = startY - (i + 1) * rowSpacing;
float yMax = yMin + buttonHeight;
if (teamNames.Contains(entry))
{
// Team row with Grant/Revoke buttons
container.Add(new CuiLabel
{
RectTransform = { AnchorMin = $"0.1 {yMin}", AnchorMax = $"0.3 {yMax}" },
Text = { Text = entry, FontSize = 20, Align = UnityEngine.TextAnchor.MiddleLeft }
}, parent);
for (int j = 0; j < availablePerms.Count; j++)
{
float xStart = 0.35f + j * (fullButtonWidth + spacingBetweenPairs);
container.Add(new CuiButton
{
RectTransform = { AnchorMin = $"{xStart} {yMin}", AnchorMax = $"{xStart + halfButtonWidth} {yMax}" },
Button = { Command = $"perm.teamgrant {entry} {availablePerms[j]}", Color = "0.2 0.8 0.2 1.0" },
Text = { Text = $"Grant", FontSize = 14, Align = UnityEngine.TextAnchor.MiddleCenter }
}, parent);
container.Add(new CuiButton
{
RectTransform = { AnchorMin = $"{xStart + halfButtonWidth} {yMin}", AnchorMax = $"{xStart + fullButtonWidth} {yMax}" },
Button = { Command = $"perm.teamrevoke {entry} {availablePerms[j]}", Color = "0.8 0.2 0.2 1.0" },
Text = { Text = $"Revoke", FontSize = 14, Align = UnityEngine.TextAnchor.MiddleCenter }
}, parent);
}
}
else
{
// Individual player row with full-width permission buttons
string displayName = BasePlayer.FindByID(ulong.Parse(entry))?.displayName ?? "Unknown Player";
container.Add(new CuiLabel
{
RectTransform = { AnchorMin = $"0.1 {yMin}", AnchorMax = $"0.3 {yMax}" },
Text = { Text = displayName, FontSize = 20, Align = UnityEngine.TextAnchor.MiddleLeft }
}, parent);
for (int j = 0; j < availablePerms.Count; j++)
{
float xStart = 0.35f + j * (fullButtonWidth + spacingBetweenPairs);
bool hasPerm = permission.UserHasPermission(entry, availablePerms[j]);
container.Add(new CuiButton
{
RectTransform = { AnchorMin = $"{xStart} {yMin}", AnchorMax = $"{xStart + fullButtonWidth} {yMax}" },
Button = { Command = $"perm.toggle {entry} {availablePerms[j]}", Color = hasPerm ? "0.2 0.8 0.2 1.0" : "0.8 0.2 0.2 1.0" },
Text = { Text = availablePerms[j], FontSize = 18, Align = UnityEngine.TextAnchor.MiddleCenter }
}, parent);
}
}
}
}
private const string BypassPermission = "eventcontrolui.bypass";
[ConsoleCommand("perm.globalgrant")]
private void GrantGlobalPermission(ConsoleSystem.Arg args)
{
if (args.Connection?.player is not BasePlayer admin || args.Args.Length < 1)
{
return;
}
string perm = args.Args[0].Trim();
int grantedCount = 0;
foreach (var player in BasePlayer.activePlayerList)
{
if (permission.UserHasPermission(player.UserIDString, BypassPermission))
{
SendReply(admin, $"Skipping {player.displayName} (bypass enabled)");
continue;
}
permission.GrantUserPermission(player.UserIDString, perm, null);
if (permission.UserHasPermission(player.UserIDString, perm))
{
grantedCount++;
}
else
{
Puts($"[DEBUG] Failed to grant {perm} to {player.displayName}");
}
}
SendReply(admin, $"Granted {perm} to {grantedCount} players (excluding bypassed).");
OpenMainMenu(admin, "permissions");
}
[ConsoleCommand("perm.globalrevoke")]
private void RevokeGlobalPermission(ConsoleSystem.Arg args)
{
if (args.Connection?.player is not BasePlayer admin || args.Args.Length < 1)
{
return;
}
string perm = args.Args[0].Trim();
int revokedCount = 0;
foreach (var player in BasePlayer.activePlayerList)
{
if (permission.UserHasPermission(player.UserIDString, BypassPermission))
{
SendReply(admin, $"Skipping {player.displayName} (bypass enabled)");
continue;
}
permission.RevokeUserPermission(player.UserIDString, perm);
if (!permission.UserHasPermission(player.UserIDString, perm))
{
revokedCount++;
}
else
{
Puts($"[DEBUG] Failed to revoke {perm} from {player.displayName}");
}
}
SendReply(admin, $"Revoked {perm} from {revokedCount} players (excluding bypassed).");
OpenMainMenu(admin, "permissions");
}
private Dictionary<string, TimerGroup> timerGroups = new Dictionary<string, TimerGroup>();
public class TimerGroup
{
public string GroupName { get; set; }
public float RemainingTime { get; set; }
public bool IsRunning { get; set; }
public bool IsUIVisible { get; set; }
public bool RaidingOnZero { get; set; }
public bool BuildingOnZero { get; set; }
public bool PvPOnZero { get; set; }
public TimerGroup(string groupName)
{
GroupName = groupName;
RemainingTime = 0f;
IsRunning = false;
IsUIVisible = true;
RaidingOnZero = false;
BuildingOnZero = false;
PvPOnZero = false;
}
}
private void AddGlobalTabContent(CuiElementContainer container, string parent)
{
// Row 1: Set World Spawn, Heal All, Kill All
float row1YMin = 0.85f;
float row1YMax = 0.9f;
float buttonWidth = 0.25f;
float buttonHeight = 0.05f;
float spacing = 0.02f;
// Set World Spawn Button
container.Add(new CuiButton
{
RectTransform = { AnchorMin = "0.1 0.85", AnchorMax = $"{0.1 + buttonWidth} {row1YMax}" },
Button = { Command = "global.setworldspawn", Color = "0.2 0.5 0.8 1.0" },
Text = { Text = "Set World Spawn", FontSize = 20, Align = TextAnchor.MiddleCenter }
}, parent);
// Heal All Button
container.Add(new CuiButton
{
RectTransform = { AnchorMin = $"{0.1 + buttonWidth + spacing} 0.85", AnchorMax = $"{0.1 + 2 * buttonWidth + spacing} {row1YMax}" },
Button = { Command = "global.healall", Color = "0.2 0.8 0.2 1.0" },
Text = { Text = "Heal All", FontSize = 20, Align = TextAnchor.MiddleCenter }
}, parent);
// Kill All Button
container.Add(new CuiButton
{
RectTransform = { AnchorMin = $"{0.1 + 2 * buttonWidth + 2 * spacing} 0.85", AnchorMax = $"{0.1 + 3 * buttonWidth + 2 * spacing} {row1YMax}" },
Button = { Command = "global.killall", Color = "0.8 0.2 0.2 1.0" },
Text = { Text = "Kill All", FontSize = 20, Align = TextAnchor.MiddleCenter }
}, parent);
// Define the actions for each row
List<string> actionButtons = new List<string> { "Freeze", "Raiding", "PvP", "God Mode", "Building", "Loot" };
List<string> actionCommands = new List<string> { "freeze", "toggle.raiding", "toggle.pvp", "toggle.godmode", "toggle.building", "toggle.loot" };
// Row 2: Global actions
float currentY = row1YMin - 0.1f;
AddActionRow(container, parent, "Global", actionButtons, actionCommands, 0.1f, currentY);
// Rows 3-6: Team actions
for (int i = 0; i < teamNames.Count; i++)
{
currentY -= 0.07f;
AddActionRow(container, parent, teamNames[i], actionButtons, actionCommands, 0.1f, currentY, isTeam: true);
}
}
private void AddActionRow(CuiElementContainer container, string parent, string rowLabel, List<string> actions, List<string> commands, float xStart, float y, bool isTeam = false)
{
// Row Label
container.Add(new CuiLabel
{
RectTransform = { AnchorMin = $"{xStart} {y + 0.04f}", AnchorMax = $"{xStart + 0.1f} {y + 0.09f}" },
Text = { Text = $"[{rowLabel}]", FontSize = 20, Align = TextAnchor.MiddleLeft }
}, parent);
// Action Buttons
float buttonWidth = 0.1f;
float buttonHeight = 0.05f;
float spacing = 0.02f;
float currentX = xStart + 0.12f;
for (int i = 0; i < actions.Count; i++)
{
string action = actions[i];
string command = commands[i];
// Determine the current state of the action
bool isEnabled = false;
switch (action)
{
case "Freeze":
// Set isEnabled for Freeze, e.g.:
isEnabled = isTeam ? (teamFreezeStatus.ContainsKey(rowLabel) && teamFreezeStatus[rowLabel])
: globalFreezeEnabled;
break; // Ensure break is present here
case "Loot":
isEnabled = isTeam ? (teamLootStatus.ContainsKey(rowLabel) && teamLootStatus[rowLabel])
: lootAllowed;
break;
case "Raiding":
isEnabled = isTeam ? teamRaidingStatus.ContainsKey(rowLabel) && teamRaidingStatus[rowLabel]
: raidingEnabled;
break;
case "PvP":
isEnabled = isTeam ? teamPvPStatus.ContainsKey(rowLabel) && teamPvPStatus[rowLabel]
: pvpEnabled;
break;
case "God Mode":
isEnabled = isTeam ? teamGodModeStatus.ContainsKey(rowLabel) && teamGodModeStatus[rowLabel]
: godModeEnabled;
break;
case "Building":
isEnabled = isTeam ? teamBuildingStatus.ContainsKey(rowLabel) && teamBuildingStatus[rowLabel]
: buildingEnabled;
break;
default:
break;
}
// Set button color based on state
string color = isEnabled ? "0.2 0.8 0.2 1.0" : "0.8 0.2 0.2 1.0"; // Green for on, Red for off
// Define the command based on whether it's Global or Team
string fullCommand = "";
switch (action)
{
case "Freeze":
fullCommand = isTeam ? $"global.freeze.team {rowLabel}" : $"global.freeze";
break;
case "Raiding":
fullCommand = isTeam ? $"global.toggle.raiding.team {rowLabel}" : $"global.toggle.raiding";
break;
case "PvP":
fullCommand = isTeam ? $"global.toggle.pvp.team {rowLabel}" : $"global.toggle.pvp";
break;
case "God Mode":
fullCommand = isTeam ? $"global.toggle.godmode.team {rowLabel}" : $"global.toggle.godmode";
break;
case "Building":
fullCommand = isTeam ? $"global.toggle.building.team {rowLabel}" : $"global.toggle.building";
break;
default:
fullCommand = $"global.{command.ToLower()}";
break;
}
container.Add(new CuiButton
{
RectTransform = { AnchorMin = $"{currentX} {y}", AnchorMax = $"{currentX + buttonWidth} {y + buttonHeight}" },
Button = { Command = fullCommand, Color = color },
Text = { Text = action, FontSize = 18, Align = TextAnchor.MiddleCenter }
}, parent);
currentX += buttonWidth + spacing;
}
}
// Global Permission Flag
private bool globalPermEnabled;
// Global Settings
private bool globalFreezeEnabled;
private bool globalBuildingEnabled;
private bool globalRaidingEnabled;
private bool globalPvPEnabled;
// Global feature states
private bool raidingEnabled = true;
private bool pvpEnabled = true;
private bool godModeEnabled = false;
private bool buildingEnabled = true;
// Team-specific feature states
private Dictionary<string, bool> teamFreezeStatus = new Dictionary<string, bool>();
private Dictionary<string, bool> teamRaidingStatus = new Dictionary<string, bool>();
private Dictionary<string, bool> teamPvPStatus = new Dictionary<string, bool>();
private Dictionary<string, bool> teamGodModeStatus = new Dictionary<string, bool>();
private Dictionary<string, bool> teamBuildingStatus = new Dictionary<string, bool>();
private void LoadConfigValues()
{
// Load global permissions
globalPermEnabled = Convert.ToBoolean(Config["GlobalPermEnabled"] ?? false);
globalFreezeEnabled = Convert.ToBoolean(Config["GlobalFreezeEnabled"] ?? false);
globalBuildingEnabled = Convert.ToBoolean(Config["GlobalBuildingEnabled"] ?? true);
globalRaidingEnabled = Convert.ToBoolean(Config["GlobalRaidingEnabled"] ?? true);
globalPvPEnabled = Convert.ToBoolean(Config["GlobalPvPEnabled"] ?? true);
// Load team-specific settings
teamFreezeStatus = Config["TeamFreezeStatus"] as Dictionary<string, bool> ?? new Dictionary<string, bool>();
teamBuildingStatus = Config["TeamBuildingStatus"] as Dictionary<string, bool> ?? new Dictionary<string, bool>();
teamRaidingStatus = Config["TeamRaidingStatus"] as Dictionary<string, bool> ?? new Dictionary<string, bool>();
teamPvPStatus = Config["TeamPvPStatus"] as Dictionary<string, bool> ?? new Dictionary<string, bool>();
}
[ConsoleCommand("global.toggle.loot")]
private void ToggleGlobalLoot(ConsoleSystem.Arg args)
{
BasePlayer admin = args.Connection?.player as BasePlayer;
if (admin == null || !permission.UserHasPermission(admin.UserIDString, PermissionManagePerms))
{
SendReply(admin, "You don't ha
// ... [Code preview truncated due to length. Full source in attached file] ...