C#:
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Core.Configuration;
namespace Oxide.Plugins {
[Info("StacksExtended", "Fujikura", "1.3.6", ResourceId = 35)]
class StacksExtended : RustPlugin {
bool Changed = false;
bool Initialized = false;
bool _loaded = false;
bool _savedDefaults = false;
bool _hasFurnaceSplitter = false;
Plugin _furnaceSplitter = null;
List<string> itemCategories = new List<string> ();
List<object> itemStackExcludes = new List<object>();
List<string> storageNames = new List<string>();
Dictionary<string, List<string>> registeredPermissions = new Dictionary<string, List<string>> ();
Dictionary<string, object> containerStacks = new Dictionary<string, object>();
Dictionary<string, object> containerVIP = new Dictionary<string, object>();
Dictionary<string, object> itemStackDefaults = new Dictionary<string, object>();
Dictionary<string, object> contStackDefaults = new Dictionary<string, object>();
Dictionary<string, object> containerItemOverrides = new Dictionary<string, object>();
Dictionary<string, object> playerInventoryItemOverrides = new Dictionary<string, object>();
int commandsAuthLevel;
bool limitPlayerInventory;
int playerInventoryStacklimit;
bool beltAntiToolWeaponStack;
bool blockDifferentSkinStacks;
bool blockModdedWeaponStacks;
bool blockUnequalAmmoWeaponStacks;
bool enableProjectileWeaponStacks;
bool enableLiquidContainerStacks;
bool enableItemStackOverrides;
bool globalDisableExtraFeatures;
DynamicConfigFile defaultStacks;
DynamicConfigFile getFile(string file) => Interface.Oxide.DataFileSystem.GetDatafile($"{file}");
bool chkFile(string file) => Interface.Oxide.DataFileSystem.ExistsDatafile($"{file}");
static List<object> defaultItemExcludes() {
var dp = new List<object>();
dp.Add("water");
dp.Add("water.salt");
dp.Add("blood");
dp.Add("blueprintbase");
dp.Add("coal");
dp.Add("flare");
dp.Add("generator.wind.scrap");
dp.Add("battery.small");
dp.Add("building.planner");
dp.Add("door.key");
dp.Add("map");
dp.Add("note");
dp.Add("hat.candle");
dp.Add("hat.miner");
return dp;
}
object GetConfig(string menu, string datavalue, object defaultValue) {
var data = Config[menu] as Dictionary<string, object>;
if (data == null) {
data = new Dictionary<string, object>();
Config[menu] = data;
Changed = true;
}
object value;
if (!data.TryGetValue(datavalue, out value)) {
value = defaultValue;
data[datavalue] = value;
Changed = true;
}
return value;
}
void LoadVariables() {
itemStackExcludes = (List<object>)GetConfig("Settings", "ExcludedItems", defaultItemExcludes());
containerStacks = (Dictionary<string, object>)GetConfig("Storages", "Stack", new Dictionary<string, object>());
containerVIP = (Dictionary<string, object>)GetConfig("Storages", "VIP", new Dictionary<string, object>());
commandsAuthLevel = Convert.ToInt32(GetConfig("Settings", "commandsAuthLevel", 2));
limitPlayerInventory = Convert.ToBoolean(GetConfig("Settings", "limitPlayerInventory", false));
enableItemStackOverrides = Convert.ToBoolean(GetConfig("Settings", "enableItemStackOverrides", true));
playerInventoryStacklimit = Convert.ToInt32(GetConfig("Settings", "playerInventoryStacklimit", 0));
blockDifferentSkinStacks = Convert.ToBoolean(GetConfig("ExtraFeatures", "blockDifferentSkinStacks", true));
beltAntiToolWeaponStack = Convert.ToBoolean(GetConfig("ExtraFeatures", "beltAntiToolWeaponStack", true));
blockModdedWeaponStacks = Convert.ToBoolean(GetConfig("ExtraFeatures", "blockModdedWeaponStacks", true));
enableProjectileWeaponStacks = Convert.ToBoolean(GetConfig("ExtraFeatures", "enableProjectileWeaponStacks", false));
blockUnequalAmmoWeaponStacks = Convert.ToBoolean(GetConfig("ExtraFeatures", "blockUnequalAmmoWeaponStacks", true));
enableLiquidContainerStacks = Convert.ToBoolean(GetConfig("ExtraFeatures", "enableLiquidContainerStacks", true));
globalDisableExtraFeatures = Convert.ToBoolean(GetConfig("ExtraFeatures", "globalDisableExtraFeatures", false));
containerItemOverrides = (Dictionary<string, object>)GetConfig("StackOverrides", "Storages", new Dictionary<string, object>());
playerInventoryItemOverrides = (Dictionary<string, object>)GetConfig("StackOverrides", "PlayerInventory", new Dictionary<string, object>());
var configremoval = false;
if ((Config.Get("Settings") as Dictionary<string, object>).ContainsKey("clearOnReboot")) {
(Config.Get("Settings") as Dictionary<string, object>).Remove("clearOnReboot");
configremoval = true;
}
if ((Config.Get("Settings") as Dictionary<string, object>).ContainsKey("enableExtendedStackMove")) {
(Config.Get("Settings") as Dictionary<string, object>).Remove("enableExtendedStackMove");
configremoval = true;
}
if (!Changed && !configremoval) return;
SaveConfig();
Changed = false;
}
protected override void LoadDefaultConfig() {
Config.Clear();
LoadVariables();
}
void Init() => LoadVariables();
void OnTerrainInitialized() {
_loaded = true;
ItemManager.GetItemDefinitions();
GetStackDefaults();
}
void OnServerInitialized() {
if (globalDisableExtraFeatures) {
Unsubscribe(nameof(CanStackItem));
Unsubscribe(nameof(OnItemSplit));
Unsubscribe(nameof(OnItemAction));
}
else {
Subscribe(nameof(CanStackItem));
Subscribe(nameof(OnItemSplit));
Subscribe(nameof(OnItemAction));
}
if (globalDisableExtraFeatures) Unsubscribe(nameof(CanMoveItem));
else Subscribe(nameof(CanMoveItem));
if(enableItemStackOverrides) Subscribe(nameof(OnMaxStackable));
else Unsubscribe(nameof(OnMaxStackable));
var storages = Resources.FindObjectsOfTypeAll<GameObject>().Where(lc => lc.GetComponent<StorageContainer>() != null && lc.GetComponent<LootContainer>() == null && !lc.GetComponent<StorageContainer>().ShortPrefabName.Contains("_static")).GroupBy(l => l.GetComponent<StorageContainer>().ShortPrefabName).Select(g => g.First()).ToList().Select(lc => lc.GetComponent<BaseEntity>()).ToList();
storageNames = storages.Select(lc => lc.GetComponent<StorageContainer>().ShortPrefabName.Replace(".deployed", "").Replace("_deployed", "")).ToList();
CreateContainerVIP(storages);
CreateContainerStacks(storages);
if(Config.Get("StackLimits") != null) StackLoad();
else StackDefaults();
CreatePermissions();
UpdateContainerStacks();
UpdateQuarryVIP();
if (limitPlayerInventory && playerInventoryStacklimit >= 0) {
foreach(var player in BasePlayer.activePlayerList) UpdatePlayer(player);
foreach(var player in BasePlayer.sleepingPlayerList) UpdatePlayer(player);
}
foreach(var player in BasePlayer.activePlayerList) LimitWear(player);
foreach(var player in BasePlayer.sleepingPlayerList) LimitWear(player);
storages.Clear();
LoadStackDefaults();
if (plugins.Exists("FurnaceSplitter")) {
_hasFurnaceSplitter = true;
_furnaceSplitter = plugins.Find("FurnaceSplitter");
}
Initialized = true;
}
void OnPluginUnloaded(Plugin name) {
if (name.Name == "FurnaceSplitter") {
_hasFurnaceSplitter = false;
_furnaceSplitter = null;
}
}
void OnPluginLoaded(Plugin name) {
if (name.Name == "FurnaceSplitter") {
_hasFurnaceSplitter = true;
_furnaceSplitter = name;
}
}
bool DisableExtraFeatures() => globalDisableExtraFeatures;
bool IsPlayerInv(PlayerInventory inv, uint cid) {
return inv.containerMain.uid == cid || inv.containerBelt.uid == cid || inv.containerWear.uid == cid;
}
bool HasActiveSplitter(PlayerInventory inv, uint cid, Item item) {
if (!_hasFurnaceSplitter || !inv.loot.IsLooting() || !(inv.loot.entitySource is BaseOven)) return false;
BasePlayer player = inv.GetComponent<BasePlayer>();
if (player) {
var isEnabled = _furnaceSplitter.CallHook("GetEnabled", player);
if (isEnabled is bool) return (bool)isEnabled;
}
var looters = _furnaceSplitter.CallHook("GetLooters", inv.loot.entitySource as BaseOven);
if (looters != null && (looters as List<BasePlayer>).Contains(player)) return true;
if (looters != null && inv.loot.entitySource == item.GetRootContainer()?.entityOwner) return true;
return false;
}
void GetStackDefaults() {
itemStackDefaults = new Dictionary<string, object>();
contStackDefaults = new Dictionary<string, object>();
foreach (var item in ItemManager.GetItemDefinitions()) itemStackDefaults.Add(item.shortname, item.stackable);
var filter = Oxide.Game.Rust.RustExtension.Filter.ToList();
filter.Add("[BUNDLE] Not found in bundle");
Oxide.Game.Rust.RustExtension.Filter = filter.ToArray();
var allStorages = Resources.FindObjectsOfTypeAll<GameObject>().Where(lc => lc.GetComponent<StorageContainer>() != null).ToList();
filter = Oxide.Game.Rust.RustExtension.Filter.ToList();
filter.Remove("[BUNDLE] Not found in bundle");
Oxide.Game.Rust.RustExtension.Filter = filter.ToArray();
foreach (var storage in allStorages) {
if (storage.GetComponent<LootContainer>() != null) continue;
var name = storage.GetComponent<BaseEntity>().ShortPrefabName.Replace(".deployed", "").Replace("_deployed", "");
if (name.EndsWith("_static")) continue;
if (!contStackDefaults.ContainsKey(name)) contStackDefaults.Add(name, storage.GetComponent<StorageContainer>().maxStackSize);
}
defaultStacks = getFile($"{this.Title}_defaults");
defaultStacks.Clear();
defaultStacks.Set("ItemStacks", itemStackDefaults);
defaultStacks.Set("ContainerStacks", contStackDefaults);
defaultStacks.Save();
_savedDefaults = true;
}
void LoadStackDefaults() {
if (itemStackDefaults == null || contStackDefaults == null || itemStackDefaults.Count == 0 || contStackDefaults.Count == 0) {
itemStackDefaults = new Dictionary<string, object>();
contStackDefaults = new Dictionary<string, object>();
defaultStacks = getFile($"{this.Title}_defaults");
itemStackDefaults = defaultStacks["ItemStacks"] as Dictionary<string, object>;
contStackDefaults = defaultStacks["ContainerStacks"] as Dictionary<string, object>;
}
if (itemStackDefaults != null && contStackDefaults != null && itemStackDefaults.Count > 0 && contStackDefaults.Count > 0) _savedDefaults = true;
}
void LimitWear(BasePlayer player) {
var inv = player.inventory;
if (inv != null) {
inv.containerWear.maxStackSize = 1;
inv.ServerUpdate(0f);
}
}
object CanStackItem(Item thisI, Item item) {
bool validTask = item != thisI && thisI.info.stackable > 1 && item.info.stackable > 1 && item.info.itemid == thisI.info.itemid && (!thisI.hasCondition || thisI.condition == thisI.maxCondition) && (!item.hasCondition || item.condition == item.maxCondition) && thisI.IsValid() && (!thisI.IsBlueprint() || thisI.blueprintTarget == item.blueprintTarget);
if (!validTask) return false;
if (thisI.GetHeldEntity() && thisI.GetHeldEntity() is BaseLiquidVessel) {
if (!enableLiquidContainerStacks) return false;
if (thisI.contents != null && item.contents != null && (thisI.contents.itemList.Count != item.contents.itemList.Count || (thisI.contents.itemList.Count > 0 && item.contents.itemList.Count > 0 && thisI.contents.itemList[0].amount != item.contents.itemList[0].amount))) return false;
}
if (blockModdedWeaponStacks || blockUnequalAmmoWeaponStacks) {
var targetProjectile = thisI.GetHeldEntity() as BaseProjectile;
var sourceProjectile = item.GetHeldEntity() as BaseProjectile;
if (!enableProjectileWeaponStacks && (targetProjectile != null || sourceProjectile != null)) return false;
if (blockModdedWeaponStacks && (targetProjectile != null && thisI.contents?.itemList?.Count > 0 || sourceProjectile != null && item.contents?.itemList?.Count > 0)) return false;
if (blockUnequalAmmoWeaponStacks && sourceProjectile != null && targetProjectile != null) {
if (targetProjectile.primaryMagazine.contents != sourceProjectile.primaryMagazine.contents) return false;
if (targetProjectile.primaryMagazine.ammoType != sourceProjectile.primaryMagazine.ammoType) return false;
}
}
if (beltAntiToolWeaponStack && thisI.info == item.info && thisI.parent.HasFlag((ItemContainer.Flag)4) && thisI.GetHeldEntity() != null && thisI.GetHeldEntity() is AttackEntity && !(thisI.GetHeldEntity() is ThrownWeapon) && !(item.GetHeldEntity() is MedicalTool)) return false;
if (thisI.skin != 0uL || item.skin != 0uL) {
if (thisI.skin != item.skin && blockDifferentSkinStacks) return false;
if (thisI.hasCondition && item.hasCondition && item.condition != thisI.condition) return false;
return true;
}
return null;
}
object CanMoveItem(Item item, PlayerInventory inv, uint num, int num2, int num3) {
ItemContainer itemContainer = inv.FindContainer(num);
if (itemContainer == null) return null;
if (HasActiveSplitter(inv, num, item)) return null;
if (globalDisableExtraFeatures) return null;
if (!CanMoveItemsFrom(inv, item.parent.entityOwner, item)) return null;
if ((item.parent != null && item.parent.IsLocked()) || itemContainer.IsLocked() || itemContainer.PlayerItemInputBlocked()) return null;
if (item.parent != null && itemContainer != item.parent) {
if (itemContainer.HasFlag((ItemContainer.Flag)4) && (item.amount > 1 && item.GetHeldEntity() != null && item.GetHeldEntity() is AttackEntity && !(item.GetHeldEntity() is ThrownWeapon) && !(item.GetHeldEntity() is MedicalTool)) ) {
if (item.amount > 1 && inv.containerBelt.SlotTaken(num2)) return false;
if (inv.containerBelt.SlotTaken(num2) && inv.containerBelt.GetSlot(num2).info == item.info) return null;
Item item2 = item.SplitItem(1);
if (!item2.MoveToContainer(inv.containerBelt, num2, false)) if(!item2.MoveToContainer(inv.containerBelt, -1, false)) inv.GiveItem(item2, null);
inv.ServerUpdate(0f);
return false;
}
else {
if (itemContainer.SlotTaken(num2)) {
var slot = itemContainer.GetSlot(num2);
if (slot.info == item.info && !slot.CanStack(item)) return false;
if (slot.amount > 1 && slot.GetHeldEntity() != null && slot.GetHeldEntity() is AttackEntity && !(slot.GetHeldEntity() is ThrownWeapon) && !(slot.GetHeldEntity() is MedicalTool)) return false;
}
}
}
if (num3 <= 0) num3 = item.amount;
num3 = Mathf.Clamp(num3, 1, (enableItemStackOverrides ? GetMaxStackable(item, itemContainer) : item.info.stackable));
if (num == 0u) {
inv.GiveItem(item, null);
return false;
}
if (item.amount > num3) {
Item item2 = item.SplitItem(num3);
if (!item2.MoveToContainer(itemContainer, num2, true)) {
item.amount += item2.amount;
item2.Remove(0f);
}
ItemManager.DoRemoves();
inv.ServerUpdate(0f);
return true;
}
if (!item.MoveToContainer(itemContainer, num2, true)) return false;
ItemManager.DoRemoves();
inv.ServerUpdate(0f);
return true;
}
bool CanMoveItemsFrom(PlayerInventory inv, BaseEntity entity, Item item) {
StorageContainer storageContainer = entity as StorageContainer;
return !storageContainer || storageContainer.CanMoveFrom(inv.GetComponent<BasePlayer>(), item);
}
object OnItemAction(Item thisI, string action) {
if (thisI != null && thisI.GetHeldEntity() != null && thisI.GetHeldEntity() is BaseProjectile && thisI.amount > 1 && action == "unload_ammo") return false;
return null;
}
object OnItemSplit(Item thisI, int split_Amount) {
if (thisI.GetHeldEntity()) {
Item item = null;
if (thisI.GetHeldEntity() is BaseLiquidVessel) {
thisI.amount -= split_Amount;
item = ItemManager.CreateByItemID(thisI.info.itemid, 1, thisI.skin);
item.OnVirginSpawn();
item.amount = split_Amount;
if (thisI.contents != null && thisI.contents.itemList.Count > 0 && item.contents != null && item.contents.itemList.Count > 0) item.contents.itemList[0].amount = thisI.contents.itemList[0].amount;
}
if (thisI.GetHeldEntity() is BaseProjectile) {
thisI.amount -= split_Amount;
item = ItemManager.CreateByItemID(thisI.info.itemid, 1, thisI.skin);
item.amount = split_Amount;
(item.GetHeldEntity() as BaseProjectile).primaryMagazine.contents = (thisI.GetHeldEntity() as BaseProjectile).primaryMagazine.contents;
(item.GetHeldEntity() as BaseProjectile).SendNetworkUpdateImmediate(false);
}
if (thisI.skin != 0uL) item = ItemManager.CreateByItemID(thisI.info.itemid, 1, thisI.skin);
if (item != null) {
thisI.amount -= split_Amount;
thisI.MarkDirty();
item.amount = split_Amount;
item.OnVirginSpawn();
if (thisI.IsBlueprint()) item.blueprintTarget = thisI.blueprintTarget;
if (thisI.hasCondition) item.condition = thisI.condition;
item.MarkDirty();
return item;
}
}
else if (thisI.skin != 0uL) {
Item item = null;
item = ItemManager.CreateByItemID(thisI.info.itemid, 1, thisI.skin);
if (item != null) {
thisI.amount -= split_Amount;
thisI.MarkDirty();
item.amount = split_Amount;
item.OnVirginSpawn();
if (thisI.IsBlueprint()) item.blueprintTarget = thisI.blueprintTarget;
if (thisI.hasCondition) item.condition = thisI.condition;
item.MarkDirty();
return item;
}
}
return null;
}
object OnMaxStackable(Item item) {
if (item.parent == null || (int)item.parent.flags == 3) return null;
ItemContainer parent = item.parent;
if ((int)parent.flags == 1 || (int)parent.flags == 5) {
object itemLimitInv;
if (playerInventoryItemOverrides.TryGetValue(item.info.shortname, out itemLimitInv)) {
if (itemLimitInv is int) return (int)itemLimitInv;
}
}
else {
BaseEntity entity = parent.entityOwner;
if (entity != null) {
string prefab = entity.ShortPrefabName.Replace(".deployed", "").Replace("_deployed", "");
object itemLimitsCont;
if (containerItemOverrides.TryGetValue(prefab, out itemLimitsCont)) {
var itemLimits = itemLimitsCont as Dictionary<string, object>;
object itemLimit;
if (itemLimits != null && itemLimits.TryGetValue(item.info.shortname, out itemLimit)) {
if (itemLimit is int) return (int)itemLimit;
}
}
}
}
return null;
}
Int32 GetMaxStackable(Item item, ItemContainer container) {
if ((int)container.flags == 1 || (int)container.flags == 5) {
object itemLimitInv;
if (playerInventoryItemOverrides.TryGetValue(item.info.shortname, out itemLimitInv)) {
if (itemLimitInv is int) return (int)itemLimitInv;
}
}
else {
BaseEntity entity = container.entityOwner;
if (entity != null) {
string prefab = entity.ShortPrefabName.Replace(".deployed", "").Replace("_deployed", "");
object itemLimitsCont;
if (containerItemOverrides.TryGetValue(prefab, out itemLimitsCont)) {
var itemLimits = itemLimitsCont as Dictionary<string, object>;
object itemLimit;
if (itemLimits != null && itemLimits.TryGetValue(item.info.shortname, out itemLimit)) {
if (itemLimit is int) return (int)itemLimit;
}
}
}
}
return item.info.stackable;
}
void OnEntityBuilt(Planner planner, GameObject obj) {
if (planner == null || planner.GetOwnerPlayer() == null || obj.GetComponent<BaseEntity>() == null || obj.GetComponent<BaseEntity>().OwnerID == 0) return;
if (obj.GetComponent<BaseEntity>() is MiningQuarry) {
OnQuarryBuilt(planner, obj);
return;
}
BaseEntity entity = obj.GetComponent<BaseEntity>();
if (!(entity is StorageContainer)) return;
BasePlayer player = planner.GetOwnerPlayer();
if (player == null) return;
var name = entity.ShortPrefabName.Replace(".deployed", "").Replace("_deployed", "");
object containerLimit;
if (containerStacks.TryGetValue(name, out containerLimit)) {
if (entity.GetComponent<StorageContainer>().inventory.maxStackSize != (int)containerLimit) {
entity.GetComponent<StorageContainer>().inventory.maxStackSize = (int)containerLimit;
entity.GetComponent<StorageContainer>().maxStackSize = (int)containerLimit;
entity.SendNetworkUpdate();
}
if (entity.OwnerID != 0) {
object containerPerms;
if (containerVIP.TryGetValue(name, out containerPerms)) {
var perms = (Dictionary<string, object>)containerPerms;
if (!(bool)perms["Enabled"]) return;
foreach (var perm in ((Dictionary<string, object>)perms["Permissions"]).Reverse()) {
if ((int)containerLimit > 0 && (int)perm.Value >= 0 && (int)perm.Value > (int)containerLimit && permission.UserHasPermission(entity.OwnerID.ToString(), this.Title.ToLower()+"."+perm.Key)) {
entity.GetComponent<StorageContainer>().inventory.maxStackSize = (int)perm.Value;
entity.GetComponent<StorageContainer>().maxStackSize = (int)perm.Value;
entity.SendNetworkUpdate();
}
}
}
}
}
}
void OnQuarryBuilt(Planner planner, GameObject obj) {
BaseEntity entity = obj.GetComponent<BaseEntity>();
BasePlayer player = planner.GetOwnerPlayer();
if (player == null) return;
var hopper = (entity as MiningQuarry).hopperPrefab.instance;
object hopperLimit;
if (containerStacks.TryGetValue(hopper.ShortPrefabName, out hopperLimit)) {
if (hopper.GetComponent<StorageContainer>().inventory.maxStackSize != (int)hopperLimit) {
hopper.GetComponent<StorageContainer>().inventory.maxStackSize = (int)hopperLimit;
hopper.GetComponent<StorageContainer>().maxStackSize = (int)hopperLimit;
hopper.SendNetworkUpdate();
}
}
object hopperPerms;
if (containerVIP.TryGetValue(hopper.ShortPrefabName, out hopperPerms)) {
var perms = (Dictionary<string, object>)hopperPerms;
if (!(bool)perms["Enabled"]) return;
foreach (var perm in ((Dictionary<string, object>)perms["Permissions"]).Reverse()) {
if ((int)hopperLimit > 0 && (int)perm.Value >= 0 && (int)perm.Value > (int)hopperLimit && permission.UserHasPermission(entity.OwnerID.ToString(), this.Title.ToLower()+"."+perm.Key)) {
hopper.GetComponent<StorageContainer>().inventory.maxStackSize = (int)perm.Value;
hopper.GetComponent<StorageContainer>().maxStackSize = (int)perm.Value;
hopper.SendNetworkUpdate();
}
}
}
var fuelstorage = (entity as MiningQuarry).fuelStoragePrefab.instance;
object fuelstorageLimit;
if (containerStacks.TryGetValue(fuelstorage.ShortPrefabName, out fuelstorageLimit)) {
if (fuelstorage.GetComponent<StorageContainer>().inventory.maxStackSize != (int)fuelstorageLimit) {
fuelstorage.GetComponent<StorageContainer>().inventory.maxStackSize = (int)fuelstorageLimit;
fuelstorage.GetComponent<StorageContainer>().maxStackSize = (int)fuelstorageLimit;
fuelstorage.SendNetworkUpdate();
}
}
object fuelstoragePerms;
if (containerVIP.TryGetValue(fuelstorage.ShortPrefabName, out fuelstoragePerms)) {
var perms = (Dictionary<string, object>)fuelstoragePerms;
if (!(bool)perms["Enabled"]) return;
foreach (var perm in ((Dictionary<string, object>)perms["Permissions"]).Reverse()) {
if ((int)fuelstorageLimit > 0 && (int)perm.Value >= 0 && (int)perm.Value > (int)fuelstorageLimit && permission.UserHasPermission(entity.OwnerID.ToString(), this.Title.ToLower()+"."+perm.Key)) {
fuelstorage.GetComponent<StorageContainer>().inventory.maxStackSize = (int)perm.Value;
fuelstorage.GetComponent<StorageContainer>().maxStackSize = (int)perm.Value;
fuelstorage.SendNetworkUpdate();
}
}
}
}
void UpdatePlayer(BasePlayer player) {
player.inventory.containerMain.maxStackSize = (int)playerInventoryStacklimit;
player.inventory.containerBelt.maxStackSize = (int)playerInventoryStacklimit;
player.inventory.SendSnapshot();
}
void OnPlayerRespawned(BasePlayer player) {
if (player == null) return;
LimitWear(player);
if (limitPlayerInventory && playerInventoryStacklimit >= 0) UpdatePlayer(player);
}
void OnPlayerInit(BasePlayer player) {
if (player == null) return;
LimitWear(player);
if (limitPlayerInventory && playerInventoryStacklimit >= 0) UpdatePlayer(player);
}
void CreateContainerVIP(List<BaseEntity> storages) {
bool wasAdded = false;
foreach (var storage in storages) {
if (storage is Workbench) continue;
var name = storage.ShortPrefabName.Replace(".deployed", "").Replace("_deployed", "");
if (containerVIP.ContainsKey(name)) continue;
var dp = new Dictionary<string, object>();
dp.Add("Enabled", false);
dp.Add("Permissions", new Dictionary<string, object>() {
{
"vip1", 0
}
, {
"vip2", 0
}
, {
"vip3", 0
}
}
);
containerVIP.Add(name, dp);
wasAdded = true;
}
if (wasAdded) {
Config["Storages", "VIP"] = containerVIP;
SaveConfig();
}
}
void CreateContainerStacks(List<BaseEntity> storages) {
bool wasAdded = false;
foreach (var storage in storages) {
if (storage is Workbench) continue;
var name = storage.ShortPrefabName.Replace(".deployed", "").Replace("_deployed", "");
if (containerStacks.ContainsKey(name)) continue;
if (storage.GetComponent<StorageContainer>().inventorySlots > 0) {
containerStacks.Add(name, storage.GetComponent<StorageContainer>().maxStackSize);
wasAdded = true;
}
}
if (wasAdded) {
Config["Storages", "Stack"] = containerStacks;
SaveConfig();
}
}
void CreatePermissions() {
foreach (var permSet in containerVIP) {
var perms = (Dictionary<string, object>)permSet.Value;
if ((bool)perms["Enabled"]) {
foreach (var perm in ((Dictionary<string, object>)perms["Permissions"])) {
if (!registeredPermissions.ContainsKey(this.Title.ToLower()+"."+perm.Key)) registeredPermissions.Add(this.Title.ToLower()+"."+perm.Key, new List<string>());
if (!registeredPermissions[this.Title.ToLower()+"."+perm.Key].Contains(permSet.Key)) registeredPermissions[this.Title.ToLower()+"."+perm.Key].Add(permSet.Key);
if (!permission.PermissionExists(this.Title.ToLower()+"."+perm.Key)) permission.RegisterPermission(this.Title.ToLower()+"."+perm.Key, this);
}
}
}
}
Dictionary<string, int> UpdateContainerStacks() {
var entities = BaseNetworkable.serverEntities.Where(p => (p as BaseEntity).GetComponent<StorageContainer>() != null && (p as BaseEntity).GetComponent<LootContainer>() == null).Cast<BaseEntity>().ToList();
var counter = 0;
var vipcounter = 0;
var dp = new Dictionary<string, int>();
foreach (var entity in entities.ToList()) {
var name = entity.ShortPrefabName.Replace(".deployed", "").Replace("_deployed", "");
object containerLimit;
if (containerStacks.TryGetValue(name, out containerLimit)) {
if (entity.GetComponent<StorageContainer>().inventory.maxStackSize != (int)containerLimit) {
entity.GetComponent<StorageContainer>().inventory.maxStackSize = (int)containerLimit;
entity.GetComponent<StorageContainer>().maxStackSize = (int)containerLimit;
counter++;
entity.SendNetworkUpdate();
}
if (entity.OwnerID != 0) {
object containerPerms;
if (containerVIP.TryGetValue(name, out containerPerms)) {
var perms = (Dictionary<string, object>)containerPerms;
if ((bool)perms["Enabled"]) {
foreach (var perm in ((Dictionary<string, object>)perms["Permissions"]).Reverse()) {
if ((int)containerLimit > 0 && (int)perm.Value >= 0 && (int)perm.Value > (int)containerLimit && permission.UserHasPermission(entity.OwnerID.ToString(), this.Title.ToLower()+"."+perm.Key)) {
entity.GetComponent<StorageContainer>().inventory.maxStackSize = (int)perm.Value;
entity.GetComponent<StorageContainer>().maxStackSize = (int)perm.Value;
vipcounter++;
entity.SendNetworkUpdate();
}
}
}
}
}
}
}
dp.Add("counter", counter);
dp.Add("vipcounter", vipcounter);
return dp;
}
Dictionary<string, int> UpdateQuarryVIP() {
var entities = BaseNetworkable.serverEntities.Where(p => (p as BaseEntity) is MiningQuarry).Cast<BaseEntity>().ToList();
var hoppercounter = 0;
var fuelstoragecounter = 0;
var dp = new Dictionary<string, int>();
foreach (var entity in entities.ToList()) {
if (entity.OwnerID == 0) continue;
var hopper = (entity as MiningQuarry).hopperPrefab.instance;
object hopperPerms;
if (containerVIP.TryGetValue(hopper.ShortPrefabName, out hopperPerms)) {
var perms = (Dictionary<string, object>)hopperPerms;
if ((bool)perms["Enabled"]) {
foreach (var perm in ((Dictionary<string, object>)perms["Permissions"]).Reverse()) {
object containerLimit;
containerStacks.TryGetValue(hopper.ShortPrefabName, out containerLimit);
if ((int)containerLimit > 0 && (int)perm.Value >= 0 && (int)perm.Value > (int)containerLimit && permission.UserHasPermission(entity.OwnerID.ToString(), this.Title.ToLower()+"."+perm.Key)) {
hopper.GetComponent<StorageContainer>().inventory.maxStackSize = (int)perm.Value;
hopper.GetComponent<StorageContainer>().maxStackSize = (int)perm.Value;
hoppercounter++;
hopper.SendNetworkUpdate();
}
}
}
}
var fuelstorage = (entity as MiningQuarry).fuelStoragePrefab.instance;
object fuelstoragePerms;
if (containerVIP.TryGetValue(fuelstorage.ShortPrefabName, out fuelstoragePerms)) {
var perms = (Dictionary<string, object>)fuelstoragePerms;
if ((bool)perms["Enabled"]) {
foreach (var perm in ((Dictionary<string, object>)perms["Permissions"]).Reverse()) {
object containerLimit;
containerStacks.TryGetValue(fuelstorage.ShortPrefabName, out containerLimit);
if ((int)containerLimit > 0 && (int)perm.Value >= 0 && (int)perm.Value > (int)containerLimit && permission.UserHasPermission(entity.OwnerID.ToString(), this.Title.ToLower()+"."+perm.Key)) {
fuelstorage.GetComponent<StorageContainer>().inventory.maxStackSize = (int)perm.Value;
fuelstorage.GetComponent<StorageContainer>().maxStackSize = (int)perm.Value;
fuelstoragecounter++;
fuelstorage.SendNetworkUpdate();
}
}
}
}
}
dp.Add("hoppercounter", hoppercounter);
dp.Add("fuelstoragecounter", fuelstoragecounter);
return dp;
}
void StackDefaults() {
var itemList = ItemManager.GetItemDefinitions();
if (itemList == null || itemList.Count == 0) {
NextTick(StackDefaults);
return;
}
int i = 0;
foreach (var item in itemList) {
if (itemStackExcludes.Contains(item.shortname)) continue;
if (!enableProjectileWeaponStacks && item.GetComponent<ItemModEntity>()?.entityPrefab?.Get()?.GetComponent<BaseProjectile>() != null) continue;
Config["StackLimits", item.shortname] = item.stackable;
if (!itemCategories.Contains(item.category.ToString().ToLower())) itemCategories.Add(item.category.ToString().ToLower());
i++;
}
Config.Save();
Puts($"Created stacksize file with '{i}' items");
}
void StackLoad() {
bool dirty = false;
bool changed = false;
var itemList = ItemManager.itemList;
if (itemList == null || itemList.Count == 0) {
NextTick(StackDefaults);
return;
}
int c = 0;
foreach (var item in itemList) {
if (itemStackExcludes.Contains(item.shortname)) continue;
if (!enableProjectileWeaponStacks && item.GetComponent<ItemModEntity>()?.entityPrefab?.Get()?.GetComponent<BaseProjectile>() != null) continue;
if (Config["StackLimits", item.shortname] == null) {
Config["StackLimits", item.shortname] = item.stackable;
dirty = true;
}
if (item.stackable != (int)Config["StackLimits", item.shortname]) {
changed = true;
c++;
}
item.stackable = (int)Config["StackLimits", item.shortname];
if (!itemCategories.Contains(item.category.ToString().ToLower())) itemCategories.Add(item.category.ToString().ToLower());
}
if (changed && !_loaded) Puts($"Changed '{c}' stacks with new values");
if (!changed && !dirty) Puts("No stacksize changed");
if (dirty) Puts("Updated stacksize file with new items");
if (dirty) Config.Save();
}
[ConsoleCommand("se.reload")]
void ccmdReload(ConsoleSystem.Arg arg) {
if(arg.Connection != null && arg.Connection.authLevel < commandsAuthLevel) return;
LoadConfig();
LoadVariables();
NextTick(()=> {
var storages = Resources.FindObjectsOfTypeAll<StorageContainer>().Where(c => !c.isActiveAndEnabled && !c.GetComponent<LootContainer>()).Cast<BaseEntity>().Where(b => !b.ShortPrefabName.Contains("_static")).ToList();
CreateContainerVIP(storages);
CreateContainerStacks(storages);
storages.Clear();
if (limitPlayerInventory && playerInventoryStacklimit > 0) {
foreach(var player in BasePlayer.activePlayerList) UpdatePlayer(player);
foreach(var player in BasePlayer.sleepingPlayerList) UpdatePlayer(player);
}
StackLoad();
registeredPermissions.Clear();
CreatePermissions();
var containerUpdates = UpdateContainerStacks();
var quarryUpdates = UpdateQuarryVIP();
SendReply(arg, $"Config reloaded and {containerUpdates["counter"]} Storages updated");
SendReply(arg, $"VIP Changes > {containerUpdates["vipcounter"]} Storages | {quarryUpdates["hoppercounter"]} Quarry Output | {quarryUpdates["fuelstoragecounter"]} Quarry Fuel");
}
);
}
[ConsoleCommand("se.clearreload")]
private void ccmdStackReload(ConsoleSystem.Arg arg) {
if(arg.Connection != null && arg.Connection.authLevel < commandsAuthLevel) return;
if (!_savedDefaults) {
SendReply(arg, $"The defaults-backup gets only created at server startup.");
Config.Set("StackLimits", new Dictionary<string, object>());
Config["Storages", "Stack"] = new Dictionary<string, object>();
Config.Save();
SendReply(arg, $"Your stack and container limits are recreated of the defaults on next startup");
return;
}
if (arg.Args == null || arg.Args.Length != 1 || arg.Args[0] != "true") {
SendReply(arg, "Usage: clearreload true | Recreates item and container stacks of the defaults");
return;
}
var itemList = ItemManager.GetItemDefinitions();
foreach (var item in itemList) {
if (!itemStackDefaults.ContainsKey(item.shortname)) continue;
item.stackable = Convert.ToInt32(itemStackDefaults[item.shortname]);
}
Config.Set("StackLimits", itemStackDefaults);
foreach (var cont in containerStacks.ToList()) {
if (contStackDefaults.ContainsKey(cont.Key)) containerStacks[cont.Key] = Convert.ToInt32(contStackDefaults[cont.Key]);
}
Config["Storages", "Stack"] = containerStacks;
Config.Save();
var entities = BaseNetworkable.serverEntities.Where(p => (p as BaseEntity).GetComponent<StorageContainer>() != null && (p as BaseEntity).GetComponent<LootContainer>() == null).Cast<BaseEntity>().ToList();
var counter = 0;
var vipcounter = 0;
var dp = new Dictionary<string, int>();
foreach (var entity in entities) {
var name = entity.ShortPrefabName.Replace(".deployed", "").Replace("_deployed", "");
if (containerStacks.ContainsKey(name)) {
int old = entity.GetComponent<StorageContainer>().inventory.maxStackSize;
entity.GetComponent<StorageContainer>().inventory.maxStackSize = Convert.ToInt32(containerStacks[name]);
entity.GetComponent<StorageContainer>().maxStackSize = Convert.ToInt32(containerStacks[name]);
entity.SendNetworkUpdate();
}
}
SendReply(arg, "Item and Storage limits were succesfully reset to the defaults.");
}
[ConsoleCommand("se.stackcategory")]
void ccmdStackCategory(ConsoleSystem.Arg arg) {
if(arg.Connection != null && arg.Connection.authLevel < commandsAuthLevel) return;
bool noInput = false;
if (arg.Args == null || arg.Args.Length != 2) {
SendReply(arg, "Syntax Error: Requires 2 arguments.Example: resources 32000");
noInput = true;
}
if (arg.Args != null && arg.Args.Length > 1 && arg.Args[0].ToLower() != "all") foreach (var cat in itemCategories) {
if (cat.StartsWith(arg.Args[0].ToLower())) {
arg.Args[0] = cat;
break;
}
}
if (noInput || (arg.Args[0].ToLower() != "all" && !itemCategories.Contains(arg.Args[0].ToLower()))) {
string cats = "";
foreach (var cat in itemCategories) {
cats += cat+" ";
}
if (!noInput) SendReply(arg, $"Category '{arg?.Args[0]}' not found");
SendReply(arg, $"Categories: {cats}all");
return;
}
int i = 0;
var itemList = ItemManager.itemList;
foreach (var item in itemList) {
if(arg.Args[0].ToLower() != "all" && item.category.ToString().ToLower() != arg.Args[0].ToLower()) continue;
if (Config["StackLimits", item.shortname] == null) continue;
if (itemStackExcludes.Contains(item.shortname)) continue;
Config["StackLimits", item.shortname] = Convert.ToInt32(arg.Args[1]);
item.stackable = Convert.ToInt32(arg.Args[1]);
i++;
}
Config.Save();
foreach (var player in BasePlayer.activePlayerList.ToList()) player.inventory.ServerUpdate(0f);
SendReply(arg, $"The Stack Size of '{i}' stackable '{arg.Args[0]}' items has been set to '{arg.Args[1]}'");
}
[ConsoleCommand("se.stackitem")]
void ccmdStackItem(ConsoleSystem.Arg arg) {
if(arg.Connection != null && arg.Connection.authLevel < commandsAuthLevel) return;
bool noInput = false;
if (!arg.HasArgs(2)) {
SendReply(arg, "Syntax Error: Requires 2 arguments (shortname + number).Example: wood 32000");
return;
}
var itemDef = ItemManager.FindItemDefinition(arg.Args[0].ToLower());
if (itemDef == null) {
SendReply(arg, $"Item '{arg.Args[0]}' does not exist");
return;
}
if (itemStackExcludes.Contains(itemDef.shortname)) {
SendReply(arg, $"The provided item is excluded from stacking by the config");
return;
}
int limit = -1;
if (!int.TryParse(arg.Args[1], out limit)) {
SendReply(arg, $"You need to set any number greater then 0");
return;
}
else itemDef.stackable = limit;
Config["StackLimits", itemDef.shortname] = limit;
Config.Save();
SendReply(arg, $"The stacksize of '{arg.Args[0]}' has been set to '{limit}'");
}
[ConsoleCommand("se.ovaddinventory")]
void ccmdOverrideAddInventory(Console
// ... [Code preview truncated due to length. Full source in attached file] ...