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 ShipwrightsTouch v1.0.2
ShipwrightsTouch.dll
Decompiled a month agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("ShipwrightsTouch")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Extra features for Valheim boats: naming and sail coloring.")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2+e3dcb73f6beac1c3d24bc053b43aab0bef5d5d3d")] [assembly: AssemblyProduct("ShipwrightsTouch")] [assembly: AssemblyTitle("ShipwrightsTouch")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 ValheimBoatCustomizer { [HarmonyPatch] public static class ColoringPatches { private static int m_selectedStyle = 0; private const int MaxStyles = 6; private static readonly Color[] SailColors = (Color[])(object)new Color[6] { Color.white, Color.red, Color.blue, Color.green, Color.yellow, new Color(0.2f, 0.2f, 0.2f) }; private static readonly string[] ColorNames = new string[6] { "White", "Red", "Blue", "Green", "Yellow", "Black" }; private static bool m_isPlacing = false; [HarmonyPatch(typeof(Player), "UpdatePlacement")] [HarmonyPrefix] private static void Prefix_UpdatePlacement(Player __instance, bool takeInput, float dt, GameObject ___m_placementGhost) { if ((Object)(object)___m_placementGhost == (Object)null) { return; } Ship component = ___m_placementGhost.GetComponent<Ship>(); if (!((Object)(object)component == (Object)null)) { ApplyStyle(component, m_selectedStyle); if (takeInput && Input.GetKeyDown((KeyCode)103)) { m_selectedStyle = (m_selectedStyle + 1) % 6; MessageHud.instance.ShowMessage((MessageType)2, "Sail Color: <color=yellow>" + ColorNames[m_selectedStyle] + "</color>", 0, (Sprite)null, false); } } } [HarmonyPatch(typeof(Player), "PlacePiece")] [HarmonyPrefix] private static void Prefix_PlacePiece(Player __instance, Piece piece) { if ((Object)(object)piece != (Object)null && (Object)(object)((Component)piece).GetComponent<Ship>() != (Object)null) { m_isPlacing = true; } } [HarmonyPatch(typeof(Player), "PlacePiece")] [HarmonyPostfix] private static void Postfix_PlacePiece() { if (m_isPlacing) { m_isPlacing = false; } } [HarmonyPatch(typeof(Ship), "Awake")] [HarmonyPostfix] private static void Postfix_ShipAwake(Ship __instance) { ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } if (m_isPlacing && component.IsOwner()) { ZLog.LogWarning((object)$"[ValheimBoatMod] Setting initial sail style {m_selectedStyle} for new ship: {((Object)((Component)__instance).gameObject).name}"); component.GetZDO().Set("custom_sail_style", m_selectedStyle); if (Plugin.AssignBuilderIdentity.Value && (Object)(object)Player.m_localPlayer != (Object)null) { component.GetZDO().Set("shipwrightstouch.builder_id", Player.m_localPlayer.GetPlayerID()); component.GetZDO().Set("shipwrightstouch.builder_name", Player.m_localPlayer.GetPlayerName()); } } UpdateSailAppearance(__instance); } [HarmonyPatch(typeof(Ship), "Start")] [HarmonyPostfix] private static void Postfix_ShipStart(Ship __instance) { UpdateSailAppearance(__instance); } private static void UpdateSailAppearance(Ship ship) { ZNetView component = ((Component)ship).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { int @int = component.GetZDO().GetInt("custom_sail_style", 0); ApplyStyle(ship, @int); } } private static void ApplyStyle(Ship ship, int style) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00a9: Unknown result type (might be due to invalid IL or missing references) if (style < 0 || style >= SailColors.Length) { return; } Color val = SailColors[style]; Renderer[] componentsInChildren = ((Component)ship).GetComponentsInChildren<Renderer>(true); int num = 0; Renderer[] array = componentsInChildren; foreach (Renderer val2 in array) { string text = ((Object)((Component)val2).gameObject).name.ToLower(); if (text.Contains("sail") || text.Contains("cloth") || text.Contains("flag")) { num++; MaterialPropertyBlock val3 = new MaterialPropertyBlock(); val2.GetPropertyBlock(val3); val3.SetColor("_Color", val); val2.SetPropertyBlock(val3); } } if (num <= 0) { } } [HarmonyPatch(typeof(Ship), "UpdateSail")] [HarmonyPostfix] private static void Postfix_UpdateSail(Ship __instance) { UpdateSailAppearance(__instance); } [HarmonyPatch(typeof(Ship), "UpdateSailSize")] [HarmonyPostfix] private static void Postfix_UpdateSailSize(Ship __instance) { UpdateSailAppearance(__instance); } [HarmonyPatch(typeof(Player), "Update")] [HarmonyPostfix] private static void Postfix_PlayerUpdate(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || TextInput.IsVisible() || !Input.GetKeyDown((KeyCode)103) || (!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303))) { return; } GameObject hoverObject = ((Humanoid)__instance).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null || (Object)(object)hoverObject.GetComponentInParent<Container>() != (Object)null) { return; } Ship parentShip = NamingPatches.GetParentShip(hoverObject.GetComponent<Component>()); if (!((Object)(object)parentShip != (Object)null)) { return; } if (Plugin.CanModifyShip(parentShip, out var ownerName)) { ZNetView component = ((Component)parentShip).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { int @int = component.GetZDO().GetInt("custom_sail_style", 0); int num = (@int + 1) % 6; component.GetZDO().Set("custom_sail_style", num); UpdateSailAppearance(parentShip); MessageHud.instance.ShowMessage((MessageType)2, "Sail Color: <color=yellow>" + ColorNames[num] + "</color>", 0, (Sprite)null, false); } } else { MessageHud.instance.ShowMessage((MessageType)2, "Only " + ownerName + " can change this ship's sail color.", 0, (Sprite)null, false); } } } [HarmonyPatch] public static class DeconstructionPatches { [HarmonyPatch(typeof(Player), "CheckCanRemovePiece")] [HarmonyPrefix] private static void Prefix_CheckCanRemovePiece(ref Piece piece) { if ((Object)(object)piece == (Object)null || !Plugin.AllowShipDeconstruction.Value) { return; } Ship componentInParent = ((Component)piece).GetComponentInParent<Ship>(); string ownerName; if ((Object)(object)componentInParent == (Object)null) { if (piece.m_name.Contains("karve") || piece.m_name.Contains("longship") || piece.m_name.Contains("raft")) { ZLog.LogWarning((object)("[ValheimBoatMod] Found ship piece " + piece.m_name + " but no Ship component in parent.")); } } else if (Plugin.CanModifyShip(componentInParent, out ownerName) && !piece.m_canBeRemoved) { piece.m_canBeRemoved = true; ZLog.LogWarning((object)("[ValheimBoatMod] Force-allowing deconstruction of ship piece: " + piece.m_name)); } } [HarmonyPatch(typeof(Player), "RemovePiece")] [HarmonyPrefix] private static bool Prefix_RemovePiece(Player __instance) { if (!Plugin.AllowShipDeconstruction.Value) { return true; } GameObject hoverObject = ((Humanoid)__instance).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { return true; } Ship componentInParent = hoverObject.GetComponentInParent<Ship>(); if ((Object)(object)componentInParent == (Object)null) { return true; } ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon(); if (currentWeapon == null || (Object)(object)currentWeapon.m_shared.m_buildPieces == (Object)null) { return true; } Piece component = ((Component)componentInParent).GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { return true; } if (!Plugin.CanModifyShip(componentInParent, out var ownerName)) { MessageHud.instance.ShowMessage((MessageType)2, "Only " + ownerName + " can deconstruct this ship.", 0, (Sprite)null, false); return false; } if (!component.m_canBeRemoved) { component.m_canBeRemoved = true; } return true; } } [HarmonyPatch] public static class HoverTextPatches { [HarmonyPatch(typeof(HoverText), "GetHoverText")] [HarmonyPostfix] [HarmonyPriority(100)] private static void Postfix_HoverText(HoverText __instance, ref string __result) { ApplyNamingHover((Component)(object)__instance, ref __result); } [HarmonyPatch(typeof(ShipControlls), "GetHoverText")] [HarmonyPostfix] [HarmonyPriority(100)] private static void Postfix_RudderHoverText(ShipControlls __instance, ref string __result) { ApplyNamingHover((Component)(object)__instance, ref __result); } [HarmonyPatch(typeof(Container), "GetHoverText")] [HarmonyPostfix] [HarmonyPriority(100)] private static void Postfix_ContainerHoverText(Container __instance, ref string __result) { ApplyNamingHover((Component)(object)__instance, ref __result); } [HarmonyPatch(typeof(Chair), "GetHoverText")] [HarmonyPostfix] [HarmonyPriority(100)] private static void Postfix_ChairHoverText(Chair __instance, ref string __result) { ApplyNamingHover((Component)(object)__instance, ref __result); } private static void ApplyNamingHover(Component instance, ref string result) { Ship parentShip = NamingPatches.GetParentShip(instance); if ((Object)(object)parentShip == (Object)null) { return; } ZNetView component = ((Component)parentShip).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } string @string = component.GetZDO().GetString("custom_ship_name", ""); string string2 = component.GetZDO().GetString("shipwrightstouch.builder_name", ""); if (!string.IsNullOrEmpty(@string)) { string text = "<color=yellow>" + @string + "</color>"; if (result == null || !result.StartsWith(text)) { result = (string.IsNullOrEmpty(result) ? text : (text + "\n" + result)); } } if (instance is Container) { return; } if (Plugin.CanModifyShip(parentShip, out var _)) { string text2 = "[<color=yellow><b>Shift + E</b></color>] " + NamingPatches.GetRenameTitle(); if (result != null && !result.Contains("Shift + E")) { result = result + "\n" + text2; } string text3 = "[<color=yellow><b>Shift + G</b></color>] Change Sail Color"; if (result != null && !result.Contains("Shift + G")) { result = result + "\n" + text3; } } if (!string.IsNullOrEmpty(string2)) { string text4 = "<size=80%><color=#C0C0C0>Built by: " + string2 + "</color></size>"; if (result != null && !result.Contains("Built by:")) { result = result + "\n" + text4; } } } } [HarmonyPatch] public static class NamingPatches { private class ShipNameTextReceiver : TextReceiver { private readonly Ship m_ship; public ShipNameTextReceiver(Ship ship) { m_ship = ship; } public string GetText() { ZNetView component = ((Component)m_ship).GetComponent<ZNetView>(); return ((Object)(object)component != (Object)null && component.IsValid()) ? component.GetZDO().GetString("custom_ship_name", "") : ""; } public void SetText(string text) { ZNetView component = ((Component)m_ship).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { component.GetZDO().Set("custom_ship_name", text); } } } public static Ship GetParentShip(Component component) { if ((Object)(object)component == (Object)null) { return null; } Ship val = (Ship)(object)((component is Ship) ? component : null); if (val != null) { return val; } Ship componentInParent = component.GetComponentInParent<Ship>(); if ((Object)(object)componentInParent != (Object)null) { return componentInParent; } Transform root = component.transform.root; if ((Object)(object)root != (Object)null) { return ((Component)root).GetComponentInChildren<Ship>(); } return null; } internal static string GetRenameTitle() { try { string text = Localization.instance.Localize("$text_rename"); if (string.IsNullOrEmpty(text) || text.StartsWith("$") || text.ToLower().Contains("text_rename")) { return "Rename Ship"; } return text; } catch { return "Rename Ship"; } } [HarmonyPatch(typeof(Player), "Interact")] [HarmonyPrefix] private static bool Prefix_PlayerInteract(Player __instance, GameObject go, bool hold, bool alt) { if (hold || (Object)(object)go == (Object)null) { return true; } if (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)) { if ((Object)(object)go.GetComponentInParent<Container>() != (Object)null) { return true; } Ship parentShip = GetParentShip(go.GetComponent<Component>()); if ((Object)(object)parentShip != (Object)null) { if (Plugin.CanModifyShip(parentShip, out var ownerName)) { TextInput.instance.RequestText((TextReceiver)(object)new ShipNameTextReceiver(parentShip), GetRenameTitle(), 20); } else { MessageHud.instance.ShowMessage((MessageType)2, "Only " + ownerName + " can rename this ship.", 0, (Sprite)null, false); } return false; } } return true; } [HarmonyPatch(typeof(Player), "Update")] [HarmonyPostfix] private static void Postfix_PlayerUpdate(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || TextInput.IsVisible() || !Input.GetKeyDown((KeyCode)101) || (!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303))) { return; } GameObject hoverObject = ((Humanoid)__instance).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null || (Object)(object)hoverObject.GetComponentInParent<Container>() != (Object)null || hoverObject.GetComponentInParent<Interactable>() != null) { return; } Ship parentShip = GetParentShip(hoverObject.GetComponent<Component>()); if ((Object)(object)parentShip != (Object)null) { if (Plugin.CanModifyShip(parentShip, out var ownerName)) { TextInput.instance.RequestText((TextReceiver)(object)new ShipNameTextReceiver(parentShip), GetRenameTitle(), 20); } else { MessageHud.instance.ShowMessage((MessageType)2, "Only " + ownerName + " can rename this ship.", 0, (Sprite)null, false); } } } } [BepInPlugin("com.malafein.shipwrightstouch", "Shipwright's Touch", "1.0.2")] public class Plugin : BaseUnityPlugin { public const string ModGUID = "com.malafein.shipwrightstouch"; public const string ModName = "Shipwright's Touch"; public const string ModVersion = "1.0.2"; public const string ZdoOwnerIdKey = "shipwrightstouch.builder_id"; public const string ZdoOwnerNameKey = "shipwrightstouch.builder_name"; public const string ZdoNameKey = "custom_ship_name"; public const string ZdoStyleKey = "custom_sail_style"; public static ConfigEntry<bool> AllowShipDeconstruction; public static ConfigEntry<bool> AssignBuilderIdentity; private readonly Harmony harmony = new Harmony("com.malafein.shipwrightstouch"); private void Awake() { AllowShipDeconstruction = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowShipDeconstruction", false, "Allow deconstructing ships with the hammer (middle-mouse button)."); AssignBuilderIdentity = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AssignBuilderIdentity", true, "Automatically assign your character as the owner when constructing a ship, restricting modifications (renaming, recoloring, deconstruction) to yourself."); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Shipwright's Touch 1.0.2 is loading..."); try { harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Shipwright's Touch patches applied successfully."); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)string.Format("{0} failed to apply some patches: {1}", "Shipwright's Touch", arg)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Shipwright's Touch loaded!"); } public static bool CanModifyShip(Ship ship, out string ownerName) { ownerName = string.Empty; if ((Object)(object)ship == (Object)null) { return true; } ZNetView component = ((Component)ship).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return true; } long @long = component.GetZDO().GetLong("shipwrightstouch.builder_id", 0L); ownerName = component.GetZDO().GetString("shipwrightstouch.builder_name", ""); int result; if (@long != 0L) { Player localPlayer = Player.m_localPlayer; result = ((@long == ((localPlayer != null) ? new long?(localPlayer.GetPlayerID()) : null)) ? 1 : 0); } else { result = 1; } return (byte)result != 0; } } }