C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
//#define DEBUG
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Oxide.Game.Rust.Libraries;
using Oxide.Plugins.AdminRadarExtensionMethods;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
/*
https://umod.org/community/admin-radar/47629-radar-not-on-by-defaultconnect?page=1#post-6
https://umod.org/community/admin-radar/49053-some-sleepers-dont-show
https://umod.org/community/admin-radar/49678-admin-radar-bugged
https://umod.org/community/admin-radar/49680-idea-scale-font-size-by-distance
https://umod.org/community/admin-radar/49900-player-stashes-not-showing-only-those-from-stashtraps
Fix for Rust update (REQUIRES RUST UPDATE TO COMPILE)
Added localization for Spain (es)
TrainCarUnloadable added to loot filter but I don't think it works yet
Added few null checks to drawing methods
Added a few null checks to backpacks
Added missing Group Limit -> Limit check
Changed tugboat from RB to TB in Boats filter
Added message for amount found to /radar buildings
Changed /radar drops to show item shortname if available
*/
namespace Oxide.Plugins {
[Info("Admin Radar", "nivex", "5.3.2")]
[Description("Radar tool for Admins and Developers.")]
internal class AdminRadar : RustPlugin {
[PluginReference]
Plugin Clans, Backpacks, DiscordMessages;
[Flags]
public enum DrawFlags {
None = 0, Arrow = 1 << 1, Box = 1 << 2, Text = 1 << 3,
}
public enum EntityType {
Active, Airdrop, Bag, Backpack, Boat, Bradley, Car, CargoPlane, CargoShip, CCTV, CH47, Box, Col, TC, TCArrow, Dead, Limit, Loot, Heli, Mini, MLRS, Npc, Ore, Horse, RHIB, Sleeper, Stash, Trap, Turret
}
private List<string> _tags = new List<string> {
"ore", "cluster", "1", "2", "3", "4", "5", "6", "_", ".", "-", "deployed", "wooden", "large", "pile", "prefab", "collectable", "loot", "small"
}
;
private List<EntityType> _errorTypes = new List<EntityType>();
private List<Radar> _radars = new List<Radar>();
private List<BaseEntity> _spawnedEntities = new List<BaseEntity>();
private Dictionary<NetworkableId, Vector3> _despawnedEntities = new Dictionary<NetworkableId, Vector3>();
private Dictionary<NetworkableId, BaseEntity> _allEntities = new Dictionary<NetworkableId, BaseEntity>();
private Dictionary<string, float> _cooldowns = new Dictionary<string, float>();
private Dictionary<ulong, string> _clans = new Dictionary<ulong, string>();
private Dictionary<ulong, string> _teamColors = new Dictionary<ulong, string>();
private Dictionary<string, string> _clanColors = new Dictionary<string, string>();
private Dictionary<ulong, Timer> _voices = new Dictionary<ulong, Timer>();
private Array _allEntityTypes = Enum.GetValues(typeof(EntityType));
private CoroutineTimer _coroutineTimer = new CoroutineTimer(1.0f);
private Stack<Coroutine> _coroutines = new Stack<Coroutine>();
private StoredData data = new StoredData();
private const bool True = true;
private const bool False = false;
private bool _isPopulatingCache;
private bool isUnloading;
private Cache cache;
private class StoredData {
public readonly Dictionary<ulong, UiOffsets> Offsets = new Dictionary<ulong, UiOffsets>();
public readonly List<string> Extended = new List<string>();
public readonly Dictionary<string, List<string>> Filters = new Dictionary<string, List<string>>();
public readonly List<string> Hidden = new List<string>();
public readonly List<string> OnlineBoxes = new List<string>();
public readonly List<string> Visions = new List<string>();
public readonly List<string> Active = new List<string>();
public StoredData() {
}
}
private class Cache {
public Cache(AdminRadar instance) {
config = instance.config;
this.instance = instance;
}
public Configuration config;
public AdminRadar instance;
internal EntityType entityType;
public Dictionary<NetworkableId, EntityInfo> Airdrops {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Animals {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Backpacks {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Bags {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Boats {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> BradleyAPCs {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> CargoPlanes {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> CargoShips {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Cars {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> CCTV {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> CH47 {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Cupboards {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Collectibles {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Containers {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Corpses {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Helicopters {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> MiniCopter {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> MLRS {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> NPCPlayers {
get;
set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Ores {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> RHIB {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> RidableHorse {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Turrets {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public Dictionary<NetworkableId, EntityInfo> Traps {
get;
private set;
}
= new Dictionary<NetworkableId, EntityInfo>();
public bool Add(BaseEntity entity) {
if (entity.IsKilled()) {
return False;
}
if (entity is BasePlayer) {
var player = entity as BasePlayer;
Interface.Oxide.NextTick(() => {
if (!player.IsValid() || player.IsDestroyed) {
return;
}
if (player.userID.IsSteamId()) {
instance._radars.ForEach(radar => radar.TryCacheOnlinePlayer(player));
}
else if (config.Core.NPCPlayer) {
EntityInfo ei;
NPCPlayers[entity.net.ID] = ei = new EntityInfo(player, EntityType.Npc, config.Distance.Get);
instance._radars.ForEach(radar => radar.TryCacheByType(EntityType.Npc, ei));
}
}
);
return False;
}
if (config.Core.Dead && entity is PlayerCorpse) {
PlayerCorpse corpse = entity as PlayerCorpse;
Interface.Oxide.NextTick(() => {
if (corpse.IsValid() && !corpse.IsDestroyed && corpse.playerSteamID.IsSteamId()) {
EntityInfo ei;
Corpses[entity.net.ID] = ei = new EntityInfo(entity, EntityType.Dead, config.Distance.Get);
ei.name = corpse.parentEnt?.ToString() ?? corpse.playerSteamID.ToString();
instance._radars.ForEach(radar => radar.TryCacheByType(EntityType.Dead, ei));
}
}
);
return False;
}
if (config.Additional.Traps && IsTrap(entity) && Add_Internal<BaseEntity, EntityInfo>(Traps, entity, EntityType.Trap)) {
return True;
}
if (config.Additional.RH && Add_Internal<RidableHorse, EntityInfo>(RidableHorse, entity, EntityType.Horse)) {
return True;
}
if (config.Core.Animals && Add_Internal<BaseNpc, EntityInfo>(Animals, entity, EntityType.Npc)) {
return True;
}
if (config.Core.Animals && Add_Internal<SimpleShark, EntityInfo>(Animals, entity, EntityType.Npc)) {
return True;
}
if (config.Core.Loot && entity is TrainCarUnloadable && Add_Internal<StorageContainer, EntityInfo>(Containers, (entity as TrainCarUnloadable).GetStorageContainer(), EntityType.Loot)) {
return True;
}
if ((config.Core.Loot || config.Core.Box) && entity is StorageContainer && TryGetContainerType(entity, out entityType) && Add_Internal<StorageContainer, EntityInfo>(Containers, entity, entityType)) {
return True;
}
if (config.Core.Col && entity is CollectibleEntity && Add_Internal<CollectibleEntity, EntityInfo>(Collectibles, entity, EntityType.Col)) {
return True;
}
if (config.Core.Ore && entity is OreResourceEntity && Add_Internal<OreResourceEntity, EntityInfo>(Ores, entity, EntityType.Ore)) {
return True;
}
if (config.Additional.Cars && Add_Internal<BasicCar, EntityInfo>(Cars, entity, EntityType.Car) || Add_Internal<ModularCar, EntityInfo>(Cars, entity, EntityType.Car)) {
return True;
}
if (config.Additional.CP && entity.prefabID == 2383782438 && Add_Internal<BaseEntity, EntityInfo>(CargoPlanes, entity, EntityType.CargoPlane)) {
return True;
}
if (config.Core.Bags && Add_Internal<SleepingBag, EntityInfo>(Bags, entity, EntityType.Bag)) {
return True;
}
if (config.Core.TC && Add_Internal<BuildingPrivlidge, EntityInfo>(Cupboards, entity, EntityType.TC)) {
return True;
}
if (config.Additional.CCTV && Add_Internal<CCTV_RC, EntityInfo>(CCTV, entity, EntityType.CCTV)) {
return True;
}
if (config.Core.Airdrop && Add_Internal<SupplyDrop, EntityInfo>(Airdrops, entity, EntityType.Airdrop)) {
return True;
}
if (config.Core.Loot && Add_Internal<DroppedItemContainer, EntityInfo>(Backpacks, entity, EntityType.Backpack)) {
return True;
}
if (config.Additional.Heli && Add_Internal<PatrolHelicopter, EntityInfo>(Helicopters, entity, EntityType.Heli)) {
return True;
}
if (config.Additional.Bradley && Add_Internal<BradleyAPC, EntityInfo>(BradleyAPCs, entity, EntityType.Bradley)) {
return True;
}
if (config.Additional.RHIB && Add_Internal<RHIB, EntityInfo>(RHIB, entity, EntityType.RHIB)) {
return True;
}
if (config.Additional.Boats && Add_Internal<BaseBoat, EntityInfo>(Boats, entity, EntityType.Boat)) {
return True;
}
if (config.Additional.MC && Add_Internal<Minicopter, EntityInfo>(MiniCopter, entity, EntityType.Mini)) {
return True;
}
if (config.Additional.CH47 && Add_Internal<CH47Helicopter, EntityInfo>(CH47, entity, EntityType.CH47)) {
return True;
}
if (config.Additional.CS && Add_Internal<CargoShip, EntityInfo>(CargoShips, entity, EntityType.CargoShip)) {
return True;
}
if (config.Core.Turrets && Add_Internal<AutoTurret, EntityInfo>(Turrets, entity, EntityType.Turret)) {
return True;
}
if (config.Additional.MLRS && Add_Internal<MLRSRocket, EntityInfo>(MLRS, entity, EntityType.MLRS)) {
return True;
}
return False;
}
private bool TryGetContainerType(BaseEntity entity, out EntityType type) {
if (entity is LockedByEntCrate || IsLoot(entity)) {
type = EntityType.Loot;
return True;
}
if (IsBox(entity)) {
type = EntityType.Box;
return True;
}
type = (EntityType)0;
return False;
}
public bool Remove(NetworkableId nid, Vector3 entityPos) {
instance._radars.ForEach(radar => radar.RemoveByNetworkId(nid));
if (Remove_Internal(Airdrops, nid)) return True;
if (Remove_Internal(Animals, nid)) return True;
if (Remove_Internal(Backpacks, nid)) return True;
if (Remove_Internal(Bags, nid)) return True;
if (Remove_Internal(Boats, nid)) return True;
if (Remove_Internal(BradleyAPCs, nid)) return True;
if (Remove_Internal(CargoPlanes, nid)) return True;
if (Remove_Internal(CargoShips, nid)) return True;
if (Remove_Internal(Cars, nid)) return True;
if (Remove_Internal(CCTV, nid)) return True;
if (Remove_Internal(CH47, nid)) return True;
if (Remove_Internal(Collectibles, nid)) return True;
if (Remove_Internal(Containers, nid)) return True;
if (Remove_Internal(Corpses, nid)) return True;
if (Remove_Internal(Cupboards, nid)) return True;
if (Remove_Internal(Helicopters, nid)) return True;
if (Remove_Internal(MiniCopter, nid)) return True;
if (Remove_Internal(MLRS, nid)) return True;
if (Remove_Internal(NPCPlayers, nid)) return True;
if (Remove_Internal(Ores, nid)) return True;
if (Remove_Internal(RHIB, nid)) return True;
if (Remove_Internal(RidableHorse, nid)) return True;
if (Remove_Internal(Traps, nid)) return True;
if (Remove_Internal(Turrets, nid)) return True;
return False;
}
private bool Add_Internal<TLookFor, TTargetType>(Dictionary<NetworkableId, EntityInfo> cachedList, BaseEntity entity, EntityType type) {
if (entity is TLookFor && entity.net != null && !cachedList.ContainsKey(entity.net.ID)) {
var ei = new EntityInfo(entity, type, config.Distance.Get, instance.StripTags);
cachedList.Add(entity.net.ID, ei);
instance._radars.ForEach(radar => radar.TryCacheByType(type, ei));
return True;
}
return False;
}
private bool Remove_Internal<TType, TKeyType>(Dictionary<TKeyType, TType> cachedList, TKeyType key) {
return cachedList.Remove(key);
}
#if DEBUG
public void Print() {
StringBuilder sb = StringBuilderCache.Acquire();
sb.AppendLine($"{nameof(Airdrops)}: {Airdrops.Count}");
sb.AppendLine($"{nameof(Animals)}: {Animals.Count}");
sb.AppendLine($"{nameof(Backpacks)}: {Backpacks.Count}");
sb.AppendLine($"{nameof(Bags)}: {Bags.Count}");
sb.AppendLine($"{nameof(Boats)}: {Boats.Count}");
sb.AppendLine($"{nameof(BradleyAPCs)}: {BradleyAPCs.Count}");
sb.AppendLine($"{nameof(CargoPlanes)}: {CargoPlanes.Count}");
sb.AppendLine($"{nameof(CargoShips)}: {CargoShips.Count}");
sb.AppendLine($"{nameof(Cars)}: {Cars.Count}");
sb.AppendLine($"{nameof(CCTV)}: {CCTV.Count}");
sb.AppendLine($"{nameof(CH47)}: {CH47.Count}");
sb.AppendLine($"{nameof(Collectibles)}: {Collectibles.Count}");
sb.AppendLine($"{nameof(Containers)}: {Containers.Count}");
sb.AppendLine($"{nameof(Corpses)}: {Corpses.Count}");
sb.AppendLine($"{nameof(Cupboards)}: {Cupboards.Count}");
sb.AppendLine($"{nameof(Helicopters)}: {Helicopters.Count}");
sb.AppendLine($"{nameof(MiniCopter)}: {MiniCopter.Count}");
sb.AppendLine($"{nameof(MLRS)}: {MLRS.Count}");
sb.AppendLine($"{nameof(NPCPlayers)}: {NPCPlayers.Count}");
sb.AppendLine($"{nameof(Ores)}: {Ores.Count}");
sb.AppendLine($"{nameof(RHIB)}: {RHIB.Count}");
sb.AppendLine($"{nameof(RidableHorse)}: {RidableHorse.Count}");
sb.AppendLine($"{nameof(Traps)}: {Traps.Count}");
sb.AppendLine($"{nameof(Turrets)}: {Turrets.Count}");
instance.Puts(StringBuilderCache.GetStringAndRelease(sb));
}
#endif
public bool IsTrap(BaseNetworkable entity) {
return entity is BaseTrap || config.Options.AdditionalTraps.Exists(entity.ShortPrefabName.Contains);
}
public bool IsLoot(BaseNetworkable entity) {
if (config.Core.Loot) {
return entity is TrainCarUnloadable || entity.ShortPrefabName == "campfire" || entity.ShortPrefabName.Contains("loot", CompareOptions.IgnoreCase) || entity.ShortPrefabName.Contains("crate_", CompareOptions.IgnoreCase) || entity.ShortPrefabName.Contains("trash", CompareOptions.IgnoreCase) || entity.ShortPrefabName.Contains("hackable", CompareOptions.IgnoreCase) || entity.ShortPrefabName.Contains("oil", CompareOptions.IgnoreCase);
}
return False;
}
public bool IsBox(BaseNetworkable entity) {
if (config.Core.Box) {
return entity.ShortPrefabName == "vendingmachine.deployed" || entity.ShortPrefabName == "woodbox_deployed" || entity.ShortPrefabName == "box.wooden.large" || entity.ShortPrefabName == "dropbox.deployed" || entity.ShortPrefabName == "coffinstorage" || entity.ShortPrefabName == "small_stash_deployed" || entity.ShortPrefabName == "mailbox.deployed" || entity.ShortPrefabName == "missionstash" || entity.ShortPrefabName.Equals("heli_crate", StringComparison.OrdinalIgnoreCase);
}
return False;
}
}
private class CoroutineTimer {
private readonly Stopwatch stopwatch = new Stopwatch();
private float _maxDurationMs;
private bool _isRunning;
//public bool ForceStop { get; set; }
public double Elapsed => stopwatch.Elapsed.TotalMilliseconds;
public CoroutineTimer(float maxDurationMs) {
_maxDurationMs = maxDurationMs;
}
public void Start() {
stopwatch.Start();
_isRunning = True;
}
public bool ShouldYield() {
_isRunning = stopwatch.Elapsed.TotalMilliseconds < _maxDurationMs;
if (!_isRunning) {
#if DEBUG
double milliseconds = Elapsed;
if (stopwatch.Elapsed.TotalMilliseconds > 2f * _maxDurationMs) {
Interface.Oxide.LogInfo($"[AdminRadar] Time slice took {Elapsed} when it should be around {_maxDurationMs}");
}
#endif
}
return !_isRunning;
}
public void ResetIfYielded() {
if (_isRunning) return;
stopwatch.Restart();
_isRunning = True;
}
}
internal static class StringBuilderCache {
[ThreadStatic]
private static StringBuilder builder;
public static StringBuilder Acquire(string text = "") {
StringBuilder cached = builder;
if (cached != null) {
builder = null;
cached.Clear();
cached.Append(text);
return cached;
}
return new StringBuilder(text);
}
public static void Clear() {
if (builder != null) {
builder.Clear();
builder = null;
}
}
public static string GetStringAndRelease(StringBuilder sb) {
string result = sb.ToString();
builder = sb;
return result;
}
}
public class EntityInfo {
public BuildingPrivlidge priv;
public BaseEntity entity;
public EntityType type;
public Color color;
public Vector3 _from;
public Vector3 to;
public Vector3 offset;
public string name;
public object info;
public float dist;
public float size = 0.5f;
public Network.Visibility.Group group => entity?.net?.group;
public Vector3 from => (IsInvalid ? _from : _from = entity.transform.position) + offset;
public bool IsInvalid {
get {
if (entity == null || entity.net == null || entity.IsDestroyed) {
return true;
}
_from = entity.transform.position;
return false;
}
}
public EntityInfo() {
}
public EntityInfo(BaseEntity entity, EntityType type, Func<EntityType, BaseEntity, float> getDistance, Func<string, string> stripTags = null) {
if (stripTags != null) {
name = stripTags(entity.ShortPrefabName);
}
if (getDistance != null) {
dist = getDistance(type, entity);
}
if (type == EntityType.TC) {
priv = entity as BuildingPrivlidge;
}
this.type = type;
this.entity = entity;
_from = entity.transform.position;
}
}
private class Radar : FacepunchBehaviour {
private static Func<char, bool> abbr = c => char.IsUpper(c) || char.IsDigit(c);
public class DataObject {
public EntityInfo ei;
public Action action;
public DrawFlags flags;
public bool disabled;
public DataObject() {
}
public bool HasFlag(DrawFlags flag) {
return ((flags & flag) == flag);
}
public void SetEnabled(Network.Visibility.Group group, Vector3 to, float max) {
disabled = ei.group != group && (ei.from - to).magnitude > Mathf.Max(max, ei.dist);
}
public bool IsOfType(EntityType type) {
if (type != EntityType.Loot) {
return ei.type == type;
}
return ei.type == EntityType.Loot || ei.type == EntityType.Backpack;
}
public void Reset() {
ei = null;
action = null;
disabled = false;
flags = DrawFlags.None;
}
}
internal class DistantPlayer {
public Vector3 pos;
public bool alive;
public DistantPlayer() {
}
}
internal bool setSource = True, canGetExistingBackpacks = True, isEnabled = True, canBypassOverride, hasPermAllowed, isAdmin, showHT, showAll;
internal int inactiveSeconds, activatedSeconds, checks;
internal float currDistance, invokeTime, maxDistance;
internal string username, userid;
internal RaycastHit hit;
internal EntityType currType;
internal Vector3 position;
internal BaseEntity source;
internal BasePlayer player;
internal AdminRadar instance;
internal Network.Visibility.Group group;
internal ItemContainer _backpackItemContainer;
internal Coroutine _radarCo, _updateCo, _groupCo;
internal List<ulong> exclude = Pool.Get<List<ulong>>();
internal List<NetworkableId> removeByNetworkId = Pool.Get<List<NetworkableId>>();
internal List<EntityType> entityTypes = Pool.Get<List<EntityType>>();
internal List<DistantPlayer> distant = Pool.Get<List<DistantPlayer>>();
internal List<EntityType> removeByEntityType = Pool.Get<List<EntityType>>();
internal Dictionary<NetworkableId, DataObject> data = Pool.Get<Dictionary<NetworkableId, DataObject>>();
internal Dictionary<EntityType, Action> filters = Pool.Get<Dictionary<EntityType, Action>>();
internal Dictionary<ulong, ItemContainer> backpacks = Pool.Get<Dictionary<ulong, ItemContainer>>();
internal Cache Cache => instance.cache;
internal Configuration config => instance.config;
internal float delay => invokeTime + 0.05f;
internal float Distance(Vector3 a) => Mathf.CeilToInt((a - position).magnitude);
public Vector3 limitUp;
public Vector3 halfUp = new Vector3(0f, 0.5f);
public Vector3 twoHalfUp = new Vector3(0f, 2.5f);
public Vector3 twoUp = new Vector3(0f, 2f);
public Vector3 fiveUp = new Vector3(0f, 5f);
private void Awake() {
source = player = GetComponent<BasePlayer>();
isAdmin = player.IsAdmin;
userid = player.UserIDString;
username = player.displayName;
position = player.transform.position;
exclude.Add(player.userID);
}
private void OnDestroy() {
isEnabled = false;
Interface.CallHook("OnRadarDeactivated", player, username, userid, position);
if (config.Settings.Cooldown > 0f) {
instance._cooldowns[userid] = Time.realtimeSinceStartup + config.Settings.Cooldown;
}
if (config.Settings.ShowToggle) {
instance.Message(player, "Deactivated");
}
if (instance._radars.Remove(this) && instance._radars.Count == 0 && !instance.isUnloading) {
instance.Unsubscribe(nameof(OnPlayerRespawned));
}
instance.DestroyUI(player);
ResetToPool();
StopAll();
}
private void ResetToPool() {
for (int i = distant.Count - 1; i >= 0; i--) {
var obj = distant[i];
if (obj != null) {
Pool.Free(ref obj);
}
distant[i] = null;
}
for (int i = data.Count - 1; i >= 0; i--) {
var obj = data.ElementAt(i);
if (obj.Value != null) {
var value = obj.Value;
Pool.Free(ref value);
}
data[obj.Key] = null;
}
data.ResetToPool();
exclude.ResetToPool();
distant.ResetToPool();
filters.ResetToPool();
backpacks.ResetToPool();
entityTypes.ResetToPool();
removeByNetworkId.ResetToPool();
removeByEntityType.ResetToPool();
}
public bool Add(EntityType type) {
if (entityTypes.Contains(type)) {
return False;
}
entityTypes.Add(type);
return True;
}
public void Init(AdminRadar instance) {
this.instance = instance;
this.limitUp = new Vector3(0f, config.Limit.Height);
this.instance._radars.Add(this);
canBypassOverride = HasPermission(userid, "adminradar.bypass.override");
hasPermAllowed = HasPermission(userid, "adminradar.allowed");
InvokeRepeating(Activity, 0f, 1f);
Interface.CallHook("OnRadarActivated", player, username, userid, position);
if (instance._radars.Count == 1) {
instance.Subscribe(nameof(OnPlayerRespawned));
}
}
public void StopAll() {
if (_radarCo != null) {
StopCoroutine(_radarCo);
_radarCo = null;
}
if (_updateCo != null) {
StopCoroutine(_updateCo);
_updateCo = null;
}
if (_groupCo != null) {
StopCoroutine(_groupCo);
_groupCo = null;
}
try {
CancelInvoke(Activity);
}
catch {
}
try {
RemoveAdminFlag();
}
catch {
}
}
public bool GetBool(EntityType type) {
return entityTypes.Contains(type);
}
private void Activity() {
inactiveSeconds = position == player.transform.position ? inactiveSeconds + 1 : 0;
position = source.transform.position;
if (source != player) {
inactiveSeconds = 0;
return;
}
if (config.Settings.DeactivateSeconds > 0 && ++activatedSeconds >= config.Settings.DeactivateSeconds) {
isEnabled = false;
Destroy(this);
}
if (config.Settings.InactiveSeconds > 0 && inactiveSeconds >= config.Settings.InactiveSeconds) {
isEnabled = false;
Destroy(this);
}
}
private void SetupFilter(EntityType type, Action action) {
if (entityTypes.Contains(type)) {
if (_radarCo != null) {
action();
}
filters[type] = action;
}
else if (filters.Remove(type)) {
RemoveByEntityType(type);
}
}
public void SetupFilters(bool barebones) {
if (_updateCo != null) {
StopCoroutine(_updateCo);
}
SetupFilter(EntityType.Active, ShowActive);
SetupFilter(EntityType.Sleeper, ShowSleepers);
if (!barebones) {
SetupFilters();
}
if (_radarCo == null) {
CheckNetworkGroupChange();
_radarCo = StartCoroutine(DoRadarRoutine());
}
if (_groupCo == null && config.Limit.Enabled) {
_groupCo = StartCoroutine(DoGroupLimitRoutine());
}
DoRemoves();
}
private void SetupFilters() {
SetupFilter(EntityType.TC, ShowTC);
SetupFilter(EntityType.Bag, ShowBags);
SetupFilter(EntityType.Box, ShowBox);
SetupFilter(EntityType.Ore, ShowOre);
SetupFilter(EntityType.Npc, ShowNPC);
SetupFilter(EntityType.CCTV, ShowCCTV);
SetupFilter(EntityType.Dead, ShowDead);
SetupFilter(EntityType.Heli, ShowHeli);
SetupFilter(EntityType.Loot, ShowLoot);
SetupFilter(EntityType.Stash, ShowStash);
SetupFilter(EntityType.Turret, ShowTurrets);
SetupFilter(EntityType.Bradley, ShowBradley);
SetupFilter(EntityType.Col, ShowCollectibles);
SetupFilter(EntityType.Airdrop, ShowSupplyDrops);
SetupFilter(EntityType.Car, () => ShowEntity(EntityType.Car, Cache.Cars));
SetupFilter(EntityType.CH47, () => ShowEntity(EntityType.CH47, Cache.CH47));
SetupFilter(EntityType.MLRS, () => ShowEntity(EntityType.MLRS, Cache.MLRS));
SetupFilter(EntityType.RHIB, () => ShowEntity(EntityType.RHIB, Cache.RHIB));
SetupFilter(EntityType.Boat, () => ShowEntity(EntityType.Boat, Cache.Boats));
SetupFilter(EntityType.Trap, () => ShowEntity(EntityType.Trap, Cache.Traps));
SetupFilter(EntityType.Mini, () => ShowEntity(EntityType.Mini, Cache.MiniCopter));
SetupFilter(EntityType.Horse, () => ShowEntity(EntityType.Horse, Cache.RidableHorse));
SetupFilter(EntityType.CargoShip, () => ShowEntity(EntityType.CargoShip, Cache.CargoShips));
SetupFilter(EntityType.CargoPlane, () => ShowEntity(EntityType.CargoPlane, Cache.CargoPlanes));
}
private IEnumerator DoGroupLimitRoutine() {
while (isEnabled) {
ShowGroupLimits();
yield return CoroutineEx.waitForSeconds(invokeTime);
}
}
private IEnumerator DoUpdateRoutine() {
SetEnabledDataObjects();
foreach (var filter in filters) {
filter.Value();
if (checks >= 100) {
checks = 0;
yield return CoroutineEx.waitForFixedUpdate;
}
}
}
private IEnumerator DoRadarRoutine() {
while (isEnabled) {
if (player == null || !player.IsConnected || instance.isUnloading) {
isEnabled = false;
Destroy(this);
yield break;
}
if (!SetSource()) {
yield return CoroutineEx.waitForSeconds(0.1f);
continue;
}
DoRemoves();
SetAdminFlag();
DirectDrawAll();
RemoveAdminFlag();
CheckNetworkGroupChange();
checks = 0;
yield return CoroutineEx.waitForSeconds(invokeTime);
}
}
private void DoRemoves() {
if (removeByEntityType.Count != 0) {
foreach (var type in removeByEntityType) {
RemoveByEntityType(type);
entityTypes.Remove(type);
filters.Remove(type);
}
removeByEntityType.Clear();
}
if (removeByNetworkId.Count != 0) {
foreach (var nid in removeByNetworkId) {
RemoveByNetworkId(nid);
}
removeByNetworkId.Clear();
}
}
private void CheckNetworkGroupChange() {
if (group == player.net.group) {
return;
}
group = player.net.group;
if (_updateCo != null) {
StopCoroutine(_updateCo);
}
_updateCo = StartCoroutine(DoUpdateRoutine());
}
public void SetEnabledDataObjects() {
foreach (var pair in data) {
pair.Value.SetEnabled(group, position, maxDistance);
}
}
public void RemoveByEntityType(EntityType type) {
foreach (var pair in data) {
if (pair.Value.IsOfType(type)) {
removeByNetworkId.Add(pair.Key);
pair.Value.disabled = true;
}
}
}
public void RemoveByNetworkId(NetworkableId nid) {
DataObject obj;
if (data.TryGetValue(nid, out obj)) {
if (obj != null) {
obj.Reset();
Pool.Free(ref obj);
}
data[nid] = null;
data.Remove(nid);
}
}
public void TryCacheByType(EntityType type, EntityInfo ei) {
try {
if (!entityTypes.Contains(type) || !ei.entity.IsValid() || ei.entity.net.group != group && Distance(ei._from) > ei.dist) {
return;
}
switch (type) {
case EntityType.Airdrop : {
CacheAirdrop(ei);
break;
}
case EntityType.Backpack : {
CacheBackpack(ei);
break;
}
case EntityType.Bag : {
CacheSleepingBag(ei);
break;
}
case EntityType.Box : {
CacheContainer(ei);
break;
}
case EntityType.Bradley : {
CacheBradley(ei);
break;
}
case EntityType.CCTV : {
CacheCCTV(ei);
break;
}
case EntityType.Col : {
CacheCol(ei);
break;
}
case EntityType.Dead : {
CacheDead(ei);
break;
}
case EntityType.Heli : {
CacheHeli(ei);
break;
}
case EntityType.Loot : {
CacheLoot(ei);
break;
}
case EntityType.Npc : {
CacheNpc(ei);
break;
}
case EntityType.Ore : {
CacheOre(ei);
break;
}
case EntityType.Stash : {
CacheStash(ei);
break;
}
case EntityType.TC : {
CacheTC(ei);
break;
}
case EntityType.Turret : {
CacheTurret(ei);
break;
}
default : {
CacheEntity(ei, type);
break;
}
}
}
catch (Exception ex) {
currType = type;
HandleException(ex);
}
}
private void DirectDrawAll() {
float delay = this.delay;
foreach (var obj in data.Values) {
if (obj.disabled) {
continue;
}
if (obj.HasFlag(DrawFlags.Arrow)) {
player.SendConsoleCommand("ddraw.arrow", delay, obj.ei.color, obj.ei.from, obj.ei.to, obj.ei.size);
}
if (obj.HasFlag(DrawFlags.Box)) {
player.SendConsoleCommand("ddraw.box", delay, obj.ei.color, obj.ei.from, obj.ei.size);
}
if (obj.HasFlag(DrawFlags.Text)) {
try {
obj.action();
}
catch (Exception ex) {
if (HandleException(obj, ex)) continue;
else break;
}
if (obj.ei.info == null) {
continue;
}
player.SendConsoleCommand("ddraw.text", delay, obj.ei.color, obj.ei.from, obj.ei.info);
}
}
}
private void DrawVisionArrow(BasePlayer target, float dist) {
if (dist <= 150f && instance.data.Visions.Contains(userid) && Physics.Raycast(target.eyes.HeadRay(), out hit, Mathf.Infinity)) {
DrawArrow(Color.red, target.eyes.position + new Vector3(0f, 0.115f, 0f), hit.point, 0.15f, True);
}
}
private void DrawVoiceArrow(BasePlayer target, Vector3 a, float dist) {
if (config.Voice.Enabled && dist <= config.Voice.Distance && instance._voices.ContainsKey(target.userID)) {
DrawArrow(Color.yellow, a + fiveUp, a + twoHalfUp, 0.5f, True);
}
}
private void DrawArrow(Color color, Vector3 from, Vector3 to, float size, bool @override = False) {
if (config.Methods.Arrow || @override) {
if (player == null || !player.IsConnected) {
return;
}
player.SendConsoleCommand("ddraw.arrow", delay, color, from, to, size);
}
}
private void DrawPlayerText(Color color, Vector3 position, object prefix, object text, bool @override = False) {
if (config.Methods.Text || @override) {
if (player == null || !player.IsConnected) {
return;
}
player.SendConsoleCommand("ddraw.text", delay, color, position, Format(prefix, text, false));
}
}
private void DrawBox(Color color, Vector3 position, float size, bool @override = False) {
if (config.Methods.Box || @override) {
if (player == null || !player.IsConnected) {
return;
}
player.SendConsoleCommand("ddraw.box", delay, color, position, size);
}
}
private void CacheArrow(DataObject obj, Color color, Vector3 offset, Vector3 to, float size, bool @override = False) {
if (config.Methods.Arrow || @override) {
obj.ei.color = color;
obj.ei._from = obj.ei.from;
obj.ei.offset = offset;
obj.ei.to = to;
obj.ei.size = size;
obj.flags |= DrawFlags.Arrow;
}
}
private void CacheBox(DataObject obj, Color color, Vector3 offset, float size, bool @override = False) {
if (config.Methods.Box || @override) {
obj.ei.color = color;
obj.ei._from = obj.ei.from;
obj.ei.offset = offset;
obj.ei.size = size;
// ... [Code preview truncated due to length. Full source in attached file] ...