C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
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 UnityEngine;
using VLB;
using Time = UnityEngine.Time;
namespace Oxide.Plugins {
[Info("Remover Tool", "Reneb/Fuji/Arainrr", "4.3.31", 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 object False;
private static RemoverTool _rt;
private static BUTTON _removeButton;
private static RemoveMode _removeMode;
private bool _removeOverride;
private Coroutine _removeAllCoroutine;
private Coroutine _removeStructureCoroutine;
private Coroutine _removeExternalCoroutine;
private Coroutine _removePlayerEntityCoroutine;
private Hash<uint, 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() {
_rt = this;
False = false;
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(OnServerSave));
Unsubscribe(nameof(OnRaidBlock));
Unsubscribe(nameof(OnCombatBlock));
foreach (var perm in configData.permS.Keys) {
if (!permission.PermissionExists(perm, this)) {
permission.RegisterPermission(perm, this);
}
}
cmd.AddChatCommand(configData.chatS.command, this, nameof(CmdRemove));
}
private void OnServerInitialized() {
Initialize();
UpdateConfig();
_removeMode = RemoveMode.None;
if (configData.removerModeS.noHeldMode) _removeMode = RemoveMode.NoHeld;
if (configData.removerModeS.meleeHitMode) _removeMode = RemoveMode.MeleeHit;
if (configData.removerModeS.specificToolMode) _removeMode = RemoveMode.SpecificTool;
if (_removeMode == RemoveMode.MeleeHit) {
BaseMelee beseMelee;
ItemDefinition itemDefinition;
if (string.IsNullOrEmpty(configData.removerModeS.meleeHitItemShortname) || (itemDefinition = ItemManager.FindItemDefinition(configData.removerModeS.meleeHitItemShortname)) == null || (beseMelee = itemDefinition.GetComponent<ItemModEntity>()?.entityPrefab.Get()?.GetComponent<BaseMelee>()) == null) {
PrintError($"{configData.removerModeS.meleeHitItemShortname} is not an item shortname for a melee tool");
_removeMode = RemoveMode.None;
}
else {
Subscribe(beseMelee is Hammer ? nameof(OnHammerHit) : nameof(OnPlayerAttack));
}
}
if (configData.noEscapeS.useRaidBlocker) {
Subscribe(nameof(OnRaidBlock));
}
if (configData.noEscapeS.useCombatBlocker) {
Subscribe(nameof(OnCombatBlock));
}
if (configData.globalS.entityTimeLimit) {
_entitySpawnedTimes = new Hash<uint, float>();
Subscribe(nameof(OnEntitySpawned));
Subscribe(nameof(OnEntityKill));
Subscribe(nameof(OnServerSave));
}
if (configData.globalS.logToFile) {
debugStringBuilder = new StringBuilder();
Subscribe(nameof(OnServerSave));
}
if (_removeMode == RemoveMode.MeleeHit && configData.removerModeS.meleeHitEnableInHand || _removeMode == RemoveMode.SpecificTool && configData.removerModeS.specificToolEnableInHand) {
Subscribe(nameof(OnActiveItemChanged));
}
if (!Enum.TryParse(configData.globalS.removeButton, true, out _removeButton) || !Enum.IsDefined(typeof(BUTTON), _removeButton)) {
PrintError($"{configData.globalS.removeButton} is an invalid button.The remove button has been changed to 'FIRE_PRIMARY'.");
_removeButton = BUTTON.FIRE_PRIMARY;
configData.globalS.removeButton = _removeButton.ToString();
SaveConfig();
}
if (ImageLibrary != null) {
foreach (var image in configData.imageUrls) {
AddImageToLibrary(image.Value, image.Key);
}
if (configData.uiS.showCrosshair) {
AddImageToLibrary(configData.uiS.crosshairImageUrl, UINAME_CROSSHAIR);
}
}
}
private void Unload() {
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();
}
SaveDebug();
configData = null;
False = _rt = null;
}
private void OnServerSave() {
if (configData.globalS.logToFile) {
timer.Once(UnityEngine.Random.Range(0f, 60f), SaveDebug);
}
if (_entitySpawnedTimes != null) {
var currentTime = Time.realtimeSinceStartup;
foreach (var entry in _entitySpawnedTimes.ToArray()) {
if (currentTime - entry.Value > configData.globalS.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] = Time.realtimeSinceStartup;
}
private void OnEntityKill(BaseEntity entity) {
if (entity == null || entity.net == null) return;
_entitySpawnedTimes.Remove(entity.net.ID);
}
private object OnPlayerAttack(BasePlayer player, HitInfo info) => 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);
return;
}
}
#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) => configData.removeTypeS[removeType].displayName;
private static void DropItemContainer(ItemContainer itemContainer, Vector3 position, Quaternion rotation) => itemContainer?.Drop(PREFAB_ITEM_DROP, position, rotation);
private static bool IsExternalWall(StabilityEntity stabilityEntity) => 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.removeS.entityS.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) {
bool valid;
if (configData.removeS.validConstruction.TryGetValue(buildingBlock.grade, out valid) && valid) {
return true;
}
}
EntitySettings entitySettings;
if (configData.removeS.entityS.TryGetValue(entity.ShortPrefabName, out entitySettings) && entitySettings.enabled) {
return true;
}
return false;
}
private static bool IsRemovableEntity(BaseEntity entity) {
if (_rt._shortPrefabNameToDeployable.ContainsKey(entity.ShortPrefabName) || _rt._prefabNameToStructure.ContainsKey(entity.PrefabName) || configData.removeS.entityS.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 (configData.imageUrls.ContainsKey(name)) {
return GetImageFromLibrary(name);
}
if (_rt._itemShortNameToItemId.ContainsKey(name)) {
return GetImageFromLibrary(name);
}
return null;
}
private static string GetItemImage(string shortname) {
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} ({GetOtherDisplayName(target.ShortPrefabName)})";
return;
}
EntitySettings entitySettings;
if (configData.removeS.entityS.TryGetValue(entity.ShortPrefabName, out entitySettings)) {
imageName = entity.ShortPrefabName;
displayName = _rt.GetDeployableDisplayName(player, entity.ShortPrefabName, entitySettings.displayName);
return;
}
string structureName;
if (_rt._prefabNameToStructure.TryGetValue(entity.PrefabName, out structureName)) {
BuildingBlocksSettings buildingBlockSettings;
if (configData.removeS.buildingBlockS.TryGetValue(structureName, out buildingBlockSettings)) {
imageName = structureName;
displayName = _rt.GetConstructionDisplayName(player, entity.PrefabName, buildingBlockSettings.displayName);
return;
}
}
imageName = entity.ShortPrefabName;
displayName = GetOtherDisplayName(entity.ShortPrefabName);
}
private static string GetDisplayNameByPriceName(string language, string priceName) {
var itemDefinition = ItemManager.FindItemDefinition(priceName);
if (itemDefinition != null) {
var displayName = _rt.GetItemDisplayName(language, itemDefinition.shortname);
if (!string.IsNullOrEmpty(displayName)) {
return displayName;
}
return GetOtherDisplayName(itemDefinition.displayName.english);
}
return GetOtherDisplayName(priceName);
}
private static string GetOtherDisplayName(string name) {
string displayName;
if (configData.displayNames.TryGetValue(name, out displayName)) {
return displayName;
}
configData.displayNames.Add(name, name);
_rt.SaveConfig();
return name;
}
private static PermissionSettings GetPermissionS(BasePlayer player) {
int priority = 0;
PermissionSettings permissionSettings = null;
foreach (var entry in configData.permS) {
if (entry.Value.priority >= priority && _rt.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) => (bool)_rt.ImageLibrary.Call("AddImage", url, shortname.ToLower(), skin);
private static string GetImageFromLibrary(string shortname, ulong skin = 0, bool returnUrl = false) => string.IsNullOrEmpty(shortname) ? null : (string)_rt.ImageLibrary.Call("GetImage", shortname.ToLower(), skin, returnUrl);
#endregion Methods
#region NoEscape
private void OnRaidBlock(BasePlayer player) {
if (configData.noEscapeS.useRaidBlocker) {
//TODO lang
player.GetComponent<ToolRemover>()?.DisableTool(false);
}
}
private void OnCombatBlock(BasePlayer player) {
if (configData.noEscapeS.useCombatBlocker) {
//TODO lang
player.GetComponent<ToolRemover>()?.DisableTool(false);
}
}
private bool IsPlayerBlocked(BasePlayer player, out string reason) {
if (NoEscape == null) {
reason = null;
return false;
}
if (configData.noEscapeS.useRaidBlocker && IsRaidBlocked(player.UserIDString)) {
//TODO lang
reason = Lang("RaidBlocked", player.UserIDString);
return true;
}
if (configData.noEscapeS.useCombatBlocker && IsCombatBlocked(player.UserIDString)) {
//TODO lang
reason = Lang("CombatBlocked", player.UserIDString);
return true;
}
reason = null;
return false;
}
private bool IsRaidBlocked(string playerID) => (bool)NoEscape.Call("IsRaidBlocked", playerID);
private bool IsCombatBlocked(string playerID) => (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 {
Sprite = "assets/content/textures/generic/fulltransparent.tga", Color = color, Png = image
}
, new CuiRectTransformComponent {
AnchorMin = anchorMin, AnchorMax = anchorMax
}
}
}
);
}
}
[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 (_rt.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.uiS.crosshairAnchorMin, configData.uiS.crosshairAnchorMax, configData.uiS.crosshairOffsetMin, configData.uiS.crosshairOffsetMax);
UI.CreateImage(ref container, UINAME_CROSSHAIR, image, "0 0", "1 1", configData.uiS.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.uiS.removerToolBackgroundColor, configData.uiS.removerToolAnchorMin, configData.uiS.removerToolAnchorMax, configData.uiS.removerToolOffsetMin, configData.uiS.removerToolOffsetMax);
UI.CreatePanel(ref container, UINAME_MAIN, configData.uiS.removeBackgroundColor, configData.uiS.removeAnchorMin, configData.uiS.removeAnchorMax);
UI.CreateLabel(ref container, UINAME_MAIN, configData.uiS.removeTextColor, _rt.Lang("RemoverToolType", player.UserIDString, GetRemoveTypeName(removeType)), configData.uiS.removeTextSize, configData.uiS.removeTextAnchorMin, configData.uiS.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.uiS.timeLeftBackgroundColor, configData.uiS.timeLeftAnchorMin, configData.uiS.timeLeftAnchorMax);
UI.CreateLabel(ref container, UINAME_TIMELEFT, configData.uiS.timeLeftTextColor, _rt.Lang("TimeLeft", player.UserIDString, timeLeft, removeType == RemoveType.Normal || removeType == RemoveType.Admin ? maxRemovable == 0 ? $"{currentRemoved} / {_rt.Lang("Unlimit", player.UserIDString)}" : $"{currentRemoved} / {maxRemovable}" : currentRemoved.ToString()), configData.uiS.timeLeftTextSize, configData.uiS.timeLeftTextAnchorMin, configData.uiS.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.uiS.entityBackgroundColor, configData.uiS.entityAnchorMin, configData.uiS.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.uiS.entityTextColor, displayName, configData.uiS.entityTextSize, configData.uiS.entityTextAnchorMin, configData.uiS.entityTextAnchorMax, TextAnchor.MiddleLeft);
if (configData.uiS.entityImageEnabled && !string.IsNullOrEmpty(imageName) && _rt.ImageLibrary != null) {
var imageId = info.HasValue && !string.IsNullOrEmpty(info.Value.ImageId.Value) ? info.Value.ImageId.Value : GetEntityImage(imageName);
if (!string.IsNullOrEmpty(imageId)) {
UI.CreateImage(ref container, UINAME_ENTITY, imageId, configData.uiS.entityImageAnchorMin, configData.uiS.entityImageAnchorMax);
}
}
CuiHelper.DestroyUi(player, UINAME_ENTITY);
CuiHelper.AddUi(player, container);
}
private static void UpdatePriceUI(BasePlayer player, BaseEntity targetEntity, RemovableEntityInfo? info, bool usePrice) {
Dictionary<string, int> price = null;
if (usePrice) {
price = _rt.GetPrice(targetEntity, info);
}
var container = UI.CreateElementContainer(UINAME_MAIN, UINAME_PRICE, configData.uiS.priceBackgroundColor, configData.uiS.priceAnchorMin, configData.uiS.priceAnchorMax);
UI.CreateLabel(ref container, UINAME_PRICE, configData.uiS.priceTextColor, _rt.Lang("Price", player.UserIDString), configData.uiS.priceTextSize, configData.uiS.priceTextAnchorMin, configData.uiS.priceTextAnchorMax, TextAnchor.MiddleLeft);
if (price == null || price.Count == 0) {
UI.CreateLabel(ref container, UINAME_PRICE, configData.uiS.price2TextColor, _rt.Lang("Free", player.UserIDString), configData.uiS.price2TextSize, configData.uiS.price2TextAnchorMin, configData.uiS.price2TextAnchorMax, TextAnchor.MiddleLeft);
}
else {
var anchorMin = configData.uiS.Price2TextAnchorMin;
var anchorMax = configData.uiS.Price2TextAnchorMax;
float x = (anchorMax.y - anchorMin.y) / price.Count;
int textSize = configData.uiS.price2TextSize - price.Count;
string language = _rt.lang.GetLanguage(player.UserIDString);
int i = 0;
foreach (var entry in price) {
var itemInfo = info?.Price[entry.Key];
string displayText = !itemInfo.HasValue || string.IsNullOrEmpty(itemInfo.Value.DisplayName.Value) ? $"{GetDisplayNameByPriceName(language, entry.Key)} x{entry.Value}" : $"{itemInfo.Value.DisplayName.Value} x{itemInfo.Value.Amount.Value}";
UI.CreateLabel(ref container, UINAME_PRICE, configData.uiS.price2TextColor, displayText, textSize, $"{anchorMin.x} {anchorMin.y + i * x}", $"{anchorMax.x} {anchorMin.y + (i + 1) * x}", TextAnchor.MiddleLeft);
if (configData.uiS.imageEnabled && _rt.ImageLibrary != null) {
var image = itemInfo.HasValue && !string.IsNullOrEmpty(itemInfo.Value.ImageId.Value) ? itemInfo.Value.ImageId.Value : GetItemImage(entry.Key);
if (!string.IsNullOrEmpty(image)) {
UI.CreateImage(ref container, UINAME_PRICE, image, $"{anchorMax.x - configData.uiS.rightDistance - x * configData.uiS.imageScale} {anchorMin.y + i * x}", $"{anchorMax.x - configData.uiS.rightDistance} {anchorMin.y + (i + 1) * x}");
}
}
i++;
}
}
CuiHelper.DestroyUi(player, UINAME_PRICE);
CuiHelper.AddUi(player, container);
}
private static void UpdateRefundUI(BasePlayer player, BaseEntity targetEntity, RemovableEntityInfo? info, bool useRefund) {
Dictionary<string, int> refund = null;
if (useRefund) {
refund = _rt.GetRefund(targetEntity, info);
}
var container = UI.CreateElementContainer(UINAME_MAIN, UINAME_REFUND, configData.uiS.refundBackgroundColor, configData.uiS.refundAnchorMin, configData.uiS.refundAnchorMax);
UI.CreateLabel(ref container, UINAME_REFUND, configData.uiS.refundTextColor, _rt.Lang("Refund", player.UserIDString), configData.uiS.refundTextSize, configData.uiS.refundTextAnchorMin, configData.uiS.refundTextAnchorMax, TextAnchor.MiddleLeft);
if (refund == null || refund.Count == 0) {
UI.CreateLabel(ref container, UINAME_REFUND, configData.uiS.refund2TextColor, _rt.Lang("Nothing", player.UserIDString), configData.uiS.refund2TextSize, configData.uiS.refund2TextAnchorMin, configData.uiS.refund2TextAnchorMax, TextAnchor.MiddleLeft);
}
else {
var anchorMin = configData.uiS.Refund2TextAnchorMin;
var anchorMax = configData.uiS.Refund2TextAnchorMax;
float x = (anchorMax.y - anchorMin.y) / refund.Count;
int textSize = configData.uiS.refund2TextSize - refund.Count;
string language = _rt.lang.GetLanguage(player.UserIDString);
int i = 0;
foreach (var entry in refund) {
var itemInfo = info?.Refund[entry.Key];
string displayText = !itemInfo.HasValue || string.IsNullOrEmpty(itemInfo.Value.DisplayName.Value) ? $"{GetDisplayNameByPriceName(language, entry.Key)} x{entry.Value}" : $"{itemInfo.Value.DisplayName.Value} x{itemInfo.Value.Amount.Value}";
UI.CreateLabel(ref container, UINAME_REFUND, configData.uiS.refund2TextColor, displayText, textSize, $"{anchorMin.x} {anchorMin.y + i * x}", $"{anchorMax.x} {anchorMin.y + (i + 1) * x}", TextAnchor.MiddleLeft);
if (configData.uiS.imageEnabled && _rt.ImageLibrary != null) {
var image = itemInfo.HasValue && !string.IsNullOrEmpty(itemInfo.Value.ImageId.Value) ? itemInfo.Value.ImageId.Value : GetItemImage(entry.Key);
if (!string.IsNullOrEmpty(image)) {
UI.CreateImage(ref container, UINAME_REFUND, image, $"{anchorMax.x - configData.uiS.rightDistance - x * configData.uiS.imageScale} {anchorMin.y + i * x}", $"{anchorMax.x - configData.uiS.rightDistance} {anchorMin.y + (i + 1) * x}");
}
}
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;
string color = _rt.CanRemoveEntity(player, removeType, targetEntity, info, shouldPay, out reason) ? configData.uiS.allowedBackgroundColor : configData.uiS.refusedBackgroundColor;
var container = UI.CreateElementContainer(UINAME_MAIN, UINAME_AUTH, color, configData.uiS.authorizationsAnchorMin, configData.uiS.authorizationsAnchorMax);
UI.CreateLabel(ref container, UINAME_AUTH, configData.uiS.authorizationsTextColor, reason, configData.uiS.authorizationsTextSize, configData.uiS.authorizationsTextAnchorMin, configData.uiS.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.removerModeS.specificToolShortname) {
if (configData.removerModeS.specificToolSkin < 0) return true;
return heldItem.skin == (ulong)configData.removerModeS.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.removerModeS.meleeHitItemShortname) {
if (configData.removerModeS.meleeHitModeSkin < 0) return true;
return heldItem.skin == (ulong)configData.removerModeS.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 uint _currentItemId;
private bool _disableInHand;
private UiEntry _activeUiEntries;
private Item _lastHeldItem;
private BaseEntity _targetEntity;
private void Awake() {
player = GetComponent<BasePlayer>();
_currentItemId = player.svActiveItemID;
_disableInHand = _removeMode == RemoveMode.MeleeHit && configData.removerModeS.meleeHitDisableInHand || _removeMode == RemoveMode.SpecificTool && configData.removerModeS.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) {
this.removeType = removeType;
this.canOverride = canOverride;
_distance = distance;
_resetTime = resetTime;
_removeTime = _timeLeft = removeTime;
_removeInterval = Mathf.Max(MinInterval, removeInterval);
if (this.removeType == RemoveType.Normal) {
_maxRemovable = maxRemovable;
_shouldPay = shouldPay && configData.removeS.priceEnabled;
_shouldRefund = shouldRefund && configData.removeS.refundEnabled;
_rt.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.uiS.showCrosshair) {
CreateCrosshairUI(player);
}
if (configData.uiS.enabled) {
CreateMainUI(player, this.removeType);
}
CancelInvoke(RemoveUpdate);
InvokeRepeating(RemoveUpdate, 0f, 1f);
}
private void RemoveUpdate() {
if (configData.uiS.enabled) {
_targetEntity = GetTargetEntity();
UpdateTimeLeftUI(player, removeType, _timeLeft, currentRemoved, _maxRemovable);
var info = removeType == RemoveType.Normal ? GetRemovableEntityInfo(_targetEntity, player) : null;
bool canShow = (info.HasValue || _targetEntity != null) && CanEntityBeDisplayed(_targetEntity, player);
if (HandleUiEntry(UiEntry.Entity, canShow)) {
UpdateEntityUI(player, _targetEntity, info);
}
if (removeType == RemoveType.Normal) {
if (configData.uiS.authorizationEnabled) {
if (HandleUiEntry(UiEntry.Auth, canShow)) {
UpdateAuthorizationUI(player, removeType, _targetEntity, info, _shouldPay);
}
}
if (configData.uiS.priceEnabled || configData.uiS.refundEnabled) {
canShow = canShow && (info.HasValue || HasEntityEnabled(_targetEntity));
if (configData.uiS.priceEnabled) {
if (HandleUiEntry(UiEntry.Price, canShow)) {
UpdatePriceUI(player, _targetEntity, info, _shouldPay);
}
}
if (configData.uiS.refundEnabled) {
if (HandleUiEntry(UiEntry.Refund, canShow)) {
UpdateRefundUI(player, _targetEntity, info, _shouldRefund);
}
}
}
}
}
if (_timeLeft-- <= 0) {
DisableTool();
}
}
private BaseEntity GetTargetEntity() {
RaycastHit hitInfo;
return Physics.Raycast(player.eyes.HeadRay(), out hitInfo, _distance, LAYER_TARGET) ? hitInfo.GetEntity() : null;
}
private void Update() {
if (player == null || !player.IsConnected || !player.CanInteract()) {
DisableTool();
return;
}
if (player.svActiveItemID != _currentItemId) {
if (_disableInHand) {
var heldItem = player.GetActiveItem();
if (_removeMode == RemoveMode.MeleeHit && IsMeleeTool(_lastHeldItem) && !IsMeleeTool(heldItem) || _removeMode == RemoveMode.SpecificTool && IsSpecificTool(_lastHeldItem) && !IsSpecificTool(heldItem)) {
DisableTool();
return;
}
_lastHeldItem = heldItem;
}
if (_removeMode == RemoveMode.NoHeld) {
if (player.svActiveItemID != 0) {
if (configData.removerModeS.noHeldDisableInHand) {
DisableTool();
return;
}
UnEquip();
}
}
_currentItemId = player.svActiveItemID;
}
if (Time.realtimeSinceStartup - _lastRemove >= _removeInterval) {
if (_removeMode == RemoveMode.MeleeHit) {
if (hitEntity == null) return;
_targetEntity = hitEntity;
hitEntity = null;
}
else {
if (!player.serverInput.IsDown(_removeButton)) {
return;
}
if (_removeMode == RemoveMode.SpecificTool && !IsSpecificTool(player)) {
//rt.Print(player,rt.Lang("UsageOfRemove",player.UserIDString));
return;
}
_targetEntity = GetTargetEntity();
}
if (_rt.TryRemove(player, _targetEntity, removeType, _shouldPay, _shouldRefund)) {
if (_resetTime) {
_timeLeft = _removeTime;
}
if (removeType == RemoveType.Normal || removeType == RemoveType.Admin) {
currentRemoved++;
}
if (configData.globalS.startCooldownOnRemoved && removeType == RemoveType.Normal) {
_rt._cooldownTimes[player.userID] = Time.realtimeSinceStartup;
}
}
_lastRemove = Time.realtimeSinceStartup;
}
if (removeType == RemoveType.Normal && _maxRemovable > 0 && currentRemoved >= _maxRemovable) {
_rt.Print(player, _rt.Lang("EntityLimit", player.UserIDString, _maxRemovable));
DisableTool(false);
}
;
}
private void UnEquip() {
//player.lastReceivedTick.activeItem = 0;
var activeItem = player.GetActiveItem();
if (activeItem?.GetHeldEntity() is HeldEntity) {
var slot = activeItem.position;
activeItem.SetParent(null);
player.Invoke(() => {
if (activeItem == null || !activeItem.IsValid()) return;
if (player.inventory.containerBelt.GetSlot(slot) == null) {
activeItem.position = slot;
activeItem.SetParent(player.inventory.containerBelt);
}
else player.GiveItem(activeItem);
}
, 0.2f);
}
}
private bool HandleUiEntry(UiEntry uiEntry, bool canShow) {
if (canShow) {
_activeUiEntries |= uiEntry;
return true;
}
if (_activeUiEntries.HasFlag(uiEntry)) {
_activeUiEntries &= ~uiEntry;
DestroyUiEntry(player, uiEntry);
}
return false;
}
public void DisableTool(bool showMessage = true) {
if (showMessage) {
if (_rt != null && player != null && player.IsConnected) {
_rt.Print(player, _rt.Lang("ToolDisabled", player.UserIDString));
}
}
if (removeType == RemoveType.Normal) {
if (_rt != null && player != null) {
_rt.PrintDebug($"{player.displayName}({player.userID}) have Disabled the remover tool.");
}
Interface.CallHook("OnRemoverToolDeactivated", player);
}
DestroyAllUI(player);
Destroy(this);
}
private void OnDestroy() {
if (_rt != null && removeType == RemoveType.Normal) {
if (configData != null && !configData.globalS.startCooldownOnRemoved) {
_rt._cooldownTimes[player.userID] = Time.realtimeSinceStartup;
}
}
}
}
#endregion ToolRemover Component
#region TryRemove
private bool TryRemove(BasePlayer player, BaseEntity targetEntity, RemoveType removeType, bool shouldPay, bool shouldRefund) {
if (targetEntity == null) {
Print(player, Lang("NotFoundOrFar", player.UserIDString));
return false;
}
if (targetEntity.IsDestroyed) {
Print(player, Lang("InvalidEntity", player.UserIDString));
// ... [Code preview truncated due to length. Full source in attached file] ...