C#:
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.IO;
using System.Globalization;
using UnityEngine;
namespace Oxide.Plugins {
[Info("Leaders", "fufeldev", "1.0.0")]
public class Leaders : RustPlugin {
[PluginReference]
private Plugin SClan, FBuildZoneStages, Stadia;
private const string UiRoot = "Leaders_UI";
private const int MaxRows = 7;
private const int KillPoints = 1;
private const int CupboardRaidPoints = 40;
private const int BradleyCratePoints = 4;
private const int HeliCratePoints = 5;
private const int HeliCrateMaxPointsPerPlayer = 20;
private const int RaidBanSeconds = 10800;
private const string RaidBanReason = "Clan raided";
private const string RaidBanData = "Leaders/RaidBans";
private const string RaidAttentionColor = "#E87878";
private const string RaidVictimColor = "#5dade2";
private readonly Dictionary<string, string> _imageStorageIds = new Dictionary<string, string>();
private readonly List<ClanRow> _demoRows = new List<ClanRow>();
private readonly HashSet<ulong> _bradleyCrates = new HashSet<ulong>();
private readonly HashSet<ulong> _scoredBradleyCrates = new HashSet<ulong>();
private readonly HashSet<ulong> _scoredHeliCrates = new HashSet<ulong>();
private readonly Dictionary<ulong, int> _heliCratePlayerPoints = new Dictionary<ulong, int>();
private readonly Dictionary<ulong, long> _raidBans = new Dictionary<ulong, long>();
private readonly Dictionary<NetworkableId, DamageEntry> _lastCupboardDamagers = new Dictionary<NetworkableId, DamageEntry>();
private readonly Dictionary<NetworkableId, string> _cupboardClanTags = new Dictionary<NetworkableId, string>();
private readonly Dictionary<NetworkableId, CupboardEntry> _cupboardEntries = new Dictionary<NetworkableId, CupboardEntry>();
private readonly Dictionary<ulong, DamageEntry> _lastPlayerDamagers = new Dictionary<ulong, DamageEntry>();
private readonly HashSet<NetworkableId> _scoredCupboards = new HashSet<NetworkableId>();
private static readonly Dictionary<string, string> ImageFiles = new Dictionary<string, string> {
{
"Hudaima_Leaders_Path_2", "Hudaima_Leaders_Path_2.png"
}
, {
"Hudaima_Leaders_Header_Backplate_1", "Hudaima_Leaders_Header_Backplate_1.png"
}
, {
"Hudaima_Leaders_Rank_1_Badge_1", "Hudaima_Leaders_Rank_1_Badge_1.png"
}
}
;
private class ClanRow {
public string Tag;
public int Points;
}
private class ClanSaveData {
public string ClanTag;
public Dictionary<ulong, ClanMemberSaveData> Members = new Dictionary<ulong, ClanMemberSaveData>();
}
private class ClanMemberSaveData {
public int Point;
}
private class DamageEntry {
public ulong UserId;
public float Time;
public string ClanTag;
public bool HasGear;
}
private class CupboardEntry {
public ulong OwnerId;
public string ClanTag;
public string GroupKey;
public HashSet<ulong> UserIds = new HashSet<ulong>();
public DamageEntry LastDamage;
}
private void OnServerInitialized() {
LoadImageAssets();
LoadRaidBans();
ScheduleRaidBans();
ScanCupboardClans();
timer.Once(1f, ShowAll);
timer.Every(10f, ShowAll);
}
private void OnEntitySpawned(BuildingPrivlidge priv) {
NextTick(() => RememberCupboardState(priv));
}
private void OnPlayerInit(BasePlayer player) {
QueueShow(player);
}
private void OnPlayerConnected(BasePlayer player) {
QueueShow(player);
}
private void OnPlayerRespawned(BasePlayer player) {
QueueShow(player);
}
private void OnPluginLoaded(Plugin plugin) {
if (plugin != null && (plugin.Name == "SClan" || plugin.Name == "FBuildZoneStages")) {
ScanCupboardClans();
}
if (plugin != null && plugin.Name == "SClan") {
timer.Once(1f, ShowAll);
}
}
private void OnClanCreate(string clanTag) {
timer.Once(0.5f, ShowAll);
}
private void OnClanDestroy(string clanTag) {
timer.Once(0.5f, ShowAll);
}
private void OnClanMemberJoined(string userID, string clanTag) {
timer.Once(0.5f, ShowAll);
}
private void OnClanMemberGone(string userID, string clanTag) {
timer.Once(0.5f, ShowAll);
}
private void OnPlayerDeath(BasePlayer player, HitInfo info) {
if (player == null || player.IsNpc || !player.userID.IsSteamId()) return;
ulong attackerId = GetAttackerId(info);
bool hasGear = HasScorableGear(player);
if (_lastPlayerDamagers.TryGetValue(player.userID, out DamageEntry entry) && Time.realtimeSinceStartup - entry.Time <= 300f) {
if (!attackerId.IsSteamId()) attackerId = entry.UserId;
if (entry.HasGear) hasGear = true;
}
if (!attackerId.IsSteamId() || attackerId == player.userID || IsSameClan(player.userID, attackerId) || !hasGear) return;
AddPoints(attackerId, KillPoints);
}
private void OnEntityDeath(BaseCombatEntity entity, HitInfo info) {
if (!IsCupboardEntity(entity)) return;
BuildingPrivlidge priv = GetCupboardPrivilege(entity);
if (priv == null) return;
ScoreCupboard(priv, info);
}
private void ScoreCupboard(BuildingPrivlidge priv, HitInfo info) {
if (priv?.net == null) {
return;
}
if (_scoredCupboards.Contains(priv.net.ID)) {
return;
}
string phase = GetCurrentPhase();
if (!IsRaidPhaseName(phase)) {
return;
}
CupboardEntry cupboard = RememberCupboardState(priv);
string victimClan = GetCupboardClanTag(priv, cupboard);
ulong attackerId = GetCupboardAttackerId(priv, info, cupboard);
BasePlayer attackerPlayer = GetAttackerPlayer(attackerId, info, priv);
string attackerClan = GetClanTag(attackerId);
ulong victimOwnerId = GetRaidVictimOwnerId(priv, cupboard, victimClan);
bool own = attackerId.IsSteamId() && IsOwnCupboard(priv, attackerId, cupboard);
if (string.IsNullOrEmpty(victimClan)) {
return;
}
if (own) {
return;
}
if (!string.IsNullOrEmpty(attackerClan) && string.Equals(victimClan, attackerClan, StringComparison.OrdinalIgnoreCase)) {
return;
}
_scoredCupboards.Add(priv.net.ID);
EliminateCupboardClan(priv, cupboard, victimClan, victimOwnerId, attackerId, attackerClan, attackerPlayer);
}
private ulong GetCupboardAttackerId(BuildingPrivlidge priv, HitInfo info, CupboardEntry cupboard) {
ulong attackerId = GetAttackerId(info);
if (!attackerId.IsSteamId()) attackerId = GetEntityPlayerId(priv.lastAttacker);
if (_lastCupboardDamagers.TryGetValue(priv.net.ID, out DamageEntry entry) && Time.realtimeSinceStartup - entry.Time <= 900f) {
if (!attackerId.IsSteamId()) attackerId = entry.UserId;
}
if (cupboard?.LastDamage != null && Time.realtimeSinceStartup - cupboard.LastDamage.Time <= 900f) {
if (!attackerId.IsSteamId()) attackerId = cupboard.LastDamage.UserId;
}
return attackerId;
}
private BasePlayer GetAttackerPlayer(ulong attackerId, HitInfo info, BuildingPrivlidge priv) {
BasePlayer player = info?.InitiatorPlayer;
if (player != null && !player.IsNpc && player.userID.IsSteamId()) return player;
player = priv?.lastAttacker as BasePlayer;
if (player != null && !player.IsNpc && player.userID.IsSteamId()) return player;
return attackerId.IsSteamId() ? BasePlayer.FindAwakeOrSleepingByID(attackerId) : null;
}
private ulong GetRaidVictimOwnerId(BuildingPrivlidge priv, CupboardEntry cupboard, string victimClan) {
ulong ownerId = cupboard == null ? priv.OwnerID : cupboard.OwnerId;
if (ownerId.IsSteamId() && string.Equals(GetClanTag(ownerId), victimClan, StringComparison.OrdinalIgnoreCase)) return ownerId;
object result = SClan?.Call("GetOwnerId", victimClan);
if (result is ulong userId && userId.IsSteamId()) return userId;
if (result is string text && ulong.TryParse(text, out ulong parsed) && parsed.IsSteamId()) return parsed;
return ownerId;
}
private void EliminateCupboardClan(BuildingPrivlidge priv, CupboardEntry cupboard, string victimClan, ulong victimOwnerId, ulong attackerId, string attackerClan, BasePlayer attackerPlayer) {
List<string> members = GetClanMembers(victimClan);
Interface.CallHook("OnTournamentClanEliminated", victimClan, members);
AnnounceClanEliminated(priv, victimClan, attackerId, attackerClan, attackerPlayer);
if (attackerId.IsSteamId() && !string.IsNullOrEmpty(attackerClan)) {
AddPoints(attackerId, CupboardRaidPoints);
SClan?.CallHook("GetPointRaid", victimOwnerId, attackerId);
}
BanCupboardVictims(priv, victimClan, cupboard);
timer.Once(0.2f, ShowAll);
}
private void AnnounceClanEliminated(BuildingPrivlidge priv, string victimClan, ulong attackerId, string attackerClan, BasePlayer attackerPlayer) {
Server.Broadcast(BuildRaidStartedMessage(MapHelper.PositionToString(priv.transform.position)));
}
private string BuildRaidStartedMessage(string grid) {
return $"<color={RaidAttentionColor}>ВНИМАНИЕ!</color>\n<size=12>Рейд начался в квадрате <color={RaidVictimColor}>{grid}</color></size>";
}
private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
ulong userId = GetAttackerId(info);
if (!userId.IsSteamId()) return null;
BasePlayer player = entity as BasePlayer;
if (player != null && !player.IsNpc && player.userID.IsSteamId() && player.userID != userId) {
_lastPlayerDamagers[player.userID] = new DamageEntry {
UserId = userId, Time = Time.realtimeSinceStartup, HasGear = HasScorableGear(player)
}
;
return null;
}
BuildingPrivlidge priv = GetCupboardPrivilege(entity);
if (priv != null) {
bool own = IsOwnCupboard(priv, userId);
if (own) return true;
RememberCupboardDamage(priv, userId);
}
return null;
}
private void RememberCupboardDamage(BuildingPrivlidge priv, ulong userId) {
if (priv?.net == null) return;
CupboardEntry cupboard = RememberCupboardState(priv);
DamageEntry damage = new DamageEntry {
UserId = userId, Time = Time.realtimeSinceStartup, ClanTag = GetCupboardClanTag(priv, cupboard)
}
;
_lastCupboardDamagers[priv.net.ID] = damage;
if (cupboard != null) cupboard.LastDamage = damage;
}
private void OnCrateSpawned(BradleyAPC bradley, BaseEntity crate) {
if (crate?.net == null) return;
_bradleyCrates.Add(crate.net.ID.Value);
}
private void OnLootEntity(BasePlayer player, BaseEntity entity) {
if (player == null || entity?.net == null || !player.userID.IsSteamId()) return;
ulong id = entity.net.ID.Value;
if (_bradleyCrates.Contains(id) || entity.ShortPrefabName == "bradley_crate") {
if (!_scoredBradleyCrates.Add(id)) return;
_bradleyCrates.Add(id);
AddPoints(player.userID, BradleyCratePoints);
return;
}
if (entity.ShortPrefabName == "heli_crate") {
if (!_scoredHeliCrates.Add(id)) return;
int current = _heliCratePlayerPoints.TryGetValue(player.userID, out var v) ? v : 0;
if (current >= HeliCrateMaxPointsPerPlayer) return;
int awarded = Math.Min(HeliCratePoints, HeliCrateMaxPointsPerPlayer - current);
_heliCratePlayerPoints[player.userID] = current + awarded;
AddPoints(player.userID, awarded);
}
}
private void OnEntityKill(BaseNetworkable entity) {
if (entity?.net == null) return;
ulong id = entity.net.ID.Value;
BaseEntity baseEntity = entity as BaseEntity;
BuildingPrivlidge priv = GetCupboardPrivilege(baseEntity);
if (priv != null) {
ScoreCupboard(priv, null);
}
_bradleyCrates.Remove(id);
_scoredBradleyCrates.Remove(id);
_scoredHeliCrates.Remove(id);
_lastCupboardDamagers.Remove(entity.net.ID);
_cupboardClanTags.Remove(entity.net.ID);
_cupboardEntries.Remove(entity.net.ID);
}
private void OnEntityKill(BuildingPrivlidge priv) {
ScoreCupboard(priv, null);
if (priv?.net != null) {
_cupboardClanTags.Remove(priv.net.ID);
_cupboardEntries.Remove(priv.net.ID);
}
}
private void QueueShow(BasePlayer player) {
if (player == null || player.IsNpc) {
return;
}
timer.Once(2f, () => {
if (player != null && player.IsConnected && !player.IsNpc) {
CreateUI(player);
}
}
);
}
private void LoadImageAssets() {
var imageDir = Path.Combine(Interface.Oxide.DataDirectory, "Leaders", "Images");
Directory.CreateDirectory(imageDir);
_imageStorageIds.Clear();
foreach (var kv in ImageFiles) {
var path = Path.Combine(imageDir, kv.Value);
if (!File.Exists(path)) {
PrintWarning($"[UIAssets] Missing PNG file: {path}");
continue;
}
try {
var bytes = File.ReadAllBytes(path);
_imageStorageIds[kv.Key] = FileStorage.server.Store(bytes, FileStorage.Type.png, CommunityEntity.ServerInstance.net.ID).ToString();
}
catch (Exception ex) {
PrintWarning($"[UIAssets] Failed to load {kv.Key}: {ex.Message}");
}
}
}
private string Img(string key) {
return _imageStorageIds.TryGetValue(key, out var stored) ? stored : string.Empty;
}
[ChatCommand("leaders.show")]
private void ShowUICommand(BasePlayer player, string command, string[] args) {
CreateUI(player);
}
[ConsoleCommand("leaders.show")]
private void ShowConsoleCommand(ConsoleSystem.Arg arg) {
var player = arg.Player();
if (player == null) {
ShowAll();
return;
}
CreateUI(player);
}
[ConsoleCommand("leaders.refresh")]
private void RefreshConsoleCommand(ConsoleSystem.Arg arg) {
ShowAll();
}
[ConsoleCommand("leaders.demo")]
private void DemoConsoleCommand(ConsoleSystem.Arg arg) {
var args = arg.Args;
if (args != null && args.Length > 0 && (args[0] == "clear" || args[0] == "delete" || args[0] == "remove")) {
_demoRows.Clear();
ShowAll();
return;
}
_demoRows.Clear();
for (var i = 1; i <= 30; i++) {
_demoRows.Add(new ClanRow {
Tag = $"DEMO{i:00}", Points = 3000 - i * 73
}
);
}
ShowAll();
}
private void ShowAll() {
foreach (var player in BasePlayer.activePlayerList) {
if (player == null || !player.IsConnected || player.IsNpc) {
continue;
}
CreateUI(player);
}
}
private List<ClanRow> GetClanRows() {
var rows = new List<ClanRow>();
if (_demoRows.Count > 0) {
rows.AddRange(_demoRows);
rows.Sort((a, b) => {
var points = b.Points.CompareTo(a.Points);
return points != 0 ? points : string.Compare(a.Tag, b.Tag, StringComparison.OrdinalIgnoreCase);
}
);
return rows;
}
var tops = SClan?.Call("GetTops");
if (tops is Dictionary<string, int> typed) {
foreach (var kv in typed) {
if (!string.IsNullOrWhiteSpace(kv.Key)) {
rows.Add(new ClanRow {
Tag = kv.Key, Points = kv.Value
}
);
}
}
}
else if (tops is Dictionary<string, object> objects) {
foreach (var kv in objects) {
if (!string.IsNullOrWhiteSpace(kv.Key)) {
rows.Add(new ClanRow {
Tag = kv.Key, Points = Convert.ToInt32(kv.Value)
}
);
}
}
}
if (rows.Count == 0) {
rows = GetClanRowsFromData();
}
rows.Sort((a, b) => {
var points = b.Points.CompareTo(a.Points);
return points != 0 ? points : string.Compare(a.Tag, b.Tag, StringComparison.OrdinalIgnoreCase);
}
);
return rows;
}
private List<ClanRow> GetClanRowsFromData() {
var rows = new List<ClanRow>();
try {
var clans = Interface.Oxide.DataFileSystem.ReadObject<List<ClanSaveData>>("SClan/ClansList");
if (clans == null) {
return rows;
}
foreach (var clan in clans) {
if (clan == null || string.IsNullOrWhiteSpace(clan.ClanTag)) {
continue;
}
var points = 0;
if (clan.Members != null) {
foreach (var member in clan.Members) {
if (member.Value != null) {
points += member.Value.Point;
}
}
}
rows.Add(new ClanRow {
Tag = clan.ClanTag, Points = points
}
);
}
}
catch {
}
return rows;
}
private void AddPoints(ulong playerId, int points) {
if (!playerId.IsSteamId() || points == 0) {
return;
}
if (SClan == null) {
return;
}
SClan.Call("AddPointsToPlayer", playerId, points);
timer.Once(0.2f, ShowAll);
}
private string GetClanTag(ulong playerId) {
string tag = SClan?.Call<string>("GetClanTag", playerId);
return string.IsNullOrEmpty(tag) ? string.Empty : tag;
}
private bool IsSameClan(ulong playerId, ulong targetId) {
string first = GetClanTag(playerId);
if (string.IsNullOrEmpty(first)) return false;
string second = GetClanTag(targetId);
return !string.IsNullOrEmpty(second) && string.Equals(first, second, StringComparison.OrdinalIgnoreCase);
}
private bool IsSameGroup(ulong playerId, ulong targetId) {
if (!playerId.IsSteamId() || !targetId.IsSteamId()) return false;
if (playerId == targetId) return true;
if (SClan?.Call<bool>("IsTeammate", playerId, targetId) == true) return true;
if (IsSameClan(playerId, targetId)) return true;
RelationshipManager.PlayerTeam team = RelationshipManager.ServerInstance?.FindPlayersTeam(playerId);
return team != null && team.members != null && team.members.Contains(targetId);
}
private bool IsOwnCupboard(BuildingPrivlidge priv, ulong playerId) {
return IsOwnCupboard(priv, playerId, null);
}
private bool IsOwnCupboard(BuildingPrivlidge priv, ulong playerId, CupboardEntry cupboard) {
if (priv == null || !playerId.IsSteamId()) return false;
if (cupboard != null) {
if (cupboard.OwnerId == playerId) return true;
if (cupboard.OwnerId.IsSteamId() && IsSameGroup(cupboard.OwnerId, playerId)) return true;
if (IsOwnCupboardGroup(cupboard.GroupKey, playerId)) return true;
foreach (ulong userId in cupboard.UserIds) {
if (userId != playerId && IsSameGroup(userId, playerId)) return true;
}
}
if (priv.OwnerID == playerId) return true;
if (priv.OwnerID.IsSteamId() && IsSameGroup(priv.OwnerID, playerId)) return true;
if (IsOwnCupboardGroup(priv, playerId)) return true;
if (priv.authorizedPlayers == null) return false;
foreach (ulong userId in priv.authorizedPlayers) {
if (userId != playerId && IsSameGroup(userId, playerId)) return true;
}
return false;
}
private bool IsOwnCupboardGroup(BuildingPrivlidge priv, ulong playerId) {
Dictionary<string, object> info = FBuildZoneStages?.Call("GetCupboardInfo", priv) as Dictionary<string, object>;
if (info == null || !info.TryGetValue("groupKey", out object value)) return false;
string groupKey = value as string;
return IsOwnCupboardGroup(groupKey, playerId);
}
private bool IsOwnCupboardGroup(string groupKey, ulong playerId) {
if (string.IsNullOrEmpty(groupKey)) return false;
if (groupKey.StartsWith("clan:", StringComparison.OrdinalIgnoreCase)) {
string clan = GetClanTag(playerId);
return !string.IsNullOrEmpty(clan) && string.Equals(clan, groupKey.Substring(5), StringComparison.OrdinalIgnoreCase);
}
if (groupKey.StartsWith("team:", StringComparison.OrdinalIgnoreCase) && ulong.TryParse(groupKey.Substring(5), out ulong teamId)) {
RelationshipManager.PlayerTeam team = RelationshipManager.ServerInstance?.FindPlayersTeam(playerId);
return team != null && team.teamID == teamId;
}
if (groupKey.StartsWith("player:", StringComparison.OrdinalIgnoreCase) && ulong.TryParse(groupKey.Substring(7), out ulong ownerId)) {
return ownerId == playerId || IsSameGroup(ownerId, playerId);
}
return false;
}
private ulong GetAttackerId(HitInfo info) {
BasePlayer player = info?.InitiatorPlayer;
if (player != null && !player.IsNpc && player.userID.IsSteamId()) return player.userID;
ulong userId = GetEntityPlayerId(info?.Initiator);
if (userId.IsSteamId()) return userId;
userId = GetEntityPlayerId(info?.Weapon);
if (userId.IsSteamId()) return userId;
return 0;
}
private ulong GetEntityPlayerId(BaseEntity entity) {
HashSet<BaseEntity> visited = null;
for (int depth = 0; entity != null && depth < 8; depth++) {
if (visited == null) visited = new HashSet<BaseEntity>();
if (!visited.Add(entity)) {
return 0;
}
BasePlayer player = entity.ToPlayer();
if (player != null && !player.IsNpc && player.userID.IsSteamId()) return player.userID;
if (entity.OwnerID.IsSteamId()) return entity.OwnerID;
entity = entity.creatorEntity;
}
return 0;
}
private string GetEntityId(BaseNetworkable entity) {
return entity?.net == null ? "0" : entity.net.ID.Value.ToString();
}
private string EntityText(BaseEntity entity) {
if (entity == null) return "null";
return $"{entity.ShortPrefabName}/{entity.OwnerID}/{GetEntityPlayerId(entity)}";
}
private string HitInfoText(HitInfo info) {
if (info == null) return "null";
string damage = info.damageTypes == null ? "null" : $"{info.damageTypes.GetMajorityDamageType()}:{info.damageTypes.Total():0.0}";
return $"initiator={EntityText(info.Initiator)} initiatorPlayer={(info.InitiatorPlayer == null ? 0 : info.InitiatorPlayer.userID)} weapon={EntityText(info.Weapon)} weaponPrefab={EntityText(info.WeaponPrefab)} damage={damage}";
}
private bool HasScorableGear(BasePlayer player) {
if (player?.inventory == null) return false;
return HasScorableItem(player.inventory.containerBelt) || HasScorableItem(player.inventory.containerMain) || HasScorableItem(player.inventory.containerWear);
}
private bool HasScorableItem(ItemContainer container) {
if (container?.itemList == null) return false;
foreach (Item item in container.itemList) {
if (item?.info == null) continue;
string shortname = item.info.shortname;
if (shortname == "rock" || shortname == "torch") continue;
if (item.info.category == ItemCategory.Weapon || item.info.category == ItemCategory.Tool || item.info.category == ItemCategory.Attire) return true;
}
return false;
}
private string GetCurrentPhase() {
string phase = NormalizePhase(GetPluginPhase(FBuildZoneStages));
if (!string.IsNullOrEmpty(phase)) return phase;
phase = GetPluginPhase(Stadia);
return NormalizePhase(phase);
}
private bool IsRaidPhase() {
string phase = NormalizePhase(GetPluginPhase(FBuildZoneStages));
if (!string.IsNullOrEmpty(phase)) return IsRaidPhaseName(phase);
return IsRaidPhaseName(GetPluginPhase(Stadia));
}
private string GetPluginPhase(Plugin plugin) {
object result = plugin?.Call("GetCurrentPhase");
return result == null ? string.Empty : result.ToString();
}
private bool IsRaidPhaseName(string phase) {
phase = NormalizePhase(phase);
return phase == "raid" || phase == "phase_raid" || phase == "raidblock" || phase == "raid_block" || phase == "phase_raidblock" || phase == "phase_raid_block";
}
private string NormalizePhase(string phase) {
return string.IsNullOrEmpty(phase) ? string.Empty : phase.Trim().ToLowerInvariant();
}
private bool IsCupboardEntity(BaseEntity entity) {
if (entity == null) return false;
if (entity is BuildingPrivlidge) return true;
string shortName = entity.ShortPrefabName;
if (!string.IsNullOrEmpty(shortName) && shortName.IndexOf("cupboard.tool", StringComparison.OrdinalIgnoreCase) >= 0) return true;
string prefabName = entity.PrefabName;
return !string.IsNullOrEmpty(prefabName) && prefabName.IndexOf("cupboard.tool", StringComparison.OrdinalIgnoreCase) >= 0;
}
private BuildingPrivlidge GetCupboardPrivilege(BaseEntity entity) {
return entity as BuildingPrivlidge;
}
private void ScanCupboardClans() {
foreach (BaseNetworkable entity in BaseNetworkable.serverEntities) {
BuildingPrivlidge priv = entity as BuildingPrivlidge;
if (priv == null || priv.IsDestroyed) continue;
RememberCupboardState(priv);
}
}
private CupboardEntry RememberCupboardState(BuildingPrivlidge priv) {
if (priv?.net == null) return null;
if (!_cupboardEntries.TryGetValue(priv.net.ID, out CupboardEntry entry)) {
entry = new CupboardEntry();
_cupboardEntries[priv.net.ID] = entry;
}
entry.OwnerId = priv.OwnerID;
entry.ClanTag = GetLiveCupboardClanTag(priv);
entry.GroupKey = GetCupboardGroupKey(priv);
entry.UserIds.Clear();
if (entry.OwnerId.IsSteamId()) entry.UserIds.Add(entry.OwnerId);
if (priv.authorizedPlayers != null) {
foreach (ulong userId in priv.authorizedPlayers) {
if (userId.IsSteamId()) entry.UserIds.Add(userId);
}
}
FillGroupUsers(entry.GroupKey, entry.UserIds);
if (string.IsNullOrEmpty(entry.ClanTag)) {
foreach (ulong userId in entry.UserIds) {
string userClan = GetClanTag(userId);
if (!string.IsNullOrEmpty(userClan)) {
entry.ClanTag = userClan;
break;
}
}
}
string clan = entry.ClanTag;
if (!string.IsNullOrEmpty(clan)) _cupboardClanTags[priv.net.ID] = clan;
return entry;
}
private string GetCupboardClanTag(BuildingPrivlidge priv) {
return GetCupboardClanTag(priv, null);
}
private string GetCupboardClanTag(BuildingPrivlidge priv, CupboardEntry cupboard) {
if (!string.IsNullOrEmpty(cupboard?.ClanTag)) return cupboard.ClanTag;
if (priv?.net != null && _cupboardClanTags.TryGetValue(priv.net.ID, out string stored) && !string.IsNullOrEmpty(stored)) return stored;
return GetLiveCupboardClanTag(priv);
}
private string GetLiveCupboardClanTag(BuildingPrivlidge priv) {
Dictionary<string, object> info = FBuildZoneStages?.Call("GetCupboardInfo", priv) as Dictionary<string, object>;
if (info != null && info.TryGetValue("clanTag", out object value)) {
string tag = value as string;
if (!string.IsNullOrEmpty(tag)) return tag;
}
if (priv == null) return string.Empty;
string clan = GetClanTag(priv.OwnerID);
if (!string.IsNullOrEmpty(clan)) return clan;
if (priv.authorizedPlayers != null) {
foreach (ulong userId in priv.authorizedPlayers) {
clan = GetClanTag(userId);
if (!string.IsNullOrEmpty(clan)) return clan;
}
}
return string.Empty;
}
private HashSet<string> GetCupboardClanTags(BuildingPrivlidge priv) {
HashSet<string> clans = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
Dictionary<string, object> info = FBuildZoneStages?.Call("GetCupboardInfo", priv) as Dictionary<string, object>;
if (info != null && info.TryGetValue("clanTag", out object value)) {
string tag = value as string;
if (!string.IsNullOrEmpty(tag)) clans.Add(tag);
}
if (priv == null) return clans;
string clan = GetClanTag(priv.OwnerID);
if (!string.IsNullOrEmpty(clan)) clans.Add(clan);
if (priv.authorizedPlayers != null) {
foreach (ulong userId in priv.authorizedPlayers) {
clan = GetClanTag(userId);
if (!string.IsNullOrEmpty(clan)) clans.Add(clan);
}
}
return clans;
}
private void BanCupboardVictims(BuildingPrivlidge priv, string clanTag, CupboardEntry cupboard) {
if (!string.IsNullOrEmpty(clanTag)) {
int banned = BanClan(clanTag);
if (banned > 0) return;
}
HashSet<ulong> users = GetCupboardUserIds(priv, cupboard);
if (users.Count == 0) {
return;
}
long until = GetNow() + RaidBanSeconds;
foreach (ulong userId in users) {
if (!userId.IsSteamId()) continue;
BanPlayer(userId, until);
}
SaveRaidBans();
}
private int BanClan(string clanTag) {
List<string> members = GetClanMembers(clanTag);
if (members == null || members.Count == 0) {
return 0;
}
int count = 0;
long until = GetNow() + RaidBanSeconds;
foreach (string member in members) {
if (!ulong.TryParse(member, out ulong userId) || !userId.IsSteamId()) continue;
BanPlayer(userId, until);
count++;
}
SaveRaidBans();
return count;
}
private HashSet<ulong> GetCupboardUserIds(BuildingPrivlidge priv) {
return GetCupboardUserIds(priv, null);
}
private HashSet<ulong> GetCupboardUserIds(BuildingPrivlidge priv, CupboardEntry cupboard) {
HashSet<ulong> users = new HashSet<ulong>();
if (cupboard != null) {
foreach (ulong userId in cupboard.UserIds) {
if (userId.IsSteamId()) users.Add(userId);
}
}
if (priv != null) {
if (priv.OwnerID.IsSteamId()) users.Add(priv.OwnerID);
if (priv.authorizedPlayers != null) {
foreach (ulong userId in priv.authorizedPlayers) {
if (userId.IsSteamId()) users.Add(userId);
}
}
}
string groupKey = string.IsNullOrEmpty(cupboard?.GroupKey) ? GetCupboardGroupKey(priv) : cupboard.GroupKey;
FillGroupUsers(groupKey, users);
return users;
}
private void FillGroupUsers(string groupKey, HashSet<ulong> users) {
if (string.IsNullOrEmpty(groupKey) || users == null) return;
if (groupKey.StartsWith("player:", StringComparison.OrdinalIgnoreCase) && ulong.TryParse(groupKey.Substring(7), out ulong ownerId) && ownerId.IsSteamId()) {
users.Add(ownerId);
}
else if (groupKey.StartsWith("team:", StringComparison.OrdinalIgnoreCase) && ulong.TryParse(groupKey.Substring(5), out ulong teamId)) {
RelationshipManager.PlayerTeam team = RelationshipManager.ServerInstance?.FindTeam(teamId);
if (team != null && team.members != null) {
foreach (ulong userId in team.members) {
if (userId.IsSteamId()) users.Add(userId);
}
}
}
else if (groupKey.StartsWith("clan:", StringComparison.OrdinalIgnoreCase)) {
foreach (string member in GetClanMembers(groupKey.Substring(5))) {
if (ulong.TryParse(member, out ulong userId) && userId.IsSteamId()) users.Add(userId);
}
}
}
private string GetCupboardGroupKey(BuildingPrivlidge priv) {
Dictionary<string, object> info = FBuildZoneStages?.Call("GetCupboardInfo", priv) as Dictionary<string, object>;
if (info == null || !info.TryGetValue("groupKey", out object value)) return string.Empty;
string key = value as string;
return key ?? string.Empty;
}
private List<string> GetClanMembers(string clanTag) {
object result = SClan?.Call("GetMembersClan", clanTag);
if (result is List<string> typed) return typed;
if (result is List<object> objects) {
List<string> members = new List<string>();
foreach (object value in objects) {
if (value != null) members.Add(value.ToString());
}
return members;
}
return new List<string>();
}
private void BanPlayer(ulong userId, long until) {
ServerUsers.User current = ServerUsers.Get(userId);
if (current != null && current.group == ServerUsers.UserGroup.Banned && current.notes != RaidBanReason && (current.expiry <= 0 || current.expiry > until)) {
return;
}
_raidBans[userId] = until;
BasePlayer player = BasePlayer.FindAwakeOrSleepingByID(userId);
string name = player == null ? userId.ToString() : player.displayName;
ServerUsers.Set(userId, ServerUsers.UserGroup.Banned, name, RaidBanReason, until);
ServerUsers.Save();
if (player != null && player.IsConnected) {
player.Kick("Ваш клан зарейдили. Бан на 3 часа.");
}
ScheduleUnban(userId, until);
}
private void LoadRaidBans() {
_raidBans.Clear();
try {
Dictionary<ulong, long> stored = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, long>>(RaidBanData);
if (stored == null) return;
foreach (KeyValuePair<ulong, long> entry in stored) {
_raidBans[entry.Key] = entry.Value;
}
}
catch {
}
}
private void SaveRaidBans() {
Interface.Oxide.DataFileSystem.WriteObject(RaidBanData, _raidBans);
}
private void ScheduleRaidBans() {
List<ulong> users = new List<ulong>(_raidBans.Keys);
foreach (ulong userId in users) {
if (!_raidBans.TryGetValue(userId, out long until)) continue;
if (until <= GetNow()) UnbanPlayer(userId);
else ScheduleUnban(userId, until);
}
}
private void ScheduleUnban(ulong userId, long until) {
float seconds = until - GetNow();
if (seconds < 1f) seconds = 1f;
timer.Once(seconds, () => UnbanPlayer(userId));
}
private void UnbanPlayer(ulong userId) {
if (_raidBans.TryGetValue(userId, out long until) && until > GetNow()) {
ScheduleUnban(userId, until);
return;
}
_raidBans.Remove(userId);
ServerUsers.User current = ServerUsers.Get(userId);
if (current != null && current.group == ServerUsers.UserGroup.Banned && current.notes == RaidBanReason) {
ServerUsers.Remove(userId);
ServerUsers.Save();
}
SaveRaidBans();
}
private long GetNow() {
return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
}
private void CreateUI(BasePlayer player) {
if (player == null || !player.IsConnected || player.IsNpc) {
return;
}
CuiHelper.DestroyUi(player, UiRoot);
var container = new CuiElementContainer();
container.Add(new CuiElement {
Name = UiRoot, Parent = "Hud", Components = {
new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "0 0", OffsetMax = "0 0"
}
}
}
);
AddFrame(container);
AddHeaders(container);
AddRows(container, GetClanRows());
CuiHelper.AddUi(player, container);
}
private void AddFrame(CuiElementContainer container) {
container.Add(new CuiElement {
Name = "Hudaima_Leaders_Path_2", Parent = UiRoot, Components = {
new CuiRawImageComponent {
Color = "1 1 1 1", Png = Img("Hudaima_Leaders_Path_2")
}
, new CuiRectTransformComponent {
AnchorMin = "1.0000 1.0000", AnchorMax = "1.0000 1.0000", OffsetMin = "-160.0000 -202.0000", OffsetMax = "-20.0000 -33.3333"
}
}
}
);
container.Add(new CuiElement {
Name = "Hudaima_Leaders_Header_Backplate_1", Parent = UiRoot, Components = {
new CuiRawImageComponent {
Color = "1 1 1 1", Png = Img("Hudaima_Leaders_Header_Backplate_1")
}
, new CuiRectTransformComponent {
AnchorMin = "1.0000 1.0000", AnchorMax = "1.0000 1.0000", OffsetMin = "-160.0000 -47.3333", OffsetMax = "-20.0000 -19.3333"
}
}
}
);
}
private void AddHeaders(CuiElementContainer container) {
container.Add(new CuiElement {
Name = "Hudaima_Leaders_Title_Text_1", Parent = UiRoot, Components = {
new CuiTextComponent {
Text = "LEADERS", FontSize = 13, Align = TextAnchor.MiddleLeft, Color = "0.925 0.925 0.925 1", Font = "robotocondensed-bold.ttf"
}
, new CuiRectTransformComponent {
AnchorMin = "1.0000 1.0000", AnchorMax = "1.0000 1.0000", OffsetMin = "-109.3333 -41.3333", OffsetMax = "-36.0000 -25.3333"
}
}
}
);
container.Add(new CuiElement {
Name = "Hudaima_Leaders_Rank_Header_Text_1", Parent = UiRoot, Components = {
new CuiTextComponent {
Text = "#", FontSize = 7, Align = TextAnchor.MiddleCenter, Color = "0.722 0.722 0.722 1", Font = "robotocondensed-bold.ttf"
}
, new CuiRectTransformComponent {
AnchorMin = "1.0000 1.0000", AnchorMax = "1.0000 1.0000", OffsetMin = "-152.0000 -68.0000", OffsetMax = "-137.3333 -56.0000"
}
}
}
);
container.Add(new CuiElement {
Name = "Hudaima_Leaders_Team_Header_Text_1", Parent = UiRoot, Components = {
new CuiTextComponent {
Text = "TEAM", FontSize = 7, Align = TextAnchor.MiddleLeft, Color = "0.722 0.722 0.722 1", Font = "robotocondensed-bold.ttf"
}
, new CuiRectTransformComponent {
AnchorMin = "1.0000 1.0000", AnchorMax = "1.0000 1.0000", OffsetMin = "-130.6667 -68.0000", OffsetMax = "-104.0000 -56.0000"
}
}
}
);
container.Add(new CuiElement {
Name = "Hudaima_Leaders_Points_Header_Text_1", Parent = UiRoot, Components = {
new CuiTextComponent {
Text = "POINTS", FontSize = 7, Align = TextAnchor.MiddleRight, Color = "0.722 0.722 0.722 1", Font = "robotocondensed-bold.ttf"
}
, new CuiRectTransformComponent {
AnchorMin = "1.0000 1.0000", AnchorMax = "1.0000 1.0000", OffsetMin = "-72.0000 -68.0000", OffsetMax = "-34.6667 -56.0000"
}
}
}
);
}
private void AddRows(CuiElementContainer container, List<ClanRow> rows) {
var count = rows.Count < MaxRows ? rows.Count : MaxRows;
for (var i = 0; i < count; i++) {
AddRow(container, i + 1, rows[i]);
}
}
private void AddRow(CuiElementContainer container, int place, ClanRow row) {
var index = place - 1;
var badgeMinY = -84f - index * 18f;
var badgeMaxY = -72f - index * 18f;
var textMinY = -84.6667f - index * 18f;
var textMaxY = -71.3333f - index * 18f;
var valueMinY = -86f - index * 18f;
var valueMaxY = -70f - index * 18f;
if (place == 7) {
badgeMinY = -192.6667f;
badgeMaxY = -180.6667f;
textMinY = -193.3333f;
textMaxY = -180f;
valueMinY = -194.6667f;
valueMaxY = -178.6667f;
}
var color = place == 1 ? "1.000 0.925 0.275 1" : "0.925 0.925 0.925 1";
container.Add(new CuiElement {
Name = $"Hudaima_Leaders_Rank_{place}_Badge_1", Parent = UiRoot, Components = {
new CuiRawImageComponent {
Color = "1 1 1 1", Png = Img("Hudaima_Leaders_Rank_1_Badge_1")
}
, new CuiRectTransformComponent {
AnchorMin = "1.0000 1.0000", AnchorMax = "1.0000 1.0000", OffsetMin = string.Format(CultureInfo.InvariantCulture, "-150.6667 {0:0.####}", badgeMinY), OffsetMax = string.Format(CultureInfo.InvariantCulture, "-138.6667 {0:0.####}", badgeMaxY)
}
}
}
);
container.Add(new CuiElement {
Name = $"Hudaima_Leaders_Rank_{place}_Text_1", Parent = UiRoot, Components = {
new CuiTextComponent {
Text = place.ToString(), FontSize = 7, Align = TextAnchor.MiddleCenter, Color = "0.925 0.925 0.925 1", Font = "robotocondensed-bold.ttf"
}
, new CuiRectTransformComponent {
AnchorMin = "1.0000 1.0000", AnchorMax = "1.0000 1.0000", OffsetMin = string.Format(CultureInfo.InvariantCulture, "-152.0000 {0:0.####}", textMinY), OffsetMax = string.Format(CultureInfo.InvariantCulture, "-137.3333 {0:0.####}", textMaxY)
}
}
}
);
container.Add(new CuiElement {
Name = $"Hudaima_Leaders_Team_{place}_Text_1", Parent = UiRoot, Components = {
new CuiTextComponent {
Text = row.Tag.ToUpperInvariant(), FontSize = 11, Align = TextAnchor.MiddleLeft, Color = color, Font = "robotocondensed-bold.ttf"
// ... [Code preview truncated due to length. Full source in attached file] ...