C#:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using System.Text;
using ConVar;
using Facepunch.Math;
using HarmonyLib;
using UnityEngine.Networking;
using Oxide.Core;
using UnityEngine.UI;
using Object = System.Object;
using Pool = Facepunch.Pool;
namespace Oxide.Plugins {
[Info("IQWipeBlock", "Mercury", "2.2.3")]
[Description("Готов к вайпу?")]
public class IQWipeBlock : RustPlugin {
/// <summary>
/// - Исправлена анимация
/// - Добавлен детект контейнера дрона
/// </summary>
#region Reference
[PluginReference]
Plugin IQChat, Battles, Duel, Duelist, ArenaTournament, AimTraining, XFarmRoom, OneVSOne, EventHelper;
#region IQChat
private void SendChat(String Message, BasePlayer player, Chat.ChatChannel channel = Chat.ChatChannel.Global) {
Configuration.ReferencePlugins.IQChat chatPreset = config.referencePlugins.presetReferenceChat;
if (IQChat) IQChat?.Call("API_ALERT_PLAYER", player, Message, chatPreset.CustomPrefix, chatPreset.CustomAvatar);
else player.SendConsoleCommand("chat.add", channel, 0, Message);
}
#endregion
#region IsDuel
public Boolean IsDuel(BasePlayer player) {
if (!player) return false;
UInt64 userID = player.userID.Get();
Object obj = Interface.Oxide.RootPluginManager.GetPlugin("AimTraining")?.CallHook("IsArenaPlayer", userID);
if (obj is Boolean) return (Boolean)obj;
if (EventHelper) {
if ((Boolean)EventHelper.CallHook("EMAtEvent", userID)) return true;
}
if (OneVSOne) if ((Boolean)OneVSOne.Call("IsEventPlayer", player)) return true;
if (Battles) if ((Boolean)Battles.Call("IsPlayerOnBattle", userID)) return true;
if (Duel) if ((Boolean)Duel.Call("IsPlayerOnActiveDuel", player)) return true;
if (Duelist) if ((Boolean)Duelist.Call("inEvent", player)) return true;
if (ArenaTournament) if (ArenaTournament.Call<Boolean>("IsOnTournament", userID)) return true;
if (XFarmRoom) if (XFarmRoom.Call<Boolean>("API_PlayerInRoom", userID)) return true;
return false;
}
#endregion
#endregion
#region Vars
private const String permissionIgnore = "iqwipeblock.ignore";
private Boolean isFullUnblocked = false;
private const String colorText = "0.8941177 0.854902 0.8196079 1";
private const String colorProgressBar = "0.894 0.855 0.82 0.5";
private const Boolean LanguageEn = true;
private static IQWipeBlock _;
private static ImageUI _imageUI;
private const UInt32 mlrs_rocket_storage = 1219574627;
private const UInt32 submarineTorpedoStorage = 2609093601;
private const UInt32 catapultAmmoStorage = 2705489675;
private const UInt32 droneAmmoStorage = 1397446101;
private const UInt32 droneAmmoStorageCooldown = 1397447202;
private const String actionDrop = "drop";
private const GameTip.Styles GameTipStylesRed = GameTip.Styles.Red_Normal;
private const Item.Flag BlockedFlag = global : : Item.Flag.OnFire;
private const String fastButtonLayer = "IQWIPEBLOCK_FAST_BUTTON";
private const String layerWipeBlock = "IQWIPEBLOCK_MAIN";
private const String mainLayer = "IQWIPEBLOCK_BACKGROUND";
private const String firstConnectedLayer = "IQWIPEBLOCK_FIRST_CONNECTED_ALERT";
private Timer timerChecker;
private Single scrollHeight = 0f;
private Dictionary<String, ElementPosition> elementPositionsBlock = new();
private readonly List<ElementPosition> positionItems = new();
private Dictionary<UInt64, Timer> timerAlertConnection = new Dictionary<UInt64, Timer>();
public List<UInt64> drawedAlertButton = new List<UInt64>();
private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private static Double CurrentTime() => DateTime.UtcNow.Subtract(epoch).TotalSeconds;
private class ElementPosition {
public String OffsetMin {
get;
}
public String OffsetMax {
get;
}
public ElementPosition(String offsetMin, String offsetMax) {
OffsetMin = offsetMin;
OffsetMax = offsetMax;
}
}
#endregion
#region Data
private Int32 timeCorrectedWipe = 0;
private void ReadData() => timeCorrectedWipe = Oxide.Core.Interface.Oxide.DataFileSystem.ReadObject<Int32>("IQSystem/IQWipeBlock/TimeCorrectedWipe");
private void WriteData() => Oxide.Core.Interface.Oxide.DataFileSystem.WriteObject("IQSystem/IQWipeBlock/TimeCorrectedWipe", timeCorrectedWipe);
#endregion
#region Configuration
private static Configuration config = new Configuration();
private class Configuration {
[JsonProperty(LanguageEn ? "Command to open the block menu [Do not use slash `/`]" : "Команда для открытия меню блокировки [Не используйте слэш `/`]")]
public String commandOpen;
[JsonProperty(LanguageEn ? "Block settings [UniqueKey] = Setting" : "Настройка блокировок [УникальныйКлюч] = Настройка")]
public Dictionary<String, CategoryBlocked> categoriesBlockeds = new Dictionary<String, CategoryBlocked>();
[JsonProperty(LanguageEn ? "Supported plugins configuration" : "Настройка поддерживаемых плагинов")]
public ReferencePlugins referencePlugins = new ReferencePlugins();
[JsonProperty(LanguageEn ? "Use notification that wipe-block is active when connecting to the server [true - yes / false - no]" : "Использовать уведомление о том, что вайпблок активен при подключении на сервер [true - да/false - нет]")]
public Boolean useFirstAlert;
[JsonProperty(LanguageEn ? "Use quick access button to open the main interface [true - yes / false - no]" : "Использовать кнопку быстрого доступа для открытия основного интерфейса [true - да/false - нет]")]
public Boolean useFastButton;
[JsonProperty(LanguageEn ? "Item synonyms. Example: rifle.ak.divier -> rifle.ak [Specify the shortname]" : "Синонимы предметов. Например : rifle.ak.divier -> rifle.ak [Указывайте shortname]", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<String, String> weaponAlias = new Dictionary<String, String>();
[JsonIgnore]
public Dictionary<Int32, Double> blockedItemsItemdIds = new Dictionary<Int32, Double>();
[JsonIgnore]
public Dictionary<Int32, Int32> blockItemNormalizeList = new();
internal class ReferencePlugins {
[JsonProperty(LanguageEn ? "Setting up IQChat" : "Настройка IQChat'a")]
public IQChat presetReferenceChat = new IQChat();
internal class IQChat {
[JsonProperty(LanguageEn ? "IQChat : Custom chat prefix" : "IQChat : Кастомный префикс в чате")]
public String CustomPrefix;
[JsonProperty(LanguageEn ? "IQChat : Custom chat avatar (If required)" : "IQChat : Кастомный аватар в чате(Если требуется)")]
public String CustomAvatar;
}
}
internal class CategoryBlocked {
[JsonProperty(LanguageEn ? "Category title in different languages [LanguageKey] = Text" : "Навзание категории на разных языках [КлючЯзыка] = Текст")]
public Dictionary<String, String> titleCategory = new Dictionary<String, String>();
[JsonProperty(LanguageEn ? "Blocked items [shortname] = seconds [Use whole numbers]" : "Заблокированные предметы [shortname] = секунды [Используйте целые числа]")]
public Dictionary<String, Int32> blockedsItems = new Dictionary<String, Int32>();
[JsonIgnore]
public List<Int32> blockedItemsItemdIds = new List<Int32>();
public String GetLangTextInConfig(BasePlayer player) {
String langPlayer = _.lang.GetLanguage(player.UserIDString);
if(titleCategory.TryGetValue(langPlayer, out String day)) return day;
if (titleCategory.TryGetValue("en", out String dayEnglish)) return dayEnglish;
KeyValuePair<String, String> defautlName = titleCategory.FirstOrDefault();
return defautlName.Value ?? String.Empty;
}
}
public Int32 NormalizeItem(Int32 itemId) => blockItemNormalizeList.GetValueOrDefault(itemId, itemId);
public void ParseItemIdsNormalized() {
foreach (KeyValuePair<String, String> alias in weaponAlias) {
ItemDefinition itemDefFirst = ItemManager.FindItemDefinition(alias.Key);
if (!itemDefFirst) {
_.PrintError(LanguageEn ? "" : $"Не найден предмет с названием : {alias.Key}, проверьте корректность введенного shortname в списке синонимов");
continue;
}
ItemDefinition itemDefTwo = ItemManager.FindItemDefinition(alias.Value);
if (!itemDefTwo) {
_.PrintError(LanguageEn ? "" : $"Не найден предмет с названием : {alias.Key}, проверьте корректность введенного shortname в списке синонимов");
continue;
}
blockItemNormalizeList.TryAdd(itemDefFirst.itemid, itemDefTwo.itemid);
}
}
public void GetItemsIDsInConfig(CategoryBlocked categoryBlocked) {
Int32 wipeTime = (Int32) SaveRestore.SaveCreatedTime.ToUniversalTime().Subtract(epoch).TotalSeconds;
config.ParseItemIdsNormalized();
Boolean isError = false;
List<String> errorListShortnames = Pool.Get<List<String>>();
foreach (KeyValuePair<String, Int32> itemsInConfig in categoryBlocked.blockedsItems) {
ItemDefinition itemDef = ItemManager.FindItemDefinition(itemsInConfig.Key);
if (!itemDef) {
isError = true;
errorListShortnames.Add(itemsInConfig.Key);
continue;
}
if (blockedItemsItemdIds.TryAdd(itemDef.itemid, wipeTime + itemsInConfig.Value + _.timeCorrectedWipe)) {
categoryBlocked.blockedItemsItemdIds.Add(itemDef.itemid);
continue;
}
_.PrintWarning(LanguageEn ? $"Attempt to add item (shortname) `{itemsInConfig.Key}` again — duplicate entries are not allowed, please remove duplicates from the configuration!" : $"Попытка добавить предмет (shortname) `{itemsInConfig.Key}` повторно, нельзя добавить один предмет несколько раз, удалите дубликаты в конфигурации!");
}
if (isError) {
String shortnames = String.Join(", ", errorListShortnames);
_.PrintError(LanguageEn ? $"Warning! An error was found in the item name(s) (shortname), incorrect name(s): {shortnames}" : $"Внимание! Допущена ошибка в название(/ях) предмета(/ов) (shortname), название(/я) с ошибкой : {shortnames}");
Pool.FreeUnmanaged(ref errorListShortnames);
Interface.Oxide.UnloadPlugin(_.Name);
}
}
public Double GetLeftTimeBlocked(Int32 itemID) {
Int32 normalizeItemID = NormalizeItem(itemID);
if (!blockedItemsItemdIds.TryGetValue(normalizeItemID, out Double blockedItemTime)) return 0;
Double elapsed = blockedItemTime - CurrentTime();
return elapsed < 0 ? 0f : elapsed;
}
public Boolean IsBlocked(Int32 itemID) => GetLeftTimeBlocked(itemID) > 0;
public Boolean IsBlocked(Int32 itemID, out String leftTime) {
Int32 normalizeItemID = NormalizeItem(itemID);
Double timeBlocked = GetLeftTimeBlocked(normalizeItemID);
if (timeBlocked > 0) {
leftTime = _.FormatTime(timeBlocked);
return true;
}
leftTime = String.Empty;
return false;
}
public Boolean IsFullUnBlocked() {
foreach (Int32 itemId in blockedItemsItemdIds.Keys) {
if (IsBlocked(itemId)) return false;
}
return true;
}
public void InitializeCategory() {
foreach (KeyValuePair<String, CategoryBlocked> categoryBlocked in categoriesBlockeds) GetItemsIDsInConfig(categoryBlocked.Value);
_.GeneratePositionsCategoriesPanel();
_.GeneratePositionsItems();
}
public static Configuration GetNewConfiguration() {
return new Configuration {
commandOpen = "block", useFastButton = true, useFirstAlert = true, referencePlugins = new ReferencePlugins {
presetReferenceChat = new ReferencePlugins.IQChat {
CustomPrefix = "<color=#8EAD57>IQWipeBlock</color> |", CustomAvatar = "0"
}
}
, weaponAlias = new Dictionary<String, String>() {
["rifle.ak.ice"]
= "rifle.ak", ["rifle.ak.diver"] = "rifle.ak", ["rifle.ak.med"] = "rifle.ak", ["rifle.ak.jungle"] = "rifle.ak", ["rocket.launcher.dragon"] = "rocket.launcher", ["metal.facemask.hockey"] = "metal.facemask", ["metal.facemask.icemask"] = "metal.facemask", ["metal.plate.torso.icevest"] = "metal.plate.torso", ["blunderbuss"] = "shotgun.double",
}
, categoriesBlockeds = new Dictionary<String, CategoryBlocked>() {
["start"]
= new CategoryBlocked() {
titleCategory = new Dictionary<String, String>() {
["ru"]
= "ИСКРА", ["en"] = "SPARK",
}
, blockedsItems = new Dictionary<String, Int32>() {
["shotgun.double"]
= 3600, ["shotgun.waterpipe"] = 3600, ["flamethrower"] = 3600, ["military flamethrower"] = 3600, ["pistol.revolver"] = 3600, ["grenade.molotov"] = 3600,
}
}
, ["warmup"] = new CategoryBlocked() {
titleCategory = new Dictionary<String, String>() {
["ru"]
= "РАЗОГРЕВ", ["en"] = "WARM UP",
}
, blockedsItems = new Dictionary<String, Int32>() {
["t1_smg"]
= 7200, ["pistol.semiauto"] = 7200, ["pistol.python"] = 7200, ["pistol.m92"] = 7200, ["pistol.prototype17"] = 7200, ["shotgun.pump"] = 7200, ["shotgun.spas12"] = 7200, ["shotgun.m4"] = 7200, ["revolver.hc"] = 7200, ["roadsign.kilt"] = 7200, ["roadsign.jacket"] = 7200, ["coffeecan.helmet"] = 7200, ["knightsarmour.helmet"] = 7200, ["knightsarmour.skirt"] = 7200, ["knighttorso.armour"] = 7200,
}
}
, ["escalation"] = new CategoryBlocked() {
titleCategory = new Dictionary<String, String>() {
["ru"]
= "НАПРЯЖЕНИЕ", ["en"] = "ESCALATION",
}
, blockedsItems = new Dictionary<String, Int32>() {
["smg.2"]
= 18000, ["rifle.semiauto"] = 18000, ["smg.thompson"] = 18000, ["smg.mp5"] = 18000, ["rifle.m39"] = 18000, ["rifle.sks"] = 18000,
}
}
, ["pressure"] = new CategoryBlocked() {
titleCategory = new Dictionary<String, String>() {
["ru"]
= "ДАВЛЕНИЕ", ["en"] = "PRESSURE",
}
, blockedsItems = new Dictionary<String, Int32>() {
["metal.facemask"]
= 28800, ["metal.plate.torso"] = 28800, ["surveycharge"] = 28800, ["grenade.f1"] = 28800, ["grenade.beancan"] = 28800,
}
}
, ["overdrive"] = new CategoryBlocked() {
titleCategory = new Dictionary<String, String>() {
["ru"]
= "ПЕРЕГРЕВ", ["en"] = "OVERDRIVE",
}
, blockedsItems = new Dictionary<String, Int32>() {
["rocket.launcher"]
= 36000, ["ammo.rocket.hv"] = 36000,
}
}
, ["ignition"] = new CategoryBlocked() {
titleCategory = new Dictionary<String, String>() {
["ru"]
= "ВОЗГОРАНИЕ", ["en"] = "IGNITION",
}
, blockedsItems = new Dictionary<String, Int32>() {
["hmlmg"]
= 72000, ["rifle.ak"] = 72000, ["multiplegrenadelauncher"] = 72000, ["rifle.lr300"] = 72000, ["rifle.bolt"] = 72000, ["rifle.l96"] = 72000, ["explosive.satchel"] = 72000, ["ammo.rifle.explosive"] = 72000, ["catapult"] = 72000, ["ballista.mounted"] = 72000, ["ballista.static"] = 72000, ["batteringram"] = 72000,
}
}
, ["breakthrough"] = new CategoryBlocked() {
titleCategory = new Dictionary<String, String>() {
["ru"]
= "ПРОРЫВ", ["en"] = "BREAKTHROUGH",
}
, blockedsItems = new Dictionary<String, Int32>() {
["lmg.m249"]
= 93600, ["minigun"] = 93600, ["ammo.rocket.basic"] = 93600, ["ammo.rocket.fire"] = 93600, ["ammo.rocket.mlrs"] = 93600, ["explosive.timed"] = 93600,
}
}
,
}
}
;
}
}
protected override void LoadConfig() {
base.LoadConfig();
try {
config = Config.ReadObject<Configuration>();
if (config == null) LoadDefaultConfig();
if (config.weaponAlias == null || config.weaponAlias.Count == 0) {
config.weaponAlias = new Dictionary<String, String>() {
["rifle.ak.ice"]
= "rifle.ak", ["rifle.ak.diver"] = "rifle.ak", ["rifle.ak.med"] = "rifle.ak", ["rifle.ak.jungle"] = "rifle.ak", ["rocket.launcher.dragon"] = "rocket.launcher", ["metal.facemask.hockey"] = "metal.facemask", ["metal.facemask.icemask"] = "metal.facemask", ["metal.plate.torso.icevest"] = "metal.plate.torso", ["blunderbuss"] = "shotgun.double",
}
;
}
}
catch {
PrintWarning(LanguageEn ? $"Error #54588528 reading configuration 'oxide/config/{Name}', creating a new configuration!!" : $"Ошибка #54588528 чтения конфигурации 'oxide/config/{Name}', создаём новую конфигурацию!!");
LoadDefaultConfig();
}
NextTick(SaveConfig);
}
protected override void LoadDefaultConfig() => config = Configuration.GetNewConfiguration();
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Hooks
#region Action Hooks
#region Hooks Blocked
#region Flag Controller
private void OnItemAction(Item? item, String action, BasePlayer player) {
if (item == null || !player || !player.userID.IsSteamId() || String.IsNullOrWhiteSpace(action)) return;
if (!action.Equals(actionDrop)) return;
if (IsDuel(player) || IsIgnoreWipeBlock(player)) {
SetOrRemoveFlag(item, false);
return;
}
SetOrRemoveFlag(item, config.IsBlocked(item.info.itemid));
}
private void OnItemAddedToContainer(ItemContainer container, Item item) {
BasePlayer player = container.playerOwner;
if (!player || !player.userID.IsSteamId()) return;
if (IsDuel(player) || IsIgnoreWipeBlock(player)) {
SetOrRemoveFlag(item, false);
return;
}
Boolean isBlocked = config.IsBlocked(item.info.itemid);
if (isBlocked) {
ItemContainer mainContainer = player.inventory.containerMain;
Boolean isMainContainerFull = mainContainer.itemList.Count > 24;
if (container == player.inventory.containerWear || container == player.inventory.containerBelt) {
if (isMainContainerFull) item.DropAndTossUpwards(player.transform.position);
else item.MoveToContainer(mainContainer);
}
else if (isMainContainerFull) {
item.DropAndTossUpwards(player.transform.position);
}
}
SetOrRemoveFlag(item, isBlocked);
}
#endregion
private Object? OnWeaponReload(BaseProjectile weapon, BasePlayer player) => OnMagazineReload(weapon, player.inventory, player);
private Object? OnMagazineReload(BaseProjectile weapon, IAmmoContainer desiredAmount, BasePlayer player) {
if (!player || !player.userID.IsSteamId() || !weapon) return null;
if (IsDuel(player) || IsIgnoreWipeBlock(player)) return null;
if (weapon.primaryMagazine == null || !weapon.primaryMagazine.ammoType) return null;
if (weapon.primaryMagazine.ammoType.itemid is 550753330 or -363689972) return null;
weapon.SwitchAmmoTypesIfNeeded(player.inventory);
weapon.SendNetworkUpdate();
Boolean isActiveItemBlocked = false;
Boolean isWeaponAmmoBlocked = config.IsBlocked(weapon.primaryMagazine.ammoType.itemid, out String timeToUnblock);
String timeToUnblockActiveItem = String.Empty;
Item? activeItem = player.GetActiveItem();
if (activeItem != null && activeItem.info) isActiveItemBlocked = config.IsBlocked(activeItem.info.itemid, out timeToUnblockActiveItem);
if (!isWeaponAmmoBlocked && !isActiveItemBlocked) return null;
ItemDefinition? blockedItem = isWeaponAmmoBlocked ? weapon.primaryMagazine.ammoType : activeItem?.info;
String unblockTime = isWeaponAmmoBlocked ? timeToUnblock : timeToUnblockActiveItem;
if (blockedItem) SendPlayerNotify(player, blockedItem, unblockTime);
return false;
}
private Object? OnRackedWeaponLoad(Item weapon, ItemDefinition itemDefinition, BasePlayer player, WeaponRack instance) {
if (!player || !player.userID.IsSteamId()) return null;
if (IsDuel(player) || IsIgnoreWipeBlock(player)) return null;
if (!config.IsBlocked(itemDefinition.itemid, out String timeToUnblock)) return null;
SendPlayerNotify(player, itemDefinition, timeToUnblock);
return false;
}
#endregion
#region [Harmony]Patch AutoTurret
[HarmonyPatch(typeof(AutoTurret), "CanAcceptItem")]
public class Patch_AutoTurret_CanAcceptItem {
[HarmonyPostfix]
public static void CanAcceptItem_Postfix(ref Boolean __result, Item item, Int32 targetSlot) {
BasePlayer player = item.GetOwnerPlayer();
if (!player) return;
if (!__result || !config.IsBlocked(item.info.itemid, out String timeToUnblock) || _.IsDuel(player) || _.IsIgnoreWipeBlock(player)) return;
SendPlayerNotify(player, item.info, timeToUnblock);
__result = false;
}
}
#endregion
#region [Harmony]Patch AttackHelicopterTurret and AttackHelicopterRockets
[HarmonyPatch(typeof(AttackHelicopterTurret), "CanAcceptItem")]
public class Patch_AttackHelicopterTurret_CanAcceptItem {
[HarmonyPostfix]
public static void CanAcceptItem_Postfix(ref Boolean __result, Item item, Int32 targetSlot) {
BasePlayer player = item.GetOwnerPlayer();
if (!__result || !config.IsBlocked(item.info.itemid, out String timeToUnblock) || _.IsDuel(player) || _.IsIgnoreWipeBlock(player)) return;
SendPlayerNotify(player, item.info, timeToUnblock);
__result = false;
}
}
[HarmonyPatch(typeof(AttackHelicopterRockets), "ItemFilter")]
public class Patch_AttackHelicopterRockets_ItemFilter {
[HarmonyPostfix]
public static void ItemFilter_Postfix(ref Boolean __result, Item item, Int32 targetSlot) {
BasePlayer player = item.GetOwnerPlayer();
if (!__result || !config.IsBlocked(item.info.itemid, out String timeToUnblock) || _.IsDuel(player) || _.IsIgnoreWipeBlock(player)) return;
SendPlayerNotify(player, item.info, timeToUnblock);
__result = false;
}
}
#endregion
#region [Harmony]Patch MLRS AND SUBMARINE AND DRONE
[HarmonyPatch(typeof(StorageContainer), "ItemFilter")]
public class Patch_StorageContainer_ItemFilter {
[HarmonyPostfix]
public static void ItemFilter_Postfix(ref bool __result, Item item, int targetSlot, StorageContainer __instance) {
if (__instance.prefabID is mlrs_rocket_storage or submarineTorpedoStorage or catapultAmmoStorage or droneAmmoStorage or droneAmmoStorageCooldown) {
BasePlayer player = item.GetOwnerPlayer();
if (!__result || !config.IsBlocked(item.info.itemid, out String timeToUnblock) || _.IsDuel(player) || _.IsIgnoreWipeBlock(player)) return;
SendPlayerNotify(player, item.info, timeToUnblock);
__result = false;
}
}
}
#endregion
#region [Harmony]Patch CanEquipItem AND CanWearItem
[HarmonyPatch]
public class Patch_PlayerInventory {
[HarmonyPatch(typeof(PlayerInventory), "CanEquipItem", typeof(Item), typeof(Int32))]
[HarmonyPostfix]
public static void CanEquipItem_Postfix(ref Boolean __result, Item item, Int32 targetSlot, PlayerInventory __instance) {
if (!__result || !config.IsBlocked(item.info.itemid, out String timeToUnblock)) return;
BasePlayer player = __instance.baseEntity;
if (!player || !player.userID.IsSteamId()) return;
if (_.IsDuel(player) || _.IsIgnoreWipeBlock(player)) return;
SendPlayerNotify(player, item.info, timeToUnblock);
__result = false;
}
[HarmonyPatch(typeof(PlayerInventory), "CanWearItem", typeof(Item), typeof(Int32))]
[HarmonyPostfix]
public static void CanWearItem_Postfix(ref Boolean __result, Item item, Int32 targetSlot, PlayerInventory __instance) {
if (!__result || !config.IsBlocked(item.info.itemid, out String timeToUnblock)) return;
BasePlayer player = __instance.baseEntity;
if (!player || !player.userID.IsSteamId()) return;
if (_.IsDuel(player) || _.IsIgnoreWipeBlock(player)) return;
SendPlayerNotify(player, item.info, timeToUnblock);
__result = false;
}
}
#endregion
#endregion
#region Server Hooks
private void OnPlayerDisconnected(BasePlayer player, String reason) => DestroyTimerAlertUI(player, true);
private void OnPlayerSleepEnded(BasePlayer player) {
if (!player || !player.userID.IsSteamId() || player.IsDead()) return;
DrawUI_FirstConnected(player);
}
private void Init() {
_ = this;
ReadData();
}
private void OnServerInitialized() {
if (!permission.PermissionExists(permissionIgnore, this)) permission.RegisterPermission(permissionIgnore, this);
config.InitializeCategory();
UnsubscribeAllHook();
if (config.IsFullUnBlocked()) {
isFullUnblocked = true;
Puts(LanguageEn ? "All items on the server have been unlocked; the plugin’s core functions will be disabled" : "Все предметы на сервере разблокированы, основные функции плагина будут отключены");
HarmonyInstance.UnpatchAll(HarmonyInstance.Id);
cmd.AddChatCommand(config.commandOpen, this, nameof(ChatCommandUnblockedAll));
cmd.AddConsoleCommand(config.commandOpen, this, nameof(ConsoleCommandUnblockedAll));
}
else {
_imageUI = new ImageUI();
_imageUI.DownloadImage();
LoadHarmony();
SubscribeAllHook();
cmd.AddChatCommand(config.commandOpen, this, nameof(DrawUI));
cmd.AddConsoleCommand(config.commandOpen, this, nameof(ConsoleCommandOpenWipeBlockFast));
timerChecker = timer.Every(60f, CheckUnblockedWipeBlock);
Puts(LanguageEn ? "Item lock on the server is active; the plugin’s functions have started successfully" : "Блокировка предметов на сервере активна, функции плагина запущены успешно");
}
}
private void Unload() {
if (_ == null) return;
HarmonyInstance?.UnpatchAll(HarmonyInstance.Id);
if (elementPositionsBlock != null) {
elementPositionsBlock.Clear();
elementPositionsBlock = null;
}
if (timerChecker is {
Destroyed : false
}
) {
timerChecker.Destroy();
timerChecker = null;
}
if (_imageUI != null) {
_imageUI.UnloadImages();
_imageUI = null;
}
foreach (BasePlayer player in BasePlayer.activePlayerList) {
DestroyUI(player, mainLayer);
DestroyUI(player, fastButtonLayer);
DestroyTimerAlertUI(player, true);
}
timerAlertConnection.Clear();
timerAlertConnection = null;
drawedAlertButton.Clear();
drawedAlertButton = null;
_ = null;
}
#endregion
#endregion
#region Commands
[ConsoleCommand("update.ui.item")]
private void UI_FuncionalCommands(ConsoleSystem.Arg arg) {
BasePlayer player = arg.Player();
if (!player) return;
if (!Int32.TryParse(arg.Args[0], out Int32 itemID)) return;
String parentLayer = arg.Args[1];
String layerName = arg.Args[2];
if (config.IsBlocked(itemID)) return;
UpdateUnblockBlockItem(player, parentLayer, layerName);
}
[ConsoleCommand("open.wipeblock.firts.alert")]
private void ConsoleCommandOpenWipeBlock(ConsoleSystem.Arg arg) {
BasePlayer player = arg.Player();
if(!player) return;
DestroyTimerAlertUI(player, false);
DrawUI_WipeBlockFastButton(player);
DrawUI(player);
}
private void ConsoleCommandOpenWipeBlockFast(ConsoleSystem.Arg arg) {
BasePlayer player = arg.Player();
if(!player) return;
DrawUI(player);
}
private void ConsoleCommandUnblockedAll(ConsoleSystem.Arg arg) {
BasePlayer player = arg.Player();
if (!player) return;
SendChat(GetLang("WIPEBLOCK_DISABLED", player.UserIDString), player);
}
private void ChatCommandUnblockedAll(BasePlayer player, String cmd, String[] arg) => SendChat(GetLang("WIPEBLOCK_DISABLED", player.UserIDString), player);
[ConsoleCommand("a.wipeblock")]
private void WipeBlockAdminCommands(ConsoleSystem.Arg arg) {
BasePlayer player = arg.Player();
if(player) if (!player.IsAdmin) return;
String action = arg.Args[0];
switch (action) {
case "reset" : {
timeCorrectedWipe = 0;
WriteData();
PrintWarning(LanguageEn ? "The wipe time has been reset to default settings; the plugin will be reloaded" : "Время вайпа было вернуто к стандартным настройка, плагин будет перезагружен");
Interface.Oxide.ReloadPlugin(this.Name);
break;
}
case "corrected" : {
Int32 wipeCorrectedSeconds = Int32.Parse(arg.Args[1]);
timeCorrectedWipe = wipeCorrectedSeconds;
WriteData();
PrintWarning(LanguageEn ? $"The wipe time has been adjusted to: {timeCorrectedWipe}; the plugin will be reloaded" : $"Время вайпа было скорректировано, значение : {timeCorrectedWipe}, плагин будет перезагружен");
Interface.Oxide.ReloadPlugin(this.Name);
break;
}
}
}
#endregion
#region UI
private static void DestroyUI(BasePlayer player, String elementName) => CommunityEntity.ServerInstance.ClientRPC<String>(RpcTarget.Player("DestroyUI", player.net.connection), elementName);
private static void AddUI(BasePlayer player, String json) => CommunityEntity.ServerInstance.ClientRPC<String>(RpcTarget.Player("AddUI", player.net.connection), json);
#region First Connected Alert
private void DrawUI_FirstConnected(BasePlayer player) {
if (isFullUnblocked) return;
if (!player) return;
if (!config.useFirstAlert) {
DrawUI_WipeBlockFastButton(player);
return;
}
if (timerAlertConnection.ContainsKey(player.userID)) {
if (timerAlertConnection[player.userID] != null && !timerAlertConnection[player.userID].Destroyed) return;
DrawUI_WipeBlockFastButton(player);
return;
}
CuiElementContainer container = new();
container.Add(new CuiElement {
Parent = "Overlay", Name = firstConnectedLayer, DestroyUi = firstConnectedLayer, Components = {
new CuiScrollViewComponent {
MovementType = ScrollRect.MovementType.Elastic, Horizontal = true, Elasticity = 0.5f, Inertia = true, ScrollSensitivity = 5f, ContentTransform = new CuiRectTransform {
AnchorMin = "-80 1", AnchorMax = "-80 1", OffsetMax = "222.335 0", Pivot = "0.5 1"
}
,
}
, new CuiRawImageComponent {
Color = "0 0 0 0"
}
, new CuiRectTransformComponent {
AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-225.3 -83.4", OffsetMax = "0 -20.4"
}
}
}
);
container.Add(new CuiElement {
Parent = firstConnectedLayer, Name = "PANEL_CONNECTED_ALERT_WIPEBLOCK", DestroyUi = "PANEL_CONNECTED_ALERT_WIPEBLOCK", Components = {
new CuiRawImageComponent {
Color = "1 1 1 1", Png = _imageUI.GetImage("UI_CONNECTED_ALERT")
}
, new CuiRectTransformComponent {
AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-225.3 -63", OffsetMax = "-31.3 0"
}
}
}
);
container.Add(new CuiElement {
Parent = "PANEL_CONNECTED_ALERT_WIPEBLOCK", Name = "PROGRESS_BAR_ALERT_WIPEBLOCK", DestroyUi = "PROGRESS_BAR_ALERT_WIPEBLOCK", Components = {
new CuiImageComponent {
Color = colorProgressBar
}
, new CuiRectTransformComponent {
AnchorMin = "0.5 0", AnchorMax = "0.5 0", OffsetMin = "-93.511 3.482", OffsetMax = "93.321 6.458"
}
}
}
);
container.Add(new CuiElement {
Parent = "PANEL_CONNECTED_ALERT_WIPEBLOCK", Name = "TITLE_WIPEBLOCK_ALERT", DestroyUi = "TITLE_WIPEBLOCK_ALERT", Components = {
new CuiTextComponent {
Text = GetLang("TITLE_ALERT_FIRST_CONNECTED", player.UserIDString), Align = TextAnchor.MiddleRight, FontSize = 14, Font = "robotocondensed-regular.ttf", Color = colorText
}
, new CuiRectTransformComponent {
AnchorMin = "1 0.5", AnchorMax = "1 0.5", OffsetMin = "-147.941 -3.199", OffsetMax = "-12.471 22.339"
}
}
}
);
container.Add(new CuiElement {
Parent = "PANEL_CONNECTED_ALERT_WIPEBLOCK", Name = "DESCRIPTION_WIPEBLOCK_ALERT", DestroyUi = "DESCRIPTION_WIPEBLOCK_ALERT", Components = {
new CuiTextComponent {
Text = GetLang("TITLE_ALERT_FIRST_CONNECTED_BUTTON", player.UserIDString), Align = TextAnchor.MiddleRight, FontSize = 16, Font = "robotocondensed-bold.ttf", Color = colorText
}
, new CuiRectTransformComponent {
AnchorMin = "1 0.5", AnchorMax = "1 0.5", OffsetMin = "-147.941 -19.499", OffsetMax = "-12.471 6.039"
}
}
}
);
container.Add(new CuiElement {
Parent = "PANEL_CONNECTED_ALERT_WIPEBLOCK", Name = "OPEN_WIPEBLOCK_IN_ALERT", DestroyUi = "OPEN_WIPEBLOCK_IN_ALERT", Components = {
new CuiButtonComponent {
Color = "0 0 0 0", Command = "open.wipeblock.firts.alert"
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1"
}
}
}
);
AddUI(player, container.ToJson());
Int32 secondAlert = 60;
Timer timerUpdateBar = timer.Every(1f, () => {
secondAlert--;
Update_ProgressBarFirstConnceted(player, secondAlert);
}
);
timerAlertConnection.Add(player.userID, timerUpdateBar);
}
private void Update_ProgressBarFirstConnceted(BasePlayer player, Int32 secondLeft) {
if (secondLeft <= 0) {
DestroyTimerAlertUI(player, false);
DrawUI_WipeBlockFastButton(player);
return;
}
CuiElementContainer container = new();
container.Add(new CuiElement {
Parent = firstConnectedLayer, Name = "PROGRESS_BAR_ALERT_WIPEBLOCK", Update = true, Components = {
new CuiRectTransformComponent {
OffsetMax = $"{CalculateOffsetMaxX()} 6.458"
}
}
}
);
AddUI(player, container.ToJson());
return;
Single CalculateOffsetMaxX() {
const Single min = -93.321f;
const Single max = 93.321f;
const Single range = max - min;
return min + ((secondLeft / 60.0f) * range);
}
}
#endregion
#region WipeBlock Fast Button
private void DrawUI_WipeBlockFastButton(BasePlayer player) {
if (isFullUnblocked) return;
if (!config.useFastButton) return;
if (drawedAlertButton.Contains(player.userID)) return;
drawedAlertButton.Add(player.userID);
CuiElementContainer container = new();
container.Add(new CuiElement {
Parent = "Overlay", Name = fastButtonLayer, DestroyUi = fastButtonLayer, Components = {
new CuiScrollViewComponent {
MovementType = ScrollRect.MovementType.Elastic, Horizontal = true, Elasticity = 0.5f, Inertia = true, ScrollSensitivity = 5f, ContentTransform = new CuiRectTransform {
AnchorMin = "-80 1", AnchorMax = "-80 1", OffsetMax = "275.335 0", Pivot = "0.5 1"
}
,
}
, new CuiRawImageComponent {
Color = "0 0 0 0"
}
, new CuiRectTransformComponent {
AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-275.3 -101.4", OffsetMax = "0 -20.4"
}
}
}
);
container.Add(new CuiElement {
Parent = fastButtonLayer, Name = "FAST_BUTTON_PANEL_BACKGORUND", DestroyUi = "FAST_BUTTON_PANEL_BACKGORUND", Components = {
new CuiRawImageComponent {
Color = "1 1 1 1", Png = _imageUI.GetImage("UI_FAST_BUTTON_PANEL")
}
, new CuiRectTransformComponent {
AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-275.3 -81", OffsetMax = "-31.3 0"
}
}
}
);
container.Add(new CuiElement {
Parent = "FAST_BUTTON_PANEL_BACKGORUND", Name = "TITLE_WIPEBLOCK_FAST_BUTTON", DestroyUi = "TITLE_WIPEBLOCK_FAST_BUTTON", Components = {
new CuiTextComponent {
Text = GetLang("TITLE_FAST_BUTTON", player.UserIDString), Align = TextAnchor.UpperLeft, FontSize = 16, Font = "robotocondensed-bold.ttf", Color = colorText
}
, new CuiRectTransformComponent {
AnchorMin = "0 0.5", AnchorMax = "0 0.5", OffsetMin = "13.41 8.493", OffsetMax = "205.27 32.307"
}
}
}
);
container.Add(new CuiElement {
Parent = "FAST_BUTTON_PANEL_BACKGORUND", Name = "DESCRIPTION_WIPEBLOCK_FAST_BUTTON", DestroyUi = "DESCRIPTION_WIPEBLOCK_FAST_BUTTON", Components = {
new CuiTextComponent {
Text = GetLang("DESCRIPTION_FAST_BUTTON", player.UserIDString, config.commandOpen), Align = TextAnchor.UpperLeft, FontSize = 12, Font = "robotocondensed-regular.ttf", Color = colorText
}
, new CuiRectTransformComponent {
AnchorMin = "0 0.5", AnchorMax = "0 0.5", OffsetMin = "13.41 -35.542", OffsetMax = "231.53 5.542"
}
}
}
);
container.Add(new CuiElement {
Parent = "FAST_BUTTON_PANEL_BACKGORUND", Name = "OPEN_WIPEBLOCK_IN_ALERT", DestroyUi = "OPEN_WIPEBLOCK_IN_ALERT", Components = {
new CuiButtonComponent {
Color = "0 0 0 0", Command = config.commandOpen
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1"
}
}
}
);
container.Add(new CuiElement {
Parent = "FAST_BUTTON_PANEL_BACKGORUND", Name = "CLOSE_PNG_FAST_BUTTON", DestroyUi = "CLOSE_PNG_FAST_BUTTON", Components = {
new CuiRawImageComponent {
Color = "1 1 1 1", Png = _imageUI.GetImage("UI_CLOSE_BUTTON")
}
, new CuiRectTransformComponent {
AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-26.47 -23.2", OffsetMax = "-12.47 -9.2"
}
}
}
);
container.Add(new CuiElement {
Parent = "CLOSE_PNG_FAST_BUTTON", Name = "CLOSE_BUTTON_WIPEBLOCK_BTN_FAST_BUTTON", DestroyUi = "CLOSE_BUTTON_WIPEBLOCK_BTN_FAST_BUTTON", Components = {
new CuiButtonComponent {
Color = "0 0 0 0", Close = fastButtonLayer
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1"
}
}
}
);
AddUI(player, container.ToJson());
}
#endregion
private void DrawUI(BasePlayer player) {
CuiElementContainer container = new();
container.Add(new CuiElement {
Parent = "Overlay", Name = mainLayer, DestroyUi = mainLayer, Components = {
new CuiImageComponent {
Color = "0.271 0.271 0.271 0.3", Material = "assets/content/ui/uibackgroundblur.mat", Sprite = "assets/content/ui/UI.Background.TileTex.psd"
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1"
}
}
}
);
container.Add(new CuiElement {
Parent = mainLayer, Name = "CLOSE_BUTTON_WIPEBLOCK", DestroyUi = "CLOSE_BUTTON_WIPEBLOCK", Components = {
new CuiButtonComponent {
Color = "0 0 0 0", Close = mainLayer
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1"
}
}
}
);
container.Add(new CuiElement {
Parent = mainLayer, Name = layerWipeBlock, DestroyUi = layerWipeBlock, Components = {
new CuiNeedsCursorComponent() {
}
, new CuiImageComponent {
Color = "0 0 0 0"
}
, new CuiRectTransformComponent {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-385 -266.5", OffsetMax = "385 266.5"
// ... [Code preview truncated due to length. Full source in attached file] ...