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 SailingTogether v1.0.0
plugins/SailingTogether.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("SailingTogether")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+d730bfbdd3d8d6ff7ae17d22fa53f3e7a46c6d19")] [assembly: AssemblyProduct("SailingTogether")] [assembly: AssemblyTitle("SailingTogether")] [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 SailingTogether { internal class DebugPanel : MonoBehaviour { internal class SimSeat { public string Name; public float LocalX; public float LocalZ; public float Row; } private static readonly List<SimSeat> s_seats = new List<SimSeat>(); private static readonly SimSeat[] s_none = new SimSeat[0]; private static Ship s_ship; private static bool s_simActive = true; private Rect _window = new Rect(40f, 120f, 380f, 10f); internal static bool IsOpen { get; private set; } internal static IEnumerable<SimSeat> GetSimulatedSeats(Ship ship) { if (!s_simActive || !SailingTogetherPlugin.DebugTool.Value || (Object)(object)ship != (Object)(object)s_ship || !Object.op_Implicit((Object)(object)s_ship)) { return s_none; } return s_seats; } private void Update() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (!SailingTogetherPlugin.DebugTool.Value) { IsOpen = false; return; } KeyboardShortcut value = SailingTogetherPlugin.DebugHotkey.Value; if (((KeyboardShortcut)(ref value)).IsDown() && Object.op_Implicit((Object)(object)Player.m_localPlayer) && !Console.IsVisible() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus())) { IsOpen = !IsOpen; } Ship val = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Ship.GetLocalShip() : null); if ((Object)(object)val != (Object)(object)s_ship) { RebuildSeats(val); } } private static void RebuildSeats(Ship ship) { s_ship = ship; s_seats.Clear(); if (!Object.op_Implicit((Object)(object)ship)) { return; } foreach (ShipLayout.Seat seat in ShipLayout.Get(ship).Seats) { s_seats.Add(new SimSeat { LocalX = seat.Local.x, LocalZ = seat.Local.z }); } if (s_seats.Count == 0) { s_seats.Add(new SimSeat { LocalX = -1f, LocalZ = 0f }); s_seats.Add(new SimSeat { LocalX = 1f, LocalZ = 0f }); } for (int i = 0; i < s_seats.Count; i++) { s_seats[i].Name = $"#{i + 1} {SideName(s_seats[i].LocalX)}"; } } private static string SideName(float localX) { float num = ShipAccess.SideOf(localX); if (num != 0f) { if (!(num < 0f)) { return "Right"; } return "Left"; } return "Center"; } private static void SetAll(float row, float side = 0f) { foreach (SimSeat s_seat in s_seats) { float num = ShipAccess.SideOf(s_seat.LocalX); if (side == 0f || num == side) { s_seat.Row = row; } else if (side != 0f) { s_seat.Row = 0f; } } } private void OnGUI() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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) if (SailingTogetherPlugin.DebugTool.Value && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { float num = Mathf.Max(1f, (float)Screen.height / 1080f); GUI.matrix = Matrix4x4.Scale(new Vector3(num, num, 1f)); if (IsOpen) { _window = GUILayout.Window(23063, _window, new WindowFunction(DrawWindow), "SailingTogether — rower simulator", Array.Empty<GUILayoutOption>()); } else if (s_simActive && Object.op_Implicit((Object)(object)s_ship) && s_seats.Any((SimSeat s) => s.Row != 0f)) { GUI.Label(new Rect(10f, 10f, 600f, 22f), $"SailingTogether sim: {StatusLine()} [{SailingTogetherPlugin.DebugHotkey.Value}] panel"); } } } private void DrawWindow(int id) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)s_ship)) { GUILayout.Label("Board a ship to simulate its benches.", Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>())) { IsOpen = false; } GUI.DragWindow(); return; } s_simActive = GUILayout.Toggle(s_simActive, " Simulation active", Array.Empty<GUILayoutOption>()); GUILayout.Label($"Ship: {Utils.GetPrefabName(((Component)s_ship).gameObject)} Speed: {s_ship.GetSpeedSetting()}", Array.Empty<GUILayoutOption>()); GUILayout.Label(StatusLine(), Array.Empty<GUILayoutOption>()); RowingStats rowingStats = RowingStats.Get(s_ship); if (rowingStats != null && !rowingStats.IsOwner) { GUILayout.Label("<color=orange>You are not the ship owner: physics runs on another client.</color>", Array.Empty<GUILayoutOption>()); } else if (rowingStats != null && !rowingStats.Allowed) { GUILayout.Label("<color=orange>Rowing inactive at this speed (set speed 1 at the helm).</color>", Array.Empty<GUILayoutOption>()); } GUILayout.Space(6f); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("All W", Array.Empty<GUILayoutOption>())) { SetAll(1f); } if (GUILayout.Button("All S", Array.Empty<GUILayoutOption>())) { SetAll(-1f); } if (GUILayout.Button("Reset", Array.Empty<GUILayoutOption>())) { SetAll(0f); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Left W", Array.Empty<GUILayoutOption>())) { SetAll(1f, -1f); } if (GUILayout.Button("Right W", Array.Empty<GUILayoutOption>())) { SetAll(1f, 1f); } if (GUILayout.Button("Spin →", Array.Empty<GUILayoutOption>())) { MergeSpin(1f); } if (GUILayout.Button("← Spin", Array.Empty<GUILayoutOption>())) { MergeSpin(-1f); } GUILayout.EndHorizontal(); GUILayout.Space(6f); foreach (SimSeat s_seat in s_seats) { GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); GUILayout.Label(s_seat.Name, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) }); GUILayout.Label("S", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(12f) }); float num = GUILayout.HorizontalSlider(s_seat.Row, -1f, 1f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); s_seat.Row = Mathf.Round(num); GUILayout.Label("W", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(16f) }); GUILayout.Label((s_seat.Row > 0f) ? "+1" : ((s_seat.Row < 0f) ? "-1" : " 0"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(24f) }); GUILayout.EndHorizontal(); } GUILayout.Space(6f); GUILayout.Label($"[{SailingTogetherPlugin.DebugHotkey.Value}] closes the panel (values keep applying).", Array.Empty<GUILayoutOption>()); GUI.DragWindow(); } private static void MergeSpin(float dir) { foreach (SimSeat s_seat in s_seats) { float num = ShipAccess.SideOf(s_seat.LocalX); s_seat.Row = ((num == 0f) ? 0f : ((0f - num) * dir)); } } private static string StatusLine() { RowingStats rowingStats = RowingStats.Get(s_ship); if (rowingStats == null) { return "no data"; } return $"rowers {rowingStats.Rowers} thrust {rowingStats.Thrust:+0.0;-0.0;0} turn {rowingStats.Turn:+0.0;-0.0;0} " + string.Format("speed {0:0.0} m/s yaw {1:+0;-0;0}°/s {2}", s_ship.GetSpeed(), rowingStats.YawRate, rowingStats.Applied ? "APPLYING" : "idle"); } } [HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")] internal static class GameCamera_UpdateMouseCapture_Patch { private static void Postfix() { if (DebugPanel.IsOpen) { ZCursor.LockState = (CursorLockMode)0; ZCursor.Show(); } } } [HarmonyPatch(typeof(PlayerController), "TakeInput")] internal static class PlayerController_TakeInput_Patch { private static void Postfix(ref bool __result) { if (DebugPanel.IsOpen) { __result = false; } } } [HarmonyPatch(typeof(Player), "TakeInput")] internal static class Player_TakeInput_Patch { private static void Postfix(ref bool __result) { if (DebugPanel.IsOpen) { __result = false; } } } internal static class GameSprites { private static readonly Color DefaultShipColor = new Color(1f, 0.62f, 0.15f, 1f); private static bool s_loaded; internal static Sprite Ship; internal static Color ShipColor = DefaultShipColor; internal static Rect ShipVisible = new Rect(0f, 0f, 1f, 1f); internal static Sprite Arrow; internal static Sprite Oar; internal static void Reset() { s_loaded = false; } internal static void TryLoad() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (!s_loaded && Object.op_Implicit((Object)(object)Hud.instance)) { s_loaded = true; Ship = Find(SailingTogetherPlugin.HudShipSprite.Value, out var hudImage); ShipColor = (Object.op_Implicit((Object)(object)hudImage) ? ((Graphic)hudImage).color : DefaultShipColor); ShipVisible = ((Object.op_Implicit((Object)(object)Ship) && ((Object)Ship).name == "ship_top") ? new Rect(61f / 171f, 0.11328125f, 49f / 171f, 0.67578125f) : new Rect(0f, 0f, 1f, 1f)); Arrow = Find(SailingTogetherPlugin.HudArrowSprite.Value, out var hudImage2); Oar = Find(SailingTogetherPlugin.HudOarSprite.Value, out hudImage2); SailingTogetherPlugin.Log.LogInfo((object)("HUD: ship = '" + (Object.op_Implicit((Object)(object)Ship) ? ((Object)Ship).name : "built-in") + "', arrow = '" + (Object.op_Implicit((Object)(object)Arrow) ? ((Object)Arrow).name : "built-in") + "', oar = '" + (Object.op_Implicit((Object)(object)Oar) ? ((Object)Oar).name : "none") + "'")); } } private static Sprite Find(string spriteName, out Image hudImage) { hudImage = null; if (string.IsNullOrWhiteSpace(spriteName)) { return null; } spriteName = spriteName.Trim(); Hud instance = Hud.instance; if (Object.op_Implicit((Object)(object)instance) && Object.op_Implicit((Object)(object)instance.m_shipHudRoot)) { Image[] componentsInChildren = instance.m_shipHudRoot.GetComponentsInChildren<Image>(true); foreach (Image val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val.sprite) && ((Object)val.sprite).name == spriteName) { hudImage = val; return val.sprite; } } } Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>(); foreach (Sprite val2 in array) { if (Object.op_Implicit((Object)(object)val2) && ((Object)val2).name == spriteName) { return val2; } } SailingTogetherPlugin.Log.LogWarning((object)("HUD: sprite '" + spriteName + "' not found.")); return null; } internal static void Draw(Rect rect, Sprite sprite, float angle, Color color, float guiScale) { //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) //IL_000a: Unknown result type (might be due to invalid IL or missing references) Draw(rect, sprite, angle, ((Rect)(ref rect)).center, color, guiScale); } internal static void Draw(Rect rect, Sprite sprite, float angle, Vector2 pivotPoint, Color color, float guiScale) { //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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_00b4: 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) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) Texture texture = (Texture)(object)sprite.texture; Rect textureRect = sprite.textureRect; Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref textureRect)).x / (float)texture.width, ((Rect)(ref textureRect)).y / (float)texture.height, ((Rect)(ref textureRect)).width / (float)texture.width, ((Rect)(ref textureRect)).height / (float)texture.height); Matrix4x4 matrix = GUI.matrix; Color color2 = GUI.color; if (angle != 0f) { Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(pivotPoint.x * guiScale, pivotPoint.y * guiScale, 0f); GUI.matrix = Matrix4x4.TRS(val2, Quaternion.Euler(0f, 0f, angle), Vector3.one) * Matrix4x4.TRS(-val2, Quaternion.identity, Vector3.one) * matrix; } GUI.color = color; GUI.DrawTextureWithTexCoords(rect, texture, val, true); GUI.color = color2; GUI.matrix = matrix; } } internal static class RowerInput { internal static readonly int RowHash = StringExtensionMethods.GetStableHashCode("SailingTogether_Row"); internal static readonly int SeatedHash = StringExtensionMethods.GetStableHashCode("SailingTogether_Seated"); private static float s_lastSent; private static bool s_lastSeated; private static Ship s_seatedShip; internal static Ship GetSeatedShip(Player player) { if (!((Character)player).IsAttachedToShip() || player.GetDoodadController() != null) { return null; } Transform attachPoint = player.GetAttachPoint(); if (!Object.op_Implicit((Object)(object)attachPoint)) { return null; } return ((Component)attachPoint).GetComponentInParent<Ship>(); } internal static void Send(Player player, float row, bool seated) { row = Mathf.Round(Mathf.Clamp(row, -1f, 1f) * 20f) / 20f; if (!Mathf.Approximately(row, s_lastSent) || seated != s_lastSeated) { ZNetView component = ((Component)player).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.IsOwner()) { component.GetZDO().Set(RowHash, row); component.GetZDO().Set(SeatedHash, seated ? 1 : 0, false); s_lastSent = row; s_lastSeated = seated; } } } internal static bool TryGetRower(Player player, out float row) { row = 0f; ZNetView val = (Object.op_Implicit((Object)(object)player) ? ((Component)player).GetComponent<ZNetView>() : null); ZDO val2 = (Object.op_Implicit((Object)(object)val) ? val.GetZDO() : null); if (val2 == null || val2.GetInt(SeatedHash, 0) == 0) { return false; } row = Mathf.Clamp(val2.GetFloat(RowHash, 0f), -1f, 1f); return true; } internal static void OnSeatChanged(Player player, Ship ship) { if (!((Object)(object)ship == (Object)(object)s_seatedShip)) { s_seatedShip = ship; if (Object.op_Implicit((Object)(object)ship) && SailingTogetherPlugin.ShowHint.Value) { ((Character)player).Message((MessageType)1, "Rowing: [W] forward [S] backward — [Jump] stand up", 0, (Sprite)null, false); } } } } [HarmonyPatch(typeof(Player), "SetControls")] internal static class Player_SetControls_Patch { private static void Prefix(Player __instance, ref Vector3 movedir) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { Ship val = (SailingTogetherPlugin.Enabled.Value ? RowerInput.GetSeatedShip(__instance) : null); RowerInput.OnSeatChanged(__instance, val); float row = 0f; if (Object.op_Implicit((Object)(object)val)) { row = movedir.z; movedir = Vector3.zero; } RowerInput.Send(__instance, row, Object.op_Implicit((Object)(object)val)); } } } internal class RowingHud : MonoBehaviour { private enum SeatState { Free, Player, Simulated, Local } private struct SeatView { public SeatState State; public float Row; } private static readonly Color HullFill = new Color(0.42f, 0.28f, 0.15f, 0.85f); private static readonly Color HullEdge = new Color(0.16f, 0.09f, 0.04f, 1f); private static readonly Color FreeColor = new Color(0.85f, 0.85f, 0.85f, 0.55f); private static readonly Color PlayerColor = new Color(0.35f, 0.7f, 1f, 1f); private static readonly Color SimColor = new Color(0.75f, 0.5f, 1f, 1f); private static readonly Color LocalColor = new Color(1f, 0.82f, 0.3f, 1f); private static readonly Color HelmColor = new Color(1f, 0.95f, 0.6f, 1f); private static readonly Color ForwardColor = new Color(0.45f, 1f, 0.45f, 1f); private static readonly Color BackColor = new Color(1f, 0.45f, 0.35f, 1f); private static readonly Color InactiveColor = new Color(0.6f, 0.6f, 0.6f, 0.6f); private const float MaxHullHeight = 140f; private const float MaxHullWidth = 52f; private const float SeatSize = 9f; private const float ArrowSize = 17f; private const float ArrowGap = 4f; private const float OarHeight = 20f; private readonly Dictionary<ShipLayout, Texture2D> _hullTextures = new Dictionary<ShipLayout, Texture2D>(); private readonly List<SeatView> _views = new List<SeatView>(); private Texture2D _circle; private Texture2D _ring; private Texture2D _arrowUp; private Texture2D _arrowDown; private void OnGUI() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_00ea: 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) if ((int)Event.current.type != 7 || !SailingTogetherPlugin.Enabled.Value || !SailingTogetherPlugin.ShowHud.Value) { return; } Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)Hud.instance) || Hud.IsUserHidden() || Menu.IsVisible() || InventoryGui.IsVisible() || Minimap.IsOpen()) { return; } bool flag = false; Ship val = null; IDoodadController doodadController = localPlayer.GetDoodadController(); ShipControlls val2 = (ShipControlls)(object)((doodadController is ShipControlls) ? doodadController : null); if (val2 != null && Object.op_Implicit((Object)(object)val2.m_ship)) { val = val2.m_ship; flag = true; } else { val = RowerInput.GetSeatedShip(localPlayer); } if (Object.op_Implicit((Object)(object)val)) { ShipLayout shipLayout = ShipLayout.Get(val); if (!flag || shipLayout.Seats.Count != 0) { EnsureResources(); GameSprites.TryLoad(); float num = Mathf.Max(1f, (float)Screen.height / 1080f) * SailingTogetherPlugin.HudScale.Value; GUI.matrix = Matrix4x4.Scale(new Vector3(num, num, 1f)); BuildViews(val, shipLayout, localPlayer, flag); Draw(val, shipLayout, flag, num); } } } private void BuildViews(Ship ship, ShipLayout layout, Player local, bool pilot) { //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) _views.Clear(); for (int i = 0; i < layout.Seats.Count; i++) { _views.Add(new SeatView { State = SeatState.Free }); } Transform transform = ((Component)ship).transform; long num = (Object.op_Implicit((Object)(object)ship.m_shipControlls) ? ship.m_shipControlls.GetUser() : 0); List<Player> list = ShipAccess.Players.Invoke(ship); if (list != null) { foreach (Player item in list) { if (!Object.op_Implicit((Object)(object)item) || item.GetPlayerID() == num) { continue; } bool flag = (Object)(object)item == (Object)(object)local; if ((pilot || flag) && RowerInput.TryGetRower(item, out var row)) { int num2 = layout.NearestSeat(transform.InverseTransformPoint(((Component)item).transform.position), 1f); if (num2 >= 0) { _views[num2] = new SeatView { State = ((!flag) ? SeatState.Player : SeatState.Local), Row = row }; } } } } if (!pilot) { return; } foreach (DebugPanel.SimSeat simulatedSeat in DebugPanel.GetSimulatedSeats(ship)) { if (simulatedSeat.Row != 0f) { int num3 = layout.NearestSeat(new Vector3(simulatedSeat.LocalX, (layout.Seats.Count > 0) ? layout.Seats[0].Local.y : 0f, simulatedSeat.LocalZ), 1f); if (num3 >= 0 && _views[num3].State == SeatState.Free) { _views[num3] = new SeatView { State = SeatState.Simulated, Row = simulatedSeat.Row }; } } } } private void Draw(Ship ship, ShipLayout layout, bool pilot, float scale) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: 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) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: 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_0154: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_03fa: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_0428: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_041a: Unknown result type (might be due to invalid IL or missing references) //IL_04b2: Unknown result type (might be due to invalid IL or missing references) //IL_04b9: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_04da: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) float num = 140f; float num2; if (Object.op_Implicit((Object)(object)GameSprites.Ship)) { Rect shipVisible = GameSprites.ShipVisible; Rect rect = GameSprites.Ship.rect; num2 = num * (((Rect)(ref shipVisible)).width * ((Rect)(ref rect)).width) / (((Rect)(ref shipVisible)).height * ((Rect)(ref rect)).height); } else { num2 = Mathf.Min(num * layout.Width / layout.Length, 52f); } float ppmX = num2 / layout.Width; float ppmZ = num / layout.Length; float num3 = 17f; if (Object.op_Implicit((Object)(object)GameSprites.Arrow)) { Rect rect2 = GameSprites.Arrow.rect; float num4 = 17f * ((Rect)(ref rect2)).width; rect2 = GameSprites.Arrow.rect; num3 = num4 / Mathf.Max(1f, ((Rect)(ref rect2)).height); } float num5 = num2 + (num3 + 4f) * 2f; float num6 = (float)Screen.width / scale; float num7 = (float)Screen.height / scale; Rect hull = new Rect(num6 - SailingTogetherPlugin.HudOffsetX.Value - (num5 + num2) * 0.5f, num7 - SailingTogetherPlugin.HudOffsetY.Value - num, num2, num); if (Object.op_Implicit((Object)(object)GameSprites.Ship)) { Rect shipVisible2 = GameSprites.ShipVisible; float num8 = num2 / ((Rect)(ref shipVisible2)).width; float num9 = num / ((Rect)(ref shipVisible2)).height; GameSprites.Draw(new Rect(((Rect)(ref hull)).x - ((Rect)(ref shipVisible2)).x * num8, ((Rect)(ref hull)).y - ((Rect)(ref shipVisible2)).y * num9, num8, num9), GameSprites.Ship, 0f, GameSprites.ShipColor, scale); } else { DrawTinted(hull, GetHullTexture(layout, num2, num), Color.white); } bool flag = ShipAccess.RowingAllowed(ship.GetSpeedSetting()); if (layout.HasHelm) { Vector2 c = ToGui(layout.HelmLocal); DrawTinted(texture: (Object.op_Implicit((Object)(object)ship.m_shipControlls) && ship.m_shipControlls.HaveValidUser()) ? _circle : _ring, rect: Centered(c, 9f), color: HelmColor); } for (int i = 0; i < layout.Seats.Count; i++) { SeatView seatView = _views[i]; if (!pilot && seatView.State != SeatState.Local) { continue; } Vector2 val = ToGui(layout.Seats[i].Local); Rect rect3 = Centered(val, 9f); switch (seatView.State) { case SeatState.Free: DrawTinted(rect3, _ring, FreeColor); continue; case SeatState.Player: DrawTinted(rect3, _circle, PlayerColor); break; case SeatState.Simulated: DrawTinted(rect3, _circle, SimColor); break; case SeatState.Local: DrawTinted(Centered(val, 13f), _ring, Color.white); DrawTinted(rect3, _circle, LocalColor); break; } bool flag2 = Mathf.Abs(seatView.Row) >= 0.05f; DrawOar(val, flag2 ? seatView.Row : 0f, flag, scale); if (flag2) { float num10 = ShipAccess.SideOf(layout.Seats[i].Local.x); Vector2 val2 = ((num10 > 0f) ? new Vector2(((Rect)(ref hull)).xMax + 4f + num3 * 0.5f, val.y) : ((num10 < 0f) ? new Vector2(((Rect)(ref hull)).x - 4f - num3 * 0.5f, val.y) : new Vector2(val.x, val.y - 18.5f))); Color color = ((!flag) ? InactiveColor : ((seatView.Row > 0f) ? ForwardColor : BackColor)); color.a *= Mathf.Lerp(0.5f, 1f, Mathf.Abs(seatView.Row)); if (Object.op_Implicit((Object)(object)GameSprites.Arrow)) { GameSprites.Draw(new Rect(val2.x - num3 * 0.5f, val2.y - 8.5f, num3, 17f), GameSprites.Arrow, (seatView.Row > 0f) ? 0f : 180f, color, scale); } else { DrawTinted(Centered(val2, 17f), (seatView.Row > 0f) ? _arrowUp : _arrowDown, color); } } } Vector2 ToGui(Vector3 local) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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) return new Vector2(((Rect)(ref hull)).x + (local.x - layout.MinX) * ppmX, ((Rect)(ref hull)).y + (layout.MaxZ - local.z) * ppmZ); } } private static void DrawOar(Vector2 seat, float row, bool allowed, float scale) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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) Sprite oar = GameSprites.Oar; if (Object.op_Implicit((Object)(object)oar)) { float angle = 0f; if (row != 0f && allowed) { angle = ((row > 0f) ? (Mathf.Sin(Time.time * 6f) * 20f) : (Mathf.Sin(Time.time * -3f) * 40f)); } Rect rect = oar.rect; float num = 20f * ((Rect)(ref rect)).width; rect = oar.rect; float num2 = num / ((Rect)(ref rect)).height; GameSprites.Draw(new Rect(seat.x - num2 * 0.5f, seat.y - 10f, num2, 20f), oar, angle, allowed ? Color.white : InactiveColor, scale); } } private static Rect Centered(Vector2 c, float size) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) return new Rect(c.x - size * 0.5f, c.y - size * 0.5f, size, size); } private static void DrawTinted(Rect rect, Texture2D texture, Color color) { //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) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Color color2 = GUI.color; GUI.color = color; GUI.DrawTexture(rect, (Texture)(object)texture, (ScaleMode)0, true); GUI.color = color2; } private void EnsureResources() { if (!Object.op_Implicit((Object)(object)_circle)) { _circle = Procedural(32, (float u, float v) => Coverage(0.46f - Mathf.Sqrt(u * u + v * v), 32)); _ring = Procedural(32, delegate(float u, float v) { float num = Mathf.Sqrt(u * u + v * v); return Mathf.Min(Coverage(0.46f - num, 32), Coverage(num - 0.32f, 32)); }); _arrowUp = Procedural(32, (float u, float v) => Coverage(Mathf.Min(v + 0.4f, (0.4f - v) * 0.5f - Mathf.Abs(u) * 1f), 32)); _arrowDown = Procedural(32, (float u, float v) => Coverage(Mathf.Min(0f - v + 0.4f, (0.4f + v) * 0.5f - Mathf.Abs(u) * 1f), 32)); } } private Texture2D GetHullTexture(ShipLayout layout, float width, float height) { //IL_0112: 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_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: 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_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) if (_hullTextures.TryGetValue(layout, out var value) && Object.op_Implicit((Object)(object)value)) { return value; } int num = Mathf.Clamp(Mathf.RoundToInt(width * 2f), 32, 256); int num2 = Mathf.Clamp(Mathf.RoundToInt(height * 2f), 64, 512); value = NewTexture(num, num2); Color32[] array = (Color32[])(object)new Color32[num * num2]; Color val = default(Color); for (int i = 0; i < num2; i++) { float num3 = ((float)i + 0.5f) / (float)num2 * 2f - 1f; float num4 = ((num3 >= 0f) ? Mathf.Pow(Mathf.Max(0f, 1f - num3 * num3), 0.6f) : Mathf.Pow(Mathf.Max(0f, 1f - Mathf.Pow(0f - num3, 2.5f)), 0.55f)); for (int j = 0; j < num; j++) { float num5 = Mathf.Abs(((float)j + 0.5f) / (float)num * 2f - 1f); float num6 = (num4 - num5) * (float)num * 0.5f; if (num6 <= -1f) { val = Color.clear; } else if (num6 < 3f) { ((Color)(ref val))..ctor(HullEdge.r, HullEdge.g, HullEdge.b, HullEdge.a * Mathf.Clamp01(num6 + 1f)); } else { val = HullFill; if (Mathf.Repeat((float)i, 10f) < 1f) { val *= 0.85f; } if (num5 * (float)num * 0.5f < 1f) { val = Color.Lerp(val, HullEdge, 0.5f); } val.a = HullFill.a; } array[i * num + j] = Color32.op_Implicit(val); } } value.SetPixels32(array); value.Apply(); _hullTextures[layout] = value; return value; } private static float Coverage(float signedDistance, int size) { return Mathf.Clamp01(signedDistance * (float)size + 0.5f); } private static Texture2D Procedural(int size, Func<float, float, float> alpha) { //IL_005e: 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_0068: Unknown result type (might be due to invalid IL or missing references) Texture2D val = NewTexture(size, size); Color32[] array = (Color32[])(object)new Color32[size * size]; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float arg = ((float)j + 0.5f) / (float)size - 0.5f; float arg2 = ((float)i + 0.5f) / (float)size - 0.5f; array[i * size + j] = Color32.op_Implicit(new Color(1f, 1f, 1f, alpha(arg, arg2))); } } val.SetPixels32(array); val.Apply(); return val; } private static Texture2D NewTexture(int w, int h) { //IL_0004: 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) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown return new Texture2D(w, h, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, hideFlags = (HideFlags)61 }; } } [BepInPlugin("farias.SailingTogether", "SailingTogether", "1.0.0")] public class SailingTogetherPlugin : BaseUnityPlugin { public const string ModGuid = "farias.SailingTogether"; public const string ModName = "SailingTogether"; public const string ModVersion = "1.0.0"; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> PowerPerRower; internal static ConfigEntry<float> TurnAccelPerRower; internal static ConfigEntry<float> MaxTurnRate; internal static ConfigEntry<float> CenterDeadZone; internal static ConfigEntry<bool> RowInStop; internal static ConfigEntry<bool> RowInBack; internal static ConfigEntry<bool> ShowHint; internal static ConfigEntry<bool> ShowHud; internal static ConfigEntry<float> HudScale; internal static ConfigEntry<float> HudOffsetX; internal static ConfigEntry<float> HudOffsetY; internal static ConfigEntry<string> HudShipSprite; internal static ConfigEntry<string> HudArrowSprite; internal static ConfigEntry<string> HudOarSprite; internal static ConfigEntry<bool> DebugTool; internal static ConfigEntry<KeyboardShortcut> DebugHotkey; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enables/disables cooperative rowing."); PowerPerRower = ((BaseUnityPlugin)this).Config.Bind<float>("Rowing", "PowerPerRower", 0.35f, "Force of each rower, as a fraction of the ship's own helm-oar force (speed 1)."); TurnAccelPerRower = ((BaseUnityPlugin)this).Config.Bind<float>("Rowing", "TurnAccelPerRower", 10f, "Turn acceleration (degrees/s²) produced by each unbalanced rower (e.g. one side rowing and the other not)."); MaxTurnRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rowing", "MaxTurnRate", 25f, "Maximum turn rate (degrees/s) the rowers can apply to the ship."); CenterDeadZone = ((BaseUnityPlugin)this).Config.Bind<float>("Rowing", "CenterDeadZone", 0.4f, "Lateral distance (meters) from the ship's centerline within which a bench counts as 'center' (pushes only, does not turn)."); RowInStop = ((BaseUnityPlugin)this).Config.Bind<bool>("Rowing", "RowInStop", false, "Allows rowing while the ship is stopped (speed 0), even with nobody at the helm."); RowInBack = ((BaseUnityPlugin)this).Config.Bind<bool>("Rowing", "RowInBack", true, "Allows rowing while the ship is in reverse."); ShowHint = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowHint", true, "Shows the controls hint when sitting on a ship bench."); ShowHud = ((BaseUnityPlugin)this).Config.Bind<bool>("Hud", "ShowShipHud", true, "Shows the top-down ship HUD with the benches (helmsman: all benches, rower: only their own)."); HudScale = ((BaseUnityPlugin)this).Config.Bind<float>("Hud", "Scale", 1f, "Scale of the ship HUD."); HudOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Hud", "OffsetX", 30f, "Distance (px at 1080p) from the right edge of the screen."); HudOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Hud", "OffsetY", 230f, "Distance (px at 1080p) from the bottom edge of the screen."); HudShipSprite = ((BaseUnityPlugin)this).Config.Bind<string>("Hud", "ShipSprite", "ship_top", "Name of the game sprite used for the ship (bow up). Empty = built-in drawing."); HudArrowSprite = ((BaseUnityPlugin)this).Config.Bind<string>("Hud", "ArrowSprite", "winddirection", "Name of the game sprite used for the arrows (tip up). Empty = built-in drawing."); HudOarSprite = ((BaseUnityPlugin)this).Config.Bind<string>("Hud", "OarSprite", "ship_rudder_icon", "Name of the game sprite used for the animated oar on each occupied bench. Empty = no oar."); HudOarSprite.SettingChanged += delegate { GameSprites.Reset(); }; HudShipSprite.SettingChanged += delegate { GameSprites.Reset(); }; HudArrowSprite.SettingChanged += delegate { GameSprites.Reset(); }; DebugTool = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "SimulatorPanel", false, "Enables the simulated rowers panel (F8), for testing alone. Default: disabled."); DebugHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Debug", "SimulatorHotkey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Key that opens/closes the simulated rowers panel."); ((Component)this).gameObject.AddComponent<DebugPanel>(); ((Component)this).gameObject.AddComponent<RowingHud>(); _harmony = new Harmony("farias.SailingTogether"); _harmony.PatchAll(typeof(SailingTogetherPlugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SailingTogether 1.0.0 loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class ShipAccess { internal static readonly FieldRef<Ship, List<Player>> Players = AccessTools.FieldRefAccess<Ship, List<Player>>("m_players"); internal static float SideOf(float localX) { if (!(Mathf.Abs(localX) < SailingTogetherPlugin.CenterDeadZone.Value)) { return Mathf.Sign(localX); } return 0f; } internal static bool RowingAllowed(Speed speed) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected I4, but got Unknown return (int)speed switch { 2 => true, 1 => SailingTogetherPlugin.RowInBack.Value, 0 => SailingTogetherPlugin.RowInStop.Value, _ => false, }; } } internal class ShipLayout { internal class Seat { public Vector3 Local; } private static readonly Dictionary<string, ShipLayout> s_cache = new Dictionary<string, ShipLayout>(); public readonly List<Seat> Seats = new List<Seat>(); public bool HasHelm; public Vector3 HelmLocal; public float MinX; public float MaxX; public float MinZ; public float MaxZ; public float Length => MaxZ - MinZ; public float Width => MaxX - MinX; internal static ShipLayout Get(Ship ship) { string prefabName = Utils.GetPrefabName(((Component)ship).gameObject); if (!s_cache.TryGetValue(prefabName, out var value)) { value = Build(ship); s_cache[prefabName] = value; } return value; } private static ShipLayout Build(Ship ship) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: 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_0158: 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_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)ship).transform; ShipLayout shipLayout = new ShipLayout(); Chair[] componentsInChildren = ((Component)ship).GetComponentsInChildren<Chair>(); foreach (Chair val in componentsInChildren) { Transform val2 = (Object.op_Implicit((Object)(object)val.m_attachPoint) ? val.m_attachPoint : ((Component)val).transform); shipLayout.Seats.Add(new Seat { Local = transform.InverseTransformPoint(val2.position) }); } shipLayout.Seats.Sort((Seat a, Seat b) => (!(Mathf.Abs(a.Local.z - b.Local.z) > 0.05f)) ? a.Local.x.CompareTo(b.Local.x) : b.Local.z.CompareTo(a.Local.z)); if (Object.op_Implicit((Object)(object)ship.m_shipControlls)) { Transform val3 = (Object.op_Implicit((Object)(object)ship.m_shipControlls.m_attachPoint) ? ship.m_shipControlls.m_attachPoint : ((Component)ship.m_shipControlls).transform); shipLayout.HasHelm = true; shipLayout.HelmLocal = transform.InverseTransformPoint(val3.position); } shipLayout.MinX = (shipLayout.MinZ = float.MaxValue); shipLayout.MaxX = (shipLayout.MaxZ = float.MinValue); if (Object.op_Implicit((Object)(object)ship.m_floatCollider)) { BoxCollider floatCollider = ship.m_floatCollider; Vector3 val4 = floatCollider.size * 0.5f; for (int num = -1; num <= 1; num += 2) { for (int num2 = -1; num2 <= 1; num2 += 2) { shipLayout.Encapsulate(transform.InverseTransformPoint(((Component)floatCollider).transform.TransformPoint(floatCollider.center + new Vector3(val4.x * (float)num, 0f, val4.z * (float)num2))), 0f); } } } foreach (Seat seat in shipLayout.Seats) { shipLayout.Encapsulate(seat.Local, 0.6f); } if (shipLayout.HasHelm) { shipLayout.Encapsulate(shipLayout.HelmLocal, 0.6f); } if (shipLayout.MinX > shipLayout.MaxX) { shipLayout.MinX = -1.5f; shipLayout.MaxX = 1.5f; shipLayout.MinZ = -4f; shipLayout.MaxZ = 4f; } return shipLayout; } private void Encapsulate(Vector3 p, float margin) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) MinX = Mathf.Min(MinX, p.x - margin); MaxX = Mathf.Max(MaxX, p.x + margin); MinZ = Mathf.Min(MinZ, p.z - margin); MaxZ = Mathf.Max(MaxZ, p.z + margin); } internal int NearestSeat(Vector3 local, float maxDistance) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) int result = -1; float num = maxDistance * maxDistance; for (int i = 0; i < Seats.Count; i++) { Vector3 val = Seats[i].Local - local; val.y *= 0.5f; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = i; } } return result; } } [HarmonyPatch(typeof(Ship), "CustomFixedUpdate")] internal static class Ship_CustomFixedUpdate_Patch { private static readonly FieldRef<Ship, ZNetView> s_nview = AccessTools.FieldRefAccess<Ship, ZNetView>("m_nview"); private static readonly FieldRef<Ship, Rigidbody> s_body = AccessTools.FieldRefAccess<Ship, Rigidbody>("m_body"); private static readonly FieldRef<Ship, WaterVolume> s_previousCenter = AccessTools.FieldRefAccess<Ship, WaterVolume>("m_previousCenter"); private static void Postfix(Ship __instance, float fixedDeltaTime) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) if (!SailingTogetherPlugin.Enabled.Value) { return; } ZNetView val = s_nview.Invoke(__instance); if (!Object.op_Implicit((Object)(object)val) || !val.IsValid()) { return; } RowingStats stats = RowingStats.For(__instance); stats.Reset(); stats.IsOwner = val.IsOwner(); if (!stats.IsOwner) { return; } stats.Allowed = ShipAccess.RowingAllowed(__instance.GetSpeedSetting()); Transform transform = ((Component)__instance).transform; float thrust = 0f; float turn = 0f; List<Player> list = ShipAccess.Players.Invoke(__instance); if (list != null) { long num = (Object.op_Implicit((Object)(object)__instance.m_shipControlls) ? __instance.m_shipControlls.GetUser() : 0); foreach (Player item in list) { if (Object.op_Implicit((Object)(object)item) && item.GetPlayerID() != num && RowerInput.TryGetRower(item, out var row)) { AddRower(transform.InverseTransformPoint(((Component)item).transform.position).x, row); } } } foreach (DebugPanel.SimSeat simulatedSeat in DebugPanel.GetSimulatedSeats(__instance)) { AddRower(simulatedSeat.LocalX, simulatedSeat.Row); } stats.Thrust = thrust; stats.Turn = turn; Rigidbody val2 = s_body.Invoke(__instance); if (!Object.op_Implicit((Object)(object)val2)) { return; } stats.YawRate = Vector3.Dot(val2.angularVelocity, transform.up) * 57.29578f; stats.Floating = IsFloating(__instance, val2); if (stats.Allowed && stats.Floating && (thrust != 0f || turn != 0f)) { stats.Applied = true; float num2 = __instance.m_backwardForce * SailingTogetherPlugin.PowerPerRower.Value; val2.AddForce(transform.forward * (thrust * num2 * fixedDeltaTime), (ForceMode)2); Vector3 up = transform.up; float yawRate = stats.YawRate; float num3 = (0f - turn) * SailingTogetherPlugin.TurnAccelPerRower.Value * fixedDeltaTime; float value = SailingTogetherPlugin.MaxTurnRate.Value; if (num3 > 0f) { num3 = Mathf.Min(num3, Mathf.Max(0f, value - yawRate)); } else if (num3 < 0f) { num3 = Mathf.Max(num3, Mathf.Min(0f, 0f - value - yawRate)); } if (num3 != 0f) { val2.AddTorque(up * (num3 * ((float)Math.PI / 180f)), (ForceMode)2); } } void AddRower(float localX, float num4) { num4 = Mathf.Clamp(num4, -1f, 1f); if (!(Mathf.Abs(num4) < 0.05f)) { float num5 = ShipAccess.SideOf(localX); thrust += num4; turn += num4 * num5; stats.Rowers++; } } } private static bool IsFloating(Ship ship, Rigidbody body) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) Vector3 worldCenterOfMass = body.worldCenterOfMass; float waterLevel = Floating.GetWaterLevel(worldCenterOfMass, ref s_previousCenter.Invoke(ship)); return worldCenterOfMass.y - waterLevel - ship.m_waterLevelOffset <= ship.m_disableLevel; } } internal class RowingStats { private static readonly RowingStats s_empty = new RowingStats(); private static Ship s_ship; private static readonly RowingStats s_current = new RowingStats(); public bool IsOwner; public bool Allowed; public bool Floating; public bool Applied; public int Rowers; public float Thrust; public float Turn; public float YawRate; internal static RowingStats For(Ship ship) { if ((Object)(object)ship != (Object)(object)Ship.GetLocalShip()) { return s_empty; } s_ship = ship; return s_current; } internal static RowingStats Get(Ship ship) { if (!Object.op_Implicit((Object)(object)ship) || !((Object)(object)ship == (Object)(object)s_ship)) { return null; } return s_current; } internal void Reset() { IsOwner = (Allowed = (Floating = (Applied = false))); Rowers = 0; Thrust = (Turn = (YawRate = 0f)); } } }