Decompiled source of RockTheBoat v1.0.12

RockTheBoat.dll

Decompiled 2 weeks ago
using System;
using System.Diagnostics;
using System.Linq;
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 ConditionalConfigSync;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Rock the Boat")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Rock the Boat")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("0dd046aa-5b38-486f-aafa-e59c509ed4f7")]
[assembly: AssemblyFileVersion("1.0.12")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.12.0")]
[module: UnverifiableCode]
namespace RockTheBoat;

[BepInPlugin("shudnal.RockTheBoat", "Rock the Boat", "1.0.12")]
[BepInDependency("_shudnal.ConditionalConfigSync", "1.0.5")]
public class RockTheBoat : BaseUnityPlugin
{
	[HarmonyPatch(typeof(GameCamera), "Awake")]
	public static class GameCamera_Awake_CameraSettings
	{
		public static void Postfix()
		{
			PatchCameraDistance();
		}
	}

	[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
	public static class GameCamera_UpdateCamera_MaxDistanceOnBoat
	{
		[HarmonyPriority(0)]
		public static void Prefix(GameCamera __instance, ref float __state)
		{
			if (modEnabled.Value && cameraSetMaxDistanceOnShip.Value && (Object)(object)Player.m_localPlayer != (Object)null && (((Character)Player.m_localPlayer).IsAttachedToShip() || Object.op_Implicit((Object)(object)Ship.GetLocalShip())))
			{
				__state = __instance.m_maxDistance;
				__instance.m_maxDistance = __instance.m_maxDistanceBoat;
			}
		}

		[HarmonyPriority(800)]
		public static void Postfix(GameCamera __instance, float __state)
		{
			if (__state != 0f)
			{
				__instance.m_maxDistance = __state;
			}
		}
	}

	[HarmonyPatch(typeof(Minimap), "UpdateExplore")]
	public static class Minimap_UpdateExplore_ExploreRadiusOnBoat
	{
		[HarmonyPriority(0)]
		public static void Prefix(Minimap __instance, Player player, ref float __state)
		{
			if (modEnabled.Value && exploreRadiusMultiplier.Value != 1f && (Object)(object)player == (Object)(object)Player.m_localPlayer && IsTouchingShip())
			{
				__state = __instance.m_exploreRadius;
				__instance.m_exploreRadius *= exploreRadiusMultiplier.Value;
			}
		}

		[HarmonyPriority(800)]
		public static void Postfix(Minimap __instance, Player player, ref float __state)
		{
			if (__state != 0f)
			{
				__instance.m_exploreRadius = __state;
			}
		}
	}

	[HarmonyPatch(typeof(Piece), "Awake")]
	public static class Piece_Awake_ShipRemovableByHammer
	{
		public static void Postfix(Piece __instance)
		{
			if (modEnabled.Value && !__instance.m_canBeRemoved && removeShipWithHammer.Value)
			{
				Ship componentInParent = ((Component)__instance).GetComponentInParent<Ship>();
				if (componentInParent != null && !IsValheimRaftShip(componentInParent))
				{
					__instance.m_canBeRemoved = true;
				}
			}
		}
	}

	[HarmonyPatch(typeof(Ship), "CustomFixedUpdate")]
	public static class Ship_CustomFixedUpdate_ShipSpeed
	{
		public struct ForceState
		{
			public bool Applied;

			public float Sail;

			public float Backward;

			public float Steering;

			public float Paddling;
		}

		private static void DepleteShipRunStamina(Player player, bool checkRun, float dt)
		{
			if (!checkRun)
			{
				return;
			}
			bool flag = ((Character)player).HaveStamina(0f);
			((Character)player).UseStamina(dt * 15f * Game.m_moveStaminaRate);
			if (flag && !((Character)player).HaveStamina(0f))
			{
				nitroStaminaDepleted = true;
				if (Object.op_Implicit((Object)(object)Hud.instance))
				{
					Hud.instance.StaminaBarEmptyFlash();
				}
			}
		}

		[HarmonyPriority(0)]
		public static void Prefix(Ship __instance, float fixedDeltaTime, out ForceState __state)
		{
			__state = default(ForceState);
			if (!modEnabled.Value || !Object.op_Implicit((Object)(object)__instance.m_nview) || !__instance.m_nview.IsValid())
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			bool flag = Object.op_Implicit((Object)(object)localPlayer) && (Object)(object)localPlayer.GetControlledShip() == (Object)(object)__instance;
			bool flag2 = __instance.m_nview.IsOwner();
			if (!flag2 && !flag)
			{
				return;
			}
			ZDO zDO = __instance.m_nview.GetZDO();
			float num = (nitroEnabled.Value ? zDO.GetFloat(s_nitroSpeed, 1f) : 1f);
			if (nitroEnabled.Value && flag)
			{
				nitroButtonPressed = ZInput.GetButton("Run") || ZInput.GetButton("JoyRun");
				nitroStaminaDepleted = nitroStaminaDepleted || !((Character)localPlayer).HaveStamina(0f);
				if (nitroButtonPressed)
				{
					nitroAmount = Mathf.MoveTowards(nitroAmount, 1f, fixedDeltaTime * 0.5f);
				}
				else
				{
					nitroAmount = Mathf.MoveTowards(nitroAmount, 0f, fixedDeltaTime * 2f);
					nitroStaminaDepleted = false;
				}
				float num2 = ((nitroButtonPressed && !nitroStaminaDepleted) ? (1.5f + nitroAmount) : 1f);
				if (num != num2)
				{
					SetNitroSpeed(zDO, num2);
				}
				DepleteShipRunStamina(localPlayer, num2 > 1f, fixedDeltaTime);
			}
			if (!flag2)
			{
				return;
			}
			float value = sailingSpeedMultiplier.Value;
			float value2 = steeringSpeedMultiplier.Value;
			float num3 = paddlingSteerSpeedMultiplier.Value * num;
			float num4 = backwardSpeedMultiplier.Value * num;
			float value3 = perRowerSpeedMultiplier.Value;
			if (value3 != 1f && __instance.m_players.Count > 0)
			{
				int num5 = 0;
				for (int i = 0; i < __instance.m_players.Count; i++)
				{
					Player val = __instance.m_players[i];
					if (Object.op_Implicit((Object)(object)val) && ((Character)val).IsAttachedToShip() && (Object)(object)val.GetControlledShip() != (Object)(object)__instance)
					{
						num5++;
					}
				}
				float num6 = 1f + value3 * (float)num5;
				num3 *= num6;
				num4 *= num6;
			}
			if (value != 1f || value2 != 1f || num3 != 1f || num4 != 1f)
			{
				__state = new ForceState
				{
					Applied = true,
					Sail = __instance.m_sailForceFactor,
					Backward = __instance.m_backwardForce,
					Steering = __instance.m_stearVelForceFactor,
					Paddling = __instance.m_stearForce
				};
				__instance.m_sailForceFactor *= value;
				__instance.m_stearVelForceFactor *= value2;
				__instance.m_backwardForce *= num4;
				__instance.m_stearForce *= num3;
			}
		}

		[HarmonyPriority(800)]
		public static void Postfix(Ship __instance, ref ForceState __state)
		{
			Restore(__instance, ref __state);
		}

		private static void Finalizer(Ship __instance, ref ForceState __state)
		{
			Restore(__instance, ref __state);
		}

		private static void Restore(Ship ship, ref ForceState state)
		{
			if (state.Applied)
			{
				state.Applied = false;
				ship.m_sailForceFactor = state.Sail;
				ship.m_backwardForce = state.Backward;
				ship.m_stearVelForceFactor = state.Steering;
				ship.m_stearForce = state.Paddling;
			}
		}
	}

	[HarmonyPatch(typeof(Ship), "UpdateUpsideDmg")]
	public static class Ship_UpdateUpsideDmg_PreventShipDamage
	{
		private static void Prefix(Ship __instance, ref float ___m_upsideDownDmg, ref float __state)
		{
			if (modEnabled.Value && emptyShipDamageMultiplier.Value != 1f && !__instance.HasPlayerOnboard())
			{
				__state = ___m_upsideDownDmg;
				___m_upsideDownDmg *= emptyShipDamageMultiplier.Value;
			}
		}

		private static void Postfix(Ship __instance, ref float ___m_upsideDownDmg, float __state)
		{
			if (modEnabled.Value && __state != 0f)
			{
				___m_upsideDownDmg = __state;
			}
		}
	}

	[HarmonyPatch(typeof(Ship), "UpdateWaterForce")]
	public static class Ship_UpdateWaterForce_PreventShipDamage
	{
		private static void Prefix(Ship __instance, ref float ___m_waterImpactDamage, ref float __state)
		{
			if (modEnabled.Value && emptyShipDamageMultiplier.Value != 1f && !__instance.HasPlayerOnboard())
			{
				__state = ___m_waterImpactDamage;
				___m_waterImpactDamage *= emptyShipDamageMultiplier.Value;
			}
		}

		private static void Postfix(Ship __instance, ref float ___m_waterImpactDamage, float __state)
		{
			if (modEnabled.Value && __state != 0f)
			{
				___m_waterImpactDamage = __state;
			}
		}
	}

	[HarmonyPatch(typeof(Player), "OnSwimming")]
	public static class Player_OnSwimming_PreventDrowningNearTheShip
	{
		public static void Prefix(Player __instance, ref float ___m_drownDamageTimer)
		{
			if (modEnabled.Value && preventDrowningNearTheShip.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && IsTouchingShip())
			{
				___m_drownDamageTimer = 0f;
			}
		}
	}

	[HarmonyPatch(typeof(WearNTear), "Damage")]
	public static class WearNTear_Damage_DamageTakenMultiplier
	{
		private static void Prefix(WearNTear __instance, ref HitData hit, ZNetView ___m_nview, Piece ___m_piece)
		{
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Invalid comparison between Unknown and I4
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Invalid comparison between Unknown and I4
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Invalid comparison between Unknown and I4
			if (!modEnabled.Value || (Object)(object)___m_nview == (Object)null || !___m_nview.IsValid() || (impactDamageMultiplier.Value == 1f && emptyShipDamageMultiplier.Value == 1f && shipDamageToPlayerBuildings.Value == 1f))
			{
				return;
			}
			Ship val = default(Ship);
			if (((Component)__instance).TryGetComponent<Ship>(ref val))
			{
				if ((int)hit.m_hitType == 17 && (impactDamageMultiplier.Value != 1f || emptyShipDamageMultiplier.Value != 1f))
				{
					if (val.HasPlayerOnboard())
					{
						ModifyHitDamage(ref hit, impactDamageMultiplier.Value);
					}
					else
					{
						ModifyHitDamage(ref hit, Mathf.Min(impactDamageMultiplier.Value, emptyShipDamageMultiplier.Value));
					}
				}
				else if ((int)hit.m_hitType != 2 && emptyShipDamageMultiplier.Value != 1f && !val.HasPlayerOnboard() && (!hit.HaveAttacker() || !hit.GetAttacker().IsBoss()))
				{
					ModifyHitDamage(ref hit, emptyShipDamageMultiplier.Value);
				}
			}
			else if ((int)hit.m_hitType == 17 && shipDamageToPlayerBuildings.Value != 1f && (Object)(object)___m_piece != (Object)null && ___m_piece.IsPlacedByPlayer())
			{
				ModifyHitDamage(ref hit, shipDamageToPlayerBuildings.Value);
			}
		}
	}

	[HarmonyPatch(typeof(Character), "Damage")]
	public static class Character_Damage_DamageMultipliers
	{
		private static void Prefix(Character __instance, ref HitData hit, ZNetView ___m_nview)
		{
			if (modEnabled.Value && (Object)(object)Player.m_localPlayer == (Object)(object)__instance && IsTouchingShip() && (!hit.HaveAttacker() || !hit.GetAttacker().IsBoss()))
			{
				ModifyHitDamage(ref hit, playerDamageTakenMultiplier.Value);
			}
		}
	}

	[HarmonyPatch(typeof(ZoneSystem), "Start")]
	public static class ZoneSystem_Start_RegisterRPC
	{
		private static void Postfix()
		{
			ZRoutedRpc.instance.Register<ZDOID, float>("RPC_RTB_SetNitroSpeed", (Action<long, ZDOID, float>)RPC_RTB_SetNitroSpeed);
		}
	}

	[HarmonyPatch(typeof(GameCamera), "UpdateCamera")]
	public static class GameCamera_UpdateCamera_NitroFOV
	{
		[HarmonyPriority(0)]
		private static void Prefix(GameCamera __instance, ref float __state)
		{
			__state = __instance.m_fov;
			if (!__instance.m_freeFly && nitroEnabled.Value && nitroAmount > 0f && (Object)(object)Player.m_localPlayer != (Object)null && Player.m_localPlayer.GetControlledShip() != null)
			{
				__state = __instance.m_fov;
				__instance.m_fov *= 1f + nitroAmount * 0.2f;
			}
		}

		[HarmonyPriority(800)]
		private static void Postfix(GameCamera __instance, float __state)
		{
			__instance.m_fov = __state;
		}
	}

	[HarmonyPatch(typeof(Player), "StartDoodadControl")]
	public static class Player_StartDoodadControl_ResetNitro
	{
		private static void Postfix(Player __instance)
		{
			if (!((Object)(object)Player.m_localPlayer != (Object)(object)__instance))
			{
				Ship controlledShip = __instance.GetControlledShip();
				if (controlledShip != null)
				{
					nitroAmount = 0f;
					nitroStaminaDepleted = false;
					ZNetView nview = controlledShip.m_nview;
					SetNitroSpeed((nview != null) ? nview.GetZDO() : null, 1f);
				}
			}
		}
	}

	public const string pluginID = "shudnal.RockTheBoat";

	public const string pluginName = "Rock the Boat";

	public const string pluginVersion = "1.0.12";

	private readonly Harmony harmony = new Harmony("shudnal.RockTheBoat");

	internal static readonly ConfigSync configSync = new ConfigSync("shudnal.RockTheBoat")
	{
		DisplayName = "Rock the Boat",
		CurrentVersion = "1.0.12",
		MinimumRequiredVersion = "1.0.12"
	};

	private static ConfigEntry<bool> modEnabled;

	private static ConfigEntry<bool> configLocked;

	private static ConfigEntry<bool> loggingEnabled;

	private static ConfigEntry<float> cameraMaxDistanceOnBoat;

	private static ConfigEntry<bool> cameraSetMaxDistanceOnShip;

	private static ConfigEntry<float> exploreRadiusMultiplier;

	private static ConfigEntry<bool> removeShipWithHammer;

	private static ConfigEntry<bool> preventDrowningNearTheShip;

	private static ConfigEntry<float> emptyShipDamageMultiplier;

	private static ConfigEntry<float> playerDamageTakenMultiplier;

	private static ConfigEntry<float> impactDamageMultiplier;

	private static ConfigEntry<float> shipDamageToPlayerBuildings;

	private static ConfigEntry<float> sailingSpeedMultiplier;

	private static ConfigEntry<float> backwardSpeedMultiplier;

	private static ConfigEntry<float> steeringSpeedMultiplier;

	private static ConfigEntry<float> paddlingSteerSpeedMultiplier;

	private static ConfigEntry<float> perRowerSpeedMultiplier;

	private static ConfigEntry<bool> nitroEnabled;

	internal static bool nitroButtonPressed;

	internal static float nitroAmount;

	internal static bool nitroStaminaDepleted;

	internal static readonly int s_nitroSpeed = StringExtensionMethods.GetStableHashCode("RTB_NitroSpeed");

	internal static RockTheBoat instance;

	private void Awake()
	{
		instance = this;
		ConfigInit();
		((ConditionalConfigSync)configSync).AddLockingConfigEntry<bool>(configLocked);
		harmony.PatchAll();
		Game.isModded = true;
	}

	private void OnDestroy()
	{
		((BaseUnityPlugin)this).Config.Save();
		instance = null;
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
	}

	public static void LogInfo(object data)
	{
		if (loggingEnabled.Value)
		{
			((BaseUnityPlugin)instance).Logger.LogInfo(data);
		}
	}

	private void ConfigInit()
	{
		modEnabled = config("General", "Enabled", defaultValue: true, "Enable the mod");
		configLocked = config("General", "Lock Configuration", defaultValue: true, "Configuration is locked and can be changed by server admins only.");
		loggingEnabled = config("General", "Enable logging", defaultValue: false, "Enable logging for ward events. [Not Synced with Server]", synchronizedSetting: false);
		cameraMaxDistanceOnBoat = config("Camera", "Max distance on boat", 16f, "Maximum camera distance while attached to boat");
		cameraSetMaxDistanceOnShip = config("Camera", "Set max distance on boat", defaultValue: true, "Set boat camera distance while you attached to boat whether or not you are controlling the ship");
		cameraMaxDistanceOnBoat.SettingChanged += delegate
		{
			PatchCameraDistance();
		};
		exploreRadiusMultiplier = config("Minimap", "Explore radius multiplier", 1f, "Set multiplier for map explore radius while you are on boat");
		playerDamageTakenMultiplier = config("Damage", "Player damage taken multiplier", 1f, "Damage taken by players on board from creatures");
		emptyShipDamageMultiplier = config("Damage", "Empty ship damage multiplier", 1f, "Set multiplier for ship damage taken when no one are on board");
		impactDamageMultiplier = config("Damage", "Impact damage multiplier", 1f, "Set multiplier for ship damage taken on terrain hit");
		shipDamageToPlayerBuildings = config("Damage", "Damage done to player buildings multiplier", 1f, "Set multiplier when ship damages player buildings");
		removeShipWithHammer = config("Misc", "Remove ship with hammer", defaultValue: false, "Ships become removable by hammer like good old times. Relog required on change.");
		preventDrowningNearTheShip = config("Misc", "Prevent drowning near the ship", defaultValue: true, "Prevents drowning if you are touching the ship");
		sailingSpeedMultiplier = config("Speed", "Sailing speed multiplier", 1f, "Wind force applied to ship when sails is up");
		backwardSpeedMultiplier = config("Speed", "Backward speed multiplier", 1f, "Paddling force applied to ship when sails is down");
		steeringSpeedMultiplier = config("Speed", "Steering speed multiplier", 1f, "Speed of steering (direction change) that depends on forward speed, faster you move faster you steer.");
		paddlingSteerSpeedMultiplier = config("Speed", "Steering paddling speed multiplier", 1f, "Speed of steering (direction change) when paddling, independent of forward speed.");
		perRowerSpeedMultiplier = config("Speed", "Paddling force per rower multiplier", 1f, "Speed of paddling (forward and steering) added per every other player attached to the ship.");
		nitroEnabled = config("Speed", "Use stamina to boost steering speed", defaultValue: true, "Press Run button to boost steering. Stamina will be depleting.");
	}

	private static bool IsTouchingShip()
	{
		return (Object)(object)Ship.GetLocalShip() != (Object)null || ((Character)Player.m_localPlayer).IsAttachedToShip();
	}

	private static bool IsValheimRaftShip(Ship ship)
	{
		return ((Object)ship).name.StartsWith("MBRaft") || ((Component)ship).GetComponents<Component>().Any((Component comp) => ((object)comp).GetType().Name == "MoveableBaseShipComponent");
	}

	private static void ModifyHitDamage(ref HitData hit, float value)
	{
		((DamageTypes)(ref hit.m_damage)).Modify(Math.Max(value, 0f));
	}

	private ConfigEntry<T> config<T>(string group, string name, T defaultValue, ConfigDescription description, bool synchronizedSetting = true)
	{
		ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, defaultValue, description);
		((ConditionalConfigSync)configSync).AddConfigEntry<T>(val, (ConfigSyncMode)1, synchronizedSetting);
		return val;
	}

	private ConfigEntry<T> config<T>(string group, string name, T defaultValue, string description, bool synchronizedSetting = true)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		return config(group, name, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
	}

	internal static void PatchCameraDistance()
	{
		if (modEnabled.Value && !((Object)(object)GameCamera.instance == (Object)null) && cameraMaxDistanceOnBoat.Value > 0f)
		{
			GameCamera.instance.m_maxDistanceBoat = cameraMaxDistanceOnBoat.Value;
		}
	}

	public static void RPC_RTB_SetNitroSpeed(long sender, ZDOID targetZDO, float nitroSpeed)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		if (((ZDOID)(ref targetZDO)).IsNone())
		{
			return;
		}
		ZDO zDO = ZDOMan.instance.GetZDO(targetZDO);
		if (zDO != null)
		{
			ZNetView val = ZNetScene.instance.FindInstance(zDO);
			if (val != null && (Object)(object)val != (Object)null && val.IsValid() && val.IsOwner())
			{
				SetNitroSpeedValue(zDO, nitroSpeed);
			}
		}
	}

	public static void SetNitroSpeedValue(ZDO zDO, float nitroSpeed)
	{
		zDO.Set(s_nitroSpeed, nitroSpeed);
	}

	public static void SetNitroSpeed(ZDO zdo, float shift)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		if (zdo != null)
		{
			if (zdo.IsOwner())
			{
				SetNitroSpeedValue(zdo, shift);
				return;
			}
			ZRoutedRpc.instance.InvokeRoutedRPC(zdo.GetOwner(), "RPC_RTB_SetNitroSpeed", new object[2] { zdo.m_uid, shift });
		}
	}
}