Decompiled source of Fleyta v1.0.0

plugins/Fleyta/Fleyta.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using Ezomic.Core;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("Thijssen Software")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright (c) 2026 Robbin Thijssen")]
[assembly: AssemblyDescription("Shove a beached boat back into the water.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+0616b41c7e9b05ada485f04e7283bd791b5c1a9a")]
[assembly: AssemblyProduct("Fleyta")]
[assembly: AssemblyTitle("Fleyta")]
[assembly: AssemblyVersion("1.0.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 Fleyta
{
	internal static class DevConsole
	{
		[HarmonyPatch(typeof(Terminal), "InitTerminal")]
		internal static class Hook
		{
			[CompilerGenerated]
			private static class <>O
			{
				public static ConsoleEvent <0>__OnCommand;
			}

			private static void Postfix()
			{
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0033: Expected O, but got Unknown
				if (!_registered)
				{
					_registered = true;
					object obj = <>O.<0>__OnCommand;
					if (obj == null)
					{
						ConsoleEvent val = OnCommand;
						<>O.<0>__OnCommand = val;
						obj = (object)val;
					}
					new ConsoleCommand("fleyta", "shove | state - shove the nearest boat as the key does, or say whether it is afloat", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				}
			}
		}

		private static bool _registered;

		private static void OnCommand(ConsoleEventArgs args)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			Terminal context = args.Context;
			if ((Object)(object)context == (Object)null)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				context.AddString("fleyta: no player.");
				return;
			}
			string text = ((args.Length > 1) ? args[1].ToLowerInvariant() : "");
			if (text == "shove")
			{
				context.AddString("fleyta: " + Shoving.TryShove(localPlayer));
			}
			else if (text == "state")
			{
				Ship val = Shoving.Nearest(localPlayer);
				if ((Object)(object)val == (Object)null)
				{
					context.AddString("fleyta: no boat within reach");
					return;
				}
				Vector3 worldCenterOfMass = ((Component)val).GetComponent<Rigidbody>().worldCenterOfMass;
				string text2 = (Water.Afloat(worldCenterOfMass) ? "afloat" : ((!Water.Shallow(worldCenterOfMass)) ? "unknown" : (Water.Resting(val, worldCenterOfMass) ? "aground" : "floating in the shallows")));
				string text3 = (Shove.Active(val) ? ", moving" : "");
				context.AddString("fleyta: " + Utils.GetPrefabName(((Component)val).gameObject) + " is " + text2 + text3);
			}
			else
			{
				context.AddString("fleyta shove - shove the nearest boat toward the water");
				context.AddString("fleyta state - afloat, aground or unknown for the nearest boat");
			}
		}
	}
	internal static class FleytaConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<KeyCode> ShoveKey;

		internal static ConfigEntry<float> StaminaCost;

		internal static ConfigEntry<float> Reach;

		internal static ConfigEntry<float> MaxDistance;

		internal static ConfigEntry<float> FloatDepth;

		internal static ConfigEntry<float> MaxRise;

		internal static ConfigEntry<float> BaseSpeed;

		internal static ConfigEntry<float> ReferenceMass;

		internal static ConfigEntry<float> MinSpeed;

		internal static ConfigEntry<float> MaxSpeed;

		internal static ConfigEntry<float> Acceleration;

		internal static ConfigEntry<string> Excluded;

		internal static ConfigEntry<bool> Verbose;

		internal static void Bind(ConfigFile cfg)
		{
			Enabled = cfg.Bind<bool>("Fleyta", "Enabled", true, "Off leaves the plugin loaded and the key doing nothing.");
			ShoveKey = cfg.Bind<KeyCode>("Fleyta", "ShoveKey", (KeyCode)98, "Stand beside a boat that is aground and press this to shove it toward the nearest water. Yours alone: the host never rebinds it.");
			StaminaCost = cfg.Bind<float>("Fleyta", "StaminaCost", 20f, "Stamina spent on each shove, taken when the shove starts (when the boat's owner accepts it) and not refunded if it jams on a rock. One press is the whole job, so this is a flat price and not a drain: a longship costs the same to start as a karve, it just moves slower. 0 makes it free.");
			Reach = cfg.Bind<float>("Fleyta", "Reach", 4f, "How close you must stand, in metres, measured to the nearest point of the hull rather than its middle, so a longship does not need to be reached from the helm.");
			MaxDistance = cfg.Bind<float>("Fleyta", "MaxDistance", 30f, "The furthest the water can be, in metres along the ground. Past this the boat is not moved at all and you are told so, because a boat left halfway up a beach is worse than one that stayed put.");
			FloatDepth = cfg.Bind<float>("Fleyta", "FloatDepth", 2f, "How far below the surface the sea floor must be under the middle of the hull before the boat counts as afloat, in metres. Too shallow and the keel grounds on the bottom in water that looks deep enough; too deep and the push runs further than it needs to. Raise it first if a boat is left stuck in the shallows. The vanilla hulls were not measured when this was written, so this is the number to tune in game.");
			MaxRise = cfg.Bind<float>("Fleyta", "MaxRise", 1.5f, "How much higher than where it sits the ground may climb on the way to the water, in metres, before that direction counts as blocked. A boat slides down a slope; it is not hauled over a dune. Raising it lets a shove cross low humps and makes the wrong side of a ridge a candidate.");
			BaseSpeed = cfg.Bind<float>("Fleyta", "BaseSpeed", 2f, "Sliding speed in metres a second for a hull of ReferenceMass.");
			ReferenceMass = cfg.Bind<float>("Fleyta", "ReferenceMass", 1000f, "The hull mass that slides at exactly BaseSpeed. Speed scales with the square root of ReferenceMass over the hull's own mass, so a heavy longship is slower and a light karve quicker, without a longship taking a minute. Turn Verbose on to read the real masses in the log.");
			MinSpeed = cfg.Bind<float>("Fleyta", "MinSpeed", 0.5f, "Slowest a shove ever goes, so the heaviest hull still arrives in reasonable time.");
			MaxSpeed = cfg.Bind<float>("Fleyta", "MaxSpeed", 4f, "Fastest a shove ever goes. A light hull at speed would clear the shoreline and keep going; this is the brake on that.");
			Acceleration = cfg.Bind<float>("Fleyta", "Acceleration", 10f, "How hard the push works against ground friction, in metres a second squared. Friction on a dragged hull is around 6, so below that the boat does not move at all; the default clears it with room. It does not change the speed, only how quickly it is reached.");
			Excluded = cfg.Bind<string>("Fleyta", "Excluded", "Raft", "Prefab names, comma separated, that are never shoved. The raft is left out by decision: it is the starter boat, and the gesture is meant for the Karve and the longships.");
			Verbose = cfg.Bind<bool>("Fleyta", "Verbose", false, "Write what was measured and decided to BepInEx/LogOutput.log: the hull's mass, the ground under it, the water found, the speed chosen and why a shove stopped. Off unless something looks wrong.");
		}
	}
	internal static class FleytaPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(Ship), "Start")]
		private static void ShipStart(Ship __instance)
		{
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsValid())
			{
				Ship ship = __instance;
				component.Register<Vector3, float, float>("Fleyta_Shove", (Action<long, Vector3, float, float>)delegate(long sender, Vector3 direction, float speed, float seconds)
				{
					//IL_0007: Unknown result type (might be due to invalid IL or missing references)
					Shoving.OnRequest(ship, sender, direction, speed, seconds);
				});
				component.Register<bool, string>("Fleyta_Shoved", (Action<long, bool, string>)Shoving.OnReply);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "Update")]
		private static void PlayerUpdate(Player __instance)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && FleytaConfig.Enabled.Value && !((Character)__instance).IsDead() && !InventoryGui.IsVisible() && !Menu.IsVisible() && Keys.PlayerTakesInput(__instance) && Keys.Pressed(FleytaConfig.ShoveKey.Value))
			{
				Shoving.TryShove(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(ShipControlls), "GetHoverText")]
		private static void HelmHover(ShipControlls __instance, ref string __result)
		{
			//IL_0011: 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_006f: 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 (!FleytaConfig.Enabled.Value || (int)FleytaConfig.ShoveKey.Value == 0)
			{
				return;
			}
			Ship ship = __instance.m_ship;
			if (!((Object)(object)ship == (Object)null) && !ship.HasPlayerOnboard() && !Shoving.IsExcluded(ship) && !Shove.Active(ship))
			{
				Rigidbody component = ((Component)ship).GetComponent<Rigidbody>();
				if (!((Object)(object)component == (Object)null) && Water.Aground(ship, component.worldCenterOfMass))
				{
					__result = __result + "\n[<color=yellow><b>" + ((object)FleytaConfig.ShoveKey.Value/*cast due to .constrained prefix*/).ToString() + "</b></color>] Shove toward the water";
				}
			}
		}
	}
	[BepInPlugin("ezomic.valheim.fleyta", "Fleyta", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class FleytaPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "ezomic.valheim.fleyta";

		public const string PluginName = "Fleyta";

		public const string PluginVersion = "1.0.0";

		public const string PluginAuthor = "Robbin Thijssen";

		private const string CoreGuid = "ezomic.valheim.core";

		internal static ManualLogSource Log;

		internal static bool CorePresent;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			FleytaConfig.Bind(((BaseUnityPlugin)this).Config);
			TryRegisterWithCore();
			_harmony = new Harmony("ezomic.valheim.fleyta");
			_harmony.PatchAll(typeof(FleytaPatches));
			_harmony.PatchAll(typeof(DevConsole.Hook));
			Log.LogInfo((object)"Fleyta 1.0.0 by Robbin Thijssen - ready.");
		}

		private void TryRegisterWithCore()
		{
			CorePresent = Chainloader.PluginInfos.ContainsKey("ezomic.valheim.core");
			if (!CorePresent)
			{
				Log.LogInfo((object)"Core not installed - running standalone, without the version gate.");
			}
			else
			{
				RegisterWithCore();
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private void RegisterWithCore()
		{
			Suite.Register("ezomic.valheim.fleyta", "Fleyta", "1.0.0", ((BaseUnityPlugin)this).Config, (Requirement)0, (Assembly)null);
			Suite.Sync((ConfigEntryBase)(object)FleytaConfig.Enabled);
			Suite.Local((ConfigEntryBase)(object)FleytaConfig.Verbose);
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
	}
	internal static class Keys
	{
		private static Func<Player, bool> _takeInput;

		private static bool _takeInputBound;

		internal static bool Pressed(KeyCode key)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if ((int)key == 0)
			{
				return false;
			}
			if (!ZInput.GetKeyDown(key, false))
			{
				return false;
			}
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return false;
			}
			if (!Console.IsVisible())
			{
				return !TextInput.IsVisible();
			}
			return false;
		}

		internal static bool PlayerTakesInput(Player player)
		{
			if (!_takeInputBound)
			{
				_takeInputBound = true;
				try
				{
					MethodInfo methodInfo = AccessTools.Method(typeof(Player), "TakeInput", (Type[])null, (Type[])null);
					if (methodInfo != null)
					{
						_takeInput = (Func<Player, bool>)Delegate.CreateDelegate(typeof(Func<Player, bool>), methodInfo);
					}
				}
				catch (Exception ex)
				{
					FleytaPlugin.Log.LogWarning((object)("Player.TakeInput could not be bound: " + ex.Message));
				}
			}
			if (_takeInput != null)
			{
				return _takeInput(player);
			}
			return true;
		}
	}
	internal sealed class Shove : MonoBehaviour
	{
		private Ship _ship;

		private Rigidbody _body;

		private Vector3 _direction;

		private float _speed;

		private float _timeLeft;

		private float _age;

		private Vector3 _checkpoint;

		private float _checkpointAge;

		internal static bool Active(Ship ship)
		{
			if ((Object)(object)ship != (Object)null)
			{
				return (Object)(object)((Component)ship).GetComponent<Shove>() != (Object)null;
			}
			return false;
		}

		internal static void Begin(Ship ship, Vector3 direction, float speed, float seconds)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			Rigidbody component = ((Component)ship).GetComponent<Rigidbody>();
			if (!((Object)(object)component == (Object)null))
			{
				Shove shove = ((Component)ship).GetComponent<Shove>();
				if ((Object)(object)shove == (Object)null)
				{
					shove = ((Component)ship).gameObject.AddComponent<Shove>();
				}
				shove._ship = ship;
				shove._body = component;
				shove._direction = direction;
				shove._speed = speed;
				shove._timeLeft = seconds;
				shove._age = 0f;
				shove._checkpoint = component.position;
				shove._checkpointAge = 0f;
			}
		}

		private void FixedUpdate()
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: 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_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: 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)
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: 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_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_0100: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_ship == (Object)null || (Object)(object)_body == (Object)null)
			{
				Object.Destroy((Object)(object)this);
				return;
			}
			if (!_ship.IsOwner())
			{
				Stop("ownership moved");
				return;
			}
			if (_ship.HasPlayerOnboard())
			{
				Stop("someone boarded");
				return;
			}
			float fixedDeltaTime = Time.fixedDeltaTime;
			_age += fixedDeltaTime;
			_timeLeft -= fixedDeltaTime;
			if (Water.Afloat(_body.worldCenterOfMass))
			{
				Stop("afloat");
				return;
			}
			if (_timeLeft <= 0f)
			{
				Stop("out of time");
				return;
			}
			if (_age - _checkpointAge > 1.5f)
			{
				Vector3 val = _body.position - _checkpoint;
				if (((Vector3)(ref val)).magnitude < 0.3f)
				{
					Stop("stuck");
					return;
				}
				_checkpoint = _body.position;
				_checkpointAge = _age;
			}
			Vector3 linearVelocity = _body.linearVelocity;
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(linearVelocity.x, 0f, linearVelocity.z);
			Vector3 val3 = _direction * _speed;
			Vector3 val4 = Vector3.MoveTowards(val2, val3, FleytaConfig.Acceleration.Value * fixedDeltaTime) - val2;
			_body.AddForce(val4, (ForceMode)2);
		}

		private void Stop(string why)
		{
			if (FleytaConfig.Verbose.Value)
			{
				FleytaPlugin.Log.LogInfo((object)("Shove ended after " + _age.ToString("0.0") + "s: " + why + "."));
			}
			Object.Destroy((Object)(object)this);
		}
	}
	internal static class Shoving
	{
		internal const string RpcName = "Fleyta_Shove";

		internal const string ReplyName = "Fleyta_Shoved";

		private const float PusherSlack = 3f;

		private static string _pendingNote;

		internal static float MaxSeconds()
		{
			return FleytaConfig.MaxDistance.Value / Mathf.Max(FleytaConfig.MinSpeed.Value, 0.05f) * 2f + 3f;
		}

		internal static string TryShove(Player player)
		{
			Ship val = Nearest(player);
			if ((Object)(object)val == (Object)null)
			{
				return Refuse(player, "No boat within reach.");
			}
			return Launch(player, val);
		}

		internal static string Launch(Player player, Ship ship)
		{
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			if (IsExcluded(ship))
			{
				return Refuse(player, "That boat is not one to shove.");
			}
			if ((Object)(object)((Character)player).GetStandingOnShip() != (Object)null || ship.HasPlayerOnboard())
			{
				return Refuse(player, "Nobody can be aboard while it is shoved.");
			}
			if (Shove.Active(ship))
			{
				return Refuse(player, "It is already moving.");
			}
			Rigidbody component = ((Component)ship).GetComponent<Rigidbody>();
			ZNetView component2 = ((Component)ship).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || !component2.IsValid())
			{
				return Refuse(player, "It will not budge.");
			}
			Vector3 worldCenterOfMass = component.worldCenterOfMass;
			if (Water.Afloat(worldCenterOfMass))
			{
				return Refuse(player, "It is already afloat.");
			}
			if (!Water.Shallow(worldCenterOfMass))
			{
				return Refuse(player, "The ground here has not loaded yet.");
			}
			if (!Water.Resting(ship, worldCenterOfMass))
			{
				return Refuse(player, "It is floating, not aground.");
			}
			Water.Plan plan = Water.Find(worldCenterOfMass);
			if (!plan.Found)
			{
				return Refuse(player, "The water is too far to shove it (" + FleytaConfig.MaxDistance.Value.ToString("0") + " m at most).");
			}
			float value = FleytaConfig.StaminaCost.Value;
			if (value > 0f && !((Character)player).HaveStamina(value))
			{
				return Refuse(player, "Not enough stamina.");
			}
			float num = SpeedFor(component.mass);
			float seconds = Mathf.Min(plan.Distance / num * 2f + 3f, MaxSeconds());
			if (FleytaConfig.Verbose.Value)
			{
				FleytaPlugin.Log.LogInfo((object)("Shoving " + Utils.GetPrefabName(((Component)ship).gameObject) + ": mass " + component.mass.ToString("0") + ", water " + plan.Distance.ToString("0") + " m toward " + ((Vector3)(ref plan.Direction)).ToString("0.00") + ", speed " + num.ToString("0.00") + " m/s, " + seconds.ToString("0.0") + " s allowed."));
			}
			string text = "You heave the boat toward the water (" + plan.Distance.ToString("0") + " m).";
			if (!Send(ship, component2, plan.Direction, num, seconds))
			{
				_pendingNote = text;
				return "asked the owner of the boat to shove it " + plan.Distance.ToString("0") + " m";
			}
			Pay(player);
			Say(player, text);
			return "shoving " + plan.Distance.ToString("0") + " m";
		}

		private static void Pay(Player player)
		{
			float value = FleytaConfig.StaminaCost.Value;
			if (value > 0f)
			{
				((Character)player).UseStamina(value);
			}
		}

		internal static void OnReply(long sender, bool accepted, string reason)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			string pendingNote = _pendingNote;
			_pendingNote = null;
			if (accepted)
			{
				Pay(localPlayer);
				if (pendingNote != null)
				{
					Say(localPlayer, pendingNote);
				}
			}
			else
			{
				Say(localPlayer, string.IsNullOrEmpty(reason) ? "It will not budge." : reason);
			}
		}

		internal static float SpeedFor(float mass)
		{
			return Mathf.Clamp(FleytaConfig.BaseSpeed.Value * Mathf.Sqrt(FleytaConfig.ReferenceMass.Value / Mathf.Max(mass, 1f)), FleytaConfig.MinSpeed.Value, FleytaConfig.MaxSpeed.Value);
		}

		internal static Ship Nearest(Player player)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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)
			Ship result = null;
			float num = FleytaConfig.Reach.Value;
			foreach (IMonoUpdater instance in Ship.Instances)
			{
				Ship val = (Ship)(object)((instance is Ship) ? instance : null);
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.m_floatCollider == (Object)null))
				{
					float num2 = Vector3.Distance(((Collider)val.m_floatCollider).ClosestPoint(((Component)player).transform.position), ((Component)player).transform.position);
					if (!(num2 > num))
					{
						num = num2;
						result = val;
					}
				}
			}
			return result;
		}

		internal static bool IsExcluded(Ship ship)
		{
			string prefabName = Utils.GetPrefabName(((Component)ship).gameObject);
			string[] array = FleytaConfig.Excluded.Value.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				if (string.Equals(array[i].Trim(), prefabName, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
			}
			return false;
		}

		private static bool Send(Ship ship, ZNetView nview, Vector3 direction, float speed, float seconds)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (nview.IsOwner())
			{
				Shove.Begin(ship, direction, speed, seconds);
				return true;
			}
			long owner = nview.GetZDO().GetOwner();
			if (owner == 0L)
			{
				nview.ClaimOwnership();
				Shove.Begin(ship, direction, speed, seconds);
				return true;
			}
			nview.InvokeRPC(owner, "Fleyta_Shove", new object[3] { direction, speed, seconds });
			return false;
		}

		internal static void OnRequest(Ship ship, long sender, Vector3 direction, float speed, float seconds)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			if (FleytaConfig.Enabled.Value && !((Object)(object)ship == (Object)null) && ship.IsOwner())
			{
				string text = Judge(ship, sender, direction, speed, seconds);
				if (text != null)
				{
					Reply(ship, sender, accepted: false, text);
					return;
				}
				speed = Mathf.Min(speed, FleytaConfig.MaxSpeed.Value);
				seconds = Mathf.Min(seconds, MaxSeconds());
				direction.y = 0f;
				Shove.Begin(ship, ((Vector3)(ref direction)).normalized, speed, seconds);
				Reply(ship, sender, accepted: true, null);
			}
		}

		private static string Judge(Ship ship, long sender, Vector3 direction, float speed, float seconds)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_008b: 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)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			if (ship.HasPlayerOnboard() || IsExcluded(ship))
			{
				return "That boat is not one to shove.";
			}
			if (Shove.Active(ship))
			{
				return "It is already moving.";
			}
			Rigidbody component = ((Component)ship).GetComponent<Rigidbody>();
			if ((Object)(object)component == (Object)null || (Object)(object)ship.m_floatCollider == (Object)null)
			{
				return "It will not budge.";
			}
			if (!Water.Aground(ship, component.worldCenterOfMass))
			{
				return "It is not aground.";
			}
			if (!PusherIsAtHull(ship, sender))
			{
				return "You are too far from the boat.";
			}
			if (!Sane(direction.x) || !Sane(direction.z) || direction.x * direction.x + direction.z * direction.z < 0.01f)
			{
				return "It will not budge.";
			}
			if (!Sane(speed) || speed <= 0f || !Sane(seconds) || seconds <= 0f)
			{
				return "It will not budge.";
			}
			return null;
		}

		private static bool Sane(float value)
		{
			if (!float.IsNaN(value))
			{
				return !float.IsInfinity(value);
			}
			return false;
		}

		private static bool PusherIsAtHull(Ship ship, long sender)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			float num = FleytaConfig.Reach.Value + 3f;
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if (!((Object)(object)allPlayer == (Object)null) && ((Character)allPlayer).GetOwner() == sender)
				{
					Vector3 position = ((Component)allPlayer).transform.position;
					if (Vector3.Distance(((Collider)ship.m_floatCollider).ClosestPoint(position), position) <= num)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static void Reply(Ship ship, long sender, bool accepted, string reason)
		{
			ZNetView component = ((Component)ship).GetComponent<ZNetView>();
			if ((Object)(object)component != (Object)null && component.IsValid())
			{
				component.InvokeRPC(sender, "Fleyta_Shoved", new object[2]
				{
					accepted,
					reason ?? ""
				});
			}
		}

		private static string Refuse(Player player, string text)
		{
			Say(player, text);
			return text;
		}

		private static void Say(Player player, string text)
		{
			((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false);
		}
	}
	internal static class Water
	{
		internal struct Plan
		{
			internal bool Found;

			internal Vector3 Direction;

			internal float Distance;
		}

		private const int Directions = 24;

		private const float Step = 2f;

		internal static float SeaLevel
		{
			get
			{
				if (!((Object)(object)ZoneSystem.instance != (Object)null))
				{
					return 30f;
				}
				return ZoneSystem.instance.m_waterLevel;
			}
		}

		internal static bool Afloat(Vector3 at)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			float num = default(float);
			if (Heightmap.GetHeight(at, ref num))
			{
				return num <= SeaLevel - FleytaConfig.FloatDepth.Value;
			}
			return false;
		}

		internal static bool Shallow(Vector3 at)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			float num = default(float);
			if (Heightmap.GetHeight(at, ref num))
			{
				return num > SeaLevel - FleytaConfig.FloatDepth.Value;
			}
			return false;
		}

		internal static bool Resting(Ship ship, Vector3 centre)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			return centre.y - SeaLevel - ship.m_waterLevelOffset > ship.m_disableLevel;
		}

		internal static bool Aground(Ship ship, Vector3 centre)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (Shallow(centre))
			{
				return Resting(ship, centre);
			}
			return false;
		}

		internal static Plan Find(Vector3 from)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			Plan result = default(Plan);
			float num = default(float);
			if (!Heightmap.GetHeight(from, ref num))
			{
				return result;
			}
			float num2 = SeaLevel - FleytaConfig.FloatDepth.Value;
			float num3 = num + FleytaConfig.MaxRise.Value;
			bool[] array = new bool[24];
			float num6 = default(float);
			for (float num4 = 2f; num4 <= FleytaConfig.MaxDistance.Value; num4 += 2f)
			{
				float num5 = float.MaxValue;
				for (int i = 0; i < 24; i++)
				{
					if (!array[i])
					{
						Vector3 val = Direction(i);
						if (!Heightmap.GetHeight(from + val * num4, ref num6) || num6 > num3)
						{
							array[i] = true;
						}
						else if (!(num6 > num2) && !(num6 >= num5))
						{
							num5 = num6;
							result.Found = true;
							result.Direction = val;
							result.Distance = num4;
						}
					}
				}
				if (result.Found)
				{
					return result;
				}
			}
			return result;
		}

		private static Vector3 Direction(int index)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			float num = (float)index * 15f * ((float)Math.PI / 180f);
			return new Vector3(Mathf.Sin(num), 0f, Mathf.Cos(num));
		}
	}
}