C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System;
using System.Linq;
using System.Globalization;
using System.Collections.Generic;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using Oxide.Core.Plugins;
using System.Reflection;
namespace Oxide.Plugins {
[Info("AdminRadar", "nivex", "4.2.1", ResourceId = 978)]
[Description("ESP tool for Admins and Developers.")]
public class AdminRadar : RustPlugin {
readonly string permName = "adminradar.allowed";
static readonly string permBypass = "adminradar.bypass";
static AdminRadar ins;
DynamicConfigFile dataFile;
static StoredData storedData = new StoredData();
static bool init = false;
// make sure the server is initialized otherwise OnEntitySpawned can throw errors
static Dictionary<string, string> guiInfo = new Dictionary<string, string>();
static List<string> tags = new List<string>() {
"ore", "cluster", "1", "2", "3", "4", "5", "6", "_", ".", "-", "deployed", "wooden", "large", "pile", "prefab", "collectable", "loot", "small"
}
;
// strip these from names to reduce the size of the text and make it more readable
static Dictionary<ulong, int> drawnObjects = new Dictionary<ulong, int>();
Dictionary<ulong, Color> playersColor = new Dictionary<ulong, Color>();
private static readonly List<ESP> activeRadars = new List<ESP>();
// to reduce server strain we'll cache all entities once.this process is extremely fast and efficient.any newly created or destroyed entities will be removed from it's respective cache.// this excludes containers as content information needs to be current
static Dictionary<Vector3, CachedInfo> cachedBags = new Dictionary<Vector3, CachedInfo>();
static Dictionary<Vector3, CachedInfo> cachedCollectibles = new Dictionary<Vector3, CachedInfo>();
static Dictionary<Vector3, CachedInfo> cachedContainers = new Dictionary<Vector3, CachedInfo>();
static Dictionary<Vector3, CachedInfo> cachedBackpacks = new Dictionary<Vector3, CachedInfo>();
static Dictionary<PlayerCorpse, CachedInfo> cachedCorpses = new Dictionary<PlayerCorpse, CachedInfo>();
static Dictionary<Vector3, CachedInfo> cachedOres = new Dictionary<Vector3, CachedInfo>();
static Dictionary<Vector3, CachedInfo> cachedTC = new Dictionary<Vector3, CachedInfo>();
static Dictionary<Vector3, CachedInfo> cachedTurrets = new Dictionary<Vector3, CachedInfo>();
static List<BaseHelicopter> helisCache = new List<BaseHelicopter>();
static Dictionary<ulong, SortedDictionary<long, Vector3>> trackers = new Dictionary<ulong, SortedDictionary<long, Vector3>>();
// player id, timestamp and player's position
static Dictionary<ulong, Timer> trackerTimers = new Dictionary<ulong, Timer>();
static List<BasePlayer> npcCache = new List<BasePlayer>();
static List<BradleyAPC> bradleyCache = new List<BradleyAPC>();
static List<SupplyDrop> airdropCache = new List<SupplyDrop>();
static List<Zombie> zombieCache = new List<Zombie>();
const float flickerDelay = 0.05f;
bool IsRadar(string id) => activeRadars.Any(x => x.player.UserIDString == id);
static long TimeStamp() => (DateTime.Now.Ticks - DateTime.Parse("01/01/1970 00:00:00").Ticks) / 10000000;
class PlayerTracker : MonoBehaviour {
BasePlayer player;
ulong uid;
void Awake() {
player = GetComponent<BasePlayer>();
uid = player.userID;
InvokeRepeating("UpdateMovement", 0f, trackerUpdateInterval);
UpdateMovement();
}
void UpdateMovement() {
if (!player.IsConnected) {
GameObject.Destroy(this);
return;
}
if (!trackers.ContainsKey(uid)) trackers.Add(uid, new SortedDictionary<long, Vector3>());
var currentStamp = TimeStamp();
foreach (var stamp in trackers[uid].Keys.ToList()) // keep the dictionary from becoming enormous by removing entries which are too old
if (currentStamp - stamp > trackerAge) trackers[uid].Remove(stamp);
if (trackers[uid].Count > 1) {
var lastPos = trackers[uid].Values.ElementAt(trackers[uid].Count - 1);
// get the last position the player was at
if (Vector3.Distance(lastPos, transform.position) <= 1f) // check the distance against the minimum requirement.without this the dictionary will accumulate thousands of entries
return;
}
trackers[uid][currentStamp] = transform.position;
UpdateTimer();
}
void UpdateTimer() {
if (trackerTimers.ContainsKey(uid)) {
if (trackerTimers[uid] != null) {
trackerTimers[uid].Reset();
return;
}
trackerTimers.Remove(uid);
}
trackerTimers.Add(uid, ins.timer.Once(trackerAge, () => {
if (trackers.ContainsKey(uid)) trackers.Remove(uid);
if (trackerTimers.ContainsKey(uid)) trackerTimers.Remove(uid);
}
));
}
void OnDestroy() {
CancelInvoke("UpdateMovement");
UpdateTimer();
GameObject.Destroy(this);
}
}
#region json
// TODO: Remove hardcoded json
static string uiJson = @"[{
""name"": ""{guid}"",
""parent"": ""Hud"",
""components"": [
{
""type"": ""UnityEngine.UI.Image"",
""color"": ""1 1 1 0""
},
{
""type"": ""RectTransform"",
""anchormin"": ""{anchorMin}"",
""anchormax"": ""{anchorMax}""
}
]
},
{
""name"": ""btnAll"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui all"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5"",
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.017 0.739"",
""anchormax"": ""0.331 0.957""
}
]
},
{
""name"": ""lblAll"",
""parent"": ""btnAll"",
""components"": [
{
""text"": ""All"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorAll}"",
""fontSize"": 10,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
},
{
""name"": ""btnBags"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui bags"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.017 0.5"",
""anchormax"": ""0.331 0.717""
}
]
},
{
""name"": ""lblBags"",
""parent"": ""btnBags"",
""components"": [
{
""text"": ""Bags"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorBags}"",
""fontSize"": 10,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
},
{
""name"": ""btnBox"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui box"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.017 0.261"",
""anchormax"": ""0.331 0.478""
}
]
},
{
""name"": ""lblBox"",
""parent"": ""btnBox"",
""components"": [
{
""text"": ""Boxes"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorBox}"",
""fontSize"": 10,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
},
{
""name"": ""btnCollectables"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui col"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.017 0.022"",
""anchormax"": ""0.331 0.239""
}
]
},
{
""name"": ""lblCollectables"",
""parent"": ""btnCollectables"",
""components"": [
{
""text"": ""Collectibles"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorCol}"",
""fontSize"": 10,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
},
{
""name"": ""btnDead"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui dead"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.343 0.739"",
""anchormax"": ""0.657 0.957""
}
]
},
{
""name"": ""lblDead"",
""parent"": ""btnDead"",
""components"": [
{
""text"": ""Dead"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorDead}"",
""fontSize"": 9,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
},
{
""name"": ""btnLoot"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui loot"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.343 0.5"",
""anchormax"": ""0.657 0.717""
}
]
},
{
""name"": ""lblLoot"",
""parent"": ""btnLoot"",
""components"": [
{
""text"": ""Loot"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorLoot}"",
""fontSize"": 10,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
},
{
""name"": ""btnNPC"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui npc"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.343 0.261"",
""anchormax"": ""0.657 0.478""
}
]
},
{
""name"": ""lblNPC"",
""parent"": ""btnNPC"",
""components"": [
{
""text"": ""NPC"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorNPC}"",
""fontSize"": 10,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
},
{
""name"": ""btnOre"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui ore"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.343 0.022"",
""anchormax"": ""0.657 0.239""
}
]
},
{
""name"": ""lblOre"",
""parent"": ""btnOre"",
""components"": [
{
""text"": ""Ore"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorOre}"",
""fontSize"": 10,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
},
{
""name"": ""btnSleepers"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui sleepers"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.669 0.739"",
""anchormax"": ""0.984 0.957""
}
]
},
{
""name"": ""lblSleepers"",
""parent"": ""btnSleepers"",
""components"": [
{
""text"": ""Sleepers"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorSleepers}"",
""fontSize"": 10,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
},
{
""name"": ""btnStash"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui stash"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.669 0.5"",
""anchormax"": ""0.984 0.717""
}
]
},
{
""name"": ""lblStash"",
""parent"": ""btnStash"",
""components"": [
{
""text"": ""Stash"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorStash}"",
""fontSize"": 10,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
},
{
""name"": ""btnTC"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui tc"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.669 0.261"",
""anchormax"": ""0.984 0.478""
}
]
},
{
""name"": ""lblTC"",
""parent"": ""btnTC"",
""components"": [
{
""text"": ""TC"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorTC}"",
""fontSize"": 10,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
},
{
""name"": ""btnTurrets"",
""parent"": ""{guid}"",
""components"": [
{
""type"": ""UnityEngine.UI.Button"",
""command"": ""espgui turrets"",
""close"": """",
""color"": ""0.29 0.49 0.69 0.5""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0.669 0.022"",
""anchormax"": ""0.984 0.239""
}
]
},
{
""name"": ""lblTurrets"",
""parent"": ""btnTurrets"",
""components"": [
{
""text"": ""Turrets"",
""type"": ""UnityEngine.UI.Text"",
""color"": ""{colorTurrets}"",
""fontSize"": 10,
""align"": ""MiddleCenter""
},
{
""type"": ""RectTransform"",
""anchormin"": ""0 0"",
""anchormax"": ""1 1""
}
]
}
]";
#endregion
void Init() {
ins = this;
}
void Loaded() {
permission.RegisterPermission(permName, this);
permission.RegisterPermission(permBypass, this);
}
void OnServerInitialized() {
dataFile = Interface.Oxide.DataFileSystem.GetFile(Title);
try {
storedData = dataFile.ReadObject<StoredData>();
}
catch {
}
if (storedData == null) storedData = new StoredData();
LoadVariables();
if (!usePlayerTracker) Unsubscribe(nameof(OnPlayerSleepEnded));
else foreach (var target in BasePlayer.activePlayerList) Track(target);
if (!drawBox && !drawText && !drawArrows) {
Puts("Configuration does not have a chosen drawing method.Setting drawing method to text.");
Config.Set("Drawing Methods", "Draw Text", true);
Config.Save();
drawText = true;
}
var tick = DateTime.Now;
init = true;
int cached = 0, total = 0;
foreach (var e in BaseNetworkable.serverEntities) {
if (AddToCache(e)) cached++;
total++;
}
//Puts("Took {0}ms to cache {1}/{2} entities: {3} bags, {4} collectibles, {5} containers, {6} corpses, {7} ores, {8} tool cupboards, {9} turrets.", (DateTime.Now - tick).TotalMilliseconds, cached, total, cachedBags.Count, cachedCollectibles.Count, cachedContainers.Count, cachedCorpses.Count, cachedOres.Count, cachedTC.Count, cachedTurrets.Count);
Puts("Took {0}ms to cache {1}/{2} entities", (DateTime.Now - tick).TotalMilliseconds, cached, total);
SaveConfig();
}
void OnPlayerSleepEnded(BasePlayer player) {
if (!trackAdmins && player.IsAdmin) return;
Track(player);
}
void Unload() {
var espobjects = UnityEngine.Object.FindObjectsOfType(typeof(ESP));
if (espobjects != null) foreach (var gameObj in espobjects) UnityEngine.Object.Destroy(gameObj);
var ptobjects = UnityEngine.Object.FindObjectsOfType(typeof(PlayerTracker));
if (ptobjects != null) foreach (var gameObj in ptobjects) UnityEngine.Object.Destroy(gameObj);
if (dataFile != null) dataFile.WriteObject(storedData);
foreach(var entry in trackerTimers.ToList()) if (entry.Value != null && !entry.Value.Destroyed) entry.Value.Destroy();
playersColor.Clear();
trackerTimers.Clear();
trackers.Clear();
drawnObjects?.Clear();
cachedOres?.Clear();
cachedCorpses?.Clear();
cachedContainers?.Clear();
cachedBackpacks?.Clear();
cachedBags?.Clear();
cachedTC?.Clear();
cachedTurrets?.Clear();
cachedCollectibles?.Clear();
helisCache?.Clear();
bradleyCache?.Clear();
tags?.Clear();
}
void OnEntityDeath(BaseCombatEntity entity, HitInfo info) => RemoveFromCache(entity);
void OnEntityKill(BaseNetworkable entity) => RemoveFromCache(entity);
void OnEntitySpawned(BaseNetworkable entity) => AddToCache(entity.GetComponent<BaseEntity>());
class StoredData {
public List<string> Visions = new List<string>();
public List<string> OnlineBoxes = new List<string>();
public Dictionary<string, List<string>> Filters = new Dictionary<string, List<string>>();
public List<string> Hidden = new List<string>();
public List<string> Extended = new List<string>();
public StoredData() {
}
}
class CachedInfo {
public string Name;
public object Info;
public double Size;
public CachedInfo() {
}
}
class ESP : MonoBehaviour {
public BasePlayer player;
BaseEntity source;
public float maxDistance;
public float invokeTime;
private float inactiveTime;
private int inactiveMins;
private Vector3 position;
public bool showAll;
public bool showBags;
public bool showBox;
public bool showCollectible;
public bool showDead;
public bool showLoot;
public bool showNPC;
public bool showOre;
public bool showSleepers;
public bool showStash;
public bool showTC;
public bool showTurrets;
private List<BasePlayer> activePlayers = new List<BasePlayer>();
void Awake() {
player = GetComponent<BasePlayer>();
source = player;
position = player.transform.position;
if (inactiveTimeLimit > 0f || deactiveTimeLimit > 0) InvokeHandler.InvokeRepeating(this, Activity, 0f, 1f);
}
void OnDestroy() {
string gui;
if (guiInfo.TryGetValue(player.UserIDString, out gui)) {
CuiHelper.DestroyUi(player, gui);
guiInfo.Remove(player.UserIDString);
}
if (inactiveTimeLimit > 0f || deactiveTimeLimit > 0) InvokeHandler.CancelInvoke(this, Activity);
activeRadars.Remove(this);
player.ChatMessage(ins.msg("Deactivated", player.UserIDString));
GameObject.Destroy(this);
}
bool LatencyAccepted(DateTime tick) {
if (latencyMs > 0) {
var ms = (DateTime.Now - tick).TotalMilliseconds;
if (ms > latencyMs) {
player.ChatMessage(ins.msg("DoESP", player.UserIDString, ms, latencyMs));
return false;
}
}
return true;
}
void Activity() {
if (source != player) return;
inactiveTime = position == player.transform.position ? inactiveTime + 1f : 0f;
position = player.transform.position;
if (inactiveTimeLimit > 0f && inactiveTime > inactiveTimeLimit) GameObject.Destroy(this);
if (deactiveTimeLimit > 0) {
if (inactiveTime > 0f && inactiveTime % 60 == 0) inactiveMins++;
else inactiveMins = 0;
if (inactiveMins >= deactiveTimeLimit) GameObject.Destroy(this);
}
}
void DoESP() {
var tick = DateTime.Now;
string error = "TRY";
try {
error = "PLAYER";
if (!player.IsConnected) {
GameObject.Destroy(this);
return;
}
error = "SOURCE";
source = player.IsSpectating() ? player.GetParentEntity() : player;
if (!(source is BasePlayer)) // compatibility for HideAndSeek plugin otherwise exceptions will be thrown
source = player;
if (player == source && (player.IsDead() || player.IsSleeping() || player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot))) return;
drawnObjects[player.userID] = 0;
error = "HELI";
if (trackHelis && helisCache.Count > 0) {
foreach (var heli in helisCache) {
if (heli == null || heli.transform == null) continue;
double currDistance = Math.Floor(Vector3.Distance(heli.transform.position, source.transform.position));
string heliHealth = heli.health > 1000 ? Math.Floor(heli.health).ToString("#,##0,K", CultureInfo.InvariantCulture) : Math.Floor(heli.health).ToString();
string info = showHeliRotorHealth ? string.Format("<color={0}>{1}</color> (<color=yellow>{2}</color>/<color=yellow>{3}</color>)", healthCC, heliHealth, Math.Floor(heli.weakspots[0].health), Math.Floor(heli.weakspots[1].health)) : string.Format("<color={0}>{1}</color>", healthCC, heliHealth);
if (drawText) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, null, heli.transform.position + new Vector3(0f, 2f, 0f), string.Format("<color={0}>H</color> {1} <color={2}>{3}</color>", heliCC, info, distCC, currDistance));
if (drawBox) player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, Color.magenta, heli.transform.position + new Vector3(0f, 1f, 0f), GetScale(currDistance));
}
}
if (!LatencyAccepted(tick)) // causing server lag, return.this shouldn't happen unless the server is already experiencing latency issues
return;
error = "BRADLEY";
if (trackHelis && bradleyCache.Count > 0) {
foreach (var bradley in bradleyCache) {
if (bradley == null || bradley.transform == null) continue;
double currDistance = Math.Floor(Vector3.Distance(bradley.transform.position, source.transform.position));
string info = string.Format("<color={0}>{1}</color>", healthCC, bradley.health > 1000 ? Math.Floor(bradley.health).ToString("#,##0,K", CultureInfo.InvariantCulture) : Math.Floor(bradley.health).ToString());
if (drawText) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, null, bradley.transform.position + new Vector3(0f, 2f, 0f), string.Format("<color={0}>B</color> {1} <color={2}>{3}</color>", bradleyCC, info, distCC, currDistance));
if (drawBox) player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, Color.magenta, bradley.transform.position + new Vector3(0f, 1f, 0f), GetScale(currDistance));
}
}
error = "ACTIVE";
foreach (var target in BasePlayer.activePlayerList.Where(target => target != null && target.transform != null && target.IsConnected)) {
double currDistance = Math.Floor(Vector3.Distance(target.transform.position, source.transform.position));
if (player == target || currDistance > maxDistance || (useBypass && ins.permission.UserHasPermission(target.UserIDString, permBypass))) continue;
if (currDistance < playerDistance) {
string extText = string.Empty;
if (storedData.Extended.Contains(player.UserIDString)) {
extText = target.GetActiveItem()?.info.displayName.translated ?? string.Empty;
if (!string.IsNullOrEmpty(extText)) {
var itemList = target?.GetHeldEntity()?.GetComponent<BaseProjectile>()?.GetItem()?.contents?.itemList;
if (itemList?.Count > 0) {
string contents = string.Join("|", itemList.Select(item => item.info.displayName.translated.Replace("Weapon ", "").Replace("Simple Handmade ", "").Replace("Muzzle ", "").Replace("4x Zoom Scope", "4x")).ToArray());
if (!string.IsNullOrEmpty(contents)) extText = string.Format("{0} ({1})", extText, contents);
}
}
}
if (storedData.Visions.Contains(player.UserIDString)) DrawVision(player, target, invokeTime);
if (drawArrows) player.SendConsoleCommand("ddraw.arrow", invokeTime + flickerDelay, Color.red, target.transform.position + new Vector3(0f, target.transform.position.y + 10), target.transform.position, 1);
if (drawText) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, null, target.transform.position + new Vector3(0f, 2f, 0f), string.Format("<color={0}>{1}</color> <color={2}>{3}</color> <color={4}>{5}</color> {6}", target.IsAlive() ? activeCC : activeDeadCC, target.displayName ?? target.userID.ToString(), healthCC, Math.Floor(target.health), distCC, currDistance, extText));
if (drawBox) player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, Color.red, target.transform.position + new Vector3(0f, 1f, 0f), target.GetHeight(target.modelState.ducked));
}
else if (drawX) activePlayers.Add(target);
else player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, Color.red, target.transform.position + new Vector3(0f, 1f, 0f), 5f);
if (objectsLimit > 0 && ++drawnObjects[player.userID] > objectsLimit) return;
}
error = "GROUP LIMIT HIGHLIGHTING";
if (activePlayers.Count > 0) {
var dict = new Dictionary<int, List<BasePlayer>>();
foreach(var target in activePlayers.ToList()) {
var list = activePlayers.Where(x => x.Distance(target) < groupRange && !dict.Any(y => y.Value.Contains(x))).ToList();
if (list.Count >= groupLimit) {
int index = 0;
while (dict.ContainsKey(index)) index++;
dict.Add(index, list);
activePlayers.RemoveAll(x => list.Contains(x));
}
}
foreach (var target in activePlayers) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, target.IsAlive() ? Color.green : Color.red, target.transform.position + new Vector3(0f, 1f, 0f), "X");
foreach (var entry in dict) {
foreach (var target in entry.Value) {
player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, target.IsAlive() ? Color.yellow : Color.red, target.transform.position + new Vector3(0f, 1f, 0f), "X");
}
if (groupCountHeight > 0f) {
player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, Color.magenta, entry.Value.First().transform.position + new Vector3(0f, groupCountHeight, 0f), entry.Value.Count.ToString());
}
}
activePlayers.Clear();
dict.Clear();
}
if (!LatencyAccepted(tick)) return;
error = "TC";
if (showTC || showAll) {
foreach (var tc in cachedTC) {
double currDistance = Math.Floor(Vector3.Distance(tc.Key, source.transform.position));
if (currDistance < tcDistance && currDistance < maxDistance) {
if (drawText) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, null, tc.Key + new Vector3(0f, 0.5f, 0f), string.Format("<color={0}>TC</color> <color={1}>{2}</color>", tcCC, distCC, currDistance));
if (drawBox) player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, Color.black, tc.Key + new Vector3(0f, 0.5f, 0f), tc.Value.Size);
if (objectsLimit > 0 && ++drawnObjects[player.userID] > objectsLimit) return;
}
}
}
if (!LatencyAccepted(tick)) return;
if (showBox || showLoot || showStash || showAll) {
if (showLoot || showAll) {
error = "BACKPACKS";
foreach (var entry in cachedBackpacks) {
double currDistance = Math.Floor(Vector3.Distance(entry.Key, source.transform.position));
if (currDistance > maxDistance) continue;
if (currDistance < lootDistance) {
string contents = string.Empty;
uint uid;
if (entry.Value.Info != null && uint.TryParse(entry.Value.Info.ToString(), out uid)) {
var backpack = BaseNetworkable.serverEntities.Find(uid) as DroppedItemContainer;
if (backpack == null) continue;
if (backpack.inventory?.itemList != null) contents = string.Format("({0}) ", backpackContentAmount > 0 && backpack.inventory.itemList.Count > 0 ? string.Join(", ", backpack.inventory.itemList.Take(backpackContentAmount).Select(item => string.Format("{0} ({1})", item.info.displayName.translated.ToLower(), item.amount)).ToArray()) : backpack.inventory.itemList.Count().ToString());
if (drawText) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, null, entry.Key + new Vector3(0f, 0.5f, 0f), string.Format("<color={0}>{1}</color> <color={0}>{2}</color><color={3}>{4}</color>", backpackCC, string.IsNullOrEmpty(backpack._playerName) ? ins.msg("backpack", player.UserIDString) : backpack._playerName, contents, distCC, currDistance));
if (drawBox) player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, Color.red, entry.Key + new Vector3(0f, 0.5f, 0f), GetScale(currDistance));
if (objectsLimit > 0 && ++drawnObjects[player.userID] > objectsLimit) return;
}
}
}
}
if (showBox || showAll) {
error = "AIRDROPS";
foreach (var drop in airdropCache) {
double currDistance = Math.Floor(Vector3.Distance(drop.transform.position, source.transform.position));
if (currDistance > maxDistance || currDistance > adDistance) continue;
string contents = showAirdropContents && drop.inventory.itemList.Count > 0 ? string.Format("({0}) ", string.Join(", ", drop.inventory.itemList.Select(item => string.Format("{0} ({1})", item.info.displayName.translated.ToLower(), item.amount)).ToArray())) : string.Format("({0}) ", drop.inventory.itemList.Count());
if (drawText) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, Color.magenta, drop.transform.position + new Vector3(0f, 0.5f, 0f), string.Format("{0} {1}<color={2}>{3}</color>", _(drop.ShortPrefabName), contents, distCC, currDistance));
if (drawBox) player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, Color.magenta, drop.transform.position + new Vector3(0f, 0.5f, 0f), GetScale(currDistance));
}
}
error = "CONTAINERS";
foreach (var box in cachedContainers) {
double currDistance = Math.Floor(Vector3.Distance(box.Key, source.transform.position));
if (currDistance > maxDistance) continue;
bool isBox = (box.Value.Name.Contains("box") || box.Value.Name.Equals("heli_crate"));
bool isLoot = box.Value.Name.Contains("loot") || box.Value.Name.Contains("crate_") || box.Value.Name.Contains("trash");
if (isBox) {
if (!showBox && !showAll) continue;
if (currDistance > boxDistance) continue;
}
if (isLoot) {
if (!showLoot && !showAll) continue;
if (currDistance > lootDistance) continue;
}
if (box.Value.Name.Contains("stash")) {
if (!showStash && !showAll) continue;
if (currDistance > stashDistance) continue;
}
var color = isBox ? Color.magenta : isLoot ? Color.yellow : Color.white;
string colorHex = color == Color.magenta ? boxCC : color == Color.yellow ? lootCC : stashCC;
string contents = string.Empty;
uint uid;
if (box.Value.Info != null && uint.TryParse(box.Value.Info.ToString(), out uid)) {
var container = BaseNetworkable.serverEntities.Find(uid) as StorageContainer;
if (container == null) continue;
if (storedData.OnlineBoxes.Contains(player.UserIDString) && container.name.Contains("box")) {
var owner = BasePlayer.activePlayerList.Find(x => x.userID == container.OwnerID);
if (owner == null || !owner.IsConnected) {
continue;
}
}
if (container?.inventory?.itemList != null) {
if (container.inventory.itemList.Count > 0) {
if ((isLoot && showLootContents) || (container.ShortPrefabName.Contains("stash") && showStashContents)) contents = string.Format("({0}) ", string.Join(", ", container.inventory.itemList.Select(item => string.Format("{0} ({1})", item.info.displayName.translated.ToLower(), item.amount)).ToArray()));
else contents = string.Format("({0}) ", container.inventory.itemList.Count());
}
}
}
if (string.IsNullOrEmpty(contents) && !drawEmptyContainers) continue;
if (drawText) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, color, box.Key + new Vector3(0f, 0.5f, 0f), string.Format("<color={0}>{1}</color> {2}<color={3}>{4}</color>", colorHex, _(box.Value.Name), contents, distCC, currDistance));
if (drawBox) player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, color, box.Key + new Vector3(0f, 0.5f, 0f), GetScale(currDistance));
if (objectsLimit > 0 && ++drawnObjects[player.userID] > objectsLimit) return;
}
}
if (!LatencyAccepted(tick)) return;
error = "BAGS";
if (showBags || showAll) {
foreach (var bag in cachedBags) {
var currDistance = Math.Floor(Vector3.Distance(bag.Key, source.transform.position));
if (currDistance < bagDistance && currDistance < maxDistance) {
if (drawText) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, null, bag.Key, string.Format("<color={0}>bag</color> <color={1}>{2}</color>", bagCC, distCC, currDistance));
if (drawBox) player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, Color.magenta, bag.Key, bag.Value.Size);
if (objectsLimit > 0 && ++drawnObjects[player.userID] > objectsLimit) return;
}
}
}
if (!LatencyAccepted(tick)) return;
error = "TURRETS";
if (showTurrets || showAll) {
foreach (var turret in cachedTurrets) {
var currDistance = Math.Floor(Vector3.Distance(turret.Key, source.transform.position));
if (currDistance < turretDistance && currDistance < maxDistance) {
if (drawText) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, null, turret.Key + new Vector3(0f, 0.5f, 0f), string.Format("<color={0}>AT</color> ({1}) <color={2}>{3}</color>", atCC, turret.Value.Info, distCC, currDistance));
if (drawBox) player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, Color.yellow, turret.Key + new Vector3(0f, 0.5f, 0f), turret.Value.Size);
if (objectsLimit > 0 && ++drawnObjects[player.userID] > objectsLimit) return;
}
}
}
if (!LatencyAccepted(tick)) return;
error = "SLEEPERS";
if (showSleepers || showAll) {
foreach (var sleeper in BasePlayer.sleepingPlayerList) {
if (sleeper == null || sleeper.transform == null) continue;
double currDistance = Math.Floor(Vector3.Distance(sleeper.transform.position, source.transform.position));
if (currDistance > maxDistance) continue;
if (currDistance < playerDistance) {
if (drawArrows) player.SendConsoleCommand("ddraw.arrow", invokeTime + flickerDelay, Color.cyan, sleeper.transform.position + new Vector3(0f, sleeper.transform.position.y + 10), sleeper.transform.position, 1);
if (drawText) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, null, sleeper.transform.position, string.Format("<color={0}>{1}</color> <color={2}>{3}</color> <color={4}>{5}</color>", sleeper.IsAlive() ? sleeperCC : sleeperDeadCC, sleeper.displayName, healthCC, Math.Floor(sleeper.health), distCC, currDistance));
if (drawX) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, sleeper.IsAlive() ? Color.cyan : Color.red, sleeper.transform.position + new Vector3(0f, 1f, 0f), "X");
else if (drawBox) player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, sleeper.IsAlive() ? Color.cyan : Color.red, sleeper.transform.position, GetScale(currDistance));
}
else player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, Color.cyan, sleeper.transform.position + new Vector3(0f, 1f, 0f), 5f);
if (objectsLimit > 0 && ++drawnObjects[player.userID] > objectsLimit) return;
}
}
if (!LatencyAccepted(tick)) return;
error = "DEAD";
if (showDead || showAll) {
foreach (var corpse in cachedCorpses) {
if (corpse.Key == null) continue;
double currDistance = Math.Floor(Vector3.Distance(source.transform.position, corpse.Key.transform.position));
if (currDistance < corpseDistance && currDistance < maxDistance) {
if (drawText) player.SendConsoleCommand("ddraw.text", invokeTime + flickerDelay, Color.yellow, corpse.Key.transform.position + new Vector3(0f, 0.25f, 0f), string.Format("{0} ({1})", corpse.Value.Name, corpse.Value.Info));
if (drawBox) player.SendConsoleCommand("ddraw.box", invokeTime + flickerDelay, Color.yellow, corpse.Key, GetScale(currDistance));
if (objectsLimit > 0 && ++drawnObjects[player.userID] > objectsLimit) return;
}
}
}
if (!LatencyAccepted(tick)) return;
if (showNPC || showAll) {
error = "ZOMBIECACHE";
// ... [Code preview truncated due to length. Full source in attached file] ...