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 ShipCartRemoval v0.5.0
ShipCartRemoval.dll
Decompiled 8 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JG224.ModCore.API; using JG224.ShipCartRemoval.Core; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ShipCartRemoval")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.5.0.0")] [assembly: AssemblyInformationalVersion("0.5.0")] [assembly: AssemblyProduct("ShipCartRemoval")] [assembly: AssemblyTitle("ShipCartRemoval")] [assembly: AssemblyVersion("0.5.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; } } } namespace JG224.ShipCartRemoval { [BepInPlugin("jg224.ShipCartRemoval", "Ship&CartRemoval", "0.5.0")] [BepInProcess("valheim.exe")] [BepInDependency("com.jg224.modcore", "0.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "jg224.ShipCartRemoval"; public const string PluginName = "Ship&CartRemoval"; public const string PluginVersion = "0.5.0"; public const string ModCoreGuid = "com.jg224.modcore"; public const string GeneralTweaksGuid = "JG224.GeneralTweaks"; public const int ProtocolVersion = 1; public static readonly ModuleId ModuleId = new ModuleId("shipcartremoval"); private readonly List<IDisposable> _registrations = new List<IDisposable>(); private Harmony _harmony; private bool _shutDown; internal static ManualLogSource Log { get; private set; } internal static ShipCartRemovalConfig Settings { get; private set; } internal static ICoreServices Core { get; private set; } private void Awake() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Settings = ShipCartRemovalConfig.Load((BaseUnityPlugin)(object)this, Paths.ConfigPath); try { if (!ModCoreApi.IsAvailable) { throw new InvalidOperationException("ModCore did not initialize before Ship&CartRemoval."); } Core = ModCoreApi.Services; RegisterWithCore(); if (TryGetLegacyOwner(out var version)) { string text = "GeneralTweaks " + version?.ToString() + " still contains vehicle removal; Ship&CartRemoval is paused to prevent duplicate hooks."; Core.Modules.SetState(ModuleId, (ModuleRuntimeState)3, text); ((BaseUnityPlugin)this).Logger.LogWarning((object)(text + " Update GeneralTweaks to 3.0.0 or newer.")); } else { _harmony = new Harmony("jg224.ShipCartRemoval"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); Core.Modules.SetState(ModuleId, (ModuleRuntimeState)2, "Safe ship and cart removal hooks ready."); Game.isModded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Ship&CartRemoval 0.5.0 loaded; protocol " + 1 + ".")); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Ship&CartRemoval failed to initialize safely: " + ex)); if (Core != null) { Core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message); } Shutdown(); throw; } } private void OnDestroy() { Shutdown(); } private void RegisterWithCore() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_004a: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) SemanticVersion val = default(SemanticVersion); if (!SemanticVersion.TryParse("0.5.0", ref val)) { throw new InvalidOperationException("Invalid plugin version."); } _registrations.Add(Core.Modules.Register(new ModuleDescriptor(ModuleId, "jg224.ShipCartRemoval", "Ship&CartRemoval", val, 1, (ModuleSide)1, (ModuleRequirement)1, 0uL, 1, 1))); foreach (IDisposable item in Settings.RegisterMetadata(Core, ModuleId)) { _registrations.Add(item); } } private static bool TryGetLegacyOwner(out Version version) { version = null; if (!Chainloader.PluginInfos.TryGetValue("JG224.GeneralTweaks", out var value)) { return false; } version = value.Metadata.Version; if (version != null) { return version.CompareTo(new Version(3, 0, 0)) < 0; } return false; } private void Shutdown() { //IL_0094: Unknown result type (might be due to invalid IL or missing references) if (_shutDown) { return; } _shutDown = true; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; for (int num = _registrations.Count - 1; num >= 0; num--) { try { _registrations[num].Dispose(); } catch (Exception ex) { ManualLogSource logger = ((BaseUnityPlugin)this).Logger; if (logger != null) { logger.LogWarning((object)("Registration cleanup failed: " + ex.Message)); } } } _registrations.Clear(); if (Core != null) { Core.Metrics.RemoveOwner(ModuleId); } Core = null; Settings = null; Log = null; } } internal sealed class ShipCartRemovalConfig { internal ConfigEntry<bool> DebugLogging { get; } private ShipCartRemovalConfig(ConfigFile file) { DebugLogging = file.Bind<bool>("Diagnostics", "DebugLogging", false, "Enable verbose Ship&CartRemoval diagnostics."); } internal static ShipCartRemovalConfig Load(BaseUnityPlugin plugin, string configDirectory) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if (!Directory.Exists(configDirectory)) { Directory.CreateDirectory(configDirectory); } return new ShipCartRemovalConfig(PluginConfigFiles.Attach(plugin, new ConfigFile(Path.Combine(configDirectory, "jg224.ShipCartRemoval.cfg"), true, plugin.Info.Metadata))); } internal IEnumerable<IDisposable> RegisterMetadata(ICoreServices services, ModuleId owner) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, ((ConfigEntryBase)DebugLogging).Definition.Section, ((ConfigEntryBase)DebugLogging).Definition.Key, (ConfigScope)5, (Func<string>)(() => Convert.ToString(((ConfigEntryBase)DebugLogging).BoxedValue, CultureInfo.InvariantCulture)), 1)); } } } namespace JG224.ShipCartRemoval.Patches { internal static class RemovalFlagTranspiler { internal static IEnumerable<CodeInstruction> Replace(IEnumerable<CodeInstruction> instructions, FieldInfo flag, MethodInfo replacement) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown if (flag == null || replacement == null) { throw new InvalidOperationException("Ship&CartRemoval could not resolve the hammer removal gate."); } List<CodeInstruction> list = new List<CodeInstruction>(); int num = 0; foreach (CodeInstruction instruction in instructions) { CodeInstruction val = new CodeInstruction(instruction); if (val.opcode == OpCodes.Ldfld && object.Equals(val.operand, flag)) { val.opcode = OpCodes.Call; val.operand = replacement; num++; } list.Add(val); } if (num != 1) { throw new InvalidOperationException("Ship&CartRemoval expected one hammer removal flag check; found " + num + "."); } return list; } } internal static class VehicleSafety { internal static bool IsTarget(Piece piece) { if (Object.op_Implicit((Object)(object)piece) && piece.IsPlacedByPlayer()) { return VehicleRules.IsVanillaVehicle(((Object)((Component)piece).gameObject).name); } return false; } internal static bool CanTargetForRemoval(Piece piece) { if (Object.op_Implicit((Object)(object)piece)) { return VehicleRules.CanTargetForRemoval(piece.m_canBeRemoved, IsTarget(piece)); } return false; } internal static bool CanRemove(Piece piece) { return Evaluate(piece) == RemovalRefusal.None; } internal static RemovalRefusal Evaluate(Piece piece) { //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) if (!IsTarget(piece)) { return RemovalRefusal.Unsupported; } ZNetView component = ((Component)piece).GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid()) { return RemovalRefusal.UnknownState; } if (!component.IsOwner()) { return RemovalRefusal.NotOwner; } Container[] componentsInChildren = ((Component)piece).GetComponentsInChildren<Container>(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (!Object.op_Implicit((Object)(object)componentsInChildren[i])) { return RemovalRefusal.UnknownState; } ZNetView containerView = GetContainerView(componentsInChildren[i]); if (!Object.op_Implicit((Object)(object)containerView) || !containerView.IsValid()) { return RemovalRefusal.UnknownState; } if (!containerView.IsOwner()) { return RemovalRefusal.NotOwner; } Inventory inventory = componentsInChildren[i].GetInventory(); RemovalRefusal removalRefusal = VehicleRules.CheckInventory(inventory != null, (inventory != null) ? inventory.NrOfItems() : (-1), componentsInChildren[i].IsInUse()); if (removalRefusal != RemovalRefusal.None) { return removalRefusal; } } Ship componentInChildren = ((Component)piece).GetComponentInChildren<Ship>(true); if (Object.op_Implicit((Object)(object)componentInChildren) && componentInChildren.HasPlayerOnboard()) { return RemovalRefusal.Occupied; } Vagon componentInChildren2 = ((Component)piece).GetComponentInChildren<Vagon>(true); if (!Object.op_Implicit((Object)(object)componentInChildren) && !Object.op_Implicit((Object)(object)componentInChildren2)) { return RemovalRefusal.UnknownState; } if (Object.op_Implicit((Object)(object)componentInChildren2) && (componentInChildren2.IsAttached() || componentInChildren2.InUse())) { return RemovalRefusal.Attached; } Rigidbody[] componentsInChildren2 = ((Component)piece).GetComponentsInChildren<Rigidbody>(true); if (componentsInChildren2.Length == 0) { return RemovalRefusal.UnknownState; } foreach (Rigidbody val in componentsInChildren2) { if (!Object.op_Implicit((Object)(object)val) || val.isKinematic) { return RemovalRefusal.UnknownState; } Vector3 linearVelocity = val.linearVelocity; linearVelocity.y = 0f; float magnitude = ((Vector3)(ref linearVelocity)).magnitude; Vector3 angularVelocity = val.angularVelocity; if (!VehicleRules.IsMotionSafe(magnitude, ((Vector3)(ref angularVelocity)).magnitude, Object.op_Implicit((Object)(object)componentInChildren))) { return RemovalRefusal.Moving; } } return RemovalRefusal.None; } internal static ZNetView GetContainerView(Container container) { if (!Object.op_Implicit((Object)(object)container.m_rootObjectOverride)) { return ((Component)container).GetComponent<ZNetView>(); } return container.m_rootObjectOverride; } } [HarmonyPatch(typeof(Player), "RemovePiece")] internal static class VehicleRemovalTargetPatch { [HarmonyTranspiler] private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { return RemovalFlagTranspiler.Replace(instructions, AccessTools.Field(typeof(Piece), "m_canBeRemoved"), AccessTools.Method(typeof(VehicleSafety), "CanTargetForRemoval", (Type[])null, (Type[])null)); } } [HarmonyPatch(typeof(Player), "CheckCanRemovePiece")] internal static class VehicleWorkbenchBypassPatch { [HarmonyPrefix] [HarmonyPriority(0)] private static bool Prefix(Player __instance, Piece piece, ref bool __result, bool __runOriginal) { if (!__runOriginal || !VehicleSafety.IsTarget(piece)) { return true; } RemovalRefusal removalRefusal = VehicleSafety.Evaluate(piece); __result = removalRefusal == RemovalRefusal.None; if (!__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { ((Character)__instance).Message((MessageType)2, VehicleRules.RefusalText(removalRefusal), 0, (Sprite)null, false); } return false; } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] internal static class VehicleSafeRemovalPatch { [HarmonyPostfix] private static void Postfix(Piece __instance, ref bool __result) { if (VehicleSafety.IsTarget(__instance)) { __result = VehicleRules.PreserveVeto(__result, VehicleSafety.CanRemove(__instance)); } } } } namespace JG224.ShipCartRemoval.Core { internal enum RemovalRefusal { None, Unsupported, UnknownState, NotOwner, Cargo, InUse, Occupied, Attached, Moving } internal static class VehicleRules { private static readonly HashSet<string> Vehicles = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Cart", "Raft", "Karve", "VikingShip", "VikingShip_Ashlands" }; internal static bool CanTargetForRemoval(bool nativeAllowed, bool supportedPlayerVehicle) { return nativeAllowed || supportedPlayerVehicle; } internal static bool PreserveVeto(bool original, bool safe) { return original && safe; } internal static RemovalRefusal CheckInventory(bool available, int count, bool inUse) { if (available && count >= 0) { if (count <= 0) { if (!inUse) { return RemovalRefusal.None; } return RemovalRefusal.InUse; } return RemovalRefusal.Cargo; } return RemovalRefusal.UnknownState; } internal static string RefusalText(RemovalRefusal reason) { return reason switch { RemovalRefusal.NotOwner => "Cannot remove: vehicle state belongs to another player. Wait for local ownership.", RemovalRefusal.Cargo => "Cannot remove: empty the vehicle's storage first.", RemovalRefusal.InUse => "Cannot remove: close the vehicle's storage first.", RemovalRefusal.Occupied => "Cannot remove: everyone must leave the ship first.", RemovalRefusal.Attached => "Cannot remove: detach the cart first.", RemovalRefusal.Moving => "Cannot remove: wait for the vehicle to stop moving.", _ => "Cannot remove: vehicle state is not ready or cannot be verified.", }; } internal static bool IsVanillaVehicle(string prefabName) { return Vehicles.Contains(Clean(prefabName)); } internal static bool IsMotionSafe(float horizontalSpeed, float angularSpeed, bool isShip) { float num = (isShip ? 0.35f : 0.25f); if (IsFinite(horizontalSpeed) && IsFinite(angularSpeed) && horizontalSpeed <= num) { return angularSpeed <= 0.35f; } return false; } private static bool IsFinite(float value) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return value >= 0f; } return false; } private static string Clean(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } int num = value.IndexOf("(Clone)", StringComparison.OrdinalIgnoreCase); return ((num >= 0) ? value.Substring(0, num) : value).Trim(); } } }