C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
//#define CHECK
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;
using System.Linq;
using Oxide.Core.Plugins;
using Newtonsoft.Json;
using System.Collections;
using Oxide.Core;
using System.IO;
namespace Oxide.Plugins
{
[Info("ItemsBlocker", "Vlad-00003", "3.1.2", ResourceId = 2407)]
[Description("Prevents some items from being used for a limited period of time.")]
class ItemsBlocker : RustPlugin
{
#region Vars
//private string Image = null;
private Dictionary<string, string> Image = new Dictionary<string, string>();
private PluginConfig config;
[PluginReference]
Plugin Duel;
private Dictionary<BasePlayer, Timer> Main = new Dictionary<BasePlayer, Timer>();
private List<BasePlayer> OnScreen = new List<BasePlayer>();
private Timer OnScreenUpdater;
#endregion
#region Config setup
#region GUI Settings
private class GUIPanel
{
[JsonProperty("Minimum anchor")]
public string Amin;
[JsonProperty("Maximum anchor")]
public string Amax;
[JsonProperty("Color")]
public string Color;
}
private class GUIText : GUIPanel
{
[JsonProperty("Size")]
public int Size;
[JsonProperty("Outline")]
public GUIOutline Outline;
}
private class GUIImage
{
[JsonProperty("Minimum anchor")]
public string Amin;
[JsonProperty("Maximum anchor")]
public string Amax;
[JsonProperty("Link to the image or file in the data folder")]
public string Image;
[JsonProperty("Opacity of the image")]
public float Opacity;
}
private class GUIOutline
{
[JsonProperty("Use Outline")]
public bool Use = true;
[JsonProperty("Outline color")]
public string Color = "0 0 0 1";
[JsonProperty("Outline distance")]
public string Distance = "1.0 -1.0";
}
#endregion
private class GUISettings
{
[JsonProperty("Backgound for main panel")]
public GUIPanel Background = new GUIPanel()
{
Amin = null,
Amax = null,
Color = "0 0 0 0.8"
};
[JsonProperty("Main panel settings (shows if player attemts to use blocked cloth/item)")]
public GUIPanel MainPanel = new GUIPanel()
{
Amin = "0.266 0.361",
Amax = "0.734 0.639",
Color = "#42e2f49f"
};
[JsonProperty("Settings for the text on main panel")]
public GUIText TextOnMain = new GUIText()
{
Amin = "0 0",
Amax = "1 1",
Color = "#f4d041",
Size = 20,
Outline = new GUIOutline()
};
[JsonProperty("Use On Screen Panel")]
public bool UseOnScreenPanel = true;
[JsonProperty("On Screen Panel (shown if the block is active)")]
public GUIPanel OnScreenPanel = new GUIPanel()
{
Amin = "0.016 0.028",
Amax = "0.172 0.167",
Color = "0 0 0 0.7"
};
[JsonProperty("Text settings for On Screen Panel")]
public GUIText TextOnScreen = new GUIText()
{
Amin = "0 0",
Amax = "0.66 1",
Color = "green",
Size = 13,
Outline = new GUIOutline()
};
[JsonProperty("Image (shown on On Screen Panel")]
public GUIImage Image = new GUIImage()
{
Amin = "0.67 0.25",
Amax = "0.92 0.75",
Opacity = 0.8f,
Image = "http://www.rigormortis.be/wp-content/uploads/rust-icon-512.png"
};
}
private class PluginConfig
{
[JsonProperty("Block end time")]
public string BlockEndStr;
[JsonProperty("Hour of block after wipe")]
public int HoursOfBlock = 30;
[JsonProperty("Chat prefix")]
public string Prefix = "[Items Blocker]";
[JsonProperty("Chat prefix color")]
public string PrefixColor = "#f44253";
[JsonProperty("Use chat insted of GUI")]
public bool UseChat = false;
[JsonProperty("Bypass permission")]
public string BypassPermission = "itemsblocker.bypass";
[JsonProperty("GUI Settings")]
public GUISettings Gui = new GUISettings();
[JsonProperty("List of blocked items")]
public List<string> BlockedItems;
[JsonProperty("List of blocked clothes")]
public List<string> BlockedClothes;
[JsonProperty("List of blocked ammunition")]
public List<string> BlockedAmmo;
[JsonIgnore]
public DateTime BlockEnd;
public static PluginConfig DefaultConfig()
{
return new PluginConfig()
{
BlockEndStr = DateTime.Now.AddHours(30).ToString("dd.MM.yyyy HH:mm:ss"),
BlockedItems = new List<string>()
{
"Satchel Charge",
"Timed Explosive Charge",
"Eoka Pistol",
"Custom SMG",
"Assault Rifle",
"Bolt Action Rifle",
"Waterpipe Shotgun",
"Revolver",
"Thompson",
"Semi-Automatic Rifle",
"Semi-Automatic Pistol",
"Pump Shotgun",
"M249",
"Rocket Launcher",
"Flame Thrower",
"Double Barrel Shotgun",
"Beancan Grenade",
"F1 Grenade",
"MP5A4",
"LR-300 Assault Rifle",
"M92 Pistol",
"Python Revolver"
},
BlockedClothes = new List<string>()
{
"Metal Facemask",
"Metal Chest Plate",
"Road Sign Kilt",
"Road Sign Jacket",
"Heavy Plate Pants",
"Heavy Plate Jacket",
"Heavy Plate Helmet",
"Riot Helmet",
"Bucket Helmet",
"Coffee Can Helmet"
},
BlockedAmmo = new List<string>()
{
"HV Pistol Ammo",
"Incendiary Pistol Bullet",
"HV 5.56 Rifle Ammo",
"Incendiary 5.56 Rifle Ammo",
"Explosive 5.56 Rifle Ammo",
"12 Gauge Slug",
"High Velocity Arrow",
"Incendiary Rocket",
"Rocket",
"High Velocity Rocket"
}
};
}
}
#endregion
#region Config and Data Initialization
protected override void LoadDefaultConfig()
{
PrintWarning("New configuration file created, Block Start now and will remain for 30 hours.You can change it into the config.");
config = PluginConfig.DefaultConfig();
}
protected override void LoadConfig()
{
base.LoadConfig();
config = Config.ReadObject<PluginConfig>();
DateTime BlockEnd;
if (!DateTime.TryParseExact(config.BlockEndStr, "dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out BlockEnd))
{
BlockEnd = SaveRestore.SaveCreatedTime.AddHours(config.HoursOfBlock);
PrintWarning($"Unable to parse block end date format, block end set to {BlockEnd.ToString("dd.MM.yyyy HH:mm:ss")}");
config.BlockEndStr = BlockEnd.ToString("dd.MM.yyyy HH:mm:ss");
SaveConfig();
}
config.BlockEnd = BlockEnd;
permission.RegisterPermission(config.BypassPermission, this);
if(!string.IsNullOrEmpty(config.Gui.Image.Image))
if (!config.Gui.Image.Image.ToLower().Contains("http"))
{
config.Gui.Image.Image = "file://" + Interface.Oxide.DataDirectory + Path.DirectorySeparatorChar + config.Gui.Image.Image;
}
LoadData();
permission.RegisterPermission("itemsblocker.refresh", this);
}
protected override void SaveConfig()
{
Config.WriteObject(config);
}
#endregion
#region Data (Image save\load)
private void LoadData()
{
try
{
Image = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, string>>(Title);
}
catch (Exception ex)
{
if(ex is JsonSerializationException)
{
try
{
string old = Interface.Oxide.DataFileSystem.ReadObject<string>(Title);
Image[config.Gui.Image.Image] = old;
SaveData();
return;
}
catch(Exception ex1)
{
PrintWarning("Failed to convert old data fromat to the new.Data wiped.\n{0}", ex1.Message);
Image = new Dictionary<string, string>();
return;
}
}
PrintWarning("Failed to load datafile (is the file corrupt?)\n{0}", ex.Message);
Image = new Dictionary<string, string>();
}
}
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject(Title, Image);
}
#endregion
#region Initialization and quiting
void OnServerInitialized()
{
if (!Image.ContainsKey(config.Gui.Image.Image))
DownloadImage();
else
OnScreenPanel(true);
}
void Unload() => DestroyAllGui();
#endregion
#region Localization
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["ItemBlocked"] = "Using this item is blocked!",
["BlockTimeLeft"] = "\n{0}d {1:00}:{2:00}:{3:00} until unblock.",
["Weapon line 2"] = "\nYou can only use Hunting bow and Crossbow",
["Cloth line 2"] = "\nYou can only use wood and bone armor!",
["OnlyPlayer"] = "This command can be executed only from the game!",
["OnScreenText"] = "Some of the items are blocked!",
["Ammo blocked"] = "The ammo you are trying to use is blocked!"
}, this);
lang.RegisterMessages(new Dictionary<string, string>
{
["ItemBlocked"] = "Использование данного предмета заблокировано!",
["BlockTimeLeft"] = "\nДо окончания блокировки осталось {0}д.{1:00}:{2:00}:{3:00}",
["Weapon line 2"] = "\nВы можете использовать только Лук и Арбалет",
["Cloth line 2"] = "\nИспользуйте только деревянную и костяную броню!",
["OnlyPlayer"] = "Эту команду можно использовать только в игре!",
["OnScreenText"] = "Некоторые предметы заблокированы!",
["Ammo blocked"] = "Вид боеприпасов, которые вы пытаетесь использовать заблокирован!"
}, this, "ru");
}
string GetMsg(string key, BasePlayer player = null) => lang.GetMessage(key, this, player?.UserIDString);
string GetMsg(string key) => lang.GetMessage(key, this);
#endregion
#region Oxide hooks
void OnPlayerDisconnected(BasePlayer player, string reason)
{
if (Main.ContainsKey(player))
Main.Remove(player);
if (OnScreen.Contains(player))
OnScreen.Remove(player);
}
void OnPlayerSleepEnded(BasePlayer player)
{
if (!InBlock)
return;
if (!OnScreen.Contains(player))
OnScreenPanelMain(player);
}
void OnNewSave(string filename)
{
config.BlockEnd = DateTime.Now.AddHours(config.HoursOfBlock);
config.BlockEndStr = config.BlockEnd.ToString("dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture);
SaveConfig();
PrintWarning($"Wipe detected.Block end set to {config.BlockEndStr}");
}
object CanEquipItem(PlayerInventory inventory, Item item)
{
if (InBlock)
{
var player = inventory.GetComponent<BasePlayer>();
if (InDuel(player) || IsNPC(player)) return null;
if (permission.UserHasPermission(player.UserIDString, config.BypassPermission))
return null;
if (config.BlockedItems.Contains(item.info.displayName.english) || config.BlockedItems.Contains(item.info.shortname))
{
string reply = GetMsg("ItemBlocked", player);
reply += GetMsg("BlockTimeLeft", player);
reply += GetMsg("Weapon line 2", player);
if (config.UseChat)
{
SendToChat(player, reply);
}
else
{
BlockerUi(player, reply);
}
return false;
}
}
return null;
}
object CanWearItem(PlayerInventory inventory, Item item)
{
if (InBlock)
{
var player = inventory.GetComponent<BasePlayer>();
if (InDuel(player) || IsNPC(player)) return null;
if (permission.UserHasPermission(player.UserIDString, config.BypassPermission))
return null;
if (config.BlockedClothes.Contains(item.info.displayName.english) || config.BlockedClothes.Contains(item.info.shortname))
{
string reply = GetMsg("ItemBlocked", player);
reply += GetMsg("BlockTimeLeft", player);
reply += GetMsg("Cloth line 2", player);
if (config.UseChat)
{
SendToChat(player, reply);
}
else
{
BlockerUi(player, reply);
}
return false;
}
}
return null;
}
void OnReloadWeapon(BasePlayer player, BaseProjectile projectile)
{
if (!InBlock) return;
if (InDuel(player) || IsNPC(player)) return;
if(IsAmmoBlocked(player, projectile))
{
SendToChat(player, GetMsg("Ammo blocked", player) + GetMsg("BlockTimeLeft", player));
}
}
object OnReloadMagazine(BasePlayer player, BaseProjectile projectile)
{
if (InBlock)
{
if (InDuel(player) || IsNPC(player)) return null;
var ammo = projectile.primaryMagazine.ammoType;
if (IsAmmoBlocked(player, projectile))
{
projectile.SendNetworkUpdateImmediate();
return false;
}
}
return null;
}
#endregion
#region Image
[ConsoleCommand("ib.refresh")]
private void CmdRefresh(ConsoleSystem.Arg arg)
{
if (arg.Connection != null && arg.Connection.player != null)
{
BasePlayer player = arg.Connection.player as BasePlayer;
if (!permission.UserHasPermission(player.UserIDString, "itemsblocker.refresh"))
return;
}
DownloadImage();
}
private void DownloadImage()
{
PrintWarning("Downloading image...");
ServerMgr.Instance.StartCoroutine(DownloadImage(config.Gui.Image.Image));
}
IEnumerator DownloadImage(string url)
{
using (var www = new WWW(url))
{
yield return www;
if (this == null) yield break;
if (www.error != null)
{
PrintError($"Failed to add image.File address possibly invalide\n {url}");
}
else
{
var reply = 0;
var tex = www.texture;
byte[] bytes = tex.EncodeToPNG();
Image[url] = FileStorage.server.Store(www.bytes, FileStorage.Type.png, CommunityEntity.ServerInstance.net.ID).ToString();
SaveData();
PrintWarning("Image download is complete.");
OnScreenPanel(true);
UnityEngine.Object.DestroyImmediate(tex);
yield break;
}
}
}
#endregion
#region GUI
#region PanelNames
private string BlockerParent = "BlockerUI";
private string BlockerPanel = "BlockerUIPanel";
private string BlockerText = "BlockerUIText";
private string OnScreenParent = "BlockerUIOnScreen";
private string OnScreenText = "BlockerUIOnScreenText";
#endregion
#region GUI Creation
private class UI
{
private static string ToRustColor(string input)
{
Color color;
if (!ColorUtility.TryParseHtmlString(input, out color))
{
var split = input.Split(' ');
for (var i = 0; i < 4; i++)
{
float num;
if (!float.TryParse(split[i], out num))
{
return null;
}
color[i] = num;
}
}
return string.Format("{0:F2} {1:F2} {2:F2} {3:F2}", color.r, color.g, color.b, color.a);
}
#region Override to custom classes
public static void CreatePanel(ref CuiElementContainer container, string Parent, string Name, GUIPanel panel, bool CursorEnabled = false) =>
CreatePanel(ref container, Parent, Name, panel.Color, panel.Amin, panel.Amax, CursorEnabled);
public static void CreateImage(ref CuiElementContainer container, string Parent, string Name, GUIImage Image, string Png) =>
CreateImage(ref container, Parent, Name, Image.Opacity, Image.Amin, Image.Amax, Png);
public static void CreateText(ref CuiElementContainer container, string Parent, string Name, GUIText TextComp, string Text, TextAnchor Anchor = TextAnchor.MiddleCenter) =>
CreateText(ref container, Parent, Name, TextComp.Amin, TextComp.Amax, Text, TextComp.Color, TextComp.Size, TextComp.Outline, Anchor);
#endregion
public static void CreatePanel(ref CuiElementContainer container, string Parent, string Name, string Color, string Amin, string Amax, bool CursorEnabled = false)
{
container.Add(new CuiPanel
{
RectTransform = { AnchorMin = Amin, AnchorMax = Amax },
Image = { Color = ToRustColor(Color) },
CursorEnabled = CursorEnabled
}, Parent, Name);
}
public static void CreateImage(ref CuiElementContainer container, string Parent, string Name, float opacity, string Amin, string Amax, string Image)
{
var ImageComp = new CuiRawImageComponent { Sprite = "assets/content/textures/generic/fulltransparent.tga", Color = $"1 1 1 {opacity}" };
if (Image != null)
{
ImageComp.Png = Image;
}
container.Add(new CuiElement
{
Name = Name ?? CuiHelper.GetGuid(),
Parent = Parent,
Components = { ImageComp, new CuiRectTransformComponent { AnchorMin = Amin, AnchorMax = Amax } }
});
}
public static void CreateFulscreenButton(ref CuiElementContainer container, string Parent, string Name, string Command)
{
container.Add(new CuiButton
{
Button = { Command = Command, Color = "0 0 0 0"},
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1"},
Text = { Text = ""}
}, Parent, Name);
}
public static void CreateText(ref CuiElementContainer container, string Parent, string Name, string Amin, string Amax, string Text, string TextColor, int FontSize, GUIOutline outline = null, TextAnchor Anchor = TextAnchor.MiddleCenter)
{
var Element = new CuiElement
{
Parent = Parent,
Name = Name ?? CuiHelper.GetGuid(),
Components =
{
new CuiTextComponent { Color = ToRustColor(TextColor), FontSize = FontSize, Text = Text, Align = Anchor },
new CuiRectTransformComponent { AnchorMin = Amin, AnchorMax = Amax }
}
};
if (outline != null && outline.Use)
{
Element.Components.Add(
new CuiOutlineComponent { Color = ToRustColor(outline.Color), Distance = outline.Distance });
}
container.Add(Element);
}
}
#endregion
#region Commands
[ConsoleCommand("ib.close")]
private void CmdCloseUI(ConsoleSystem.Arg arg)
{
var player = arg.Player();
if(player == null)
{
arg.ReplyWith(GetMsg("OnlyPlayer"));
return;
}
if (Main.ContainsKey(player))
{
Main[player]?.Destroy();
Main.Remove(player);
CuiHelper.DestroyUi(player, BlockerParent);
}
}
#endregion
private void DestroyAllGui()
{
OnScreenUpdater?.Destroy();
foreach (var player in BasePlayer.activePlayerList)
{
CuiHelper.DestroyUi(player, OnScreenParent);
if (Main.ContainsKey(player))
{
Main[player]?.Destroy();
Main.Remove(player);
CuiHelper.DestroyUi(player, BlockerParent);
}
}
}
private void OnScreenPanel(bool init = false)
{
if (!config.Gui.UseOnScreenPanel)
return;
if (init)
foreach (var player in BasePlayer.activePlayerList)
OnScreenPanelMain(player);
if (!InBlock)
{
DestroyAllGui();
return;
}
foreach(var player in OnScreen)
{
CuiHelper.DestroyUi(player, OnScreenText);
var container = new CuiElementContainer();
string text = GetMsg("OnScreenText", player) + GetMsg("BlockTimeLeft", player);
var timeleft = TimeLeft;
text = string.Format(text, timeleft.Days, timeleft.Hours, timeleft.Minutes, timeleft.Seconds);
UI.CreateText(ref container, OnScreenParent, OnScreenText, config.Gui.TextOnScreen, text);
CuiHelper.AddUi(player, container);
}
OnScreenUpdater = timer.Once(1f, () => OnScreenPanel());
}
private void OnScreenPanelMain(BasePlayer player)
{
if (!config.Gui.UseOnScreenPanel)
return;
CuiHelper.DestroyUi(player, OnScreenParent);
var container = new CuiElementContainer();
UI.CreatePanel(ref container, "Hud", OnScreenParent, config.Gui.OnScreenPanel);
if(Image.ContainsKey(config.Gui.Image.Image))
UI.CreateImage(ref container, OnScreenParent, null, config.Gui.Image, Image[config.Gui.Image.Image]);
CuiHelper.AddUi(player, container);
OnScreen.Add(player);
}
private void BlockerUi(BasePlayer player, string inputText)
{
if (!Main.ContainsKey(player))
ShowBlocker(player);
CuiHelper.DestroyUi(player, BlockerText);
var timeleft = TimeLeft;
string formatted = string.Format(inputText, timeleft.Days, timeleft.Hours, timeleft.Minutes, timeleft.Seconds);
var container = new CuiElementContainer();
UI.CreateText(ref container, BlockerPanel, BlockerText, config.Gui.TextOnMain, formatted);
CuiHelper.AddUi(player, container);
Main[player] = timer.Once(1f, () => BlockerUi(player, inputText));
}
private void ShowBlocker(BasePlayer player)
{
CuiHelper.DestroyUi(player, BlockerParent);
var container = new CuiElementContainer();
UI.CreatePanel(ref container, "Overlay", BlockerParent, config.Gui.Background.Color, "0 0", "1 1", true);
UI.CreatePanel(ref container, BlockerParent, BlockerPanel, config.Gui.MainPanel);
UI.CreateFulscreenButton(ref container, BlockerParent, null, "ib.close");
CuiHelper.AddUi(player, container);
}
#endregion
#region Helpers
private void Debug(string text)
{
#if CHECK
PrintWarning(text);
#endif
}
private bool IsAmmoBlocked(BasePlayer owner, BaseProjectile proj)
{
Debug($"IsAmmoBlocked called on player \"{owner.displayName}\" for weapon \"{proj.GetItem()?.info.displayName.english ?? "Unknown"}\"");
List<Item> currentAmmo = owner.inventory.FindItemIDs(proj.primaryMagazine.ammoType.itemid).ToList();
Item newAmmo = null;
Debug($"CurrentAmmo count = {currentAmmo.Count}");
if (currentAmmo.Count == 0)
{
List<Item> newAmmoList = new List<Item>();
owner.inventory.FindAmmo(newAmmoList, proj.primaryMagazine.definition.ammoTypes);
Debug(
$"CurrentAmmo count equals 0.NewAmmoList count = {newAmmoList.Count}\nTrying to get the first item.");
if (newAmmoList.Count == 0)
return false;
try
{
newAmmo = newAmmoList[0];
Debug($"Successfully got item {newAmmo.info.displayName.english}");
}
catch (Exception e)
{
PrintError($"Error in attempt to get the item from NewAmmoList.{e.GetType()}:\n{e.Message}");
return false;
}
}
else
{
Debug($"CurrentAmmo count doesn't equals 0.Getting NewAmmo out of it.");
try
{
newAmmo = currentAmmo[0];
Debug($"Successfully got item {newAmmo.info.displayName.english}");
}
catch (Exception e)
{
PrintError($"Error in attempt to get the item from the CurrentAmmo list.{e.GetType()}:\n{e.Message}");
return false;
}
}
return config.BlockedAmmo.Contains(newAmmo.info.displayName.english) || config.BlockedAmmo.Contains(newAmmo.info.shortname);
}
private bool IsNPC(BasePlayer player)
{
//BotSpawn
if (player is NPCPlayer)
return true;
//HumanNPC
if (!(player.userID >= 76560000000000000L || player.userID <= 0L))
return true;
return false;
}
private bool InDuel(BasePlayer player)
{
if (Duel == null) return false;
return (bool)Duel.Call("IsPlayerOnActiveDuel", player);
}
TimeSpan TimeLeft => config.BlockEnd.Subtract(DateTime.Now);
private bool InBlock
{
get
{
if (TimeLeft.TotalSeconds >= 0)
{
return true;
}
return false;
}
}
private void SendToChat(BasePlayer Player, string Message)
{
var timeleft = TimeLeft;
Message = string.Format(Message, timeleft.Days, timeleft.Hours, timeleft.Minutes, timeleft.Seconds);
PrintToChat(Player, "<color=" + config.PrefixColor + ">" + config.Prefix + "</color> " + Message);
}
#endregion
}
}