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 Cart Control v0.4.3
FrizzQOL.CartControl.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [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("FrizzQOL.CartControl")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+b5ff921dd55e0d4d16c1710703ae9d2ec02d8f4e")] [assembly: AssemblyProduct("FrizzQOL.CartControl")] [assembly: AssemblyTitle("FrizzQOL.CartControl")] [assembly: AssemblyVersion("1.0.0.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; } } } public static class CartRules { public const int MaxWidth = 8; public static int ResolveWidth(int config, int vanilla) { if (config <= 0) { return vanilla; } if (config > 8) { return 8; } return config; } public static int ResolveHeight(int config, int vanilla) { if (config > 0) { return config; } return vanilla; } public static float ResolveCartWeight(float config, float vanilla) { if (!(config < 0f)) { return config; } return vanilla; } public static float ResolveCargoPull(float config, float vanilla) { if (!(config < 0f)) { return config; } return vanilla; } public static float ResolvePullMass(float cartWeight, float vanillaCart, float cargoPull, float vanillaPull, float cargoWeight) { float num = ResolveCartWeight(cartWeight, vanillaCart); float num2 = ResolveCargoPull(cargoPull, vanillaPull); float num3 = ((cargoWeight > 0f) ? cargoWeight : 0f); return num + num3 * num2; } public static bool BlocksBreak(bool invincible) { return invincible; } public static bool? RemovalOverride(bool featureOn, bool isCart, bool inUse, bool duringWear) { if (duringWear || !featureOn || !isCart || inUse) { return null; } return true; } public static bool ShouldSpillCargo(bool featureOn, bool isCart, bool hammerRemove, bool blockDrop) { if (featureOn && isCart && hammerRemove) { return !blockDrop; } return false; } public static bool CanAddWeight(float currentWeight, float itemWeight, float maxWeight) { if (maxWeight <= 0f) { return true; } return currentWeight + itemWeight <= maxWeight; } } namespace CartControl { internal static class CartApplier { private static readonly FieldInfo ContainerWidth = AccessTools.Field(typeof(Container), "m_width"); private static readonly FieldInfo ContainerHeight = AccessTools.Field(typeof(Container), "m_height"); private static readonly FieldInfo InventoryWidth = AccessTools.Field(typeof(Inventory), "m_width"); private static readonly FieldInfo InventoryHeight = AccessTools.Field(typeof(Inventory), "m_height"); private static readonly MethodInfo UpdateMass = AccessTools.Method(typeof(Vagon), "UpdateMass", (Type[])null, (Type[])null); public static void Apply(Container container) { if ((Object)(object)container == (Object)null) { return; } Vagon componentInParent = ((Component)container).GetComponentInParent<Vagon>(); if ((Object)(object)componentInParent == (Object)null) { return; } CartCatalog.CartConfig cartConfig = CartCatalog.BindFromVagon(componentInParent); if (cartConfig == null) { return; } int num = CartRules.ResolveWidth(cartConfig.Width.Value, cartConfig.VanillaWidth); int num2 = CartRules.ResolveHeight(cartConfig.Height.Value, cartConfig.VanillaHeight); if (ContainerWidth != null) { ContainerWidth.SetValue(container, num); } if (ContainerHeight != null) { ContainerHeight.SetValue(container, num2); } Inventory inventory = container.GetInventory(); if (inventory != null) { if (InventoryWidth != null) { InventoryWidth.SetValue(inventory, num); } inventory.SetHeight(num2); if (InventoryHeight != null) { InventoryHeight.SetValue(inventory, num2); } CartCatalog.RegisterInventory(inventory, CartCatalog.PrefabName(((Component)componentInParent).gameObject)); } ApplyPull(componentInParent); if (AccessTools.Field(typeof(Vagon), "m_nview")?.GetValue(componentInParent) == null || UpdateMass == null) { return; } try { UpdateMass.Invoke(componentInParent, null); } catch (Exception ex) { Exception ex2 = ((ex is TargetInvocationException { InnerException: not null } ex3) ? ex3.InnerException : ex); Plugin.LogError("Cart pull weight was not applied: " + ex2.Message); } } public static void ApplyPull(Vagon cart) { if ((Object)(object)cart == (Object)null) { return; } CartCatalog.CartConfig cartConfig = CartCatalog.BindFromVagon(cart); if (cartConfig != null) { float cargoWeight = 0f; Container container = cart.m_container; if ((Object)(object)container != (Object)null && container.GetInventory() != null) { cargoWeight = container.GetInventory().GetTotalWeight(); } float num = CartRules.ResolveCartWeight(cartConfig.CartWeight.Value, cartConfig.VanillaCartWeight); float num2 = CartRules.ResolveCargoPull(cartConfig.CargoPull.Value, cartConfig.VanillaCargoPull); cart.m_baseMass = num; cart.m_itemWeightMassFactor = num2; Plugin.LogPull(cart, num, num2, CartRules.ResolvePullMass(cartConfig.CartWeight.Value, cartConfig.VanillaCartWeight, cartConfig.CargoPull.Value, cartConfig.VanillaCargoPull, cargoWeight)); } } public static void ApplyAllLoaded() { Container[] array = Object.FindObjectsByType<Container>((FindObjectsSortMode)0); if (array != null) { Container[] array2 = array; for (int i = 0; i < array2.Length; i++) { Apply(array2[i]); } } } } internal static class CartCatalog { internal sealed class CartConfig { public int VanillaWidth; public int VanillaHeight; public float VanillaCartWeight; public float VanillaCargoPull; public ConfigEntry<int> Width; public ConfigEntry<int> Height; public ConfigEntry<float> CartWeight; public ConfigEntry<float> CargoWeight; public ConfigEntry<float> CargoPull; } private static ConfigFile _config; private static readonly Dictionary<string, CartConfig> Entries = new Dictionary<string, CartConfig>(); private static readonly Dictionary<Inventory, string> Inventories = new Dictionary<Inventory, string>(); public static void Initialize(ConfigFile config) { _config = config; } public static void DiscoverFromScene(ZNetScene scene) { if (_config == null || (Object)(object)scene == (Object)null || !(AccessTools.Field(typeof(ZNetScene), "m_prefabs")?.GetValue(scene) is List<GameObject> list)) { return; } int num = 0; foreach (GameObject item in list) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item.GetComponent<Vagon>() == (Object)null) && Bind(item)) { num++; } } if (num > 0) { Plugin.LogInfo("Bound config for " + num + " carts."); } } public static CartConfig BindFromVagon(Vagon cart) { if ((Object)(object)cart == (Object)null) { return null; } Bind(((Component)cart).gameObject); return Get(PrefabName(((Component)cart).gameObject)); } public static CartConfig Get(string prefabName) { if (prefabName == null || !Entries.TryGetValue(prefabName, out var value)) { return null; } return value; } public static void RegisterInventory(Inventory inventory, string prefabName) { if (inventory != null && !string.IsNullOrEmpty(prefabName)) { Inventories[inventory] = prefabName; } } public static CartConfig GetForInventory(Inventory inventory) { if (inventory == null || !Inventories.TryGetValue(inventory, out var value)) { return null; } return Get(value); } public static string PrefabName(GameObject obj) { if ((Object)(object)obj == (Object)null) { return null; } string name = ((Object)obj).name; int num = name.IndexOf("(Clone)"); if (num < 0) { return name; } return name.Substring(0, num).Trim(); } private static bool Bind(GameObject cartObj) { string text = PrefabName(cartObj); if (string.IsNullOrEmpty(text) || _config == null || Entries.ContainsKey(text)) { return false; } Vagon component = cartObj.GetComponent<Vagon>(); Container val = (((Object)(object)component != (Object)null) ? component.m_container : null); if ((Object)(object)val == (Object)null) { val = cartObj.GetComponentInChildren<Container>(true); } int num = (((Object)(object)val != (Object)null) ? ReadInt(val, "m_width", 6) : 6); int num2 = (((Object)(object)val != (Object)null) ? ReadInt(val, "m_height", 3) : 3); float num3 = (((Object)(object)component != (Object)null) ? component.m_baseMass : 20f); float vanillaCargoPull = (((Object)(object)component != (Object)null) ? component.m_itemWeightMassFactor : 1f); Entries[text] = new CartConfig { VanillaWidth = num, VanillaHeight = num2, VanillaCartWeight = num3, VanillaCargoPull = vanillaCargoPull, Width = _config.Bind<int>(text, "Width", num, "Storage columns. 1 to 8. 0 or less keeps the cart's normal width."), Height = _config.Bind<int>(text, "Height", num2, "Storage rows. 0 or less keeps the cart's normal height."), CartWeight = _config.Bind<float>(text, "CartWeight", num3, "Pull weight of the empty cart. 0 is weightless. Below 0 keeps the normal empty weight."), CargoWeight = _config.Bind<float>(text, "CargoWeight", 0f, "Most item weight this cart will hold. 0 or less means no storage limit. This does not change how heavy the cart feels to pull."), CargoPull = _config.Bind<float>(text, "CargoPull", 0.25f, "How much cargo weight counts while pulling. 1 is normal Valheim. 0.25 makes a full cart about one quarter as heavy and easier to steer. 0 means cargo adds no pull weight. Below 0 keeps the cart's normal pull.") }; return true; } private static int ReadInt(object instance, string fieldName, int fallback) { FieldInfo fieldInfo = AccessTools.Field(instance.GetType(), fieldName); object obj = ((fieldInfo != null) ? fieldInfo.GetValue(instance) : null); if (obj is int) { return (int)obj; } return fallback; } } internal static class CartDeconstruct { private static readonly Dictionary<string, bool> Originals = new Dictionary<string, bool>(); private static readonly FieldInfo ContainerNview = AccessTools.Field(typeof(Container), "m_nview"); private static readonly MethodInfo DropAllItems = AccessTools.Method(typeof(Container), "DropAllItems", Type.EmptyTypes, (Type[])null); internal static Vagon FindCart(Component component) { if ((Object)(object)component == (Object)null) { return null; } Vagon component2 = component.GetComponent<Vagon>(); if ((Object)(object)component2 != (Object)null) { return component2; } return component.GetComponentInParent<Vagon>(); } internal static void ApplyAllLoaded(bool featureOn) { if ((Object)(object)ZNetScene.instance != (Object)null) { ApplyPrefabs(ZNetScene.instance, featureOn); } Vagon[] array = Object.FindObjectsByType<Vagon>((FindObjectsSortMode)0); if (array == null) { return; } for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null) { ApplyPiece(((Component)array[i]).gameObject, featureOn); } } } internal static void ApplyPrefabs(ZNetScene scene, bool featureOn) { if ((Object)(object)scene == (Object)null || !(AccessTools.Field(typeof(ZNetScene), "m_prefabs")?.GetValue(scene) is List<GameObject> list)) { return; } for (int i = 0; i < list.Count; i++) { GameObject val = list[i]; if ((Object)(object)val != (Object)null && (Object)(object)val.GetComponent<Vagon>() != (Object)null) { ApplyPiece(val, featureOn); } } } internal static void ApplyPiece(GameObject cartObject, bool featureOn) { if ((Object)(object)cartObject == (Object)null) { return; } Piece[] array = cartObject.GetComponentsInChildren<Piece>(true); if (array == null || array.Length == 0) { Piece componentInParent = cartObject.GetComponentInParent<Piece>(); if ((Object)(object)componentInParent == (Object)null) { return; } array = (Piece[])(object)new Piece[1] { componentInParent }; } string text = CartCatalog.PrefabName(cartObject); if (string.IsNullOrEmpty(text)) { return; } foreach (Piece val in array) { if (!((Object)(object)val == (Object)null)) { if (!Originals.ContainsKey(text)) { Originals[text] = val.m_canBeRemoved; } val.m_canBeRemoved = featureOn || Originals[text]; } } } internal static bool AllowDestroy(WearNTear wear, bool featureOn, bool hammerRemove, bool blockDrop) { if (!featureOn || !hammerRemove || blockDrop) { return true; } Vagon val = FindCart((Component)(object)wear); if (!CartRules.ShouldSpillCargo(featureOn, (Object)(object)val != (Object)null, hammerRemove, blockDrop)) { return true; } if (DropAllItems == null) { Plugin.LogError("Container.DropAllItems() was not found. Cart was not removed."); return false; } Container[] componentsInChildren = ((Component)val).GetComponentsInChildren<Container>(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (!TryDrop(componentsInChildren[i])) { return false; } } return true; } private static bool TryDrop(Container chest) { if ((Object)(object)chest == (Object)null || chest.GetInventory() == null) { return true; } object? obj = ContainerNview?.GetValue(chest); ZNetView val = (ZNetView)((obj is ZNetView) ? obj : null); if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner()) { return true; } try { DropAllItems.Invoke(chest, null); return true; } catch (Exception ex) { Exception ex2 = ((ex is TargetInvocationException { InnerException: not null } ex3) ? ex3.InnerException : ex); Plugin.LogError("Cargo drop failed. Cart was not removed: " + ex2.Message); return false; } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ZNetSceneAwakePatch { private static void Postfix(ZNetScene __instance) { CartCatalog.DiscoverFromScene(__instance); CartDeconstruct.ApplyPrefabs(__instance, Plugin.FeatureOn()); } } [HarmonyPatch(typeof(Vagon), "UpdateMass")] internal static class VagonUpdateMassPatch { private static void Prefix(Vagon __instance) { try { CartApplier.ApplyPull(__instance); } catch (Exception ex) { Plugin.LogError("Cart pull weight was not applied: " + ex.Message); } } } [HarmonyPatch(typeof(WearNTear), "ApplyDamage")] internal static class CartBreakPatch { private static bool Prefix(WearNTear __instance, ref bool __result) { if (Plugin.Invincible == null || !CartRules.BlocksBreak(Plugin.Invincible.Value)) { return true; } if (!IsCart(__instance)) { return true; } __result = false; return false; } private static bool IsCart(WearNTear wear) { if ((Object)(object)wear == (Object)null) { return false; } if (!((Object)(object)((Component)wear).GetComponent<Vagon>() != (Object)null)) { return (Object)(object)((Component)wear).GetComponentInParent<Vagon>() != (Object)null; } return true; } } [HarmonyPatch(typeof(Vagon), "Awake")] internal static class VagonAwakePatch { private static void Postfix(Vagon __instance) { if ((Object)(object)__instance != (Object)null) { CartDeconstruct.ApplyPiece(((Component)__instance).gameObject, Plugin.FeatureOn()); } } } [HarmonyPatch(typeof(WearNTear), "UpdateWear")] internal static class WearNTearUpdateWearPatch { [ThreadStatic] private static int s_depth; internal static bool IsActive => s_depth > 0; private static void Prefix() { s_depth++; } private static Exception Finalizer(Exception __exception) { if (s_depth > 0) { s_depth--; } return __exception; } } [HarmonyPatch(typeof(WearNTear), "RPC_Remove")] internal static class WearNTearRpcRemovePatch { [ThreadStatic] private static int s_depth; internal static bool IsActive => s_depth > 0; private static void Prefix() { s_depth++; } private static Exception Finalizer(Exception __exception) { if (s_depth > 0) { s_depth--; } return __exception; } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] internal static class PieceCanBeRemovedPatch { private static void Postfix(Piece __instance, ref bool __result) { try { if (!WearNTearUpdateWearPatch.IsActive && !((Object)(object)__instance == (Object)null)) { Vagon val = CartDeconstruct.FindCart((Component)(object)__instance); bool? flag = CartRules.RemovalOverride(Plugin.FeatureOn(), (Object)(object)val != (Object)null, inUse: false, duringWear: false); if (flag.HasValue) { __result = flag.Value; } } } catch (Exception ex) { Plugin.LogError("Cart remove check failed: " + ex.Message); } } } [HarmonyPatch(typeof(WearNTear), "Destroy")] internal static class WearNTearDestroyPatch { private static bool Prefix(WearNTear __instance, bool blockDrop) { try { return CartDeconstruct.AllowDestroy(__instance, Plugin.FeatureOn(), WearNTearRpcRemovePatch.IsActive, blockDrop); } catch (Exception ex) { Plugin.LogError("Cart remove failed: " + ex.Message); return true; } } } [HarmonyPatch(typeof(Piece), "Awake")] internal static class PieceAwakePatch { private static void Postfix(Piece __instance) { if (!((Object)(object)__instance == (Object)null) && Plugin.FeatureOn() && !((Object)(object)CartDeconstruct.FindCart((Component)(object)__instance) == (Object)null)) { __instance.m_canBeRemoved = true; } } } [HarmonyPatch(typeof(Container), "Awake")] internal static class ContainerAwakePatch { private static void Postfix(Container __instance) { CartApplier.Apply(__instance); } } [HarmonyPatch(typeof(Inventory), "CanAddItem", new Type[] { typeof(ItemData), typeof(int) })] internal static class CanAddItemPatch { private static bool Prefix(Inventory __instance, ItemData __0, int __1, ref bool __result) { if (CargoGate.Allows(__instance, CargoGate.ItemWeight(__0, __1))) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] internal static class AddItemPatch { private static bool Prefix(Inventory __instance, ItemData __0) { return CargoGate.Allows(__instance, CargoGate.ItemWeight(__0, __0?.m_stack ?? 0)); } } internal static class CargoGate { public static bool Allows(Inventory inventory, float itemWeight) { CartCatalog.CartConfig forInventory = CartCatalog.GetForInventory(inventory); if (forInventory == null) { return true; } return CartRules.CanAddWeight(inventory.GetTotalWeight(), itemWeight, forInventory.CargoWeight.Value); } public static float ItemWeight(ItemData item, int stack) { if (item == null || item.m_shared == null) { return 0f; } int num = ((stack <= 0) ? 1 : stack); return item.m_shared.m_weight * (float)num; } } [BepInPlugin("com.frizzqol.cartcontrol", "FrizzQOL Cart Control", "0.4.3")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.frizzqol.cartcontrol"; public const string PluginName = "FrizzQOL Cart Control"; public const string PluginVersion = "0.4.3"; private static readonly HashSet<string> _pullLogs = new HashSet<string>(); internal static Plugin Instance { get; private set; } internal static ConfigEntry<bool> Invincible { get; private set; } internal static ConfigEntry<bool> HammerDeconstruct { get; private set; } private void Awake() { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown Instance = this; Invincible = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Invincible", true, "On by default. Carts take no damage and do not wear down, so they cannot break. Set this to false to use normal cart breaking."); HammerDeconstruct = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "HammerDeconstruct", true, "On by default. Hammer middle-click empties a cart onto the ground, then removes the cart and returns its materials."); CartCatalog.Initialize(((BaseUnityPlugin)this).Config); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { CartApplier.ApplyAllLoaded(); CartDeconstruct.ApplyAllLoaded(FeatureOn()); }; Harmony val = new Harmony("com.frizzqol.cartcontrol"); try { val.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"FrizzQOL Cart Control 0.4.3 loaded"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Harmony patch failed: " + ex.Message)); } } internal static bool FeatureOn() { if (HammerDeconstruct != null) { return HammerDeconstruct.Value; } return false; } internal static void LogInfo(string message) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)message); } } internal static void LogPull(Vagon cart, float empty, float cargoPull, float pullMass) { if (!((Object)(object)Instance == (Object)null) && !((Object)(object)cart == (Object)null)) { string item = ((Object)cart).GetInstanceID() + ":" + empty.ToString("0.##") + ":" + cargoPull.ToString("0.##") + ":" + pullMass.ToString("0.##"); if (_pullLogs.Add(item)) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)(CartCatalog.PrefabName(((Component)cart).gameObject) + " pull mass " + pullMass.ToString("0.##") + " (empty " + empty.ToString("0.##") + ", cargo factor " + cargoPull.ToString("0.##") + ").")); } } } internal static void LogError(string message) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogError((object)message); } } internal static void LogWarning(string message) { if ((Object)(object)Instance != (Object)null) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)message); } } } }