C#:
// #define TESTING
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Oxide.Plugins.StacksExtensionMethods;
using UnityEngine;
using Debug = UnityEngine.Debug;
using Random = UnityEngine.Random;
#if TESTING
using System.Diagnostics;
#endif
#if CARBON
using Carbon.Base;
using Carbon.Modules;
#endif
namespace Oxide.Plugins
{
[Info("Stacks", "Mevent", "1.5.19")]
public class Stacks : RustPlugin
{
#region Fields
[PluginReference] private Plugin
ImageLibrary = null,
FurnaceSplitter = null,
Notify = null,
UINotify = null,
LangAPI = null;
private static Stacks _instance;
private bool _enabledImageLibrary;
#if CARBON
ImageDatabaseModule imageDatabase;
#endif
private const bool LangRu = false;
private const string
CMD_Main_Console = "UI_Stacks",
Layer = "UI.Stacks",
AdminPerm = "stacks.admin";
private readonly Dictionary<ulong, float> _multiplierByItem = new();
private readonly List<CategoryInfo> _categories = new();
private class CategoryInfo
{
public string Title;
public List<ItemInfo> Items;
}
private readonly Dictionary<string, int> _defaultItemStackSize = new();
private bool _hasFurnaceSplitter;
#endregion
#region Config
private Configuration _config;
private class Configuration
{
[JsonProperty(PropertyName = LangRu ? "Команды" : "Commands", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public string[] Commands = {"stacks"};
[JsonProperty(PropertyName = LangRu ? "Включить работу с Notify?" : "Work with Notify?")]
public bool UseNotify = true;
[JsonProperty(PropertyName = LangRu ? "Включить работу с LangAPI?" : "Work with LangAPI?")]
public bool UseLangAPI = true;
[JsonProperty(PropertyName = LangRu ? "Изменение множителей в контейнерах при помощи киянки" : "Changing multiplies in containers using a hammer")]
public bool UserHammer = false;
[JsonProperty(PropertyName = LangRu ? "Стандартный множитель для новых контейнеров" : "Default Multiplier for new containers")]
public float DefaultContainerMultiplier = 1f;
[JsonProperty(PropertyName = LangRu ? "Запретить overstack предметов?" : "Disallow overstack items?")] public bool DisableOverstack = true;
[JsonProperty(PropertyName = LangRu ? "Заблокированный список" : "Blocked List")]
public BlockList BlockList = new()
{
Items = new List<string>
{
"item",
"short name"
},
Skins = new List<ulong>
{
111111111111,
222222222222
}
};
}
private class BlockList
{
[JsonProperty(PropertyName = LangRu ? "Предметы" : "Items", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<string> Items;
[JsonProperty(PropertyName = LangRu ? "Скины" : "Skins", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<ulong> Skins;
public bool Exists(Item item)
{
return Items.Contains(item.info.shortname) || Skins.Contains(item.skin);
}
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
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();
}
#endregion
#region Data
private List<ItemInfo> _items;
private Dictionary<string, ContainerData> _containers;
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/Containers", _containers);
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/Items", _items);
}
private void LoadData()
{
try
{
_containers =
Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, ContainerData>>($"{Name}/Containers");
_items = Interface.Oxide.DataFileSystem.ReadObject<List<ItemInfo>>($"{Name}/Items");
}
catch (Exception e)
{
PrintError(e.ToString());
}
_containers ??= new Dictionary<string, ContainerData>();
_items ??= new List<ItemInfo>();
}
private class ContainerData
{
[JsonProperty(PropertyName = "Image")] public string Image;
[JsonProperty(PropertyName = "Multiplier")] [DefaultValue(1f)]
public float Multiplier;
[JsonIgnore] private int _id = -1;
[JsonIgnore]
public int ID
{
get
{
while (_id == -1)
{
var id = Random.Range(0, int.MaxValue);
if (_instance._containerBase.ContainsKey(id)) continue;
_id = id;
break;
}
return _id;
}
}
[JsonIgnore] public string Prefab;
[JsonIgnore] private CuiRawImageComponent _image;
public CuiElement GetImage(string aMin, string aMax, string oMin, string oMax, string parent,
string name = null)
{
_image ??= new CuiRawImageComponent
{
Png = _instance.ImageLibrary?.Call<string>("GetImage",
string.IsNullOrEmpty(Image) ? "NONE" : Image) ?? string.Empty
};
return new CuiElement
{
Name = string.IsNullOrEmpty(name) ? CuiHelper.GetGuid() : name,
Parent = parent,
Components =
{
_image,
new CuiRectTransformComponent
{
AnchorMin = aMin, AnchorMax = aMax,
OffsetMin = oMin, OffsetMax = oMax
}
}
};
}
}
private class ItemInfo
{
[JsonProperty(PropertyName = "ShortName")]
public string ShortName;
[JsonProperty(PropertyName = "Name")] public string Name;
[JsonIgnore] public int DefaultStackSize => _instance._defaultStackByID.GetValueOrDefault(itemId, 0);
[JsonProperty(PropertyName = "Custom Stack Size")]
public int CustomStackSize;
[JsonIgnore] public int ID;
public string GetItemDisplayName(BasePlayer player)
{
return _instance._config.UseLangAPI && _instance.LangAPI != null &&
_instance.LangAPI.Call<bool>("IsDefaultDisplayName", Name)
? _instance.LangAPI.Call<string>("GetItemDisplayName", ShortName, Name, player.UserIDString) ?? Name
: Name;
}
public static ItemInfo Find(int id)
{
return _instance._itemByID.GetValueOrDefault(id);
}
[JsonIgnore] public int itemId;
[JsonIgnore] private ICuiComponent _image;
public CuiElement GetImage(string aMin, string aMax, string oMin, string oMax, string parent,
string name = null)
{
_image ??= new CuiImageComponent
{
ItemId = itemId
};
return new CuiElement
{
Name = string.IsNullOrEmpty(name) ? CuiHelper.GetGuid() : name,
Parent = parent,
Components =
{
_image,
new CuiRectTransformComponent
{
AnchorMin = aMin, AnchorMax = aMax,
OffsetMin = oMin, OffsetMax = oMax
}
}
};
}
}
private readonly Dictionary<string, string> _constContainers = new()
{
["assets/bundled/prefabs/static/bbq.static.prefab"] = "https://i.imgur.com/L28375p.png",
["assets/bundled/prefabs/static/hobobarrel_static.prefab"] = "https://i.imgur.com/v8sDTaP.png",
["assets/bundled/prefabs/static/recycler_static.prefab"] = "https://i.imgur.com/V1smQYs.png",
["assets/bundled/prefabs/static/repairbench_static.prefab"] = "https://i.imgur.com/8qV6Z10.png",
["assets/bundled/prefabs/static/researchtable_static.prefab"] = "https://i.imgur.com/guoVK66.png",
["assets/bundled/prefabs/static/small_refinery_static.prefab"] = "https://i.imgur.com/o4iHwpz.png",
["assets/bundled/prefabs/static/wall.frame.shopfront.metal.static.prefab"] =
"https://i.imgur.com/aJIU90I.png",
["assets/bundled/prefabs/static/water_catcher_small.static.prefab"] = "https://i.imgur.com/ZdaXU6q.png",
["assets/bundled/prefabs/static/workbench1.static.prefab"] = "https://i.imgur.com/0Trejvg.png",
["assets/content/props/fog machine/fogmachine.prefab"] = "https://i.imgur.com/v33hmbo.png",
["assets/content/structures/excavator/prefabs/engine.prefab"] = "",
["assets/content/structures/excavator/prefabs/excavator_output_pile.prefab"] = "",
["assets/content/vehicles/boats/rhib/subents/fuel_storage.prefab"] = "https://i.imgur.com/QXjLWzj.png",
["assets/content/vehicles/boats/rhib/subents/rhib_storage.prefab"] = "https://i.imgur.com/QXjLWzj.png",
["assets/content/vehicles/boats/rowboat/subents/fuel_storage.prefab"] = "https://i.imgur.com/FLr37Mb.png",
["assets/content/vehicles/boats/rowboat/subents/rowboat_storage.prefab"] =
"https://i.imgur.com/FLr37Mb.png",
["assets/content/vehicles/minicopter/subents/fuel_storage.prefab"] = "https://i.imgur.com/BRBfPjB.png",
["assets/content/vehicles/modularcar/2module_car_spawned.entity.prefab"] =
"https://i.imgur.com/3CSoGly.png",
["assets/content/vehicles/modularcar/3module_car_spawned.entity.prefab"] =
"https://i.imgur.com/HpteUCe.png",
["assets/content/vehicles/modularcar/4module_car_spawned.entity.prefab"] =
"https://i.imgur.com/QI7tzYJ.png",
["assets/content/vehicles/modularcar/subents/modular_car_1mod_storage.prefab"] = "",
["assets/content/vehicles/modularcar/subents/modular_car_2mod_fuel_tank.prefab"] = "",
["assets/content/vehicles/modularcar/subents/modular_car_fuel_storage.prefab"] = "",
["assets/content/vehicles/modularcar/subents/modular_car_i4_engine_storage.prefab"] = "",
["assets/content/vehicles/modularcar/subents/modular_car_v8_engine_storage.prefab"] = "",
["assets/content/vehicles/scrap heli carrier/subents/fuel_storage_scrapheli.prefab"] = "",
["assets/prefabs/building/wall.frame.shopfront/wall.frame.shopfront.metal.prefab"] =
"https://i.imgur.com/aJIU90I.png",
["assets/prefabs/deployable/bbq/bbq.deployed.prefab"] = "https://i.imgur.com/L28375p.png",
["assets/prefabs/deployable/campfire/campfire.prefab"] = "https://i.imgur.com/FIznmKI.png",
["assets/prefabs/deployable/composter/composter.prefab"] = "https://i.imgur.com/glcIjOS.png",
["assets/prefabs/deployable/dropbox/dropbox.deployed.prefab"] = "https://i.imgur.com/HmoyaIU.png",
["assets/prefabs/deployable/fireplace/fireplace.deployed.prefab"] = "https://i.imgur.com/XsMSlNY.png",
["assets/prefabs/deployable/fridge/fridge.deployed.prefab"] = "https://i.imgur.com/ERNmHjz.png",
["assets/prefabs/deployable/furnace.large/furnace.large.prefab"] = "https://i.imgur.com/GWaSIUw.png",
["assets/prefabs/deployable/furnace/furnace.prefab"] = "https://i.imgur.com/cnFpbOj.png",
["assets/prefabs/deployable/hitch & trough/hitchtrough.deployed.prefab"] =
"https://i.imgur.com/FiSIYh9.png",
["assets/prefabs/deployable/hot air balloon/subents/hab_storage.prefab"] =
"https://i.imgur.com/KaGFKkM.png",
["assets/prefabs/deployable/jack o lantern/jackolantern.angry.prefab"] = "https://i.imgur.com/iPBEYf3.png",
["assets/prefabs/deployable/jack o lantern/jackolantern.happy.prefab"] = "https://i.imgur.com/brKtJJj.png",
["assets/prefabs/deployable/lantern/lantern.deployed.prefab"] = "https://i.imgur.com/LqfkTKp.png",
["assets/prefabs/deployable/large wood storage/box.wooden.large.prefab"] =
"https://i.imgur.com/wecMrji.png",
["assets/prefabs/deployable/liquidbarrel/waterbarrel.prefab"] = "https://i.imgur.com/LAHPuI9.png",
["assets/prefabs/deployable/locker/locker.deployed.prefab"] = "https://i.imgur.com/jZ4raNL.png",
["assets/prefabs/deployable/mailbox/mailbox.deployed.prefab"] = "https://i.imgur.com/egLTaYb.png",
["assets/prefabs/deployable/mixingtable/mixingtable.deployed.prefab"] = "https://i.imgur.com/sbyHOjn.png",
["assets/prefabs/deployable/oil jack/crudeoutput.prefab"] = "",
["assets/prefabs/deployable/oil jack/fuelstorage.prefab"] = "",
["assets/prefabs/deployable/oil refinery/refinery_small_deployed.prefab"] =
"https://i.imgur.com/1KMt1eu.png",
["assets/prefabs/deployable/planters/planter.large.deployed.prefab"] = "https://i.imgur.com/POcQ0Ya.png",
["assets/prefabs/deployable/planters/planter.small.deployed.prefab"] = "https://i.imgur.com/fMO8cJF.png",
["assets/prefabs/deployable/playerioents/generators/fuel generator/small_fuel_generator.deployed.prefab"] =
"https://i.imgur.com/fghbYKE.png",
["assets/prefabs/deployable/playerioents/poweredwaterpurifier/poweredwaterpurifier.deployed.prefab"] =
"https://i.imgur.com/Tg2dX8b.png",
["assets/prefabs/deployable/playerioents/poweredwaterpurifier/poweredwaterpurifier.storage.prefab"] =
"https://i.imgur.com/Tg2dX8b.png",
["assets/prefabs/deployable/playerioents/waterpump/water.pump.deployed.prefab"] =
"https://i.imgur.com/FZG19ki.png",
["assets/prefabs/deployable/quarry/fuelstorage.prefab"] = "https://i.imgur.com/U1y3pmJ.png",
["assets/prefabs/deployable/quarry/hopperoutput.prefab"] = "https://i.imgur.com/U1y3pmJ.png",
["assets/prefabs/deployable/repair bench/repairbench_deployed.prefab"] = "https://i.imgur.com/8qV6Z10.png",
["assets/prefabs/deployable/research table/researchtable_deployed.prefab"] =
"https://i.imgur.com/guoVK66.png",
["assets/prefabs/deployable/single shot trap/guntrap.deployed.prefab"] = "https://i.imgur.com/rGstq6A.png",
["assets/prefabs/deployable/small stash/small_stash_deployed.prefab"] = "https://i.imgur.com/ToPKE7j.png",
["assets/prefabs/deployable/survivalfishtrap/survivalfishtrap.deployed.prefab"] =
"https://i.imgur.com/2D6jZ7j.png",
["assets/prefabs/deployable/tier 1 workbench/workbench1.deployed.prefab"] =
"https://i.imgur.com/0Trejvg.png",
["assets/prefabs/deployable/tier 2 workbench/workbench2.deployed.prefab"] =
"https://i.imgur.com/cM5F6SO.png",
["assets/prefabs/deployable/tier 3 workbench/workbench3.deployed.prefab"] =
"https://i.imgur.com/ToyPHJK.png",
["assets/prefabs/deployable/tool cupboard/cupboard.tool.deployed.prefab"] = "https://i.imgur.com/mD9KsAL.png",
["assets/prefabs/deployable/tuna can wall lamp/tunalight.deployed.prefab"] =
"https://i.imgur.com/EWXtCJg.png",
["assets/prefabs/deployable/vendingmachine/npcvendingmachines/npcvendingmachine_attire.prefab"] = "",
["assets/prefabs/deployable/vendingmachine/npcvendingmachines/npcvendingmachine_building.prefab"] = "",
["assets/prefabs/deployable/vendingmachine/npcvendingmachines/npcvendingmachine_components.prefab"] = "",
["assets/prefabs/deployable/vendingmachine/npcvendingmachines/npcvendingmachine_extra.prefab"] = "",
["assets/prefabs/deployable/vendingmachine/npcvendingmachines/npcvendingmachine_farming.prefab"] = "",
["assets/prefabs/deployable/vendingmachine/npcvendingmachines/npcvendingmachine_resources.prefab"] = "",
["assets/prefabs/deployable/vendingmachine/npcvendingmachines/npcvendingmachine_tools.prefab"] = "",
["assets/prefabs/deployable/vendingmachine/npcvendingmachines/npcvendingmachine_vehicleshigh.prefab"] = "",
["assets/prefabs/deployable/vendingmachine/npcvendingmachines/npcvendingmachine_weapons.prefab"] = "",
["assets/prefabs/deployable/vendingmachine/npcvendingmachines/shopkeeper_vm_invis.prefab"] = "",
["assets/prefabs/deployable/vendingmachine/vendingmachine.deployed.prefab"] =
"https://i.imgur.com/8Kfvfgp.png",
["assets/prefabs/deployable/water catcher/water_catcher_large.prefab"] = "https://i.imgur.com/MF90xE7.png",
["assets/prefabs/deployable/water catcher/water_catcher_small.prefab"] = "https://i.imgur.com/ZdaXU6q.png",
["assets/prefabs/deployable/water well/waterwellstatic.prefab"] = "",
["assets/prefabs/deployable/water well/waterwellstatic.prefab"] = "https://i.imgur.com/FyQJnhX.png",
["assets/prefabs/deployable/waterpurifier/waterstorage.prefab"] = "https://i.imgur.com/FyQJnhX.png",
["assets/prefabs/deployable/woodenbox/woodbox_deployed.prefab"] = "https://i.imgur.com/gwhRYjt.png",
["assets/prefabs/io/electric/switches/fusebox/fusebox.prefab"] = "",
["assets/prefabs/misc/casino/bigwheel/bigwheelbettingterminal.prefab"] = "",
["assets/prefabs/misc/chinesenewyear/chineselantern/chineselantern.deployed.prefab"] =
"https://i.imgur.com/WUa0fN2.png",
["assets/prefabs/misc/halloween/coffin/coffinstorage.prefab"] = "https://i.imgur.com/zHbT59P.png",
["assets/prefabs/misc/halloween/cursed_cauldron/cursedcauldron.deployed.prefab"] =
"https://i.imgur.com/z6QnrT3.png",
["assets/prefabs/misc/halloween/skull_fire_pit/skull_fire_pit.prefab"] = "https://i.imgur.com/9phq5Bu.png",
["assets/prefabs/misc/halloween/trophy skulls/skulltrophy.deployed.prefab"] =
"https://i.imgur.com/TmntgJT.png",
["assets/prefabs/misc/item drop/item_drop.prefab"] = "",
["assets/prefabs/misc/item drop/item_drop_backpack.prefab"] = "",
["assets/prefabs/misc/marketplace/marketterminal.prefab"] = "",
["assets/prefabs/misc/summer_dlc/abovegroundpool/abovegroundpool.deployed.prefab"] = "",
["assets/prefabs/misc/summer_dlc/paddling_pool/paddlingpool.deployed.prefab"] =
"https://i.imgur.com/v2V6T7d.png",
["assets/prefabs/misc/summer_dlc/photoframe/photoframe.landscape.prefab"] =
"https://i.imgur.com/nH2jf5j.png",
["assets/prefabs/misc/summer_dlc/photoframe/photoframe.large.prefab"] = "https://i.imgur.com/sPfBcVt.png",
["assets/prefabs/misc/summer_dlc/photoframe/photoframe.portrait.prefab"] =
"https://i.imgur.com/gvbD7Pm.png",
["assets/prefabs/misc/supply drop/supply_drop.prefab"] = "https://i.imgur.com/VAtGtQB.png",
["assets/prefabs/misc/xmas/snow_machine/models/snowmachine.prefab"] = "https://i.imgur.com/pAqw9It.png",
["assets/prefabs/misc/twitch/hobobarrel/hobobarrel.deployed.prefab"] = "https://i.imgur.com/v8sDTaP.png",
["assets/prefabs/misc/xmas/xmastree/xmas_tree.deployed.prefab"] = "https://i.imgur.com/wQU9ojJ.png",
["assets/prefabs/npc/autoturret/autoturret_deployed.prefab"] = "https://i.imgur.com/VUiBkC5.png",
["assets/prefabs/npc/flame turret/flameturret.deployed.prefab"] = "https://i.imgur.com/TcIOwLa.png",
["assets/prefabs/npc/sam_site_turret/sam_site_turret_deployed.prefab"] = "https://i.imgur.com/SNBPqIX.png",
["assets/content/vehicles/submarine/subents/submarineitemstorage.prefab"] = "",
["assets/rust.ai/nextai/ridablehorse/items/horse.saddlebag.item.prefab"] = "https://i.imgur.com/BpZPZYH.png",
["assets/prefabs/deployable/tool cupboard/retro/cupboard.tool.retro.deployed.prefab"] = "https://i.ibb.co/6RW24LK/image.png",
};
#endregion
#region Hooks
private void Init()
{
_instance = this;
LoadData();
if (!_config.UserHammer)
Unsubscribe(nameof(OnHammerHit));
#if TESTING
StopwatchWrapper.OnComplete = DebugMessage;
#endif
}
private void OnServerInitialized(bool init)
{
LoadImages();
LoadItems();
LoadCategories();
UniqueLoadContainers();
LoadReferences();
RegisterPermissions();
RegisterCommands();
}
private void Unload()
{
foreach (var player in BasePlayer.activePlayerList) CuiHelper.DestroyUi(player, Layer);
foreach (var check in _defaultItemStackSize)
{
var info = ItemManager.FindItemDefinition(check.Key);
if (info != null)
info.stackable = check.Value;
}
SaveData();
_instance = null;
}
#region Stacks
private object CanMoveItem(Item movedItem, PlayerInventory playerInventory, ItemContainerId targetContainer,
int targetSlot, int amount)
{
if (movedItem == null || playerInventory == null || _config.BlockList.Exists(movedItem)) return null;
_multiplierByItem.Remove(movedItem.uid.Value);
var container = playerInventory.FindContainer(targetContainer);
var player = playerInventory.GetComponent<BasePlayer>();
if (container != null)
{
var entity = container.entityOwner;
if (entity != null)
_multiplierByItem[movedItem.uid.Value] = GetContainerMultiplier(entity.name);
}
#region Right-Click Overstack into Player Inventory
if (targetSlot == -1)
{
#if TESTING
Puts("Right-Click Overstack into Player Inventory");
#endif
//Right click overstacks into player inventory
if (container == null)
{
if (_config.DisableOverstack && movedItem.amount > movedItem.info.stackable)
{
var loops = 1;
if (player.serverInput.IsDown(BUTTON.SPRINT))
loops = Mathf.CeilToInt((float) movedItem.amount / movedItem.info.stackable);
for (var i = 0; i < loops; i++)
{
if (movedItem.amount <= movedItem.info.stackable)
{
playerInventory.GiveItem(movedItem);
break;
}
if (movedItem.info.stackable > 0)
{
var itemToMove = movedItem.SplitItem(movedItem.info.stackable);
if (!playerInventory.GiveItem(itemToMove))
{
movedItem.amount += itemToMove.amount;
itemToMove.Remove();
break;
}
movedItem.MarkDirty();
}
}
playerInventory.ServerUpdate(0f);
return true;
}
}
//Shift Right click into storage container
else
{
if (player.serverInput.IsDown(BUTTON.SPRINT))
{
if (_hasFurnaceSplitter && container.entityOwner is BaseOven)
return null;
ItemHelper.MoveShiftRight(movedItem, container, playerInventory);
return true;
}
}
}
#endregion
#region Moving Overstacks Around In Chest
if (amount > movedItem.info.stackable && container != null)
{
#if TESTING
Puts("Moving Overstacks Around In Chest");
#endif
var targetItem = container.GetSlot(targetSlot);
if (targetItem == null)
{
//Split item into chest
ItemHelper.SplitMoveItem(movedItem, movedItem.info.stackable, container, targetSlot);
}
else
{
//Stacking items when amount > info.stacksize
if (targetItem.CanStack(movedItem))
{
if (amount < movedItem.amount)
{
ItemHelper.SplitMoveItem(movedItem, movedItem.info.stackable, playerInventory);
}
else
{
if (targetItem.info.stackable < targetItem.amount + movedItem.amount)
{
var splitAmount = targetItem.info.stackable - targetItem.amount;
if (splitAmount > 0)
{
var itemToMove = movedItem.SplitItem(splitAmount);
if (!itemToMove.MoveToContainer(container, targetSlot))
{
movedItem.amount += itemToMove.amount;
itemToMove.Remove();
playerInventory.ServerUpdate(0f);
return true;
}
playerInventory.ServerUpdate(0f);
return true;
}
}
movedItem.MoveToContainer(container, targetSlot);
}
}
}
playerInventory.ServerUpdate(0f);
return true;
}
#endregion
#region Prevent Moving Overstacks To Inventory
if (_config.DisableOverstack && container != null)
{
#if TESTING
Puts("Prevent Moving Overstacks To Inventory");
#endif
var targetItem = container.GetSlot(targetSlot);
if (targetItem != null && !movedItem.CanStack(targetItem) &&
targetItem.amount > targetItem.info.stackable)
return true;
}
#endregion
return null;
}
private int? OnMaxStackable(Item item)
{
#if TESTING
using (var watch = new StopwatchWrapper("OnMaxStackable took {0}ms."))
#endif
{
if (item == null ||
item.info.itemType == ItemContainer.ContentsType.Liquid ||
item.info.stackable == 1 ||
_config.BlockList.Exists(item))
return null;
#if TESTING
watch.AdditionalInfo = $"dictionary_count: {_multiplierByItem.Count}";
#endif
if (_multiplierByItem.TryGetValue(item.uid.Value, out var multiplier))
return Mathf.FloorToInt(item.info.stackable * multiplier);
if (item.parent == null || item.parent.entityOwner == null) return null;
var container = GetContainerMultiplier(item.parent.entityOwner.name);
return Mathf.FloorToInt(container * item.info.stackable);
}
}
private void OnItemDropped(Item item, BaseEntity entity)
{
#if TESTING
Puts($"OnItemDropped: {item}");
#endif
_multiplierByItem.Remove(item.uid.Value);
var stackSize = item.info.stackable;
#if TESTING
Puts($"OnItemDropped.stackSize: {stackSize} | item.amount: {item.amount}");
#endif
if (stackSize <= 0f || item.amount <= stackSize) return;
var loops = Mathf.FloorToInt((float) item.amount / stackSize);
if (loops > 20) return;
for (var i = 0; i < loops; i++)
{
if (stackSize <= 0f || item.amount <= stackSize) break;
item.SplitItem(stackSize)?.Drop(entity.transform.position,
entity.GetComponent<Rigidbody>().velocity + Vector3Ex.Range(-1f, 1f));
}
}
private void OnHammerHit(BasePlayer player, HitInfo info)
{
if (!_config.UserHammer || player == null ||
!player.HasPermission(AdminPerm) || info == null)
return;
var container = info.HitEntity;
if (container == null)
return;
if (_containers.TryGetValue(container.name, out var data))
SettingsUi(player, 1, 0, 0, data.ID, first: true);
}
private void OnItemDespawn(Item item)
{
if (item == null) return;
_multiplierByItem.Remove(item.uid.Value);
}
#endregion
#region FurnaceSplitter && Image Library
private void OnPluginLoaded(Plugin plugin)
{
switch (plugin.Name)
{
case "FurnaceSplitter":
_hasFurnaceSplitter = true;
break;
case "ImageLibrary":
_enabledImageLibrary = true;
break;
}
}
private void OnPluginUnloaded(Plugin plugin)
{
switch (plugin.Name)
{
case "FurnaceSplitter":
_hasFurnaceSplitter = false;
break;
case "ImageLibrary":
_enabledImageLibrary = false;
break;
}
}
#endregion
#endregion
#region Commands
private void CmdOpenStacks(IPlayer cov, string command, string[] args)
{
var player = cov?.Object as BasePlayer;
if (player == null) return;
if (_enabledImageLibrary == false)
{
SendNotify(player, NoILError, 1);
BroadcastILNotInstalled();
return;
}
if (!player.HasPermission(AdminPerm))
{
SendNotify(player, NoPermission, 1);
return;
}
if (args.Length == 0)
{
MainUi(player, first: true);
return;
}
switch (args[0])
{
case "sethandstack":
{
if (args.Length < 2 || !int.TryParse(args[1], out var stackSize))
{
cov.Reply($"Error syntax! Use: /{command} {args[0]} [stackSize]");
return;
}
var activeItem = player.GetActiveItem();
if (activeItem == null)
{
cov.Reply("You are missing an item in your hand!");
return;
}
var item = _items.Find(x => x.ShortName == activeItem.info.shortname);
if (item == null)
{
cov.Reply("Item not found!");
return;
}
item.CustomStackSize = stackSize;
UpdateItemStack(item);
SendNotify(player, SetStack, 0, stackSize, item.GetItemDisplayName(player));
SaveData();
break;
}
case "setstack":
{
if (args.Length < 3 || !int.TryParse(args[2], out var stackSize))
{
cov.Reply($"Error syntax! Use: /{command} {args[0]} [shortName] [stackSize]");
return;
}
var item = _items.Find(x => x.ShortName == args[1]);
if (item == null)
{
cov.Reply($"Item '{args[1]}' not found!");
return;
}
item.CustomStackSize = stackSize;
UpdateItemStack(item);
SendNotify(player, SetStack, 0, stackSize, item.GetItemDisplayName(player));
SaveData();
break;
}
}
}
[ConsoleCommand("stacks.manage")]
private void CmdConsoleStacksManage(ConsoleSystem.Arg arg)
{
if (!arg.IsServerside) return;
if (!arg.HasArgs())
{
var sb = new StringBuilder();
sb.AppendLine("Stacks management commands:");
sb.AppendLine($"– stacks.manage stack set [shortname] [size] – set stack size");
sb.AppendLine($"– stacks.manage stack get [shortname] – get stack size");
sb.AppendLine($"– stacks.manage stack get all – get all stack sizes");
SendReply(arg, sb.ToString());
return;
}
switch (arg.GetString(0))
{
case "stack":
{
switch (arg.GetString(1))
{
case "set":
{
var shortName = arg.GetString(2);
if (string.IsNullOrEmpty(shortName))
{
SendReply(arg, "Invalid shortname!");
return;
}
var item = _items.Find(x => x.ShortName == shortName);
if (item == null)
{
SendReply(arg, $"Item '{shortName}' not found!");
return;
}
var stackSize = arg.GetInt(3, -1);
if (stackSize <= 0)
{
SendReply(arg, $"Invalid stack size!");
return;
}
item.CustomStackSize = stackSize;
UpdateItemStack(item);
SendReply(arg, $"You have changed stack size to {item.CustomStackSize}!");
break;
}
case "get":
{
if (arg.GetString(2) == "all")
{
var sb = new StringBuilder();
sb.AppendLine("All stacks:");
_items.ForEach(item => sb.AppendLine($"{item.ShortName}: {item.CustomStackSize}"));
SendReply(arg, sb.ToString());
}
else
{
var shortName = arg.GetString(2);
if (string.IsNullOrEmpty(shortName))
{
SendReply(arg, "Invalid shortname!");
return;
}
var item = _items.Find(x => x.ShortName == shortName);
if (item == null)
{
SendReply(arg, $"Item '{shortName}' not found!");
return;
}
SendReply(arg, $"Stack size: {item.CustomStackSize} (0 – default)");
}
break;
}
}
break;
}
default:
{
SendReply(arg, $"Invalid command!");
break;
}
}
}
[ConsoleCommand(CMD_Main_Console)]
private void CmdConsoleStacks(ConsoleSystem.Arg arg)
{
var player = arg?.Player();
if (player == null || !arg.HasArgs()) return;
switch (arg.Args[0])
{
case "page":
{
int category = -1, page = 0;
if (!arg.HasArgs(2) || !int.TryParse(arg.Args[1], out var type)) return;
if (arg.HasArgs(3))
int.TryParse(arg.Args[2], out category);
if (arg.HasArgs(4))
int.TryParse(arg.Args[3], out page);
var search = string.Empty;
if (arg.HasArgs(5))
search = arg.Args[4];
MainUi(player, type, category, page, search);
break;
}
case "enter_page":
{
if (!arg.HasArgs(5) ||
!int.TryParse(arg.Args[1], out var type) ||
!int.TryParse(arg.Args[2], out var category) ||
!int.TryParse(arg.Args[4], out var page)) return;
var search = arg.Args[3];
if (string.IsNullOrEmpty(search)) return;
MainUi(player, type, category, page, search);
break;
}
case "settings":
{
if (!arg.HasArgs(5) ||
!int.TryParse(arg.Args[1], out var type) ||
!int.TryParse(arg.Args[2], out var category) ||
!int.TryParse(arg.Args[3], out var page) ||
!int.TryParse(arg.Args[4], out var id)) return;
var enterValue = -1f;
if (arg.HasArgs(6))
{
float.TryParse(arg.Args[5], out enterValue);
enterValue = (float) Math.Round(enterValue, 2);
}
SettingsUi(player, type, category, page, id, enterValue);
break;
}
case "apply_settings":
{
if (!arg.HasArgs(6) ||
!int.TryParse(arg.Args[1], out var type) ||
!int.TryParse(arg.Args[2], out var category) ||
!int.TryParse(arg.Args[3], out var page) ||
!int.TryParse(arg.Args[4], out var id) ||
!float.TryParse(arg.Args[5], out var nowValue) || nowValue <= 0) return;
switch (type)
{
case 0: //item
{
SetItemMultiplier(id, nowValue);
break;
}
case 1: //container
{
SetContainerMultiplier(id, nowValue);
break;
}
}
MainUi(player, type, category, page);
break;
}
}
}
#endregion
#region Interface
private void MainUi(BasePlayer player, int type = 0, int category = -1, int page = 0, string search = "",
bool first = false)
{
var lines = 0;
float height;
float ySwitch;
var container = new CuiElementContainer();
#region Background
if (first)
{
container.Add(new CuiPanel
{
RectTransform = {AnchorMin = "0 0", AnchorMax = "1 1"},
Image =
{
Color = "0 0 0 0.9",
Material = "assets/content/ui/uibackgroundblur.mat"
},
CursorEnabled = true
}, "Overlay", Layer, Layer);
container.Add(new CuiButton
{
RectTransform = {AnchorMin = "0 0", AnchorMax = "1 1"},
Text = {Text = string.Empty},
Button =
{
Color = "0 0 0 0",
Close = Layer
}
}, Layer);
}
#endregion
#region Main
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5",
OffsetMin = "-300 -250",
OffsetMax = "300 255"
},
Image =
{
Color = HexToCuiColor("#0E0E10")
}
}, Layer, Layer + ".Main", Layer + ".Main");
#endregion
#region Header
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "1 1",
OffsetMin = "0 -50",
OffsetMax = "0 0"
},
Image = {Color = HexToCuiColor("#161617")}
}, Layer + ".Main", Layer + ".Header");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "30 0",
OffsetMax = "0 0"
},
Text =
{
Text = Msg(player, TitleMenu),
Align = TextAnchor.MiddleLeft,
Font = "robotocondensed-bold.ttf",
FontSize = 14,
Color = HexToCuiColor("#FFFFFF")
}
}, Layer + ".Header");
float xSwitch = -25;
float width = 25;
float margin = 5;
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = $"{xSwitch - width} -37.5",
OffsetMax = $"{xSwitch} -12.5"
},
Text =
{
Text = Msg(player, CloseButton),
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-bold.ttf",
FontSize = 10,
Color = HexToCuiColor("#FFFFFF")
},
Button =
{
Close = Layer,
Color = HexToCuiColor("#4B68FF")
}
}, Layer + ".Header");
xSwitch = xSwitch - margin - width;
width = 80;
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = $"{xSwitch - width} -37.5",
OffsetMax = $"{xSwitch} -12.5"
},
Text =
{
Text = Msg(player, ContainerTitle),
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = HexToCuiColor("#FFFFFF")
},
Button =
{
Color = type == 1 ? HexToCuiColor("#4B68FF") : HexToCuiColor("#FFFFFF", 5),
Command = $"{CMD_Main_Console} page 1"
}
}, Layer + ".Header");
xSwitch = xSwitch - margin - width;
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = $"{xSwitch - width} -37.5",
OffsetMax = $"{xSwitch} -12.5"
},
Text =
{
Text = Msg(player, ItemTitle),
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = HexToCuiColor("#FFFFFF")
},
Button =
{
Color = type == 0 ? HexToCuiColor("#4B68FF") : HexToCuiColor("#FFFFFF", 5),
Command = $"{CMD_Main_Console} page 0"
}
}, Layer + ".Header");
#region Search
xSwitch = xSwitch - margin - width;
width = 140;
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = $"{xSwitch - width} -37.5",
OffsetMax = $"{xSwitch} -12.5"
},
Image =
{
Color = HexToCuiColor("#000000")
}
}, Layer + ".Header", Layer + ".Header.Search");
container.Add(new CuiElement
{
Parent = Layer + ".Header.Search",
Components =
{
new CuiInputFieldComponent
{
Text = string.IsNullOrEmpty(search) ? Msg(player, SearchTitle) : $"{search}",
FontSize = 12,
Align = TextAnchor.MiddleLeft,
Font = "robotocondensed-regular.ttf",
Command = $"{CMD_Main_Console} page {type} {category} {page}",
Color = "1 1 1 0.95",
CharsLimit = 32,
NeedsKeyboard = true,
HudMenuInput = true
},
new CuiRectTransformComponent
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "10 0", OffsetMax = "-10 0"
}
}
});
#endregion
#endregion
var maxCount = 0;
switch (type)
{
case 0: //Item
{
#region Categories
var amountOnString = 6;
width = 90;
margin = 5;
height = 25;
ySwitch = -60;
xSwitch = 20;
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "0 1",
OffsetMin = $"{xSwitch} {ySwitch - height}",
OffsetMax = $"{xSwitch + width} {ySwitch}"
},
Text =
{
Text = Msg(player, AllTitle),
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-bold.ttf",
FontSize = 12,
Color = "1 1 1 1"
},
Button =
{
Color = -1 == category ? HexToCuiColor("#4B68FF") : HexToCuiColor("#161617"),
Command = $"{CMD_Main_Console} page {type} {-1}"
}
}, Layer + ".Main");
xSwitch += width + margin;
for (var i = 0; i < _categories.Count; i++)
{
var info = _categories[i];
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "0 1",
OffsetMin = $"{xSwitch} {ySwitch - height}",
OffsetMax = $"{xSwitch + width} {ySwitch}"
},
Text =
{
Text = $"{info.Title}",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-bold.ttf",
FontSize = 12,
Color = "1 1 1 1"
},
Button =
{
Color = i == category ? HexToCuiColor("#4B68FF") : HexToCuiColor("#161617"),
Command = $"{CMD_Main_Console} page {type} {i}"
}
}, Layer + ".Main");
if ((i + 2) % amountOnString == 0)
{
ySwitch = ySwitch - height - margin;
xSwitch = 20;
}
else
{
xSwitch += width + margin;
}
}
#endregion
#region Items
ySwitch = ySwitch - height - 5;
margin = 5;
height = 50f;
xSwitch = 20;
width = 565;
lines = 6;
var categoryInfo = category == -1
? _categories.SelectMany(x => x.Items).ToList()
: _categories[category].Items;
var items = string.IsNullOrEmpty(search) || search.Length < 2
? categoryInfo
: categoryInfo.FindAll(x => x.GetItemDisplayName(player).StartsWith(search) ||
x.GetItemDisplayName(player).Contains(search)
|| x.Name.StartsWith(search) || x.Name.Contains(search) ||
x.ShortName.StartsWith(search) || x.ShortName.Contains(search));
maxCount = items.Count;
foreach (var item in items.Skip(page * lines).Take(lines))
{
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "0 1",
OffsetMin = $"{xSwitch} {ySwitch - height}",
OffsetMax = $"{xSwitch + width} {ySwitch}"
},
Image =
{
Color = HexToCuiColor("#161617")
}
}, Layer + ".Main", Layer + $".Panel.{item.ShortName}");
container.Add(item.GetImage("0 0.5", "0 0.5", "20 -15", "50 15",
Layer + $".Panel.{item.ShortName}"));
#region Name
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "55 0", OffsetMax = "0 0"
},
Text =
{
Text = $"{item.GetItemDisplayName(player)}",
Align = TextAnchor.MiddleLeft,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 1"
}
}, Layer + $".Panel.{item.ShortName}");
#endregion
#region Default Stack
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0.5", AnchorMax = "1 1",
OffsetMin = "180 0", OffsetMax = "0 0"
},
Text =
{
Text = Msg(player, DefaultStack),
Align = TextAnchor.LowerLeft,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 0.5"
}
}, Layer + $".Panel.{item.ShortName}");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 0.5",
OffsetMin = "180 0", OffsetMax = "0 0"
},
Text =
{
Text = Msg(player, StackFormat, item.DefaultStackSize),
Align = TextAnchor.UpperLeft,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 1"
}
}, Layer + $".Panel.{item.ShortName}");
#endregion
#region Custom Stack
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0.5", AnchorMax = "1 1",
OffsetMin = "310 0", OffsetMax = "0 0"
},
Text =
{
Text = Msg(player, CustomStack),
Align = TextAnchor.LowerLeft,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 0.5"
}
}, Layer + $".Panel.{item.ShortName}");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 0.5",
OffsetMin = "310 0", OffsetMax = "0 0"
},
Text =
{
Text = Msg(player, StackFormat,
item.CustomStackSize == 0 ? item.DefaultStackSize : item.CustomStackSize),
Align = TextAnchor.UpperLeft,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 1"
}
}, Layer + $".Panel.{item.ShortName}");
#endregion
#region Settings
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "1 0.5", AnchorMax = "1 0.5",
OffsetMin = "-110 -12.5",
OffsetMax = "-10 12.5"
},
Text =
{
Text = Msg(player, SettingsTitle),
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 1"
},
Button =
{
Color = HexToCuiColor("#4B68FF"),
Command =
$"{CMD_Main_Console} settings {type} {category} {(string.IsNullOrEmpty(search) ? page : 0)} {item.ID}"
}
}, Layer + $".Panel.{item.ShortName}");
#endregion
ySwitch = ySwitch - height - margin;
}
#endregion
break;
}
case 1: //Container
{
#region Items
ySwitch = -65;
margin = 10;
height = 60;
xSwitch = 20;
width = 565;
lines = 6;
var containers = string.IsNullOrEmpty(search) || search.Length < 2
? _containerBase.ToList()
: _containerBase.Where(x => x.Value.Prefab.EndsWith(search) ||
x.Value.Prefab.Contains(search)).ToList();
maxCount = containers.Count;
foreach (var check in containers.Skip(page * lines).Take(lines))
{
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "0 1",
OffsetMin = $"{xSwitch} {ySwitch - height}",
OffsetMax = $"{xSwitch + width} {ySwitch}"
},
Image =
{
Color = HexToCuiColor("#161617")
}
}, Layer + ".Main", Layer + $".Panel.{ySwitch}");
#region Image
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "0 0",
OffsetMin = "5 5", OffsetMax = "55 55"
},
Image =
{
Color = HexToCuiColor("#0E0E10", 50)
}
}, Layer + $".Panel.{ySwitch}", Layer + $".Panel.{ySwitch}.Image");
container.Add(check.Value.GetImage("0 0", "1 1", "0 0", "0 0",
Layer + $".Panel.{ySwitch}.Image"));
#endregion
#region Prefab
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = "-500 -25", OffsetMax = "0 0 0 0"
},
Image =
{
Color = HexToCuiColor("#0E0E10", 50)
}
}, Layer + $".Panel.{ySwitch}", Layer + $".Panel.{ySwitch}.Prefab");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "5 0", OffsetMax = "0 0"
},
Text =
{
Text = $"{check.Value.Prefab}",
Align = TextAnchor.MiddleLeft,
FontSize = 12,
Font = "robotocondensed-regular.ttf",
Color = "1 1 1 0.5"
}
}, Layer + $".Panel.{ySwitch}.Prefab");
#endregion
#region Info
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "0 0",
OffsetMin = "70 0",
OffsetMax = "200 35"
},
Text =
{
Text = Msg(player, DefaultMultiplier, _config.DefaultContainerMultiplier),
Align = TextAnchor.MiddleLeft,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 0.5"
}
}, Layer + $".Panel.{ySwitch}");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "0 0",
OffsetMin = "260 0",
OffsetMax = "400 35"
},
Text =
{
Text = Msg(player, CustomMultiplier, check.Value.Multiplier),
Align = TextAnchor.MiddleLeft,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 0.5"
}
}, Layer + $".Panel.{ySwitch}");
#endregion
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "1 0", AnchorMax = "1 0",
OffsetMin = "-90 7.5", OffsetMax = "-10 27.5"
},
Text =
{
Text = Msg(player, SettingsTitle),
Align = TextAnchor.MiddleCenter,
FontSize = 14,
Font = "robotocondensed-regular.ttf",
Color = "1 1 1 1"
},
Button =
{
Color = HexToCuiColor("#4B68FF"),
Command =
$"{CMD_Main_Console} settings {type} {category} {(string.IsNullOrEmpty(search) ? page : 0)} {check.Value.ID}"
}
}, Layer + $".Panel.{ySwitch}");
ySwitch = ySwitch - height - margin;
}
#endregion
break;
}
}
#region Pages
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0.5 0", AnchorMax = "0.5 0",
OffsetMin = "-50 5", OffsetMax = "50 25"
},
Image =
{
Color = HexToCuiColor("#161617")
}
}, Layer + ".Main", Layer + ".Pages");
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "0 0",
AnchorMax = "0 1",
OffsetMin = "-20 0",
OffsetMax = "0 0"
},
Text =
{
Text = Msg(player, BtnBack),
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 10,
Color = "1 1 1 0.95"
},
Button =
{
Color = HexToCuiColor("#4B68FF", 33),
Command = page != 0 ? $"{CMD_Main_Console} page {type} {category} {pa
// ... [Code preview truncated due to length. Full source in attached file] ...