C#:
using System;
using System.Collections.Generic;
using Oxide.Core.Plugins;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("HammerRemove", "i3ladik", "1.0.0")]
[Description("Ремув с помощью удара киянкой с зажатой кнопкой")]
public class HammerRemove : RustPlugin
{
[PluginReference] Plugin Clans, Friends, NoEscape;
static Configuration config = new Configuration();
private static Dictionary<uint, RemovableObject> RemovableInfos = new Dictionary<uint,RemovableObject>();
private static Dictionary<string, int> deployedToItem = new Dictionary<string, int>();
private static double CurrentTime() => DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
private static BUTTON _removeButton;
class Configuration
{
[JsonProperty("Кнопка для удаления (FORWARD/BACKWARD/LEFT/RIGHT/JUMP/DUCK/SPRINT/USE/FIRE_PRIMARY/FIRE_SECONDARY/RELOAD/FIRE_THIRD)")]
public string removeButton;
[JsonProperty("Время удаления построек")]
public double bRemoveTime;
[JsonProperty("Включить запрет на удаление объекта если в его инвентаре есть предметы")]
public bool checkRemoveItems;
[JsonProperty("Процент возвращаемых ресурсов с предметов (1.0 - 100%)")]
public float refundItemsPercent;
[JsonProperty("Процент возвращаемых ресурсов с построек (1.0 - 100%)")]
public float refundPercent;
[JsonProperty("Включить возрат предметов (будут возвращаться предметы а не ресурсы)")]
public bool refundItemsGive;
[JsonProperty("Процент выпадающих ресурсов (не вещей) с удаляемых ящиков (1.0 - 100%)")]
public float refundStoragePercent;
[JsonProperty("Разрешить удаление объектов друзей без авторизации в шкафу")]
public bool friendRemove;
[JsonProperty("Разрешить удаление объектов соклановцев без авторизации в шкафу")]
public bool clanRemove;
[JsonProperty("Разрешить удаление объектов тиммейтов (RUST) без авторизации в шкафу")]
public bool teamRemove;
[JsonProperty("Разрешить удаление чужих объектов при наличии авторизации в шкафу")]
public bool cupboardRemove;
[JsonProperty("Разрешить удаление собственных объектов без авторизации в шкафу")]
public bool selfRemove;
[JsonProperty("Включить поддержку NoEscape")]
public bool useNoEscape;
[JsonProperty("Разрешить удаление обьектов друзьям")]
public bool removeFriends;
[JsonProperty("Разрешить удаление объектов соклановцев")]
public bool removeClans;
[JsonProperty("Разрешить удаление объектов тиммейтов (RUST)")]
public bool removeTeam;
[JsonProperty("Черный список удаления")]
public List<string> blackList = new List<string>();
public static Configuration GetNewConfiguration()
{
return new Configuration
{
removeButton = BUTTON.RELOAD.ToString(),
bRemoveTime = 21600,
checkRemoveItems = true,
refundItemsPercent = 1.0f,
refundPercent = 1.0f,
refundItemsGive = true,
refundStoragePercent = 1.0f,
friendRemove = false,
clanRemove = false,
teamRemove = false,
cupboardRemove = true,
selfRemove = false,
useNoEscape = false,
removeFriends = false,
removeClans = false,
removeTeam = true,
blackList = new List<string>
{
"small_stash_deployed"
}
};
}
}
private class RemovableObject
{
[JsonProperty("S")]
public bool isInteractable;
[JsonProperty("T")]
public long buildTime;
[JsonIgnore]
public long lastAttackedTime;
public string Label() => isInteractable ? $"<size=14>РЕМУВ/ПОВОРОТ ДОСТУПЕН</size>\n" : $"<size=14>РЕМУВ/ПОВОРОТ ОТНЫНЕ НЕ ДОСТУПЕН</size>\n";
public string InteractStatus(bool admin = false)
{
if (!isInteractable)
{
if (buildTime < 0)
return $"{Label()}" + "<size=13>ИСТЕКЛО ВРЕМЯ УДАЛЕНИЯ</size>\n<color=#d3c9c0>✕</color>";
return $"{Label()}" + "<size=13>ДОМ БЫЛ ПОДВЕРЖЕН РЕЙДУ</size>\n<color=#d3c9c0>✕</color>";
}
if (CurrentTime() >= (buildTime + config.bRemoveTime))
{
isInteractable = false;
buildTime = -1;
return InteractStatus();
}
var totalTime = TimeSpan.FromSeconds((buildTime + config.bRemoveTime) - CurrentTime());
return $"<size=18>{Label()}</size>" +
$"<size=16>{totalTime.Hours}ч.{totalTime.Minutes}м.</size>";
}
public string BuildTimeConverted()
{
var date = DateTime.FromFileTime(buildTime);
return $"{date.ToShortDateString()} {date.ToShortTimeString()}";
}
public static RemovableObject Generate(BuildingBlock obj)
{
return new RemovableObject
{
isInteractable = true,
buildTime = (long) CurrentTime()
};
}
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<Configuration>();
if (config == null) LoadDefaultConfig();
}
catch
{
PrintWarning($"Ошибка чтения конфигурации 'oxide/config/{Name}', создаём новую конфигурацию!!");
LoadDefaultConfig();
}
NextTick(SaveConfig);
}
protected override void LoadDefaultConfig() => config = Configuration.GetNewConfiguration();
protected override void SaveConfig() => Config.WriteObject(config);
private void Unload() => SaveData();
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject(Name, RemovableInfos);
}
private void OnServerInitialized()
{
if (Interface.Oxide.DataFileSystem.ExistsDatafile(Name))
RemovableInfos = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<uint, RemovableObject>>(Name);
var dirty = new List<uint>();
foreach (var check in RemovableInfos.Where(p => BaseNetworkable.serverEntities.Find(p.Key)?.IsDestroyed ?? true))
dirty.Add(check.Key);
foreach (var check in dirty)
RemovableInfos.Remove(check);
SaveData();
UnityEngine.Object.FindObjectsOfType<BuildingBlock>().ToList().ForEach(p =>
{
if (!RemovableInfos.ContainsKey(p.net.ID))
RemovableInfos.Add(p.net.ID, RemovableObject.Generate(p));
p.SetFlag(BaseEntity.Flags.Reserved1, true);
p.SetFlag(BaseEntity.Flags.Reserved2, true);
p.CancelInvoke(p.StopBeingRotatable);
p.CancelInvoke(p.StopBeingDemolishable);
});
deployedToItem.Clear();
List<ItemDefinition> ItemsDefinition = ItemManager.GetItemDefinitions() as List<ItemDefinition>;
foreach (ItemDefinition itemdef in ItemsDefinition)
{
if (itemdef?.GetComponent<ItemModDeployable>() == null) continue;
if (deployedToItem.ContainsKey(itemdef.GetComponent<ItemModDeployable>().entityPrefab.resourcePath)) continue;
deployedToItem.Add(itemdef.GetComponent<ItemModDeployable>().entityPrefab.resourcePath, itemdef.itemid);
}
lang.RegisterMessages(Messages, this, "ru");
Messages = lang.GetMessages("ru", this);
if (!Enum.TryParse(config.removeButton, true, out _removeButton) || !Enum.IsDefined(typeof(BUTTON), _removeButton))
{
PrintError($"{config.removeButton} неподходящая кнопка.Конфиг изменен на кнопку 'RELOAD'.");
_removeButton = BUTTON.RELOAD;
config.removeButton = _removeButton.ToString();
SaveConfig();
}
timer.Every(600, SaveData);
}
private object OnHammerHit(BasePlayer player, HitInfo info)
{
if (info == null || player == null) return null;
var entity = info?.HitEntity;
if (entity == null) return null;
if (entity.IsDestroyed) return false;
if (entity.OwnerID == 0) return null;
if (entity.ShortPrefabName.Contains("recycler")) return false;
if ((!(entity is DecayEntity) && !(entity is Signage)) && !entity.ShortPrefabName.Contains("shelves") && !entity.ShortPrefabName.Contains("ladder") && !entity.ShortPrefabName.Contains("quarry")) return null;
if (!entity.OwnerID.IsSteamId()) return null;
var privilege = player.GetBuildingPrivilege(player.WorldSpaceBounds());
if (player.serverInput.IsDown(_removeButton))
{
StorageContainer storage = entity as StorageContainer;
if (storage && config.checkRemoveItems)
{
if (storage.inventory.itemList.Count > 0)
{
SendReply(player, Messages["CheckItems"]);
return false;
}
}
var externalPlugins = Interface.CallHook("canRemove", player);
if (externalPlugins != null)
{
SendReply(player, Messages["RET"]);
return false;
}
if (config.useNoEscape)
{
if (plugins.Exists("NoEscape"))
{
var isRaid = (bool)NoEscape?.Call("IsRaidBlocked", player.userID);
if (isRaid)
{
SendReply(player, Messages["NoEscape"]);
return false;
}
}
}
if (config.blackList.Contains(entity.ShortPrefabName))
{
SendReply(player, Messages["EntityBlackListed"]);
return false;
}
if (config.cupboardRemove)
{
if (privilege != null && player.IsBuildingAuthed())
{
RemoveEntity(player, entity);
return true;
}
}
if (privilege != null && !player.IsBuildingAuthed())
{
if (config.selfRemove && entity.OwnerID == player.userID)
{
RemoveEntity(player, entity);
return true;
}
if (config.friendRemove)
{
if (config.removeFriends)
{
if (IsFriends(entity.OwnerID, player.userID))
{
RemoveEntity(player, entity);
return true;
}
}
}
if (config.clanRemove)
{
if (config.removeClans)
{
if (IsClanMember(entity.OwnerID, player.userID))
{
RemoveEntity(player, entity);
return true;
}
}
}
if (config.teamRemove)
{
if (config.removeTeam)
{
if (IsTeamate(BasePlayer.FindByID(entity.OwnerID), player.userID))
{
if (!config.selfRemove && entity.OwnerID == player.userID)
{
SendReply(player, Messages["ownerCup"]);
return false;
}
RemoveEntity(player, entity);
return true;
}
}
}
SendReply(player, Messages["ownerCup"]);
return false;
}
if (entity.OwnerID != player.userID)
{
if (config.removeFriends)
{
if (IsFriends(entity.OwnerID, player.userID))
{
RemoveEntity(player, entity);
return true;
}
}
if (config.removeClans)
{
if (IsClanMember(entity.OwnerID, player.userID))
{
RemoveEntity(player, entity);
return true;
}
}
if (config.removeTeam)
{
if (IsTeamate(BasePlayer.FindByID(entity.OwnerID), player.userID))
{
if (!config.selfRemove && entity.OwnerID == player.userID)
{
SendReply(player, Messages["ownerCup"]);
return false;
}
RemoveEntity(player, entity);
return true;
}
}
SendReply(player, Messages["norights"]);
return false;
}
RemoveEntity(player, entity);
return true;
}
else
{
if (privilege != null && player.IsBuildingAuthed())
{
RemovableObject removeInfo;
if (!RemovableInfos.TryGetValue(entity.net.ID, out removeInfo) || CurrentTime() < removeInfo.lastAttackedTime + 10) return null;
SendMarker(player, info.PointEnd, removeInfo.InteractStatus());
removeInfo.lastAttackedTime = (long) CurrentTime();
return null;
}
return null;
}
}
void RemoveEntity(BasePlayer player, BaseEntity entity)
{
if (!CheckRemoveInteractable(player, entity)) return;
Refund(player, entity);
NextFrame(() =>
{
entity.Kill();
});
}
bool CheckRemoveInteractable(BasePlayer player, BaseEntity entity)
{
RemovableObject removeInfo;
if (RemovableInfos.TryGetValue(entity.net.ID, out removeInfo))
{
var result = removeInfo.InteractStatus();
if (!removeInfo.isInteractable)
{
RaycastHit infohit;
Physics.Raycast(player.eyes.position, player.eyes.HeadForward(), out infohit);
if (CurrentTime() < removeInfo.lastAttackedTime + 3)
{
return false;
}
SendMarker(player, infohit.point, result);
return false;
}else return true;
}else return true;
}
void OnNewSave()
{
Puts("Обнаружен вайп.Очищаем сохраненные объекты");
RemovableInfos.Clear();
SaveData();
}
private void BlockObject(BuildingBlock obj)
{
if (!RemovableInfos.ContainsKey(obj.net.ID))
RemovableInfos.Add(obj.net.ID, RemovableObject.Generate(obj));
var info = RemovableInfos[obj.net.ID];
info.isInteractable = false;
}
private void OnEntitySpawned(BaseEntity entity)
{
var obj = entity as BuildingBlock;
if (obj == null) return;
if (!RemovableInfos.ContainsKey(obj.net.ID))
RemovableInfos.Add(obj.net.ID, RemovableObject.Generate(obj));
NextTick(() =>
{
obj.CancelInvoke(obj.StopBeingRotatable);
obj.CancelInvoke(obj.StopBeingDemolishable);
});
}
private object OnStructureDemolish(BuildingBlock block, BasePlayer player)
{
RemovableObject removeInfo;
if (RemovableInfos.TryGetValue(block.net.ID, out removeInfo))
{
var result = removeInfo.InteractStatus();
if (!removeInfo.isInteractable)
{
RaycastHit info;
Physics.Raycast(player.eyes.position, player.eyes.HeadForward(), out info);
if (CurrentTime() < removeInfo.lastAttackedTime + 3)
{
return false;
}
SendMarker(player, info.point, result);
return false;
}
}
return null;
}
private object OnStructureRotate(BuildingBlock block, BasePlayer player)
{
RemovableObject removeInfo;
if (RemovableInfos.TryGetValue(block.net.ID, out removeInfo))
{
RaycastHit info;
Physics.Raycast(player.eyes.position, player.eyes.HeadForward(), out info);
var result = removeInfo.InteractStatus();
if (!removeInfo.isInteractable)
{
if (CurrentTime() < removeInfo.lastAttackedTime + 3)
{
return false;
}
SendMarker(player, info.point, result);
return false;
}
}
return null;
}
void Refund(BasePlayer player, BaseEntity entity)
{
if (entity is BuildingBlock)
{
BuildingBlock buildingblock = entity as BuildingBlock;
if (buildingblock.blockDefinition == null) return;
int buildingblockGrade = (int)buildingblock.grade;
if (buildingblock.blockDefinition.grades[buildingblockGrade] != null)
{
float refundRate = buildingblock.healthFraction * config.refundPercent;
List<ItemAmount> currentCost = buildingblock.blockDefinition.grades[buildingblockGrade].costToBuild as List<ItemAmount>;
foreach (ItemAmount ia in currentCost)
{
int amount = (int)(ia.amount * refundRate);
if (amount <= 0 || amount > ia.amount || amount >= int.MaxValue) amount = 1;
if (refundRate != 0)
{
Item x = ItemManager.CreateByItemID(ia.itemid, amount);
player.GiveItem(x, BaseEntity.GiveItemReason.PickedUp);
}
}
}
return;
}
StorageContainer storage = entity as StorageContainer;
if (storage)
{
if (storage.inventory.itemList.Count > 0) for (int i = storage.inventory.itemList.Count - 1;
i >= 0;
i--)
{
var item = storage.inventory.itemList[i];
if (item == null) continue;
if (item.info.shortname == "water") continue;
item.amount = (int)(item.amount * config.refundStoragePercent);
float single = 20f;
Vector3 vector32 = Quaternion.Euler(UnityEngine.Random.Range(-single * 0.1f, single * 0.1f), UnityEngine.Random.Range(-single * 0.1f, single * 0.1f), UnityEngine.Random.Range(-single * 0.1f, single * 0.1f)) * Vector3.up;
BaseEntity baseEntity = item.Drop(storage.transform.position + (Vector3.up * 0f), vector32 * UnityEngine.Random.Range(5f, 10f), UnityEngine.Random.rotation);
baseEntity.SetAngularVelocity(UnityEngine.Random.rotation.eulerAngles * 5f);
}
}
if (deployedToItem.ContainsKey(entity.gameObject.name))
{
ItemDefinition def = ItemManager.FindItemDefinition(deployedToItem[entity.gameObject.name]);
foreach (var ingredient in def.Blueprint.ingredients)
{
var reply = 1;
if (reply == 0) { }
var amountOfIngridient = ingredient.amount;
var amount = Mathf.Floor(amountOfIngridient * config.refundItemsPercent);
if (amount <= 0 || amount > amountOfIngridient || amount >= int.MaxValue) amount = 1;
if (!config.refundItemsGive)
{
if (config.refundItemsPercent != 0)
{
Item x = ItemManager.Create(ingredient.itemDef, (int)amount);
player.GiveItem(x, BaseEntity.GiveItemReason.PickedUp);
}
}
else
{
GiveAndShowItem(player, deployedToItem[entity.PrefabName], 1, entity.skinID);
return;
}
}
}
}
void GiveAndShowItem(BasePlayer player, int item, int amount, ulong skin)
{
Item x = ItemManager.CreateByItemID(item, amount, skin);
player.GiveItem(x, BaseEntity.GiveItemReason.PickedUp);
}
private static void SendMarker(BasePlayer player, Vector3 position, string text)
{
player.SetPlayerFlag(BasePlayer.PlayerFlags.IsAdmin, true);
player.SendEntityUpdate();
player.SendConsoleCommand("ddraw.text", 2f, Color.white, position, text);
if (player.Connection.authLevel < 2)
{
player.SetPlayerFlag(BasePlayer.PlayerFlags.IsAdmin, false);
player.SendConsoleCommand("camspeed 0");
}
player.SendEntityUpdate();
}
bool IsClanMember(ulong playerID, ulong targetID)
{
if (plugins.Exists("Clans")) return (bool)(Clans?.Call("IsClanMember", playerID, targetID) ?? false);
return false;
}
bool IsFriends(ulong playerID, ulong friendId, ulong playerid = 1)
{
if (plugins.Exists("Friends")) return (bool)(Friends?.Call("AreFriends", playerID, friendId) ?? false);
return false;
}
bool IsTeamate(BasePlayer player, ulong targetID)
{
if (player.currentTeam < 2) return false;
var team = RelationshipManager.ServerInstance.FindTeam(player.currentTeam);
if (team == null) return false;
var list = RelationshipManager.ServerInstance.FindTeam(player.currentTeam).members.Where(p => p == targetID).ToList();
return list.Count > 0;
}
Dictionary<string, string> Messages = new Dictionary<string, string>() {
{
"NoEscape", "Удаление построек во время рейдблока запрещёно!"
}
, {
"ownerCup", "Что бы удалять постройки, вы должны быть авторизированы в шкафу"
}
, {
"norights", "Вы не имеете права удалять чужие постройки!"
}
, {
"RET", "Не удалось использовать удаление постройки: внешний фактор заблокировал его использование"
}
, {
"CheckItems", "Не удалось использовать удаление предмета: в его инвентаре есть предметы, очистите их"
}
, {
"EntityBlackListed", "Не удалось использовать удаление предмета: он находиться в черном списке."
}
,
};
}
}