C#:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust;
using Oxide.Game.Rust.Cui;
using UnityEngine;
namespace Oxide.Plugins {
[Info("Remover Tool", "Reneb/Fuji/Arainrr", "4.3.15", ResourceId = 651)]
[Description("Building and entity removal tool")]
public class RemoverTool : RustPlugin {
#region Fields
[PluginReference]
private readonly Plugin Friends, ServerRewards, Clans, Economics, ImageLibrary;
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 readonly static int LAYER_ALL = LayerMask.GetMask("Construction", "Deployed", "Default");
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 readonly Hash<uint, float> entitySpawnedTimes = new Hash<uint, float>();
private readonly Hash<ulong, float> cooldownTimes = new Hash<ulong, float>();
private enum RemoveMode {
None, NoHeld, HammerHit, SpecificTool
}
private enum RemoveType {
All, Admin, Normal, External, Structure
}
#endregion Fields
#region Oxide Hooks
private void Init() {
rt = 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);
cmd.AddChatCommand(configData.chatS.command, this, nameof(CmdRemove));
foreach (var perm in configData.permS.Keys) {
if (!permission.PermissionExists(perm, this)) permission.RegisterPermission(perm, this);
}
Unsubscribe(nameof(OnEntityDeath));
Unsubscribe(nameof(OnHammerHit));
Unsubscribe(nameof(OnEntitySpawned));
Unsubscribe(nameof(OnEntityKill));
}
private void OnServerInitialized() {
Initialize();
UpdateConfig();
removeMode = RemoveMode.None;
if (configData.removerModeS.noHeldMode) removeMode = RemoveMode.NoHeld;
if (configData.removerModeS.hammerHitMode) removeMode = RemoveMode.HammerHit;
if (configData.removerModeS.specificTool) removeMode = RemoveMode.SpecificTool;
if (removeMode == RemoveMode.HammerHit) Subscribe(nameof(OnHammerHit));
if (configData.raidS.enabled) Subscribe(nameof(OnEntityDeath));
if (configData.globalS.entityTimeLimit) {
Subscribe(nameof(OnEntitySpawned));
Subscribe(nameof(OnEntityKill));
}
if (!Enum.TryParse(configData.globalS.removeButton, true, out 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);
}
}
private void Unload() {
if (removeAllCoroutine != null) ServerMgr.Instance.StopCoroutine(removeAllCoroutine);
if (removeStructureCoroutine != null) ServerMgr.Instance.StopCoroutine(removeStructureCoroutine);
if (removeExternalCoroutine != null) ServerMgr.Instance.StopCoroutine(removeExternalCoroutine);
foreach (var player in BasePlayer.activePlayerList) {
var toolRemover = player.GetComponent<ToolRemover>();
if (toolRemover != null) UnityEngine.Object.Destroy(toolRemover);
DestroyUI(player);
}
rt = null;
configData = null;
}
private void OnEntityDeath(BuildingBlock buildingBlock, HitInfo info) {
if (buildingBlock == null || info == null) return;
var attacker = info.InitiatorPlayer;
if (attacker != null && attacker.userID.IsSteamId() && HasAccess(attacker, buildingBlock)) return;
BlockRemove(buildingBlock);
}
private void OnEntitySpawned(BaseEntity entity) {
if (entity == null || entity.net == null) return;
if (!EntityCanBeSaved(entity)) return;
entitySpawnedTimes[entity.net.ID] = Time.realtimeSinceStartup;
}
private void OnEntityKill(BaseEntity entity) {
if (entity == null || entity.net == null) return;
if (!EntityCanBeSaved(entity)) return;
entitySpawnedTimes.Remove(entity.net.ID);
}
private object OnHammerHit(BasePlayer player, HitInfo info) {
var toolRemover = player.GetComponent<ToolRemover>();
if (toolRemover == null) return null;
toolRemover.hitEntity = info.HitEntity;
return false;
}
#endregion Oxide Hooks
#region Initializing
private readonly Dictionary<string, string> shorPrefabNameToDeployable = new Dictionary<string, string>();
private readonly Dictionary<string, string> prefabNameToStructure = new Dictionary<string, string>();
private readonly Dictionary<string, int> itemShortNameToItemID = new Dictionary<string, int>();
private readonly HashSet<Construction> constructions = new HashSet<Construction>();
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 = GameManager.server.FindPrefab(deployablePrefab)?.GetComponent<BaseEntity>()?.ShortPrefabName;
if (!string.IsNullOrEmpty(shortPrefabName) && !shorPrefabNameToDeployable.ContainsKey(shortPrefabName)) shorPrefabNameToDeployable.Add(shortPrefabName, itemDefinition.shortname);
}
foreach (var entityPath in GameManifest.Current.entities) {
var construction = PrefabAttribute.server.Find<Construction>(StringPool.Get(entityPath));
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 dropPosition, Quaternion rotation) => itemContainer?.Drop(PREFAB_ITEM_DROP, dropPosition, rotation);
private static bool IsExternalWall(StabilityEntity stabilityEntity) => stabilityEntity.ShortPrefabName.Contains("external");
private static bool IsRemovableEntity(BaseEntity entity) => rt.shorPrefabNameToDeployable.ContainsKey(entity.ShortPrefabName) || rt.prefabNameToStructure.ContainsKey(entity.PrefabName) || configData.removeS.entityS.ContainsKey(entity.ShortPrefabName);
private static bool EntityCanBeSaved(BaseEntity entity) {
if (entity is BuildingBlock) return true;
ConfigData.RemoveS.EntityS entityS;
return configData.removeS.entityS.TryGetValue(entity.ShortPrefabName, out entityS) && entityS.enabled;
}
private static bool IsValidEntity(BaseEntity entity) {
var buildingBlock = entity.GetComponent<BuildingBlock>();
bool valid;
if (buildingBlock != null && configData.removeS.validConstruction.TryGetValue(buildingBlock.grade, out valid) && valid) return true;
ConfigData.RemoveS.EntityS entityS;
if (configData.removeS.entityS.TryGetValue(entity.ShortPrefabName, out entityS) && entityS.enabled) return true;
return false;
}
private static string GetEntityName(BaseEntity entity) {
string entityName;
if (rt.shorPrefabNameToDeployable.TryGetValue(entity.ShortPrefabName, out entityName)) return entityName;
if (rt.prefabNameToStructure.TryGetValue(entity.PrefabName, out entityName)) return entityName;
if (configData.removeS.entityS.ContainsKey(entity.ShortPrefabName)) return entity.ShortPrefabName;
return string.Empty;
}
private static string GetEntityImage(string name) {
if (configData.imageUrls.ContainsKey(name)) return GetImageFromLibrary(name);
if (rt.itemShortNameToItemID.ContainsKey(name)) return GetImageFromLibrary(name);
return string.Empty;
}
private static string GetItemImage(string shortname) {
switch (shortname.ToLower()) {
case "economics" : return GetImageFromLibrary("Economics");
case "serverrewards" : return GetImageFromLibrary("ServerRewards");
}
return GetEntityImage(shortname);
}
private static string GetDisplayName(string name) {
var shorPrefabName = rt.shorPrefabNameToDeployable.FirstOrDefault(x => x.Value == name).Key;
if (string.IsNullOrEmpty(shorPrefabName)) shorPrefabName = name;
ConfigData.RemoveS.EntityS entityS;
if (configData.removeS.entityS.TryGetValue(shorPrefabName, out entityS)) return entityS.displayName;
ConfigData.RemoveS.BuildingBlocksS buildingBlockS;
if (configData.removeS.buildingBlockS.TryGetValue(name, out buildingBlockS)) return buildingBlockS.displayName;
if (configData.displayNames.TryGetValue(name, out shorPrefabName)) return shorPrefabName;
var itemDefinition = ItemManager.FindItemDefinition(name);
if (itemDefinition != null) {
configData.displayNames.Add(name, itemDefinition.displayName.english);
name = itemDefinition.displayName.english;
}
else configData.displayNames.Add(name, name);
rt.SaveConfig();
return name;
}
private static Vector2 GetAnchor(string anchor) {
string[] 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) ? string.Empty : (string)rt.ImageLibrary.Call("GetImage", shortname.ToLower(), skin, returnUrl);
#endregion Methods
#region UI
private class UI {
public static CuiElementContainer CreateElementContainer(string parent, string panelName, string backgroundColor, string anchorMin, string anchorMax, bool cursor = false) {
return new CuiElementContainer() {
{
new CuiPanel {
Image = {
Color = backgroundColor
}
, RectTransform = {
AnchorMin = anchorMin, AnchorMax = anchorMax
}
, CursorEnabled = cursor
}
, new CuiElement().Parent = 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, CuiHelper.GetGuid());
}
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, CuiHelper.GetGuid());
}
public static void CreateImage(ref CuiElementContainer container, string panelName, string image, string anchorMin, string anchorMax) {
CuiRawImageComponent imageComponent = new CuiRawImageComponent {
Sprite = "assets/content/textures/generic/fulltransparent.tga"
}
;
if (image.StartsWith("http") || image.StartsWith("www")) imageComponent.Url = image;
else imageComponent.Png = image;
container.Add(new CuiElement {
Name = CuiHelper.GetGuid(), Parent = panelName, Components = {
imageComponent, new CuiRectTransformComponent {
AnchorMin = anchorMin, AnchorMax = anchorMax
}
}
}
);
}
}
private const string UINAME_MAIN = "RemoverTool";
private const string UINAME_TIMELEFT = "RemoverToolTimeLeft";
private const string UINAME_ENTITY = "RemoverToolEntity";
private const string UINAME_PRICE = "RemoverToolPrice";
private const string UINAME_REFUND = "RemoverToolRefund";
private const string UINAME_AUTH = "RemoverToolAuth";
private static void CreateUI(BasePlayer player, RemoveType removeType) {
CuiHelper.DestroyUi(player, UINAME_MAIN);
var container = UI.CreateElementContainer("Hud", UINAME_MAIN, configData.uiS.removerToolBackgroundColor, configData.uiS.removerToolAnchorMin, configData.uiS.removerToolAnchorMax);
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.AddUi(player, container);
}
private static void TimeLeftUpdate(BasePlayer player, RemoveType removeType, int timeLeft, int currentRemoved, int maxRemovable) {
CuiHelper.DestroyUi(player, UINAME_TIMELEFT);
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.AddUi(player, container);
}
private static void EntityUpdate(BasePlayer player, BaseEntity targetEntity) {
CuiHelper.DestroyUi(player, UINAME_ENTITY);
if (targetEntity == null) return;
var container = UI.CreateElementContainer(UINAME_MAIN, UINAME_ENTITY, configData.uiS.entityBackgroundColor, configData.uiS.entityAnchorMin, configData.uiS.entityAnchorMax);
string name;
var entityName = GetEntityName(targetEntity);
if (string.IsNullOrEmpty(entityName)) {
if (targetEntity is BasePlayer) name = $"{(targetEntity as BasePlayer).displayName} ({GetDisplayName(targetEntity.ShortPrefabName)})";
else name = targetEntity.ShortPrefabName;
}
else name = GetDisplayName(entityName);
UI.CreateLabel(ref container, UINAME_ENTITY, configData.uiS.entityTextColor, name, configData.uiS.entityTextSize, configData.uiS.entityTextAnchorMin, configData.uiS.entityTextAnchorMax, TextAnchor.MiddleLeft);
if (configData.uiS.entityImageEnabled && !string.IsNullOrEmpty(entityName) && rt.ImageLibrary != null) {
var image = GetEntityImage(entityName);
if (!string.IsNullOrEmpty(image)) UI.CreateImage(ref container, UINAME_ENTITY, image, configData.uiS.entityImageAnchorMin, configData.uiS.entityImageAnchorMax);
}
CuiHelper.AddUi(player, container);
}
private static void PricesUpdate(BasePlayer player, bool usePrice, BaseEntity targetEntity) {
CuiHelper.DestroyUi(player, UINAME_PRICE);
if (targetEntity == null || !IsValidEntity(targetEntity)) return;
var price = new Dictionary<string, int>();
if (usePrice) price = rt.GetPrice(targetEntity);
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.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 = GetAnchor(configData.uiS.price2TextAnchorMin);
var anchorMax = GetAnchor(configData.uiS.price2TextAnchorMax);
float x = (anchorMax.y - anchorMin.y) / price.Count;
int textSize = configData.uiS.price2TextSize - price.Count;
int i = 0;
foreach (var p in price) {
UI.CreateLabel(ref container, UINAME_PRICE, configData.uiS.price2TextColor, $"{GetDisplayName(p.Key)} x{p.Value}", 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 = GetItemImage(p.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.AddUi(player, container);
}
private static void RefundUpdate(BasePlayer player, bool useRefund, BaseEntity targetEntity) {
CuiHelper.DestroyUi(player, UINAME_REFUND);
if (targetEntity == null || !IsValidEntity(targetEntity)) return;
var refund = new Dictionary<string, int>();
if (useRefund) refund = rt.GetRefund(targetEntity);
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.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 = GetAnchor(configData.uiS.refund2TextAnchorMin);
var anchorMax = GetAnchor(configData.uiS.refund2TextAnchorMax);
float x = (anchorMax.y - anchorMin.y) / refund.Count;
int textSize = configData.uiS.refund2TextSize - refund.Count;
int i = 0;
foreach (var p in refund) {
UI.CreateLabel(ref container, UINAME_REFUND, configData.uiS.refund2TextColor, $"{GetDisplayName(p.Key)} x{p.Value}", 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 = GetItemImage(p.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.AddUi(player, container);
}
private static void AuthorizationUpdate(BasePlayer player, RemoveType removeType, BaseEntity targetEntity, bool shouldPay) {
CuiHelper.DestroyUi(player, UINAME_AUTH);
if (targetEntity == null) return;
string reason;
string color = rt.CanRemoveEntity(player, removeType, targetEntity, 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.AddUi(player, container);
}
private static void DestroyUI(BasePlayer player) => CuiHelper.DestroyUi(player, UINAME_MAIN);
#endregion UI
#region ToolRemover Class
private class ToolRemover : FacepunchBehaviour {
public BasePlayer player;
public RemoveType removeType;
public bool canOverride;
public BaseEntity hitEntity;
public int currentRemoved;
private int timeLeft;
private float distance;
private float lastRemove;
private float removeInterval;
private bool pay;
private bool refund;
private int maxRemovable;
private RaycastHit raycastHit;
private BaseEntity targetEntity;
private uint currentItemID;
private Item heldItem;
private int removeTime;
private bool resetTime;
private void Awake() {
player = GetComponent<BasePlayer>();
if (removeMode == RemoveMode.NoHeld) {
currentItemID = player.svActiveItemID;
UnEquip();
}
if (removeMode == RemoveMode.SpecificTool) heldItem = player.GetActiveItem();
}
public void Init(RemoveType type, int time, int max, float dis, float interval, bool p, bool r, bool reset, bool c) {
canOverride = c;
removeTime = timeLeft = time;
removeType = type;
distance = dis;
resetTime = reset;
removeInterval = interval;
if (removeInterval < 0.2f) removeInterval = 0.2f;
if (removeType == RemoveType.Normal) {
maxRemovable = max;
pay = p && configData.removeS.priceEnabled;
refund = r && configData.removeS.refundEnabled;
}
else {
maxRemovable = currentRemoved = 0;
pay = refund = false;
}
CreateUI(player, removeType);
CancelInvoke(RemoveUpdate);
InvokeRepeating(RemoveUpdate, 0f, 1f);
}
private void RemoveUpdate() {
if (configData.uiS.enabled) {
TimeLeftUpdate(player, removeType, timeLeft, currentRemoved, maxRemovable);
GetTargetEntity();
EntityUpdate(player, targetEntity);
if (removeType == RemoveType.Normal) {
if (configData.uiS.authorizationEnabled) AuthorizationUpdate(player, removeType, targetEntity, pay);
if (configData.uiS.priceEnabled) PricesUpdate(player, pay, targetEntity);
if (configData.uiS.refundEnabled) RefundUpdate(player, refund, targetEntity);
}
}
if (timeLeft-- <= 0) Destroy(this);
}
private void GetTargetEntity() {
bool flag = Physics.Raycast(player.eyes.HeadRay(), out raycastHit, distance, Rust.Layers.Solid);
targetEntity = flag ? raycastHit.GetEntity() : null;
}
private bool IsSpecificTool() {
heldItem = player.GetActiveItem();
if (heldItem != null && heldItem.info.shortname == configData.removerModeS.shortname) {
if (configData.removerModeS.skin < 0) return true;
return heldItem.skin == (ulong)configData.removerModeS.skin;
}
return false;
}
private void FixedUpdate() {
if (player == null || !player.IsConnected || !player.CanInteract()) {
Destroy(this);
return;
}
if (removeMode == RemoveMode.NoHeld && player.svActiveItemID != currentItemID) {
currentItemID = player.svActiveItemID;
if (currentItemID != 0) {
if (configData.removerModeS.disableInHand) {
Destroy(this);
return;
}
UnEquip();
}
}
if (Time.realtimeSinceStartup - lastRemove >= removeInterval) {
if (removeMode != RemoveMode.HammerHit) {
if (!player.serverInput.IsDown(removeButton)) return;
if (removeMode == RemoveMode.SpecificTool && !IsSpecificTool()) return;
GetTargetEntity();
if (rt.TryRemove(player, targetEntity, removeType, distance, pay, refund)) {
if (resetTime) timeLeft = removeTime;
if (removeType == RemoveType.Normal || removeType == RemoveType.Admin) currentRemoved++;
}
}
else {
if (hitEntity == null) return;
targetEntity = hitEntity;
if (rt.TryRemove(player, targetEntity, removeType, distance, pay, refund)) {
if (resetTime) timeLeft = removeTime;
if (removeType == RemoveType.Normal || removeType == RemoveType.Admin) currentRemoved++;
}
hitEntity = null;
}
lastRemove = Time.realtimeSinceStartup;
}
if (removeType == RemoveType.Normal && maxRemovable > 0 && currentRemoved >= maxRemovable) {
rt.Print(player, rt.Lang("EntityLimit", player.UserIDString, maxRemovable));
Destroy(this);
}
;
}
private void UnEquip() {
//player.lastReceivedTick.activeItem = 0;
var activeItem = player.GetActiveItem();
if (activeItem == null) return;
var heldEntity = activeItem.GetHeldEntity() as HeldEntity;
if (heldEntity == null) return;
var slot = activeItem.position;
activeItem.SetParent(null);
rt.timer.Once(0.2f, () => {
if (activeItem == null || player == null) return;
if (player.inventory.containerBelt.GetSlot(slot) == null) {
activeItem.position = slot;
activeItem.SetParent(player.inventory.containerBelt);
}
else player.GiveItem(activeItem);
}
);
}
private void OnDestroy() {
CancelInvoke(RemoveUpdate);
DestroyUI(player);
if (removeType == RemoveType.Normal && rt != null) rt.cooldownTimes[player.userID] = Time.realtimeSinceStartup;
}
}
#endregion ToolRemover Class
#region Pay
private bool Pay(BasePlayer player, BaseEntity targetEntity) {
var price = GetPrice(targetEntity);
try {
List<Item> collect = new List<Item>();
foreach (var p in price) {
if (p.Value <= 0) continue;
int itemID;
if (itemShortNameToItemID.TryGetValue(p.Key, out itemID)) {
player.inventory.Take(collect, itemID, p.Value);
player.Command("note.inv", itemID, -p.Value);
}
else if (!CheckOrPay(p.Key, p.Value, player.userID)) return false;
}
foreach (Item item in collect) item.Remove();
}
catch (Exception e) {
PrintError($"{player} couldn't pay to remove entity.Error Message: {e.Message}");
return false;
}
return true;
}
private Dictionary<string, int> GetPrice(BaseEntity targetEntity) {
var price = new Dictionary<string, int>();
var buildingblock = targetEntity.GetComponent<BuildingBlock>();
if (buildingblock != null) {
var entityName = prefabNameToStructure[buildingblock.PrefabName];
ConfigData.RemoveS.BuildingBlocksS buildingBlockS;
if (configData.removeS.buildingBlockS.TryGetValue(entityName, out buildingBlockS)) {
ConfigData.RemoveS.BuildingBlocksS.BuildingGradeS buildingGradeS;
if (buildingBlockS.buildingGradeS.TryGetValue(buildingblock.grade, out buildingGradeS)) {
float percentage;
if (float.TryParse(buildingGradeS.price.ToString(), out percentage)) {
var currentGrade = buildingblock.currentGrade;
if (currentGrade != null) {
foreach (var itemAmount in currentGrade.costToBuild) {
var amount = Mathf.RoundToInt(itemAmount.amount * percentage / 100);
if (amount <= 0) continue;
price.Add(itemAmount.itemDef.shortname, amount);
}
return price;
}
}
else {
if (buildingGradeS.price is Dictionary<string, int>) return buildingGradeS.price as Dictionary<string, int>;
try {
return JsonConvert.DeserializeObject<Dictionary<string, int>>(buildingGradeS.price.ToString());
}
catch (Exception e) {
PrintError($"Wrong price format for '{buildingblock.grade}' of '{entityName}' in 'Building Blocks Settings'.Error Message: {e.Message}");
var currentGrade = buildingblock.currentGrade;
if (currentGrade != null) return currentGrade.costToBuild.ToDictionary(x => x.itemDef.shortname, y => Mathf.RoundToInt(y.amount));
}
}
}
}
}
else {
ConfigData.RemoveS.EntityS entityS;
if (configData.removeS.entityS.TryGetValue(targetEntity.ShortPrefabName, out entityS)) return entityS.price;
}
return price;
}
private bool CanPay(BasePlayer player, BaseEntity targetEntity) {
var price = GetPrice(targetEntity);
if (price.Count <= 0) return true;
foreach (var p in price) {
if (p.Value <= 0) continue;
int itemID;
if (itemShortNameToItemID.TryGetValue(p.Key, out itemID)) {
int c = player.inventory.GetAmount(itemID);
if (c < p.Value) return false;
}
else if (!CheckOrPay(p.Key, p.Value, player.userID, true)) return false;
}
return true;
}
private bool CheckOrPay(string key, int price, ulong playerID, bool check = false) {
if (price <= 0) return true;
switch (key.ToLower()) {
case "economics" : if (Economics == null) return false;
if (check) {
var b = Economics.Call("Balance", playerID);
if (b == null) return false;
if ((double)b < price) return false;
}
else {
var w = Economics.Call("Withdraw", playerID, (double)price);
if (w == null || !(bool)w) return false;
}
return true;
case "serverrewards" : if (ServerRewards == null) return false;
if (check) {
var c = ServerRewards.Call("CheckPoints", playerID);
if (c == null) return false;
if ((int)c < price) return false;
}
else {
var t = ServerRewards.Call("TakePoints", playerID, price);
if (t == null || !(bool)t) return false;
}
return true;
}
return true;
}
#endregion Pay
#region Refund
private void GiveRefund(BasePlayer player, BaseEntity targetEntity) {
var refund = GetRefund(targetEntity);
foreach (var r in refund) {
if (r.Value <= 0) continue;
int itemID;
string shortname;
shorPrefabNameToDeployable.TryGetValue(targetEntity.ShortPrefabName, out shortname);
if (itemShortNameToItemID.TryGetValue(r.Key, out itemID)) {
var item = ItemManager.CreateByItemID(itemID, r.Value, r.Key == shortname ? targetEntity.skinID : 0);
player.GiveItem(item);
}
else {
switch (r.Key.ToLower()) {
case "economics" : if (Economics == null) continue;
Economics.Call("Deposit", player.userID, (double)r.Value);
continue;
case "serverrewards" : if (ServerRewards == null) continue;
ServerRewards.Call("AddPoints", player.userID, r.Value);
continue;
default : PrintError($"{player} didn't receive refund because {r.Key} doesn't seem to be a valid item name");
continue;
}
}
}
}
private Dictionary<string, int> GetRefund(BaseEntity targetEntity) {
var refund = new Dictionary<string, int>();
var buildingblock = targetEntity.GetComponent<BuildingBlock>();
if (buildingblock != null) {
var entityName = prefabNameToStructure[buildingblock.PrefabName];
ConfigData.RemoveS.BuildingBlocksS buildingBlockS;
if (configData.removeS.buildingBlockS.TryGetValue(entityName, out buildingBlockS)) {
ConfigData.RemoveS.BuildingBlocksS.BuildingGradeS buildingGradeS;
if (buildingBlockS.buildingGradeS.TryGetValue(buildingblock.grade, out buildingGradeS)) {
float percentage;
if (float.TryParse(buildingGradeS.refund.ToString(), out percentage)) {
var currentGrade = buildingblock.currentGrade;
if (currentGrade != null) {
foreach (var itemAmount in currentGrade.costToBuild) {
var amount = Mathf.RoundToInt(itemAmount.amount * percentage / 100);
if (amount <= 0) continue;
refund.Add(itemAmount.itemDef.shortname, amount);
}
return refund;
}
}
else {
if (buildingGradeS.refund is Dictionary<string, int>) return buildingGradeS.refund as Dictionary<string, int>;
try {
return JsonConvert.DeserializeObject<Dictionary<string, int>>(buildingGradeS.refund.ToString());
}
catch (Exception e) {
PrintError($"Wrong refund format for '{buildingblock.grade}' of '{entityName}' in 'Building Blocks Settings'.Error Message: {e.Message}");
var currentGrade = buildingblock.currentGrade;
if (currentGrade != null) return currentGrade.costToBuild.ToDictionary(x => x.itemDef.shortname, y => Mathf.RoundToInt(y.amount));
}
}
}
}
}
else {
ConfigData.RemoveS.EntityS entityS;
if (configData.removeS.entityS.TryGetValue(targetEntity.ShortPrefabName, out entityS)) refund = entityS.refund;
if (configData.removeS.refundSlot) {
var slots = GetSlots(targetEntity);
if (slots.Count > 0) {
int value, amount;
var r = new Dictionary<string, int>();
var union = refund.Keys.Union(slots.Keys);
foreach (var u in union) {
value = 0;
if (refund.TryGetValue(u, out amount)) value += amount;
if (slots.TryGetValue(u, out amount)) value += amount;
r.Add(u, value);
}
return r;
}
}
}
return refund;
}
private Dictionary<string, int> GetSlots(BaseEntity targetEntity) {
var slots = new Dictionary<string, int>();
foreach (BaseEntity.Slot slot in Enum.GetValues(typeof(BaseEntity.Slot))) {
if (targetEntity.HasSlot(slot)) {
var s = targetEntity.GetSlot(slot);
if (s != null) {
string slotName;
if (shorPrefabNameToDeployable.TryGetValue(s.ShortPrefabName, out slotName)) slots.Add(slotName, 1);
}
}
}
return slots;
}
#endregion Refund
#region RaidBlocker
private readonly Hash<uint, float> lastAttackedBuildings = new Hash<uint, float>();
private readonly Hash<ulong, float> lastBlockedPlayers = new Hash<ulong, float>();
private void BlockRemove(BuildingBlock buildingBlock) {
if (configData.raidS.blockBuildingID) {
var buildingID = buildingBlock.buildingID;
lastAttackedBuildings[buildingID] = Time.realtimeSinceStartup;
}
if (configData.raidS.blockPlayers) {
var players = Pool.GetList<BasePlayer>();
Vis.Entities(buildingBlock.transform.position, configData.raidS.blockRadius, players, Rust.Layers.Mask.Player_Server);
foreach (var player in players) {
if (player.userID.IsSteamId()) lastBlockedPlayers[player.userID] = Time.realtimeSinceStartup;
}
Pool.FreeList(ref players);
}
}
private bool IsRaidBlocked(BasePlayer player, BaseEntity targetEntity, out float timeLeft) {
if (configData.raidS.blockBuildingID) {
var buildingBlock = targetEntity.GetComponent<BuildingBlock>();
if (buildingBlock != null) {
timeLeft = configData.raidS.blockTime - (Time.realtimeSinceStartup - lastAttackedBuildings[buildingBlock.buildingID]);
if (timeLeft > 0) return true;
}
}
if (configData.raidS.blockPlayers) {
timeLeft = configData.raidS.blockTime - (Time.realtimeSinceStartup - lastBlockedPlayers[player.userID]);
if (timeLeft > 0) return true;
}
timeLeft = 0;
return false;
}
#endregion RaidBlocker
#region TryRemove
private bool TryRemove(BasePlayer player, BaseEntity targetEntity, RemoveType removeType, float distance, bool shouldPay, bool shouldRefund) {
if (targetEntity == null) {
Print(player, Lang("NotFoundOrFar", player.UserIDString));
return false;
}
if (removeType == RemoveType.Admin) {
if (targetEntity is BasePlayer) {
var target = targetEntity as BasePlayer;
if (target.userID.IsSteamId() && target.IsConnected) {
target.Kick("From RemoverTool Plugin");
return true;
}
}
DoRemove(targetEntity, configData.removeTypeS[RemoveType.Admin].gibs);
return true;
}
string reason;
if (!CanRemoveEntity(player, removeType, targetEntity, shouldPay, out reason)) {
Print(player, reason);
return false;
}
if (removeType == RemoveType.All) {
if (removeAllCoroutine != null) {
Print(player, Lang("AlreadyRemoveAll", player.UserIDString));
return false;
}
removeAllCoroutine = ServerMgr.Instance.StartCoroutine(RemoveAll(targetEntity, player));
Print(player, Lang("StartRemoveAll", player.UserIDString));
return true;
}
if (removeType == RemoveType.External) {
var stabilityEntity = targetEntity.GetComponent<StabilityEntity>();
if (stabilityEntity == null || !IsExternalWall(stabilityEntity)) {
Print(player, Lang("NotExternalWall", player.UserIDString));
return false;
}
if (removeExternalCoroutine != null) {
Print(player, Lang("AlreadyRemoveExternal", player.UserIDString));
return false;
}
removeExternalCoroutine = ServerMgr.Instance.StartCoroutine(RemoveExternal(stabilityEntity, player));
Print(player, Lang("StartRemoveExternal", player.UserIDString));
return true;
}
if (removeType == RemoveType.Structure) {
var decayEntity = targetEntity.GetComponent<DecayEntity>();
if (decayEntity == null) {
Print(player, Lang("NotStructure", player.UserIDString));
return false;
}
if (removeStructureCoroutine != null) {
Print(player, Lang("AlreadyRemoveStructure", player.UserIDString));
return false;
}
removeStructureCoroutine = ServerMgr.Instance.StartCoroutine(RemoveStructure(decayEntity, player));
Print(player, Lang("StartRemoveStructure", player.UserIDString));
return true;
}
if (targetEntity is StorageContainer) {
var storageContainer = targetEntity as StorageContainer;
if (storageContainer.inventory?.itemList?.Count > 0) {
if (configData.con
// ... [Code preview truncated due to length. Full source in attached file] ...