C#:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Facepunch;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust;
using Oxide.Game.Rust.Cui;
using Rust;
using UnityEngine;
using VLB;
using Random = UnityEngine.Random;
namespace Oxide.Plugins {
[Info("Remover Tool", "Reneb/Fuji/Arainrr/Tryhard", "4.3.48", ResourceId = 651)]
[Description("Building and entity removal tool")]
public class RemoverTool : RustPlugin {
#region Fields
[PluginReference]
private readonly Plugin Friends, ServerRewards, Clans, Economics, ImageLibrary, BuildingOwners, RustTranslationAPI, NoEscape;
private const string ECONOMICS_KEY = "economics";
private const string SERVER_REWARDS_KEY = "serverrewards";
private const string PERMISSION_ALL = "removertool.all";
private const string PERMISSION_ADMIN = "removertool.admin";
private const string PERMISSION_NORMAL = "removertool.normal";
private const string PERMISSION_TARGET = "removertool.target";
private const string PERMISSION_EXTERNAL = "removertool.external";
private const string PERMISSION_OVERRIDE = "removertool.override";
private const string PERMISSION_STRUCTURE = "removertool.structure";
private const string PREFAB_ITEM_DROP = "assets/prefabs/misc/item drop/item_drop.prefab";
private const int LAYER_ALL = 1 << 0 | 1 << 8 | 1 << 21;
private const int LAYER_TARGET = ~(1 << 2 | 1 << 3 | 1 << 4 | 1 << 10 | 1 << 18 | 1 << 28 | 1 << 29);
private static RemoverTool _instance;
private static BUTTON _removeButton;
private static RemoveMode _removeMode;
private readonly object _false = false;
private bool _configChanged;
private bool _removeOverride;
private Coroutine _removeAllCoroutine;
private Coroutine _removeStructureCoroutine;
private Coroutine _removeExternalCoroutine;
private Coroutine _removePlayerEntityCoroutine;
private StringBuilder _debugStringBuilder;
private Hash<ulong, float> _entitySpawnedTimes;
private readonly Hash<ulong, float> _cooldownTimes = new Hash<ulong, float>();
private enum RemoveMode {
None, NoHeld, MeleeHit, SpecificTool
}
private enum RemoveType {
None, All, Admin, Normal, External, Structure
}
private enum PlayerEntityRemoveType {
All, Cupboard, Building
}
#endregion Fields
#region Oxide Hooks
private void Init() {
_instance = this;
permission.RegisterPermission(PERMISSION_ALL, this);
permission.RegisterPermission(PERMISSION_ADMIN, this);
permission.RegisterPermission(PERMISSION_NORMAL, this);
permission.RegisterPermission(PERMISSION_TARGET, this);
permission.RegisterPermission(PERMISSION_OVERRIDE, this);
permission.RegisterPermission(PERMISSION_EXTERNAL, this);
permission.RegisterPermission(PERMISSION_STRUCTURE, this);
Unsubscribe(nameof(OnHammerHit));
Unsubscribe(nameof(OnEntitySpawned));
Unsubscribe(nameof(OnEntityKill));
Unsubscribe(nameof(OnPlayerAttack));
Unsubscribe(nameof(OnActiveItemChanged));
Unsubscribe(nameof(OnRaidBlock));
Unsubscribe(nameof(OnCombatBlock));
foreach (var perm in _configData.permission.Keys) {
if (!permission.PermissionExists(perm, this)) {
permission.RegisterPermission(perm, this);
}
}
cmd.AddChatCommand(_configData.chat.command, this, nameof(CmdRemove));
}
private void OnServerInitialized() {
Initialize();
UpdateConfig();
LoadConfig();
_removeMode = RemoveMode.None;
if (_configData.removerMode.noHeldMode) {
_removeMode = RemoveMode.NoHeld;
}
if (_configData.removerMode.meleeHitMode) {
_removeMode = RemoveMode.MeleeHit;
}
if (_configData.removerMode.specificToolMode) {
_removeMode = RemoveMode.SpecificTool;
}
if (_removeMode == RemoveMode.MeleeHit) {
BaseMelee baseMelee;
ItemDefinition itemDefinition;
if (string.IsNullOrEmpty(_configData.removerMode.meleeHitItemShortname) || (itemDefinition = ItemManager.FindItemDefinition(_configData.removerMode.meleeHitItemShortname)) == null || (baseMelee = itemDefinition.GetComponent<ItemModEntity>()?.entityPrefab.Get()?.GetComponent<BaseMelee>()) == null) {
PrintError($"{_configData.removerMode.meleeHitItemShortname} is not an item shortname for a melee tool");
_removeMode = RemoveMode.None;
}
else {
Subscribe(baseMelee is Hammer ? nameof(OnHammerHit) : nameof(OnPlayerAttack));
}
}
if (_configData.noEscape.useRaidBlocker) {
Subscribe(nameof(OnRaidBlock));
}
if (_configData.noEscape.useCombatBlocker) {
Subscribe(nameof(OnCombatBlock));
}
if (_configData.global.entityTimeLimit) {
_entitySpawnedTimes = new Hash<ulong, float>();
Subscribe(nameof(OnEntitySpawned));
Subscribe(nameof(OnEntityKill));
}
if (_configData.global.logToFile) {
_debugStringBuilder = new StringBuilder();
}
if (_removeMode == RemoveMode.MeleeHit && _configData.removerMode.meleeHitEnableInHand || _removeMode == RemoveMode.SpecificTool && _configData.removerMode.specificToolEnableInHand) {
Subscribe(nameof(OnActiveItemChanged));
}
if (!Enum.TryParse(_configData.global.removeButton, true, out _removeButton) || !Enum.IsDefined(typeof(BUTTON), _removeButton)) {
PrintError($"{_configData.global.removeButton} is an invalid button. The remove button has been changed to 'FIRE_PRIMARY'.");
_removeButton = BUTTON.FIRE_PRIMARY;
_configData.global.removeButton = _removeButton.ToString();
SaveConfig();
}
if (ImageLibrary != null) {
foreach (var image in _configData.imageUrls) {
AddImageToLibrary(image.Value, image.Key);
}
if (_configData.ui.showCrosshair) {
AddImageToLibrary(_configData.ui.crosshairImageUrl, UINAME_CROSSHAIR);
}
}
}
private void Unload() {
// if (_configChanged)
// {
// SaveConfig();
// }
SaveDebug();
if (_removeAllCoroutine != null) {
ServerMgr.Instance.StopCoroutine(_removeAllCoroutine);
}
if (_removeStructureCoroutine != null) {
ServerMgr.Instance.StopCoroutine(_removeStructureCoroutine);
}
if (_removeExternalCoroutine != null) {
ServerMgr.Instance.StopCoroutine(_removeExternalCoroutine);
}
if (_removePlayerEntityCoroutine != null) {
ServerMgr.Instance.StopCoroutine(_removePlayerEntityCoroutine);
}
foreach (var player in BasePlayer.activePlayerList) {
player.GetComponent<ToolRemover>()?.DisableTool();
}
_configData = null;
_instance = null;
}
private void OnServerSave() {
if (_configChanged) {
_configChanged = false;
timer.Once(Random.Range(0f, 60f), SaveConfig);
}
if (_configData.global.logToFile) {
timer.Once(Random.Range(0f, 60f), SaveDebug);
}
if (_configData.global.entityTimeLimit && _entitySpawnedTimes != null) {
var currentTime = Time.realtimeSinceStartup;
foreach (var entry in _entitySpawnedTimes.ToArray()) {
if (currentTime - entry.Value > _configData.global.limitTime) {
_entitySpawnedTimes.Remove(entry.Key);
}
}
}
}
private void OnEntitySpawned(BaseEntity entity) {
if (entity == null || entity.net == null) {
return;
}
// if (!CanEntityBeSaved(entity)) return;
_entitySpawnedTimes[entity.net.ID.Value] = Time.realtimeSinceStartup;
}
private void OnEntityKill(BaseEntity entity) {
if (entity == null || entity.net == null) {
return;
}
_entitySpawnedTimes.Remove(entity.net.ID.Value);
}
private object OnPlayerAttack(BasePlayer player, HitInfo info) {
return OnHammerHit(player, info);
}
private object OnHammerHit(BasePlayer player, HitInfo info) {
if (player == null || info.HitEntity == null) {
return null;
}
var toolRemover = player.GetComponent<ToolRemover>();
if (toolRemover == null) {
return null;
}
if (!IsMeleeTool(player)) {
return null;
}
toolRemover.HitEntity = info.HitEntity;
return _false;
}
private void OnActiveItemChanged(BasePlayer player, Item oldItem, Item newItem) {
if (newItem == null) {
return;
}
if (player == null || !player.userID.IsSteamId()) {
return;
}
if (IsToolRemover(player)) {
return;
}
if (_removeMode == RemoveMode.MeleeHit && IsMeleeTool(newItem)) {
ToggleRemove(player, RemoveType.Normal);
return;
}
if (_removeMode == RemoveMode.SpecificTool && IsSpecificTool(newItem)) {
ToggleRemove(player, RemoveType.Normal);
}
}
#endregion Oxide Hooks
#region Initializing
private readonly HashSet<Construction> _constructions = new HashSet<Construction>();
private readonly Dictionary<string, int> _itemShortNameToItemId = new Dictionary<string, int>();
private readonly Dictionary<string, string> _prefabNameToStructure = new Dictionary<string, string>();
private readonly Dictionary<string, string> _shortPrefabNameToDeployable = new Dictionary<string, string>();
private void Initialize() {
foreach (var itemDefinition in ItemManager.GetItemDefinitions()) {
if (!_itemShortNameToItemId.ContainsKey(itemDefinition.shortname)) {
_itemShortNameToItemId.Add(itemDefinition.shortname, itemDefinition.itemid);
}
var deployablePrefab = itemDefinition.GetComponent<ItemModDeployable>()?.entityPrefab?.resourcePath;
if (string.IsNullOrEmpty(deployablePrefab)) {
continue;
}
var shortPrefabName = Utility.GetFileNameWithoutExtension(deployablePrefab);
if (!string.IsNullOrEmpty(shortPrefabName) && !_shortPrefabNameToDeployable.ContainsKey(shortPrefabName)) {
_shortPrefabNameToDeployable.Add(shortPrefabName, itemDefinition.shortname);
}
}
foreach (var entry in PrefabAttribute.server.prefabs) {
var construction = entry.Value.Find<Construction>().FirstOrDefault();
if (construction != null && construction.deployable == null && !string.IsNullOrEmpty(construction.info.name.english)) {
_constructions.Add(construction);
if (!_prefabNameToStructure.ContainsKey(construction.fullName)) {
_prefabNameToStructure.Add(construction.fullName, construction.info.name.english);
}
}
}
}
#endregion Initializing
#region Methods
private static string GetRemoveTypeName(RemoveType removeType) {
return _configData.removeType[removeType].displayName;
}
private static void DropItemContainer(ItemContainer itemContainer, Vector3 position, Quaternion rotation) {
itemContainer?.Drop(PREFAB_ITEM_DROP, position, rotation, 0);
}
private static bool IsExternalWall(StabilityEntity stabilityEntity) {
return stabilityEntity.ShortPrefabName.Contains("external");
}
private static bool CanEntityBeDisplayed(BaseEntity entity, BasePlayer player) {
var stash = entity as StashContainer;
return stash == null || !stash.IsHidden() || stash.PlayerInRange(player);
}
private static bool CanEntityBeSaved(BaseEntity entity) {
if (entity is BuildingBlock) {
return true;
}
EntitySettings entitySettings;
if (_configData.remove.entity.TryGetValue(entity.ShortPrefabName, out entitySettings) && entitySettings.enabled) {
return true;
}
return false;
}
private static bool HasEntityEnabled(BaseEntity entity) {
var buildingBlock = entity as BuildingBlock;
if (buildingBlock != null) {
if (buildingBlock is BoatBuildingBlock) {
return false;
}
bool valid;
if (_configData.remove.validConstruction.TryGetValue(buildingBlock.grade, out valid) && valid) {
return true;
}
}
EntitySettings entitySettings;
if (_configData.remove.entity.TryGetValue(entity.ShortPrefabName, out entitySettings) && entitySettings.enabled) {
return true;
}
return false;
}
private static bool IsRemovableEntity(BaseEntity entity) {
if (_instance._shortPrefabNameToDeployable.ContainsKey(entity.ShortPrefabName) || _instance._prefabNameToStructure.ContainsKey(entity.PrefabName) || _configData.remove.entity.ContainsKey(entity.ShortPrefabName)) {
var baseCombatEntity = entity as BaseCombatEntity;
if (baseCombatEntity != null) {
if (baseCombatEntity.IsDead()) {
return false;
}
if (baseCombatEntity.pickup.itemTarget != null) {
return true;
}
}
return true;
}
return false;
}
private static string GetEntityImage(string name) {
if (_instance.ImageLibrary == null) {
return null;
}
if (_configData.imageUrls.ContainsKey(name)) {
return GetImageFromLibrary(name);
}
if (_instance._itemShortNameToItemId.ContainsKey(name)) {
return GetImageFromLibrary(name);
}
return null;
}
private static string GetItemImage(string shortname) {
if (_instance.ImageLibrary == null) {
return null;
}
switch (shortname.ToLower()) {
case ECONOMICS_KEY : return GetImageFromLibrary(ECONOMICS_KEY);
case SERVER_REWARDS_KEY : return GetImageFromLibrary(SERVER_REWARDS_KEY);
}
return GetEntityImage(shortname);
}
private static void TryFindEntityName(BasePlayer player, BaseEntity entity, out string displayName, out string imageName) {
var target = entity as BasePlayer;
if (target != null) {
imageName = target.userID.IsSteamId() ? target.UserIDString : target.ShortPrefabName;
displayName = $"{target.displayName} ({target.ShortPrefabName})";
return;
}
EntitySettings entitySettings;
if (_configData.remove.entity.TryGetValue(entity.ShortPrefabName, out entitySettings)) {
imageName = entity.ShortPrefabName;
displayName = _instance.GetDeployableDisplayName(player, entity.ShortPrefabName, entitySettings.displayName);
return;
}
string structureName;
if (_instance._prefabNameToStructure.TryGetValue(entity.PrefabName, out structureName)) {
BuildingBlocksSettings buildingBlockSettings;
if (_configData.remove.buildingBlock.TryGetValue(structureName, out buildingBlockSettings)) {
imageName = structureName;
displayName = _instance.GetConstructionDisplayName(player, entity.PrefabName, buildingBlockSettings.displayName);
return;
}
}
imageName = entity.ShortPrefabName;
displayName = entity.ShortPrefabName;
}
private static string GetDisplayNameByCurrencyName(string language, string currencyName, long skinId) {
var itemDefinition = ItemManager.FindItemDefinition(currencyName);
if (itemDefinition != null) {
var translationKey = $"{itemDefinition.shortname}_{skinId}";
var translationValue = GetCurrencyDisplayName(translationKey, itemDefinition.displayName.english, true);
if (skinId <= 0 || string.IsNullOrEmpty(translationValue)) {
var displayName = _instance.GetItemDisplayName(language, itemDefinition.shortname);
if (!string.IsNullOrEmpty(displayName)) {
return displayName;
}
return itemDefinition.displayName.english;
}
return GetCurrencyDisplayName(translationKey, itemDefinition.displayName.english);
}
return GetCurrencyDisplayName(currencyName, currencyName);
}
private static string GetCurrencyDisplayName(string currencyName, string defaultName = null, bool readOnly = false) {
string displayName;
if (_configData.remove.displayNames.TryGetValue(currencyName, out displayName)) {
return displayName;
}
if (!readOnly) {
_configData.remove.displayNames.Add(currencyName, defaultName);
_instance._configChanged = true;
}
return defaultName;
}
private static PermissionSettings GetPermissionSettings(BasePlayer player) {
var priority = 0;
PermissionSettings permissionSettings = null;
foreach (var entry in _configData.permission) {
if (entry.Value.priority >= priority && _instance.permission.UserHasPermission(player.UserIDString, entry.Key)) {
priority = entry.Value.priority;
permissionSettings = entry.Value;
}
}
return permissionSettings ?? new PermissionSettings();
}
private static Vector2 GetAnchor(string anchor) {
var array = anchor.Split(' ');
return new Vector2(float.Parse(array[0]), float.Parse(array[1]));
}
private static bool AddImageToLibrary(string url, string shortname, ulong skin = 0) {
return (bool)_instance.ImageLibrary.Call("AddImage", url, shortname.ToLower(), skin);
}
private static string GetImageFromLibrary(string shortname, ulong skin = 0, bool returnUrl = false) {
return string.IsNullOrEmpty(shortname) ? null : (string)_instance.ImageLibrary.Call("GetImage", shortname.ToLower(), skin, returnUrl);
}
#endregion Methods
#region NoEscape
private void OnRaidBlock(BasePlayer player) {
if (_configData.noEscape.useRaidBlocker) {
// Print(player, Lang("RaidBlocked", player.UserIDString));
player.GetComponent<ToolRemover>()?.DisableTool(false);
}
}
private void OnCombatBlock(BasePlayer player) {
if (_configData.noEscape.useCombatBlocker) {
// Print(player, Lang("CombatBlocked", player.UserIDString));
player.GetComponent<ToolRemover>()?.DisableTool(false);
}
}
private bool IsPlayerBlocked(BasePlayer player, out string reason) {
if (NoEscape != null) {
if (_configData.noEscape.useRaidBlocker && IsRaidBlocked(player.UserIDString)) {
reason = Lang("RaidBlocked", player.UserIDString);
return true;
}
if (_configData.noEscape.useCombatBlocker && IsCombatBlocked(player.UserIDString)) {
reason = Lang("CombatBlocked", player.UserIDString);
return true;
}
}
reason = null;
return false;
}
private bool IsRaidBlocked(string playerID) {
return (bool)NoEscape.Call("IsRaidBlocked", playerID);
}
private bool IsCombatBlocked(string playerID) {
return (bool)NoEscape.Call("IsCombatBlocked", playerID);
}
#endregion NoEscape
#region UI
private static class UI {
public static CuiElementContainer CreateElementContainer(string parent, string panelName, string backgroundColor, string anchorMin, string anchorMax, string offsetMin = "", string offsetMax = "", bool cursor = false) {
return new CuiElementContainer {
{
new CuiPanel {
Image = {
Color = backgroundColor
}
, RectTransform = {
AnchorMin = anchorMin, AnchorMax = anchorMax, OffsetMin = offsetMin, OffsetMax = offsetMax
}
, CursorEnabled = cursor
}
, parent, panelName
}
}
;
}
public static void CreatePanel(ref CuiElementContainer container, string panelName, string backgroundColor, string anchorMin, string anchorMax, bool cursor = false) {
container.Add(new CuiPanel {
Image = {
Color = backgroundColor
}
, RectTransform = {
AnchorMin = anchorMin, AnchorMax = anchorMax
}
, CursorEnabled = cursor
}
, panelName);
}
public static void CreateLabel(ref CuiElementContainer container, string panelName, string textColor, string text, int fontSize, string anchorMin, string anchorMax, TextAnchor align = TextAnchor.MiddleCenter, float fadeIn = 0f) {
container.Add(new CuiLabel {
Text = {
Color = textColor, FontSize = fontSize, Align = align, Text = text, FadeIn = fadeIn
}
, RectTransform = {
AnchorMin = anchorMin, AnchorMax = anchorMax
}
}
, panelName);
}
public static void CreateImage(ref CuiElementContainer container, string panelName, string image, string anchorMin, string anchorMax, string color = "1 1 1 1") {
container.Add(new CuiElement {
Name = CuiHelper.GetGuid(), Parent = panelName, Components = {
new CuiRawImageComponent {
Color = color, Png = image
}
, new CuiRectTransformComponent {
AnchorMin = anchorMin, AnchorMax = anchorMax
}
}
}
);
}
public static void CreateImage(ref CuiElementContainer container, string panelName, int itemId, ulong skinId, string anchorMin, string anchorMax) {
container.Add(new CuiPanel {
Image = {
ItemId = itemId, SkinId = skinId
}
, RectTransform = {
AnchorMin = anchorMin, AnchorMax = anchorMax
}
, CursorEnabled = false
}
, panelName);
}
}
[Flags]
private enum UiEntry {
None = 0, Entity = 1, Price = 1 << 1, Refund = 1 << 2, Auth = 1 << 3
}
private const string UINAME_MAIN = "RemoverToolUI_Main";
private const string UINAME_TIMELEFT = "RemoverToolUI_TimeLeft";
private const string UINAME_ENTITY = "RemoverToolUI_Entity";
private const string UINAME_PRICE = "RemoverToolUI_Price";
private const string UINAME_REFUND = "RemoverToolUI_Refund";
private const string UINAME_AUTH = "RemoverToolUI_Auth";
private const string UINAME_CROSSHAIR = "RemoverToolUI_Crosshair";
private static void CreateCrosshairUI(BasePlayer player) {
if (_instance.ImageLibrary == null) {
return;
}
var image = GetImageFromLibrary(UINAME_CROSSHAIR);
if (string.IsNullOrEmpty(image)) {
return;
}
var container = UI.CreateElementContainer("Hud", UINAME_CROSSHAIR, "0 0 0 0", _configData.ui.crosshairAnchorMin, _configData.ui.crosshairAnchorMax, _configData.ui.crosshairOffsetMin, _configData.ui.crosshairOffsetMax);
UI.CreateImage(ref container, UINAME_CROSSHAIR, image, "0 0", "1 1", _configData.ui.crosshairColor);
CuiHelper.DestroyUi(player, UINAME_CROSSHAIR);
CuiHelper.AddUi(player, container);
}
private static void CreateMainUI(BasePlayer player, RemoveType removeType) {
var container = UI.CreateElementContainer("Hud", UINAME_MAIN, _configData.ui.removerToolBackgroundColor, _configData.ui.removerToolAnchorMin, _configData.ui.removerToolAnchorMax, _configData.ui.removerToolOffsetMin, _configData.ui.removerToolOffsetMax);
UI.CreatePanel(ref container, UINAME_MAIN, _configData.ui.removeBackgroundColor, _configData.ui.removeAnchorMin, _configData.ui.removeAnchorMax);
UI.CreateLabel(ref container, UINAME_MAIN, _configData.ui.removeTextColor, _instance.Lang("RemoverToolType", player.UserIDString, GetRemoveTypeName(removeType)), _configData.ui.removeTextSize, _configData.ui.removeTextAnchorMin, _configData.ui.removeTextAnchorMax, TextAnchor.MiddleLeft);
CuiHelper.DestroyUi(player, UINAME_MAIN);
CuiHelper.AddUi(player, container);
}
private static void UpdateTimeLeftUI(BasePlayer player, RemoveType removeType, int timeLeft, int currentRemoved, int maxRemovable) {
var container = UI.CreateElementContainer(UINAME_MAIN, UINAME_TIMELEFT, _configData.ui.timeLeftBackgroundColor, _configData.ui.timeLeftAnchorMin, _configData.ui.timeLeftAnchorMax);
UI.CreateLabel(ref container, UINAME_TIMELEFT, _configData.ui.timeLeftTextColor, _instance.Lang("TimeLeft", player.UserIDString, timeLeft, removeType == RemoveType.Normal || removeType == RemoveType.Admin ? maxRemovable == 0 ? $"{currentRemoved} / {_instance.Lang("Unlimit", player.UserIDString)}" : $"{currentRemoved} / {maxRemovable}" : currentRemoved.ToString()), _configData.ui.timeLeftTextSize, _configData.ui.timeLeftTextAnchorMin, _configData.ui.timeLeftTextAnchorMax, TextAnchor.MiddleLeft);
CuiHelper.DestroyUi(player, UINAME_TIMELEFT);
CuiHelper.AddUi(player, container);
}
private static void UpdateEntityUI(BasePlayer player, BaseEntity targetEntity, RemovableEntityInfo? info) {
var container = UI.CreateElementContainer(UINAME_MAIN, UINAME_ENTITY, _configData.ui.entityBackgroundColor, _configData.ui.entityAnchorMin, _configData.ui.entityAnchorMax);
string displayName, imageName;
TryFindEntityName(player, targetEntity, out displayName, out imageName);
if (info.HasValue && !string.IsNullOrEmpty(info.Value.DisplayName.Value)) {
displayName = info.Value.DisplayName.Value;
}
UI.CreateLabel(ref container, UINAME_ENTITY, _configData.ui.entityTextColor, displayName, _configData.ui.entityTextSize, _configData.ui.entityTextAnchorMin, _configData.ui.entityTextAnchorMax, TextAnchor.MiddleLeft);
if (_configData.ui.entityImageEnabled) {
var imageAnchorMin = _configData.ui.entityImageAnchorMin;
var imageAnchorMax = _configData.ui.entityImageAnchorMax;
if (info.HasValue && !string.IsNullOrEmpty(info.Value.ImageId.Value)) {
var image = info.Value.ImageId.Value;
if (!string.IsNullOrEmpty(image)) {
UI.CreateImage(ref container, UINAME_ENTITY, image, imageAnchorMin, imageAnchorMax);
}
}
else if (!string.IsNullOrEmpty(imageName)) {
string shortname;
int itemId;
if (_instance._shortPrefabNameToDeployable.TryGetValue(imageName, out shortname) && _instance._itemShortNameToItemId.TryGetValue(shortname, out itemId)) {
UI.CreateImage(ref container, UINAME_ENTITY, itemId, targetEntity.skinID, imageAnchorMin, imageAnchorMax);
}
else {
var image = GetEntityImage(imageName);
if (!string.IsNullOrEmpty(image)) {
UI.CreateImage(ref container, UINAME_ENTITY, image, imageAnchorMin, imageAnchorMax);
}
}
}
}
CuiHelper.DestroyUi(player, UINAME_ENTITY);
CuiHelper.AddUi(player, container);
}
private static void UpdatePriceUI(BasePlayer player, BaseEntity targetEntity, RemovableEntityInfo? info, bool usePrice) {
Dictionary<string, CurrencyInfo> price = null;
if (usePrice) {
price = _instance.GetPrice(targetEntity, info);
}
var container = UI.CreateElementContainer(UINAME_MAIN, UINAME_PRICE, _configData.ui.priceBackgroundColor, _configData.ui.priceAnchorMin, _configData.ui.priceAnchorMax);
UI.CreateLabel(ref container, UINAME_PRICE, _configData.ui.priceTextColor, _instance.Lang("Price", player.UserIDString), _configData.ui.priceTextSize, _configData.ui.priceTextAnchorMin, _configData.ui.priceTextAnchorMax, TextAnchor.MiddleLeft);
if (price == null || price.Count == 0) {
UI.CreateLabel(ref container, UINAME_PRICE, _configData.ui.price2TextColor, _instance.Lang("Free", player.UserIDString), _configData.ui.price2TextSize, _configData.ui.price2TextAnchorMin, _configData.ui.price2TextAnchorMax, TextAnchor.MiddleLeft);
}
else {
var anchorMin = _configData.ui.Price2TextAnchorMin;
var anchorMax = _configData.ui.Price2TextAnchorMax;
var x = (anchorMax.y - anchorMin.y) / price.Count;
var textSize = _configData.ui.price2TextSize - price.Count;
var language = _instance.lang.GetLanguage(player.UserIDString);
var i = 0;
foreach (var entry in price) {
var externalItemInfo = info?.Price[entry.Key];
var displayText = !externalItemInfo.HasValue || string.IsNullOrEmpty(externalItemInfo.Value.DisplayName.Value) ? $"{GetDisplayNameByCurrencyName(language, entry.Key, entry.Value.SkinId)} <color=#00B5FF>x{entry.Value.Amount}</color>" : $"{externalItemInfo.Value.DisplayName.Value} x{externalItemInfo.Value.Amount.Value}";
UI.CreateLabel(ref container, UINAME_PRICE, _configData.ui.price2TextColor, displayText, textSize, $"{anchorMin.x} {anchorMin.y + i * x}", $"{anchorMax.x} {anchorMin.y + (i + 1) * x}", TextAnchor.MiddleLeft);
if (_configData.ui.imageEnabled) {
var imageAnchorMin = $"{anchorMax.x - _configData.ui.rightDistance - x * _configData.ui.imageScale} {anchorMin.y + i * x}";
var imageAnchorMax = $"{anchorMax.x - _configData.ui.rightDistance} {anchorMin.y + (i + 1) * x}";
if (externalItemInfo.HasValue && !string.IsNullOrEmpty(externalItemInfo.Value.ImageId.Value)) {
var image = externalItemInfo.Value.ImageId.Value;
if (!string.IsNullOrEmpty(image)) {
UI.CreateImage(ref container, UINAME_PRICE, image, imageAnchorMin, imageAnchorMax);
}
}
else {
int itemId;
if (_instance._itemShortNameToItemId.TryGetValue(entry.Key, out itemId)) {
UI.CreateImage(ref container, UINAME_PRICE, itemId, entry.Value.SkinId >= 0 ? (ulong)entry.Value.SkinId : 0, imageAnchorMin, imageAnchorMax);
}
else {
var image = GetItemImage(entry.Key);
if (!string.IsNullOrEmpty(image)) {
UI.CreateImage(ref container, UINAME_PRICE, image, imageAnchorMin, imageAnchorMax);
}
}
}
}
i++;
}
}
CuiHelper.DestroyUi(player, UINAME_PRICE);
CuiHelper.AddUi(player, container);
}
private static void UpdateRefundUI(BasePlayer player, BaseEntity targetEntity, RemovableEntityInfo? info, bool useRefund) {
Dictionary<string, CurrencyInfo> refund = null;
if (useRefund) {
refund = _instance.GetRefund(targetEntity, info);
}
var container = UI.CreateElementContainer(UINAME_MAIN, UINAME_REFUND, _configData.ui.refundBackgroundColor, _configData.ui.refundAnchorMin, _configData.ui.refundAnchorMax);
UI.CreateLabel(ref container, UINAME_REFUND, _configData.ui.refundTextColor, _instance.Lang("Refund", player.UserIDString), _configData.ui.refundTextSize, _configData.ui.refundTextAnchorMin, _configData.ui.refundTextAnchorMax, TextAnchor.MiddleLeft);
if (refund == null || refund.Count == 0) {
UI.CreateLabel(ref container, UINAME_REFUND, _configData.ui.refund2TextColor, _instance.Lang("Nothing", player.UserIDString), _configData.ui.refund2TextSize, _configData.ui.refund2TextAnchorMin, _configData.ui.refund2TextAnchorMax, TextAnchor.MiddleLeft);
}
else {
var anchorMin = _configData.ui.Refund2TextAnchorMin;
var anchorMax = _configData.ui.Refund2TextAnchorMax;
var x = (anchorMax.y - anchorMin.y) / refund.Count;
var textSize = _configData.ui.refund2TextSize - refund.Count;
var language = _instance.lang.GetLanguage(player.UserIDString);
var i = 0;
foreach (var entry in refund) {
var externalItemInfo = info?.Refund[entry.Key];
var displayText = !externalItemInfo.HasValue || string.IsNullOrEmpty(externalItemInfo.Value.DisplayName.Value) ? $"{GetDisplayNameByCurrencyName(language, entry.Key, entry.Value.SkinId)} <color=#00B5FF>x{entry.Value.Amount}</color>" : $"{externalItemInfo.Value.DisplayName.Value} x{externalItemInfo.Value.Amount.Value}";
UI.CreateLabel(ref container, UINAME_REFUND, _configData.ui.refund2TextColor, displayText, textSize, $"{anchorMin.x} {anchorMin.y + i * x}", $"{anchorMax.x} {anchorMin.y + (i + 1) * x}", TextAnchor.MiddleLeft);
if (_configData.ui.imageEnabled) {
var imageAnchorMin = $"{anchorMax.x - _configData.ui.rightDistance - x * _configData.ui.imageScale} {anchorMin.y + i * x}";
var imageAnchorMax = $"{anchorMax.x - _configData.ui.rightDistance} {anchorMin.y + (i + 1) * x}";
if (externalItemInfo.HasValue && !string.IsNullOrEmpty(externalItemInfo.Value.ImageId.Value)) {
var image = externalItemInfo.Value.ImageId.Value;
if (!string.IsNullOrEmpty(image)) {
UI.CreateImage(ref container, UINAME_REFUND, image, imageAnchorMin, imageAnchorMax);
}
}
else {
int itemId;
if (_instance._itemShortNameToItemId.TryGetValue(entry.Key, out itemId)) {
UI.CreateImage(ref container, UINAME_REFUND, itemId, entry.Value.SkinId >= 0 ? (ulong)entry.Value.SkinId : 0, imageAnchorMin, imageAnchorMax);
}
else {
var image = GetItemImage(entry.Key);
if (!string.IsNullOrEmpty(image)) {
UI.CreateImage(ref container, UINAME_REFUND, image, imageAnchorMin, imageAnchorMax);
}
}
}
}
i++;
}
}
CuiHelper.DestroyUi(player, UINAME_REFUND);
CuiHelper.AddUi(player, container);
}
private static void UpdateAuthorizationUI(BasePlayer player, RemoveType removeType, BaseEntity targetEntity, RemovableEntityInfo? info, bool shouldPay) {
string reason;
var color = _instance.CanRemoveEntity(player, removeType, targetEntity, info, shouldPay, out reason) ? _configData.ui.allowedBackgroundColor : _configData.ui.refusedBackgroundColor;
var container = UI.CreateElementContainer(UINAME_MAIN, UINAME_AUTH, color, _configData.ui.authorizationsAnchorMin, _configData.ui.authorizationsAnchorMax);
UI.CreateLabel(ref container, UINAME_AUTH, _configData.ui.authorizationsTextColor, reason, _configData.ui.authorizationsTextSize, _configData.ui.authorizationsTextAnchorMin, _configData.ui.authorizationsTextAnchorMax, TextAnchor.MiddleLeft);
CuiHelper.DestroyUi(player, UINAME_AUTH);
CuiHelper.AddUi(player, container);
}
private static void DestroyAllUI(BasePlayer player) {
CuiHelper.DestroyUi(player, UINAME_CROSSHAIR);
CuiHelper.DestroyUi(player, UINAME_MAIN);
}
private static void DestroyUiEntry(BasePlayer player, UiEntry uiEntry) {
switch (uiEntry) {
case UiEntry.Entity : CuiHelper.DestroyUi(player, UINAME_ENTITY);
return;
case UiEntry.Price : CuiHelper.DestroyUi(player, UINAME_PRICE);
return;
case UiEntry.Refund : CuiHelper.DestroyUi(player, UINAME_REFUND);
return;
case UiEntry.Auth : CuiHelper.DestroyUi(player, UINAME_AUTH);
return;
}
}
#endregion UI
#region ToolRemover Component
#region Tool Helpers
private static bool IsSpecificTool(BasePlayer player) {
var heldItem = player.GetActiveItem();
return IsSpecificTool(heldItem);
}
private static bool IsSpecificTool(Item heldItem) {
if (heldItem != null && heldItem.info.shortname == _configData.removerMode.specificToolShortName) {
if (_configData.removerMode.specificToolSkin < 0) {
return true;
}
return heldItem.skin == (ulong)_configData.removerMode.specificToolSkin;
}
return false;
}
private static bool IsMeleeTool(BasePlayer player) {
var heldItem = player.GetActiveItem();
return IsMeleeTool(heldItem);
}
private static bool IsMeleeTool(Item heldItem) {
if (heldItem != null && heldItem.info.shortname == _configData.removerMode.meleeHitItemShortname) {
if (_configData.removerMode.meleeHitModeSkin < 0) {
return true;
}
return heldItem.skin == (ulong)_configData.removerMode.meleeHitModeSkin;
}
return false;
}
#endregion Tool Helpers
private class ToolRemover : FacepunchBehaviour {
private const float MinInterval = 0.2f;
public int CurrentRemoved {
get;
set;
}
public BaseEntity HitEntity {
get;
set;
}
public bool CanOverride {
get;
private set;
}
public BasePlayer Player {
get;
private set;
}
public RemoveType RemoveType {
get;
private set;
}
private bool _resetTime;
private bool _shouldPay;
private bool _shouldRefund;
private int _removeTime;
private int _maxRemovable;
private float _distance;
private float _removeInterval;
private int _timeLeft;
private float _lastRemove;
private ItemId _currentItemId;
private bool _disableInHand;
private Item _lastHeldItem;
private BaseEntity _targetEntity;
private UiEntry _activeUiEntries;
private void Awake() {
Player = GetComponent<BasePlayer>();
_currentItemId = Player.svActiveItemID;
_disableInHand = _removeMode == RemoveMode.MeleeHit && _configData.removerMode.meleeHitDisableInHand || _removeMode == RemoveMode.SpecificTool && _configData.removerMode.specificToolDisableInHand;
if (_disableInHand) {
_lastHeldItem = Player.GetActiveItem();
}
if (_removeMode == RemoveMode.NoHeld) {
UnEquip();
}
}
public void Init(RemoveType removeType, int removeTime, int maxRemovable, float distance, float removeInterval, bool shouldPay, bool shouldRefund, bool resetTime, bool canOverride) {
RemoveType = removeType;
CanOverride = canOverride;
_distance = distance;
_resetTime = resetTime;
_removeTime = _timeLeft = removeTime;
_removeInterval = Mathf.Max(MinInterval, removeInterval);
if (RemoveType == RemoveType.Normal) {
_maxRemovable = maxRemovable;
_shouldPay = shouldPay && _configData.remove.priceEnabled;
_shouldRefund = shouldRefund && _configData.remove.refundEnabled;
_instance.PrintDebug($"{Player.displayName}({Player.userID}) have Enabled the remover tool.");
Interface.CallHook("OnRemoverToolActivated", Player);
}
else {
_maxRemovable = CurrentRemoved = 0;
_shouldPay = _shouldRefund = false;
}
DestroyAllUI(Player);
if (_configData.ui.showCrosshair) {
CreateCrosshairUI(Player);
}
if (_configData.ui.enabled) {
CreateMainUI(Player, RemoveType);
}
CancelInvoke(RemoveUpdate);
InvokeRepeating(RemoveUpdate, 0f, 1f);
}
private void RemoveUpdate() {
if (_configData.ui.enabled) {
_targetEntity = GetTargetEntity();
UpdateTimeLeftUI(Player, RemoveType, _timeLeft, CurrentRemoved, _maxRemovable);
var info = RemoveType == RemoveType.Normal ? GetRemovableEntityInfo(_targetEntity, Player) : null;
var canShow = (info.HasValue || _targetEntity != null) && CanEntityBeDisplayed(_targetEntity, Player);
if (HandleUiEntry(UiEntry.Entity, canShow)) {
UpdateEntityUI(Player, _targetEntity, info);
}
if (RemoveType == RemoveType.Normal) {
if (_configData.ui.authorizationEnabled) {
if (HandleUiEntry(UiEntry.Auth, canShow)) {
UpdateAuthorizationUI(Player, RemoveType, _targetEntity, info, _shouldPay);
}
}
if (_configData.ui.priceEnabled || _configData.ui.refundEnabled) {
canShow = canShow && (info.HasValue || HasEntityEnabled(_targetEntity));
if (_configData.ui.priceEnabled) {
if (HandleUiEntry(UiEntry.Price, canShow)) {
UpdatePriceUI(Player, _targetEntity, info, _shouldPay);
}
}
if (_configData.ui.refundEnabled) {
if (HandleUiEntry(UiEntry.Refund, canShow)) {
UpdateRefundUI(Player, _targetEntity, info, _shouldRefund);
}
}
}
}
}
if (_timeLeft-- <= 0) {
DisableTool();
}
}
private BaseEntity GetTargetEntity() {
BaseEntity target = null;
List<RaycastHit> hitInfos = Pool.Get<List<RaycastHit>>();
GamePhysics.TraceAll(Player.eyes.HeadRay(), 0f, hitInfos, _distance, LAYER_TARGET);
foreach (var hitInfo in hitInfos) {
var hitEntity = hitInfo.GetEntity();
if (hitEntity != null) {
if (target == null) {
target = hitEntity;
}
else if (hitEntity.GetParentEntity() == target) {
target = hitEntity;
// ... [Code preview truncated due to length. Full source in attached file] ...