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 ValheimDryDock v1.1.0
ValheimDryDock.dll
Decompiled 3 days agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Splatform; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ValheimDryDock")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ValheimDryDock")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("0a05fd87-cc17-4dfd-95de-c925ea56f3c4")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace ValheimDryDock; [BepInPlugin("com.github.seniormodder.valheimdrydock", "ValheimDryDock", "1.1.0")] [BepInProcess("valheim.exe")] public class Plugin : BaseUnityPlugin { public const string ModGUID = "com.github.seniormodder.valheimdrydock"; public const string ModName = "ValheimDryDock"; public const string ModVersion = "1.1.0"; public static ManualLogSource ModLogger; private Harmony _harmony; public static Plugin Instance { get; private set; } 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; ModLogger = ((BaseUnityPlugin)this).Logger; Configuration.BindConfig(((BaseUnityPlugin)this).Config); _harmony = new Harmony("com.github.seniormodder.valheimdrydock"); _harmony.PatchAll(); ModLogger.LogInfo((object)"ValheimDryDock Structural System Module v1.1.0 Initialized."); } private void Update() { //IL_0054: 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) if ((Object)(object)Player.m_localPlayer == (Object)null) { return; } Chat instance = Chat.instance; if ((instance == null || !instance.HasFocus()) && !Menu.IsVisible() && !Console.IsVisible() && !(DateTime.Now < Configuration.LastActionTime.AddMilliseconds(600.0))) { if (Input.GetKeyDown(Configuration.DockHotkey.Value)) { Configuration.LastActionTime = DateTime.Now; DryDockController.ExecuteDock(); } if (Input.GetKeyDown(Configuration.UndockHotkey.Value)) { Configuration.LastActionTime = DateTime.Now; DryDockController.ExecuteUndock(); } } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } public static class Configuration { public static DateTime LastActionTime = DateTime.MinValue; public static ConfigEntry<KeyCode> DockHotkey { get; private set; } public static ConfigEntry<KeyCode> UndockHotkey { get; private set; } public static ConfigEntry<float> SafetyClearanceBuffer { get; private set; } public static ConfigEntry<float> RaycastDistance { get; private set; } public static ConfigEntry<string> VerticalPostPrefab { get; private set; } public static ConfigEntry<string> AngledBracePrefab { get; private set; } public static void BindConfig(ConfigFile config) { DockHotkey = config.Bind<KeyCode>("Controls", "DockHotkey", (KeyCode)121, "Press to lift and dock the targeted ship."); UndockHotkey = config.Bind<KeyCode>("Controls", "UndockHotkey", (KeyCode)104, "Press to restore and release the targeted ship into water."); SafetyClearanceBuffer = config.Bind<float>("Mechanics", "SafetyClearanceBuffer", 3f, "Vertical buffer clearance in meters added directly above the highest local wave crest."); RaycastDistance = config.Bind<float>("Mechanics", "RaycastDistance", 30f, "Maximum distance targeting vector for ship selection scans."); VerticalPostPrefab = config.Bind<string>("Assets", "VerticalPostPrefab", "wood_pole2", "Vanilla prefab used to build the center support columns."); AngledBracePrefab = config.Bind<string>("Assets", "AngledBracePrefab", "wood_beam2_26", "Vanilla prefab used to build the dynamic angled side hull supports."); } } public static class DryDockController { private const string ZdoKeyDocked = "DryDock_IsDocked"; private const string ZdoKeyOrigPos = "DryDock_OrigPos"; private const string ZdoKeyOrigRot = "DryDock_OrigRot"; public static void ExecuteDock() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: 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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) try { Ship val = FindTargetShip(); if ((Object)(object)val == (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, "No ship targeted.", 0, (Sprite)null, false); return; } Component component = ((Component)val).gameObject.GetComponent(typeof(ZNetView)); ZNetView val2 = (ZNetView)(object)((component is ZNetView) ? component : null); if ((Object)(object)val2 == (Object)null || !val2.IsValid()) { return; } if (!PrivateArea.CheckAccess(((Component)val).transform.position, 0f, true, false)) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Building access restricted by Ward protection.", 0, (Sprite)null, false); return; } if (!val2.IsOwner()) { val2.ClaimOwnership(); } if (!val2.IsOwner()) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Network link sync deferred. Try again.", 0, (Sprite)null, false); return; } if (val2.GetZDO().GetInt("DryDock_IsDocked", 0) == 1) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Targeted ship is already docked.", 0, (Sprite)null, false); return; } Vector3 position = ((Component)val).transform.position; float num = Floating.GetLiquidLevel(position, 0f, (LiquidType)10) - position.y + Configuration.SafetyClearanceBuffer.Value; if (num < Configuration.SafetyClearanceBuffer.Value) { num = Configuration.SafetyClearanceBuffer.Value; } val2.GetZDO().Set("DryDock_OrigPos", position); ZDO zDO = val2.GetZDO(); Quaternion rotation = ((Component)val).transform.rotation; zDO.Set("DryDock_OrigRot", ((Quaternion)(ref rotation)).eulerAngles); Component component2 = ((Component)val).gameObject.GetComponent(typeof(Rigidbody)); Rigidbody val3 = (Rigidbody)(object)((component2 is Rigidbody) ? component2 : null); if ((Object)(object)val3 != (Object)null) { val3.linearVelocity = Vector3.zero; val3.angularVelocity = Vector3.zero; val3.isKinematic = true; } Bounds val4 = CalculateHullBounds(val); float z = ((Bounds)(ref val4)).size.z; float x = ((Bounds)(ref val4)).size.x; Vector3 position2 = position + new Vector3(0f, num, 0f); ((Component)val).transform.position = position2; val2.GetZDO().SetPosition(position2); ConstructCradle(val, z, x); val2.GetZDO().Set("DryDock_IsDocked", 1); ((Character)Player.m_localPlayer).Message((MessageType)2, $"Dry Dock Secure: Raised +{num:F1}m above sea level.", 0, (Sprite)null, false); } catch (Exception arg) { Plugin.ModLogger.LogError((object)$"Exception during ExecuteDock processing sequence: {arg}"); } } public static void ExecuteUndock() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0143: 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_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: 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) try { Ship val = FindTargetShip(); if ((Object)(object)val == (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, "No ship targeted.", 0, (Sprite)null, false); return; } Component component = ((Component)val).gameObject.GetComponent(typeof(ZNetView)); ZNetView val2 = (ZNetView)(object)((component is ZNetView) ? component : null); if ((Object)(object)val2 == (Object)null || !val2.IsValid()) { return; } if (!PrivateArea.CheckAccess(((Component)val).transform.position, 0f, true, false)) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Building access restricted by Ward protection.", 0, (Sprite)null, false); return; } if (!val2.IsOwner()) { val2.ClaimOwnership(); } if (!val2.IsOwner()) { return; } if (val2.GetZDO().GetInt("DryDock_IsDocked", 0) == 0) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Targeted ship is not currently docked.", 0, (Sprite)null, false); return; } Vector3 val3 = val2.GetZDO().GetVec3("DryDock_OrigPos", Vector3.zero); Vector3 vec = val2.GetZDO().GetVec3("DryDock_OrigRot", Vector3.zero); if (val3 == Vector3.zero) { Plugin.ModLogger.LogWarning((object)"ZDO reference data empty. Falling back to dynamic water calculations."); val3 = ((Component)val).transform.position; val3.y = Floating.GetLiquidLevel(val3, 0f, (LiquidType)10); } DemolishCradleSubstructures(val); ((Component)val).transform.position = val3; ((Component)val).transform.rotation = Quaternion.Euler(vec); val2.GetZDO().SetPosition(val3); Component component2 = ((Component)val).gameObject.GetComponent(typeof(Rigidbody)); Rigidbody val4 = (Rigidbody)(object)((component2 is Rigidbody) ? component2 : null); if ((Object)(object)val4 != (Object)null) { val4.isKinematic = false; val4.WakeUp(); } val2.GetZDO().Set("DryDock_IsDocked", 0); ((Character)Player.m_localPlayer).Message((MessageType)2, "Ship returned safely to the sea.", 0, (Sprite)null, false); } catch (Exception arg) { Plugin.ModLogger.LogError((object)$"Exception during ExecuteUndock processing sequence: {arg}"); } } private static Ship FindTargetShip() { //IL_000e: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)GameCamera.instance).transform; Ray val = default(Ray); ((Ray)(ref val))..ctor(transform.position, transform.forward); int mask = LayerMask.GetMask(new string[4] { "piece", "item", "viewblock", "vehicle" }); RaycastHit val2 = default(RaycastHit); if (Physics.Raycast(val, ref val2, Configuration.RaycastDistance.Value, mask)) { Component componentInParent = ((Component)((RaycastHit)(ref val2)).collider).gameObject.GetComponentInParent(typeof(Ship)); Ship val3 = (Ship)(object)((componentInParent is Ship) ? componentInParent : null); if ((Object)(object)val3 != (Object)null) { return val3; } Collider[] array = Physics.OverlapSphere(((RaycastHit)(ref val2)).point, 4f, LayerMask.GetMask(new string[1] { "vehicle" })); for (int i = 0; i < array.Length; i++) { Component componentInParent2 = ((Component)array[i]).gameObject.GetComponentInParent(typeof(Ship)); Ship val4 = (Ship)(object)((componentInParent2 is Ship) ? componentInParent2 : null); if ((Object)(object)val4 != (Object)null) { return val4; } } } return null; } private static Bounds CalculateHullBounds(Ship ship) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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_005a: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = default(Bounds); ((Bounds)(ref bounds))..ctor(((Component)ship).transform.position, Vector3.zero); Component[] componentsInChildren = ((Component)ship).gameObject.GetComponentsInChildren(typeof(Collider)); bool flag = false; Component[] array = componentsInChildren; foreach (Component obj in array) { Collider val = (Collider)(object)((obj is Collider) ? obj : null); if (!((Object)(object)val == (Object)null) && !val.isTrigger) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } return bounds; } private static void ConstructCradle(Ship ship, float length, float width) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0123: 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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = ZNetScene.instance.GetPrefab(Configuration.VerticalPostPrefab.Value); GameObject prefab2 = ZNetScene.instance.GetPrefab(Configuration.AngledBracePrefab.Value); if ((Object)(object)prefab == (Object)null || (Object)(object)prefab2 == (Object)null) { Plugin.ModLogger.LogError((object)"Configured cradle build prefabs are missing from the game's internal ZNetScene database."); return; } int num = Mathf.Max(4, Mathf.CeilToInt(length / 1.8f)); float num2 = length / (float)(num - 1); Vector3 val = default(Vector3); Vector3 val2 = default(Vector3); Vector3 val3 = default(Vector3); for (int i = 0; i < num; i++) { float num3 = 0f - length / 2f + (float)i * num2; ((Vector3)(ref val))..ctor(0f, -0.4f, num3); Vector3 worldPosition = ((Component)ship).transform.TransformPoint(val); BuildPieceServerSide(prefab, worldPosition, ((Component)ship).transform.rotation); ((Vector3)(ref val2))..ctor(0f - width * 0.45f, -0.2f, num3); Vector3 worldPosition2 = ((Component)ship).transform.TransformPoint(val2); Quaternion rotation = ((Component)ship).transform.rotation * Quaternion.Euler(0f, 0f, -26f); BuildPieceServerSide(prefab2, worldPosition2, rotation); ((Vector3)(ref val3))..ctor(width * 0.45f, -0.2f, num3); Vector3 worldPosition3 = ((Component)ship).transform.TransformPoint(val3); Quaternion rotation2 = ((Component)ship).transform.rotation * Quaternion.Euler(0f, 0f, 26f); BuildPieceServerSide(prefab2, worldPosition3, rotation2); } } private static void BuildPieceServerSide(GameObject prefab, Vector3 worldPosition, Quaternion rotation) { //IL_0025: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) Component component = prefab.GetComponent(typeof(Piece)); if ((Object)(object)((component is Piece) ? component : null) == (Object)null) { return; } Player localPlayer = Player.m_localPlayer; GameObject val = Object.Instantiate<GameObject>(prefab, worldPosition, rotation); Component component2 = val.GetComponent(typeof(ZNetView)); ZNetView val2 = (ZNetView)(object)((component2 is ZNetView) ? component2 : null); if ((Object)(object)val2 != (Object)null && val2.IsValid()) { val2.GetZDO().SetOwner(ZNet.GetUID()); Component component3 = val.GetComponent(typeof(Piece)); Piece val3 = (Piece)(object)((component3 is Piece) ? component3 : null); if ((Object)(object)val3 != (Object)null) { val3.SetCreator(localPlayer.GetPlayerID(), default(PlatformUserID)); } Component component4 = val.GetComponent(typeof(WearNTear)); WearNTear val4 = (WearNTear)(object)((component4 is WearNTear) ? component4 : null); if ((Object)(object)val4 != (Object)null) { val4.OnPlaced(); } } } private static void DemolishCradleSubstructures(Ship ship) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) int mask = LayerMask.GetMask(new string[1] { "piece" }); Collider[] array = Physics.OverlapSphere(((Component)ship).transform.position, 12f, mask); for (int i = 0; i < array.Length; i++) { Component componentInParent = ((Component)array[i]).gameObject.GetComponentInParent(typeof(Piece)); Piece val = (Piece)(object)((componentInParent is Piece) ? componentInParent : null); if ((Object)(object)val == (Object)null) { continue; } string text = ((Object)((Component)val).gameObject).name.Replace("(Clone)", "").Trim(); if (!(text == Configuration.VerticalPostPrefab.Value) && !(text == Configuration.AngledBracePrefab.Value)) { continue; } Component component = ((Component)val).gameObject.GetComponent(typeof(ZNetView)); ZNetView val2 = (ZNetView)(object)((component is ZNetView) ? component : null); if ((Object)(object)val2 != (Object)null && val2.IsValid()) { if (!val2.IsOwner()) { val2.ClaimOwnership(); } if (val2.IsOwner()) { ZNetScene.instance.Destroy(((Component)val).gameObject); } } } } } [HarmonyPatch] public static class DryDockNetworkPatches { [HarmonyPatch(typeof(Ship), "CustomFixedUpdate")] [HarmonyPrefix] public static bool PrefixShipPhysicsUpdate(Ship __instance, float fixedDeltaTime) { //IL_0078: 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 ((Object)(object)__instance == (Object)null) { return true; } Component component = ((Component)__instance).gameObject.GetComponent(typeof(ZNetView)); ZNetView val = (ZNetView)(object)((component is ZNetView) ? component : null); if ((Object)(object)val != (Object)null && val.IsValid() && val.GetZDO().GetInt("DryDock_IsDocked", 0) == 1) { Component component2 = ((Component)__instance).gameObject.GetComponent(typeof(Rigidbody)); Rigidbody val2 = (Rigidbody)(object)((component2 is Rigidbody) ? component2 : null); if ((Object)(object)val2 != (Object)null && !val2.isKinematic) { val2.linearVelocity = Vector3.zero; val2.angularVelocity = Vector3.zero; val2.isKinematic = true; } return false; } return true; } }