using System; using System.Collections; 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 FishNet; using FishNet.Connection; using FishNet.Managing; using FishNet.Managing.Object; using FishNet.Object; using FishNet.Observing; using HarmonyLib; using HowToFish.OpenSea.Pirates; using Microsoft.CodeAnalysis; using Unity.Mathematics; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Behold")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Adds hostile pirate fleets to the open ocean in How to Fish.")] [assembly: AssemblyFileVersion("0.10.2.0")] [assembly: AssemblyInformationalVersion("0.10.2+8a654bc991c15eb866a0717277930c97c5c304ad")] [assembly: AssemblyProduct("Behold: Pirates")] [assembly: AssemblyTitle("Behold: Pirates")] [assembly: AssemblyVersion("0.10.2.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 HowToFish.OpenSea { internal sealed class OpenSeaBoundary : MonoBehaviour { private const int ShorelineSampleCount = 120; private const float MinimumScanRadius = 500f; private const float ScanRadiusMultiplier = 4f; private const float MinimumValidShoreRadius = 1f; private const float MinimumValidSampleRatio = 0.5f; private static readonly float[] ProbeHeightsAboveWater = new float[3] { 0.25f, 1f, 2f }; private ConfigEntry _distanceBeyondIsland; private Island? _sampledIsland; private Vector3 _islandPosition; private float _authoredIslandRadius; private float[] _shoreRadii = Array.Empty(); private int _revision; public int Revision { get { EnsureCurrentIsland(); return _revision; } } public int SampleCount { get { EnsureCurrentIsland(); return _shoreRadii.Length; } } public float DistanceBeyondIsland => Mathf.Max(0f, _distanceBeyondIsland.Value); public void Initialize(ConfigEntry distanceBeyondIsland) { _distanceBeyondIsland = distanceBeyondIsland; } private void Update() { EnsureCurrentIsland(); } public float GetDistanceFromShoreline(Vector3 position) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) EnsureCurrentIsland(); Vector3 offset = position - _islandPosition; offset.y = 0f; return ((Vector3)(ref offset)).magnitude - GetShoreRadius(offset); } public bool IsBeyondBoundary(Vector3 position, float distanceBeyondShoreline) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return GetDistanceFromShoreline(position) > Mathf.Max(0f, distanceBeyondShoreline); } public Vector3 GetBoundaryPoint(int sampleIndex, float distanceBeyondShoreline) { //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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_0010: Unknown result type (might be due to invalid IL or missing references) EnsureCurrentIsland(); if (_shoreRadii.Length == 0) { return _islandPosition; } int num = (sampleIndex % _shoreRadii.Length + _shoreRadii.Length) % _shoreRadii.Length; float num2 = MathF.PI * 2f * (float)num / (float)_shoreRadii.Length; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(Mathf.Cos(num2), 0f, Mathf.Sin(num2)); float num3 = _shoreRadii[num] + Mathf.Max(0f, distanceBeyondShoreline); return _islandPosition + val * num3; } private void EnsureCurrentIsland() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (IslandManager.IsLoading || !Object.op_Implicit((Object)(object)Island.CurIsland)) { Clear(); return; } Island curIsland = Island.CurIsland; if (!((Object)(object)_sampledIsland == (Object)(object)curIsland) || !(HorizontalSqrDistance(_islandPosition, Island.IslandPos) <= 0.01f) || !Mathf.Approximately(_authoredIslandRadius, Island.IslandSize)) { SampleShoreline(curIsland); } } private void SampleShoreline(Island island) { //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_00a2: Unknown result type (might be due to invalid IL or missing references) _sampledIsland = island; _islandPosition = Island.IslandPos; _authoredIslandRadius = Mathf.Max(1f, Island.IslandSize); _shoreRadii = new float[120]; bool[] array = new bool[120]; float scanRadius = Mathf.Max(500f, _authoredIslandRadius * 4f); float waterHeight = WaterManager.WaterHeight; int num = 0; float num2 = float.PositiveInfinity; float num3 = 0f; Physics.SyncTransforms(); Vector3 outward = default(Vector3); for (int i = 0; i < 120; i++) { float num4 = MathF.PI * 2f * (float)i / 120f; ((Vector3)(ref outward))..ctor(Mathf.Cos(num4), 0f, Mathf.Sin(num4)); float num5 = FindOutermostShoreRadius(outward, scanRadius, waterHeight); if (num5 >= 1f) { array[i] = true; num++; num2 = Mathf.Min(num2, num5); num3 = Mathf.Max(num3, num5); _shoreRadii[i] = num5; } else { _shoreRadii[i] = _authoredIslandRadius; } } if (num < Mathf.CeilToInt(60f)) { for (int j = 0; j < _shoreRadii.Length; j++) { _shoreRadii[j] = _authoredIslandRadius; } Plugin.Log.LogWarning((object)($"Only {num}/{120} shoreline directions hit level geometry; " + $"using the authored {_authoredIslandRadius:0.#}m island radius as the open-sea boundary fallback.")); } else { ReplaceMissingSamples(array); Plugin.Log.LogInfo((object)($"Sampled the island shoreline in {num}/{120} directions " + $"with radii from {num2:0.#}m to {num3:0.#}m.")); } _revision++; } private float FindOutermostShoreRadius(Vector3 outward, float scanRadius, float waterHeight) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0051: 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_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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) float num = -1f; float[] probeHeightsAboveWater = ProbeHeightsAboveWater; RaycastHit val2 = default(RaycastHit); foreach (float num2 in probeHeightsAboveWater) { Vector3 val = _islandPosition + outward * scanRadius; val.y = waterHeight + num2; if (Physics.Raycast(val, -outward, ref val2, scanRadius, LayerMask.op_Implicit(GameInfo.LevelLayer), (QueryTriggerInteraction)1)) { Vector3 val3 = ((RaycastHit)(ref val2)).point - _islandPosition; val3.y = 0f; float num3 = Vector3.Dot(val3, outward); num = Mathf.Max(num, num3); } } return num; } private void ReplaceMissingSamples(bool[] validDirections) { for (int i = 0; i < _shoreRadii.Length; i++) { if (!validDirections[i]) { int num = FindValidNeighbor(i, -1, validDirections); int num2 = FindValidNeighbor(i, 1, validDirections); if (num != i && num2 != i) { int num3 = (num2 - num + _shoreRadii.Length) % _shoreRadii.Length; int num4 = (i - num + _shoreRadii.Length) % _shoreRadii.Length; _shoreRadii[i] = Mathf.Lerp(_shoreRadii[num], _shoreRadii[num2], (float)num4 / (float)num3); } } } } private int FindValidNeighbor(int startIndex, int step, bool[] validDirections) { int num = startIndex; for (int i = 0; i < _shoreRadii.Length; i++) { num = (num + step + _shoreRadii.Length) % _shoreRadii.Length; if (validDirections[num]) { return num; } } return startIndex; } private float GetShoreRadius(Vector3 offset) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (_shoreRadii.Length == 0 || ((Vector3)(ref offset)).sqrMagnitude <= 0.0001f) { return _authoredIslandRadius; } float num = Mathf.Atan2(offset.z, offset.x); if (num < 0f) { num += MathF.PI * 2f; } float num2 = num * (float)_shoreRadii.Length / (MathF.PI * 2f); int num3 = Mathf.FloorToInt(num2) % _shoreRadii.Length; int num4 = (num3 + 1) % _shoreRadii.Length; return Mathf.Lerp(_shoreRadii[num3], _shoreRadii[num4], num2 - (float)num3); } private void Clear() { if (Object.op_Implicit((Object)(object)_sampledIsland) || _shoreRadii.Length != 0) { _sampledIsland = null; _shoreRadii = Array.Empty(); _authoredIslandRadius = 0f; _revision++; } } private static float HorizontalSqrDistance(Vector3 first, Vector3 second) { //IL_0000: 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) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = first.x - second.x; float num2 = first.z - second.z; return num * num + num2 * num2; } } internal sealed class OpenSeaBoundaryMarkers : MonoBehaviour { private const float MarkerSpacing = 10f; private const float MarkerDiameter = 0.6f; private const string MarkerShaderName = "Universal Render Pipeline/Lit"; private static readonly int BaseColorId = Shader.PropertyToID("_BaseColor"); private static readonly Color MarkerColor = Color32.op_Implicit(new Color32(byte.MaxValue, (byte)60, (byte)12, byte.MaxValue)); private readonly List _markers = new List(); private OpenSeaBoundary _openSeaBoundary; private GameObject? _markerRoot; private Material? _markerMaterial; private Mesh? _markerMesh; private int _boundaryRevision = -1; private float _boundaryOffset = -1f; public void Initialize(OpenSeaBoundary openSeaBoundary) { _openSeaBoundary = openSeaBoundary; } private void Update() { if (IslandManager.IsLoading || !Object.op_Implicit((Object)(object)Island.CurIsland)) { ClearMarkers(); return; } int revision = _openSeaBoundary.Revision; float distanceBeyondIsland = _openSeaBoundary.DistanceBeyondIsland; if (!Object.op_Implicit((Object)(object)_markerRoot) || revision != _boundaryRevision || !Mathf.Approximately(distanceBeyondIsland, _boundaryOffset)) { CreateMarkers(revision, distanceBeyondIsland); } UpdateWaterHeights(); } private void CreateMarkers(int boundaryRevision, float boundaryOffset) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //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_0097: 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) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_014e: 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_0161: 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) ClearMarkers(); _boundaryRevision = boundaryRevision; _boundaryOffset = boundaryOffset; _markerRoot = new GameObject("Open Sea Boundary Markers"); _markerRoot.transform.SetParent(((Component)this).transform, false); int sampleCount = _openSeaBoundary.SampleCount; if (sampleCount == 0) { return; } Vector3[] array = (Vector3[])(object)new Vector3[sampleCount]; float[] array2 = new float[sampleCount]; float num = 0f; for (int i = 0; i < _openSeaBoundary.SampleCount; i++) { array[i] = _openSeaBoundary.GetBoundaryPoint(i, boundaryOffset); } for (int j = 0; j < sampleCount; j++) { num += (array2[j] = Vector3.Distance(array[j], array[(j + 1) % sampleCount])); } if (num <= Mathf.Epsilon) { CreateMarker(0, array[0]); return; } int num2 = Mathf.Max(1, Mathf.RoundToInt(num / 10f)); float num3 = num / (float)num2; int k = 0; float num4 = 0f; for (int l = 0; l < num2; l++) { float num5; for (num5 = (float)l * num3; k < sampleCount && (array2[k] <= Mathf.Epsilon || num4 + array2[k] < num5); k++) { num4 += array2[k]; } if (k >= sampleCount) { break; } float num6 = (num5 - num4) / array2[k]; Vector3 position = Vector3.Lerp(array[k], array[(k + 1) % sampleCount], num6); CreateMarker(l, position); } Plugin.Log.LogInfo((object)($"Created {num2} orange-red shoreline-shaped open-sea boundary markers " + $"approximately {num3:0.#}m apart.")); } private void CreateMarker(int index, Vector3 position) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_0045: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject($"Open Sea Boundary Point {index + 1}"); val.layer = LayerMask.NameToLayer("Ignore Raycast"); val.transform.SetParent(_markerRoot.transform, true); val.transform.position = position; val.transform.localScale = Vector3.one * 0.6f; MeshFilter obj = val.AddComponent(); if (!Object.op_Implicit((Object)(object)_markerMesh)) { _markerMesh = CreateMarkerMesh(); } obj.sharedMesh = _markerMesh; MeshRenderer obj2 = val.AddComponent(); if (!Object.op_Implicit((Object)(object)_markerMaterial)) { Shader val2 = Shader.Find("Universal Render Pipeline/Lit"); if (!Object.op_Implicit((Object)(object)val2)) { Plugin.Log.LogError((object)"Could not find the Universal Render Pipeline/Lit shader for boundary markers."); } else { _markerMaterial = new Material(val2) { name = "Open Sea Boundary Orange Red", color = MarkerColor }; _markerMaterial.SetColor(BaseColorId, MarkerColor); } } ((Renderer)obj2).sharedMaterial = _markerMaterial; ((Renderer)obj2).shadowCastingMode = (ShadowCastingMode)1; ((Renderer)obj2).receiveShadows = true; _markers.Add(val.transform); } private static Mesh CreateMarkerMesh() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) //IL_005f: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0131: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_019c: 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_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Expected O, but got Unknown float num = (1f + Mathf.Sqrt(5f)) * 0.5f; Vector3[] array = (Vector3[])(object)new Vector3[12] { new Vector3(-1f, num, 0f), new Vector3(1f, num, 0f), new Vector3(-1f, 0f - num, 0f), new Vector3(1f, 0f - num, 0f), new Vector3(0f, -1f, num), new Vector3(0f, 1f, num), new Vector3(0f, -1f, 0f - num), new Vector3(0f, 1f, 0f - num), new Vector3(num, 0f, -1f), new Vector3(num, 0f, 1f), new Vector3(0f - num, 0f, -1f), new Vector3(0f - num, 0f, 1f) }; int[] array2 = new int[60] { 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 }; Vector3[] array3 = (Vector3[])(object)new Vector3[array2.Length]; int[] array4 = new int[array2.Length]; for (int i = 0; i < array2.Length; i++) { array3[i] = ((Vector3)(ref array[array2[i]])).normalized * 0.5f; array4[i] = i; } Mesh val = new Mesh { name = "Open Sea Boundary Low-Poly Icosahedron", vertices = array3, triangles = array4 }; val.RecalculateNormals(); val.RecalculateBounds(); val.UploadMeshData(true); return val; } private void UpdateWaterHeights() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) foreach (Transform marker in _markers) { if (Object.op_Implicit((Object)(object)marker)) { Vector3 position = marker.position; position.y = WaterManager.GetWaterHeight(position); marker.position = position; } } } private void ClearMarkers() { if (Object.op_Implicit((Object)(object)_markerRoot)) { Object.Destroy((Object)(object)_markerRoot); } _markerRoot = null; _markers.Clear(); _boundaryRevision = -1; _boundaryOffset = -1f; } private void OnDestroy() { ClearMarkers(); if (Object.op_Implicit((Object)(object)_markerMaterial)) { Object.Destroy((Object)(object)_markerMaterial); } if (Object.op_Implicit((Object)(object)_markerMesh)) { Object.Destroy((Object)(object)_markerMesh); } } } internal sealed class OpenSeaConfig { public ConfigEntry PiratesEnabled { get; } public ConfigEntry DistanceBeyondIsland { get; } public ConfigEntry DifficultyMultiplier { get; } public ConfigEntry MaximumActiveBoats { get; } public ConfigEntry BoundaryMarkersEnabled { get; } public OpenSeaConfig(ConfigFile config) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Expected O, but got Unknown PiratesEnabled = config.Bind("Pirates", "Enabled", true, "Spawn pirate encounters in the open ocean. The host's setting controls multiplayer encounters."); DistanceBeyondIsland = config.Bind("Pirates", "DistanceBeyondIsland", 60f, new ConfigDescription("Horizontal distance in metres beyond the sampled island shoreline before pirates spawn.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 500f), Array.Empty())); DifficultyMultiplier = config.Bind("Pirates", "DifficultyMultiplier", 1f, new ConfigDescription("Multiplier applied to the value budget used to equip and reinforce pirate fleets. Lower values make encounters easier; higher values make them harder.", (AcceptableValueBase)(object)new AcceptableValueRange(0.25f, 3f), Array.Empty())); MaximumActiveBoats = config.Bind("Pirates", "MaximumActiveBoats", 8, new ConfigDescription("Maximum number of pirate boats that may be active at once.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 8), Array.Empty())); BoundaryMarkersEnabled = config.Bind("Visuals", "BoundaryMarkersEnabled", true, "Show the orange-red markers around the open-sea encounter boundary."); } } internal sealed class PirateEncounterController : MonoBehaviour { private sealed class PirateBoatPlan { public int MotorIndex; public IReadOnlyList Weapons; public int Worth; } private sealed class PirateFleetPlan { public readonly List Boats = new List(); public int Worth; } private const float CheckInterval = 1f; private const float PreferredSingleBoatChance = 0.7f; private const float PreferredTwoBoatChance = 0.25f; private const float AdditionalPirateChance = 0.5f; private const float AdditionalPirateChanceMultiplier = 0.5f; private const float HorizonSpawnDistance = 250f; private const float MaximumFleetBearingOffsetDegrees = 90f; private const float FleetArcSpacingDegrees = 12f; private const float FleetArcJitterDegrees = 4f; private const float WeaponRangeOrbitMultiplier = 0.25f; private const float UpgradeMotorWeightMultiplier = 0.35f; private const float FleetWorthLowerBound = 0.75f; private const int WorthPercentPerDistanceBand = 10; private const int PirateHullWorth = 100; private const int MaximumFleetRerolls = 256; private static readonly string[] PirateWeaponSpawnNames = new string[5] { "pistol", "shotgun", "smg", "assaultrifle", "sniperrifle" }; private static readonly FieldInfo MotorsField = AccessTools.Field(typeof(Boat), "_motors"); private static readonly FieldInfo MotorPurchasableIndexField = AccessTools.Field(typeof(MotorPurchasable), "_motorIndex"); private static readonly FieldInfo PurchasableCostField = AccessTools.Field(typeof(Purchasable), "_customCost"); private static readonly Dictionary MotorWorthByIndex = new Dictionary(); private OpenSeaConfig _config; private OpenSeaBoundary _openSeaBoundary; private Boat? _boatPrefab; private readonly List _weapons = new List(); private readonly Dictionary _activePirateBoats = new Dictionary(); private float _nextCheckTime; private int _preferredReinforcementBoatCount; private bool _loggedNoWeapons; private bool _motorWorthsLoaded; public void Initialize(OpenSeaConfig config, OpenSeaBoundary openSeaBoundary) { _config = config; _openSeaBoundary = openSeaBoundary; } private void Update() { if (Time.time < _nextCheckTime) { return; } _nextCheckTime = Time.time + 1f; if (!Object.op_Implicit((Object)(object)Server.Instance) || !((NetworkBehaviour)Server.Instance).IsServerInitialized) { return; } if (!_config.PiratesEnabled.Value) { DespawnPirates(); return; } if (IslandManager.IsLoading || !Object.op_Implicit((Object)(object)Island.CurIsland)) { _motorWorthsLoaded = false; DespawnPirates(); return; } if (!_motorWorthsLoaded) { RefreshMotorWorths(); _motorWorthsLoaded = true; } float distanceBeyondIsland = _openSeaBoundary.DistanceBeyondIsland; float farthestDistanceFromShoreline; Player val = FindFarthestPlayerFromIsland(out farthestDistanceFromShoreline); RemoveDestroyedPirateBoats(); if (!Object.op_Implicit((Object)(object)val) || farthestDistanceFromShoreline <= distanceBeyondIsland) { _preferredReinforcementBoatCount = 0; return; } int openOceanPlayerWorth = GetOpenOceanPlayerWorth(distanceBeyondIsland, farthestDistanceFromShoreline); openOceanPlayerWorth = ApplyDifficultyMultiplier(openOceanPlayerWorth); int activePirateWorth = GetActivePirateWorth(); int num = Mathf.Max(1, openOceanPlayerWorth); int num2 = Mathf.Max(0, _config.MaximumActiveBoats.Value - _activePirateBoats.Count); if (activePirateWorth < num && num2 > 0) { TrySpawnPirates(val, num - activePirateWorth, openOceanPlayerWorth, num2); } else { _preferredReinforcementBoatCount = 0; } } private bool TrySpawnPirates(Player target, int reinforcementWorth, int playerWorth, int maximumBoatCount) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_00a1: 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_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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) Boat boatPrefab = GetBoatPrefab(); if (!Object.op_Implicit((Object)(object)boatPrefab)) { Plugin.Log.LogError((object)"Could not find the game's registered boat network prefab for the pirate encounter."); return false; } IReadOnlyList readOnlyList = FindPirateWeapons(); if (readOnlyList.Count == 0) { if (!_loggedNoWeapons) { _loggedNoWeapons = true; Plugin.Log.LogError((object)"No pirate weapon resources were available; pirate encounter could not spawn."); } return false; } _loggedNoWeapons = false; if (_preferredReinforcementBoatCount <= 0) { _preferredReinforcementBoatCount = Mathf.Min(SelectPreferredReinforcementBoatCount(), maximumBoatCount); } Vector3 val = target.Transform.position - Island.IslandPos; val.y = 0f; Vector3 val2 = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val)).normalized : Vector3.forward); PirateFleetPlan pirateFleetPlan = SelectFleetForWorth(boatPrefab, readOnlyList, reinforcementWorth, playerWorth, _preferredReinforcementBoatCount, maximumBoatCount); if (pirateFleetPlan == null) { return false; } int count = pirateFleetPlan.Boats.Count; Vector3 seawardDirection = Quaternion.AngleAxis(Random.Range(-90f, 90f), Vector3.up) * val2; float formationAngle = Random.Range(-4f, 4f); for (int i = 0; i < count; i++) { SpawnPirateBoat(target, boatPrefab, pirateFleetPlan.Boats[i], seawardDirection, formationAngle, i, count, playerWorth, pirateFleetPlan.Worth); } _preferredReinforcementBoatCount = 0; return true; } private void SpawnPirateBoat(Player target, Boat boatPrefab, PirateBoatPlan plan, Vector3 seawardDirection, float formationAngle, int index, int boatCount, int playerWorth, int fleetWorth) { //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_0024: 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_0045: 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_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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: 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) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) float num = (float)index - (float)(boatCount - 1) * 0.5f; Vector3 val = Quaternion.AngleAxis(formationAngle + num * 12f, Vector3.up) * seawardDirection; float num2 = 250f + Mathf.Abs(num) * 5f; Vector3 val2 = target.Transform.position + val * num2; val2.y = SpawnManager.BoatSpawnPos.y; Vector3 desiredForward = target.Transform.position - val2; desiredForward.y = 0f; Quaternion val3 = Quaternion.LookRotation(((Vector3)(ref desiredForward)).normalized, Vector3.up); Boat val4 = Object.Instantiate(boatPrefab, val2, val3); ((Object)val4).name = $"Pirate Boat {index + 1}"; int motorIndex = plan.MotorIndex; AlignBoatForward(val4, desiredForward); IReadOnlyList weapons = plan.Weapons; int count = weapons.Count; float num3 = weapons.Max((PirateWeaponDefinition weapon) => weapon.AttackRange) * 0.25f; string motorName = GetMotorName(val4, motorIndex); ConfigureLongRangeNetworkVisibility(val4); PirateBoatSupport.RegisterServerPirate(val4, weapons); ((Component)val4).gameObject.AddComponent().Initialize(val4, weapons, num3, _openSeaBoundary); ((NetworkBehaviour)Server.Instance).Spawn(((Component)val4).gameObject, (NetworkConnection)null, default(Scene)); val4._curSkin.Value = (byte)(count - 1); val4._boatUnlocked.Value = true; val4._boatRadarUnlocked.Value = true; val4._motorIndex.Value = (byte)motorIndex; _activePirateBoats[val4] = plan.Worth; Plugin.Log.LogInfo((object)($"Spawned pirate boat {index + 1}/{boatCount}, " + string.Format("with {0}, {1} shooter{2}, ", motorName, count, (count == 1) ? "" : "s") + "one helmsman, and " + string.Join(", ", weapons.Select((PirateWeaponDefinition weapon) => weapon.Name)) + " " + $"on the seaward horizon with a {num3:0.#}m attack orbit " + $"near island {OnlineIslandManager.CurIsland + 1}. " + $"Reinforcement worth {fleetWorth:N0} counters open-ocean player worth {playerWorth:N0}.")); } private static PirateFleetPlan? SelectFleetForWorth(Boat boatPrefab, IReadOnlyList weapons, int worthRequirement, int totalWorthBudget, int preferredBoatCount, int maximumBoatCount) { int num = SaturatingMultiply(GetBoatWorth(boatPrefab, 0, (IEnumerable)(object)new Weapon[1] { weapons.OrderBy(GetWeaponWorth).First() }), preferredBoatCount); if (worthRequirement < num) { return null; } int num2 = Mathf.CeilToInt((float)worthRequirement * 0.75f); PirateFleetPlan pirateFleetPlan = ((preferredBoatCount == 1) ? CreatePreferredSingleBoat(boatPrefab, weapons, totalWorthBudget) : null); if (pirateFleetPlan != null && pirateFleetPlan.Worth > worthRequirement) { return null; } PirateFleetPlan pirateFleetPlan2 = null; PirateFleetPlan pirateFleetPlan3 = pirateFleetPlan; if (pirateFleetPlan != null && pirateFleetPlan.Worth >= num2) { pirateFleetPlan2 = pirateFleetPlan; } for (int i = 1; i <= 256; i++) { PirateFleetPlan pirateFleetPlan4 = GenerateRandomFleet(boatPrefab, weapons, maximumBoatCount); if (pirateFleetPlan4.Worth <= worthRequirement) { if (IsPreferredFleet(pirateFleetPlan4, pirateFleetPlan3, preferredBoatCount)) { pirateFleetPlan3 = pirateFleetPlan4; } if (pirateFleetPlan4.Worth >= num2 && IsPreferredFleet(pirateFleetPlan4, pirateFleetPlan2, preferredBoatCount)) { pirateFleetPlan2 = pirateFleetPlan4; } } } if (pirateFleetPlan2 != null) { Plugin.Log.LogInfo((object)($"Selected {pirateFleetPlan2.Boats.Count} pirate reinforcement " + string.Format("boat{0} worth {1:N0} ", (pirateFleetPlan2.Boats.Count == 1) ? "" : "s", pirateFleetPlan2.Worth) + $"for shortfall {worthRequirement:N0} after comparing {256} rolls.")); return pirateFleetPlan2; } PirateFleetPlan pirateFleetPlan5 = pirateFleetPlan3 ?? CreateMinimumFleet(weapons); Plugin.Log.LogWarning((object)($"No pirate reinforcement landed within 75%-100% of shortfall {worthRequirement:N0} " + $"after {256} rolls; using the preferred affordable " + $"{pirateFleetPlan5.Boats.Count}-boat fleet worth {pirateFleetPlan5.Worth:N0}.")); return pirateFleetPlan5; } private static PirateFleetPlan? CreatePreferredSingleBoat(Boat boatPrefab, IReadOnlyList weapons, int worthBudget) { List list = (List)MotorsField.GetValue(boatPrefab); int num = ((list == null || list.Count == 0) ? 1 : list.Count); int num2 = Mathf.Min(new int[3] { num, PirateBoatSupport.MaximumShooterCount, weapons.Count }); PirateBoatPlan preferredBoat = null; List selectedWeapons = new List(num2); for (int i = 0; i < num; i++) { for (int j = 1; j <= num2; j++) { FindPreferredSingleBoatLoadout(boatPrefab, weapons, worthBudget, i, j, 0, selectedWeapons, ref preferredBoat); } } if (preferredBoat == null) { return null; } return new PirateFleetPlan { Worth = preferredBoat.Worth, Boats = { preferredBoat } }; } private static void FindPreferredSingleBoatLoadout(Boat boatPrefab, IReadOnlyList weapons, int worthBudget, int motorIndex, int weaponsRemaining, int startWeaponIndex, List selectedWeapons, ref PirateBoatPlan? preferredBoat) { if (weaponsRemaining == 0) { int boatWorth = GetBoatWorth(boatPrefab, motorIndex, selectedWeapons); if (boatWorth <= worthBudget && (preferredBoat == null || boatWorth > preferredBoat.Worth)) { preferredBoat = new PirateBoatPlan { MotorIndex = motorIndex, Weapons = selectedWeapons.Select(PirateWeaponDefinition.FromWeapon).ToArray(), Worth = boatWorth }; } } else { int num = weapons.Count - weaponsRemaining; for (int i = startWeaponIndex; i <= num; i++) { selectedWeapons.Add(weapons[i]); FindPreferredSingleBoatLoadout(boatPrefab, weapons, worthBudget, motorIndex, weaponsRemaining - 1, i + 1, selectedWeapons, ref preferredBoat); selectedWeapons.RemoveAt(selectedWeapons.Count - 1); } } } private static bool IsPreferredFleet(PirateFleetPlan candidate, PirateFleetPlan? current, int preferredBoatCount) { if (current == null) { return true; } int num = Mathf.Abs(candidate.Boats.Count - preferredBoatCount); int num2 = Mathf.Abs(current.Boats.Count - preferredBoatCount); if (num != num2) { return num < num2; } return candidate.Worth > current.Worth; } private static int SelectPreferredReinforcementBoatCount() { float value = Random.value; if (value < 0.7f) { return 1; } if (!(value < 0.95f)) { return 3; } return 2; } private static PirateFleetPlan GenerateRandomFleet(Boat boatPrefab, IReadOnlyList weapons, int maximumBoatCount) { PirateFleetPlan pirateFleetPlan = new PirateFleetPlan(); int num = 1; float num2 = 0.5f; while (num < maximumBoatCount && Random.value < num2) { num++; num2 *= 0.5f; } for (int i = 0; i < num; i++) { int motorIndex = SelectMotorIndex(boatPrefab); int shooterCount = SelectShooterCount(boatPrefab); IReadOnlyList readOnlyList = SelectShooterWeapons(weapons, shooterCount); PirateBoatPlan pirateBoatPlan = new PirateBoatPlan { MotorIndex = motorIndex, Weapons = readOnlyList, Worth = GetBoatWorth(boatPrefab, motorIndex, readOnlyList.Select((PirateWeaponDefinition weapon) => weapon.VisualSource)) }; pirateFleetPlan.Boats.Add(pirateBoatPlan); pirateFleetPlan.Worth = SaturatingAdd(pirateFleetPlan.Worth, pirateBoatPlan.Worth); } return pirateFleetPlan; } private static PirateFleetPlan CreateMinimumFleet(IReadOnlyList weapons) { Boat boat = FindLoadedPlayerBoat(); Weapon val = weapons.OrderBy(GetWeaponWorth).First(); IReadOnlyList weapons2 = new PirateWeaponDefinition[1] { PirateWeaponDefinition.FromWeapon(val) }; PirateBoatPlan pirateBoatPlan = new PirateBoatPlan(); pirateBoatPlan.MotorIndex = 0; pirateBoatPlan.Weapons = weapons2; pirateBoatPlan.Worth = GetBoatWorth(boat, 0, (IEnumerable)(object)new Weapon[1] { val }); PirateBoatPlan pirateBoatPlan2 = pirateBoatPlan; return new PirateFleetPlan { Worth = pirateBoatPlan2.Worth, Boats = { pirateBoatPlan2 } }; } private static int GetBoatWorth(Boat? boat, int motorIndex, IEnumerable weapons) { int num = SaturatingAdd(100, GetMotorWorth(boat, motorIndex)); foreach (Weapon weapon in weapons) { num = SaturatingAdd(num, GetWeaponWorth(weapon)); } return num; } private static int GetWeaponWorth(Weapon weapon) { return Mathf.Max(1, (((Item)weapon).Cost > 0) ? ((Item)weapon).Cost : ((Item)weapon).DefaultWorth); } private int GetOpenOceanPlayerWorth(float triggerDistance, float farthestDistanceFromShoreline) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) HashSet countedItems = new HashSet(); int num = 0; bool flag = false; foreach (Player alivePlayer in PlayerManager.AlivePlayers) { if (!Object.op_Implicit((Object)(object)alivePlayer) || !Object.op_Implicit((Object)(object)alivePlayer.Transform) || !_openSeaBoundary.IsBeyondBoundary(alivePlayer.Transform.position, triggerDistance)) { continue; } flag = true; foreach (KeyValuePair item in alivePlayer.Inventory._items) { num = AddItemWorth(item.Value, countedItems, num); } Item heldItem = alivePlayer.Holding.HeldItem; if (Object.op_Implicit((Object)(object)heldItem) && (Object)(object)heldItem.SyncedHolder == (Object)(object)alivePlayer) { num = AddItemWorth(heldItem, countedItems, num); } } if (flag) { Boat val = FindLoadedPlayerBoat(); if (Object.op_Implicit((Object)(object)val)) { num = SaturatingAdd(num, GetMotorWorth(val, val.MotorIndex)); } } return ScaleWorthForDistance(num, farthestDistanceFromShoreline, triggerDistance); } private static int ScaleWorthForDistance(int worth, float distanceFromShoreline, float distanceBandSize) { int num = ((!(distanceBandSize > 0f)) ? 1 : Mathf.Max(1, Mathf.FloorToInt(distanceFromShoreline / distanceBandSize))); long num2 = (long)worth * (long)num / 10; if (num2 < int.MaxValue) { return (int)num2; } return int.MaxValue; } private int ApplyDifficultyMultiplier(int worth) { double num = (double)worth * (double)_config.DifficultyMultiplier.Value; if (!(num >= 2147483647.0)) { return Mathf.Max(0, Mathf.RoundToInt((float)num)); } return int.MaxValue; } private static int GetMotorWorth(Boat? boat, int motorIndex) { if (motorIndex <= 0) { return 0; } if (MotorWorthByIndex.TryGetValue(motorIndex, out var value)) { return value; } List list = (Object.op_Implicit((Object)(object)boat) ? ((List)MotorsField.GetValue(boat)) : null); if (list == null || motorIndex >= list.Count) { return 0; } return SaturatingMultiply(100, motorIndex); } private static void RefreshMotorWorths() { MotorPurchasable[] array = Resources.FindObjectsOfTypeAll(); foreach (MotorPurchasable val in array) { if (Object.op_Implicit((Object)(object)val)) { int num = (byte)MotorPurchasableIndexField.GetValue(val); int num2 = Mathf.Max(0, (int)PurchasableCostField.GetValue(val)); if (num > 0 && (!MotorWorthByIndex.TryGetValue(num, out var value) || num2 > value)) { MotorWorthByIndex[num] = num2; } } } } private static Boat? FindLoadedPlayerBoat() { Boat boat = BoatManager.Boat; if (!Object.op_Implicit((Object)(object)boat) || PirateBoatSupport.IsPirateBoat(boat)) { return null; } return boat; } private static int AddItemWorth(Item item, ISet countedItems, int totalWorth) { if (!Object.op_Implicit((Object)(object)item) || !countedItems.Add(item)) { return totalWorth; } return SaturatingAdd(totalWorth, Mathf.Max(0, item.TotalWorth)); } private static int SaturatingAdd(int first, int second) { long num = (long)first + (long)second; if (num < int.MaxValue) { return (int)num; } return int.MaxValue; } private static int SaturatingMultiply(int value, int multiplier) { long num = (long)value * (long)multiplier; if (num < int.MaxValue) { return (int)num; } return int.MaxValue; } private static IReadOnlyList SelectShooterWeapons(IReadOnlyList weapons, int shooterCount) { List list = new List(weapons); List list2 = new List(shooterCount); for (int i = 0; i < shooterCount; i++) { if (list.Count == 0) { list.AddRange(weapons); } int index = Random.Range(0, list.Count); list2.Add(PirateWeaponDefinition.FromWeapon(list[index])); list.RemoveAt(index); } return list2; } private static int SelectMotorIndex(Boat boat) { List list = (List)MotorsField.GetValue(boat); if (list == null || list.Count <= 1) { return 0; } return SelectWeightedTier(list.Count); } private static void AlignBoatForward(Boat boat, Vector3 desiredForward) { //IL_0006: 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) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) //IL_0026: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.ProjectOnPlane(-boat.VisualBoat.right, Vector3.up); desiredForward = Vector3.ProjectOnPlane(desiredForward, Vector3.up); if (!(((Vector3)(ref val)).sqrMagnitude <= 0.01f) && !(((Vector3)(ref desiredForward)).sqrMagnitude <= 0.01f)) { float num = Vector3.SignedAngle(val, desiredForward, Vector3.up); ((Component)boat).transform.rotation = Quaternion.AngleAxis(num, Vector3.up) * ((Component)boat).transform.rotation; } } private static int SelectShooterCount(Boat boat) { List list = (List)MotorsField.GetValue(boat); return SelectWeightedTier((list == null || list.Count == 0) ? 1 : Mathf.Min(list.Count, PirateBoatSupport.MaximumShooterCount)) + 1; } private static int SelectWeightedTier(int tierCount) { float num = 0f; float num2 = 1f; for (int i = 0; i < tierCount; i++) { num += num2; num2 *= 0.35f; } float num3 = Random.value * num; num2 = 1f; for (int j = 0; j < tierCount; j++) { if (num3 < num2) { return j; } num3 -= num2; num2 *= 0.35f; } return tierCount - 1; } private static string GetMotorName(Boat boat, int motorIndex) { List list = (List)MotorsField.GetValue(boat); if (list == null || list.Count == 0) { return "default motor"; } BoatMotor val = list[Mathf.Clamp(motorIndex, 0, list.Count - 1)]; if (!Object.op_Implicit((Object)(object)val)) { return $"motor {motorIndex + 1}"; } return $"motor {motorIndex + 1} ({((Object)val).name})"; } private static void ConfigureLongRangeNetworkVisibility(Boat pirateBoat) { if (!Object.op_Implicit((Object)(object)((Component)pirateBoat).GetComponent())) { ((Component)pirateBoat).gameObject.AddComponent(); } } private IReadOnlyList FindPirateWeapons() { _weapons.RemoveAll((Weapon weapon) => !Object.op_Implicit((Object)(object)weapon)); if (_weapons.Count > 0) { return _weapons; } string[] pirateWeaponSpawnNames = PirateWeaponSpawnNames; foreach (string text in pirateWeaponSpawnNames) { Item spawnable = GameInfo.GetSpawnable(text); Weapon val = (Weapon)(object)((spawnable is Weapon) ? spawnable : null); if (Object.op_Implicit((Object)(object)val)) { _weapons.Add(val); } else { Plugin.Log.LogWarning((object)("Pirate weapon resource " + text + " was unavailable.")); } } return _weapons; } private Boat? GetBoatPrefab() { if (Object.op_Implicit((Object)(object)_boatPrefab)) { return _boatPrefab; } NetworkManager networkManager = InstanceFinder.NetworkManager; PrefabObjects val = ((networkManager != null) ? networkManager.SpawnablePrefabs : null); if ((Object)(object)val == (Object)null) { return null; } for (int i = 0; i < val.GetObjectCount(); i++) { NetworkObject val2 = val.GetObject(true, i); if (Object.op_Implicit((Object)(object)val2)) { Boat component = ((Component)val2).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { _boatPrefab = component; break; } } } return _boatPrefab; } private Player? FindFarthestPlayerFromIsland(out float farthestDistanceFromShoreline) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) Player result = null; farthestDistanceFromShoreline = float.NegativeInfinity; foreach (Player alivePlayer in PlayerManager.AlivePlayers) { if (Object.op_Implicit((Object)(object)alivePlayer) && Object.op_Implicit((Object)(object)alivePlayer.Transform)) { float distanceFromShoreline = _openSeaBoundary.GetDistanceFromShoreline(alivePlayer.Transform.position); if (distanceFromShoreline > farthestDistanceFromShoreline) { result = alivePlayer; farthestDistanceFromShoreline = distanceFromShoreline; } } } return result; } private void DespawnPirates() { Boat[] array = _activePirateBoats.Keys.ToArray(); foreach (Boat val in array) { if (Object.op_Implicit((Object)(object)val)) { PirateBoatSupport.UnregisterServerPirate(val); if (Object.op_Implicit((Object)(object)Server.Instance) && ((NetworkBehaviour)Server.Instance).IsServerInitialized) { ((NetworkBehaviour)Server.Instance).Despawn(((Component)val).gameObject, (DespawnType?)null); } } } _activePirateBoats.Clear(); _preferredReinforcementBoatCount = 0; } private void RemoveDestroyedPirateBoats() { Boat[] array = _activePirateBoats.Keys.Where((Boat boat) => !Object.op_Implicit((Object)(object)boat)).ToArray(); foreach (Boat key in array) { _activePirateBoats.Remove(key); } } private int GetActivePirateWorth() { int num = 0; foreach (KeyValuePair activePirateBoat in _activePirateBoats) { if (Object.op_Implicit((Object)(object)activePirateBoat.Key)) { num = SaturatingAdd(num, activePirateBoat.Value); } } return num; } private void OnDestroy() { DespawnPirates(); } } [BepInPlugin("behold.howtofish.pirates", "Behold: Pirates", "0.10.2")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "behold.howtofish.pirates"; public const string PluginName = "Behold: Pirates"; public const string PluginVersion = "0.10.2"; private Harmony? _harmony; private OpenSeaBoundary? _openSeaBoundary; private PirateEncounterController? _pirateEncounterController; private OpenSeaBoundaryMarkers? _openSeaBoundaryMarkers; private int _boatLayer = -1; private bool _boatCollisionsWereIgnored; private bool _boatCollisionStateCaptured; internal static ManualLogSource Log { get; private set; } private void Awake() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; _harmony = new Harmony("behold.howtofish.pirates"); _harmony.PatchAll(typeof(Plugin).Assembly); EnableBoatToBoatCollisions(); OpenSeaConfig openSeaConfig = new OpenSeaConfig(((BaseUnityPlugin)this).Config); _openSeaBoundary = ((Component)this).gameObject.AddComponent(); _openSeaBoundary.Initialize(openSeaConfig.DistanceBeyondIsland); _pirateEncounterController = ((Component)this).gameObject.AddComponent(); _pirateEncounterController.Initialize(openSeaConfig, _openSeaBoundary); if (openSeaConfig.BoundaryMarkersEnabled.Value) { _openSeaBoundaryMarkers = ((Component)this).gameObject.AddComponent(); _openSeaBoundaryMarkers.Initialize(_openSeaBoundary); } Log.LogInfo((object)("Behold: Pirates 0.10.2 loaded; Harmony patches applied. Configuration: " + ((BaseUnityPlugin)this).Config.ConfigFilePath)); } private void OnDestroy() { RestoreBoatToBoatCollisionSetting(); Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _openSeaBoundary = null; _pirateEncounterController = null; _openSeaBoundaryMarkers = null; } private void EnableBoatToBoatCollisions() { _boatLayer = LayerMask.NameToLayer("Boat"); if (_boatLayer < 0) { Log.LogWarning((object)"Could not find the Boat physics layer; boat-to-boat collisions remain unchanged."); return; } _boatCollisionsWereIgnored = Physics.GetIgnoreLayerCollision(_boatLayer, _boatLayer); _boatCollisionStateCaptured = true; Physics.IgnoreLayerCollision(_boatLayer, _boatLayer, false); Log.LogInfo((object)"Enabled boat-to-boat collisions using the boats' authored physics hulls."); } private void RestoreBoatToBoatCollisionSetting() { if (_boatCollisionStateCaptured) { Physics.IgnoreLayerCollision(_boatLayer, _boatLayer, _boatCollisionsWereIgnored); _boatCollisionStateCaptured = false; } } } } namespace HowToFish.OpenSea.Pirates { internal sealed class PirateBoatAudio : MonoBehaviour { private const float PirateBoatAudibleDistance = 80f; private static readonly FieldInfo CurrentMotorField = AccessTools.Field(typeof(Boat), "_curMotor"); private static readonly FieldInfo StartStopVolumeField = AccessTools.Field(typeof(Boat), "_boatStartStopSoundVolume"); private Boat _boat; private BoatMotor? _playingMotor; private Coroutine? _startCoroutine; private bool _stopped; private void Awake() { _boat = ((Component)this).GetComponent(); AudioSource[] componentsInChildren = ((Component)_boat).GetComponentsInChildren(true); foreach (AudioSource val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val)) { val.maxDistance = Mathf.Max(val.maxDistance, 80f); } } } private void OnEnable() { StartMotor(); } private void Update() { if (!Object.op_Implicit((Object)(object)_boat)) { return; } if (!_boat.BoatUnlocked && !_boat.BoatRadarUnlocked) { StopMotor(playStopSound: true); return; } BoatMotor currentMotor = GetCurrentMotor(); if ((Object)(object)currentMotor != (Object)(object)_playingMotor && _startCoroutine == null) { StopMotor(playStopSound: false); StartMotor(); } EnsureSourcesPlaying(currentMotor); } private void StartMotor() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_boat) && !_stopped) { BoatMotor currentMotor = GetCurrentMotor(); if (Object.op_Implicit((Object)(object)currentMotor)) { _playingMotor = currentMotor; AudioManager.PlayClipAt(currentMotor.MotorStartSoundName, ((Component)currentMotor).transform.position, false, (AudioDistance)2, GetStartStopVolume(), 0.1f); _startCoroutine = ((MonoBehaviour)this).StartCoroutine(StartLoopsAfterDelay(currentMotor)); } } } private IEnumerator StartLoopsAfterDelay(BoatMotor motor) { if (motor.MotorStartDelay > 0f) { yield return (object)new WaitForSeconds(motor.MotorStartDelay); } _startCoroutine = null; if (Object.op_Implicit((Object)(object)_boat) && !_stopped && (Object)(object)motor == (Object)(object)GetCurrentMotor()) { PlaySources(motor.MotorSounds); PlaySources(motor.MotorIdleSounds); Plugin.Log.LogInfo((object)"Started the pirate boat's default motor audio."); } } private static void PlaySources(AudioSource[] sources) { foreach (AudioSource val in sources) { if (Object.op_Implicit((Object)(object)val)) { ((Behaviour)val).enabled = true; val.maxDistance = Mathf.Max(val.maxDistance, 80f); if (!val.isPlaying) { val.Play(); } } } } private void EnsureSourcesPlaying(BoatMotor? motor) { if (Object.op_Implicit((Object)(object)motor) && !_stopped && _startCoroutine == null) { PlaySources(motor.MotorSounds); PlaySources(motor.MotorIdleSounds); } } private static void StopSources(AudioSource[] sources) { foreach (AudioSource val in sources) { if (Object.op_Implicit((Object)(object)val)) { val.Stop(); ((Behaviour)val).enabled = false; } } } private void StopMotor(bool playStopSound) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) if (_stopped && playStopSound) { return; } if (_startCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(_startCoroutine); _startCoroutine = null; } BoatMotor val = _playingMotor ?? GetCurrentMotor(); if (Object.op_Implicit((Object)(object)val)) { StopSources(val.MotorSounds); StopSources(val.MotorIdleSounds); if (playStopSound) { AudioManager.PlayClipAt(val.MotorStopSoundName, ((Component)val).transform.position, false, (AudioDistance)2, GetStartStopVolume(), 0.1f); } } _playingMotor = null; _stopped = playStopSound; } private BoatMotor? GetCurrentMotor() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)_boat)) { return null; } return (BoatMotor)CurrentMotorField.GetValue(_boat); } private float GetStartStopVolume() { if (!Object.op_Implicit((Object)(object)_boat)) { return 1f; } return (float)StartStopVolumeField.GetValue(_boat); } private void OnDisable() { StopMotor(playStopSound: false); } } internal sealed class PirateBoatController : MonoBehaviour { private sealed class ShooterState { public int ShooterIndex; public PirateCrewHealth? Health; public bool WasBoundToCrew; public PirateWeaponDefinition Weapon; public float NextShotTime; public int Ammo; public bool IsReloading; public float ReloadCompleteTime; } private static readonly FieldInfo CurrentMotorField = AccessTools.Field(typeof(Boat), "_curMotor"); private static readonly FieldInfo ForcePointsField = AccessTools.Field(typeof(Boat), "_forcePoints"); private static readonly FieldInfo ForceModeField = AccessTools.Field(typeof(Boat), "_forceMode"); private static readonly FieldInfo BoatBouncinessField = AccessTools.Field(typeof(Boat), "_boatBounciness"); private const float FullSteerAngle = 22f; private const float InputChangeSpeed = 3f; private const float MinimumOrbitLookAheadAngle = 25f; internal const float BuoyancyFadeDuration = 30f; private const float SinkRollAcceleration = 0.35f; private const float SinkDespawnDepth = 8f; private const float MaxSinkDuration = 45f; private const float RetreatDespawnDistance = 250f; private const float RetreatPlayerDespawnDistance = 200f; private const float ShooterSpreadDegrees = 4f; private const float NavigationCheckInterval = 5f; private Boat _boat; private OpenSeaBoundary _openSeaBoundary; private float _orbitRadius; private readonly List _shooters = new List(); private bool _clockwise; private float _sinkStartedAt = -1f; private float _sinkRollDirection; private float _steeringInput; private float _throttleInput; private bool _retreatComplete; private bool _isRetreatingFromIsland; private Vector3 _retreatStartPosition; private float _nextNavigationCheckTime; public bool IsSinking => _sinkStartedAt >= 0f; public bool IsRetreating => _isRetreatingFromIsland; public void Initialize(Boat boat, IReadOnlyList shooterWeapons, float orbitRadius, OpenSeaBoundary openSeaBoundary) { //IL_00be: 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) _boat = boat; _openSeaBoundary = openSeaBoundary; _orbitRadius = orbitRadius; for (int i = 0; i < shooterWeapons.Count; i++) { PirateWeaponDefinition pirateWeaponDefinition = shooterWeapons[i]; ShooterState item = new ShooterState { ShooterIndex = i, Weapon = pirateWeaponDefinition, Ammo = pirateWeaponDefinition.MagazineSize, NextShotTime = Time.time + Random.Range(1.5f, 3f) }; _shooters.Add(item); } _clockwise = Random.value >= 0.5f; _sinkRollDirection = ((Random.value >= 0.5f) ? 1f : (-1f)); Rigidbody hiddenPhysicsRig = boat.HiddenPhysicsRig; hiddenPhysicsRig.interpolation = (RigidbodyInterpolation)1; hiddenPhysicsRig.isKinematic = false; hiddenPhysicsRig.linearVelocity = Vector3.zero; hiddenPhysicsRig.angularVelocity = Vector3.zero; _nextNavigationCheckTime = Time.time + 5f; } private void LateUpdate() { //IL_0057: 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) if (Object.op_Implicit((Object)(object)_boat) && ((NetworkBehaviour)_boat).IsServerInitialized && !IslandManager.IsLoading) { Rigidbody hiddenPhysicsRig = _boat.HiddenPhysicsRig; Rigidbody visualPhysicsRig = _boat.VisualPhysicsRig; if (Object.op_Implicit((Object)(object)hiddenPhysicsRig) && Object.op_Implicit((Object)(object)visualPhysicsRig)) { ((Component)visualPhysicsRig).transform.SetPositionAndRotation(((Component)hiddenPhysicsRig).transform.position, ((Component)hiddenPhysicsRig).transform.rotation); } } } private void FixedUpdate() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0176: 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_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_018c: 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) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)_boat) || !((NetworkBehaviour)_boat).IsServerInitialized || IslandManager.IsLoading) { return; } if (IsSinking) { Rigidbody hiddenPhysicsRig = _boat.HiddenPhysicsRig; float sinkProgress = GetSinkProgress(); hiddenPhysicsRig.AddTorque(((Component)hiddenPhysicsRig).transform.forward * (_sinkRollDirection * 0.35f * sinkProgress), (ForceMode)5); return; } Rigidbody hiddenPhysicsRig2 = _boat.HiddenPhysicsRig; Player val = FindClosestOceanPlayer(hiddenPhysicsRig2.position); UpdateRetreatState(val); float distance = 0f; Vector3 directionToTarget = Vector3.zero; Vector3 val6; if (_isRetreatingFromIsland) { Vector3 val2 = hiddenPhysicsRig2.position - _retreatStartPosition; val2.y = 0f; Player val3 = FindClosestLivingPlayer(hiddenPhysicsRig2.position); Vector3 val4 = (Object.op_Implicit((Object)(object)val3) ? (val3.Transform.position - hiddenPhysicsRig2.position) : Vector3.zero); val4.y = 0f; bool flag = !Object.op_Implicit((Object)(object)val3) || ((Vector3)(ref val4)).sqrMagnitude >= 40000f; if (((Vector3)(ref val2)).sqrMagnitude >= 62500f && flag) { _retreatComplete = true; SetBoatInputs(0f, 0f); Plugin.Log.LogInfo((object)"A retreating pirate boat is beyond both its travel and player-distance despawn limits."); return; } Vector3 val5 = (Object.op_Implicit((Object)(object)val3) ? (hiddenPhysicsRig2.position - val3.Transform.position) : (hiddenPhysicsRig2.position - Island.IslandPos)); val5.y = 0f; val6 = ((((Vector3)(ref val5)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val5)).normalized : GetHullForward()); } else { if (!Object.op_Implicit((Object)(object)val)) { SetBoatInputs(0f, 0f); return; } Vector3 val7 = val.Transform.position - hiddenPhysicsRig2.position; val7.y = 0f; float magnitude = ((Vector3)(ref val7)).magnitude; Vector3 val8 = ((magnitude > 0.01f) ? (val7 / magnitude) : Vector3.forward); distance = magnitude; directionToTarget = val8; val6 = GetOrbitPointDirection(hiddenPhysicsRig2.position, val.Transform.position); } Vector3 hullForward = GetHullForward(); float steering = ((((Vector3)(ref hullForward)).sqrMagnitude > 0.01f) ? Mathf.Clamp(Vector3.SignedAngle(hullForward, val6, Vector3.up) / 22f, -1f, 1f) : 0f); int num; if (!_boat.BoatUnlocked) { if (_boat.BoatRadarUnlocked) { num = (IsOutsideCirclingRange() ? 1 : 0); if (num != 0) { goto IL_02a7; } } else { num = 0; } steering = 0f; } else { num = 1; } goto IL_02a7; IL_02a7: float throttle = ((num != 0) ? 1f : 0f); SetBoatInputs(steering, throttle); if (!_isRetreatingFromIsland) { MonitorApproach(hiddenPhysicsRig2, distance, directionToTarget); } } private Vector3 GetHullForward() { //IL_000b: 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_0015: Unknown result type (might be due to invalid IL or missing references) //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_0022: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.ProjectOnPlane(-_boat.VisualBoat.right, Vector3.up); return ((Vector3)(ref val)).normalized; } private Vector3 GetOrbitPointDirection(Vector3 boatPosition, Vector3 targetPosition) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: 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_00f5: 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_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) Vector3 val = boatPosition - targetPosition; val.y = 0f; float magnitude = ((Vector3)(ref val)).magnitude; Vector3 val2 = ((magnitude > 0.01f) ? (val / magnitude) : (-GetHullForward())); float num = Mathf.Max(0.1f, _orbitRadius); float num2 = ((magnitude > num) ? (Mathf.Acos(Mathf.Clamp01(num / magnitude)) * 57.29578f) : 0f); float num3 = Mathf.Max(25f, num2); Vector3 val3 = Quaternion.AngleAxis(_clockwise ? (0f - num3) : num3, Vector3.up) * val2; Vector3 val4 = targetPosition + val3 * num; val4.y = boatPosition.y; Vector3 val5 = val4 - boatPosition; if (!(((Vector3)(ref val5)).sqrMagnitude > 0.01f)) { return Vector3.Cross(Vector3.up, val2) * (_clockwise ? (-1f) : 1f); } return ((Vector3)(ref val5)).normalized; } private void MonitorApproach(Rigidbody rig, float distance, Vector3 directionToTarget) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_003e: 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_005b: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time < _nextNavigationCheckTime)) { _nextNavigationCheckTime = Time.time + 5f; Vector3 val = Vector3.ProjectOnPlane(rig.linearVelocity, Vector3.up); float num = Vector3.Dot(val, directionToTarget); float num2 = Vector3.Dot(GetHullForward(), directionToTarget); BoatMotor val2 = (BoatMotor)CurrentMotorField.GetValue(_boat); bool flag = Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.Propeller) && WaterManager.IsUnderWater(val2.Propeller.position); Plugin.Log.LogInfo((object)($"Pirate navigation: {distance:0.#}m away, {((Vector3)(ref val)).magnitude:0.#}m/s speed, " + $"{num:0.#}m/s closing, bow alignment {num2:0.00}, " + $"{_throttleInput:0.00} throttle, motor force {(Object.op_Implicit((Object)(object)val2) ? val2.Force : 0f):0.#}, " + $"propeller underwater={flag}, " + $"kinematic={rig.isKinematic}.")); } } private void Update() { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)_boat) || !((NetworkBehaviour)_boat).IsServerInitialized || IslandManager.IsLoading) { return; } if (!_boat.BoatUnlocked && !_boat.BoatRadarUnlocked) { if (!IsSinking) { BeginSinking(); } if ((_boat.HiddenPhysicsRig.position.y <= WaterManager.WaterHeight - 8f || Time.time - _sinkStartedAt >= 45f) && Object.op_Implicit((Object)(object)Server.Instance) && ((NetworkBehaviour)Server.Instance).IsServerInitialized) { PirateBoatSupport.UnregisterServerPirate(_boat); ((NetworkBehaviour)Server.Instance).Despawn(((Component)_boat).gameObject, (DespawnType?)null); } return; } Player val = FindClosestOceanPlayer(_boat.VisualBoat.position); UpdateRetreatState(val); if (_retreatComplete) { PirateBoatSupport.UnregisterServerPirate(_boat); ((NetworkBehaviour)Server.Instance).Despawn(((Component)_boat).gameObject, (DespawnType?)null); } else { if (_isRetreatingFromIsland || !_boat.BoatRadarUnlocked || !Object.op_Implicit((Object)(object)val)) { return; } foreach (ShooterState shooter in _shooters) { UpdateShooter(shooter, val); } } } private void UpdateShooter(ShooterState shooter, Player target) { //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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_013a: 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_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0156: 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) PirateWeaponDefinition weapon = shooter.Weapon; PirateCrewHealth pirateCrewHealth = ResolveShooterHealth(shooter); if (!IsShooterAlive(shooter, pirateCrewHealth) || IsShooterAtHelm(shooter, pirateCrewHealth)) { return; } if (shooter.IsReloading) { if (Time.time < shooter.ReloadCompleteTime) { return; } shooter.IsReloading = false; shooter.Ammo = weapon.MagazineSize; } if (Time.time < shooter.NextShotTime) { return; } Vector3 val = target.Transform.position + Vector3.up * 0.8f; PirateWeaponVisual pirateWeaponVisual = (Object.op_Implicit((Object)(object)pirateCrewHealth) ? ((Component)pirateCrewHealth).GetComponentInChildren() : null); if (Object.op_Implicit((Object)(object)pirateWeaponVisual) && !pirateWeaponVisual.CanFire) { return; } Vector3 val2 = (Object.op_Implicit((Object)(object)pirateWeaponVisual) ? pirateWeaponVisual.GetMuzzlePosition(val) : PirateBoatSupport.GetShooterMuzzleFallback(_boat, shooter.ShooterIndex, val)); float num = Vector3.Distance(val2, val); float num2 = Mathf.Min(1.5f, num / weapon.ProjectileSpeed); val += target.Other.Velocity * num2; val.y += 0.5f * weapon.Projectile.ProjectileGravity * num2 * num2; Vector3 val3 = val - val2; float magnitude = ((Vector3)(ref val3)).magnitude; if (!(magnitude > weapon.AttackRange) && !Physics.Raycast(val2, val3, magnitude, LayerMask.op_Implicit(GameInfo.LevelLayer))) { FireAt(shooter, target, pirateWeaponVisual, val2, ((Vector3)(ref val3)).normalized); shooter.Ammo--; if (shooter.Ammo <= 0) { StartReload(shooter, pirateWeaponVisual, empty: true); } else { shooter.NextShotTime = Time.time + weapon.FireInterval; } } } private void FireAt(ShooterState shooter, Player target, PirateWeaponVisual? visual, Vector3 muzzlePosition, Vector3 direction) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: 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_0019: 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) //IL_0023: 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) //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_003f: 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_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_006b: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0138: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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) PirateWeaponDefinition weapon = shooter.Weapon; Vector2 val = Random.insideUnitCircle * 4f; Vector3 val2 = Quaternion.LookRotation(direction, Vector3.up) * Quaternion.Euler(0f - val.y, val.x, 0f) * Vector3.forward; Vector3[] array = (Vector3[])(object)new Vector3[weapon.ProjectileCount]; for (int i = 0; i < array.Length; i++) { Vector3 val3 = Random.insideUnitSphere * weapon.Spread; array[i] = Quaternion.Euler(val3) * val2 * weapon.ProjectileSpeed; } Player val4 = (Player)(Object.op_Implicit((Object)(object)Player.LocalPlayer) ? ((object)Player.LocalPlayer) : ((object)target)); uint num = PirateProjectileSupport.AllocateIds(array.Length); if (array.Length == 1) { ProjectileManager.Instance.ObserverAddProjectile(val4, weapon.Projectile, InstanceFinder.TimeManager.Tick, num, muzzlePosition, array[0]); ProjectileManager.Instance.AddProjectile(val4, weapon.Projectile, false, muzzlePosition, array[0], 0u, num, true); } else { ProjectileManager.Instance.ObserverAddProjectiles(val4, weapon.Projectile, InstanceFinder.TimeManager.Tick, num, muzzlePosition, array); ProjectileManager.Instance.AddProjectiles(val4, weapon.Projectile, false, muzzlePosition, array, 0u, num, true); } Attachments attachments = weapon.Attachments; AudioManager.PlayRandomClipAt(attachments.FireSound, 1, attachments.FireSoundCount, muzzlePosition, false, (AudioDistance)(attachments.UseMediumSoundDistance ? 2 : 3), attachments.FireSoundVolume, weapon.FireInterval * 0.8f); if (Object.op_Implicit((Object)(object)visual)) { visual.Fire(); } PirateCrewAnimator pirateCrewAnimator = (Object.op_Implicit((Object)(object)visual) ? ((Component)visual).GetComponentInParent() : null); if (Object.op_Implicit((Object)(object)pirateCrewAnimator)) { pirateCrewAnimator.Fire(); } } private void StartReload(ShooterState shooter, PirateWeaponVisual? visual, bool empty) { shooter.IsReloading = true; PirateWeaponDefinition weapon = shooter.Weapon; float num = (empty ? weapon.EmptyReloadDuration : weapon.ReloadDuration); shooter.ReloadCompleteTime = Time.time + num; shooter.NextShotTime = shooter.ReloadCompleteTime; if (Object.op_Implicit((Object)(object)visual)) { visual.Reload(num); } PirateCrewAnimator pirateCrewAnimator = (Object.op_Implicit((Object)(object)visual) ? ((Component)visual).GetComponentInParent() : null); if (Object.op_Implicit((Object)(object)pirateCrewAnimator)) { pirateCrewAnimator.Reload(num); } Plugin.Log.LogDebug((object)$"Pirate reloading {weapon.Name} ({num:0.00}s)."); } private PirateCrewHealth? ResolveShooterHealth(ShooterState shooter) { if (Object.op_Implicit((Object)(object)shooter.Health)) { return shooter.Health; } if (shooter.WasBoundToCrew) { return null; } int num = shooter.ShooterIndex + 1; PirateCrewHealth[] componentsInChildren = ((Component)_boat).GetComponentsInChildren(); foreach (PirateCrewHealth pirateCrewHealth in componentsInChildren) { if (pirateCrewHealth.IsShooter && pirateCrewHealth.CrewIndex == num) { shooter.Health = pirateCrewHealth; shooter.WasBoundToCrew = true; return shooter.Health; } } return null; } private bool IsShooterAlive(ShooterState shooter, PirateCrewHealth? health) { if (!Object.op_Implicit((Object)(object)health)) { if (!shooter.WasBoundToCrew) { return _boat.BoatRadarUnlocked; } return false; } return health.Alive; } private bool IsShooterAtHelm(ShooterState shooter, PirateCrewHealth? health) { if (Object.op_Implicit((Object)(object)health)) { return health.IsAtHelm; } if (!_boat.BoatUnlocked && shooter.ShooterIndex == 0) { return IsOutsideCirclingRange(); } return false; } internal bool IsOutsideCirclingRange() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0045: 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) //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) if (!Object.op_Implicit((Object)(object)_boat)) { return false; } Vector3 val = (Object.op_Implicit((Object)(object)_boat.HiddenPhysicsRig) ? _boat.HiddenPhysicsRig.position : ((Component)_boat).transform.position); Player val2 = FindClosestLivingPlayer(val); if (!Object.op_Implicit((Object)(object)val2)) { return true; } Vector3 val3 = val2.Transform.position - val; val3.y = 0f; return ((Vector3)(ref val3)).sqrMagnitude > _orbitRadius * _orbitRadius; } private Player? FindClosestOceanPlayer(Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return FindClosestLivingPlayer(position, requireOpenOcean: true); } private Player? FindClosestLivingPlayer(Vector3 position, bool requireOpenOcean = false) { //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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) Player result = null; float num = float.PositiveInfinity; foreach (Player alivePlayer in PlayerManager.AlivePlayers) { if (Object.op_Implicit((Object)(object)alivePlayer) && Object.op_Implicit((Object)(object)alivePlayer.Transform) && (!requireOpenOcean || _openSeaBoundary.IsBeyondBoundary(alivePlayer.Transform.position, _openSeaBoundary.DistanceBeyondIsland))) { Vector3 val = alivePlayer.Transform.position - position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { result = alivePlayer; num = sqrMagnitude; } } } return result; } private void SetBoatInputs(float steering, float throttle) { //IL_004b: 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) _steeringInput = Mathf.MoveTowards(_steeringInput, steering, 3f * Time.fixedDeltaTime); _throttleInput = Mathf.MoveTowards(_throttleInput, throttle, 3f * Time.fixedDeltaTime); _boat._driverXInput.Value = (half)_steeringInput; _boat._driverYInput.Value = (half)_throttleInput; } public void ApplyNativeInputForce() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0066: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: 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_00c4: 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_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) if (!Object.op_Implicit((Object)(object)_boat) || (!_boat.BoatUnlocked && !_boat.BoatRadarUnlocked) || _throttleInput <= 0f) { return; } BoatMotor val = (BoatMotor)CurrentMotorField.GetValue(_boat); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.Propeller) && WaterManager.IsUnderWater(val.Propeller.position)) { Rigidbody hiddenPhysicsRig = _boat.HiddenPhysicsRig; Vector3 val2 = -val.Propeller.right; Vector3 hullForward = GetHullForward(); if (Vector3.Dot(val2, hullForward) < 0f) { val2 = -val2; } hiddenPhysicsRig.AddForceAtPosition(val2 * (val.Force * _throttleInput), val.Propeller.position); } } private void UpdateRetreatState(Player? oceanTarget) { bool flag = HasLivingFreeShooter(); if (Object.op_Implicit((Object)(object)oceanTarget) && flag) { ResumePursuit(); } else { BeginRetreat(flag ? "No living player remains in the open ocean" : "No living pirate remains free to shoot"); } } private bool HasLivingFreeShooter() { foreach (ShooterState shooter in _shooters) { PirateCrewHealth health = ResolveShooterHealth(shooter); if (IsShooterAlive(shooter, health) && !IsShooterAtHelm(shooter, health)) { return true; } } return false; } private void BeginRetreat(string reason) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (IsSinking || _isRetreatingFromIsland) { return; } _isRetreatingFromIsland = true; _retreatStartPosition = _boat.HiddenPhysicsRig.position; foreach (ShooterState shooter in _shooters) { shooter.IsReloading = false; shooter.NextShotTime = float.PositiveInfinity; } Plugin.Log.LogInfo((object)(reason + "; the pirate boat is retreating.")); } private void ResumePursuit() { if (!_isRetreatingFromIsland || IsSinking) { return; } _isRetreatingFromIsland = false; _retreatComplete = false; foreach (ShooterState shooter in _shooters) { shooter.NextShotTime = Time.time + Random.Range(0.5f, 1.5f); } Plugin.Log.LogInfo((object)"A living player is in the open ocean; the pirate boat is pursuing again."); } public void ReduceNativeBuoyancy() { //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) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) if (!IsSinking) { return; } float sinkProgress = GetSinkProgress(); Rigidbody hiddenPhysicsRig = _boat.HiddenPhysicsRig; Transform[] obj = (Transform[])ForcePointsField.GetValue(_boat); ForceMode val = (ForceMode)ForceModeField.GetValue(_boat); float num = (float)BoatBouncinessField.GetValue(_boat); Transform[] array = obj; foreach (Transform val2 in array) { if (Object.op_Implicit((Object)(object)val2)) { KeyValuePair waterInfo = WaterManager.GetWaterInfo(val2.position); if (waterInfo.Key) { float num2 = WaterManager.BoatWaterForce * Mathf.Abs(waterInfo.Value); float y = hiddenPhysicsRig.GetPointVelocity(val2.position).y; float num3 = WaterManager.BoatWaterForce * (1f - num); float num4 = Mathf.Clamp((0f - y) * num3, 0f - num2, WaterManager.BoatWaterForce); float num5 = num2 + num4; hiddenPhysicsRig.AddForceAtPosition(Vector3.down * (num5 * sinkProgress), val2.position, val); } } } } private float GetSinkProgress() { return Mathf.Clamp01((Time.time - _sinkStartedAt) / 30f); } private void BeginSinking() { _sinkStartedAt = Time.time; SetBoatInputs(0f, 0f); Rigidbody hiddenPhysicsRig = _boat.HiddenPhysicsRig; hiddenPhysicsRig.linearDamping = Mathf.Min(hiddenPhysicsRig.linearDamping, 0.35f); hiddenPhysicsRig.angularDamping = Mathf.Min(hiddenPhysicsRig.angularDamping, 0.5f); Plugin.Log.LogInfo((object)"Both pirates were killed; the pirate boat is losing buoyancy over 30 seconds."); } private void OnDestroy() { PirateBoatSupport.UnregisterServerPirate(_boat); } } internal static class PirateBoatSupport { private static readonly Vector3[] ShooterStations = (Vector3[])(object)new Vector3[5] { new Vector3(-1.75f, 0.28f, 0f), new Vector3(-2.45f, 0.28f, -0.8f), new Vector3(-2.45f, 0.28f, 0.8f), new Vector3(-3.1f, 0.28f, -0.75f), new Vector3(-3.1f, 0.28f, 0.75f) }; private static readonly FieldInfo DynamicObjectCollidersField = AccessTools.Field(typeof(Boat), "_dynamicObjectCols"); private static readonly FieldInfo BoatInteractableField = AccessTools.Field(typeof(Boat), "_boatInteractable"); private static readonly FieldInfo BoatSkinRendererField = AccessTools.Field(typeof(Boat), "_skinRenderer"); private static readonly FieldInfo PlayerBodyRendererField = AccessTools.Field(typeof(PlayerSkin), "_bodyRenderer"); private static readonly FieldInfo PlayerOutfitRendererField = AccessTools.Field(typeof(PlayerSkin), "_outfitRenderer"); private static readonly FieldInfo PlayerHatRendererField = AccessTools.Field(typeof(PlayerSkin), "_hatRenderer"); private static readonly FieldInfo PlayerAccessoryRendererField = AccessTools.Field(typeof(PlayerSkin), "_accessoryRenderer"); private static readonly FieldInfo PlayerLeftHandRendererField = AccessTools.Field(typeof(PlayerSkin), "_leftHand"); private static readonly FieldInfo PlayerRightHandRendererField = AccessTools.Field(typeof(PlayerSkin), "_rightHand"); private static readonly FieldInfo ItemInHandHolderField = AccessTools.Field(typeof(Item), "_inHandHolder"); private static readonly FieldInfo PlayerRightArmIkField = AccessTools.Field(typeof(PlayerArms), "_ikRight"); private static readonly FieldInfo PlayerLeftArmIkField = AccessTools.Field(typeof(PlayerArms), "_ikLeft"); private static readonly FieldInfo IkPoleField = AccessTools.Field(typeof(IK), "_pole"); private static readonly HashSet ServerPirates = new HashSet(); private static readonly HashSet IdentifiedClientPirates = new HashSet(); private static readonly HashSet VisualizedPirates = new HashSet(); private static readonly Dictionary> PirateWeapons = new Dictionary>(); private static readonly Dictionary PirateShooterCounts = new Dictionary(); private static readonly Dictionary PirateTriggers = new Dictionary(); private static Boat? MainBoat; private static Boat? LocalRiddenPirate; [ThreadStatic] private static int PirateMotorChangeDepth; public static bool IsApplyingPirateMotor => PirateMotorChangeDepth > 0; public static int MaximumShooterCount => ShooterStations.Length; public static void RegisterServerPirate(Boat boat, IReadOnlyList shooterWeapons) { ServerPirates.Add(boat); PirateWeapons[boat] = shooterWeapons; PirateShooterCounts[boat] = Mathf.Clamp(shooterWeapons.Count, 1, MaximumShooterCount); } public static void IdentifyClientPirate(Boat boat) { if (Object.op_Implicit((Object)(object)boat)) { IdentifiedClientPirates.Add(boat); } } public static void UnregisterServerPirate(Boat boat) { if (!Object.op_Implicit((Object)(object)boat)) { return; } if (Object.op_Implicit((Object)(object)boat.BoatTrigger)) { PirateTriggers.Remove(boat.BoatTrigger); } if ((Object)(object)LocalRiddenPirate == (Object)(object)boat) { Boat boat2 = BoatManager.Boat; SelectPirateBoatForLocalPlayer(boat); if (Object.op_Implicit((Object)(object)Player.LocalPlayer) && Player.LocalPlayer.Movement.OnBoat) { Player.LocalPlayer.Movement.SetBoat(false); boat.SetLocalPlayerOnBoat((Player)null); } LocalRiddenPirate = null; RestoreBoatSelection(boat2); } else if ((Object)(object)BoatManager.Boat == (Object)(object)boat) { RestoreTrackedMainBoat(); } ServerPirates.Remove(boat); IdentifiedClientPirates.Remove(boat); VisualizedPirates.Remove(boat); PirateWeapons.Remove(boat); PirateShooterCounts.Remove(boat); } public static bool IsServerPirate(Boat boat) { if (Object.op_Implicit((Object)(object)boat)) { return ServerPirates.Contains(boat); } return false; } public static bool IsPirateBoat(Boat boat) { if (Object.op_Implicit((Object)(object)boat)) { if (!ServerPirates.Contains(boat) && !IdentifiedClientPirates.Contains(boat)) { return VisualizedPirates.Contains(boat); } return true; } return false; } public static bool BeginPirateMotorChange(Boat boat) { if (!IsPirateBoat(boat)) { return false; } PirateMotorChangeDepth++; return true; } public static void EndPirateMotorChange() { PirateMotorChangeDepth--; } public static Vector3 GetShooterMuzzleFallback(Boat boat, int shooterIndex, Vector3 targetPosition) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) Transform visualBoat = boat.VisualBoat; Transform val = (Object.op_Implicit((Object)(object)boat.DriverPos) ? boat.DriverPos : visualBoat); Vector3 val2 = visualBoat.InverseTransformPoint(val.position) + GetShooterOffset(shooterIndex); Vector3 val3 = visualBoat.TransformPoint(val2 + Vector3.up * 1.15f); Vector3 val4 = targetPosition - val3; Vector3 normalized = ((Vector3)(ref val4)).normalized; return val3 + normalized * 0.75f; } public static void ApplyServerPirateDefaults(Boat boat) { if (PirateShooterCounts.TryGetValue(boat, out var value)) { ApplyDefaultBoatSkin(boat); boat._curSkin.Value = (byte)Mathf.Clamp(value - 1, 0, 255); } } public static bool ShouldApplyBoatSkin(Boat boat, byte encodedSkin) { if (encodedSkin != 0 || IsPirateBoat(boat)) { if (!IsPirateBoat(boat)) { if (Object.op_Implicit((Object)(object)BoatManager.Boat)) { return (Object)(object)BoatManager.Boat == (Object)(object)boat; } return true; } return false; } return true; } private static int GetShooterCount(Boat boat) { if (!PirateShooterCounts.TryGetValue(boat, out var value)) { return Mathf.Max(1, boat.CurSkin + 1); } return value; } public static Vector3 GetShooterOffset(int shooterIndex) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) return ShooterStations[Mathf.Clamp(shooterIndex, 0, ShooterStations.Length - 1)]; } public static void ConfigureClientPirate(Boat pirateBoat, Boat mainBoat) { RestoreMainBoat(mainBoat); IdentifyClientPirate(pirateBoat); ApplyDefaultBoatSkin(pirateBoat); if (Object.op_Implicit((Object)(object)pirateBoat.BoatTrigger)) { PirateTriggers[pirateBoat.BoatTrigger] = pirateBoat; } if (VisualizedPirates.Add(pirateBoat)) { DisableDrivingInteraction(pirateBoat); CreatePirateVisuals(pirateBoat); ((Component)pirateBoat).gameObject.AddComponent(); ((Component)pirateBoat).gameObject.AddComponent().Initialize(pirateBoat); } } private static void ApplyDefaultBoatSkin(Boat boat) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) SkinPreset skinPreset = boat.SkinPreset; Renderer val = (Renderer)BoatSkinRendererField.GetValue(boat); if (!Object.op_Implicit((Object)(object)skinPreset) || skinPreset.Skins.Count == 0 || !Object.op_Implicit((Object)(object)val)) { Plugin.Log.LogWarning((object)"Could not apply the default wood skin to a pirate boat."); } else { ShaderManager.ApplyItemSkin(skinPreset.Skins[0], val, true); } } public static void RestoreMainBoat(Boat mainBoat) { if (Object.op_Implicit((Object)(object)mainBoat)) { MainBoat = mainBoat; BoatManager.SetBoat((Collider[])DynamicObjectCollidersField.GetValue(mainBoat), mainBoat); } } public static bool TryGetPirateBoat(BoatTrigger trigger, out Boat boat) { if (PirateTriggers.TryGetValue(trigger, out boat)) { return Object.op_Implicit((Object)(object)boat); } return false; } public static void SelectPirateBoatForLocalPlayer(Boat boat) { if (Object.op_Implicit((Object)(object)boat)) { BoatManager.SetBoat((Collider[])DynamicObjectCollidersField.GetValue(boat), boat); } } public static void DisableDrivingInteraction(Boat boat) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown BoatInteractable val = (BoatInteractable)BoatInteractableField.GetValue(boat); if (Object.op_Implicit((Object)(object)val)) { ((Interactable)val).ToggleIsInteractable(false); } } public static bool TryGetPirateBoat(Transform target, out Boat boat) { boat = (Object.op_Implicit((Object)(object)target) ? ((Component)target).GetComponentInParent() : null); return IsPirateBoat(boat); } public static bool TryGetPirateBoatAtPoint(Vector3 point, out Boat boat) { //IL_0042: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) foreach (Boat item in ServerPirates.Concat(VisualizedPirates)) { if (!Object.op_Implicit((Object)(object)item)) { continue; } Collider[] componentsInChildren = ((Component)item).GetComponentsInChildren(false); foreach (Collider val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val)) { Vector3 val2 = val.ClosestPoint(point) - point; if (((Vector3)(ref val2)).sqrMagnitude <= 0.0025f) { boat = item; return true; } } } } boat = null; return false; } public static bool TryGetLivingPirateHit(Boat? boat, Ray ray, float maxDistance, float radius, out RaycastHit pirateHit) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0012: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) pirateHit = default(RaycastHit); if (maxDistance <= 0f) { return false; } int num = LayerMask.op_Implicit(GameInfo.NpcLayer) | LayerMask.op_Implicit(GameInfo.ItemPartLayer); RaycastHit[] obj = ((radius > 0f) ? Physics.SphereCastAll(ray, radius, maxDistance, num, (QueryTriggerInteraction)1) : Physics.RaycastAll(ray, maxDistance, num, (QueryTriggerInteraction)1)); float num2 = float.PositiveInfinity; RaycastHit[] array = obj; for (int i = 0; i < array.Length; i++) { RaycastHit val = array[i]; PirateCrewHealth pirateCrewHealth = (Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider) ? ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent() : null); if (Object.op_Implicit((Object)(object)pirateCrewHealth) && pirateCrewHealth.Alive && (!Object.op_Implicit((Object)(object)boat) || !((Object)(object)pirateCrewHealth.Boat != (Object)(object)boat)) && !(((RaycastHit)(ref val)).distance >= num2)) { num2 = ((RaycastHit)(ref val)).distance; pirateHit = val; } } return Object.op_Implicit((Object)(object)((RaycastHit)(ref pirateHit)).collider); } public static void BeginLocalPirateRide(Boat boat) { LocalRiddenPirate = boat; } public static void EndLocalPirateRide(Boat boat) { if ((Object)(object)LocalRiddenPirate == (Object)(object)boat) { LocalRiddenPirate = null; } } public static bool SelectLocalRiddenPirate(out Boat? previousBoat) { previousBoat = null; if (!Object.op_Implicit((Object)(object)LocalRiddenPirate)) { return false; } previousBoat = BoatManager.Boat; SelectPirateBoatForLocalPlayer(LocalRiddenPirate); return true; } public static void RestoreBoatSelection(Boat? previousBoat) { if (Object.op_Implicit((Object)(object)previousBoat)) { BoatManager.SetBoat((Collider[])DynamicObjectCollidersField.GetValue(previousBoat), previousBoat); } else { RestoreTrackedMainBoat(); } } public static void RestoreTrackedMainBoat() { if (Object.op_Implicit((Object)(object)MainBoat)) { RestoreMainBoat(MainBoat); } } public static int DisableWaterMask(Boat boat) { int num = 0; Renderer[] componentsInChildren = ((Component)boat).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && UsesDepthMaskShader(val)) { val.enabled = false; num++; } } return num; } private static bool UsesDepthMaskShader(Renderer renderer) { Material[] sharedMaterials = renderer.sharedMaterials; foreach (Material val in sharedMaterials) { if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.shader) && ((Object)val.shader).name == "Custom/DepthMaskShader") { return true; } } return false; } private static void CreatePirateVisuals(Boat boat) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //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_0048: 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_0054: 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) //IL_005f: 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_0071: 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_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018b: 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) Transform val = (Object.op_Implicit((Object)(object)boat.DriverPos) ? boat.DriverPos : boat.VisualBoat); int objectId = ((NetworkBehaviour)boat).ObjectId; Vector3 val2 = boat.VisualBoat.InverseTransformPoint(val.position) + Vector3.down * 0.08f; Quaternion val3 = Quaternion.Inverse(boat.VisualBoat.rotation) * val.rotation; GameObject val4 = CreatePirateFigure("Pirate 1", boat, boat.VisualBoat, val2, val3, objectId, isShooter: false); PirateCrewAnimator component = val4.GetComponent(); PirateCrewPoseDriver helmPose = CreateHelmPose(boat, val4.transform, component); PirateCrewHealth component2 = val4.GetComponent(); component2.SetCrewIndex(0); val4.AddComponent().Initialize(boat, component2, val2, val3, val2, Quaternion.identity, component, helmPose, null); int shooterCount = GetShooterCount(boat); PirateWeapons.TryGetValue(boat, out IReadOnlyList value); for (int i = 0; i < shooterCount; i++) { Vector3 val5 = val2 + GetShooterOffset(i); GameObject val6 = CreatePirateFigure($"Pirate {i + 2}", boat, boat.VisualBoat, val5, Quaternion.identity, objectId + (i + 1) * 7919, isShooter: true); PirateCrewAnimator component3 = val6.GetComponent(); PirateCrewPoseDriver helmPose2 = CreateHelmPose(boat, val6.transform, component3); PirateWeaponVisual weapon = ((value != null && i < value.Count) ? CreateHeldWeaponVisual(boat, val6.transform, component3, value[i]) : null); PirateCrewHealth component4 = val6.GetComponent(); component4.SetCrewIndex(i + 1); val6.AddComponent().Initialize(boat, component4, val2, val3, val5, Quaternion.identity, component3, helmPose2, weapon); } } private static PirateCrewPoseDriver? CreateHelmPose(Boat boat, Transform pirate, PirateCrewAnimator? animator) { if (!Object.op_Implicit((Object)(object)animator)) { return null; } PirateCrewPoseDriver pirateCrewPoseDriver = ((Component)pirate).gameObject.AddComponent(); pirateCrewPoseDriver.Initialize(((Component)boat).transform, ((Component)boat).transform, animator.RightHand, animator.LeftHand, boat.HandTransformsRight, boat.HandTransformsLeft); animator.UseExternalArmPose(); return pirateCrewPoseDriver; } private static GameObject CreatePirateFigure(string name, Boat boat, Transform parent, Vector3 localPosition, Quaternion localRotation, int appearanceSeed, bool isShooter) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0087: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: 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) GameObject val = TryClonePlayerModel(name, parent, localPosition, localRotation, appearanceSeed, isShooter); if (Object.op_Implicit((Object)(object)val)) { AddCrewHitbox(val, boat, isShooter); return val; } Color color = default(Color); ((Color)(ref color))..ctor(0.12f, 0.12f, 0.16f); GameObject val2 = GameObject.CreatePrimitive((PrimitiveType)1); ((Object)val2).name = name; RemoveCollider(val2); val2.transform.SetParent(parent, false); val2.transform.localPosition = localPosition; val2.transform.localRotation = localRotation; val2.transform.localScale = new Vector3(0.55f, 0.75f, 0.55f); Renderer componentInChildren = ((Component)boat.VisualBoat).GetComponentInChildren(); SetColor(val2, color, componentInChildren); GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)obj).name = name + " Head"; RemoveCollider(obj); obj.transform.SetParent(val2.transform, false); obj.transform.localPosition = new Vector3(0f, 0.95f, 0f); obj.transform.localScale = Vector3.one * 0.65f; SetColor(obj, new Color(0.72f, 0.48f, 0.32f), componentInChildren); val2.AddComponent().Initialize(isShooter, null, null); AddCrewHitbox(val2, boat, isShooter); return val2; } private static GameObject? TryClonePlayerModel(string name, Transform parent, Vector3 localPosition, Quaternion localRotation, int appearanceSeed, bool isShooter) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_009d: 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) //IL_00b5: 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_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0245: 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) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) Player playerPrefab = GameInfo.PlayerPrefab; if (!Object.op_Implicit((Object)(object)playerPrefab) || !Object.op_Implicit((Object)(object)playerPrefab.Skin)) { Plugin.Log.LogWarning((object)"The player prefab was unavailable; using fallback pirate figures."); return null; } SkinnedMeshRenderer val = (SkinnedMeshRenderer)PlayerBodyRendererField.GetValue(playerPrefab.Skin); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.rootBone)) { Plugin.Log.LogWarning((object)"The player prefab has no usable third-person skeleton; using fallback pirate figures."); return null; } GameObject val2 = new GameObject(name + " (Player Model)"); ((Object)val2).name = name + " (Player Model)"; val2.transform.SetParent(parent, false); val2.transform.localPosition = localPosition; val2.transform.localRotation = localRotation; val2.transform.localScale = Vector3.one; Transform rootBone = val.rootBone; Transform transform = Object.Instantiate(((Component)rootBone).gameObject).transform; ((Object)transform).name = ((Object)rootBone).name; transform.SetParent(val2.transform, false); CopyRelativeTransform(((Component)playerPrefab).transform, rootBone, transform); MonoBehaviour[] componentsInChildren = ((Component)transform).GetComponentsInChildren(true); foreach (MonoBehaviour val3 in componentsInChildren) { IK val4 = (IK)(object)((val3 is IK) ? val3 : null); if (val4 != null) { ((Behaviour)val4).enabled = false; } else { Object.Destroy((Object)(object)val3); } } PlayerSkin skin = playerPrefab.Skin; SkinnedMeshRenderer val5 = CloneRenderer(skin, PlayerBodyRendererField, ((Component)playerPrefab).transform, rootBone, transform, val2.transform); SkinnedMeshRenderer val6 = CloneRenderer(skin, PlayerLeftHandRendererField, ((Component)playerPrefab).transform, rootBone, transform, val2.transform); SkinnedMeshRenderer val7 = CloneRenderer(skin, PlayerRightHandRendererField, ((Component)playerPrefab).transform, rootBone, transform, val2.transform); SkinnedMeshRenderer renderer = CloneRenderer(skin, PlayerOutfitRendererField, ((Component)playerPrefab).transform, rootBone, transform, val2.transform); SkinnedMeshRenderer renderer2 = CloneRenderer(skin, PlayerHatRendererField, ((Component)playerPrefab).transform, rootBone, transform, val2.transform); SkinnedMeshRenderer? renderer3 = CloneRenderer(skin, PlayerAccessoryRendererField, ((Component)playerPrefab).transform, rootBone, transform, val2.transform); Random random = new Random(appearanceSeed); Vector3 val8 = RandomSkinUv(random); if (Object.op_Implicit((Object)(object)val5)) { ShaderManager.SetPlayerColors((Renderer)(object)val5, val8, default(Vector3), default(Vector3), default(Vector3)); } if (Object.op_Implicit((Object)(object)val6)) { ShaderManager.SetPlayerColors((Renderer)(object)val6, val8, default(Vector3), default(Vector3), default(Vector3)); } if (Object.op_Implicit((Object)(object)val7)) { ShaderManager.SetPlayerColors((Renderer)(object)val7, val8, default(Vector3), default(Vector3), default(Vector3)); } RandomizeClothing(renderer, SkinManager.SeenOutfits, (Func)SkinManager.GetOutfit, random, val8); RandomizeClothing(renderer2, SkinManager.SeenHats, (Func)SkinManager.GetHat, random, val8); RandomizeClothing(renderer3, SkinManager.SeenAccesories, (Func)SkinManager.GetAccessory, random, val8); IK val9 = ((!Object.op_Implicit((Object)(object)playerPrefab.Arms)) ? ((IK)null) : ((IK)PlayerRightArmIkField.GetValue(playerPrefab.Arms))); IK val10 = ((!Object.op_Implicit((Object)(object)playerPrefab.Arms)) ? ((IK)null) : ((IK)PlayerLeftArmIkField.GetValue(playerPrefab.Arms))); Transform val11 = FindClonedBone(Object.op_Implicit((Object)(object)val9) ? ((Component)val9).transform : null, rootBone, transform); Transform val12 = FindClonedBone(Object.op_Implicit((Object)(object)val10) ? ((Component)val10).transform : null, rootBone, transform); val11 = (Transform)(Object.op_Implicit((Object)(object)val11) ? ((object)val11) : ((object)FindDescendantByName(transform, "Hand_R"))); val12 = (Transform)(Object.op_Implicit((Object)(object)val12) ? ((object)val12) : ((object)FindDescendantByName(transform, "Hand_L"))); val11 = (Transform)(Object.op_Implicit((Object)(object)val11) ? ((object)val11) : ((object)FindClonedBone(Object.op_Implicit((Object)(object)playerPrefab.Hands) ? playerPrefab.Hands.HandBoneRight : null, rootBone, transform))); val12 = (Transform)(Object.op_Implicit((Object)(object)val12) ? ((object)val12) : ((object)FindClonedBone(Object.op_Implicit((Object)(object)playerPrefab.Hands) ? playerPrefab.Hands.HandBoneLeft : null, rootBone, transform))); val11 = (Transform)(Object.op_Implicit((Object)(object)val11) ? ((object)val11) : ((object)FindHandBone(val, ((Component)playerPrefab).transform, rootBone, transform, right: true))); val12 = (Transform)(Object.op_Implicit((Object)(object)val12) ? ((object)val12) : ((object)FindHandBone(val, ((Component)playerPrefab).transform, rootBone, transform, right: false))); RemapIkPole(((Component)playerPrefab).transform, rootBone, transform, val2.transform, val9, val11); RemapIkPole(((Component)playerPrefab).transform, rootBone, transform, val2.transform, val10, val12); val2.AddComponent().Initialize(isShooter, val11, val12); Plugin.Log.LogDebug((object)("Using randomized third-person player model for " + name + ".")); return val2; } private static void RemapIkPole(Transform playerRoot, Transform sourceSkeleton, Transform clonedSkeleton, Transform cloneRoot, IK? sourceSolver, Transform? clonedHand) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)sourceSolver) || !Object.op_Implicit((Object)(object)clonedHand)) { return; } IK component = ((Component)clonedHand).GetComponent(); Transform val = (Transform)IkPoleField.GetValue(sourceSolver); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)val)) { Transform val2 = FindClonedBone(val, sourceSkeleton, clonedSkeleton); if (!Object.op_Implicit((Object)(object)val2) || (Object)(object)val2 == (Object)(object)val) { GameObject val3 = new GameObject(((Object)val).name); val3.transform.SetParent(cloneRoot, false); CopyRelativeTransform(playerRoot, val, val3.transform); val2 = val3.transform; } IkPoleField.SetValue(component, val2); } } private static SkinnedMeshRenderer? CloneRenderer(PlayerSkin skin, FieldInfo field, Transform playerRoot, Transform sourceSkeleton, Transform clonedSkeleton, Transform cloneRoot) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) SkinnedMeshRenderer val = (SkinnedMeshRenderer)field.GetValue(skin); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.sharedMesh)) { return null; } GameObject val2 = new GameObject(((Object)((Component)val).gameObject).name); val2.transform.SetParent(cloneRoot, false); CopyRelativeTransform(playerRoot, ((Component)val).transform, val2.transform); SkinnedMeshRenderer obj = val2.AddComponent(); obj.sharedMesh = val.sharedMesh; ((Renderer)obj).sharedMaterials = ((Renderer)val).sharedMaterials; ((Renderer)obj).localBounds = ((Renderer)val).localBounds; obj.updateWhenOffscreen = val.updateWhenOffscreen; obj.rootBone = FindClonedBone(val.rootBone, sourceSkeleton, clonedSkeleton); obj.bones = val.bones.Select((Transform bone) => FindClonedBone(bone, sourceSkeleton, clonedSkeleton)).ToArray(); return obj; } private static Transform? FindClonedBone(Transform? source, Transform sourceSkeleton, Transform clonedSkeleton) { if (!Object.op_Implicit((Object)(object)source)) { return null; } if ((Object)(object)source != (Object)(object)sourceSkeleton && !source.IsChildOf(sourceSkeleton)) { return FindDescendantByName(clonedSkeleton, ((Object)source).name); } if ((Object)(object)source == (Object)(object)sourceSkeleton) { return clonedSkeleton; } return clonedSkeleton.Find(GetRelativePath(sourceSkeleton, source)); } private static Transform? FindDescendantByName(Transform parent, string name) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown foreach (Transform item in parent) { Transform val = item; if (((Object)val).name == name) { return val; } Transform val2 = FindDescendantByName(val, name); if (Object.op_Implicit((Object)(object)val2)) { return val2; } } return null; } private static Transform? FindHandBone(SkinnedMeshRenderer renderer, Transform playerRoot, Transform sourceSkeleton, Transform clonedSkeleton, bool right) { //IL_0059: 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) Transform source = null; float num = (right ? float.NegativeInfinity : float.PositiveInfinity); Transform[] bones = renderer.bones; foreach (Transform val in bones) { if (!Object.op_Implicit((Object)(object)val)) { continue; } string text = ((Object)val).name.ToLowerInvariant(); if (text.Contains("hand") || text.Contains("wrist")) { float x = playerRoot.InverseTransformPoint(val.position).x; if ((right && x > num) || (!right && x < num)) { source = val; num = x; } } } return FindClonedBone(source, sourceSkeleton, clonedSkeleton); } private static string GetRelativePath(Transform root, Transform child) { List list = new List(); Transform val = child; while ((Object)(object)val != (Object)(object)root) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list); } private static void CopyRelativeTransform(Transform root, Transform source, Transform destination) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) destination.localPosition = root.InverseTransformPoint(source.position); destination.localRotation = Quaternion.Inverse(root.rotation) * source.rotation; destination.localScale = source.lossyScale; } private static PirateWeaponVisual CreateHeldWeaponVisual(Boat boat, Transform shooter, PirateCrewAnimator? crew, PirateWeaponDefinition weapon) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Expected O, but got Unknown //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) GameObject val = FindAnimatedWeaponVisual(weapon.VisualSource); GameObject val2 = new GameObject("Pirate " + weapon.Name); val2.transform.SetParent(shooter, false); SetThirdPersonWeaponPose(val2.transform, weapon.VisualSource); GameObject val3 = val2; if (Object.op_Implicit((Object)(object)val)) { val3 = Object.Instantiate(val, val2.transform, false); ((Object)val3).name = weapon.Name + " (Held)"; CopyRelativeTransform(((Component)weapon.VisualSource).transform, val.transform, val3.transform); val3.SetActive(true); Collider[] componentsInChildren = val3.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.Destroy((Object)(object)componentsInChildren[i]); } MonoBehaviour[] componentsInChildren2 = val3.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.Destroy((Object)(object)componentsInChildren2[i]); } Renderer[] componentsInChildren3 = val3.GetComponentsInChildren(true); foreach (Renderer obj in componentsInChildren3) { obj.enabled = true; SkinnedMeshRenderer val4 = (SkinnedMeshRenderer)(object)((obj is SkinnedMeshRenderer) ? obj : null); if (val4 != null) { val4.updateWhenOffscreen = true; } } EnableAnimatedWeaponHands(val.transform, val3.transform, ((Tool)weapon.VisualSource).HandsMesh); } PirateWeaponVisual pirateWeaponVisual = val2.AddComponent(); GameObject val5 = new GameObject("Pirate Muzzle"); val5.transform.SetParent(val2.transform, false); val5.transform.localPosition = Vector3.forward * 0.7f; val5.transform.localRotation = Quaternion.identity; Transform muzzle = val5.transform; if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)weapon.Attachments.FirePoint)) { Transform val6 = FindClonedTarget(val.transform, val3.transform, weapon.Attachments.FirePoint); if (Object.op_Implicit((Object)(object)val6)) { muzzle = val6; Object.Destroy((Object)(object)val5); } } PirateCrewPoseDriver pirateCrewPoseDriver = null; Renderer[] crewHandRenderers = Array.Empty(); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)crew)) { pirateCrewPoseDriver = ((Component)shooter).gameObject.AddComponent(); Transform val7 = FindClonedTarget(val.transform, val3.transform, ((Item)weapon.VisualSource).HandModelRight); Transform val8 = FindClonedTarget(val.transform, val3.transform, ((Item)weapon.VisualSource).HandModelLeft); if (Object.op_Implicit((Object)(object)val7) || Object.op_Implicit((Object)(object)val8)) { crewHandRenderers = HideClonedPlayerHandRenderers(shooter); pirateCrewPoseDriver.InitializeAnimatedWeaponTargets(crew.RightHand, crew.LeftHand, val7, val8); } else { pirateCrewPoseDriver.Initialize(val.transform, val3.transform, crew.RightHand, crew.LeftHand, ((Item)weapon.VisualSource).HandTransformsRight, ((Item)weapon.VisualSource).HandTransformsLeft, createFallbackWeaponPose: true); } crew.UseExternalArmPose(); } pirateWeaponVisual.Initialize(boat, val3, muzzle, pirateCrewPoseDriver, crewHandRenderers); Plugin.Log.LogInfo((object)($"Pirate weapon visual initialized: {val3.GetComponentsInChildren(true).Length} renderers, " + "animation=" + (Object.op_Implicit((Object)(object)val3.GetComponentInChildren(true)) ? "yes" : "no") + ", right hand=" + (((Object)(object)crew != (Object)null && Object.op_Implicit((Object)(object)crew.RightHand)) ? ((Object)crew.RightHand).name : "missing") + ", left hand=" + (((Object)(object)crew != (Object)null && Object.op_Implicit((Object)(object)crew.LeftHand)) ? ((Object)crew.LeftHand).name : "missing") + ".")); return pirateWeaponVisual; } private static GameObject? FindAnimatedWeaponVisual(Weapon weapon) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown Animation componentInChildren = ((Component)weapon).GetComponentInChildren(true); if (Object.op_Implicit((Object)(object)componentInChildren)) { return ((Component)componentInChildren).gameObject; } return (GameObject)ItemInHandHolderField.GetValue(weapon); } private static void SetThirdPersonWeaponPose(Transform pivot, Weapon weapon) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_007d: 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_0087: 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_0090: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) Player playerPrefab = GameInfo.PlayerPrefab; Transform val = ((Object.op_Implicit((Object)(object)playerPrefab) && Object.op_Implicit((Object)(object)playerPrefab.Other)) ? playerPrefab.Other.CamProxy : null); if (!Object.op_Implicit((Object)(object)playerPrefab) || !Object.op_Implicit((Object)(object)val)) { pivot.localPosition = new Vector3(0f, 0.82f, Mathf.Max(0.15f, ((Tool)weapon).ThirdPersonOffset)); pivot.localRotation = Quaternion.identity; } else { Vector3 val2 = val.position + val.forward * ((Tool)weapon).ThirdPersonOffset; pivot.localPosition = ((Component)playerPrefab).transform.InverseTransformPoint(val2); pivot.localRotation = Quaternion.Inverse(((Component)playerPrefab).transform.rotation) * val.rotation; } } private static Renderer[] HideClonedPlayerHandRenderers(Transform shooter) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown Player playerPrefab = GameInfo.PlayerPrefab; if (!Object.op_Implicit((Object)(object)playerPrefab) || !Object.op_Implicit((Object)(object)playerPrefab.Skin)) { return Array.Empty(); } List list = new List(); Renderer val = HideClonedRenderer(shooter, (Renderer)PlayerRightHandRendererField.GetValue(playerPrefab.Skin)); Renderer val2 = HideClonedRenderer(shooter, (Renderer)PlayerLeftHandRendererField.GetValue(playerPrefab.Skin)); if (Object.op_Implicit((Object)(object)val)) { list.Add(val); } if (Object.op_Implicit((Object)(object)val2)) { list.Add(val2); } return list.ToArray(); } private static Renderer? HideClonedRenderer(Transform cloneRoot, Renderer sourceRenderer) { if (!Object.op_Implicit((Object)(object)sourceRenderer)) { return null; } Transform val = cloneRoot.Find(((Object)((Component)sourceRenderer).gameObject).name); Renderer val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent() : null); if (Object.op_Implicit((Object)(object)val2)) { val2.enabled = false; } return val2; } private static Transform? FindClonedTarget(Transform sourceRoot, Transform clonedRoot, Transform sourceTarget) { if (!Object.op_Implicit((Object)(object)sourceTarget)) { return null; } if ((Object)(object)sourceTarget == (Object)(object)sourceRoot) { return clonedRoot; } if (!sourceTarget.IsChildOf(sourceRoot)) { return null; } return clonedRoot.Find(GetRelativePath(sourceRoot, sourceTarget)); } private static void EnableAnimatedWeaponHands(Transform sourceRoot, Transform clonedRoot, Renderer sourceHands) { if (Object.op_Implicit((Object)(object)sourceHands) && (!((Object)(object)((Component)sourceHands).transform != (Object)(object)sourceRoot) || ((Component)sourceHands).transform.IsChildOf(sourceRoot))) { Transform val = (Transform)(((Object)(object)((Component)sourceHands).transform == (Object)(object)sourceRoot) ? ((object)clonedRoot) : ((object)clonedRoot.Find(GetRelativePath(sourceRoot, ((Component)sourceHands).transform)))); Renderer val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent() : null); if (Object.op_Implicit((Object)(object)val2)) { val2.enabled = true; } } } private static void RandomizeClothing(SkinnedMeshRenderer? renderer, bool[]? available, Func meshGetter, Random random, Vector3 skinColor) { //IL_0027: 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) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)renderer) && available != null && available.Length != 0) { renderer.sharedMesh = meshGetter((byte)random.Next(available.Length)); ShaderManager.SetPlayerColors((Renderer)(object)renderer, skinColor, RandomClothingUv(random), RandomClothingUv(random), RandomClothingUv(random)); } } private static void AddCrewHitbox(GameObject figure, Boat boat, bool isShooter) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Pirate Hitbox"); val.tag = "NPC"; int num = LayerMask.NameToLayer("NPC"); if (num >= 0) { val.layer = num; } val.transform.SetParent(figure.transform, false); val.transform.localPosition = new Vector3(0f, 0.95f, 0f); CapsuleCollider val2 = val.AddComponent(); val2.height = 1.9f; val2.radius = 0.42f; val2.direction = 1; figure.AddComponent().Initialize(boat, isShooter, (Collider)(object)val2); } private static Vector3 RandomSkinUv(Random random) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) float[] array = new float[4] { 0.2f, 0.23f, 0.45f, 0.48f }; return new Vector3((float)random.NextDouble(), array[random.Next(array.Length)], 0f); } private static Vector3 RandomClothingUv(Random random) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) float[] array = new float[4] { 0.2f, 0.45f, 0.7f, 0.95f }; return new Vector3((float)random.NextDouble(), array[random.Next(array.Length)], 0f); } private static void RemoveCollider(GameObject gameObject) { Collider component = gameObject.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { Object.Destroy((Object)(object)component); } } private static void SetColor(GameObject gameObject, Color color, Renderer? materialSource = null) { //IL_003b: 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_0035: Expected O, but got Unknown Renderer component = gameObject.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { if (Object.op_Implicit((Object)(object)materialSource) && Object.op_Implicit((Object)(object)materialSource.sharedMaterial)) { component.material = new Material(materialSource.sharedMaterial); } component.material.color = color; } } } internal sealed class PirateBoatWaterMask : MonoBehaviour { private Boat _boat; private bool _disabled; public void Initialize(Boat boat) { _boat = boat; } private void Update() { if (!_disabled && Object.op_Implicit((Object)(object)_boat) && !_boat.BoatUnlocked && !_boat.BoatRadarUnlocked) { _disabled = true; int num = PirateBoatSupport.DisableWaterMask(_boat); Plugin.Log.LogInfo((object)$"Disabled {num} pirate boat water-mask renderer(s) so the hull can flood."); } } } internal static class PirateCollectibleSupport { private const float MatchDistance = 1.25f; private const float PirateHeadHeight = 1.45f; private static readonly FieldInfo ExcludeFromJournalField = AccessTools.Field(typeof(Creature), "_excludeFromJournal"); private static readonly FieldInfo MaxHealthField = AccessTools.Field(typeof(Creature), "_maxHp"); private static readonly FieldInfo HeadPositionField = AccessTools.Field(typeof(Creature), "_headPos"); private static readonly FieldInfo ItemRenderersField = AccessTools.Field(typeof(Item), "_renderers"); private static readonly FieldInfo CreatureReferenceField = AccessTools.Field(typeof(Item), "_creature"); private static readonly FieldInfo DeadPlayerReferenceField = AccessTools.Field(typeof(Item), "_deadPlayer"); private static readonly FieldInfo WorthField = AccessTools.Field(typeof(Item), "_worth"); private static readonly FieldInfo IgnoredByMoneyNpcField = AccessTools.Field(typeof(Item), "_ignoredByMoneyNPC"); private static readonly FieldInfo WorldCollidersField = AccessTools.Field(typeof(Item), "_worldColliders"); private static readonly FieldInfo PickupColliderField = AccessTools.Field(typeof(Item), "_pickUpCollider"); private static readonly HashSet ClaimedPirates = new HashSet(); private static readonly Dictionary PendingHostBindings = new Dictionary(); public static void SpawnLivingCreature(PirateCrewHealth pirate) { //IL_0025: 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_006e: 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) Creature val = FindCollectiblePrefab(); if (!Object.op_Implicit((Object)(object)val)) { Plugin.Log.LogError((object)"Could not find a non-boss creature prefab for the pirate creature proxy."); return; } Creature val2 = Object.Instantiate(val, ((Component)pirate).transform.position, GetCreatureRotation(pirate)); ConfigureCreatureIdentity(val2, pirate); ConfigureAttachedCreature(val2); val2._hp.Value = pirate.MaxHealth; PendingHostBindings[val2] = pirate; ((NetworkBehaviour)Server.Instance).Spawn(((Component)val2).gameObject, (NetworkConnection)null, default(Scene)); Plugin.Log.LogDebug((object)("Spawned living creature proxy for " + GetRoleName(pirate) + ".")); } public static PirateCrewHealth? FindMatchingPirate(Creature creature) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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) if (PendingHostBindings.TryGetValue(creature, out PirateCrewHealth value)) { PendingHostBindings.Remove(creature); if (Object.op_Implicit((Object)(object)value) && !ClaimedPirates.Contains(value)) { ClaimedPirates.Add(value); return value; } } PirateCrewHealth pirateCrewHealth = null; float num = 1.5625f; PirateCrewHealth[] array = Object.FindObjectsByType((FindObjectsInactive)1); foreach (PirateCrewHealth pirateCrewHealth2 in array) { if (Object.op_Implicit((Object)(object)pirateCrewHealth2) && !ClaimedPirates.Contains(pirateCrewHealth2)) { Vector3 val = ((Component)pirateCrewHealth2).transform.position - ((Component)creature).transform.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude <= num) { pirateCrewHealth = pirateCrewHealth2; num = sqrMagnitude; } } } if (Object.op_Implicit((Object)(object)pirateCrewHealth)) { ClaimedPirates.Add(pirateCrewHealth); } return pirateCrewHealth; } public static void Prepare(Creature creature, PirateCrewHealth pirate) { ConfigureCreatureIdentity(creature, pirate); EnsureCollectibleVisual(creature); } public static void BindLivingCreature(Creature creature, PirateCrewHealth pirate) { pirate.AttachCreature(creature); HideProxyVisuals(creature); SetProxyCollidersEnabled(creature, enabled: false); ((Component)pirate.Hitbox).tag = "Untagged"; int num = LayerMask.NameToLayer("NPC"); if (num >= 0) { ((Component)pirate.Hitbox).gameObject.layer = num; } ItemManager.Add((Item)(object)creature, pirate.Hitbox, (Collider[])(object)new Collider[1] { pirate.Hitbox }); ((Item)creature).RigidbodySync.SetBoat(true); ((Item)creature).RigidbodySync.SetKinematic(true); ((Behaviour)creature).enabled = false; ((Component)creature).gameObject.AddComponent().Initialize(creature, pirate); Plugin.Log.LogInfo((object)($"Bound pirate creature {((NetworkBehaviour)creature).ObjectId} to boat {((NetworkBehaviour)pirate.Boat).ObjectId}, " + $"crew index {pirate.CrewIndex}.")); } public static void AdoptVisual(Creature creature, PirateCrewHealth pirate) { //IL_0056: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) List list = (List)ItemRenderersField.GetValue(creature); pirate.HandleCreatureDeath(); pirate.ConvertToCollectible(); ClassifyAsCorpse(creature); DisableCorpseBehaviours(pirate); SetProxyCollidersEnabled(creature, enabled: false); SetPickupColliderEnabled(creature, enabled: true); ((Behaviour)creature).enabled = true; ((Item)creature).RigidbodySync.SetBoat(false); ((Component)creature).transform.SetPositionAndRotation(((Component)pirate).transform.position, Quaternion.Euler(0f, ((Component)pirate).transform.eulerAngles.y, 0f)); ((Component)pirate).transform.SetParent(((Component)creature).transform, false); ((Component)pirate).transform.localPosition = Vector3.zero; ((Component)pirate).transform.localRotation = Quaternion.Euler(90f, 0f, 90f); Rigidbody[] ragdollBodies = PirateRagdoll.Enable(pirate, creature); EnsureCollectibleVisual(creature).BeginWaterDecay(ragdollBodies); if (((NetworkBehaviour)creature).IsServerInitialized) { ((Item)creature).RigidbodySync.StartSimulateLocal(default(Vector3), default(Quaternion)); } ((Item)creature).RigidbodySync.SetKinematic(false); PirateRagdoll.ResetSpawnMotion(creature, ragdollBodies); list.Clear(); Renderer[] componentsInChildren = ((Component)pirate).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { val.enabled = true; list.Add(val); } Plugin.Log.LogInfo((object)$"Converted pirate {((NetworkBehaviour)creature).ObjectId} into a detached collectible corpse."); } public static string GetRoleName(PirateCrewHealth pirate) { return "Pirate"; } public static bool IsPirateProxy(Item item) { if (Object.op_Implicit((Object)(object)item)) { return Object.op_Implicit((Object)(object)((Component)item).GetComponent()); } return false; } public static void ReleasePirate(PirateCrewHealth pirate) { if (Object.op_Implicit((Object)(object)pirate)) { ClaimedPirates.Remove(pirate); } Creature key = null; bool flag = false; foreach (KeyValuePair pendingHostBinding in PendingHostBindings) { if (!Object.op_Implicit((Object)(object)pendingHostBinding.Key) || (Object)(object)pendingHostBinding.Value == (Object)(object)pirate) { key = pendingHostBinding.Key; flag = true; break; } } if (flag) { PendingHostBindings.Remove(key); } } private static void ConfigureAttachedCreature(Creature creature) { EnsureCollectibleVisual(creature); if (!Object.op_Implicit((Object)(object)((Component)creature).GetComponent())) { ((Component)creature).gameObject.AddComponent(); } if (!Object.op_Implicit((Object)(object)((Component)creature).GetComponent())) { ((Component)creature).gameObject.AddComponent(); } } private static PirateCollectibleVisual EnsureCollectibleVisual(Creature creature) { PirateCollectibleVisual pirateCollectibleVisual = ((Component)creature).GetComponent(); if (!Object.op_Implicit((Object)(object)pirateCollectibleVisual)) { pirateCollectibleVisual = ((Component)creature).gameObject.AddComponent(); } pirateCollectibleVisual.Initialize(creature); return pirateCollectibleVisual; } private static void ConfigureCreatureIdentity(Creature creature, PirateCrewHealth pirate) { ((Object)creature).name = "Pirate Creature"; ExcludeFromJournalField.SetValue(creature, true); MaxHealthField.SetValue(creature, pirate.MaxHealth); HeadPositionField.SetValue(creature, 1.45f); } private static void ClassifyAsCorpse(Creature creature) { CreatureReferenceField.SetValue(creature, null); WorthField.SetValue(creature, 0); IgnoredByMoneyNpcField.SetValue(creature, true); DeadPlayer deadPlayerPrefab = GameInfo.DeadPlayerPrefab; if (Object.op_Implicit((Object)(object)deadPlayerPrefab)) { DeadPlayerReferenceField.SetValue(creature, deadPlayerPrefab); } else { Plugin.Log.LogWarning((object)"The dead-player prefab was unavailable, so a pirate body could not receive native corpse classification."); } } private static Quaternion GetCreatureRotation(PirateCrewHealth pirate) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //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) return ((Component)pirate).transform.rotation * Quaternion.Euler(-90f, 0f, 0f); } private static void HideProxyVisuals(Creature creature) { foreach (Renderer item in (List)ItemRenderersField.GetValue(creature)) { if (Object.op_Implicit((Object)(object)item)) { item.enabled = false; } } } private static void SetProxyCollidersEnabled(Creature creature, bool enabled) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown Collider[] array = (Collider[])WorldCollidersField.GetValue(creature); foreach (Collider val in array) { if (Object.op_Implicit((Object)(object)val)) { val.enabled = enabled; } } Collider val2 = (Collider)PickupColliderField.GetValue(creature); if (Object.op_Implicit((Object)(object)val2)) { val2.enabled = enabled; } } private static void SetPickupColliderEnabled(Creature creature, bool enabled) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Collider val = (Collider)PickupColliderField.GetValue(creature); if (Object.op_Implicit((Object)(object)val)) { val.enabled = enabled; } } private static Creature? FindCollectiblePrefab() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < GameInfo.AllCreatureCount; i++) { Creature creature = GameInfo.GetCreature(i); if (Object.op_Implicit((Object)(object)creature) && (int)creature.BossType == 0) { return creature; } } return null; } private static void DisableCorpseBehaviours(PirateCrewHealth pirate) { PirateCrewAnimator[] componentsInChildren = ((Component)pirate).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Behaviour)componentsInChildren[i]).enabled = false; } PirateCrewPoseDriver[] componentsInChildren2 = ((Component)pirate).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { ((Behaviour)componentsInChildren2[i]).enabled = false; } PirateWeaponVisual[] componentsInChildren3 = ((Component)pirate).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren3.Length; i++) { componentsInChildren3[i].PrepareForCorpse(); } } } internal sealed class PirateCreatureProxy : MonoBehaviour { } internal sealed class PirateCreatureLink : MonoBehaviour { private Creature _creature; private PirateCrewHealth _pirate; private bool _adopted; public PirateCrewHealth Pirate => _pirate; public bool IsAttached { get { if (!_adopted && Object.op_Implicit((Object)(object)_creature)) { return Object.op_Implicit((Object)(object)_pirate); } return false; } } public void Initialize(Creature creature, PirateCrewHealth pirate) { _creature = creature; _pirate = pirate; FollowPirate(); } private void LateUpdate() { if (!_adopted && Object.op_Implicit((Object)(object)_creature) && Object.op_Implicit((Object)(object)_pirate) && !TryAdoptIfDead()) { FollowPirate(); } } public bool TryAdoptIfDead() { if (_adopted || !Object.op_Implicit((Object)(object)_creature) || !Object.op_Implicit((Object)(object)_pirate) || _creature._hp.Value > 0) { return false; } _adopted = true; PirateCollectibleSupport.AdoptVisual(_creature, _pirate); return true; } private void FollowPirate() { //IL_0016: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) ((Component)_creature).transform.SetPositionAndRotation(((Component)_pirate).transform.position, ((Component)_pirate).transform.rotation * Quaternion.Euler(-90f, 0f, 0f)); } private void OnDestroy() { PirateCollectibleSupport.ReleasePirate(_pirate); } } internal sealed class PirateCollectibleVisual : MonoBehaviour { private static readonly FieldInfo BuoyancyField = AccessTools.Field(typeof(Item), "_buoyancy"); private Creature _creature; private Rigidbody[] _ragdollBodies = (Rigidbody[])(object)new Rigidbody[0]; private float _originalBuoyancy; private float _waterDecayElapsed; private bool _waterDecayEnabled; private bool _loggedWaterEntry; public void Initialize(Creature creature) { if (!Object.op_Implicit((Object)(object)_creature)) { _creature = creature; _originalBuoyancy = ((Item)creature).Buoyancy; } } public void BeginWaterDecay(Rigidbody[] ragdollBodies) { _ragdollBodies = (Rigidbody[])(((object)ragdollBodies) ?? ((object)new Rigidbody[0])); _waterDecayEnabled = true; _waterDecayElapsed = 0f; _loggedWaterEntry = false; RestoreBuoyancy(); } private void OnDisable() { ResetWaterDecay(); } private void FixedUpdate() { //IL_009e: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) if (!_waterDecayEnabled || !Object.op_Implicit((Object)(object)_creature) || ((NetworkBehaviour)_creature).IsDeinitializing) { return; } if (!IsInWater()) { ResetWaterDecay(); return; } if (_waterDecayElapsed <= 0f && !_loggedWaterEntry) { _loggedWaterEntry = true; Plugin.Log.LogInfo((object)$"Pirate corpse {((NetworkBehaviour)_creature).ObjectId} is substantially submerged; starting 30-second decay."); } if (((Item)_creature).RigidbodySync.IsFloating && ((NetworkBehaviour)_creature).IsServerInitialized) { ((Item)_creature).RigidbodySync.StartSimulateLocal(default(Vector3), default(Quaternion)); } _waterDecayElapsed = Mathf.Min(_waterDecayElapsed + Time.fixedDeltaTime, 30f); float num = _waterDecayElapsed / 30f; BuoyancyField.SetValue(_creature, _originalBuoyancy * (1f - num)); ApplyRagdollBuoyancy(1f - num); if (num >= 1f && ((NetworkBehaviour)_creature).IsServerInitialized && Object.op_Implicit((Object)(object)Server.Instance) && ((NetworkBehaviour)Server.Instance).IsServerInitialized) { Plugin.Log.LogInfo((object)$"Pirate corpse {((NetworkBehaviour)_creature).ObjectId} fully decayed underwater and is being despawned."); ((NetworkBehaviour)Server.Instance).Despawn(((Component)_creature).gameObject, (DespawnType?)null); } } private bool IsInWater() { //IL_0056: 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) if (Object.op_Implicit((Object)(object)((Item)_creature).Holder) || ((Item)_creature).IsInInventory || ((Item)_creature).RigidbodySync.OnBoat) { return false; } int num = 0; int num2 = 0; Rigidbody[] ragdollBodies = _ragdollBodies; foreach (Rigidbody val in ragdollBodies) { if (Object.op_Implicit((Object)(object)val)) { num++; if (WaterManager.IsUnderWater(val.worldCenterOfMass)) { num2++; } } } if (num > 0) { return num2 * 4 >= num * 3; } return WaterManager.IsUnderWater(((Item)_creature).Rig.worldCenterOfMass); } private void ApplyRagdollBuoyancy(float buoyancyScale) { //IL_0047: 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) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) if (!((Item)_creature).RigidbodySync.IsSimulatedLocal || buoyancyScale <= 0f) { return; } float num = _originalBuoyancy * buoyancyScale; Rigidbody[] ragdollBodies = _ragdollBodies; foreach (Rigidbody val in ragdollBodies) { if (Object.op_Implicit((Object)(object)val) && !val.isKinematic) { KeyValuePair waterInfo = WaterManager.GetWaterInfo(val.worldCenterOfMass); if (waterInfo.Key) { Vector3 linearVelocity = val.linearVelocity; float num2 = Mathf.Clamp(waterInfo.Value, WaterManager.ItemMinForce, float.MaxValue) * WaterManager.ItemBouyancy * num * Time.fixedDeltaTime; linearVelocity.y = Mathf.MoveTowards(linearVelocity.y, WaterManager.ItemWaterMaxVelocity * num, num2); val.linearVelocity = linearVelocity; } } } } private void ResetWaterDecay() { _waterDecayElapsed = 0f; _loggedWaterEntry = false; RestoreBuoyancy(); } private void RestoreBuoyancy() { if (Object.op_Implicit((Object)(object)_creature)) { BuoyancyField.SetValue(_creature, _originalBuoyancy); } } } [DefaultExecutionOrder(1000)] internal sealed class PirateCrewAnimator : MonoBehaviour { private sealed class ArmAnimation { public Transform UpperArm; public Transform Forearm; public Quaternion UpperBaseRotation; public Quaternion ForearmBaseRotation; public float Side; } private bool _isShooter; private Vector3 _baseLocalPosition; private Quaternion _baseLocalRotation; private float _phase; private float _recoil; private float _reloadStart = -1f; private float _reloadDuration; private bool _animateArms = true; private ArmAnimation? _rightArm; private ArmAnimation? _leftArm; public Transform? RightHand { get; private set; } public Transform? LeftHand { get; private set; } public void Initialize(bool isShooter, Transform? rightHand, Transform? leftHand) { //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) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) _isShooter = isShooter; RightHand = rightHand; LeftHand = leftHand; _baseLocalPosition = ((Component)this).transform.localPosition; _baseLocalRotation = ((Component)this).transform.localRotation; _phase = Random.Range(0f, MathF.PI * 2f); _rightArm = CreateArmAnimation(rightHand, 1f); _leftArm = CreateArmAnimation(leftHand, -1f); } public void Fire() { if (_isShooter) { _recoil = 1f; } } public void SetArmed(bool armed) { _isShooter = armed; if (!armed) { _recoil = 0f; _reloadStart = -1f; } } public void Reload(float duration) { if (_isShooter) { _reloadStart = Time.time; _reloadDuration = Mathf.Max(0.1f, duration); } } public void UseExternalArmPose() { _animateArms = false; } public void SetBasePose(Vector3 localPosition, Quaternion localRotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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) _baseLocalPosition = localPosition; _baseLocalRotation = localRotation; } private void LateUpdate() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: 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_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0198: 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_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: 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) float num = Mathf.Sin(Time.time * 2f + _phase); _recoil = Mathf.MoveTowards(_recoil, 0f, Time.deltaTime * 7f); float num2 = 0f; if (_reloadStart >= 0f) { float num3 = (Time.time - _reloadStart) / _reloadDuration; if (num3 >= 1f) { _reloadStart = -1f; } else { num2 = Mathf.Sin(num3 * MathF.PI); } } ((Component)this).transform.localPosition = _baseLocalPosition + Vector3.up * (num * 0.025f - num2 * 0.12f) + Vector3.back * (_recoil * 0.12f); Quaternion val = Quaternion.Euler((0f - num2) * 12f + _recoil * 9f, 0f, num * 1.25f); Quaternion val2 = _baseLocalRotation * val; if (_isShooter && Object.op_Implicit((Object)(object)Player.LocalPlayer) && Object.op_Implicit((Object)(object)Player.LocalPlayer.Transform) && Object.op_Implicit((Object)(object)((Component)this).transform.parent)) { Vector3 val3 = ((Component)this).transform.parent.InverseTransformPoint(Player.LocalPlayer.Transform.position) - ((Component)this).transform.localPosition; val3.y = 0f; if (((Vector3)(ref val3)).sqrMagnitude > 0.01f) { float num4 = Mathf.Atan2(val3.x, val3.z) * 57.29578f; val2 = _baseLocalRotation * Quaternion.Euler((0f - num2) * 12f + _recoil * 9f, num4, num * 0.5f); } } ((Component)this).transform.localRotation = Quaternion.Slerp(((Component)this).transform.localRotation, val2, Time.deltaTime * 5f); if (_animateArms) { AnimateArm(_rightArm, num, num2, _recoil, right: true); AnimateArm(_leftArm, num, num2, _recoil, right: false); } } private static ArmAnimation? CreateArmAnimation(Transform? hand, float side) { //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_0058: 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) if (!Object.op_Implicit((Object)(object)hand) || !Object.op_Implicit((Object)(object)hand.parent) || !Object.op_Implicit((Object)(object)hand.parent.parent)) { return null; } Transform parent = hand.parent; Transform parent2 = parent.parent; return new ArmAnimation { UpperArm = parent2, Forearm = parent, UpperBaseRotation = parent2.localRotation, ForearmBaseRotation = parent.localRotation, Side = side }; } private void AnimateArm(ArmAnimation? arm, float idleWave, float reload, float recoil, bool right) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: 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) //IL_0080: 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_0096: 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_00d0: Unknown result type (might be due to invalid IL or missing references) if (arm != null && Object.op_Implicit((Object)(object)arm.UpperArm) && Object.op_Implicit((Object)(object)arm.Forearm)) { float num = idleWave * 2.5f; if (_isShooter) { float num2 = (right ? 67f : 72f); float num3 = (right ? 28f : 42f); arm.UpperArm.localRotation = arm.UpperBaseRotation * Quaternion.Euler(num3 - reload * 18f + recoil * 7f, 0f, arm.Side * num2 + num); arm.Forearm.localRotation = arm.ForearmBaseRotation * Quaternion.Euler(0f, arm.Side * (right ? 24f : 38f), arm.Side * (-54f + reload * 30f)); } else { arm.UpperArm.localRotation = arm.UpperBaseRotation * Quaternion.Euler(8f, 0f, arm.Side * (72f + num)); arm.Forearm.localRotation = arm.ForearmBaseRotation * Quaternion.Euler(0f, 0f, arm.Side * -42f); } } } } internal sealed class PirateCrewHealth : MonoBehaviour { private static readonly FieldInfo StartHealthField = AccessTools.Field(typeof(PlayerVitals), "_startHealth"); private static readonly FieldInfo PlayerDamageMultiplierField = AccessTools.Field(typeof(PlayerVitals), "_playerDamageMultiplier"); private Boat _boat; private Collider _hitbox; private Creature? _creature; private bool _isShooter; private int _crewIndex; private int _maxHealth; private float _playerDamageMultiplier; private bool _isCollectible; private bool _deathHandled; public bool Alive { get { if (!Object.op_Implicit((Object)(object)_creature)) { if (Object.op_Implicit((Object)(object)_boat)) { if (!_isShooter) { return _boat.BoatUnlocked; } return _boat.BoatRadarUnlocked; } return false; } return _creature._hp.Value > 0; } } public bool IsSecondCrewMember => _isShooter; public bool IsShooter => _isShooter; public int CrewIndex => _crewIndex; public bool IsAtHelm { get { if (!Alive) { return false; } if (!_isShooter) { return true; } PirateBoatController component = ((Component)_boat).GetComponent(); if (Object.op_Implicit((Object)(object)component) && !component.IsOutsideCirclingRange()) { return false; } PirateCrewHealth[] componentsInChildren = ((Component)_boat).GetComponentsInChildren(); foreach (PirateCrewHealth pirateCrewHealth in componentsInChildren) { if (pirateCrewHealth.Alive && (!pirateCrewHealth.IsShooter || pirateCrewHealth.CrewIndex < _crewIndex)) { return false; } } return true; } } public int MaxHealth => _maxHealth; public Collider Hitbox => _hitbox; public Creature? BoundCreature => _creature; public Boat Boat => _boat; public void Initialize(Boat boat, bool isShooter, Collider hitbox) { _boat = boat; _isShooter = isShooter; _hitbox = hitbox; PlayerVitals val = (Object.op_Implicit((Object)(object)GameInfo.PlayerPrefab) ? GameInfo.PlayerPrefab.Vitals : null); _maxHealth = (Object.op_Implicit((Object)(object)val) ? Mathf.Max(1, (int)StartHealthField.GetValue(val)) : 100); _playerDamageMultiplier = (Object.op_Implicit((Object)(object)val) ? Mathf.Max(0f, (float)PlayerDamageMultiplierField.GetValue(val)) : 0.25f); if (Object.op_Implicit((Object)(object)Server.Instance) && ((NetworkBehaviour)Server.Instance).IsServerInitialized) { PirateCollectibleSupport.SpawnLivingCreature(this); } } public void SetCrewIndex(int crewIndex) { _crewIndex = Mathf.Max(0, crewIndex); } public int ScalePlayerDamage(int damage) { return Mathf.Max(1, (int)((float)damage * _playerDamageMultiplier)); } public void AttachCreature(Creature creature) { _creature = creature; } public void HandleCreatureDeath() { if (_deathHandled) { return; } _deathHandled = true; if (Object.op_Implicit((Object)(object)Server.Instance) && ((NetworkBehaviour)Server.Instance).IsServerInitialized && Object.op_Implicit((Object)(object)_boat)) { if (_isShooter) { bool value = false; PirateCrewHealth[] componentsInChildren = ((Component)_boat).GetComponentsInChildren(); foreach (PirateCrewHealth pirateCrewHealth in componentsInChildren) { if ((Object)(object)pirateCrewHealth != (Object)(object)this && pirateCrewHealth.IsShooter && pirateCrewHealth.Alive) { value = true; break; } } _boat._boatRadarUnlocked.Value = value; } else { _boat._boatUnlocked.Value = false; } } string text = (_isShooter ? $"shooter {_crewIndex}" : "helmsman"); Plugin.Log.LogInfo((object)("A pirate boat lost its " + text + ".")); } public void ConvertToCollectible() { _isCollectible = true; if (Object.op_Implicit((Object)(object)_hitbox)) { _hitbox.enabled = false; } Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = true; } } private void OnDestroy() { if (!_isCollectible && Object.op_Implicit((Object)(object)_creature) && !((NetworkBehaviour)_creature).IsDeinitializing && Object.op_Implicit((Object)(object)Server.Instance) && ((NetworkBehaviour)Server.Instance).IsServerInitialized) { ((NetworkBehaviour)Server.Instance).Despawn(((Component)_creature).gameObject, (DespawnType?)null); } } } [DefaultExecutionOrder(2000)] internal sealed class PirateCrewPoseDriver : MonoBehaviour { private sealed class HandRig { public Transform Hand; public Transform Target; public Transform[] Fingers = Array.Empty(); public Quaternion[] FingerRotations = Array.Empty(); public IK Solver; } private static readonly MethodInfo ResolveIkMethod = AccessTools.Method(typeof(IK), "ResolveIK", new Type[1] { typeof(bool) }, (Type[])null); private HandRig? _right; private HandRig? _left; public void Initialize(Transform sourceSpace, Transform targetSpace, Transform? rightHand, Transform? leftHand, HandTransforms? rightPose, HandTransforms? leftPose, bool createFallbackWeaponPose = false) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) _right = CreateHandRig("Pirate Right Hand Target", sourceSpace, targetSpace, rightHand, rightPose); _left = CreateHandRig("Pirate Left Hand Target", sourceSpace, targetSpace, leftHand, leftPose); if (createFallbackWeaponPose) { if (_right == null) { _right = CreateFallbackHandRig("Pirate Right Hand Target", targetSpace, rightHand, new Vector3(0.18f, 0f, 0.04f)); } if (_left == null) { _left = CreateFallbackHandRig("Pirate Left Hand Target", targetSpace, leftHand, new Vector3(-0.14f, 0f, 0.18f)); } } } public void InitializeAnimatedWeaponTargets(Transform? rightHand, Transform? leftHand, Transform? rightTarget, Transform? leftTarget) { _right = CreateAnimatedHandRig(rightHand, rightTarget); _left = CreateAnimatedHandRig(leftHand, leftTarget); } private void LateUpdate() { UpdateHand(_right); UpdateHand(_left); } private static HandRig? CreateHandRig(string name, Transform sourceSpace, Transform targetSpace, Transform? hand, HandTransforms? pose) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)hand) || pose == null || !pose.Exists || !Object.op_Implicit((Object)(object)pose.Parent)) { return null; } Transform val = FindMatchingTransform(sourceSpace, targetSpace, pose.Parent); if (!Object.op_Implicit((Object)(object)val)) { return null; } GameObject val2 = new GameObject(name); val2.transform.SetParent(val, false); val2.transform.localPosition = pose.HandPos; val2.transform.localRotation = pose.HandRot; IK solver = AddIk(hand, val2.transform); return new HandRig { Hand = hand, Target = val2.transform, Fingers = FindFingers(hand), FingerRotations = (pose.FingerRots ?? Array.Empty()), Solver = solver }; } private static HandRig? CreateFallbackHandRig(string name, Transform targetSpace, Transform? hand, Vector3 localPosition) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)hand)) { return null; } GameObject val = new GameObject(name); val.transform.SetParent(targetSpace, false); val.transform.localPosition = localPosition; val.transform.localRotation = Quaternion.identity; IK solver = AddIk(hand, val.transform); return new HandRig { Hand = hand, Target = val.transform, Fingers = FindFingers(hand), Solver = solver }; } private static HandRig? CreateAnimatedHandRig(Transform? hand, Transform? target) { if (!Object.op_Implicit((Object)(object)hand) || !Object.op_Implicit((Object)(object)target)) { return null; } IK solver = AddIk(hand, target); return new HandRig { Hand = hand, Target = target, Fingers = FindFingers(hand), Solver = solver }; } private static IK AddIk(Transform hand, Transform target) { IK component = ((Component)hand).GetComponent(); bool num = !Object.op_Implicit((Object)(object)component); IK val = (Object.op_Implicit((Object)(object)component) ? component : ((Component)hand).gameObject.AddComponent()); Transform val2 = (num ? val.Target : null); val.Target = target; ((Behaviour)val).enabled = false; if (Object.op_Implicit((Object)(object)val2) && (Object)(object)val2 != (Object)(object)target) { Object.Destroy((Object)(object)((Component)val2).gameObject); } return val; } private static void UpdateHand(HandRig? rig) { //IL_0057: 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) if (rig == null || !Object.op_Implicit((Object)(object)rig.Hand) || !Object.op_Implicit((Object)(object)rig.Target)) { return; } if (Object.op_Implicit((Object)(object)rig.Solver)) { ResolveIkMethod.Invoke(rig.Solver, new object[1] { false }); } rig.Hand.rotation = rig.Target.rotation; int num = Mathf.Min(rig.Fingers.Length, rig.FingerRotations.Length); for (int i = 0; i < num; i++) { if (Object.op_Implicit((Object)(object)rig.Fingers[i])) { rig.Fingers[i].localRotation = rig.FingerRotations[i]; } } } private static Transform? FindMatchingTransform(Transform sourceRoot, Transform targetRoot, Transform source) { if ((Object)(object)source == (Object)(object)sourceRoot) { return targetRoot; } if (!source.IsChildOf(sourceRoot)) { return null; } List list = new List(); Transform val = source; while ((Object)(object)val != (Object)(object)sourceRoot) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return targetRoot.Find(string.Join("/", list)); } private static Transform[] FindFingers(Transform hand) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown List list = new List(); foreach (Transform item in hand) { Transform val = item; list.Add(val); if (val.childCount != 0) { Transform child = val.GetChild(0); list.Add(child); if (child.childCount > 0) { list.Add(child.GetChild(0)); } } } return list.ToArray(); } } internal sealed class PirateCrewRole : MonoBehaviour { private const float PositionChangeSpeed = 3f; private const float RotationChangeSpeed = 6f; private Boat _boat; private PirateCrewHealth _health; private Vector3 _driverLocalPosition; private Quaternion _driverLocalRotation; private Vector3 _passengerLocalPosition; private Quaternion _passengerLocalRotation; private PirateCrewAnimator? _animator; private PirateCrewPoseDriver? _helmPose; private PirateWeaponVisual? _weapon; private Vector3 _currentLocalPosition; private Quaternion _currentLocalRotation; private bool _isDriving; private bool _initialized; public void Initialize(Boat boat, PirateCrewHealth health, Vector3 driverLocalPosition, Quaternion driverLocalRotation, Vector3 passengerLocalPosition, Quaternion passengerLocalRotation, PirateCrewAnimator? animator, PirateCrewPoseDriver? helmPose, PirateWeaponVisual? weapon) { //IL_000f: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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) //IL_0020: 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_0028: Unknown result type (might be due to invalid IL or missing references) _boat = boat; _health = health; _driverLocalPosition = driverLocalPosition; _driverLocalRotation = driverLocalRotation; _passengerLocalPosition = passengerLocalPosition; _passengerLocalRotation = passengerLocalRotation; _animator = animator; _helmPose = helmPose; _weapon = weapon; ApplyRole(snapToPosition: true); _initialized = true; } private void Update() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) if (_initialized && Object.op_Implicit((Object)(object)_boat) && IsAlive()) { if (ShouldDrive() != _isDriving) { ApplyRole(snapToPosition: false); } Vector3 val = (_isDriving ? _driverLocalPosition : _passengerLocalPosition); Quaternion val2 = (_isDriving ? _driverLocalRotation : _passengerLocalRotation); _currentLocalPosition = Vector3.MoveTowards(_currentLocalPosition, val, 3f * Time.deltaTime); _currentLocalRotation = Quaternion.Slerp(_currentLocalRotation, val2, 6f * Time.deltaTime); ApplyCurrentPose(); } } private void ApplyRole(bool snapToPosition) { //IL_0070: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_0091: Unknown result type (might be due to invalid IL or missing references) _isDriving = ShouldDrive(); _animator?.SetArmed(!_isDriving); if (Object.op_Implicit((Object)(object)_helmPose)) { ((Behaviour)_helmPose).enabled = _isDriving; } _weapon?.SetDriving(_isDriving); if (snapToPosition) { _currentLocalPosition = (_isDriving ? _driverLocalPosition : _passengerLocalPosition); _currentLocalRotation = (_isDriving ? _driverLocalRotation : _passengerLocalRotation); ApplyCurrentPose(); } } private void ApplyCurrentPose() { //IL_002c: 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_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_animator)) { _animator.SetBasePose(_currentLocalPosition, _currentLocalRotation); return; } ((Component)this).transform.localPosition = _currentLocalPosition; ((Component)this).transform.localRotation = _currentLocalRotation; } private bool IsAlive() { if (Object.op_Implicit((Object)(object)_health)) { return _health.Alive; } return false; } private bool ShouldDrive() { return _health.IsAtHelm; } } internal static class PirateProjectileSupport { private const uint FirstPirateProjectileId = 3000000000u; private static uint _nextProjectileId = 3000000000u; public static uint AllocateIds(int count) { uint num = (uint)Math.Max(1, count); if (_nextProjectileId > (uint)(-1 - (int)num)) { _nextProjectileId = 3000000000u; } uint nextProjectileId = _nextProjectileId; _nextProjectileId += num; return nextProjectileId; } public static bool IsPirateProjectile(WeaponInfo weaponInfo, bool isLocal, uint id) { if (!isLocal && id >= 3000000000u && weaponInfo != null) { return !Object.op_Implicit((Object)(object)weaponInfo.Weapon); } return false; } } internal static class PirateRagdoll { private static readonly FieldInfo DeadPlayerBodyRendererField = AccessTools.Field(typeof(DeadPlayer), "_bodyRenderer"); private static readonly FieldInfo DeadPlayerLeftHandRendererField = AccessTools.Field(typeof(DeadPlayer), "_leftHand"); private static readonly FieldInfo DeadPlayerRightHandRendererField = AccessTools.Field(typeof(DeadPlayer), "_rightHand"); private static readonly FieldInfo ItemWorldCollidersField = AccessTools.Field(typeof(Item), "_worldColliders"); private static readonly FieldInfo ItemExtraRigsField = AccessTools.Field(typeof(Item), "_extraRigs"); private static readonly FieldInfo ItemPickupColliderField = AccessTools.Field(typeof(Item), "_pickUpCollider"); private static readonly FieldInfo RigidbodySyncExtraHingesField = AccessTools.Field(typeof(RigidbodySync), "_extraHinges"); private static readonly FieldInfo RigidbodySyncHingeDirectionField = AccessTools.Field(typeof(RigidbodySync), "_hingeDirection"); private static readonly FieldInfo RigidbodySyncServerHingeAnglesField = AccessTools.Field(typeof(RigidbodySync), "_serverExtraHingeAngles"); private static readonly FieldInfo RigidbodySyncServerHingeRotationsField = AccessTools.Field(typeof(RigidbodySync), "_serverExtraHingeRots"); public static Rigidbody[] Enable(PirateCrewHealth pirate, Creature creature) { //IL_001c: 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_0054: 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_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) DeadPlayer deadPlayerPrefab = GameInfo.DeadPlayerPrefab; SkinnedMeshRenderer val = ((!Object.op_Implicit((Object)(object)deadPlayerPrefab)) ? ((SkinnedMeshRenderer)null) : ((SkinnedMeshRenderer)DeadPlayerBodyRendererField.GetValue(deadPlayerPrefab))); SkinnedMeshRenderer templateHand = ((!Object.op_Implicit((Object)(object)deadPlayerPrefab)) ? ((SkinnedMeshRenderer)null) : ((SkinnedMeshRenderer)DeadPlayerLeftHandRendererField.GetValue(deadPlayerPrefab))); SkinnedMeshRenderer templateHand2 = ((!Object.op_Implicit((Object)(object)deadPlayerPrefab)) ? ((SkinnedMeshRenderer)null) : ((SkinnedMeshRenderer)DeadPlayerRightHandRendererField.GetValue(deadPlayerPrefab))); SkinnedMeshRenderer componentInChildren = ((Component)pirate).GetComponentInChildren(true); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.rootBone) || !Object.op_Implicit((Object)(object)componentInChildren) || !Object.op_Implicit((Object)(object)componentInChildren.rootBone)) { Plugin.Log.LogWarning((object)("Could not create the native player ragdoll for " + PirateCollectibleSupport.GetRoleName(pirate) + ".")); return (Rigidbody[])(object)new Rigidbody[0]; } Transform rootBone = componentInChildren.rootBone; Transform transform = Object.Instantiate(((Component)val.rootBone).gameObject).transform; ((Object)transform).name = ((Object)val.rootBone).name; Rigidbody[] componentsInChildren = ((Component)transform).GetComponentsInChildren(true); Rigidbody[] array = componentsInChildren; for (int i = 0; i < array.Length; i++) { array[i].isKinematic = true; } MonoBehaviour[] componentsInChildren2 = ((Component)transform).GetComponentsInChildren(true); foreach (MonoBehaviour val2 in componentsInChildren2) { if (!(val2 is ItemExtraRigidbody)) { Object.Destroy((Object)(object)val2); } } transform.SetParent(rootBone.parent, false); transform.localPosition = rootBone.localPosition; transform.localRotation = rootBone.localRotation; transform.localScale = rootBone.localScale; CopyPose(rootBone, transform); if (!RetargetRenderers(pirate, rootBone, transform)) { Object.Destroy((Object)(object)((Component)transform).gameObject); Plugin.Log.LogWarning((object)"Kept the original pirate skeleton because the ragdoll bone mapping was incomplete."); return (Rigidbody[])(object)new Rigidbody[0]; } ReplaceHandRenderer(pirate, rootBone, transform, val.rootBone, templateHand); ReplaceHandRenderer(pirate, rootBone, transform, val.rootBone, templateHand2); RegisterItemPhysics(creature, transform, componentsInChildren); Rigidbody component = ((Component)creature).GetComponent(); Joint[] componentsInChildren3 = ((Component)transform).GetComponentsInChildren(true); foreach (Joint val3 in componentsInChildren3) { if (Object.op_Implicit((Object)(object)val3.connectedBody) && !((Component)val3.connectedBody).transform.IsChildOf(transform)) { val3.connectedBody = component; } } Object.Destroy((Object)(object)((Component)rootBone).gameObject); Plugin.Log.LogDebug((object)("Enabled native player-style ragdoll for " + PirateCollectibleSupport.GetRoleName(pirate) + ".")); return componentsInChildren; } public static void ResetSpawnMotion(Creature creature, Rigidbody[] ragdollBodies) { //IL_0010: 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_002f: 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) Rigidbody component = ((Component)creature).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.linearVelocity = Vector3.zero; component.angularVelocity = Vector3.zero; } foreach (Rigidbody obj in ragdollBodies) { obj.linearVelocity = Vector3.zero; obj.angularVelocity = Vector3.zero; } Plugin.Log.LogDebug((object)"Spawned pirate corpse with zero relative velocity for boat carrying."); } private static void RegisterItemPhysics(Creature creature, Transform skeleton, Rigidbody[] ragdollBodies) { //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown Collider[] componentsInChildren = ((Component)skeleton).GetComponentsInChildren(true); Collider[] array = AppendUnique((Collider[])ItemWorldCollidersField.GetValue(creature), componentsInChildren); ItemWorldCollidersField.SetValue(creature, array); ItemExtraRigidbody[] componentsInChildren2 = ((Component)skeleton).GetComponentsInChildren(true); ItemExtraRigidbody[] array2 = componentsInChildren2; for (int i = 0; i < array2.Length; i++) { array2[i].SetItem((Item)(object)creature); } ItemExtraRigidbody[] existing = (ItemExtraRigidbody[])ItemExtraRigsField.GetValue(creature); ItemExtraRigsField.SetValue(creature, AppendUnique(existing, componentsInChildren2)); Rigidbody[] array3 = AppendUnique((Rigidbody[])RigidbodySyncExtraHingesField.GetValue(((Item)creature).RigidbodySync), ragdollBodies); RigidbodySyncExtraHingesField.SetValue(((Item)creature).RigidbodySync, array3); RigidbodySyncServerHingeAnglesField.SetValue(((Item)creature).RigidbodySync, new float[array3.Length]); RigidbodySyncServerHingeRotationsField.SetValue(((Item)creature).RigidbodySync, new Quaternion[array3.Length]); RigidbodySyncHingeDirectionField.SetValue(((Item)creature).RigidbodySync, Enum.ToObject(RigidbodySyncHingeDirectionField.FieldType, 3)); int layer = LayerMask.NameToLayer(Object.op_Implicit((Object)(object)((Item)creature).Holder) ? "ItemInHand" : "ItemPart"); Collider[] array4 = componentsInChildren; for (int i = 0; i < array4.Length; i++) { ((Component)array4[i]).gameObject.layer = layer; } Collider val = (Collider)ItemPickupColliderField.GetValue(creature); ItemManager.Add((Item)(object)creature, val, array); } private static T[] AppendUnique(T[] existing, T[] additions) where T : Object { List list = new List(existing.Length + additions.Length); T[] array = existing; foreach (T val in array) { if (Object.op_Implicit((Object)(object)val) && !list.Contains(val)) { list.Add(val); } } array = additions; foreach (T val2 in array) { if (Object.op_Implicit((Object)(object)val2) && !list.Contains(val2)) { list.Add(val2); } } return list.ToArray(); } private static void CopyPose(Transform sourceRoot, Transform destinationRoot) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) Transform[] componentsInChildren = ((Component)sourceRoot).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { Transform val2 = FindEquivalent(val, sourceRoot, destinationRoot); if (Object.op_Implicit((Object)(object)val2)) { val2.localPosition = val.localPosition; val2.localRotation = val.localRotation; val2.localScale = val.localScale; } } } private static bool RetargetRenderers(PirateCrewHealth pirate, Transform sourceRoot, Transform destinationRoot) { Dictionary dictionary = new Dictionary(); SkinnedMeshRenderer[] componentsInChildren = ((Component)pirate).GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val in componentsInChildren) { Transform[] bones = val.bones; foreach (Transform val2 in bones) { if (Object.op_Implicit((Object)(object)val2) && (!((Object)(object)val2 != (Object)(object)sourceRoot) || val2.IsChildOf(sourceRoot))) { Transform val3 = FindEquivalent(val2, sourceRoot, destinationRoot); if (!Object.op_Implicit((Object)(object)val3)) { return false; } dictionary[val2] = val3; } } if (Object.op_Implicit((Object)(object)val.rootBone) && ((Object)(object)val.rootBone == (Object)(object)sourceRoot || val.rootBone.IsChildOf(sourceRoot))) { Transform val4 = FindEquivalent(val.rootBone, sourceRoot, destinationRoot); if (!Object.op_Implicit((Object)(object)val4)) { return false; } dictionary[val.rootBone] = val4; } } componentsInChildren = ((Component)pirate).GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val5 in componentsInChildren) { Transform[] bones2 = val5.bones; for (int k = 0; k < bones2.Length; k++) { if (Object.op_Implicit((Object)(object)bones2[k]) && dictionary.TryGetValue(bones2[k], out var value)) { bones2[k] = value; } } val5.bones = bones2; if (Object.op_Implicit((Object)(object)val5.rootBone) && dictionary.TryGetValue(val5.rootBone, out var value2)) { val5.rootBone = value2; } } return true; } private static void ReplaceHandRenderer(PirateCrewHealth pirate, Transform sourceRoot, Transform destinationRoot, Transform templateRoot, SkinnedMeshRenderer templateHand) { if (!Object.op_Implicit((Object)(object)templateHand) || !((Component)templateHand).transform.IsChildOf(templateRoot)) { return; } Transform val = destinationRoot.Find(GetRelativePath(templateRoot, ((Component)templateHand).transform)); SkinnedMeshRenderer val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent() : null); if (!Object.op_Implicit((Object)(object)val2)) { Plugin.Log.LogWarning((object)("The native ragdoll " + ((Object)templateHand).name + " renderer was unavailable.")); return; } SkinnedMeshRenderer[] componentsInChildren = ((Component)pirate).GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val3 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val3) && !((Object)(object)val3 == (Object)(object)val2) && !(((Object)((Component)val3).gameObject).name != ((Object)((Component)templateHand).gameObject).name) && !((Object)(object)((Component)val3).transform == (Object)(object)sourceRoot) && !((Component)val3).transform.IsChildOf(sourceRoot) && !((Object)(object)((Component)val3).transform == (Object)(object)destinationRoot) && !((Component)val3).transform.IsChildOf(destinationRoot)) { ((Renderer)val2).sharedMaterials = ((Renderer)val3).sharedMaterials; ((Renderer)val2).enabled = true; ((Component)val3).gameObject.SetActive(false); ((Component)val3).transform.SetParent((Transform)null, false); Object.Destroy((Object)(object)((Component)val3).gameObject); break; } } } private static Transform? FindEquivalent(Transform source, Transform sourceRoot, Transform destinationRoot) { if (!Object.op_Implicit((Object)(object)source)) { return null; } if ((Object)(object)source == (Object)(object)sourceRoot) { return destinationRoot; } string relativePath = GetRelativePath(sourceRoot, source); Transform val = destinationRoot.Find(relativePath); if (!Object.op_Implicit((Object)(object)val)) { return FindByName(destinationRoot, ((Object)source).name); } return val; } private static string GetRelativePath(Transform root, Transform child) { List list = new List(); Transform val = child; while (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)root) { list.Add(((Object)val).name); val = val.parent; } list.Reverse(); return string.Join("/", list); } private static Transform? FindByName(Transform root, string name) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown foreach (Transform item in root) { Transform val = item; if (((Object)val).name == name) { return val; } Transform val2 = FindByName(val, name); if (Object.op_Implicit((Object)(object)val2)) { return val2; } } return null; } } internal sealed class PirateWeaponDefinition { private static readonly FieldInfo WeaponInfoField = AccessTools.Field(typeof(Weapon), "_weaponInfo"); private static readonly FieldInfo ProjectileSpeedField = AccessTools.Field(typeof(Weapon), "_projSpeed"); private static readonly FieldInfo SpreadField = AccessTools.Field(typeof(Weapon), "_spread"); private static readonly FieldInfo ProjectileCountField = AccessTools.Field(typeof(Weapon), "_projectileCountPerShot"); private static readonly FieldInfo TimeBetweenShotsField = AccessTools.Field(typeof(Weapon), "_timeBetweenShots"); private static readonly FieldInfo AnimationField = AccessTools.Field(typeof(Tool), "_anim"); private static readonly FieldInfo HasLastReloadAnimationField = AccessTools.Field(typeof(Weapon), "_hasLastReloadAnim"); public string Name { get; } public WeaponInfo Projectile { get; } public float ProjectileSpeed { get; } public float Spread { get; } public int ProjectileCount { get; } public float FireInterval { get; } public float AttackRange { get; } public Attachments Attachments { get; } public Weapon VisualSource { get; } public int MagazineSize { get; } public float ReloadDuration { get; } public float EmptyReloadDuration { get; } private PirateWeaponDefinition(string name, WeaponInfo projectile, float projectileSpeed, float spread, int projectileCount, float fireInterval, float attackRange, Attachments attachments, Weapon visualSource, int magazineSize, float reloadDuration, float emptyReloadDuration) { Name = name; Projectile = projectile; ProjectileSpeed = projectileSpeed; Spread = spread; ProjectileCount = projectileCount; FireInterval = fireInterval; AttackRange = attackRange; Attachments = attachments; VisualSource = visualSource; MagazineSize = magazineSize; ReloadDuration = reloadDuration; EmptyReloadDuration = emptyReloadDuration; } public static PirateWeaponDefinition FromWeapon(Weapon weapon) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_007a: 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_0086: 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_009e: 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_00b6: 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_00d0: Expected O, but got Unknown //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown WeaponInfo val = (WeaponInfo)WeaponInfoField.GetValue(weapon); float projectileSpeed = Math.Max(1f, (float)ProjectileSpeedField.GetValue(weapon)); float num = Math.Max(0f, (float)SpreadField.GetValue(weapon)); int projectileCount = Math.Max(1, (int)ProjectileCountField.GetValue(weapon)); float fireInterval = Math.Max(0.1f, (float)TimeBetweenShotsField.GetValue(weapon)); WeaponInfo projectile = new WeaponInfo { Weapon = null, ProjectileType = val.ProjectileType, ProjectileDamage = weapon.Damage, ProjectileForce = val.ProjectileForce, ProjectileGravity = val.ProjectileGravity, ShootVFX = val.ShootVFX, BoatForceOverride = val.BoatForceOverride }; float attackRange = Mathf.Clamp(70f - num * 2f, 18f, 70f); Animation animation = (Animation)AnimationField.GetValue(weapon); float animationDuration = GetAnimationDuration(animation, "Reload", 1.8f); float emptyReloadDuration = (((bool)HasLastReloadAnimationField.GetValue(weapon)) ? GetAnimationDuration(animation, "ReloadLast", animationDuration) : animationDuration); return new PirateWeaponDefinition(((Object)weapon).name, projectile, projectileSpeed, num, projectileCount, fireInterval, attackRange, weapon.Attachments, weapon, Math.Max(1, weapon.Attachments.AmmoPerMag), animationDuration, emptyReloadDuration); } private static float GetAnimationDuration(Animation animation, string stateName, float fallback) { if (!Object.op_Implicit((Object)(object)animation)) { return fallback; } AnimationState val = animation[stateName]; if (!((TrackedReference)(object)val != (TrackedReference)null) || !(val.length > 0f)) { return fallback; } return val.length; } } internal sealed class PirateWeaponVisual : MonoBehaviour { private static readonly Vector3 HipFireOffset = new Vector3(0.22f, -0.3f, 0.32f); private const float HipFirePitch = 10f; private Boat _boat; private ParticleSystem[] _particles = Array.Empty(); private Renderer[] _renderers = Array.Empty(); private Renderer[] _crewHandRenderers = Array.Empty(); private Vector3 _heldPosition; private Quaternion _heldRotation; private float _recoil; private float _reloadStart = -1f; private float _reloadDuration; private Transform? _muzzle; private PirateCrewPoseDriver? _handPose; private Animation? _animation; private bool _isDriving; public bool CanFire { get { if (!_isDriving) { return ((Behaviour)this).isActiveAndEnabled; } return false; } } public Vector3 GetMuzzlePosition(Vector3 targetPosition) { //IL_0004: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_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) bool flag = false; Bounds val = default(Bounds); Renderer[] renderers = _renderers; foreach (Renderer val2 in renderers) { if (Object.op_Implicit((Object)(object)val2) && val2.enabled) { if (!flag) { val = val2.bounds; flag = true; } else { ((Bounds)(ref val)).Encapsulate(val2.bounds); } } } if (Object.op_Implicit((Object)(object)_muzzle) && (!flag || ((Bounds)(ref val)).SqrDistance(_muzzle.position) <= 0.25f)) { return _muzzle.position; } if (!flag) { return ((Component)this).transform.position; } Vector3 val3 = targetPosition - ((Bounds)(ref val)).center; Vector3 normalized = ((Vector3)(ref val3)).normalized; Vector3 extents = ((Bounds)(ref val)).extents; float num = Mathf.Abs(normalized.x) * extents.x + Mathf.Abs(normalized.y) * extents.y + Mathf.Abs(normalized.z) * extents.z; return ((Bounds)(ref val)).center + normalized * num; } public void Initialize(Boat boat, GameObject model, Transform? muzzle, PirateCrewPoseDriver? handPose, Renderer[] crewHandRenderers) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //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) _boat = boat; _particles = model.GetComponentsInChildren(true); _renderers = model.GetComponentsInChildren(true); _crewHandRenderers = crewHandRenderers; _heldPosition = ((Component)this).transform.localPosition; _heldRotation = ((Component)this).transform.localRotation; _muzzle = muzzle; _handPose = handPose; _animation = model.GetComponentInChildren(true); PlayAnimation("Idle"); } public void SetDriving(bool driving) { _isDriving = driving; Renderer[] renderers = _renderers; foreach (Renderer val in renderers) { if (Object.op_Implicit((Object)(object)val)) { val.enabled = !driving; } } renderers = _crewHandRenderers; foreach (Renderer val2 in renderers) { if (Object.op_Implicit((Object)(object)val2)) { val2.enabled = driving; } } if (Object.op_Implicit((Object)(object)_handPose)) { ((Behaviour)_handPose).enabled = !driving; } if (driving) { _recoil = 0f; _reloadStart = -1f; } } public void PrepareForCorpse() { Renderer[] renderers = _renderers; foreach (Renderer val in renderers) { if (Object.op_Implicit((Object)(object)val)) { val.enabled = false; } } renderers = _crewHandRenderers; foreach (Renderer val2 in renderers) { if (Object.op_Implicit((Object)(object)val2)) { val2.enabled = true; } } ParticleSystem[] particles = _particles; foreach (ParticleSystem val3 in particles) { if (Object.op_Implicit((Object)(object)val3)) { val3.Stop(true, (ParticleSystemStopBehavior)0); } } if (Object.op_Implicit((Object)(object)_animation)) { _animation.Stop(); } if (Object.op_Implicit((Object)(object)_handPose)) { ((Behaviour)_handPose).enabled = false; } ((Behaviour)this).enabled = false; ((Component)this).gameObject.SetActive(false); } public void Fire() { _recoil = 1f; PlayAnimation("Fire"); ParticleSystem[] particles = _particles; for (int i = 0; i < particles.Length; i++) { particles[i].Play(); } } public void Reload(float duration) { _reloadStart = Time.time; _reloadDuration = Mathf.Max(0.1f, duration); PlayAnimation("ReloadLast", "Reload"); } private void Update() { //IL_0088: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: 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) if (!Object.op_Implicit((Object)(object)_boat) || _isDriving) { return; } _recoil = Mathf.MoveTowards(_recoil, 0f, Time.deltaTime * 8f); float num = 0f; if (_reloadStart >= 0f) { float num2 = (Time.time - _reloadStart) / _reloadDuration; if (num2 >= 1f) { _reloadStart = -1f; } else { num = Mathf.Sin(num2 * MathF.PI); } } ((Component)this).transform.localPosition = _heldPosition + HipFireOffset + Vector3.down * (num * 0.04f) + Vector3.back * (_recoil * 0.04f); ((Component)this).transform.localRotation = _heldRotation * Quaternion.Euler(10f - num * 4f + _recoil * 4f, 0f, 0f); if (Object.op_Implicit((Object)(object)_animation) && !_animation.isPlaying) { PlayAnimation("Idle"); } } private void PlayAnimation(string preferred, string? fallback = null) { if (Object.op_Implicit((Object)(object)_animation)) { if ((TrackedReference)(object)_animation[preferred] != (TrackedReference)null) { _animation.Play(preferred); } else if (fallback != null && (TrackedReference)(object)_animation[fallback] != (TrackedReference)null) { _animation.Play(fallback); } } } } } namespace HowToFish.OpenSea.Patches { [HarmonyPatch(typeof(Boat), "OnStartClient")] internal static class PirateBoatStartClientPatch { private static void Prefix(Boat __instance, out Boat? __state) { Boat boat = BoatManager.Boat; __state = ((Object.op_Implicit((Object)(object)boat) && (Object)(object)boat != (Object)(object)__instance) ? boat : null); if (Object.op_Implicit((Object)(object)__state)) { PirateBoatSupport.IdentifyClientPirate(__instance); } } private static void Postfix(Boat __instance, Boat? __state) { if (Object.op_Implicit((Object)(object)__state)) { PirateBoatSupport.ConfigureClientPirate(__instance, __state); } } } [HarmonyPatch(typeof(Boat), "OnStartServer")] internal static class PirateBoatStartServerPatch { private static void Postfix(Boat __instance) { PirateBoatSupport.ApplyServerPirateDefaults(__instance); } } [HarmonyPatch(typeof(Boat), "OnSkinChange")] internal static class PirateBoatSkinPatch { private static bool Prefix(Boat __instance, byte next) { return PirateBoatSupport.ShouldApplyBoatSkin(__instance, next); } } [HarmonyPatch(typeof(Boat), "OnMotorChange")] internal static class PirateBoatMotorAchievementScopePatch { private static void Prefix(Boat __instance, out bool __state) { __state = PirateBoatSupport.BeginPirateMotorChange(__instance); } private static void Postfix(bool __state) { if (__state) { PirateBoatSupport.EndPirateMotorChange(); } } } [HarmonyPatch(typeof(AchievementManager), "CheckBoatUpgradeAchievement")] internal static class PirateBoatMotorAchievementPatch { private static bool Prefix() { return !PirateBoatSupport.IsApplyingPirateMotor; } } [HarmonyPatch(typeof(Boat), "OnStopClient")] internal static class PirateBoatStopClientPatch { private static void Prefix(Boat __instance, out Boat? __state) { Boat boat = BoatManager.Boat; __state = ((Object.op_Implicit((Object)(object)boat) && (Object)(object)boat != (Object)(object)__instance) ? boat : null); } private static void Postfix(Boat __instance, Boat? __state) { PirateBoatSupport.UnregisterServerPirate(__instance); if (Object.op_Implicit((Object)(object)__state)) { PirateBoatSupport.RestoreMainBoat(__state); } } } [HarmonyPatch(typeof(Boat), "ApplyReturnForce")] internal static class PirateBoatReturnForcePatch { private static bool Prefix(Boat __instance) { return !PirateBoatSupport.IsServerPirate(__instance); } } [HarmonyPatch(typeof(Boat), "ApplyInputForce")] internal static class PirateBoatInputForcePatch { private static bool Prefix(Boat __instance) { if (!PirateBoatSupport.IsServerPirate(__instance)) { return true; } PirateBoatController component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.ApplyNativeInputForce(); } return false; } } [HarmonyPatch(typeof(Boat), "ApplyWaterForce")] internal static class PirateBoatWaterForcePatch { private static bool Prefix(Boat __instance) { PirateBoatController component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.IsSinking) { component.ReduceNativeBuoyancy(); } return true; } } [HarmonyPatch(typeof(BoatTrigger), "TellPlayerTheyAreOnBoat")] internal static class PirateBoatTriggerPlayerPatch { private struct RideTransition { public Boat? PreviousBoat; public Boat? PirateBoat; public bool Switched; public bool Leaving; } private static readonly FieldInfo LocalPlayerOnBoatField = AccessTools.Field(typeof(BoatTrigger), "_localPlayerOnBoat"); private static readonly FieldInfo OldLocalPlayerOnBoatField = AccessTools.Field(typeof(BoatTrigger), "_oldLocalPlayerOnBoat"); private static void Prefix(BoatTrigger __instance, out RideTransition __state) { __state = default(RideTransition); if (!PirateBoatSupport.TryGetPirateBoat(__instance, out Boat boat)) { return; } bool flag = (bool)LocalPlayerOnBoatField.GetValue(__instance); bool flag2 = (bool)OldLocalPlayerOnBoatField.GetValue(__instance); if (flag != flag2) { if (flag) { PirateBoatSupport.BeginLocalPirateRide(boat); } __state.PreviousBoat = BoatManager.Boat; __state.PirateBoat = boat; __state.Switched = true; __state.Leaving = !flag; PirateBoatSupport.SelectPirateBoatForLocalPlayer(boat); } } private static void Postfix(RideTransition __state) { if (__state.Switched) { if (__state.Leaving && Object.op_Implicit((Object)(object)__state.PirateBoat)) { PirateBoatSupport.EndLocalPirateRide(__state.PirateBoat); } PirateBoatSupport.RestoreBoatSelection(__state.PreviousBoat); } } } [HarmonyPatch(typeof(PlayerMovement), "FixedUpdate")] internal static class PirateBoatPlayerMovementPatch { private static void Prefix(PlayerMovement __instance, out Boat? __state) { __state = null; if (Object.op_Implicit((Object)(object)Player.LocalPlayer) && (Object)(object)__instance == (Object)(object)Player.LocalPlayer.Movement) { PirateBoatSupport.SelectLocalRiddenPirate(out __state); } } private static void Postfix(Boat? __state) { if (Object.op_Implicit((Object)(object)__state)) { PirateBoatSupport.RestoreBoatSelection(__state); } } } [HarmonyPatch(typeof(PlayerMovement), "AddBoatPos")] internal static class PirateBoatPlayerCarryPatch { private static void Prefix(PlayerMovement __instance, out Boat? __state) { __state = null; if (Object.op_Implicit((Object)(object)Player.LocalPlayer) && (Object)(object)__instance == (Object)(object)Player.LocalPlayer.Movement) { PirateBoatSupport.SelectLocalRiddenPirate(out __state); } } private static void Postfix(Boat? __state) { if (Object.op_Implicit((Object)(object)__state)) { PirateBoatSupport.RestoreBoatSelection(__state); } } } [HarmonyPatch(typeof(Boat), "GiveBoatDeltaToPlayerAndItems")] internal static class PirateBoatItemCarryPatch { private static void Prefix(Boat __instance, out Boat? __state) { __state = null; if (PirateBoatSupport.IsPirateBoat(__instance)) { __state = BoatManager.Boat; PirateBoatSupport.SelectPirateBoatForLocalPlayer(__instance); } } private static void Postfix(Boat __instance, Boat? __state) { if (PirateBoatSupport.IsPirateBoat(__instance)) { PirateBoatSupport.RestoreBoatSelection(__state); } } } [HarmonyPatch(typeof(Player), "TickUpdate")] internal static class PirateBoatLocalPlayerNetworkPositionPatch { private static void Prefix(Player __instance, out Boat? __state) { __state = null; if (Object.op_Implicit((Object)(object)Player.LocalPlayer) && (Object)(object)__instance == (Object)(object)Player.LocalPlayer) { PirateBoatSupport.SelectLocalRiddenPirate(out __state); } } private static void Postfix(Boat? __state) { if (Object.op_Implicit((Object)(object)__state)) { PirateBoatSupport.RestoreBoatSelection(__state); } } } [HarmonyPatch(typeof(Boat), "SetLocalPlayerOnBoat")] internal static class PirateBoatInteractionStatePatch { private static void Postfix(Boat __instance) { if (PirateBoatSupport.IsPirateBoat(__instance)) { PirateBoatSupport.DisableDrivingInteraction(__instance); } } } [HarmonyPatch(typeof(BoatInteractable), "Interact")] internal static class PirateBoatDriveInteractionPatch { private static bool Prefix(BoatInteractable __instance) { return !PirateBoatSupport.IsPirateBoat(((Component)__instance).GetComponentInParent()); } } [HarmonyPatch] internal static class PirateBoatMeleeTargetPatch { private static readonly FieldInfo PunchPlayerField = AccessTools.Field(typeof(PlayerPunching), "_player"); private static readonly FieldInfo PunchRangeField = AccessTools.Field(typeof(PlayerPunching), "_range"); private static readonly FieldInfo MeleeHolderField = AccessTools.Field(typeof(Item), "_holder"); private static readonly FieldInfo MeleeRangeField = AccessTools.Field(typeof(Melee), "_range"); private static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(PlayerPunching), "CheckForPlayersAndLevel", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Melee), "CheckForPlayersAndLevel", (Type[])null, (Type[])null); } private static void Postfix(object __instance, ref Transform finalTarget, ref Vector3 finalHitPoint) { //IL_001b: 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_0025: 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_0058: 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) //IL_005e: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: 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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)finalTarget) || !((Component)finalTarget).CompareTag("Boat")) { return; } Vector3 val = finalTarget.TransformPoint(finalHitPoint); if (PirateBoatSupport.TryGetPirateBoatAtPoint(val, out Boat boat)) { Player val2 = ((__instance is PlayerPunching) ? ((Player)PunchPlayerField.GetValue(__instance)) : ((Player)MeleeHolderField.GetValue(__instance))); float maxDistance = ((__instance is PlayerPunching) ? ((float)PunchRangeField.GetValue(__instance)) : ((float)MeleeRangeField.GetValue(__instance))); if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.CamObject) && PirateBoatSupport.TryGetLivingPirateHit(boat, new Ray(val2.CamObject.position, val2.CamObject.forward), maxDistance, 0f, out var pirateHit)) { finalTarget = ((RaycastHit)(ref pirateHit)).transform; finalHitPoint = finalTarget.InverseTransformPoint(((RaycastHit)(ref pirateHit)).point); } else { finalTarget = boat.VisualBoat; finalHitPoint = finalTarget.InverseTransformPoint(val); } } } } [HarmonyPatch] internal static class PirateBoatMeleeForcePatch { private static readonly FieldInfo PunchTargetsField = AccessTools.Field(typeof(PlayerPunching), "_curTarget"); private static readonly FieldInfo MeleeTargetsField = AccessTools.Field(typeof(Melee), "_curTarget"); private static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(PlayerPunching), "HitTarget", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Melee), "HitTarget", (Type[])null, (Type[])null); } private static void Prefix(object __instance, int side, out Boat? __state) { __state = null; Transform[] array = (Transform[])((__instance is PlayerPunching) ? PunchTargetsField : MeleeTargetsField).GetValue(__instance); if (side >= 0 && side < array.Length && PirateBoatSupport.TryGetPirateBoat(array[side], out Boat boat)) { __state = BoatManager.Boat; PirateBoatSupport.SelectPirateBoatForLocalPlayer(boat); } } private static void Postfix(Boat? __state) { if (Object.op_Implicit((Object)(object)__state)) { PirateBoatSupport.RestoreBoatSelection(__state); } } } [HarmonyPatch(typeof(ProjectileManager), "Hit")] internal static class PirateBoatProjectileForcePatch { private static void Prefix(RaycastHit hit, out Boat? __state) { __state = null; if (PirateBoatSupport.TryGetPirateBoat(((RaycastHit)(ref hit)).transform, out Boat boat)) { __state = BoatManager.Boat; PirateBoatSupport.SelectPirateBoatForLocalPlayer(boat); } } private static void Postfix(Boat? __state) { if (Object.op_Implicit((Object)(object)__state)) { PirateBoatSupport.RestoreBoatSelection(__state); } } } [HarmonyPatch(typeof(ProjectileManager), "Hit")] [HarmonyPriority(800)] internal static class PirateCrewProjectileOcclusionPatch { private const float MaximumHullTraversalDistance = 12f; private static void Prefix(Projectile projectile, ProjectileType type, ref RaycastHit hit) { //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) //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) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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) if (projectile.FromNpc || !Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).collider)) { return; } Boat boat; Boat val = (PirateBoatSupport.TryGetPirateBoat(((RaycastHit)(ref hit)).transform, out boat) ? boat : null); if (!Object.op_Implicit((Object)(object)val) && !((Component)((RaycastHit)(ref hit)).transform).CompareTag("Boat")) { return; } Vector3 normalized = ((Vector3)(ref projectile.Velocity)).normalized; if (!(((Vector3)(ref normalized)).sqrMagnitude <= 0.001f)) { Ray ray = default(Ray); ((Ray)(ref ray))..ctor(projectile.Position, normalized); float maxDistance = ((RaycastHit)(ref hit)).distance + 12f; if (PirateBoatSupport.TryGetLivingPirateHit(val, ray, maxDistance, type.WidthRadius, out var pirateHit)) { hit = pirateHit; } } } } [HarmonyPatch(typeof(CreatureManager), "AddAliveCreature")] internal static class PirateCreatureManagerRegistrationPatch { private static bool Prefix(Creature creature) { return !Object.op_Implicit((Object)(object)((Component)creature).GetComponent()); } } [HarmonyPatch(typeof(Creature), "OnStartClient")] internal static class PirateCollectibleStartClientPatch { private static void Prefix(Creature __instance, out PirateCrewHealth? __state) { __state = PirateCollectibleSupport.FindMatchingPirate(__instance); if (Object.op_Implicit((Object)(object)__state)) { PirateCollectibleSupport.Prepare(__instance, __state); } } private static void Postfix(Creature __instance, PirateCrewHealth? __state) { if (Object.op_Implicit((Object)(object)__state)) { PirateCollectibleSupport.BindLivingCreature(__instance, __state); } } } [HarmonyPatch(typeof(Creature), "ServerChangeHp")] internal static class PirateCreatureServerDeathPatch { private static void Postfix(Creature __instance) { PirateCreatureLink component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.TryAdoptIfDead(); } } } [HarmonyPatch(typeof(Creature), "OnHealthChange")] internal static class PirateCreatureObservedDeathPatch { private static void Postfix(Creature __instance) { PirateCreatureLink component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.TryAdoptIfDead(); } } } [HarmonyPatch(typeof(Item), "GetName")] internal static class PirateCollectibleNamePatch { private static void Postfix(Item __instance, ref string __result) { if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponent())) { __result = "Pirate"; } } } [HarmonyPatch(typeof(CloseItemsUI), "ShouldHideItem")] internal static class PirateCreatureCloseDotPatch { private static void Postfix(Item item, ref bool __result) { if (PirateCollectibleSupport.IsPirateProxy(item)) { __result = true; } } } [HarmonyPatch(typeof(ItemUI), "ShowSpecificItemInfo", new Type[] { typeof(Item) })] internal static class PirateCorpseHeldInfoPatch { private static bool Prefix(ItemUI __instance, Item __0) { if (!PirateCollectibleSupport.IsPirateProxy(__0)) { return true; } __instance.HideSpecificItemInfo(); return false; } } [HarmonyPatch(typeof(ItemManager), "Get", new Type[] { typeof(Collider) })] internal static class PirateCrewColliderItemLookupPatch { private static void Postfix(Collider col, ref Item? __result) { if (!Object.op_Implicit((Object)(object)__result) && Object.op_Implicit((Object)(object)col)) { PirateCrewHealth componentInParent = ((Component)col).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent) && Object.op_Implicit((Object)(object)componentInParent.BoundCreature)) { __result = (Item?)(object)componentInParent.BoundCreature; } } } } [HarmonyPatch(typeof(ItemManager), "Get", new Type[] { typeof(Transform) })] internal static class PirateCrewTransformItemLookupPatch { private static void Postfix(Transform tran, ref Item? __result) { if (!Object.op_Implicit((Object)(object)__result) && Object.op_Implicit((Object)(object)tran)) { PirateCrewHealth componentInParent = ((Component)tran).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent) && Object.op_Implicit((Object)(object)componentInParent.BoundCreature)) { __result = (Item?)(object)componentInParent.BoundCreature; } } } } [HarmonyPatch(typeof(ProjectileManager), "Hit")] internal static class PirateCrewProjectileHitPatch { private static void Prefix(Projectile projectile, RaycastHit hit) { //IL_005a: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (projectile.FromNpc && Object.op_Implicit((Object)(object)((RaycastHit)(ref hit)).collider) && !projectile.IsLocal && Object.op_Implicit((Object)(object)Server.Instance) && ((NetworkBehaviour)Server.Instance).IsServerInitialized) { Player playerFromBodyPart = PlayerManager.GetPlayerFromBodyPart(((RaycastHit)(ref hit)).transform); if (Object.op_Implicit((Object)(object)playerFromBodyPart) && !((NetworkBehaviour)playerFromBodyPart).IsDeinitializing) { Vector3 val = ((Vector3)(ref projectile.Velocity)).normalized * GameInfo.PlayerKillForce; Server.Instance.RpcLogic___HitPlayer___2449261505(playerFromBodyPart, projectile.Damage, val, ((RaycastHit)(ref hit)).point, (byte)2, (Player)null); } } } } [HarmonyPatch(typeof(Creature), "LocalHit")] internal static class PirateCreatureDamageScalingPatch { private static void Prefix(Creature __instance, ref int damage) { PirateCreatureLink component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.Pirate)) { damage = component.Pirate.ScalePlayerDamage(damage); } } } [HarmonyPatch(typeof(Item), "LocalHit")] internal static class PirateCreaturePhysicsHitPatch { private static bool Prefix(Item __instance) { PirateCreatureLink component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { return !component.IsAttached; } return true; } } [HarmonyPatch(typeof(ProjectileManager), "ReceiveAddProjectiles")] internal static class PirateProjectileReceivePatch { private static bool Prefix(ProjectileManager __instance, Player owner, WeaponInfo weaponInfo, uint tick, uint id, Vector3 pos, Vector3[] velocities) { //IL_0063: 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_004f: Unknown result type (might be due to invalid IL or missing references) if (!PirateProjectileSupport.IsPirateProjectile(weaponInfo, isLocal: false, id)) { return true; } if (((NetworkBehaviour)__instance).IsServerInitialized || velocities == null || velocities.Length == 0) { return false; } uint num = (uint)((float)(uint)((float)(InstanceFinder.TimeManager.Tick - tick) * GameInfo.TickMulti) * GameInfo.TickMulti); if (velocities.Length == 1) { __instance.AddProjectile(owner, weaponInfo, false, pos, velocities[0], num, id, true); } else { __instance.AddProjectiles(owner, weaponInfo, false, pos, velocities, num, id, true); } return false; } } [HarmonyPatch(typeof(ProjectileManager), "AddProjectile")] internal static class PirateSingleProjectileDamagePatch { private static void Prefix(WeaponInfo weaponInfo, bool isLocal, uint id, ref bool fromNpc, out int __state) { __state = int.MinValue; if (PirateProjectileSupport.IsPirateProjectile(weaponInfo, isLocal, id)) { fromNpc = true; __state = weaponInfo.ProjectileDamage; int num = Math.Max(0, PlayerManager.Players.Count - 1) * 2; weaponInfo.ProjectileDamage -= num; } } private static void Postfix(WeaponInfo weaponInfo, int __state) { if (__state != int.MinValue) { weaponInfo.ProjectileDamage = __state; } } } [HarmonyPatch(typeof(ProjectileManager), "AddProjectiles")] internal static class PirateMultipleProjectileNpcPatch { private static void Prefix(WeaponInfo weaponInfo, bool isLocal, uint id, ref bool canHitOwner) { if (PirateProjectileSupport.IsPirateProjectile(weaponInfo, isLocal, id)) { canHitOwner = true; } } } [HarmonyPatch(typeof(SaveManager), "CanSaveWorldItem")] internal static class PirateCorpseWorldSavePatch { private static void Postfix(Item item, ref bool __result) { if (__result && PirateCollectibleSupport.IsPirateProxy(item)) { __result = false; } } } [HarmonyPatch(typeof(SaveManager), "SavePlayer")] internal static class PirateCorpseInventorySavePatch { private static void Prefix(ref Item heldItem, ref Dictionary slotToItem) { if (PirateCollectibleSupport.IsPirateProxy(heldItem)) { heldItem = null; } bool flag = false; foreach (Item value in slotToItem.Values) { if (PirateCollectibleSupport.IsPirateProxy(value)) { flag = true; break; } } if (!flag) { return; } Dictionary dictionary = new Dictionary(); foreach (KeyValuePair item in slotToItem) { if (!PirateCollectibleSupport.IsPirateProxy(item.Value)) { dictionary.Add(item.Key, item.Value); } } slotToItem = dictionary; } } [HarmonyPatch] internal static class PlayerAwakePatch { private static MethodBase? TargetMethod() { return AccessTools.Method("Player:Awake", (Type[])null, (Type[])null); } private static void Postfix(object __instance) { Plugin.Log.LogDebug((object)$"Harmony observed Player.Awake on {__instance}."); } } }