Decompiled source of ShipwrightsTouch v1.0.2

ShipwrightsTouch.dll

Decompiled a month ago
using 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;
		}
	}
}