Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of CraftFromContainersEvolved v1.0.3
CraftFromContainersEvolved.Core.dll
Decompiled 21 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("KodeMan")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2026 KodeMan")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3+bfaa1afefa5f05c6be8b24c474b2b23abced2cbf")] [assembly: AssemblyProduct("Craft From Containers Evolved")] [assembly: AssemblyTitle("CraftFromContainersEvolved.Core")] [assembly: AssemblyVersion("1.0.3.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CraftFromContainersEvolved.Core { public readonly struct AccessDecision { public static readonly AccessDecision Allow = new AccessDecision(allowed: true, DenyReason.None); public bool Allowed { get; } public DenyReason Reason { get; } private AccessDecision(bool allowed, DenyReason reason) { Allowed = allowed; Reason = reason; } public static AccessDecision Deny(DenyReason reason) { return new AccessDecision(allowed: false, reason); } } public enum AccessMode { Vanilla, WardStrict, OwnerStrict } public static class AccessPolicy { public static AccessDecision Evaluate(AccessMode mode, ContainerCandidate candidate, long playerId, bool includeWardPermitted) { if (!candidate.HasInventory) { return AccessDecision.Deny(DenyReason.NoInventory); } if (candidate.IsInUse) { return AccessDecision.Deny(DenyReason.InUse); } if (!candidate.TypeAllowed) { return AccessDecision.Deny(DenyReason.FilteredType); } if (!candidate.InRange) { return AccessDecision.Deny(DenyReason.OutOfRange); } if (candidate.Privacy switch { ContainerPrivacy.Public => 1, ContainerPrivacy.Private => (candidate.HasPiece && candidate.CreatorId == playerId) ? 1 : 0, _ => 0, } == 0) { if (candidate.Privacy != ContainerPrivacy.Private || !candidate.HasPiece) { return AccessDecision.Deny(DenyReason.OpenAccessDenied); } return AccessDecision.Deny(DenyReason.NotOwner); } if ((candidate.CheckGuardStone || mode >= AccessMode.WardStrict) && !candidate.WardAllows) { return AccessDecision.Deny(DenyReason.WardDenied); } if (mode == AccessMode.OwnerStrict) { bool num = candidate.HasPiece && candidate.CreatorId == playerId; bool flag = includeWardPermitted && candidate.InsideWard && candidate.WardAllows; if (!num && !flag) { if (!candidate.HasPiece) { return AccessDecision.Deny(DenyReason.NoCreator); } return AccessDecision.Deny(DenyReason.NotOwner); } } return AccessDecision.Allow; } } public sealed class ContainerCandidate { public bool HasInventory = true; public bool TypeAllowed = true; public bool InRange = true; public bool IsInUse; public bool HasPiece; public long CreatorId; public bool CheckGuardStone; public bool WardAllows = true; public bool InsideWard; public ContainerPrivacy Privacy = ContainerPrivacy.Public; } public enum ContainerPrivacy { Private, Group, Public } public enum DenyReason { None, NoInventory, InUse, FilteredType, OutOfRange, OpenAccessDenied, NotOwner, NoCreator, WardDenied } public static class PeerClaim { public static bool IsValid(long claimedPlayerId, long actualPlayerId) { if (claimedPlayerId != 0L && actualPlayerId != 0L) { return claimedPlayerId == actualPlayerId; } return false; } } public static class StackMath { public static int UsableStackCount(int stackSize, bool leaveOne) { if (stackSize <= 0) { return 0; } if (!leaveOne) { return stackSize; } return stackSize - 1; } public static int CountUsable(IReadOnlyList<int> stackSizes, bool leaveOne) { if (stackSizes == null) { return 0; } int num = 0; for (int i = 0; i < stackSizes.Count; i++) { num += UsableStackCount(stackSizes[i], leaveOne); } return num; } } }
CraftFromContainersEvolved.dll
Decompiled 21 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using CraftFromContainersEvolved.Core; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("KodeMan")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2026 KodeMan")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3+bfaa1afefa5f05c6be8b24c474b2b23abced2cbf")] [assembly: AssemblyProduct("Craft From Containers Evolved")] [assembly: AssemblyTitle("CraftFromContainersEvolved")] [assembly: AssemblyVersion("1.0.3.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CraftFromContainersEvolved { internal static class AccessGate { internal static bool TryGetDecision(Container container, long playerId, out AccessDecision decision) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) decision = AccessDecision.Deny((DenyReason)1); if ((Object)(object)container == (Object)null || playerId == 0L) { return false; } ContainerInfo containerInfo = ContainerInfo.FromContainer(container); Piece componentInParent = ((Component)container).GetComponentInParent<Piece>(); WardProbe.Probe(((Component)container).transform.position, playerId, out var wardAllows, out var insideWard); ContainerCandidate val = new ContainerCandidate { HasInventory = (container.GetInventory() != null), TypeAllowed = ContainerTypeFilter.IsAllowed(containerInfo.Name, containerInfo.IsWagon, containerInfo.IsShip, containerInfo.IsTombstone), InRange = true, IsInUse = container.IsInUse(), HasPiece = ((Object)(object)componentInParent != (Object)null), CreatorId = (((Object)(object)componentInParent != (Object)null) ? componentInParent.GetCreator() : 0), Privacy = containerInfo.Privacy, CheckGuardStone = containerInfo.CheckGuardStone, WardAllows = wardAllows, InsideWard = insideWard }; decision = AccessPolicy.Evaluate(PolicyState.EffectiveMode, val, playerId, PolicyState.EffectiveIncludeWardPermitted); return ((AccessDecision)(ref decision)).Allowed; } } internal static class ContainerRegistry { private static readonly List<Container> Containers = new List<Container>(); internal static int Count => Containers.Count; internal static void Add(Container container) { if (!((Object)(object)container == (Object)null)) { Containers.Add(container); ContainerScanner.Invalidate(); } } internal static void Remove(Container container) { if (!((Object)(object)container == (Object)null) && Containers.Remove(container)) { ContainerScanner.Invalidate(); } } internal static void Collect(Vector3 center, float range, List<Container> results) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) results.Clear(); if (Containers.Count == 0) { return; } float num = ((range > 0f) ? (range * range) : (-1f)); for (int num2 = Containers.Count - 1; num2 >= 0; num2--) { Container val = Containers[num2]; if ((Object)(object)val == (Object)null) { Containers.RemoveAt(num2); } else { if (!((Behaviour)val).isActiveAndEnabled) { continue; } if (num > 0f) { Vector3 val2 = ((Component)val).transform.position - center; if (((Vector3)(ref val2)).sqrMagnitude > num) { continue; } } results.Add(val); } } } } internal static class ContainerScanner { private const float MoveToleranceSquared = 0.25f; private const int CacheRefreshFrames = 30; private static readonly List<Container> Candidates = new List<Container>(); private static readonly List<Container> Allowed = new List<Container>(); private static Vector3 _cacheCenter; private static Vector3 _sortCenter; private static float _cacheRange = -1f; private static int _cacheRegistryCount = -1; private static int _cacheFrame = -2147483647; private static bool _cacheValid; internal static List<Container> GetAllowedContainers(Player player) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { Allowed.Clear(); return Allowed; } float effectiveRange = PolicyState.EffectiveRange; Vector3 position = ((Component)player).transform.position; if (_cacheValid && _cacheRegistryCount == ContainerRegistry.Count) { Vector3 val = position - _cacheCenter; if (!(((Vector3)(ref val)).sqrMagnitude > 0.25f) && !(Mathf.Abs(effectiveRange - _cacheRange) > 0.01f) && Time.frameCount - _cacheFrame <= 30) { return Allowed; } } ContainerRegistry.Collect(position, effectiveRange, Candidates); Allowed.Clear(); long playerID = player.GetPlayerID(); for (int i = 0; i < Candidates.Count; i++) { Container val2 = Candidates[i]; if (AccessGate.TryGetDecision(val2, playerID, out var decision)) { Allowed.Add(val2); } else if (ModConfig.Debug.Value) { CraftFromContainersEvolvedPlugin.Dbg("Skipping container " + ((Object)val2).name + ": " + ((object)((AccessDecision)(ref decision)).Reason/*cast due to .constrained prefix*/).ToString()); } } if (ModConfig.PullByDistance.Value && Allowed.Count > 1) { _sortCenter = position; Allowed.Sort(CompareByDistance); } _cacheCenter = position; _cacheRange = effectiveRange; _cacheRegistryCount = ContainerRegistry.Count; _cacheFrame = Time.frameCount; _cacheValid = true; return Allowed; } internal static void Invalidate() { _cacheValid = false; _cacheRegistryCount = -1; _cacheFrame = -2147483647; } private static int CompareByDistance(Container a, Container b) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)a).transform.position - _sortCenter; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; val = ((Component)b).transform.position - _sortCenter; return sqrMagnitude.CompareTo(((Vector3)(ref val)).sqrMagnitude); } } internal static class ContainerTypeFilter { internal static bool IsAllowed(string name, bool isWagon, bool isShip, bool isTombstone) { if (isShip && PolicyState.IgnoreShipContainers) { return false; } if (isWagon && PolicyState.IgnoreWagonContainers) { return false; } if (isTombstone && PolicyState.IgnoreTombstones) { return false; } string text = name ?? string.Empty; if (PolicyState.IgnorePrivateChests && text.StartsWith("piece_chest_private")) { return false; } if (PolicyState.IgnoreWoodChests && text.StartsWith("piece_chest_wood")) { return false; } if (PolicyState.IgnoreBlackMetalChests && text.StartsWith("piece_chest_blackmetal")) { return false; } if (PolicyState.IgnoreReinforcedChests && text.StartsWith("piece_chest") && !text.StartsWith("piece_chest_private") && !text.StartsWith("piece_chest_wood") && !text.StartsWith("piece_chest_blackmetal")) { return false; } return true; } } internal static class EnforcementSelfTest { private static readonly string[,] Targets = new string[12, 2] { { "ZDOMan", "RPC_ZDOData" }, { "ZDO", "Deserialize" }, { "ZDO", "set_OwnerRevision" }, { "ZDO", "set_DataRevision" }, { "ZDO", "SetOwnerInternal" }, { "Container", "RPC_RequestOpen" }, { "Container", "RPC_RequestStack" }, { "Container", "RPC_RequestTakeAll" }, { "PrivateArea", "IsEnabled" }, { "PrivateArea", "IsInside" }, { "PrivateArea", "IsPermitted" }, { "PrivateArea", "m_allAreas" } }; internal static void Run() { int length = Targets.GetLength(0); int num = 0; for (int i = 0; i < length; i++) { string text = Targets[i, 0]; string text2 = Targets[i, 1]; Type type = AccessTools.TypeByName(text); if ((!(text2 == "m_allAreas")) ? (type != null && AccessTools.Method(type, text2, (Type[])null, (Type[])null) != null) : (type != null && AccessTools.Field(type, text2) != null)) { num++; } else { CraftFromContainersEvolvedPlugin.Warn("Server enforcement target missing: " + text + "." + text2); } } length++; if (WardProbe.DelegatesReady) { num++; } else { CraftFromContainersEvolvedPlugin.Warn("Server enforcement target missing: ward probe delegates (PrivateArea reflection)."); } if (num == length) { CraftFromContainersEvolvedPlugin.LogMessage("Server enforcement targets resolved: " + num + "/" + length + "."); } else { CraftFromContainersEvolvedPlugin.Warn("Server enforcement targets resolved: " + num + "/" + length + ". Container write protection may be incomplete."); } } } internal static class InventoryUtil { private static readonly List<ItemData> StackBuffer = new List<ItemData>(); internal static int CountInContainers(IReadOnlyList<Container> containers, string sharedName, int quality, bool worldLevelBased, bool leaveOne) { int num = 0; for (int i = 0; i < containers.Count; i++) { Inventory val = (((Object)(object)containers[i] != (Object)null) ? containers[i].GetInventory() : null); if (val != null) { num += CountUsable(val, sharedName, quality, worldLevelBased, leaveOne); } } return num; } internal static int BestQualityCount(Player player, IReadOnlyList<Container> containers, string sharedName, int maxQuality, bool leaveOne) { int num = 0; Inventory inventory = ((Humanoid)player).GetInventory(); for (int i = 1; i <= maxQuality; i++) { int num2 = inventory.CountItems(sharedName, i, true) + CountInContainers(containers, sharedName, i, worldLevelBased: true, leaveOne); if (num2 > num) { num = num2; } } return num; } internal static int CountUsable(Inventory inventory, string sharedName, int quality, bool worldLevelBased, bool leaveOne) { if (!leaveOne) { return inventory.CountItems(sharedName, quality, worldLevelBased); } StackBuffer.Clear(); inventory.GetAllItems(sharedName, StackBuffer); int num = 0; for (int i = 0; i < StackBuffer.Count; i++) { ItemData val = StackBuffer[i]; if (val != null && val.m_shared != null && !(val.m_shared.m_name != sharedName) && (quality < 0 || val.m_quality == quality) && (!worldLevelBased || val.m_worldLevel >= Game.m_worldLevel) && val.m_stack > 1) { num += val.m_stack - 1; } } return num; } internal static int Consume(Inventory inventory, string sharedName, int quality, int amount) { if (inventory == null || amount <= 0) { return 0; } int num = inventory.CountItems(sharedName, quality, true); if (num <= 0) { return 0; } int num2 = Math.Min(num, amount); inventory.RemoveItem(sharedName, num2, quality, true); int num3 = inventory.CountItems(sharedName, quality, true); return num - num3; } internal static int ConsumeFromContainers(IReadOnlyList<Container> containers, string sharedName, int quality, int amount) { int num = amount; for (int i = 0; i < containers.Count; i++) { if (num <= 0) { break; } Container val = containers[i]; if (!((Object)(object)val == (Object)null)) { num -= Consume(val.GetInventory(), sharedName, quality, num); } } return amount - num; } } internal static class ModConfig { internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> Debug; internal static ConfigEntry<AccessMode> Mode; internal static ConfigEntry<bool> IncludeWardPermitted; internal static ConfigEntry<float> ContainerRange; internal static ConfigEntry<bool> ApplyToCrafting; internal static ConfigEntry<bool> ApplyToBuilding; internal static ConfigEntry<bool> PullByDistance; internal static ConfigEntry<bool> LeaveOne; internal static ConfigEntry<bool> IgnoreShipContainers; internal static ConfigEntry<bool> IgnoreWagonContainers; internal static ConfigEntry<bool> IgnoreWoodChests; internal static ConfigEntry<bool> IgnoreReinforcedChests; internal static ConfigEntry<bool> IgnoreBlackMetalChests; internal static ConfigEntry<bool> IgnorePrivateChests; internal static ConfigEntry<bool> IgnoreTombstones; internal static ConfigEntry<bool> ShowContainerCounts; internal static ConfigEntry<string> ResourceCostString; internal static ConfigEntry<string> ContainerAvailableColor; internal static ConfigEntry<string> InsufficientColor; internal static ConfigEntry<bool> EnforceServerPolicy; internal static ConfigEntry<bool> ServerEnforcement; internal static ConfigEntry<bool> EnforceModeOnWrites; internal static ConfigEntry<bool> LogDeniedAttempts; internal static ConfigEntry<bool> NotifyDeniedPlayers; internal static Color AvailableColor = new Color(1f, 0.92f, 0.02f, 1f); internal static Color MissingColor = new Color(1f, 0.25f, 0.25f, 1f); internal static void Init(ConfigFile config) { Enabled = config.Bind<bool>("General", "Enabled", true, "Enable this mod."); Debug = config.Bind<bool>("General", "Debug", false, "Log verbose diagnostics."); Mode = config.Bind<AccessMode>("Security", "AccessMode", (AccessMode)2, "Vanilla: only mirror the game's own container access checks.\nWardStrict: additionally never use containers inside an enabled ward without permission.\nOwnerStrict: only use containers created by you (plus ward-shared containers when enabled below)."); IncludeWardPermitted = config.Bind<bool>("Security", "IncludeWardPermitted", true, "In OwnerStrict mode, also allow containers inside an enabled ward you have permission in."); ContainerRange = config.Bind<float>("General", "ContainerRange", 10f, "Maximum distance to pull from."); ApplyToCrafting = config.Bind<bool>("General", "ApplyToCrafting", true, "Use container resources when crafting and upgrading."); ApplyToBuilding = config.Bind<bool>("General", "ApplyToBuilding", true, "Use container resources when building."); PullByDistance = config.Bind<bool>("General", "PullByDistance", true, "Pull from closest containers first."); LeaveOne = config.Bind<bool>("General", "LeaveOne", false, "Keep at least one item in every container stack. Recipes that would need the last item of a stack are treated as not craftable."); IgnoreShipContainers = config.Bind<bool>("Container Types", "IgnoreShipContainers", false, "Ignore containers on ships."); IgnoreWagonContainers = config.Bind<bool>("Container Types", "IgnoreWagonContainers", false, "Ignore containers on carts."); IgnoreWoodChests = config.Bind<bool>("Container Types", "IgnoreWoodChests", false, "Ignore wood chests."); IgnoreReinforcedChests = config.Bind<bool>("Container Types", "IgnoreReinforcedChests", false, "Ignore reinforced chests."); IgnoreBlackMetalChests = config.Bind<bool>("Container Types", "IgnoreBlackMetalChests", false, "Ignore black metal chests."); IgnorePrivateChests = config.Bind<bool>("Container Types", "IgnorePrivateChests", false, "Ignore personal chests."); IgnoreTombstones = config.Bind<bool>("Container Types", "IgnoreTombstones", true, "Ignore tombstones."); ShowContainerCounts = config.Bind<bool>("UI", "ShowContainerCounts", true, "Show combined player and container resource counts in the crafting UI."); ResourceCostString = config.Bind<string>("UI", "ResourceCostString", "{0}/{1}", "{0} is the available amount including containers, {1} is the required amount."); ContainerAvailableColor = config.Bind<string>("UI", "ContainerAvailableColor", "FFEB04", "Hex colour used when a resource is only available in containers."); InsufficientColor = config.Bind<string>("UI", "InsufficientColor", "FF4040", "Hex colour used when a resource is missing entirely."); EnforceServerPolicy = config.Bind<bool>("Server", "EnforceServerPolicy", true, "When connected to a server running this mod, apply the server's security policy (clients may only be stricter, never looser)."); ServerEnforcement = config.Bind<bool>("Server", "ServerEnforcement", true, "When running on a server (host or dedicated), validate container writes and container RPCs server-side so modified clients cannot bypass access rules."); EnforceModeOnWrites = config.Bind<bool>("Server", "EnforceModeOnWrites", true, "Apply the AccessMode policy to container writes, not just the game's own checks. With OwnerStrict, only creators (and ward-permitted players) can modify a container. Set false for pure vanilla access parity."); LogDeniedAttempts = config.Bind<bool>("Server", "LogDeniedAttempts", true, "Log denied container writes and RPCs with player, position and reason (rate limited)."); NotifyDeniedPlayers = config.Bind<bool>("Server", "NotifyDeniedPlayers", true, "Send a message to modded clients when the server denies access to a container. Clients without the mod still get no message."); RefreshColors(); config.SettingChanged += delegate { RefreshColors(); }; } internal static void RefreshColors() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) AvailableColor = ParseColor((ContainerAvailableColor != null) ? ContainerAvailableColor.Value : null, new Color(1f, 0.92f, 0.02f, 1f)); MissingColor = ParseColor((InsufficientColor != null) ? InsufficientColor.Value : null, new Color(1f, 0.25f, 0.25f, 1f)); } private static Color ParseColor(string value, Color fallback) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(value)) { return fallback; } Color result = default(Color); if (!ColorUtility.TryParseHtmlString((value[0] == '#') ? value : ("#" + value), ref result)) { return fallback; } return result; } } internal sealed class ContainerInfo { internal bool IsContainer; internal ContainerPrivacy Privacy = (ContainerPrivacy)2; internal bool CheckGuardStone; internal string Name = string.Empty; internal bool IsShip; internal bool IsWagon; internal bool IsTombstone; internal static ContainerInfo FromContainer(Container container) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) GameObject gameObject = ((Component)container).gameObject; return new ContainerInfo { IsContainer = true, Privacy = (ContainerPrivacy)container.m_privacy, CheckGuardStone = container.m_checkGuardStone, Name = (((Object)gameObject).name ?? string.Empty), IsShip = ((Object)(object)gameObject.GetComponentInParent<Ship>() != (Object)null), IsWagon = ((Object)(object)container.m_wagon != (Object)null || (Object)(object)gameObject.GetComponentInParent<Vagon>() != (Object)null), IsTombstone = ((Object)(object)gameObject.GetComponentInParent<TombStone>() != (Object)null) }; } } internal static class PeerDirectory { internal static long GetPlayerId(long peerUid) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) if (peerUid == 0L) { return 0L; } ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return 0L; } if (peerUid == ZDOMan.GetSessionID()) { if (instance.IsServer() && instance.IsDedicated()) { return 0L; } PlayerProfile val = (((Object)(object)Game.instance != (Object)null) ? Game.instance.GetPlayerProfile() : null); if (val != null) { return val.GetPlayerID(); } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer != (Object)null)) { return 0L; } return localPlayer.GetPlayerID(); } ZNetPeer peer = instance.GetPeer(peerUid); if (peer == null) { return 0L; } ZNetScene instance2 = ZNetScene.instance; if ((Object)(object)instance2 != (Object)null) { GameObject val2 = instance2.FindInstance(peer.m_characterID); if ((Object)(object)val2 != (Object)null) { Player component = val2.GetComponent<Player>(); if ((Object)(object)component != (Object)null) { long playerID = component.GetPlayerID(); if (playerID != 0L) { return playerID; } } } } return peer.m_playerID; } internal static string GetPlayerName(long peerUid) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || peerUid == 0L) { return "unknown"; } ZNetPeer peer = instance.GetPeer(peerUid); if (peer != null && !string.IsNullOrEmpty(peer.m_playerName)) { return peer.m_playerName; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && peerUid == ZDOMan.GetSessionID()) { return localPlayer.GetPlayerName(); } return "unknown"; } } internal static class PrefabInfoCache { private static readonly Dictionary<int, ContainerInfo> Cache = new Dictionary<int, ContainerInfo>(); internal static ContainerInfo Get(int prefabHash) { if (prefabHash == 0) { return null; } if (Cache.TryGetValue(prefabHash, out var value)) { return value; } ContainerInfo containerInfo = Build(prefabHash); Cache[prefabHash] = containerInfo; return containerInfo; } private static ContainerInfo Build(int prefabHash) { ZNetScene instance = ZNetScene.instance; GameObject val = (((Object)(object)instance != (Object)null) ? instance.GetPrefab(prefabHash) : null); if ((Object)(object)val == (Object)null) { return null; } Container component = val.GetComponent<Container>(); if (!((Object)(object)component == (Object)null)) { return ContainerInfo.FromContainer(component); } return new ContainerInfo { IsContainer = false }; } } internal static class SenderContext { private static long _current; private static int _depth; internal static bool HasContext => _depth > 0; internal static long Current => _current; internal static void Push(long senderUid) { if (_depth == 0) { _current = senderUid; } _depth++; } internal static void Pop() { if (_depth <= 0) { _depth = 0; _current = 0L; return; } _depth--; if (_depth == 0) { _current = 0L; } } } internal static class ServerAccess { internal static AccessDecision Evaluate(ContainerInfo info, long creatorId, Vector3 position, long playerId) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (info == null || !info.IsContainer) { return AccessDecision.Allow; } WardProbe.Probe(position, playerId, out var wardAllows, out var insideWard); AccessMode val = (AccessMode)0; bool flag = false; if (creatorId != 0L && ModConfig.EnforceModeOnWrites.Value) { val = PolicyState.EffectiveMode; flag = PolicyState.EffectiveIncludeWardPermitted; } ContainerCandidate val2 = new ContainerCandidate { HasInventory = true, TypeAllowed = true, InRange = true, IsInUse = false, HasPiece = (creatorId != 0), CreatorId = creatorId, Privacy = info.Privacy, CheckGuardStone = info.CheckGuardStone, WardAllows = wardAllows, InsideWard = insideWard }; return AccessPolicy.Evaluate(val, val2, playerId, flag); } internal static AccessDecision EvaluateForContainer(Container container, long playerId) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)container == (Object)null) { return AccessDecision.Deny((DenyReason)1); } long num = 0L; ZNetView component = ((Component)container).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.GetZDO() != null) { num = component.GetZDO().GetLong(ZDOVars.s_creator, 0L); } if (num == 0L) { Piece componentInParent = ((Component)container).GetComponentInParent<Piece>(); if ((Object)(object)componentInParent != (Object)null) { num = componentInParent.GetCreator(); } } return Evaluate(ContainerInfo.FromContainer(container), num, ((Component)container).transform.position, playerId); } } internal static class ServerAudit { private const float Interval = 2f; private const float PruneAge = 60f; private const int PruneThreshold = 64; private static readonly Dictionary<string, float> LastEntry = new Dictionary<string, float>(); private static float _nextPrune; internal unsafe static void Denied(string action, long peerUid, string playerName, ZDO zdo, DenyReason reason) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if (ModConfig.LogDeniedAttempts != null && ModConfig.LogDeniedAttempts.Value) { float realtimeSinceStartup = Time.realtimeSinceStartup; Prune(realtimeSinceStartup); string key = action + "|" + peerUid; if (!LastEntry.TryGetValue(key, out var value) || !(realtimeSinceStartup - value < 2f)) { LastEntry[key] = realtimeSinceStartup; Vector3 val = ((zdo != null) ? zdo.GetPosition() : Vector3.zero); string[] obj = new string[10] { "Denied container ", action, " for ", playerName, " (peer ", peerUid.ToString(), ") at ", null, null, null }; Vector3 val2 = val; obj[7] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString(); obj[8] = ": "; obj[9] = ((object)(*(DenyReason*)(&reason))/*cast due to .constrained prefix*/).ToString(); CraftFromContainersEvolvedPlugin.Warn(string.Concat(obj)); } } } private static void Prune(float now) { if (LastEntry.Count < 64 || now < _nextPrune) { return; } _nextPrune = now + 60f; List<string> list = null; foreach (KeyValuePair<string, float> item in LastEntry) { if (now - item.Value > 60f) { if (list == null) { list = new List<string>(); } list.Add(item.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { LastEntry.Remove(list[i]); } } } } internal static class ServerGate { internal static bool IsActive { get { if (ModConfig.Enabled != null && ModConfig.Enabled.Value && ModConfig.ServerEnforcement != null && ModConfig.ServerEnforcement.Value && (Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } } internal static bool AllowZdoWrite(ZDO zdo, string action) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) if (!IsActive || !SenderContext.HasContext || zdo == null) { return true; } ContainerInfo containerInfo = PrefabInfoCache.Get(zdo.GetPrefab()); if (containerInfo == null || !containerInfo.IsContainer) { return true; } long current = SenderContext.Current; long playerId = PeerDirectory.GetPlayerId(current); if (playerId == 0L) { ServerAudit.Denied(action, current, PeerDirectory.GetPlayerName(current), zdo, (DenyReason)7); return false; } long creatorId = zdo.GetLong(ZDOVars.s_creator, 0L); AccessDecision val = ServerAccess.Evaluate(containerInfo, creatorId, zdo.GetPosition(), playerId); if (((AccessDecision)(ref val)).Allowed) { return true; } ServerAudit.Denied(action, current, PeerDirectory.GetPlayerName(current), zdo, ((AccessDecision)(ref val)).Reason); return false; } internal static bool AllowContainerRpc(Container container, long senderUid, long claimedPlayerId, string action) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (!IsActive || (Object)(object)container == (Object)null) { return true; } long playerId = PeerDirectory.GetPlayerId(senderUid); if (!PeerClaim.IsValid(claimedPlayerId, playerId)) { ServerAudit.Denied(action + ":spoofed-claim", senderUid, PeerDirectory.GetPlayerName(senderUid), GetZdo(container), (DenyReason)5); ServerNotifications.NotifyAccessDenied(senderUid, action); return false; } AccessDecision val = ServerAccess.EvaluateForContainer(container, playerId); if (((AccessDecision)(ref val)).Allowed) { return true; } ServerAudit.Denied(action, senderUid, PeerDirectory.GetPlayerName(senderUid), GetZdo(container), ((AccessDecision)(ref val)).Reason); ServerNotifications.NotifyAccessDenied(senderUid, action); return false; } internal static long PeerUidFromRpc(ZRpc rpc) { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null || rpc == null) { return 0L; } List<ZNetPeer> peers = instance.GetPeers(); if (peers == null) { return 0L; } for (int i = 0; i < peers.Count; i++) { ZNetPeer val = peers[i]; if (val != null && val.m_rpc == rpc) { return val.m_uid; } } return 0L; } private static ZDO GetZdo(Container container) { ZNetView component = ((Component)container).GetComponent<ZNetView>(); if (!((Object)(object)component != (Object)null)) { return null; } return component.GetZDO(); } } internal static class ServerNotifications { private const string DeniedRpc = "CFCE_AccessDenied"; private const float MessageCooldown = 2f; private static ZRoutedRpc _registeredInstance; private static float _nextMessageTime; internal static void EnsureRegistered() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null && instance != _registeredInstance) { instance.Register<string>("CFCE_AccessDenied", (Action<long, string>)OnAccessDenied); _registeredInstance = instance; } } internal static void NotifyAccessDenied(long targetPeerUid, string action) { if (ModConfig.NotifyDeniedPlayers.Value) { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(targetPeerUid, "CFCE_AccessDenied", new object[1] { action ?? string.Empty }); } } } private static void OnAccessDenied(long sender, string action) { if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { float time = Time.time; if (!(time < _nextMessageTime)) { _nextMessageTime = time + 2f; ((Character)localPlayer).Message((MessageType)2, "You do not have access to this container", 0, (Sprite)null, false); } } } } [HarmonyPatch(typeof(Container), "Awake")] internal static class ContainerAwakePatch { [HarmonyPostfix] private static void Postfix(Container __instance) { ContainerRegistry.Add(__instance); } } [HarmonyPatch(typeof(Container), "OnDestroyed")] internal static class ContainerDestroyedPatch { [HarmonyPostfix] private static void Postfix(Container __instance) { ContainerRegistry.Remove(__instance); } } [HarmonyPatch(typeof(Container), "RPC_RequestOpen")] internal static class ContainerOpenRpcGate { [HarmonyPrefix] private static bool Prefix(Container __instance, long uid, long playerID) { return ServerGate.AllowContainerRpc(__instance, uid, playerID, "open"); } } [HarmonyPatch(typeof(Container), "RPC_RequestStack")] internal static class ContainerStackRpcGate { [HarmonyPrefix] private static bool Prefix(Container __instance, long uid, long playerID) { return ServerGate.AllowContainerRpc(__instance, uid, playerID, "stack"); } } [HarmonyPatch(typeof(Container), "RPC_RequestTakeAll")] internal static class ContainerTakeAllRpcGate { [HarmonyPrefix] private static bool Prefix(Container __instance, long uid, long playerID) { return ServerGate.AllowContainerRpc(__instance, uid, playerID, "take-all"); } } [HarmonyPatch] internal static class InventoryGuiPatches { private sealed class TextRef { internal TMP_Text Text; } private static readonly ConditionalWeakTable<Transform, TextRef> AmountTextCache = new ConditionalWeakTable<Transform, TextRef>(); [HarmonyPostfix] [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] private static void SetupRequirement_Postfix(Transform elementRoot, Requirement req, Player player, bool craft, int quality, int craftMultiplier, bool __result) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) if (!__result || req == null || (Object)(object)req.m_resItem == (Object)null || (Object)(object)player == (Object)null || (Object)(object)elementRoot == (Object)null || !ModConfig.Enabled.Value || !ModConfig.ShowContainerCounts.Value || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return; } TMP_Text text = AmountTextCache.GetValue(elementRoot, CreateTextRef).Text; if ((Object)(object)text == (Object)null) { return; } int num = req.GetAmount(quality) * craftMultiplier; if (num > 0) { string name = req.m_resItem.m_itemData.m_shared.m_name; Inventory inventory = ((Humanoid)player).GetInventory(); int num2 = ((inventory != null) ? inventory.CountItems(name, -1, true) : 0); List<Container> allowedContainers = ContainerScanner.GetAllowedContainers(player); int num3 = num2 + InventoryUtil.CountInContainers(allowedContainers, name, -1, worldLevelBased: true, ModConfig.LeaveOne.Value); text.text = string.Format(CultureInfo.InvariantCulture, ModConfig.ResourceCostString.Value, num3, num); if (IsNoCostActive()) { ((Graphic)text).color = Color.white; } else if (num3 < num) { ((Graphic)text).color = ModConfig.MissingColor; } else if (num2 < num) { ((Graphic)text).color = ModConfig.AvailableColor; } else { ((Graphic)text).color = Color.white; } } } private static TextRef CreateTextRef(Transform elementRoot) { Transform val = elementRoot.Find("res_amount"); return new TextRef { Text = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<TMP_Text>() : null) }; } private static bool IsNoCostActive() { ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null) { return false; } if (!instance.GetGlobalKey((GlobalKeys)24)) { return instance.GetGlobalKey((GlobalKeys)25); } return true; } } [HarmonyPatch] internal static class PlayerPatches { [HarmonyPostfix] [HarmonyPatch(typeof(Player), "HaveRequirementItems")] private static void HaveRequirementItems_Postfix(Player __instance, Recipe piece, bool discover, int qualityLevel, int amount, ref bool __result) { if (__result || discover || (Object)(object)piece == (Object)null || (Object)(object)__instance == (Object)null || piece.m_requireOnlyOneIngredient || !ModConfig.Enabled.Value || !ModConfig.ApplyToCrafting.Value) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)__instance != (Object)(object)localPlayer)) { List<Container> allowedContainers = ContainerScanner.GetAllowedContainers(localPlayer); if (allowedContainers.Count != 0 && RequirementLogic.RecipeSatisfied(localPlayer, piece, qualityLevel, amount, allowedContainers)) { __result = true; } } } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] private static void HaveRequirements_Piece_Postfix(Player __instance, Piece piece, RequirementMode mode, ref bool __result) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if (__result || (int)mode != 0 || (Object)(object)piece == (Object)null || (Object)(object)__instance == (Object)null || !ModConfig.Enabled.Value || !ModConfig.ApplyToBuilding.Value) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)__instance != (Object)(object)localPlayer) && (!((Object)(object)piece.m_craftingStation != (Object)null) || !((Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)__instance).transform.position) == (Object)null) || ZoneSystem.instance.GetGlobalKey(piece.FreeBuildKey())) && (string.IsNullOrEmpty(piece.m_dlc) || DLCMan.instance.IsDLCInstalled(piece.m_dlc))) { List<Container> allowedContainers = ContainerScanner.GetAllowedContainers(localPlayer); if (allowedContainers.Count != 0 && RequirementLogic.PieceSatisfied(localPlayer, piece, allowedContainers)) { __result = true; } } } [HarmonyPrefix] [HarmonyPatch(typeof(Player), "ConsumeResources", new Type[] { typeof(Requirement[]), typeof(int), typeof(int), typeof(int) })] private static bool ConsumeResources_Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier) { if (requirements == null || requirements.Length == 0 || (Object)(object)__instance == (Object)null) { return true; } if (!ModConfig.Enabled.Value) { return true; } if (!ModConfig.ApplyToCrafting.Value && !ModConfig.ApplyToBuilding.Value) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)__instance != (Object)(object)localPlayer) { return true; } Inventory inventory = ((Humanoid)__instance).GetInventory(); if (inventory == null) { return true; } if (!NeedsContainers(__instance, inventory, requirements, qualityLevel, itemQuality, multiplier)) { return true; } List<Container> allowedContainers = ContainerScanner.GetAllowedContainers(localPlayer); ConsumeExactly(__instance, inventory, allowedContainers, requirements, qualityLevel, itemQuality, multiplier); return false; } [HarmonyPostfix] [HarmonyPatch(typeof(Player), "OnSpawned")] private static void OnSpawned_Postfix() { ServerPolicySync.RequestFromServer(); } private static bool NeedsContainers(Player player, Inventory inventory, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier) { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); foreach (Requirement val in requirements) { if (RequirementLogic.IncludeRequirement(currentCraftingStation, val)) { int num = val.GetAmount(qualityLevel) * multiplier; if (num > 0 && inventory.CountItems(RequirementLogic.GetSharedName(val), itemQuality, true) < num) { return true; } } } return false; } private static void ConsumeExactly(Player player, Inventory inventory, IReadOnlyList<Container> containers, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier) { CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); foreach (Requirement val in requirements) { if (!RequirementLogic.IncludeRequirement(currentCraftingStation, val)) { continue; } int num = val.GetAmount(qualityLevel) * multiplier; if (num > 0) { string sharedName = RequirementLogic.GetSharedName(val); int num2 = num - InventoryUtil.Consume(inventory, sharedName, itemQuality, num); if (num2 > 0 && containers.Count > 0) { num2 -= InventoryUtil.ConsumeFromContainers(containers, sharedName, itemQuality, num2); } if (num2 > 0) { CraftFromContainersEvolvedPlugin.Warn("Could not consume " + num2 + " " + sharedName + " for a craft; containers may have changed mid-frame."); } } } } } [HarmonyPatch(typeof(ZDOMan), "RPC_ZDOData")] internal static class ZdoDataSenderContextPatch { [HarmonyPrefix] private static void Prefix(ZRpc rpc) { if (ServerGate.IsActive) { long num = 0L; try { num = ServerGate.PeerUidFromRpc(rpc); } catch (Exception) { num = 0L; } SenderContext.Push(num); } } [HarmonyFinalizer] private static Exception Finalizer(Exception __exception) { SenderContext.Pop(); return __exception; } } [HarmonyPatch(typeof(ZDO), "Deserialize")] internal static class ZdoDeserializeWriteGate { [HarmonyPrefix] private static bool Prefix(ZDO __instance) { return ServerGate.AllowZdoWrite(__instance, "write"); } } [HarmonyPatch(typeof(ZDO), "set_OwnerRevision")] internal static class ZdoOwnerRevisionGate { [HarmonyPrefix] private static bool Prefix(ZDO __instance) { return ServerGate.AllowZdoWrite(__instance, "owner-revision"); } } [HarmonyPatch(typeof(ZDO), "set_DataRevision")] internal static class ZdoDataRevisionGate { [HarmonyPrefix] private static bool Prefix(ZDO __instance) { return ServerGate.AllowZdoWrite(__instance, "data-revision"); } } [HarmonyPatch(typeof(ZDO), "SetOwnerInternal")] internal static class ZdoOwnerChangeGate { [HarmonyPrefix] private static bool Prefix(ZDO __instance) { return ServerGate.AllowZdoWrite(__instance, "owner-change"); } } [BepInPlugin("CraftFromContainersEvolved", "Craft From Containers Evolved", "1.0.3")] public sealed class CraftFromContainersEvolvedPlugin : BaseUnityPlugin { public const string PluginGuid = "CraftFromContainersEvolved"; public const string PluginName = "Craft From Containers Evolved"; public const string PluginVersion = "1.0.3"; internal static CraftFromContainersEvolvedPlugin Instance; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ModConfig.Init(((BaseUnityPlugin)this).Config); _harmony = new Harmony("CraftFromContainersEvolved"); _harmony.PatchAll(); EnforcementSelfTest.Run(); ServerPolicySync.Init(); Log.LogInfo((object)"Craft From Containers Evolved 1.0.3 loaded."); } private void Update() { ServerPolicySync.Tick(); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); _harmony = null; } Instance = null; } internal static void Dbg(string message) { if (ModConfig.Debug != null && ModConfig.Debug.Value && Log != null) { Log.LogInfo((object)("[debug] " + message)); } } internal static void Warn(string message) { if (Log != null) { Log.LogWarning((object)message); } } internal static void LogMessage(string message) { if (Log != null) { Log.LogInfo((object)message); } } } internal static class PolicyState { internal static ServerPolicy Server; internal static bool ServerPolicyActive { get { if (ModConfig.EnforceServerPolicy != null && ModConfig.EnforceServerPolicy.Value) { return Server != null; } return false; } } internal static AccessMode EffectiveMode { get { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected I4, but got Unknown //IL_0024: Expected I4, but got Unknown //IL_0012: Unknown result type (might be due to invalid IL or missing references) AccessMode value = ModConfig.Mode.Value; if (!ServerPolicyActive) { return value; } return (AccessMode)Math.Max((int)value, (int)Server.Mode); } } internal static float EffectiveRange { get { float value = ModConfig.ContainerRange.Value; if (!ServerPolicyActive || Server.Range <= 0f) { return value; } if (!(value > 0f)) { return Server.Range; } return Math.Min(value, Server.Range); } } internal static bool EffectiveIncludeWardPermitted { get { bool value = ModConfig.IncludeWardPermitted.Value; if (!ServerPolicyActive) { return value; } if (value) { return Server.IncludeWardPermitted; } return false; } } internal static bool IgnoreShipContainers { get { if (!Local(ModConfig.IgnoreShipContainers)) { return ServerFlag((ServerPolicy p) => p.IgnoreShipContainers); } return true; } } internal static bool IgnoreWagonContainers { get { if (!Local(ModConfig.IgnoreWagonContainers)) { return ServerFlag((ServerPolicy p) => p.IgnoreWagonContainers); } return true; } } internal static bool IgnoreWoodChests { get { if (!Local(ModConfig.IgnoreWoodChests)) { return ServerFlag((ServerPolicy p) => p.IgnoreWoodChests); } return true; } } internal static bool IgnoreReinforcedChests { get { if (!Local(ModConfig.IgnoreReinforcedChests)) { return ServerFlag((ServerPolicy p) => p.IgnoreReinforcedChests); } return true; } } internal static bool IgnoreBlackMetalChests { get { if (!Local(ModConfig.IgnoreBlackMetalChests)) { return ServerFlag((ServerPolicy p) => p.IgnoreBlackMetalChests); } return true; } } internal static bool IgnorePrivateChests { get { if (!Local(ModConfig.IgnorePrivateChests)) { return ServerFlag((ServerPolicy p) => p.IgnorePrivateChests); } return true; } } internal static bool IgnoreTombstones { get { if (!Local(ModConfig.IgnoreTombstones)) { return ServerFlag((ServerPolicy p) => p.IgnoreTombstones); } return true; } } private static bool Local(ConfigEntry<bool> entry) { return entry?.Value ?? false; } private static bool ServerFlag(Func<ServerPolicy, bool> selector) { if (ServerPolicyActive) { return selector(Server); } return false; } } internal static class RequirementLogic { internal static bool IncludeRequirement(CraftingStation station, Requirement requirement) { if (requirement == null || (Object)(object)requirement.m_resItem == (Object)null) { return false; } if ((Object)(object)station != (Object)null) { if (station.m_upgrader != requirement.m_upgraderResource) { return false; } } else if (requirement.m_upgraderResource) { return false; } return true; } internal static string GetSharedName(Requirement requirement) { return requirement.m_resItem.m_itemData.m_shared.m_name; } internal static bool RecipeSatisfied(Player player, Recipe recipe, int qualityLevel, int craftMultiplier, IReadOnlyList<Container> containers) { if ((Object)(object)recipe == (Object)null || recipe.m_resources == null) { return false; } CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); bool requireOnlyOneIngredient = recipe.m_requireOnlyOneIngredient; bool value = ModConfig.LeaveOne.Value; for (int i = 0; i < recipe.m_resources.Length; i++) { Requirement val = recipe.m_resources[i]; if (!IncludeRequirement(currentCraftingStation, val)) { continue; } int num = val.GetAmount(qualityLevel) * craftMultiplier; if (InventoryUtil.BestQualityCount(player, containers, GetSharedName(val), val.m_resItem.m_itemData.m_shared.m_maxQuality, value) >= num) { if (requireOnlyOneIngredient) { return true; } } else if (!requireOnlyOneIngredient) { return false; } } return !requireOnlyOneIngredient; } internal static bool PieceSatisfied(Player player, Piece piece, IReadOnlyList<Container> containers) { if ((Object)(object)piece == (Object)null || piece.m_resources == null) { return false; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } bool value = ModConfig.LeaveOne.Value; for (int i = 0; i < piece.m_resources.Length; i++) { Requirement val = piece.m_resources[i]; if (IncludeRequirement(null, val) && val.m_amount > 0) { string sharedName = GetSharedName(val); if (inventory.CountItems(sharedName, -1, true) + InventoryUtil.CountInContainers(containers, sharedName, -1, worldLevelBased: true, value) < val.m_amount) { return false; } } } return true; } } internal sealed class ServerPolicy { internal AccessMode Mode = (AccessMode)2; internal float Range = 10f; internal bool IncludeWardPermitted = true; internal bool IgnoreShipContainers; internal bool IgnoreWagonContainers; internal bool IgnoreWoodChests; internal bool IgnoreReinforcedChests; internal bool IgnoreBlackMetalChests; internal bool IgnorePrivateChests; internal bool IgnoreTombstones = true; internal static ServerPolicy FromConfig() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return new ServerPolicy { Mode = ModConfig.Mode.Value, Range = ModConfig.ContainerRange.Value, IncludeWardPermitted = ModConfig.IncludeWardPermitted.Value, IgnoreShipContainers = ModConfig.IgnoreShipContainers.Value, IgnoreWagonContainers = ModConfig.IgnoreWagonContainers.Value, IgnoreWoodChests = ModConfig.IgnoreWoodChests.Value, IgnoreReinforcedChests = ModConfig.IgnoreReinforcedChests.Value, IgnoreBlackMetalChests = ModConfig.IgnoreBlackMetalChests.Value, IgnorePrivateChests = ModConfig.IgnorePrivateChests.Value, IgnoreTombstones = ModConfig.IgnoreTombstones.Value }; } internal string Serialize() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected I4, but got Unknown return string.Join("|", "CFCE1", ((int)Mode).ToString(CultureInfo.InvariantCulture), Range.ToString("0.##", CultureInfo.InvariantCulture), IncludeWardPermitted ? "1" : "0", IgnoreShipContainers ? "1" : "0", IgnoreWagonContainers ? "1" : "0", IgnoreWoodChests ? "1" : "0", IgnoreReinforcedChests ? "1" : "0", IgnoreBlackMetalChests ? "1" : "0", IgnorePrivateChests ? "1" : "0", IgnoreTombstones ? "1" : "0"); } internal static bool TryParse(string payload, out ServerPolicy policy) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) policy = null; if (string.IsNullOrEmpty(payload)) { return false; } string[] array = payload.Split(new char[1] { '|' }); if (array.Length < 4 || array[0] != "CFCE1") { return false; } if (!int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return false; } if (result < 0) { result = 0; } else if (result > 2) { result = 2; } float result2 = 10f; if (array.Length > 2) { float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out result2); } ServerPolicy serverPolicy = new ServerPolicy { Mode = (AccessMode)result, Range = result2, IncludeWardPermitted = IsTrue(array, 3), IgnoreShipContainers = IsTrue(array, 4), IgnoreWagonContainers = IsTrue(array, 5), IgnoreWoodChests = IsTrue(array, 6), IgnoreReinforcedChests = IsTrue(array, 7), IgnoreBlackMetalChests = IsTrue(array, 8), IgnorePrivateChests = IsTrue(array, 9), IgnoreTombstones = IsTrue(array, 10) }; policy = serverPolicy; return true; } private static bool IsTrue(string[] parts, int index) { if (parts.Length > index) { return parts[index] == "1"; } return false; } } internal static class ServerPolicySync { private const string RequestRpc = "CFCE_RequestPolicy"; private const string PolicyRpc = "CFCE_ServerPolicy"; private const float BroadcastInterval = 10f; private static ZRoutedRpc _registeredInstance; private static float _nextBroadcast; private static string _lastPayload; internal static void Init() { ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { if (instance != _registeredInstance) { instance.Register("CFCE_RequestPolicy", (Action<long>)OnPolicyRequested); instance.Register<string>("CFCE_ServerPolicy", (Action<long, string>)OnPolicyReceived); _registeredInstance = instance; } ServerNotifications.EnsureRegistered(); } } internal static void Tick() { if (_registeredInstance != null && !((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && !(Time.unscaledTime < _nextBroadcast)) { _nextBroadcast = Time.unscaledTime + 10f; string text = (PolicyState.Server = ServerPolicy.FromConfig()).Serialize(); if (!(text == _lastPayload)) { _lastPayload = text; ZRoutedRpc.instance.InvokeRoutedRPC("CFCE_ServerPolicy", new object[1] { text }); CraftFromContainersEvolvedPlugin.Dbg("Broadcast server policy: " + text); } } } internal static void RequestFromServer() { Init(); if (_registeredInstance == null || (Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsServer()) { return; } ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { long num = 1L; ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null) { num = serverPeer.m_uid; } instance.InvokeRoutedRPC(num, "CFCE_RequestPolicy", Array.Empty<object>()); CraftFromContainersEvolvedPlugin.Dbg("Requested server policy from peer " + num); } } private static void OnPolicyRequested(long sender) { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { _lastPayload = (PolicyState.Server = ServerPolicy.FromConfig()).Serialize(); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "CFCE_ServerPolicy", new object[1] { _lastPayload }); } } private static void OnPolicyReceived(long sender, string payload) { if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsServer() && ModConfig.EnforceServerPolicy.Value) { ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer == null || sender != serverPeer.m_uid) { CraftFromContainersEvolvedPlugin.Dbg("Ignored policy payload from non-server peer " + sender); return; } if (!ServerPolicy.TryParse(payload, out var policy)) { CraftFromContainersEvolvedPlugin.Warn("Ignored malformed server policy payload."); return; } PolicyState.Server = policy; ContainerScanner.Invalidate(); CraftFromContainersEvolvedPlugin.LogMessage("Applied server policy: " + payload); } } } internal static class WardProbe { private static readonly FieldInfo AllAreasField = AccessTools.Field(typeof(PrivateArea), "m_allAreas"); private static readonly FieldRef<List<PrivateArea>> AllAreasRef = ((AllAreasField != null) ? AccessTools.StaticFieldRefAccess<List<PrivateArea>>(AllAreasField) : null); private static readonly Func<PrivateArea, bool> IsEnabledDelegate = CreateDelegate<Func<PrivateArea, bool>>("IsEnabled"); private static readonly Func<PrivateArea, Vector3, float, bool> IsInsideDelegate = CreateDelegate<Func<PrivateArea, Vector3, float, bool>>("IsInside"); private static readonly Func<PrivateArea, long, bool> IsPermittedDelegate = CreateDelegate<Func<PrivateArea, long, bool>>("IsPermitted"); private static bool _fallbackLogged; internal static bool DelegatesReady { get { if ((AllAreasRef != null || AllAreasField != null) && IsEnabledDelegate != null && IsInsideDelegate != null) { return IsPermittedDelegate != null; } return false; } } internal static void Probe(Vector3 point, long playerId, out bool wardAllows, out bool insideWard) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) insideWard = false; wardAllows = true; List<PrivateArea> areas = GetAreas(); if (areas == null || IsEnabledDelegate == null || IsInsideDelegate == null || IsPermittedDelegate == null) { Fallback(point, playerId, ref wardAllows, ref insideWard); return; } bool flag = false; bool flag2 = false; for (int i = 0; i < areas.Count; i++) { PrivateArea val = areas[i]; if (!((Object)(object)val == (Object)null) && IsEnabledDelegate(val) && IsInsideDelegate(val, point, 0f)) { flag = true; insideWard = true; if (HasAccess(val, playerId)) { flag2 = true; break; } } } if (flag && !flag2) { wardAllows = false; } } private static List<PrivateArea> GetAreas() { if (AllAreasRef != null) { return AllAreasRef.Invoke(); } if (!(AllAreasField != null)) { return null; } return AllAreasField.GetValue(null) as List<PrivateArea>; } private static bool HasAccess(PrivateArea area, long playerId) { if (playerId == 0L) { return false; } Piece component = ((Component)area).GetComponent<Piece>(); if ((Object)(object)component != (Object)null && component.GetCreator() == playerId) { return true; } return IsPermittedDelegate(area, playerId); } private static void Fallback(Vector3 point, long playerId, ref bool wardAllows, ref bool insideWard) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; long num = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetPlayerID() : 0); if (!_fallbackLogged) { _fallbackLogged = true; CraftFromContainersEvolvedPlugin.Warn("Ward reflection unavailable; using reduced ward checks. Container access may be denied more strictly than intended."); } if (playerId != 0L && playerId == num) { wardAllows = PrivateArea.CheckAccess(point, 0f, false, false); insideWard = !wardAllows; } else { wardAllows = false; insideWard = true; } } private static T CreateDelegate<T>(string methodName) where T : class { MethodInfo methodInfo = AccessTools.Method(typeof(PrivateArea), methodName, (Type[])null, (Type[])null); if (methodInfo == null) { return null; } try { return methodInfo.CreateDelegate(typeof(T)) as T; } catch (Exception) { return null; } } } }