C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
// #define TESTING
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Rust;
using UnityEngine;
using UnityEngine.Networking;
using Debug = UnityEngine.Debug;
using Global = Rust.Global;
using Time = UnityEngine.Time;
using Utility = Oxide.Core.Utility;
#if TESTING
using System.Diagnostics;
#endif
namespace Oxide.Plugins {
[Info("Build Tools", "Mevent", "1.5.27")]
public class BuildTools : RustPlugin {
#region Fields
[PluginReference]
private Plugin ImageLibrary = null, NoEscape = null, Clans = null, Friends = null, PersonalVaultDoor = null, Notify = null, UINotify = null;
private const string Layer = "UI.BuildTools";
private const string CrosshairLayer = "UI.BuildTools.Sight";
private static BuildTools _instance;
private enum Types {
None = 0, Remove = 5, Down = 6, Wood = 1, Stone = 2, Metal = 3, TopTier = 4
}
private const string PermFree = "buildtools.free";
private const string HammerShortname = "hammer";
private const string ToolGunShortname = "toolgun";
private const string BuldingPlannerShortname = "building.planner";
private Dictionary<string, string> _shortPrefabNamesToItem = new Dictionary<string, string>();
private bool _needImageLibrary;
private bool _enabledImageLibrary;
private Dictionary<int, Mode> _modeByType = new Dictionary<int, Mode>();
#endregion
#region Config
private static Configuration _config;
private class Configuration {
[JsonProperty(PropertyName = "Remove Commands")]
public string[] RemoveCommands = {
"remove"
}
;
[JsonProperty(PropertyName = "Upgrade Commands")]
public string[] UpgradeCommands = {
"up", "building.upgrade"
}
;
[JsonProperty(PropertyName = "Downgrade Commands")]
public string[] DowngradeCommands = {
"down", "down.grade"
}
;
[JsonProperty(PropertyName = "Work with Notify?")]
public bool UseNotify = true;
[JsonProperty(PropertyName = "Work with PersonalVaultDoor?")]
public bool UsePersonalVaultDoor = true;
[JsonProperty(PropertyName = "Use hammer hit actions on entity?")]
public bool UseHammer = true;
[JsonProperty(PropertyName = "Switching between modes with a middle click?")]
public bool SwitchModesMiddleClick = false;
[JsonProperty(PropertyName = "Setting Modes", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<Mode> Modes = new List<Mode> {
new Mode {
Type = Types.Remove, Icon = "assets/icons/clear.png", Permission = string.Empty, Additional = true, UseSkins = false, Skins = new List<SkinConf>(),
}
, new Mode {
Type = Types.Wood, Icon = "assets/icons/level_wood.png", Permission = string.Empty, Additional = false, UseSkins = false, Skins = new List<SkinConf>(),
}
, new Mode {
Type = Types.Stone, Icon = "assets/icons/level_stone.png", Permission = string.Empty, Additional = false, UseSkins = true, Skins = new List<SkinConf> {
new SkinConf {
Enabled = true, LangKey = "SkinAdobe", Permission = string.Empty, Skin = 10220
}
, new SkinConf {
Enabled = true, LangKey = "SkinBrick", Permission = string.Empty, Skin = 10223
}
, new SkinConf {
Enabled = true, LangKey = "SkinBrutalist", Permission = string.Empty, Skin = 10225
}
}
}
, new Mode {
Type = Types.Metal, Icon = "assets/icons/level_metal.png", Permission = string.Empty, Additional = false, UseSkins = true, Skins = new List<SkinConf> {
new SkinConf {
Enabled = true, LangKey = "SkinContainer", Permission = string.Empty, Skin = 10221
}
}
,
}
, new Mode {
Type = Types.TopTier, Icon = "assets/icons/level_top.png", Permission = string.Empty, Additional = false, UseSkins = false, Skins = new List<SkinConf>(),
}
, new Mode {
Type = Types.Down, Icon = "assets/icons/demolish.png", Permission = string.Empty, Additional = false, UseSkins = false, Skins = new List<SkinConf>(),
}
}
;
[JsonProperty(PropertyName = "Upgrade Settings")]
public UpgradeSettings Upgrade = new UpgradeSettings {
PermissionToAll = "buildtools.all", ActionTime = 30, Cooldown = 0, VipCooldown = new Dictionary<string, int> {
["buildtools.vip"]
= 0, ["buildtools.premium"] = 0
}
, AfterWipe = 0, VipAfterWipe = new Dictionary<string, int> {
["buildtools.vip"]
= 0, ["buildtools.premium"] = 0
}
, AmountPerTick = 5, NotifyRequiredResources = false, ShiftAttackToUpgradeAll = false, UpdateSkinsOnRightClick = true
}
;
[JsonProperty(PropertyName = "Remove Settings")]
public RemoveSettings Remove = new RemoveSettings {
PermissionToAll = "buildtools.all", ActionTime = 30, Cooldown = 0, VipCooldown = new Dictionary<string, int> {
["buildtools.vip"]
= 0, ["buildtools.premium"] = 0
}
, AfterWipe = 0, VipAfterWipe = new Dictionary<string, int> {
["buildtools.vip"]
= 0, ["buildtools.premium"] = 0
}
, Condition = new ConditionSettings {
Default = true, Percent = false, PercentValue = 0
}
, ReturnItem = true, ReturnPercent = 100, ReturnPercents = new Dictionary<string, float> {
["buildtools.vip"]
= 100, ["buildtools.premium"] = 100
}
, CanFriends = true, CanClan = true, CanTeams = true, RemoveByCupboard = false, RemoveItemsContainer = false, BlockedList = new Dictionary<string, List<IgnoredBlock>> {
["shortname 1"]
= new List<IgnoredBlock> {
new IgnoredBlock {
Skins = new List<string> {
"*"
}
, CanRemove = false, ReturnItem = false, ReturnPercent = 100
}
}
, ["shortname 2"] = new List<IgnoredBlock> {
new IgnoredBlock {
Skins = new List<string> {
"*"
}
, CanRemove = false, ReturnItem = false, ReturnPercent = 100
}
}
, ["shortname 3"] = new List<IgnoredBlock> {
new IgnoredBlock {
Skins = new List<string> {
"*"
}
, CanRemove = false, ReturnItem = false, ReturnPercent = 100
}
}
,
}
, BlockCooldown = new ActionCooldown {
Default = 36000, Permissions = new Dictionary<string, float> {
["buildtools.vip"]
= 34000, ["buildtools.premium"] = 32000
}
}
, AmountPerTick = 5, ShiftAttackToRemoveAll = false, Vision = new RemoveSettings.VisionRemoval {
Enabled = false, Permission = "buildtools.vision", Distance = 5f, Crosshair = new CrosshairSettings {
Enabled = false, Size = 30f, Thickness = 4f, Color = new IColor("#FFFFFF"), DisplayType = "Overlay"
}
}
}
;
[JsonProperty(PropertyName = "Downgrade Settings")]
public DowngradeSettings Downgrade = new DowngradeSettings {
PermissionToAll = "buildtools.all", ActionTime = 30, Cooldown = 0, VipCooldown = new Dictionary<string, int> {
["buildtools.vip"]
= 0, ["buildtools.premium"] = 0
}
, AfterWipe = 0, VipAfterWipe = new Dictionary<string, int> {
["buildtools.vip"]
= 0, ["buildtools.premium"] = 0
}
, CanFriends = true, CanClan = true, CanTeams = true, BlockedList = new Dictionary<string, List<string>> {
["shortname 1"]
= new List<string> {
"*"
}
, ["shortname 2"] = new List<string> {
"*"
}
, ["shortname 3"] = new List<string> {
"*"
}
}
, AmountPerTick = 5, ShiftAttackToDowngradeAll = false
}
;
[JsonProperty(PropertyName = "Block Settings")]
public BlockSettings Block = new BlockSettings {
UseNoEscape = true, UseClans = true, UseFriends = true, UseCupboard = true, NeedCupboard = false
}
;
[JsonProperty(PropertyName = "UI Settings")]
public InterfaceSettings UI = new InterfaceSettings {
DisplayType = "Overlay", Color1 = new IColor("#4B68FF"), Color2 = new IColor("#2C2C2C"), Color3 = new IColor("#B64040"), OffsetY = 0, OffsetX = 0, ProgressTitleTextSize = 12, ProgressTitleTextColor = new IColor("#FFFFFF", 60), SettingsBackgroundColor = new IColor("#0E0E10"), SettingsHeaderColor = new IColor("#161617"), SettingsImageBackgroundColor = new IColor("#161617"), SettingsSelectedColor = new IColor("#4B68FF"), SettingsNotSelectedColor = new IColor("#242425"), SettingsTextColor = new IColor("#FFFFFF"), Skins = new InterfaceSettings.SkinsUI {
TabUpIndent = 15, TabHeight = 20, TabWidth = 80, TabMargin = 5, ImageLeftIndent = -22.5f, ImageUpIndent = 60, ImageHeight = 190, ImageWidth = 190, ModeUpIndent = 60, ModeHeight = 40, ModeWidth = 130, ModeMargin = 15
}
}
;
[JsonProperty(PropertyName = "Active Item Settings")]
public ActiveItemConf ActiveItem = new ActiveItemConf {
Enabled = false, Items = new Dictionary<string, ActiveItemConf.ActiveItem> {
[HammerShortname]
= new ActiveItemConf.ActiveItem {
Enabled = true, DefaultMode = Types.Remove, IgnoredSkins = new List<ulong> {
1196009619u
}
, SaveSelectedMode = false
}
, [ToolGunShortname] = new ActiveItemConf.ActiveItem {
Enabled = true, DefaultMode = Types.Remove, IgnoredSkins = new List<ulong>(), SaveSelectedMode = false
}
, ["building.planner"] = new ActiveItemConf.ActiveItem {
Enabled = true, DefaultMode = Types.Stone, IgnoredSkins = new List<ulong> {
1195976254u
}
, SaveSelectedMode = false
}
}
}
;
public VersionNumber Version;
}
private class CrosshairSettings {
[JsonProperty(PropertyName = "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = "Size")]
public float Size;
[JsonProperty(PropertyName = "Thickness")]
public float Thickness;
[JsonProperty(PropertyName = "Color")]
public IColor Color;
[JsonProperty(PropertyName = "Display type (Overlay/Hud)")]
public string DisplayType;
}
private class ActiveItemConf {
[JsonProperty(PropertyName = "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = "Items", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, ActiveItem> Items;
public class ActiveItem {
[JsonProperty(PropertyName = "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = "Default Mode")]
[JsonConverter(typeof(StringEnumConverter))]
public Types DefaultMode;
[JsonProperty(PropertyName = "Ignored Skins", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<ulong> IgnoredSkins = new List<ulong>();
[JsonProperty(PropertyName = "Save the selected mode when closing?")]
public bool SaveSelectedMode;
[JsonIgnore]
private Mode _mode;
public Mode GetMode(BasePlayer player, string item) {
#if TESTING
Debug.Log($"[ActiveItem.GetMode] player={player.UserIDString}, item={item}");
#endif
if (SaveSelectedMode) {
var selectedMode = PlayerData.GetOrLoad(player.UserIDString)?.GetSelectedMode(item);
if (selectedMode != null) {
#if TESTING
Debug.Log($"[ActiveItem.GetMode] SaveSelectedMode.return: {selectedMode.Type}");
#endif
return selectedMode;
}
}
#if TESTING
Debug.Log($"[ActiveItem.GetMode] return default");
#endif
return _mode;
}
public void SetMode(Mode mode) {
_mode = mode;
}
}
public void Init() {
foreach (var item in Items.Values) item.SetMode(_instance.GetModeByType(item.DefaultMode));
}
}
private class ActionCooldown {
[JsonProperty(PropertyName = "Default")]
public float Default;
[JsonProperty(PropertyName = "Permissions", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, float> Permissions;
public float GetCooldown(BasePlayer player) {
var result = Default;
foreach (var check in Permissions.Where(check => player.IPlayer.HasPermission(check.Key) && result < check.Value)) result = check.Value;
return result;
}
}
private class InterfaceSettings {
[JsonProperty(PropertyName = "Display type (Overlay/Hud)")]
public string DisplayType;
[JsonProperty(PropertyName = "Color 1")]
public IColor Color1;
[JsonProperty(PropertyName = "Color 2")]
public IColor Color2;
[JsonProperty(PropertyName = "Color 3")]
public IColor Color3;
[JsonProperty(PropertyName = "Offset Y")]
public float OffsetY;
[JsonProperty(PropertyName = "Offset X")]
public float OffsetX;
[JsonProperty(PropertyName = "Progress Title Text Size")]
public int ProgressTitleTextSize;
[JsonProperty(PropertyName = "Progress Title Text Color")]
public IColor ProgressTitleTextColor;
[JsonProperty(PropertyName = "Settings Background Color")]
public IColor SettingsBackgroundColor;
[JsonProperty(PropertyName = "Settings Header Color")]
public IColor SettingsHeaderColor;
[JsonProperty(PropertyName = "Settings Image Background Color")]
public IColor SettingsImageBackgroundColor;
[JsonProperty(PropertyName = "Settings Selected Color")]
public IColor SettingsSelectedColor;
[JsonProperty(PropertyName = "Settings Not Selected Color")]
public IColor SettingsNotSelectedColor;
[JsonProperty(PropertyName = "Settings Text Color")]
public IColor SettingsTextColor;
[JsonProperty(PropertyName = "Skins")]
public SkinsUI Skins;
public class SkinsUI {
[JsonProperty(PropertyName = "Tab Up Indent")]
public float TabUpIndent;
[JsonProperty(PropertyName = "Tab Height")]
public float TabHeight;
[JsonProperty(PropertyName = "Tab Width")]
public float TabWidth;
[JsonProperty(PropertyName = "Tab Margin")]
public float TabMargin;
[JsonProperty(PropertyName = "Image Left Indent")]
public float ImageLeftIndent;
[JsonProperty(PropertyName = "Image Up Indent")]
public float ImageUpIndent;
[JsonProperty(PropertyName = "Image Height")]
public float ImageHeight;
[JsonProperty(PropertyName = "Image Width")]
public float ImageWidth;
[JsonProperty(PropertyName = "Mode Up Indent")]
public float ModeUpIndent;
[JsonProperty(PropertyName = "Mode Height")]
public float ModeHeight;
[JsonProperty(PropertyName = "Mode Width")]
public float ModeWidth;
[JsonProperty(PropertyName = "Mode Margin")]
public float ModeMargin;
}
}
private class IColor {
[JsonProperty(PropertyName = "HEX")]
public string Hex;
[JsonProperty(PropertyName = "Opacity (0 - 100)")]
public float Alpha;
[JsonIgnore]
private string _color;
[JsonIgnore]
public string Get {
get {
if (string.IsNullOrEmpty(_color)) _color = GetColor();
return _color;
}
}
private string GetColor() {
if (string.IsNullOrEmpty(Hex)) Hex = "#FFFFFF";
var str = Hex.Trim('#');
if (str.Length != 6) throw new Exception(Hex);
var r = byte.Parse(str.Substring(0, 2), NumberStyles.HexNumber);
var g = byte.Parse(str.Substring(2, 2), NumberStyles.HexNumber);
var b = byte.Parse(str.Substring(4, 2), NumberStyles.HexNumber);
return $"{(double) r / 255} {(double) g / 255} {(double) b / 255} {Alpha / 100}";
}
public IColor() {
}
public IColor(string hex, float alpha = 100) {
Hex = hex;
Alpha = alpha;
}
}
private class ConditionSettings {
[JsonProperty(PropertyName = "Default (from game)")]
public bool Default;
[JsonProperty(PropertyName = "Use percent?")]
public bool Percent;
[JsonProperty(PropertyName = "Percent (value)")]
public float PercentValue;
}
private class BlockSettings {
[JsonProperty(PropertyName = "Work with NoEscape?")]
public bool UseNoEscape;
[JsonProperty(PropertyName = "Work with Clans? (clan members will be able to delete/upgrade)")]
public bool UseClans;
[JsonProperty(PropertyName = "Work with Friends? (friends will be able to delete/upgrade)")]
public bool UseFriends;
[JsonProperty(PropertyName = "Can those authorized in the cupboard delete/upgrade?")]
public bool UseCupboard;
[JsonProperty(PropertyName = "Is an upgrade/remove cupboard required?")]
public bool NeedCupboard;
}
private abstract class TotalSettings {
[JsonProperty(PropertyName = "Permission to modify all entities (/command all) ")]
public string PermissionToAll;
[JsonProperty(PropertyName = "Time of action")]
public int ActionTime;
[JsonProperty(PropertyName = "Cooldown (default | 0 - disable)")]
public int Cooldown;
[JsonProperty(PropertyName = "Cooldowns", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, int> VipCooldown;
[JsonProperty(PropertyName = "Block After Wipe (default | 0 - disable)")]
public int AfterWipe;
[JsonProperty(PropertyName = "Block After Wipe", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, int> VipAfterWipe;
public int GetCooldown(BasePlayer player) {
return (from check in VipCooldown where player.IPlayer.HasPermission(check.Key) select check.Value).Prepend(Cooldown).Min();
}
public int GetWipeCooldown(BasePlayer player) {
return (from check in VipAfterWipe where player.IPlayer.HasPermission(check.Key) select check.Value).Prepend(AfterWipe).Min();
}
public bool HasAllPermission(BasePlayer player) {
return string.IsNullOrWhiteSpace(PermissionToAll) || _instance.permission.UserHasPermission(player.UserIDString, PermissionToAll);
}
}
private class UpgradeSettings : TotalSettings {
[JsonProperty(PropertyName = "Amount of upgrade entities per tick")]
public int AmountPerTick;
[JsonProperty(PropertyName = "Notify the player of the required resources for upgrading a building when they do not have enough resources")]
public bool NotifyRequiredResources;
[JsonProperty(PropertyName = "Press Shift + Attack to Upgrade All")]
public bool ShiftAttackToUpgradeAll;
[JsonProperty(PropertyName = "Updating building skins on right-click upgrade?")]
public bool UpdateSkinsOnRightClick;
[JsonProperty(PropertyName = "Skins Settings")]
public SkinsInfo Skins = new SkinsInfo {
Enabled = true, Icon = "assets/icons/gear.png", Images = new Dictionary<ulong, string> {
[10220]
= "https://i.ibb.co/GRjNqrq/ty1gZVS.png", [10221] = "https://i.ibb.co/N1ZtZ1h/CSTnZ9V.png", [10223] = "https://i.ibb.co/6yv2gCp/SGB52rr.png", [10225] = "https://i.ibb.co/HgjXDCp/512fx512fdpx2x.png",
}
}
;
}
private class SkinsInfo {
[JsonProperty(PropertyName = "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = "Icon (assets/url)")]
public string Icon;
[JsonProperty(PropertyName = "Image for skins", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<ulong, string> Images = new Dictionary<ulong, string>();
}
private class SkinConf {
[JsonProperty(PropertyName = "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = "Lang Key")]
public string LangKey;
[JsonProperty(PropertyName = "Permission")]
public string Permission;
[JsonProperty(PropertyName = "Skin")]
public ulong Skin;
}
private class RemoveSettings : TotalSettings {
[JsonProperty(PropertyName = "Blocked items to remove (prefab – settings)", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, List<IgnoredBlock>> BlockedList;
[JsonProperty(PropertyName = "Return Item")]
public bool ReturnItem;
[JsonProperty(PropertyName = "Returnable Item Percentage")]
public float ReturnPercent;
[JsonProperty(PropertyName = "Percentages of returnable items (permission – percent)", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, float> ReturnPercents = new Dictionary<string, float>();
[JsonProperty(PropertyName = "Can friends remove? (Friends)")]
public bool CanFriends;
[JsonProperty(PropertyName = "Can clanmates remove? (Clans)")]
public bool CanClan;
[JsonProperty(PropertyName = "Can teammates remove?")]
public bool CanTeams;
[JsonProperty(PropertyName = "Remove by cupboard? (those who are authorized in the cupboard can remove)")]
public bool RemoveByCupboard;
[JsonProperty(PropertyName = "Remove container with items?")]
public bool RemoveItemsContainer;
[JsonProperty(PropertyName = "Condition Settings")]
public ConditionSettings Condition;
[JsonProperty(PropertyName = "Block Cooldown After Spawn Settings")]
public ActionCooldown BlockCooldown;
[JsonProperty(PropertyName = "Amount of remove entities per tick")]
public int AmountPerTick;
[JsonProperty(PropertyName = "Press Shift + Attack to Remove All")]
public bool ShiftAttackToRemoveAll;
[JsonProperty(PropertyName = "Vision Removal")]
public VisionRemoval Vision;
public class VisionRemoval {
[JsonProperty(PropertyName = "Enabled")]
public bool Enabled;
[JsonProperty(PropertyName = "Permission")]
public string Permission;
[JsonProperty(PropertyName = "Distance")]
public float Distance;
[JsonProperty(PropertyName = "Crosshair")]
public CrosshairSettings Crosshair;
}
public float GetReturnPercent(BasePlayer player) {
var result = ReturnPercent;
foreach (var returnPercent in ReturnPercents) if (_instance?.permission?.UserHasPermission(returnPercent.Key, player.UserIDString) == true && returnPercent.Value > result) result = returnPercent.Value;
return result;
}
[JsonIgnore]
private Dictionary<string, Dictionary<string, IgnoredBlock>> _ignoredBlocks;
public void Init() {
_ignoredBlocks = new Dictionary<string, Dictionary<string, IgnoredBlock>>();
foreach (var block in BlockedList) {
_ignoredBlocks[block.Key] = new Dictionary<string, IgnoredBlock>();
foreach (var ignoredBlock in block.Value) {
foreach (var ignoredSkin in ignoredBlock.Skins) {
IgnoredBlock check;
if (!_ignoredBlocks[block.Key].TryGetValue(ignoredSkin, out check)) {
_ignoredBlocks[block.Key].Add(ignoredSkin, ignoredBlock);
}
}
}
}
}
public IgnoredBlock GetIgnoredBlock(BaseEntity entity) {
Dictionary<string, IgnoredBlock> dictionary;
if (!_ignoredBlocks.TryGetValue(entity.name, out dictionary)) return null;
IgnoredBlock block;
return dictionary.TryGetValue(entity.skinID.ToString(), out block) ? block : dictionary.TryGetValue("*", out block) ? block : null;
}
}
private class DowngradeSettings : TotalSettings {
[JsonProperty(PropertyName = "Blocked items to downgrade (prefab – skins, but '*' - all skins)", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, List<string>> BlockedList;
[JsonProperty(PropertyName = "Can friends downgrade? (Friends)")]
public bool CanFriends;
[JsonProperty(PropertyName = "Can clanmates downgrade? (Clans)")]
public bool CanClan;
[JsonProperty(PropertyName = "Can teammates downgrade?")]
public bool CanTeams;
[JsonProperty(PropertyName = "Amount of downgrade entities per tick")]
public int AmountPerTick;
[JsonProperty(PropertyName = "Press Shift + Attack to Downgrade All")]
public bool ShiftAttackToDowngradeAll;
public bool IsIgnored(BaseEntity entity) {
List<string> list;
if (!BlockedList.TryGetValue(entity.name, out list)) return false;
return list.Contains("*") || list.Contains(entity.skinID.ToString());
}
}
private class IgnoredBlock {
[JsonProperty(PropertyName = "Skins (* – all)")]
public List<string> Skins;
[JsonProperty(PropertyName = "Can remove?")]
public bool CanRemove;
[JsonProperty(PropertyName = "Return Item")]
public bool ReturnItem;
[JsonProperty(PropertyName = "Returnable Item Percentage")]
public float ReturnPercent;
}
private class Mode {
[JsonProperty(PropertyName = "Icon (assets/url)")]
public string Icon;
[JsonProperty(PropertyName = "Type (Remove/Wood/Stone/Metal/TopTier)")]
[JsonConverter(typeof(StringEnumConverter))]
public Types Type;
[JsonProperty(PropertyName = "Permission (ex: buildtools.1)")]
public string Permission;
[JsonProperty(PropertyName = "Default value for additional slot")]
public bool Additional;
[JsonProperty(PropertyName = "Enable skins?")]
public bool UseSkins;
[JsonProperty(PropertyName = "Skins", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<SkinConf> Skins = new List<SkinConf>();
public List<SkinConf> GetSkins(BasePlayer player) {
return Skins.FindAll(x => x.Enabled && (string.IsNullOrEmpty(x.Permission) || _instance.permission.UserHasPermission(player.UserIDString, x.Permission)));
}
}
protected override void LoadConfig() {
base.LoadConfig();
try {
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
if (_config.Version < Version) UpdateConfigValues();
SaveConfig();
}
catch (Exception ex) {
PrintError("Your configuration file contains an error.Using default configuration values.");
LoadDefaultConfig();
Debug.LogException(ex);
}
}
protected override void SaveConfig() {
Config.WriteObject(_config);
}
protected override void LoadDefaultConfig() {
_config = new Configuration();
}
private void UpdateConfigValues() {
PrintWarning("Config update detected! Updating config values...");
if (_config.Version != default(VersionNumber)) {
if (_config.Version < new VersionNumber(1, 3, 0)) ConvertOldData();
if (_config.Version < new VersionNumber(1, 5, 10)) {
_config.Remove.ReturnPercents = new Dictionary<string, float> {
["buildtools.vip"]
= 100, ["buildtools.premium"] = 100
}
;
}
if (_config.Version < new VersionNumber(1, 5, 14)) {
foreach (var mode in _config.Modes) {
if (mode.Type == Types.Stone && mode.Skins.All(x => x.LangKey != "SkinBrick")) {
mode.Skins.Add(new SkinConf {
Enabled = true, LangKey = "SkinBrick", Permission = string.Empty, Skin = 10223
}
);
}
}
if (_config.Upgrade.Skins.Images.ContainsKey(10223) == false) _config.Upgrade.Skins.Images.TryAdd(10223, "https://i.ibb.co/6yv2gCp/SGB52rr.png");
}
if (_config.Version < new VersionNumber(1, 5, 17)) {
foreach (var activeItem in _config.ActiveItem.Items) {
switch (activeItem.Key) {
case HammerShortname : {
activeItem.Value.IgnoredSkins = new List<ulong> {
1196009619u
}
;
break;
}
case "building.planner" : {
activeItem.Value.IgnoredSkins = new List<ulong> {
1195976254u
}
;
break;
}
default : {
activeItem.Value.IgnoredSkins = new List<ulong>();
break;
}
}
}
}
if (_config.Version == new VersionNumber(1, 5, 18)) {
foreach (var activeItem in _config.ActiveItem.Items.Values) if (activeItem.IgnoredSkins == null) activeItem.IgnoredSkins = new List<ulong>();
}
if (_config.Version < new VersionNumber(1, 5, 20)) {
var oldValue = Config["Block Settings", "Is an upgrade/remove cupbaord required?"];
if (oldValue != null) {
_config.Block.NeedCupboard = Convert.ToBoolean(oldValue);
}
}
if (_config.Version < new VersionNumber(1, 5, 21)) {
_config.Remove.BlockedList = new Dictionary<string, List<IgnoredBlock>>();
var confObj = Config["Remove Settings", "Blocked items to remove (prefab)"];
if (confObj != null) {
var list = (IList) confObj;
foreach (var block in list.Cast<string>().ToList()) {
_config.Remove.BlockedList.TryAdd(block, new List<IgnoredBlock> {
new IgnoredBlock {
Skins = new List<string> {
"*"
}
, CanRemove = false, ReturnItem = false, ReturnPercent = 100
}
}
);
}
}
}
if (_config.Version < new VersionNumber(1, 5, 12)) {
foreach (var mode in _config.Modes) {
if (mode.Type == Types.Stone && mode.Skins.All(x => x.LangKey != "SkinBrutalist")) {
mode.Skins.Add(new SkinConf {
Enabled = true, LangKey = "SkinBrutalist", Permission = string.Empty, Skin = 10225
}
);
}
}
if (_config.Upgrade.Skins.Images.ContainsKey(10225) == false) _config.Upgrade.Skins.Images.TryAdd(10225, "https://i.ibb.co/HgjXDCp/512fx512fdpx2x.png");
foreach (var check in _config.Upgrade.Skins.Images.ToArray()) {
string newValue;
switch (check.Value) {
case "https://i.imgur.com/ty1gZVS.png" : newValue = "https://i.ibb.co/GRjNqrq/ty1gZVS.png";
break;
case "https://i.imgur.com/CSTnZ9V.png" : newValue = "https://i.ibb.co/N1ZtZ1h/CSTnZ9V.png";
break;
case "https://i.imgur.com/SGB52rr.png" : newValue = "https://i.ibb.co/6yv2gCp/SGB52rr.png";
break;
default : continue;
}
if (!string.IsNullOrWhiteSpace(newValue)) _config.Upgrade.Skins.Images[check.Key] = newValue;
}
}
}
_config.Version = Version;
PrintWarning("Config update completed!");
}
#endregion
#region Data
private EntitiesData _entitiesData;
private void SaveEntities() {
Interface.Oxide.DataFileSystem.WriteObject(Name + "_Entities", _entitiesData);
}
private void LoadEntities() {
try {
_entitiesData = Interface.Oxide.DataFileSystem.ReadObject<EntitiesData>(Name + "_Entities");
}
catch (Exception e) {
PrintError(e.ToString());
}
if (_entitiesData == null) _entitiesData = new EntitiesData();
}
private class EntitiesData {
[JsonProperty(PropertyName = "Entities", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<ulong, DateTime> Entities = new Dictionary<ulong, DateTime>();
}
#endregion
#region Hooks
private void Init() {
_instance = this;
LoadEntities();
RegisterPermissions();
RegisterCommands();
_config.Remove.Init();
UnsubscribeEntities();
#if TESTING
StopwatchWrapper.OnComplete = DebugMessage;
#endif
}
private void OnServerInitialized() {
LoadImages();
TryToLoadPersonalVaultDoor();
LoadItemPrefabs();
ClearData();
LoadCacheModes();
if (_config.ActiveItem.Enabled) _config.ActiveItem.Init();
}
private void Unload() {
if (_parsingSkins != null) ServerMgr.Instance.StopCoroutine(_parsingSkins);
foreach (var player in BasePlayer.activePlayerList) {
CuiHelper.DestroyUi(player, Layer);
CuiHelper.DestroyUi(player, Layer + ".Settings");
CuiHelper.DestroyUi(player, CrosshairLayer);
PlayerData.SaveAndUnload(player.UserIDString);
}
Array.ForEach(_components.Values.ToArray(), build => {
if (build != null) build.Kill();
}
);
SaveEntities();
_config = null;
_instance = null;
}
private void OnPlayerDisconnected(BasePlayer player) {
PlayerData.SaveAndUnload(player.UserIDString);
}
private void OnPlayerInput(BasePlayer player, InputState input) {
if (player == null || input == null) return;
if (_config.Remove.Vision?.Enabled == true && input.WasJustPressed(BUTTON.FIRE_PRIMARY)) {
var build = GetBuild(player.userID);
if (build == null) return;
var mode = build.GetMode();
if (mode == null || mode.Type != Types.Remove || ActiveItemIsBuildingPlan(player)) return;
if (!string.IsNullOrWhiteSpace(_config.Remove.Vision.Permission) && !permission.UserHasPermission(player.UserIDString, _config.Remove.Vision.Permission)) return;
var entity = GetLookEntity(player);
if (entity == null) {
SendNotify(player, NotFoundEntity, 1);
return;
}
var cupboard = player.GetBuildingPrivilege();
if (cupboard == null) {
SendNotify(player, NoCupboard, 1);
return;
}
if (!CanRemoveEntity(player, entity)) return;
var ignoredBlock = _config.Remove.GetIgnoredBlock(entity);
if (ignoredBlock != null) {
if (ignoredBlock.CanRemove == false) {
_instance.SendNotify(player, CantRemove, 1);
return;
}
}
var data = PlayerData.GetOrCreate(player.UserIDString);
var cooldown = _config.Remove.GetCooldown(player);
if (cooldown > 0 && data.HasCooldown(Types.Remove, cooldown)) {
SendNotify(player, RemoveCanThrough, 1, data.LeftTime(Types.Remove, cooldown));
return;
}
var blockWipe = _config.Remove.GetWipeCooldown(player);
if (blockWipe > 0 && PlayerData.HasWipeCooldown(blockWipe)) {
SendNotify(player, RemoveCanThrough, 1, PlayerData.WipeLeftTime(blockWipe));
return;
}
entity.Invoke(() => RemoveEntity(player, entity, ignoredBlock), 0.11f);
data.LastRemove = DateTime.UtcNow;
return;
}
if (_config.SwitchModesMiddleClick && input.WasJustPressed(BUTTON.FIRE_THIRD)) GetBuild(player.userID)?.GoNext();
}
private object OnHammerHit(BasePlayer player, HitInfo info) {
if (player == null || info == null) return null;
var build = GetBuild(player.userID);
if (build == null) return null;
var mode = build.GetMode();
if (mode == null || !ActiveItemIsHammerOrGunTools(player)) return null;
var entity = info.HitEntity as BaseCombatEntity;
if (entity == null || entity.OwnerID == 0) return null;
if (!player.CanBuild()) {
SendNotify(player, BuildingBlocked, 1);
return true;
}
if (_config.Block.UseNoEscape && NoEscape != null && NoEscape.IsLoaded && IsRaidBlocked(player)) {
SendNotify(player, mode.Type == Types.Remove ? RemoveRaidBlocked : UpgradeRaidBlocked, 1);
return true;
}
var cupboard = entity.GetBuildingPrivilege();
if (_config.Block.NeedCupboard && cupboard == null) {
SendNotify(player, CupboardRequired, 1);
return true;
}
if (entity.OwnerID != player.userID) //NOT OWNER
{
var any = (_config.Block.UseFriends && IsFriends(player.OwnerID, entity.OwnerID)) || (_config.Block.UseClans && IsClanMember(player.OwnerID, entity.OwnerID)) || (_config.Block.UseCupboard && (cupboard == null || cupboard.IsAuthed(player)));
if (!any) {
SendNotify(player, mode.Type == Types.Remove ? CantRemove : mode.Type == Types.Down ? CantDowngrade : CantUpgrade, 1);
return true;
}
}
switch (mode.Type) {
case Types.Remove : {
var cd = _config.Remove.BlockCooldown.GetCooldown(player);
if (cd > 0) {
DateTime created;
if (_entitiesData.Entities.TryGetValue(entity.net.ID.Value, out created)) {
var leftTime = DateTime.Now.Subtract(created).TotalSeconds;
if (leftTime > cd) {
SendNotify(player, RemoveTimeLeft, 1, FormatTime(player, cd));
return true;
}
}
}
#if TESTING
SayDebug($"[OnHammerHit.{player.UserIDString}] start check shift attack for remove");
#endif
if (_config.Remove.ShiftAttackToRemoveAll && player.serverInput.WasDown(BUTTON.SPRINT)) {
RemoveAll(player);
return true;
}
break;
}
case Types.Down : {
var block = entity as BuildingBlock;
if (block == null || (int) block.grade < 2) {
SendNotify(player, CantDowngrade, 1);
return true;
}
var grade = GetTypes(block.grade - 1);
if (grade == Types.None) {
SendNotify(player, CantDowngrade, 1);
return true;
}
if (_config.Downgrade.ShiftAttackToDowngradeAll && player.serverInput.WasDown(BUTTON.SPRINT)) {
DowngradeAll(player, grade);
return true;
}
break;
}
default : {
var block = entity as BuildingBlock;
if (block == null) {
SendNotify(player, CantDowngrade, 1);
return true;
}
if ((int) block.grade == (int) mode.Type) {
var skin = PlayerData.GetOrLoad(player.UserIDString)?.GetSkin((int) GetEnum(mode.Type)) ?? 0UL;
if (block.skinID == skin) return null;
}
if ((int) block.grade > (int) mode.Type) {
SendNotify(player, CantDowngrade, 1);
return true;
}
if (_config.Upgrade.ShiftAttackToUpgradeAll && player.serverInput.WasDown(BUTTON.SPRINT)) {
UpgradeAll(player, mode.Type);
return true;
}
break;
}
}
build.DoIt(entity);
#if TESTING
SayDebug($"[{nameof(OnHammerHit)} do it ended!");
#endif
return true;
}
private void OnEntityBuilt(Planner plan, GameObject go) {
var player = plan.GetOwnerPlayer();
if (player == null) return;
var block = go.ToBaseEntity() as BuildingBlock;
if (block == null) return;
_entitiesData.Entities[block.net.ID.Value] = DateTime.Now;
var build = GetBuild(player.user
// ... [Code preview truncated due to length. Full source in attached file] ...