using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FishNet; using FishNet.Connection; using FishNet.Object; using FishNet.Serializing; using HarmonyLib; 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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Untamo.Boats")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("Untamo.Boats")] [assembly: AssemblyTitle("Untamo.Boats")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Untamo.Boats { [BepInPlugin("Untamo.Boats", "Untamo.Boats", "1.0.5")] public sealed class Plugin : BaseUnityPlugin { private readonly struct CollisionPair { internal readonly Collider Item; internal readonly Collider Boat; internal CollisionPair(Collider item, Collider boat) { Item = item; Boat = boat; } } public const string PluginGuid = "Untamo.Boats"; public const string PluginName = "Untamo.Boats"; public const string PluginVersion = "1.0.5"; private const int BoatCost = 250; private const int MaximumBoats = 10; private ConfigEntry _purchaseKey; private ConfigEntry _removeAllKey; private bool _purchaseInProgress; private Boat _activeBoat; private Harmony _harmony; private readonly Dictionary _savedBoats = new Dictionary(); private readonly HashSet _restoringCustomBoats = new HashSet(); private BoatSaveFile _save = new BoatSaveFile(); private string _savePath; private string _saveContextKey; private string _nextBoatName = "Custom Boat 1"; private bool _restoreStarted; private BoatManager _knownBoatManager; private float _nextAutoSave; private bool _hasRuntimeSpawnAnchor; private Vector3 _runtimeSpawnAnchor; private bool _isIslandTransition; private readonly List _ignoredHeldItemCollisions = new List(); private Component _collisionIgnoredItem; private Boat _collisionIgnoredBoat; private Boat _lastLocallyDrivenBoat; private bool _selectedMotorRestored; private bool _selectedSkinRestored; private bool _selectedControlSkinRestored; private Boat _selectedControlSkinRestoredBoat; private bool _selectedMotorMountRestored; private Boat _selectedMotorMountRestoredBoat; private Coroutine _selectedControlSkinRestoreRoutine; private bool _selectedRadarPositionRestored; private bool _originalHealthRestored; private bool _originalFuelRestored; private bool _originalCooknessRestored; private ILogHandler _previousUnityLogHandler; private GameObject _boostHudObject; private Component _boostTextComponent; private float _nextBoostHudRefresh; private float _nextNearbyBoatRefresh; private Boat _cachedNearbyBoat; private float _nextBoatCountRefresh; private int _cachedBoatCount; private float _nextOriginalBoatRefresh; private Boat _cachedOriginalBoat; private static int _drivenBoatCacheFrame = -1; private static Boat _cachedLocallyDrivenBoat; private float _interactionRecoveryHoldStart = -1f; private bool _interactionRecoveryTriggered; private const float DestructiveKeyHoldSeconds = 0.3f; private float _purchaseKeyHoldStart = -1f; private bool _purchaseKeyHoldTriggered; private float _removeAllKeyHoldStart = -1f; private bool _removeAllKeyHoldTriggered; private float _deleteKeyHoldStart = -1f; private bool _deleteKeyHoldTriggered; private float _insertKeyHoldStart = -1f; private bool _insertKeyHoldTriggered; private const float FuelSellHoldStepSeconds = 0.4f; private float _homeFuelHoldStart = -1f; private int _homeFuelSellSteps; internal static Plugin Instance { get; private set; } private void Awake() { //IL_0023: 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_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown Instance = this; _purchaseKey = ((BaseUnityPlugin)this).Config.Bind("Controls", "PurchaseBoatKey", new KeyboardShortcut((KeyCode)289, Array.Empty()), "Buys and spawns a boat for 250. Up to four boats may exist."); _removeAllKey = ((BaseUnityPlugin)this).Config.Bind("Controls", "RemoveAllBoatsKey", new KeyboardShortcut((KeyCode)290, Array.Empty()), "Despawns every boat and clears all saved purchased boats."); _saveContextKey = null; _savePath = Path.Combine(Paths.ConfigPath, "Untamo.Boats.pending.boats.txt"); _save = new BoatSaveFile(); BoatCruiseRouting.ConfigurePersistence(1f, RememberCruisePower); try { _previousUnityLogHandler = Debug.unityLogger.logHandler; if (!(_previousUnityLogHandler is SkinKeywordNoiseLogHandler)) { Debug.unityLogger.logHandler = (ILogHandler)(object)new SkinKeywordNoiseLogHandler(_previousUnityLogHandler); } } catch { _previousUnityLogHandler = null; } _harmony = new Harmony("Untamo.Boats"); _harmony.PatchAll(); BoatAdditionalDamageBridge.Install(_harmony, ((BaseUnityPlugin)this).Logger); BoatExactMeleeHitBridge.Install(_harmony, ((BaseUnityPlugin)this).Logger); BoatExactFistHitBridge.Install(_harmony, ((BaseUnityPlugin)this).Logger); ((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded. Press F8 to buy a boat for {2:N0}.", "Untamo.Boats", "1.0.5", 250)); } private void OnDestroy() { if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } RestoreHeldItemCollisions(); if ((Object)(object)_boostHudObject != (Object)null) { Object.Destroy((Object)(object)_boostHudObject); } SaveBoats(); try { if (_previousUnityLogHandler != null && Debug.unityLogger.logHandler is SkinKeywordNoiseLogHandler) { Debug.unityLogger.logHandler = _previousUnityLogHandler; } } catch { } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void Update() { //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) EnsurePerGameSaveContext(); BoatManager instance = BoatManager.Instance; bool flag = (Object)(object)instance != (Object)(object)_knownBoatManager; if (flag) { if (_savedBoats.Count > 0 && _save != null && !string.IsNullOrEmpty(_savePath)) { SaveBoats(); } _knownBoatManager = instance; _restoreStarted = false; _selectedMotorRestored = false; _selectedSkinRestored = false; _selectedControlSkinRestored = false; _selectedControlSkinRestoredBoat = null; _selectedMotorMountRestored = false; _selectedMotorMountRestoredBoat = null; if (_selectedControlSkinRestoreRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_selectedControlSkinRestoreRoutine); _selectedControlSkinRestoreRoutine = null; } _selectedRadarPositionRestored = false; BoatMotorSkinRouting.ClearAllRuntime(); _originalHealthRestored = false; _originalFuelRestored = false; _originalCooknessRestored = false; _savedBoats.Clear(); _restoringCustomBoats.Clear(); if ((Object)(object)instance == (Object)null) { BoatGpsRouting.ClearRadarPositionRuntimeCache(); } if (InstanceFinder.IsServerStarted) { StopAllBoatInput(); } Boat locallyDrivenBoat = GetLocallyDrivenBoat(); if ((Object)(object)locallyDrivenBoat == (Object)null && (Object)(object)_lastLocallyDrivenBoat != (Object)null && ((NetworkBehaviour)_lastLocallyDrivenBoat).IsSpawned && (Object)(object)Player.LocalPlayer != (Object)null && InstanceFinder.IsServerStarted) { BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(_lastLocallyDrivenBoat), _lastLocallyDrivenBoat); _lastLocallyDrivenBoat.TrySetDriver(Player.LocalPlayer); } } SyncDrivenBoatWithManager(); RestoreSelectedMotorIfNeeded(); RestoreSelectedMotorSkinIfNeeded(); RestoreSelectedSkinIfNeeded(); RestoreSelectedControlSkinIfNeeded(); RestoreSelectedMotorMountModeIfNeeded(); RestoreSelectedRadarPositionIfNeeded(); RestoreSelectedRadarSkinIfNeeded(); RestoreOriginalHealthIfNeeded(); RestoreOriginalFuelIfNeeded(); BoatCommandRouting.UpdatePendingResets(); UpdateIslandAnchor(); UpdateBoatInventoryControls(); UpdateBoatMotorAndGpsControls(); UpdateHeldItemBoatCollisions(); UpdateBoatBoostSelection(); BoatHitboxRouting.Update(); BoatDamageRouting.Update(); BoatDiscNativeCollisionPatch.UpdateThrowState(); BoatDamageVisualRouting.Update(); BoatMotorSkinRouting.Update(); BoatControlSkinRouting.Update(); BoatRadarSkinRouting.Update(); BoatFuelRouting.Update(); BoatCooknessInspectRouting.Update(); BoatPhysicsKeepAlive.Update(); BoatInteractionRouting.Update(); BoatClosestPhysicsRouting.Update(); UpdateInteractionRecoveryHold(); Boat locallyDrivenBoat2 = GetLocallyDrivenBoat(); if ((Object)(object)locallyDrivenBoat2 != (Object)null && Input.GetKey((KeyCode)308)) { bool key = Input.GetKey((KeyCode)304); if (Input.GetKeyDown((KeyCode)276)) { MoveRadarAndSave(locallyDrivenBoat2, new Vector3(0f, 0f, -0.1f)); } else if (Input.GetKeyDown((KeyCode)275)) { MoveRadarAndSave(locallyDrivenBoat2, new Vector3(0f, 0f, 0.1f)); } else if (Input.GetKeyDown((KeyCode)273)) { MoveRadarAndSave(locallyDrivenBoat2, key ? new Vector3(0f, 0.1f, 0f) : new Vector3(-0.1f, 0f, 0f)); } else if (Input.GetKeyDown((KeyCode)274)) { MoveRadarAndSave(locallyDrivenBoat2, key ? new Vector3(0f, -0.1f, 0f) : new Vector3(0.1f, 0f, 0f)); } } if ((Object)(object)locallyDrivenBoat2 != (Object)null) { _lastLocallyDrivenBoat = locallyDrivenBoat2; } else if (!flag && !_isIslandTransition) { _lastLocallyDrivenBoat = null; } KeyboardShortcut value; if (!_purchaseInProgress) { value = _purchaseKey.Value; if (IsHoldKeyTriggered(((KeyboardShortcut)(ref value)).MainKey, ref _purchaseKeyHoldStart, ref _purchaseKeyHoldTriggered, 0.3f)) { ((MonoBehaviour)this).StartCoroutine(TryPurchaseBoat()); } } value = _removeAllKey.Value; if (IsHoldKeyTriggered(((KeyboardShortcut)(ref value)).MainKey, ref _removeAllKeyHoldStart, ref _removeAllKeyHoldTriggered, 0.3f)) { RemoveAllBoats(); } if (IsHoldKeyTriggered((KeyCode)127, ref _deleteKeyHoldStart, ref _deleteKeyHoldTriggered, 0.3f)) { RemoveCurrentBoat(); } if (IsHoldKeyTriggered((KeyCode)277, ref _insertKeyHoldStart, ref _insertKeyHoldTriggered, 0.3f)) { TryRepairNearbyBoat(); } UpdateHomeFuelBuySellControl(); if ((Object)(object)locallyDrivenBoat2 != (Object)null && (Object)(object)BoatManager.Instance != (Object)null && (Object)(object)BoatManager.Boat != (Object)(object)locallyDrivenBoat2) { BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(locallyDrivenBoat2), locallyDrivenBoat2); } if (!_restoreStarted && !string.IsNullOrEmpty(_saveContextKey) && !string.IsNullOrEmpty(_savePath) && InstanceFinder.IsServerStarted && (Object)(object)BoatManager.Instance != (Object)null) { _restoreStarted = true; ((MonoBehaviour)this).StartCoroutine(RestoreSavedBoats()); } if (InstanceFinder.IsServerStarted && Time.unscaledTime >= _nextAutoSave) { _nextAutoSave = Time.unscaledTime + 5f; SaveBoats(); } } private void LateUpdate() { BoatCruiseRouting.UpdatePersistentCruise(); BoatSkinRouting.UpdateCustomSkins(); BoatSkinRouting.UpdateRainbowSkins(); } private void FixedUpdate() { BoatFollowRouting.Update(); BoatAnchorRouting.FixedUpdate(); BoatDamageRouting.FixedUpdate(); } private void UpdateHomeFuelBuySellControl() { if (Input.GetKeyDown((KeyCode)278)) { _homeFuelHoldStart = Time.unscaledTime; _homeFuelSellSteps = 0; } if (Input.GetKey((KeyCode)278) && _homeFuelHoldStart >= 0f) { float num = Mathf.Max(0f, Time.unscaledTime - _homeFuelHoldStart); int num2 = Mathf.FloorToInt(num / 0.4f); while (_homeFuelSellSteps < num2) { _homeFuelSellSteps++; TrySellFuelNearbyBoat(); } } if (Input.GetKeyUp((KeyCode)278)) { if (_homeFuelHoldStart >= 0f && _homeFuelSellSteps == 0) { TryBuyFuelNearbyBoat(); } _homeFuelHoldStart = -1f; _homeFuelSellSteps = 0; } } private void TrySellFuelNearbyBoat() { if (!InstanceFinder.IsServerStarted) { return; } Boat val = GetLocallyDrivenBoat(); if ((Object)(object)val == (Object)null) { val = GetCachedNearbyBoat(); } if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Move close to a boat before holding Home to sell fuel."); return; } float fuel = BoatFuelRouting.GetFuel(val); float num = Mathf.Round(fuel * 100f) / 100f; if (num < 0.5f) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Boat needs at least {0.5f:0.00} Liter of fuel to sell. Fuel: {num:0.00} / 5 Liter."); return; } float fuel2 = Mathf.Max(0f, num - 0.5f); BoatFuelRouting.SetFuel(val, fuel2); if ((Object)(object)MoneyManager.Instance != (Object)null) { MoneyManager.AddMoney(1, Player.LocalPlayer); } SaveBoats(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Sold {0.5f:0.00} Liter of boat fuel for {1} game money. Fuel: {BoatFuelRouting.GetFuel(val):0.##} / 5 Liter."); } private void TryBuyFuelNearbyBoat() { if (!InstanceFinder.IsServerStarted) { return; } Boat val = GetLocallyDrivenBoat(); if ((Object)(object)val == (Object)null) { val = GetCachedNearbyBoat(); } if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Move close to a boat before tapping Home to buy fuel."); return; } float fuel = BoatFuelRouting.GetFuel(val); float num = Mathf.Round(fuel * 100f) / 100f; if (num > 4.5f) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Boat fuel is above 4.50 Liter, so no more fuel can be purchased."); return; } if (num >= 5f) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Boat fuel tank is already full at 5 Liter."); return; } if ((Object)(object)MoneyManager.Instance == (Object)null || !MoneyManager.CanAfford(1)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"You need 1 game money to buy 0.50 Liter of boat fuel."); return; } int money = MoneyManager.Money; MoneyManager.RemoveMoney(1, Player.LocalPlayer); int num2 = money - 1; if (MoneyManager.Money < num2) { int num3 = num2 - MoneyManager.Money; MoneyManager.AddMoney(num3, (Player)null); } BoatFuelRouting.SetFuel(val, Mathf.Min(5f, num + 0.5f)); SaveBoats(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Bought {0.5f:0.##} Liter of boat fuel for {1} game money. Fuel: {BoatFuelRouting.GetFuel(val):0.##} / 5 Liter."); } private void TryRepairNearbyBoat() { if (!InstanceFinder.IsServerStarted) { return; } Boat val = GetLocallyDrivenBoat(); if ((Object)(object)val == (Object)null) { val = GetCachedNearbyBoat(); } if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Move close to a boat before pressing Insert to repair it."); return; } if (BoatDamageRouting.IsSinking(val)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"This boat is already sinking and cannot be repaired."); return; } float health = BoatDamageRouting.GetHealth(val); float num = Mathf.Max(0f, 7500f - health); if (num <= 0.01f) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Boat health is already 7500. No repair needed and no money was charged."); return; } int boatRepairCost = GetBoatRepairCost(val); if ((Object)(object)MoneyManager.Instance == (Object)null || !MoneyManager.CanAfford(boatRepairCost)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"You need {boatRepairCost:N0} game money to repair this boat."); return; } int money = MoneyManager.Money; MoneyManager.RemoveMoney(boatRepairCost, Player.LocalPlayer); int num2 = money - boatRepairCost; if (MoneyManager.Money < num2) { int num3 = num2 - MoneyManager.Money; MoneyManager.AddMoney(num3, (Player)null); } BoatDamageRouting.SetSavedHealth(val, 7500f); SaveBoats(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Boat repaired to 7500 health for {boatRepairCost:N0} game money."); } private IEnumerator TryPurchaseBoat() { _purchaseInProgress = true; if ((Object)(object)BoatManager.Instance == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Boat manager is not ready. Unlock boats in the base game first."); _purchaseInProgress = false; yield break; } if (!InstanceFinder.IsServerStarted) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"The FishNet server is not running. In multiplayer, press F8 on the host."); _purchaseInProgress = false; yield break; } if (!IsBaseGameBoatUnlocked()) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Boats are not unlocked yet. Unlock the boat in the base game before using F8."); _purchaseInProgress = false; yield break; } Boat[] boatsBefore = Object.FindObjectsByType((FindObjectsSortMode)0); int purchaseCost = ((boatsBefore.Length != 0) ? 250 : 0); Boat steeringBoat = GetLocallyDrivenBoat(); if ((Object)(object)steeringBoat == (Object)null) { steeringBoat = GetCachedNearbyBoat(); } if (boatsBefore.Length != 0 && (Object)(object)steeringBoat == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Stand on/next to an existing boat or drive one before pressing F8."); _purchaseInProgress = false; yield break; } if (boatsBefore.Length >= 10) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"The maximum of {10} active boats has already been reached."); _purchaseInProgress = false; yield break; } if (purchaseCost > 0 && ((Object)(object)MoneyManager.Instance == (Object)null || !MoneyManager.CanAfford(purchaseCost))) { ((BaseUnityPlugin)this).Logger.LogWarning((object)$"You need {purchaseCost:N0} game money to buy a boat."); _purchaseInProgress = false; yield break; } object prefab = GetBoatPrefab(); if (prefab == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"The game's boat prefab could not be found."); _purchaseInProgress = false; yield break; } Vector3 spawnPosition = GetBoatSpawnPosition(steeringBoat); Boat spawnedBoat = TrySpawnExtraBoat(rotation: (!((Object)(object)steeringBoat != (Object)null)) ? SpawnManager.BoatSpawnRot : (((Object)(object)steeringBoat.HiddenPhysicsRig != (Object)null) ? steeringBoat.HiddenPhysicsRig.rotation : ((Component)steeringBoat).transform.rotation), prefab: (Boat)prefab, position: spawnPosition); for (int frame = 0; frame < 60; frame++) { if (IsNetworkSpawned(spawnedBoat)) { break; } yield return null; } bool spawned = IsNetworkSpawned(spawnedBoat); if (!spawned && (Object)(object)spawnedBoat != (Object)null) { Object.Destroy((Object)(object)((Component)spawnedBoat).gameObject); } if (!spawned) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Boat spawn failed. In multiplayer, buy boats on the host. Solo games are supported."); _purchaseInProgress = false; yield break; } byte inheritedMotor = (((Object)(object)steeringBoat != (Object)null) ? steeringBoat.MotorIndex : (_save.hasSelectedMotor ? _save.selectedMotorIndex : spawnedBoat.MotorIndex)); bool inheritedRadarUnlocked = (Object)(object)steeringBoat != (Object)null && BoatGpsRouting.HasRadar(steeringBoat); bool inheritedRadarVisible = inheritedRadarUnlocked && BoatGpsRouting.IsVisible(steeringBoat); byte inheritedMotorSkin = (((Object)(object)steeringBoat != (Object)null) ? BoatMotorSkinRouting.GetSkinIndex(steeringBoat) : byte.MaxValue); byte inheritedMotorFinish = (byte)(((Object)(object)steeringBoat != (Object)null) ? BoatMotorSkinRouting.GetFinishMode(steeringBoat) : (_save.hasSelectedMotorFinish ? _save.selectedMotorFinish : 0)); byte inheritedRadarSkin = (((Object)(object)steeringBoat != (Object)null) ? BoatRadarSkinRouting.GetSkinIndex(steeringBoat) : byte.MaxValue); byte inheritedControlSkin = (byte)(((Object)(object)steeringBoat != (Object)null) ? BoatControlSkinRouting.GetSkinIndex(steeringBoat) : (_save.hasSelectedControlSkin ? _save.selectedControlSkinIndex : 14)); byte inheritedHullSkin = (byte)(((Object)(object)steeringBoat != (Object)null) ? BoatSkinRouting.GetSkinIndex(steeringBoat) : (_save.hasSelectedSkin ? _save.selectedSkinIndex : 0)); byte inheritedHullStyle = (byte)(((Object)(object)steeringBoat != (Object)null) ? BoatSkinRouting.GetStyleMode(steeringBoat) : (_save.hasSelectedSkin ? _save.selectedSkinStyleMode : 0)); byte inheritedStripeSecondary = (byte)(((Object)(object)steeringBoat != (Object)null) ? BoatSkinRouting.GetStripeSecondarySkinIndex(steeringBoat) : (_save.hasSelectedSkin ? _save.selectedStripeSecondarySkinIndex : 14)); bool inheritedMotorMountUsesControls = (((Object)(object)steeringBoat != (Object)null) ? BoatControlSkinRouting.IsMotorMountUsingControls(steeringBoat) : (_save.hasSelectedMotorMountMode && _save.selectedMotorMountUsesControls)); Vector3 inheritedRadarOffset = (((Object)(object)steeringBoat != (Object)null) ? BoatGpsRouting.GetRadarOffset(steeringBoat) : Vector3.zero); EnsureBoatUnlocked(spawnedBoat); BoatGpsRouting.SetRadarUnlocked(spawnedBoat, inheritedRadarUnlocked); ActivateBoat(spawnedBoat); MotorRouting.ApplyMotor(spawnedBoat, inheritedMotor); BoatMotorSkinRouting.SetFinishMode(spawnedBoat, inheritedMotorFinish, reapplySkin: false); BoatMotorSkinRouting.ApplySkin(spawnedBoat, inheritedMotorSkin); BoatSkinRouting.SetSavedFinish(spawnedBoat, inheritedHullStyle); BoatSkinRouting.SetSavedStripeSecondarySkin(spawnedBoat, inheritedStripeSecondary); BoatSkinRouting.ApplySkin(spawnedBoat, inheritedHullSkin); BoatControlSkinRouting.SetMotorMountMode(spawnedBoat, inheritedMotorMountUsesControls, reapplyControls: false); if ((Object)(object)steeringBoat != (Object)null) { BoatControlSkinRouting.ApplySkin(spawnedBoat, inheritedControlSkin); } BoatGpsRouting.SetVisible(spawnedBoat, inheritedRadarVisible); BoatRadarSkinRouting.ApplySkin(spawnedBoat, inheritedRadarSkin); for (int inheritedRadarFrame = 0; inheritedRadarFrame < 120; inheritedRadarFrame++) { if (BoatGpsRouting.SetRadarOffset(spawnedBoat, inheritedRadarOffset)) { break; } yield return null; } if ((Object)(object)steeringBoat != (Object)null) { for (int skinReadyFrame = 0; skinReadyFrame < 120; skinReadyFrame++) { if (BoatSkinRouting.AreSkinRenderersReady(spawnedBoat)) { break; } yield return null; } BoatSkinRouting.SetSavedFinish(spawnedBoat, inheritedHullStyle); BoatSkinRouting.SetSavedStripeSecondarySkin(spawnedBoat, inheritedStripeSecondary); BoatSkinRouting.ApplySkin(spawnedBoat, inheritedHullSkin); BoatControlSkinRouting.SetMotorMountMode(spawnedBoat, inheritedMotorMountUsesControls, reapplyControls: false); BoatControlSkinRouting.ApplySkin(spawnedBoat, inheritedControlSkin); byte inheritedSkin = inheritedHullSkin; byte inheritedStyle = inheritedHullStyle; if ((inheritedStyle == 6 || inheritedStyle == 8) && inheritedSkin > 13) { for (int specialRetry = 0; specialRetry < 6; specialRetry++) { for (int settleFrame = 0; settleFrame < 15; settleFrame++) { yield return null; } if ((Object)(object)spawnedBoat == (Object)null || !((NetworkBehaviour)spawnedBoat).IsSpawned) { break; } BoatSkinRouting.SetSavedFinish(spawnedBoat, inheritedStyle); BoatSkinRouting.RebuildSavedSpecialFinishLikeManualSelection(spawnedBoat, inheritedSkin); } } } if ((Object)(object)steeringBoat != (Object)null) { for (int mountSettle = 0; mountSettle < 8; mountSettle++) { for (int mountWait = 0; mountWait < 5; mountWait++) { yield return null; } if ((Object)(object)spawnedBoat == (Object)null || !((NetworkBehaviour)spawnedBoat).IsSpawned) { break; } BoatControlSkinRouting.SetMotorMountMode(spawnedBoat, inheritedMotorMountUsesControls, reapplyControls: false); BoatControlSkinRouting.ApplySkin(spawnedBoat, inheritedControlSkin); } } BoatSkinRouting.SetSavedFinish(spawnedBoat, inheritedHullStyle); BoatSkinRouting.SetSavedStripeSecondarySkin(spawnedBoat, inheritedStripeSecondary); BoatSkinRouting.ApplySkin(spawnedBoat, inheritedHullSkin); BoatMotorSkinRouting.SetFinishMode(spawnedBoat, inheritedMotorFinish, reapplySkin: false); BoatMotorSkinRouting.ApplySkin(spawnedBoat, inheritedMotorSkin); BoatControlSkinRouting.SetMotorMountMode(spawnedBoat, inheritedMotorMountUsesControls, reapplyControls: false); BoatControlSkinRouting.ApplySkin(spawnedBoat, inheritedControlSkin); BoatRadarSkinRouting.ApplySkin(spawnedBoat, inheritedRadarSkin); BoatGpsRouting.SetVisible(spawnedBoat, inheritedRadarVisible); BoatGpsRouting.SetRadarOffset(spawnedBoat, inheritedRadarOffset); RememberSelectedMotor(inheritedMotor, saveImmediately: false); RememberSelectedRadar(inheritedRadarVisible, saveImmediately: false); RegisterPurchasedBoat(spawnedBoat); foreach (KeyValuePair pair in _savedBoats) { if ((Object)(object)pair.Value != (Object)(object)spawnedBoat) { continue; } BoatSaveRecord newRecord = _save.boats.Find((BoatSaveRecord item) => item != null && item.id == pair.Key); if (newRecord != null) { newRecord.motorIndex = inheritedMotor; newRecord.skinIndex = inheritedHullSkin; newRecord.skinStyleMode = inheritedHullStyle; newRecord.stripeSecondarySkinIndex = inheritedStripeSecondary; newRecord.controlSkinIndex = BoatControlSkinRouting.NormalizeSkinIndex(inheritedControlSkin); newRecord.motorSkinIndex = BoatMotorSkinRouting.NormalizeSkinIndex(inheritedMotorSkin); newRecord.motorFinishMode = BoatMotorSkinRouting.NormalizeFinishMode(inheritedMotorFinish); newRecord.radarSkinIndex = BoatRadarSkinRouting.NormalizeSkinIndex(inheritedRadarSkin); newRecord.motorMountUsesControls = inheritedMotorMountUsesControls; newRecord.radarUnlocked = inheritedRadarUnlocked; newRecord.radarVisible = inheritedRadarVisible; newRecord.radarOffsetX = inheritedRadarOffset.x; newRecord.radarOffsetY = inheritedRadarOffset.y; newRecord.radarOffsetZ = inheritedRadarOffset.z; } break; } SaveBoats(); if (purchaseCost > 0) { int balanceBefore = MoneyManager.Money; MoneyManager.RemoveMoney(purchaseCost, Player.LocalPlayer); yield return null; int expectedBalance = balanceBefore - purchaseCost; if (MoneyManager.Money < expectedBalance) { int refund = expectedBalance - MoneyManager.Money; MoneyManager.AddMoney(refund, (Player)null); ((BaseUnityPlugin)this).Logger.LogWarning((object)$"The game removed too much money; Untamo.Boats refunded {refund:N0}."); } } if ((Object)(object)steeringBoat != (Object)null && (Object)(object)steeringBoat.Driver == (Object)(object)Player.LocalPlayer) { steeringBoat.TrySetDriver((Player)null); } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Boat purchased for {purchaseCost:N0} and spawned near you at {spawnPosition}."); _purchaseInProgress = false; } private static bool IsBaseGameBoatUnlocked() { Boat boat = BoatManager.Boat; if ((Object)(object)boat != (Object)null && boat.BoatUnlocked) { return true; } object obj = AccessTools.Property(typeof(SaveManager), "CurServerSave")?.GetValue(null, null); if (obj != null && obj.GetType().GetField("UnlockedBoat", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj) is bool result) { return result; } return false; } private static void EnsureBoatUnlocked(Boat boat) { if ((Object)(object)boat == (Object)null) { return; } try { boat.UnlockBoat(); } catch { } if (boat.BoatUnlocked) { return; } PropertyInfo propertyInfo = AccessTools.Property(typeof(Boat), "BoatUnlocked"); if (propertyInfo != null && propertyInfo.CanWrite) { try { propertyInfo.SetValue(boat, true, null); } catch { } } FieldInfo[] fields = typeof(Boat).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < fields.Length; i++) { if (boat.BoatUnlocked) { break; } FieldInfo fieldInfo = fields[i]; string text = fieldInfo.Name.ToLowerInvariant(); if (!text.Contains("unlock") || text.Contains("radar")) { continue; } try { if (fieldInfo.FieldType == typeof(bool)) { fieldInfo.SetValue(boat, true); continue; } object value = fieldInfo.GetValue(boat); PropertyInfo propertyInfo2 = value?.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (propertyInfo2 != null && propertyInfo2.CanWrite && propertyInfo2.PropertyType == typeof(bool)) { propertyInfo2.SetValue(value, true, null); } } catch { } } } internal static Boat GetLocallyDrivenBoat() { int frameCount = Time.frameCount; if (_drivenBoatCacheFrame == frameCount) { if ((Object)(object)_cachedLocallyDrivenBoat != (Object)null && (Object)(object)_cachedLocallyDrivenBoat.Driver == (Object)(object)Player.LocalPlayer) { return _cachedLocallyDrivenBoat; } if ((Object)(object)_cachedLocallyDrivenBoat == (Object)null) { return null; } } _drivenBoatCacheFrame = frameCount; _cachedLocallyDrivenBoat = null; Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } Boat val = (((Object)(object)BoatManager.Instance == (Object)null) ? null : BoatManager.Boat); if ((Object)(object)val != (Object)null && (Object)(object)val.Driver == (Object)(object)localPlayer) { _cachedLocallyDrivenBoat = val; return val; } Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Boat val2 in array) { if ((Object)(object)val2 != (Object)null && (Object)(object)val2.Driver == (Object)(object)localPlayer) { _cachedLocallyDrivenBoat = val2; return val2; } } return null; } internal static void InvalidateDrivenBoatCache() { _drivenBoatCacheFrame = -1; _cachedLocallyDrivenBoat = null; } private Boat GetCachedNearbyBoat() { Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { _cachedNearbyBoat = null; return null; } if (Time.unscaledTime >= _nextNearbyBoatRefresh || (Object)(object)_cachedNearbyBoat == (Object)null || !((NetworkBehaviour)_cachedNearbyBoat).IsSpawned || (Object)(object)((Component)_cachedNearbyBoat).gameObject == (Object)null || !((Component)_cachedNearbyBoat).gameObject.activeInHierarchy) { _nextNearbyBoatRefresh = Time.unscaledTime + 0.15f; _cachedNearbyBoat = BoatClosestPhysicsRouting.FindNearestPhysicalBoat(localPlayer, 3.5f); } return _cachedNearbyBoat; } private int GetCachedBoatCount() { if (Time.unscaledTime >= _nextBoatCountRefresh) { _nextBoatCountRefresh = Time.unscaledTime + 1f; _cachedBoatCount = Object.FindObjectsByType((FindObjectsSortMode)0).Length; } return _cachedBoatCount; } private Boat GetCachedOriginalBoat() { HashSet hashSet = new HashSet(_savedBoats.Values); if (Time.unscaledTime < _nextOriginalBoatRefresh && (Object)(object)_cachedOriginalBoat != (Object)null && ((NetworkBehaviour)_cachedOriginalBoat).IsSpawned && (Object)(object)((Component)_cachedOriginalBoat).gameObject != (Object)null && ((Component)_cachedOriginalBoat).gameObject.activeInHierarchy && !hashSet.Contains(_cachedOriginalBoat) && !_restoringCustomBoats.Contains(_cachedOriginalBoat) && !IsSavedCustomBoatName(((Object)_cachedOriginalBoat).name)) { return _cachedOriginalBoat; } _nextOriginalBoatRefresh = Time.unscaledTime + 1f; _cachedOriginalBoat = null; Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Boat val in array) { if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).IsSpawned && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy && !hashSet.Contains(val) && !_restoringCustomBoats.Contains(val) && !IsSavedCustomBoatName(((Object)val).name)) { _cachedOriginalBoat = val; return val; } } return null; } private void SyncDrivenBoatWithManager() { Boat locallyDrivenBoat = GetLocallyDrivenBoat(); if (!((Object)(object)locallyDrivenBoat == (Object)null) && !BoatDamageRouting.IsSinking(locallyDrivenBoat) && !((Object)(object)BoatManager.Instance == (Object)null)) { if ((Object)(object)BoatManager.Boat != (Object)(object)locallyDrivenBoat) { BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(locallyDrivenBoat), locallyDrivenBoat); } _activeBoat = locallyDrivenBoat; } } private void UpdateBoatInventoryControls() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Invalid comparison between Unknown and I4 Boat locallyDrivenBoat = GetLocallyDrivenBoat(); Player localPlayer = Player.LocalPlayer; PlayerInventory val = (((Object)(object)localPlayer == (Object)null) ? null : localPlayer.Inventory); if ((Object)(object)locallyDrivenBoat == (Object)null || (Object)(object)val == (Object)null || (int)Cursor.lockState != 1) { return; } for (int i = 0; i < 8; i++) { if (Input.GetKeyDown((KeyCode)(49 + i))) { AccessTools.Method(typeof(PlayerInventory), "LocalTrySelectSlot", (Type[])null, (Type[])null)?.Invoke(val, new object[1] { i }); break; } } if (!Input.GetKeyDown((KeyCode)98)) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(PlayerInventory), "GetNextAvailableBait", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(Server), "ChangeBait", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null || (Object)(object)Server.Instance == (Object)null) { return; } try { byte b = (byte)methodInfo.Invoke(val, new object[1] { false }); methodInfo2.Invoke(Server.Instance, new object[2] { localPlayer, b }); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not change bait while driving: " + ex.Message)); } } private static bool IsHoldKeyTriggered(KeyCode key, ref float holdStart, ref bool triggered, float requiredSeconds) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (!Input.GetKey(key)) { holdStart = -1f; triggered = false; return false; } if (triggered) { return false; } if (holdStart < 0f) { holdStart = Time.unscaledTime; return false; } if (Time.unscaledTime - holdStart < requiredSeconds) { return false; } triggered = true; return true; } private void UpdateInteractionRecoveryHold() { if (!Input.GetKey((KeyCode)101)) { _interactionRecoveryHoldStart = -1f; _interactionRecoveryTriggered = false; } else if (!_interactionRecoveryTriggered) { if (_interactionRecoveryHoldStart < 0f) { _interactionRecoveryHoldStart = Time.unscaledTime; } else if (!(Time.unscaledTime - _interactionRecoveryHoldStart < 3f)) { _interactionRecoveryTriggered = true; RecoverBoatInteractionState(); } } } private void RecoverBoatInteractionState() { Player localPlayer = Player.LocalPlayer; BoatManagerContactGuard.ClearAllExplicitSwitches(); Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); if ((Object)(object)localPlayer != (Object)null) { foreach (Boat val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val.Driver != (Object)(object)localPlayer)) { StopBoatInputAndMotion(val, stopMotion: false); try { val.TrySetDriver((Player)null); } catch { } } } } BoatClosestPhysicsRouting.ClearContext(localPlayer); _lastLocallyDrivenBoat = null; if ((Object)(object)BoatManager.Instance != (Object)null) { try { BoatManager.SetBoat(Array.Empty(), (Boat)null); } catch { } } BoatInteractionRouting.ForceRefresh(); BoatClosestPhysicsRouting.ForceRefresh(); ((BaseUnityPlugin)this).Logger.LogWarning((object)"Boat interaction state reset after holding E for 3 seconds."); } private void MoveRadarAndSave(Boat boat, Vector3 localDelta) { //IL_0012: 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_008b: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_0113: 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_014d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null) { return; } BoatGpsRouting.MoveRadar(boat, localDelta); Vector3 radarOffset = BoatGpsRouting.GetRadarOffset(boat); bool flag = false; foreach (Boat value2 in _savedBoats.Values) { if ((Object)(object)value2 == (Object)(object)boat) { flag = true; break; } } if (!flag) { _save.hasSelectedRadarPosition = true; _save.selectedRadarOffsetX = radarOffset.x; _save.selectedRadarOffsetY = radarOffset.y; _save.selectedRadarOffsetZ = radarOffset.z; _selectedRadarPositionRestored = false; } for (int i = 0; i < _save.boats.Count; i++) { if (_savedBoats.TryGetValue(_save.boats[i].id, out var value) && (Object)(object)value == (Object)(object)boat) { _save.boats[i].radarOffsetX = radarOffset.x; _save.boats[i].radarOffsetY = radarOffset.y; _save.boats[i].radarOffsetZ = radarOffset.z; break; } } SaveBoats(); } private void UpdateBoatMotorAndGpsControls() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Invalid comparison between Unknown and I4 //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Invalid comparison between Unknown and I4 //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Invalid comparison between Unknown and I4 //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Invalid comparison between Unknown and I4 //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Invalid comparison between Unknown and I4 Boat locallyDrivenBoat = GetLocallyDrivenBoat(); Boat val = locallyDrivenBoat; if ((Object)(object)val == (Object)null) { val = GetCachedNearbyBoat(); } if ((int)Cursor.lockState == 1 && Input.GetKeyDown((KeyCode)111) && (Object)(object)val != (Object)null) { BoatCruiseRouting.Toggle(val, ((BaseUnityPlugin)this).Logger); } if ((int)Cursor.lockState == 1 && (Object)(object)val != (Object)null && BoatCruiseRouting.EnabledFor(val)) { if (Input.GetKeyDown((KeyCode)280)) { BoatCruiseRouting.AdjustThrottle(val, 0.1f); } else if (Input.GetKeyDown((KeyCode)281)) { BoatCruiseRouting.AdjustThrottle(val, -0.1f); } } if ((int)Cursor.lockState == 1 && Input.GetKeyDown((KeyCode)112)) { if ((Object)(object)locallyDrivenBoat != (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Follow selection: exit the driver seat and stand on the boat you want to follow you, then press P."); } else { Boat boat = BoatClosestPhysicsRouting.FindNearestPhysicalBoat(Player.LocalPlayer, 3.5f); BoatFollowRouting.ToggleFollower(boat, ((BaseUnityPlugin)this).Logger); } } if ((int)Cursor.lockState == 1 && (Object)(object)locallyDrivenBoat == (Object)null && (Object)(object)val != (Object)null && BoatCruiseRouting.EnabledFor(val)) { float num = 0f; if (Input.GetKey((KeyCode)276)) { num -= 1f; } if (Input.GetKey((KeyCode)275)) { num += 1f; } if (!Mathf.Approximately(num, 0f)) { BoatCruiseRouting.AdjustAutopilotHeading(val, num * 55f * Time.unscaledDeltaTime); } } if ((int)Cursor.lockState != 1) { return; } Boat val2 = (((Object)(object)locallyDrivenBoat != (Object)null) ? locallyDrivenBoat : GetCachedNearbyBoat()); if ((Object)(object)val2 != (Object)null) { if (Input.GetKeyDown((KeyCode)291)) { BoatSkinRouting.DumpCustomSkinTargets(val2, ((BaseUnityPlugin)this).Logger); } MotorRouting.ObservePurchasedMotor(val2); int num2 = ((!Input.GetKey((KeyCode)308) && Input.GetKeyDown((KeyCode)109)) ? ((!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303)) ? 1 : (-1)) : 0); if (num2 != 0 && MotorRouting.TryGetCycledMotor(val2, num2, out var motorIndex)) { if (InstanceFinder.IsServerStarted) { if (MotorRouting.ApplyMotor(val2, motorIndex)) { RememberSelectedMotor(motorIndex, saveImmediately: true); ((MonoBehaviour)this).StartCoroutine(ReapplyControlsAfterMotorChange(val2)); SaveBoats(); } } else if ((Object)(object)Server.Instance != (Object)null && (Object)(object)val2 == (Object)(object)locallyDrivenBoat) { RememberSelectedMotor(motorIndex, saveImmediately: true); Server.Instance.SetBoatSkin(MotorRouting.EncodeMotorRequest(motorIndex)); ((MonoBehaviour)this).StartCoroutine(ReapplyControlsAfterMotorChange(val2)); } } if (Input.GetKey((KeyCode)308) && Input.GetKeyDown((KeyCode)109)) { int direction = ((!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303)) ? 1 : (-1)); if (BoatMotorSkinRouting.TryGetCycledSkin(val2, direction, out var skinIndex) && BoatMotorSkinRouting.ApplySkin(val2, skinIndex)) { BoatControlSkinRouting.ApplySkin(val2, BoatControlSkinRouting.GetSkinIndex(val2)); RememberSelectedMotorSkin(val2); SaveBoats(); } } if (Input.GetKey((KeyCode)308) && Input.GetKeyDown((KeyCode)106)) { int direction2 = ((!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303)) ? 1 : (-1)); if (BoatMotorSkinRouting.ToggleFinish(val2, direction2)) { RememberSelectedMotorSkin(val2); RememberMotorFinish(val2); SaveBoats(); } } if (Input.GetKey((KeyCode)308) && Input.GetKeyDown((KeyCode)117) && !MotorRouting.HasNoMotor(val2) && BoatControlSkinRouting.ToggleMotorMountMode(val2)) { RememberMotorMountMode(val2); SaveBoats(); } if (!Input.GetKey((KeyCode)308) && Input.GetKeyDown((KeyCode)106)) { int direction3 = ((!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303)) ? 1 : (-1)); if (BoatSkinRouting.ToggleFinish(val2, direction3, ((BaseUnityPlugin)this).Logger)) { RememberSelectedSkin(val2); SaveBoats(); } } if (Input.GetKey((KeyCode)308) && Input.GetKeyDown((KeyCode)107)) { int direction4 = ((!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303)) ? 1 : (-1)); if (BoatControlSkinRouting.TryGetCycledSkin(val2, direction4, out var skinIndex2) && BoatControlSkinRouting.ApplySkin(val2, skinIndex2)) { RememberSelectedControlSkin(val2); RememberCustomBoatControlSkin(val2, skinIndex2); SaveBoats(); } } if (!Input.GetKey((KeyCode)308) && Input.GetKeyDown((KeyCode)107)) { int direction5 = ((!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303)) ? 1 : (-1)); if (BoatSkinRouting.TryGetCycledSkin(val2, direction5, out var skinIndex3)) { BoatSkinRouting.ApplySkin(val2, skinIndex3); RememberSelectedSkin(val2); SaveBoats(); } } if (!Input.GetKey((KeyCode)308) && Input.GetKeyDown((KeyCode)59)) { int direction6 = ((!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303)) ? 1 : (-1)); if (BoatSkinRouting.ToggleStripeSecondaryColor(val2, direction6, ((BaseUnityPlugin)this).Logger)) { RememberSelectedSkin(val2); SaveBoats(); } } } if ((Object)(object)val2 != (Object)null && Input.GetKeyDown((KeyCode)279)) { BoatAnchorRouting.Toggle(val2, ((BaseUnityPlugin)this).Logger); } if ((Object)(object)val2 != (Object)null && Input.GetKey((KeyCode)308) && Input.GetKeyDown((KeyCode)103)) { int direction7 = ((!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303)) ? 1 : (-1)); if (BoatRadarSkinRouting.TryGetCycledSkin(val2, direction7, out var skinIndex4) && BoatRadarSkinRouting.ApplySkin(val2, skinIndex4)) { RememberSelectedRadarSkin(val2); RememberCustomBoatRadarSkin(val2, skinIndex4); SaveBoats(); } } if ((Object)(object)locallyDrivenBoat == (Object)null) { return; } if (!Input.GetKey((KeyCode)308) && Input.GetKeyDown((KeyCode)103)) { BoatGpsRouting.Toggle(locallyDrivenBoat, ((BaseUnityPlugin)this).Logger); RememberSelectedRadar(BoatGpsRouting.IsVisible(locallyDrivenBoat), saveImmediately: true); } if (Input.GetKeyDown((KeyCode)104)) { BoatHornRouting.Play(locallyDrivenBoat, ((BaseUnityPlugin)this).Logger); } if (((Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305)) && Input.GetKeyDown((KeyCode)114)) || ((Input.GetKeyDown((KeyCode)306) || Input.GetKeyDown((KeyCode)305)) && Input.GetKey((KeyCode)114))) { if (InstanceFinder.IsServerStarted) { BoatCommandRouting.ResetToDefaultSpawn(locallyDrivenBoat); } else if ((Object)(object)Server.Instance != (Object)null) { Server.Instance.SetBoatSkin((byte)239); } } } private void UpdateBoatBoostSelection() { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) Boat locallyDrivenBoat = GetLocallyDrivenBoat(); Boat val = (((Object)(object)locallyDrivenBoat != (Object)null) ? locallyDrivenBoat : GetCachedNearbyBoat()); if ((Object)(object)val == (Object)null) { if ((Object)(object)_boostHudObject != (Object)null) { _boostHudObject.SetActive(false); } return; } EnsureBoostHud(); if ((Object)(object)_boostHudObject != (Object)null) { _boostHudObject.SetActive(true); } if (Time.unscaledTime >= _nextBoostHudRefresh) { _nextBoostHudRefresh = Time.unscaledTime + 0.2f; SetBoostHudText(val); } if (!((Object)(object)locallyDrivenBoat == (Object)null)) { float y = Input.mouseScrollDelta.y; if (!Mathf.Approximately(y, 0f)) { float num = ((y > 0f) ? 0.25f : (-0.25f)); BoatBoostRouting.SelectedMultiplier = Mathf.Clamp(BoatBoostRouting.SelectedMultiplier + num, 1.25f, 5f); _nextBoostHudRefresh = Time.unscaledTime + 0.2f; SetBoostHudText(val); } } } private void EnsureBoostHud() { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown //IL_0132: 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: Expected O, but got Unknown //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Expected O, but got Unknown //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Expected O, but got Unknown //IL_0249: 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_026d: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_048c: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_052a: Unknown result type (might be due to invalid IL or missing references) //IL_054b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_boostHudObject != (Object)null && (Object)(object)_boostTextComponent != (Object)null) { return; } Type type = FindRuntimeType("UnityEngine.Canvas"); Type type2 = FindRuntimeType("UnityEngine.UI.CanvasScaler"); Type type3 = FindRuntimeType("UnityEngine.UI.Text"); Type type4 = FindRuntimeType("UnityEngine.UI.Shadow"); Component val = FindNativeDamageTextTemplate(); Type type5 = (((Object)(object)val != (Object)null) ? ((object)val).GetType() : type3); if (type == null || type2 == null || type5 == null) { return; } _boostHudObject = new GameObject("Untamo Boat Boost HUD"); _boostHudObject.transform.SetParent((Transform)null, false); Object.DontDestroyOnLoad((Object)(object)_boostHudObject); Component target = _boostHudObject.AddComponent(type); SetEnumProperty(target, "renderMode", "ScreenSpaceOverlay"); SetRuntimeProperty(target, "sortingOrder", 4000); Component target2 = _boostHudObject.AddComponent(type2); SetEnumProperty(target2, "uiScaleMode", "ScaleWithScreenSize"); SetRuntimeProperty(target2, "referenceResolution", (object)new Vector2(1920f, 1080f)); GameObject val2 = new GameObject("Boat Boost Panel", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(_boostHudObject.transform, false); RectTransform val3 = (RectTransform)val2.transform; val3.anchorMin = new Vector2(0f, 1f); val3.anchorMax = new Vector2(0f, 1f); val3.pivot = new Vector2(0f, 1f); val3.anchoredPosition = new Vector2(20f, -20f); val3.sizeDelta = new Vector2(760f, 300f); GameObject val4 = new GameObject("Boat Boost Text", new Type[1] { typeof(RectTransform) }); val4.transform.SetParent(val2.transform, false); RectTransform val5 = (RectTransform)val4.transform; val5.anchorMin = new Vector2(0f, 1f); val5.anchorMax = Vector2.one; val5.pivot = new Vector2(0f, 1f); val5.anchoredPosition = Vector2.zero; val5.sizeDelta = new Vector2(760f, 290f); _boostTextComponent = val4.AddComponent(type5); if ((Object)(object)val != (Object)null) { CopyNativeDamageTextFont(val, _boostTextComponent); } else { object obj = FindNativeGameUiFont(); if (obj == null) { obj = typeof(Resources).GetMethod("GetBuiltinResource", new Type[2] { typeof(Type), typeof(string) })?.Invoke(null, new object[2] { FindRuntimeType("UnityEngine.Font"), "Arial.ttf" }); } SetRuntimeProperty(_boostTextComponent, "font", obj); } if (((object)_boostTextComponent).GetType().FullName != null && ((object)_boostTextComponent).GetType().FullName.StartsWith("TMPro.", StringComparison.Ordinal)) { SetRuntimeProperty(_boostTextComponent, "fontSize", 16f); SetEnumProperty(_boostTextComponent, "fontStyle", "Bold"); SetEnumProperty(_boostTextComponent, "alignment", "TopLeft"); SetRuntimeProperty(_boostTextComponent, "color", Color.white); SetRuntimeProperty(_boostTextComponent, "enableWordWrapping", false); SetRuntimeProperty(_boostTextComponent, "overflowMode", ParseEnumValue(_boostTextComponent, "overflowMode", "Overflow")); } else { SetRuntimeProperty(_boostTextComponent, "fontSize", 16); SetEnumProperty(_boostTextComponent, "fontStyle", "Bold"); SetEnumProperty(_boostTextComponent, "alignment", "UpperLeft"); SetRuntimeProperty(_boostTextComponent, "color", Color.white); SetEnumProperty(_boostTextComponent, "horizontalOverflow", "Overflow"); SetEnumProperty(_boostTextComponent, "verticalOverflow", "Overflow"); } SetRuntimeProperty(_boostTextComponent, "richText", true); SetRuntimeProperty(_boostTextComponent, "supportRichText", true); if (type4 != null) { Component target3 = val4.AddComponent(type4); SetRuntimeProperty(target3, "effectColor", (object)new Color(0f, 0f, 0f, 0.6f)); SetRuntimeProperty(target3, "effectDistance", (object)new Vector2(1.5f, -1.5f)); } Boat val6 = GetLocallyDrivenBoat(); if ((Object)(object)val6 == (Object)null) { val6 = GetCachedNearbyBoat(); } if ((Object)(object)val6 != (Object)null) { SetBoostHudText(val6); } } private static string GetFleetDriverNameFromSteamId(Player driver) { if ((Object)(object)driver == (Object)null) { return "Player"; } try { Type type = ((object)driver).GetType(); object obj = null; PropertyInfo property = type.GetProperty("SteamID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { obj = property.GetValue(driver, null); } if (obj == null) { FieldInfo field = type.GetField("_steamID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { obj = field.GetValue(driver); } } if (obj == null) { return "Player"; } Type type2 = Type.GetType("Steamworks.SteamFriends, com.rlabrecque.steamworks.net", throwOnError: false); if (type2 == null) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (!(assembly == null)) { type2 = assembly.GetType("Steamworks.SteamFriends", throwOnError: false); if (type2 != null) { break; } } } } if (type2 == null) { return "Player"; } MethodInfo[] methods = type2.GetMethods(BindingFlags.Static | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { if (methodInfo == null || methodInfo.Name != "GetFriendPersonaName") { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters == null || parameters.Length != 1) { continue; } Type parameterType = parameters[0].ParameterType; object obj2 = obj; if (!parameterType.IsInstanceOfType(obj2)) { ulong num; try { num = Convert.ToUInt64(obj, CultureInfo.InvariantCulture); } catch { PropertyInfo property2 = obj.GetType().GetProperty("m_SteamID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property2 == null) { continue; } num = Convert.ToUInt64(property2.GetValue(obj, null), CultureInfo.InvariantCulture); } try { obj2 = Activator.CreateInstance(parameterType, num); } catch { continue; } } string text = methodInfo.Invoke(null, new object[1] { obj2 }) as string; if (string.IsNullOrWhiteSpace(text)) { continue; } return text.Trim(); } } catch { } return "Player"; } private static string GetFleetFuelHudText(Boat boat) { float fuel = BoatFuelRouting.GetFuel(boat); string text = "Fuel: " + fuel.ToString("0.00", CultureInfo.InvariantCulture) + " L"; if (fuel >= 0.2f) { return text; } if (fuel <= 0.0001f) { return (((int)(Time.unscaledTime * 4f) & 1) == 0) ? ("" + text + "") : ("" + text + ""); } if (((int)(Time.unscaledTime * 4f) & 1) != 0) { return text; } return "" + text + ""; } private void SetBoostHudText(Boat selectedBoat) { if ((Object)(object)selectedBoat == (Object)null) { return; } int cachedBoatCount = GetCachedBoatCount(); string boatDisplayName = GetBoatDisplayName(selectedBoat); string visibilityText = BoatGpsRouting.GetVisibilityText(selectedBoat); string text = (BoatFollowRouting.IsSelectedFollower(selectedBoat) ? " | Follow Selected" : string.Empty); string stateText = BoatAnchorRouting.GetStateText(selectedBoat); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("\nFleet:"); Boat cachedOriginalBoat = GetCachedOriginalBoat(); if ((Object)(object)cachedOriginalBoat != (Object)null) { string value = (BoatDamageRouting.IsSinking(cachedOriginalBoat) ? "Sinking" : (BoatFollowRouting.IsSelectedFollower(cachedOriginalBoat) ? "Follow" : (BoatCruiseRouting.EnabledFor(cachedOriginalBoat) ? "Cruise" : ((!((Object)(object)cachedOriginalBoat.Driver != (Object)null)) ? "Idle" : ("Driving/" + GetFleetDriverNameFromSteamId(cachedOriginalBoat.Driver)))))); stringBuilder.Append("\n"); stringBuilder.Append(GetFleetBoatNameRichText(cachedOriginalBoat, "Original Boat")); stringBuilder.Append(" | "); stringBuilder.Append(value); stringBuilder.Append(" | "); stringBuilder.Append(GetFleetFuelHudText(cachedOriginalBoat)); stringBuilder.Append(" | Health: "); stringBuilder.Append(BoatDamageRouting.GetHealthText(cachedOriginalBoat)); } if (_save != null && _save.boats != null) { List list = new List(); for (int i = 0; i < _save.boats.Count; i++) { BoatSaveRecord boatSaveRecord = _save.boats[i]; if (boatSaveRecord != null) { Boat value2 = null; _savedBoats.TryGetValue(boatSaveRecord.id, out value2); if (!((Object)(object)value2 == (Object)null) && ((NetworkBehaviour)value2).IsSpawned && !((Object)(object)((Component)value2).gameObject == (Object)null) && ((Component)value2).gameObject.activeInHierarchy) { list.Add(boatSaveRecord); } } } list.Sort(delegate(BoatSaveRecord left, BoatSaveRecord right) { string strA = ((left == null || string.IsNullOrWhiteSpace(left.boatName)) ? string.Empty : left.boatName); string strB = ((right == null || string.IsNullOrWhiteSpace(right.boatName)) ? string.Empty : right.boatName); return string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase); }); for (int num = 0; num < list.Count; num++) { BoatSaveRecord boatSaveRecord2 = list[num]; if (boatSaveRecord2 != null) { Boat value3 = null; _savedBoats.TryGetValue(boatSaveRecord2.id, out value3); if (!((Object)(object)value3 == (Object)null) && ((NetworkBehaviour)value3).IsSpawned && !((Object)(object)((Component)value3).gameObject == (Object)null) && ((Component)value3).gameObject.activeInHierarchy) { string value4 = (BoatDamageRouting.IsSinking(value3) ? "Sinking" : (BoatFollowRouting.IsSelectedFollower(value3) ? "Follow" : (BoatCruiseRouting.EnabledFor(value3) ? "Cruise" : ((!((Object)(object)value3.Driver != (Object)null)) ? "Idle" : ("Driving/" + GetFleetDriverNameFromSteamId(value3.Driver)))))); string boatName = (string.IsNullOrWhiteSpace(boatSaveRecord2.boatName) ? $"Custom Boat {num + 1}" : boatSaveRecord2.boatName); stringBuilder.Append("\n"); stringBuilder.Append(GetFleetBoatNameRichText(value3, boatName)); stringBuilder.Append(" | "); stringBuilder.Append(value4); stringBuilder.Append(" | "); stringBuilder.Append(GetFleetFuelHudText(value3)); stringBuilder.Append(" | Health: "); stringBuilder.Append(BoatDamageRouting.GetHealthText(value3)); } } } } SetRuntimeProperty(_boostTextComponent, "text", boatDisplayName + " | " + MotorRouting.GetDisplayName(selectedBoat) + " | Cruise " + BoatCruiseRouting.GetStateText(selectedBoat) + text + " | Anchor " + stateText + "\nBoat: Skin " + BoatSkinRouting.GetSkinDisplayName(selectedBoat) + BoatSkinRouting.GetStripeSecondaryHudText(selectedBoat) + BoatSkinRouting.GetFinishHudText(selectedBoat) + " | Motor: " + BoatMotorSkinRouting.GetHudDisplayName(selectedBoat) + " | Radar: " + BoatRadarSkinRouting.GetSkinDisplayName(selectedBoat) + " | Controls: Skin " + BoatControlSkinRouting.GetSkinDisplayName(selectedBoat) + "\n" + $"Boat Boost: {BoatBoostRouting.SelectedMultiplier:0.##}x | Speed: {BoatSpeedRouting.GetSpeedText(selectedBoat)} | Cruise Power: {BoatCruiseRouting.GetThrottleText(selectedBoat)}\n" + $"{cachedBoatCount}/{10} Boats" + stringBuilder.ToString()); } private static string GetFleetBoatNameRichText(Boat boat, string boatName) { //IL_0089: 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_007e: 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_0079: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(boatName) || (Object)(object)boat == (Object)null) { return boatName ?? string.Empty; } if (BoatSkinRouting.IsRainbowSkin(boat)) { return BoatFleetTextEffectRouting.BuildDripText(boatName); } if (!BoatSkinRouting.TryGetHudSkinColor(BoatSkinRouting.GetSkinIndex(boat), out var color)) { return boatName; } if (BoatSkinRouting.IsStripeStyle(boat)) { if (!BoatSkinRouting.TryGetHudSkinColor(BoatSkinRouting.GetStripeSecondarySkinIndex(boat), out var color2)) { color2 = color; } return BoatFleetTextEffectRouting.BuildAlternatingText(boatName, color, color2); } return BoatFleetTextEffectRouting.WrapColor(boatName, color); } internal string GetBoatDisplayName(Boat boat) { if ((Object)(object)boat == (Object)null) { return "Boat"; } foreach (KeyValuePair pair in _savedBoats) { if (!((Object)(object)pair.Value != (Object)(object)boat)) { BoatSaveRecord boatSaveRecord = _save.boats.Find((BoatSaveRecord item) => item.id == pair.Key); if (boatSaveRecord != null && !string.IsNullOrWhiteSpace(boatSaveRecord.boatName)) { return boatSaveRecord.boatName; } } } return "Original Boat"; } private static Type FindRuntimeType(string fullName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType(fullName, throwOnError: false); if (type != null) { return type; } } return null; } private static Component FindNativeDamageTextTemplate() { Component[] array; try { array = Resources.FindObjectsOfTypeAll(); } catch { array = null; } if (array == null) { return null; } Component result = null; int num = 0; foreach (Component val in array) { if ((Object)(object)val == (Object)null || (Object)(object)val.gameObject == (Object)null) { continue; } PropertyInfo property = ((object)val).GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo property2 = ((object)val).GetType().GetProperty("font", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null || !property.CanWrite || property2 == null || !property2.CanRead) { continue; } int num2 = ScoreDamageTextComponent(val); if (num2 > num) { object obj2; try { obj2 = property2.GetValue(val, null); } catch { obj2 = null; } if (obj2 != null) { num = num2; result = val; } } } return result; } private static int ScoreDamageTextComponent(Component component) { if ((Object)(object)component == (Object)null) { return 0; } int num = 0; string text = ((object)component).GetType().Name.ToLowerInvariant(); if (text.Contains("textmeshpro")) { num += 10; } Transform val = component.transform; int num2 = 0; while ((Object)(object)val != (Object)null && num2 < 8) { string text2 = (((Object)(object)((Component)val).gameObject == (Object)null) ? string.Empty : ((Object)((Component)val).gameObject).name.ToLowerInvariant()); if (text2.Contains("damagenumber") || text2.Contains("damage number")) { num += 500; } if (text2.Contains("damage")) { num += 220; } if (text2.Contains("onhit")) { num += 300; } if (text2.Contains("hitmarker") || text2.Contains("hit marker")) { num += 180; } Component[] array; try { array = ((Component)val).GetComponents(); } catch { array = null; } if (array != null) { foreach (Component val2 in array) { if (!((Object)(object)val2 == (Object)null)) { string text3 = ((object)val2).GetType().Name.ToLowerInvariant(); if (text3 == "onhitui") { num += 700; } else if (text3.Contains("damagenumber")) { num += 600; } else if (text3.Contains("hitmarker")) { num += 300; } } } } val = val.parent; num2++; } return num; } private static void CopyNativeDamageTextFont(Component source, Component destination) { if ((Object)(object)source == (Object)null || (Object)(object)destination == (Object)null) { return; } string[] array = new string[3] { "font", "fontSharedMaterial", "fontMaterial" }; foreach (string name in array) { PropertyInfo property = ((object)source).GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo property2 = ((object)destination).GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null || property2 == null || !property.CanRead || !property2.CanWrite) { continue; } try { object value = property.GetValue(source, null); if (value != null && property2.PropertyType.IsInstanceOfType(value)) { property2.SetValue(destination, value, null); } } catch { } } } private static object FindNativeGameUiFont() { Component val = FindNativeDamageTextTemplate(); if ((Object)(object)val == (Object)null) { return null; } PropertyInfo property = ((object)val).GetType().GetProperty("font", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null || !property.CanRead) { return null; } try { return property.GetValue(val, null); } catch { return null; } } private static object ParseEnumValue(object target, string propertyName, string value) { if (target == null) { return null; } PropertyInfo property = target.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null || !property.PropertyType.IsEnum) { return null; } try { return Enum.Parse(property.PropertyType, value, ignoreCase: true); } catch { return Activator.CreateInstance(property.PropertyType); } } private static void SetRuntimeProperty(object target, string name, object value) { if (target == null || value == null) { return; } PropertyInfo property = target.GetType().GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null || !property.CanWrite) { return; } try { object obj = value; if (!property.PropertyType.IsInstanceOfType(obj) && obj is IConvertible && typeof(IConvertible).IsAssignableFrom(property.PropertyType)) { obj = Convert.ChangeType(obj, property.PropertyType, CultureInfo.InvariantCulture); } if (obj != null && property.PropertyType.IsInstanceOfType(obj)) { property.SetValue(target, obj, null); } } catch { } } private static void SetEnumProperty(object target, string name, string value) { if (target != null) { PropertyInfo property = target.GetType().GetProperty(name); if (!(property == null) && property.CanWrite && property.PropertyType.IsEnum) { property.SetValue(target, Enum.Parse(property.PropertyType, value, ignoreCase: true), null); } } } private void UpdateHeldItemBoatCollisions() { Boat locallyDrivenBoat = GetLocallyDrivenBoat(); Player localPlayer = Player.LocalPlayer; PlayerHolding val = (((Object)(object)localPlayer == (Object)null) ? null : localPlayer.Holding); Component val2 = (Component)(object)(((Object)(object)val == (Object)null) ? null : val.HeldItem); if ((Object)(object)locallyDrivenBoat == (Object)(object)_collisionIgnoredBoat && (Object)(object)val2 == (Object)(object)_collisionIgnoredItem) { return; } RestoreHeldItemCollisions(); if ((Object)(object)locallyDrivenBoat == (Object)null || (Object)(object)val2 == (Object)null) { return; } Collider[] componentsInChildren = val2.GetComponentsInChildren(); Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(locallyDrivenBoat); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] == (Object)null) { continue; } for (int j = 0; j < managerColliders.Length; j++) { if (!((Object)(object)managerColliders[j] == (Object)null)) { Physics.IgnoreCollision(componentsInChildren[i], managerColliders[j], true); _ignoredHeldItemCollisions.Add(new CollisionPair(componentsInChildren[i], managerColliders[j])); } } } _collisionIgnoredItem = val2; _collisionIgnoredBoat = locallyDrivenBoat; } private void RestoreHeldItemCollisions() { for (int i = 0; i < _ignoredHeldItemCollisions.Count; i++) { CollisionPair collisionPair = _ignoredHeldItemCollisions[i]; if ((Object)(object)collisionPair.Item != (Object)null && (Object)(object)collisionPair.Boat != (Object)null) { Physics.IgnoreCollision(collisionPair.Item, collisionPair.Boat, false); } } _ignoredHeldItemCollisions.Clear(); _collisionIgnoredItem = null; _collisionIgnoredBoat = null; } internal int GetBoatRepairCost(Boat boat) { if ((Object)(object)boat == (Object)null) { return 0; } float health = BoatDamageRouting.GetHealth(boat); float num = Mathf.Max(0f, 7500f - health); if (num <= 0.01f) { return 0; } bool flag = true; foreach (KeyValuePair savedBoat in _savedBoats) { if ((Object)(object)savedBoat.Value == (Object)(object)boat) { flag = false; break; } } int num2 = (flag ? 190 : 240); return Mathf.Clamp(Mathf.CeilToInt(num / 7500f * (float)num2), 1, num2); } internal int GetBoatSellValue(Boat boat) { if ((Object)(object)boat == (Object)null) { return 0; } bool flag = false; foreach (KeyValuePair savedBoat in _savedBoats) { if ((Object)(object)savedBoat.Value == (Object)(object)boat) { flag = true; break; } } if (!flag) { return 0; } float num = Mathf.Clamp(BoatDamageRouting.GetHealth(boat), 0f, 7500f); if (num <= 0f) { return 1; } return Mathf.Clamp(Mathf.CeilToInt(num / 7500f * 225f), 1, 225); } internal static int GetFuelSellRefundValue(Boat boat) { if ((Object)(object)boat == (Object)null) { return 0; } float fuel = BoatFuelRouting.GetFuel(boat); float num = Mathf.Round(fuel * 100f) / 100f; int num2 = Mathf.FloorToInt(num / 0.5f); return Mathf.Max(0, num2); } private void RemoveCurrentBoat() { Boat val = GetLocallyDrivenBoat(); if ((Object)(object)val == (Object)null) { val = GetCachedNearbyBoat(); } if ((Object)(object)val == (Object)null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Delete ignored: drive a boat or stand on/next to one."); return; } if (!IsBaseGameBoatUnlocked()) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Boats are not unlocked yet. Delete cannot remove boats until the base game boat is unlocked."); return; } string text = null; foreach (KeyValuePair savedBoat in _savedBoats) { if ((Object)(object)savedBoat.Value == (Object)(object)val) { text = savedBoat.Key; break; } } if (string.IsNullOrEmpty(text)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"The original/base-game boat cannot be sold or deleted."); return; } int boatSellValue = GetBoatSellValue(val); int fuelSellRefundValue = GetFuelSellRefundValue(val); int num = boatSellValue + fuelSellRefundValue; _savedBoats.Remove(text); for (int num2 = _save.boats.Count - 1; num2 >= 0; num2--) { if (_save.boats[num2].id == text) { _save.boats.RemoveAt(num2); } } _nextBoatName = GetNextCustomBoatName(); RestoreHeldItemCollisions(); BoatGpsRouting.ClearExplicitRadarOwnership(val); BoatFollowRouting.ClearForBoat(val); BoatSkinRouting.ClearForBoat(val); BoatControlSkinRouting.ClearForBoat(val); BoatManagerContactGuard.ClearExplicitSwitch(val); try { if ((Object)(object)val.Driver == (Object)(object)Player.LocalPlayer) { val.TrySetDriver((Player)null); } } catch { } if ((Object)(object)BoatManager.Instance != (Object)null && (Object)(object)BoatManager.Boat == (Object)(object)val) { try { BoatManager.SetBoat(Array.Empty(), (Boat)null); } catch { } } StopBoatInputAndMotion(val, stopMotion: false); if (InstanceFinder.IsServerStarted && ((NetworkBehaviour)val).IsSpawned) { try { InstanceFinder.ServerManager.Despawn(((Component)val).gameObject, (DespawnType?)null); } catch { Object.Destroy((Object)(object)((Component)val).gameObject); } } else if ((Object)(object)((Component)val).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } _lastLocallyDrivenBoat = null; _activeBoat = null; BoatClosestPhysicsRouting.ClearContext(Player.LocalPlayer); BoatInteractionRouting.ForceRefresh(); BoatClosestPhysicsRouting.ForceRefresh(); SaveBoats(); MoneyManager.AddMoney(num, Player.LocalPlayer); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Sold the currently driven boat for {boatSellValue} plus {fuelSellRefundValue} fuel money = {num} total."); } private void RemoveAllBoats() { if (!IsBaseGameBoatUnlocked()) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Boats are not unlocked yet. F9 cannot remove boats until the base game boat is unlocked."); return; } List list = new List(); foreach (KeyValuePair savedBoat in _savedBoats) { Boat value = savedBoat.Value; if ((Object)(object)value != (Object)null) { list.Add(value); } } int num = 0; int num2 = 0; for (int i = 0; i < list.Count; i++) { Boat val = list[i]; if ((Object)(object)val == (Object)null) { continue; } bool flag = ((NetworkBehaviour)val).IsSpawned && (Object)(object)((Component)val).gameObject != (Object)null && ((Component)val).gameObject.activeInHierarchy; int num3 = (flag ? GetBoatSellValue(val) : 0); int num4 = (flag ? GetFuelSellRefundValue(val) : 0); BoatGpsRouting.ClearExplicitRadarOwnership(val); BoatManagerContactGuard.ClearExplicitSwitch(val); try { if ((Object)(object)val.Driver == (Object)(object)Player.LocalPlayer) { val.TrySetDriver((Player)null); } } catch { } StopBoatInputAndMotion(val, stopMotion: false); if (InstanceFinder.IsServerStarted && ((NetworkBehaviour)val).IsSpawned) { try { InstanceFinder.ServerManager.Despawn(((Component)val).gameObject, (DespawnType?)null); } catch { if ((Object)(object)((Component)val).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } } else if ((Object)(object)((Component)val).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } if (flag) { num++; num2 += num3 + num4; } } _savedBoats.Clear(); _save.boats.Clear(); _nextBoatName = "Custom Boat 1"; _lastLocallyDrivenBoat = null; _activeBoat = null; BoatClosestPhysicsRouting.ClearContext(Player.LocalPlayer); BoatInteractionRouting.ForceRefresh(); BoatClosestPhysicsRouting.ForceRefresh(); SaveBoats(); if (num2 > 0) { MoneyManager.AddMoney(num2, Player.LocalPlayer); } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Sold {num} spawned purchased boat(s) for {num2}. The original boat was kept."); } internal void HandleDestroyedBoatAfterSink(Boat boat) { if ((Object)(object)boat == (Object)null) { return; } bool flag = false; string text = null; foreach (KeyValuePair savedBoat in _savedBoats) { if ((Object)(object)savedBoat.Value == (Object)(object)boat) { flag = true; text = savedBoat.Key; break; } } if (flag && !string.IsNullOrEmpty(text)) { _savedBoats.Remove(text); if (_save != null && _save.boats != null) { for (int num = _save.boats.Count - 1; num >= 0; num--) { if (_save.boats[num].id == text) { _save.boats.RemoveAt(num); } } } _nextBoatName = GetNextCustomBoatName(); } BoatGpsRouting.ClearExplicitRadarOwnership(boat); BoatFollowRouting.ClearForBoat(boat); BoatCruiseRouting.DisableForBoat(boat); BoatSkinRouting.ClearForBoat(boat); BoatManagerContactGuard.ClearExplicitSwitch(boat); try { if ((Object)(object)boat.Driver != (Object)null) { boat.TrySetDriver((Player)null); } } catch { } if ((Object)(object)BoatManager.Instance != (Object)null && (Object)(object)BoatManager.Boat == (Object)(object)boat) { try { BoatManager.SetBoat(Array.Empty(), (Boat)null); } catch { } } BoatDamageRouting.ForgetBoat(boat); ForceRemoveBoat(boat); SaveBoats(); if (!flag) { ((MonoBehaviour)this).StartCoroutine(RespawnOriginalBoatAfterSink()); } } private void ChargeOriginalBoatRespawnFee() { int money = MoneyManager.Money; MoneyManager.RemoveMoney(200, Player.LocalPlayer); int num = money - 200; if (MoneyManager.Money < num) { int num2 = num - MoneyManager.Money; MoneyManager.AddMoney(num2, (Player)null); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Original boat reached 0 HP and respawned for 200 game money."); } private IEnumerator RespawnOriginalBoatAfterSink() { float readyAt = Time.unscaledTime + 1f; while (Time.unscaledTime < readyAt) { yield return null; } if ((Object)(object)MoneyManager.Instance == (Object)null || !MoneyManager.CanAfford(200)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"Original boat was destroyed, but you need 200 game money to respawn it. It will not respawn."); yield break; } for (int waitFrame = 0; waitFrame < 600; waitFrame++) { if (!InstanceFinder.IsServerStarted || (Object)(object)BoatManager.Instance == (Object)null) { yield return null; continue; } Boat existingOriginal = GetCachedOriginalBoat(); if ((Object)(object)existingOriginal != (Object)null && ((NetworkBehaviour)existingOriginal).IsSpawned) { PlaceOriginalBoatAtDefaultSpawn(existingOriginal); BoatDamageRouting.SetSavedHealth(existingOriginal, 7500f); BoatFuelRouting.SetFuel(existingOriginal, 1.5f); if (_save != null && _save.hasSelectedSkin) { BoatSkinRouting.SetSavedFinish(existingOriginal, _save.selectedSkinStyleMode); BoatSkinRouting.SetSavedStripeSecondarySkin(existingOriginal, _save.selectedStripeSecondarySkinIndex); BoatSkinRouting.ApplySkin(existingOriginal, _save.selectedSkinIndex); if ((_save.selectedSkinStyleMode == 6 || _save.selectedSkinStyleMode == 8) && _save.selectedSkinIndex > 13) { ((MonoBehaviour)this).StartCoroutine(RebuildOriginalSpecialFinishAfterLoad(existingOriginal, _save.selectedSkinIndex, _save.selectedSkinStyleMode)); } } ChargeOriginalBoatRespawnFee(); SaveBoats(); yield break; } object prefabObject = GetBoatPrefab(); if (!(prefabObject is Boat)) { yield return null; continue; } Boat replacement = TrySpawnExtraBoat((Boat)prefabObject, SpawnManager.BoatSpawnPos, SpawnManager.BoatSpawnRot); if ((Object)(object)replacement == (Object)null) { yield return null; continue; } for (int spawnFrame = 0; spawnFrame < 180; spawnFrame++) { if (((NetworkBehaviour)replacement).IsSpawned) { break; } yield return null; } if (!((NetworkBehaviour)replacement).IsSpawned) { if ((Object)(object)((Component)replacement).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)replacement).gameObject); } yield return null; continue; } PlaceOriginalBoatAtDefaultSpawn(replacement); EnsureBoatUnlocked(replacement); if (_save != null && _save.hasSelectedMotor) { MotorRouting.ApplyMotor(replacement, _save.selectedMotorIndex); } if (_save != null && _save.hasSelectedSkin) { BoatSkinRouting.SetSavedFinish(replacement, _save.selectedSkinStyleMode); BoatSkinRouting.SetSavedStripeSecondarySkin(replacement, _save.selectedStripeSecondarySkinIndex); BoatSkinRouting.ApplySkin(replacement, _save.selectedSkinIndex); if ((_save.selectedSkinStyleMode == 6 || _save.selectedSkinStyleMode == 8) && _save.selectedSkinIndex > 13) { ((MonoBehaviour)this).StartCoroutine(RebuildOriginalSpecialFinishAfterLoad(replacement, _save.selectedSkinIndex, _save.selectedSkinStyleMode)); } } BoatDamageRouting.SetSavedHealth(replacement, 7500f); BoatFuelRouting.SetFuel(replacement, 1.5f); _cachedOriginalBoat = replacement; _nextOriginalBoatRefresh = Time.unscaledTime + 1f; ChargeOriginalBoatRespawnFee(); SaveBoats(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Original boat respawned at its default game location after sinking."); yield break; } ((BaseUnityPlugin)this).Logger.LogWarning((object)"Original boat could not be respawned yet because the map/server boat prefab was not ready."); } private static void PlaceOriginalBoatAtDefaultSpawn(Boat boat) { //IL_000e: 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) //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_0020: 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_0054: 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_0064: 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) if (!((Object)(object)boat == (Object)null)) { Vector3 boatSpawnPos = SpawnManager.BoatSpawnPos; Quaternion boatSpawnRot = SpawnManager.BoatSpawnRot; ((Component)boat).transform.SetPositionAndRotation(boatSpawnPos, boatSpawnRot); Rigidbody val = boat.HiddenPhysicsRig; if ((Object)(object)val == (Object)null) { val = ((Component)boat).GetComponentInChildren(); } if ((Object)(object)val != (Object)null) { val.position = boatSpawnPos; val.rotation = boatSpawnRot; val.linearVelocity = Vector3.zero; val.angularVelocity = Vector3.zero; val.WakeUp(); } } } private static void ForceRemoveBoat(Boat boat) { if (!((Object)(object)boat == (Object)null)) { DespawnBoat(boat); if ((Object)(object)boat != (Object)null && (Object)(object)((Component)boat).gameObject != (Object)null) { ((Component)boat).gameObject.SetActive(false); Object.Destroy((Object)(object)((Component)boat).gameObject); } } } private static bool DespawnBoat(Boat boat) { if ((Object)(object)boat == (Object)null) { return false; } object networkObject = ((NetworkBehaviour)boat).NetworkObject; if (networkObject != null) { MethodInfo[] methods = networkObject.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < methods.Length; i++) { if (!(methods[i].Name != "Despawn")) { object[] parameters = BuildDefaultArguments(methods[i].GetParameters(), 0, null); try { methods[i].Invoke(networkObject, parameters); return true; } catch { } } } } MethodInfo[] methods2 = ((object)InstanceFinder.ServerManager).GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int j = 0; j < methods2.Length; j++) { if (methods2[j].Name != "Despawn") { continue; } ParameterInfo[] parameters2 = methods2[j].GetParameters(); if (parameters2.Length == 0) { continue; } object obj2 = (parameters2[0].ParameterType.IsInstanceOfType(((Component)boat).gameObject) ? ((Component)boat).gameObject : (parameters2[0].ParameterType.IsInstanceOfType(networkObject) ? networkObject : null)); if (obj2 != null) { object[] parameters3 = BuildDefaultArguments(parameters2, 1, obj2); try { methods2[j].Invoke(InstanceFinder.ServerManager, parameters3); return true; } catch { } } } return false; } private static object[] BuildDefaultArguments(ParameterInfo[] parameters, int startIndex, object firstArgument) { object[] array = new object[parameters.Length]; if (startIndex == 1) { array[0] = firstArgument; } for (int i = startIndex; i < parameters.Length; i++) { if (parameters[i].HasDefaultValue) { array[i] = parameters[i].DefaultValue; } else if (parameters[i].ParameterType.IsValueType) { array[i] = Activator.CreateInstance(parameters[i].ParameterType); } else { array[i] = null; } } return array; } private void ActivateBoat(Boat boat) { if (!((Object)(object)boat == (Object)null)) { Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(boat); BoatManager.SetBoat(managerColliders, boat); _activeBoat = boat; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Active drivable boat changed to " + ((Object)boat).name + ".")); } } private static bool IsNetworkSpawned(Boat boat) { return (Object)(object)boat != (Object)null && (Object)(object)((Component)boat).gameObject != (Object)null && ((Component)boat).gameObject.activeInHierarchy && ((NetworkBehaviour)boat).IsSpawned; } private static Vector3 GetBoatSpawnPosition(Boat steeringBoat) { //IL_000c: 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_0039: 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_00b6: 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_0060: 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_0065: 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_0067: 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) //IL_0072: 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_0078: 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_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_00a1: 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_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_00b2: 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_00a0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)steeringBoat == (Object)null) { return SpawnManager.BoatSpawnPos; } Vector3 val = (((Object)(object)steeringBoat.HiddenPhysicsRig != (Object)null) ? steeringBoat.HiddenPhysicsRig.position : ((Component)steeringBoat).transform.position); Quaternion val2 = (((Object)(object)steeringBoat.HiddenPhysicsRig != (Object)null) ? steeringBoat.HiddenPhysicsRig.rotation : ((Component)steeringBoat).transform.rotation); Vector3 val3 = val2 * Vector3.forward; Vector3 val4 = Vector3.ProjectOnPlane(val3, Vector3.up); val3 = ((Vector3)(ref val4)).normalized; if (((Vector3)(ref val3)).sqrMagnitude < 0.01f) { val3 = Vector3.forward; } return val + val3 * 10f; } private static Vector3 SeparateFromExistingBoats(Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //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_0011: 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_0017: 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_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_0037: 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_00ed: 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_00f2: 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_0076: 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_007c: 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_00c6: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) Vector3 val = SpawnManager.BoatSpawnRot * Vector3.right; Vector3 val2 = Vector3.ProjectOnPlane(val, Vector3.up); val = ((Vector3)(ref val2)).normalized; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { val = Vector3.right; } Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < 3; i++) { bool flag = false; for (int j = 0; j < array.Length; j++) { if (!((Object)(object)array[j] == (Object)null)) { Vector3 val3 = ((Component)array[j]).transform.position - position; val3.y = 0f; if (((Vector3)(ref val3)).sqrMagnitude < 9f) { flag = true; break; } } } if (!flag) { break; } position += val * 4f; } return position; } private Boat TrySpawnExtraBoat(Boat prefab, Vector3 position, Quaternion? rotation = null) { //IL_0002: 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_000e: 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_0047: Unknown result type (might be due to invalid IL or missing references) Boat val = Object.Instantiate(prefab, position, (Quaternion)(((??)rotation) ?? SpawnManager.BoatSpawnRot)); if ((Object)(object)val == (Object)null) { return null; } try { InstanceFinder.ServerManager.Spawn(((Component)val).gameObject, (NetworkConnection)null, default(Scene)); return val; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)ex); Object.Destroy((Object)(object)((Component)val).gameObject); return null; } } private static object GetBoatPrefab() { SpawnManager val = Object.FindAnyObjectByType(); if ((Object)(object)val == (Object)null) { return null; } return typeof(SpawnManager).GetField("_boatPrefab", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(val); } private string GetNextCustomBoatName() { HashSet hashSet = new HashSet(); foreach (KeyValuePair pair in _savedBoats) { Boat value = pair.Value; if ((Object)(object)value == (Object)null || !((NetworkBehaviour)value).IsSpawned || (Object)(object)((Component)value).gameObject == (Object)null || !((Component)value).gameObject.activeInHierarchy) { continue; } string name = ((Object)value).name; BoatSaveRecord boatSaveRecord = null; if (_save != null && _save.boats != null) { boatSaveRecord = _save.boats.Find((BoatSaveRecord item) => item.id == pair.Key); } if (boatSaveRecord != null && !string.IsNullOrWhiteSpace(boatSaveRecord.boatName)) { name = boatSaveRecord.boatName; } if (TryGetCustomBoatNumber(name, out var number)) { hashSet.Add(number); } } int num; for (num = 1; hashSet.Contains(num); num++) { } return $"Custom Boat {num}"; } private void EnsureUniqueCustomBoatNames() { if (_save == null || _save.boats == null) { return; } HashSet hashSet = new HashSet(); for (int i = 0; i < _save.boats.Count; i++) { BoatSaveRecord boatSaveRecord = _save.boats[i]; if (TryGetCustomBoatNumber(boatSaveRecord.boatName, out var number) && !hashSet.Contains(number)) { hashSet.Add(number); boatSaveRecord.boatName = $"Custom Boat {number}"; continue; } int j; for (j = 1; hashSet.Contains(j); j++) { } hashSet.Add(j); boatSaveRecord.boatName = $"Custom Boat {j}"; } } private static string NormalizeCustomBoatName(string name, int fallbackNumber) { if (TryGetCustomBoatNumber(name, out var number)) { return $"Custom Boat {number}"; } return $"Custom Boat {Mathf.Max(1, fallbackNumber)}"; } private static bool TryGetCustomBoatNumber(string name, out int number) { number = 0; if (string.IsNullOrWhiteSpace(name)) { return false; } string text = name.Trim(); string text2 = null; if (text.StartsWith("Custom Boat ", StringComparison.OrdinalIgnoreCase)) { text2 = text.Substring("Custom Boat ".Length); } else if (text.StartsWith("Boat ", StringComparison.OrdinalIgnoreCase)) { text2 = text.Substring("Boat ".Length); } if (text2 == null || !int.TryParse(text2, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result < 1) { return false; } number = result; return true; } private void RegisterPurchasedBoat(Boat boat) { //IL_00d5: 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_00f7: Unknown result type (might be due to invalid IL or missing references) string nextCustomBoatName = GetNextCustomBoatName(); BoatSaveRecord boatSaveRecord = new BoatSaveRecord { id = Guid.NewGuid().ToString("N"), ownerId = GetLocalOwnerId(), boatName = nextCustomBoatName, motorIndex = boat.MotorIndex, radarUnlocked = BoatGpsRouting.HasRadar(boat), radarVisible = BoatGpsRouting.IsVisible(boat), skinIndex = BoatSkinRouting.GetSkinIndex(boat), skinStyleMode = BoatSkinRouting.GetStyleMode(boat), stripeSecondarySkinIndex = BoatSkinRouting.GetStripeSecondarySkinIndex(boat), controlSkinIndex = BoatControlSkinRouting.GetSkinIndex(boat), motorSkinIndex = BoatMotorSkinRouting.GetSkinIndex(boat), motorFinishMode = BoatMotorSkinRouting.GetFinishMode(boat), radarSkinIndex = BoatRadarSkinRouting.GetSkinIndex(boat), motorMountUsesControls = BoatControlSkinRouting.IsMotorMountUsingControls(boat), skinMetallic = BoatSkinRouting.IsMetallicFinish(boat), fuel = 0.5f, radarOffsetX = BoatGpsRouting.GetRadarOffset(boat).x, radarOffsetY = BoatGpsRouting.GetRadarOffset(boat).y, radarOffsetZ = BoatGpsRouting.GetRadarOffset(boat).z }; _save.boats.Add(boatSaveRecord); _savedBoats[boatSaveRecord.id] = boat; BoatFuelRouting.SetFuel(boat, 0.5f); ((Object)boat).name = nextCustomBoatName; UpdateRecordTransform(boatSaveRecord, boat); _nextBoatName = GetNextCustomBoatName(); SaveBoats(); } private IEnumerator RestoreSavedBoats() { object prefabObject = null; for (int waitFrame = 0; waitFrame < 600; waitFrame++) { if (!InstanceFinder.IsServerStarted || (Object)(object)BoatManager.Instance == (Object)null) { yield return null; continue; } prefabObject = GetBoatPrefab(); if (prefabObject is Boat) { break; } yield return null; } if (!(prefabObject is Boat)) { _restoreStarted = false; } else { if (_save == null || _save.boats == null || _save.boats.Count == 0) { yield break; } for (int i = 0; i < _save.boats.Count && i < 10; i++) { if (Object.FindObjectsByType((FindObjectsSortMode)0).Length >= 10) { break; } BoatSaveRecord record = _save.boats[i]; if (_savedBoats.ContainsKey(record.id)) { continue; } Vector3 savedPosition = new Vector3(record.x, record.y, record.z); Quaternion savedRotation = new Quaternion(record.qx, record.qy, record.qz, record.qw); Boat boat = null; for (int spawnAttempt = 0; spawnAttempt < 5; spawnAttempt++) { if (!((Object)(object)boat == (Object)null)) { break; } boat = TrySpawnExtraBoat((Boat)prefabObject, savedPosition, savedRotation); if ((Object)(object)boat == (Object)null) { for (int delay = 0; delay < 30; delay++) { yield return null; } } } if ((Object)(object)boat == (Object)null) { continue; } _restoringCustomBoats.Add(boat); for (int frame = 0; frame < 180; frame++) { if (((NetworkBehaviour)boat).IsSpawned) { break; } yield return null; } if (!((NetworkBehaviour)boat).IsSpawned) { _restoringCustomBoats.Remove(boat); Object.Destroy((Object)(object)((Component)boat).gameObject); continue; } ((Component)boat).transform.SetPositionAndRotation(savedPosition, savedRotation); Rigidbody restoredBody = boat.HiddenPhysicsRig; if ((Object)(object)restoredBody == (Object)null) { restoredBody = ((Component)boat).GetComponentInChildren(); } if ((Object)(object)restoredBody != (Object)null) { restoredBody.position = savedPosition; restoredBody.rotation = savedRotation; restoredBody.linearVelocity = Vector3.zero; restoredBody.angularVelocity = Vector3.zero; restoredBody.WakeUp(); } record.boatName = NormalizeCustomBoatName(record.boatName, i + 1); ((Object)boat).name = record.boatName; if ((Object)(object)_cachedOriginalBoat == (Object)(object)boat) { _cachedOriginalBoat = null; _nextOriginalBoatRefresh = 0f; _selectedControlSkinRestored = false; _selectedControlSkinRestoredBoat = null; } EnsureBoatUnlocked(boat); BoatGpsRouting.SetRadarUnlocked(boat, record.radarUnlocked); MotorRouting.ApplyMotor(boat, record.motorIndex); byte restoredStyle = (byte)((record.skinStyleMode != 0) ? record.skinStyleMode : (record.skinMetallic ? 1 : 0)); BoatSkinRouting.SetSavedFinish(boat, restoredStyle); BoatSkinRouting.SetSavedStripeSecondarySkin(boat, record.stripeSecondarySkinIndex); for (int materialFrame = 0; materialFrame < 120; materialFrame++) { if (BoatSkinRouting.AreSkinRenderersReady(boat)) { break; } yield return null; } BoatSkinRouting.ApplySkin(boat, record.skinIndex); for (int settleFrame = 0; settleFrame < 6; settleFrame++) { yield return null; } BoatSkinRouting.SetSavedFinish(boat, restoredStyle); BoatSkinRouting.SetSavedStripeSecondarySkin(boat, record.stripeSecondarySkinIndex); BoatSkinRouting.ApplySkin(boat, record.skinIndex); BoatSkinRouting.EnsureSavedFinishMaterialState(boat); for (int visualRetry = 0; visualRetry < 6; visualRetry++) { for (int retryFrame = 0; retryFrame < 10; retryFrame++) { yield return null; } BoatSkinRouting.SetSavedFinish(boat, restoredStyle); BoatSkinRouting.SetSavedStripeSecondarySkin(boat, record.stripeSecondarySkinIndex); BoatSkinRouting.ApplySkin(boat, record.skinIndex); BoatSkinRouting.EnsureSavedFinishMaterialState(boat); } if ((restoredStyle == 6 || restoredStyle == 8) && record.skinIndex > 13) { for (int specialFinishSettleFrame = 0; specialFinishSettleFrame < 30; specialFinishSettleFrame++) { yield return null; } BoatSkinRouting.SetSavedFinish(boat, restoredStyle); BoatSkinRouting.RebuildSavedSpecialFinishLikeManualSelection(boat, record.skinIndex); } BoatMotorSkinRouting.SetFinishMode(boat, record.motorFinishMode, reapplySkin: false); BoatMotorSkinRouting.ApplySkin(boat, record.motorSkinIndex); BoatRadarSkinRouting.ApplySkin(boat, record.radarSkinIndex); for (int radarColorRetry = 0; radarColorRetry < 8; radarColorRetry++) { for (int radarColorWait = 0; radarColorWait < 6; radarColorWait++) { yield return null; } if ((Object)(object)boat == (Object)null || !((NetworkBehaviour)boat).IsSpawned) { break; } BoatRadarSkinRouting.EnsureDesiredSkin(boat, record.radarSkinIndex); } BoatControlSkinRouting.SetMotorMountMode(boat, record.motorMountUsesControls, reapplyControls: false); BoatControlSkinRouting.ApplySkin(boat, record.controlSkinIndex); for (int controlRestoreRetry = 0; controlRestoreRetry < 8; controlRestoreRetry++) { for (int controlWait = 0; controlWait < 8; controlWait++) { yield return null; } if ((Object)(object)boat == (Object)null || !((NetworkBehaviour)boat).IsSpawned) { break; } BoatControlSkinRouting.SetMotorMountMode(boat, record.motorMountUsesControls, reapplyControls: false); BoatControlSkinRouting.EnsureDesiredSkin(boat, record.controlSkinIndex); } BoatGpsRouting.SetVisible(boat, record.radarUnlocked && record.radarVisible); Vector3 savedRadarOffset = new Vector3(record.radarOffsetX, record.radarOffsetY, record.radarOffsetZ); for (int radarFrame = 0; radarFrame < 120; radarFrame++) { if (BoatGpsRouting.SetRadarOffset(boat, savedRadarOffset)) { break; } yield return null; } if ((Object)(object)GetLocallyDrivenBoat() == (Object)null) { BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(boat), boat); } BoatDamageRouting.SetSavedHealth(boat, record.health); BoatFuelRouting.SetFuel(boat, record.fuel); _savedBoats[record.id] = boat; _restoringCustomBoats.Remove(boat); } SyncDrivenBoatWithManager(); if (_save != null && _save.boats != null && _save.boats.Count > 0 && _savedBoats.Count == 0) { _restoreStarted = false; } } } private string GetLocalOwnerId() { if ((Object)(object)Player.LocalPlayer != (Object)null && ((NetworkBehaviour)Player.LocalPlayer).Owner != (NetworkConnection)null) { return "fishnet:" + ((NetworkBehaviour)Player.LocalPlayer).Owner.ClientId; } return "local-host"; } private void UpdateIslandAnchor() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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) //IL_0054: 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_003a: 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_006d: Unknown result type (might be due to invalid IL or missing references) if (!InstanceFinder.IsServerStarted || (Object)(object)BoatManager.Instance == (Object)null || _isIslandTransition) { return; } Vector3 boatSpawnPos = SpawnManager.BoatSpawnPos; if (!_hasRuntimeSpawnAnchor) { _runtimeSpawnAnchor = boatSpawnPos; _hasRuntimeSpawnAnchor = true; return; } Vector3 val = boatSpawnPos - _runtimeSpawnAnchor; if (!(((Vector3)(ref val)).sqrMagnitude < 1f)) { _runtimeSpawnAnchor = boatSpawnPos; _isIslandTransition = true; ((MonoBehaviour)this).StartCoroutine(HandleBoatsForIslandChange()); } } private IEnumerator HandleBoatsForIslandChange() { StopAllBoatInput(); yield return (object)new WaitForFixedUpdate(); BoatFollowRouting.GetSelectedFollowers(); foreach (KeyValuePair pair in _savedBoats) { Boat boat = pair.Value; if ((Object)(object)boat == (Object)null) { continue; } BoatSaveRecord record = _save.boats.Find((BoatSaveRecord item) => item.id == pair.Key); if (BoatFollowRouting.IsSelectedFollower(boat)) { if (record != null) { record.leftBehind = false; } } else if (!((Object)(object)boat.Driver != (Object)null)) { if (record != null) { record.leftBehind = true; UpdateRecordTransform(record, boat); } StopBoatInputAndMotion(boat, stopMotion: true); yield return (object)new WaitForFixedUpdate(); } } Boat[] selectedFollowers = BoatFollowRouting.GetSelectedFollowers(); for (int followerIndex = 0; followerIndex < selectedFollowers.Length; followerIndex++) { Boat selectedFollower = selectedFollowers[followerIndex]; if ((Object)(object)selectedFollower == (Object)null || !((NetworkBehaviour)selectedFollower).IsSpawned || (Object)(object)selectedFollower.Driver != (Object)null) { continue; } Rigidbody followerBody = selectedFollower.HiddenPhysicsRig; if ((Object)(object)followerBody == (Object)null) { followerBody = ((Component)selectedFollower).GetComponentInChildren(); } float side = ((followerIndex % 2 == 0) ? (-1f) : 1f); float row = 1f + (float)(followerIndex / 2); Vector3 carryPosition = SpawnManager.BoatSpawnPos + Vector3.right * side * (4f + row * 2f) - Vector3.forward * (6f + row * 3f); ((Component)selectedFollower).transform.position = carryPosition; if ((Object)(object)followerBody != (Object)null) { followerBody.position = carryPosition; followerBody.linearVelocity = Vector3.zero; followerBody.angularVelocity = Vector3.zero; followerBody.WakeUp(); } foreach (KeyValuePair pair2 in _savedBoats) { if ((Object)(object)pair2.Value != (Object)(object)selectedFollower) { continue; } BoatSaveRecord record2 = _save.boats.Find((BoatSaveRecord item) => item.id == pair2.Key); if (record2 != null) { record2.leftBehind = false; UpdateRecordTransform(record2, selectedFollower); } break; } } SaveBoats(); _isIslandTransition = false; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Island transition complete; selected Follow boats carried forward."); } private static void StopAllBoatInput() { Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { StopBoatInputAndMotion(array[i], stopMotion: false); } } internal static void StopBoatInputAndMotion(Boat boat, bool stopMotion) { //IL_002d: 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_0036: 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_0060: 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) if ((Object)(object)boat == (Object)null) { return; } if (!stopMotion && BoatCruiseRouting.EnabledFor(boat)) { BoatCruiseRouting.UpdatePersistentCruise(); return; } boat.ServerSetInput(default(half), default(half)); if (stopMotion) { Rigidbody[] componentsInChildren = ((Component)boat).GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].linearVelocity = Vector3.zero; componentsInChildren[i].angularVelocity = Vector3.zero; componentsInChildren[i].Sleep(); } } } private bool EnsurePerGameSaveContext() { if (!TryGetGameSaveContextKey(out var contextKey) || string.IsNullOrEmpty(contextKey)) { return false; } string text = Path.Combine(Paths.ConfigPath, "Untamo.Boats." + contextKey + ".boats.txt"); if (string.Equals(_saveContextKey, contextKey, StringComparison.Ordinal) && string.Equals(_savePath, text, StringComparison.Ordinal) && _save != null) { return true; } if (!string.IsNullOrEmpty(_saveContextKey) && !string.IsNullOrEmpty(_savePath) && _save != null) { SaveBoats(); } _saveContextKey = contextKey; _savePath = text; _savedBoats.Clear(); _restoringCustomBoats.Clear(); BoatGpsRouting.ClearAllExplicitRadarOwnership(); _save = new BoatSaveFile(); _nextBoatName = "Custom Boat 1"; _restoreStarted = false; _selectedMotorRestored = false; _selectedSkinRestored = false; _selectedControlSkinRestored = false; _selectedControlSkinRestoredBoat = null; _selectedMotorMountRestored = false; _selectedMotorMountRestoredBoat = null; BoatMotorSkinRouting.ClearAllRuntime(); if (_selectedControlSkinRestoreRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_selectedControlSkinRestoreRoutine); _selectedControlSkinRestoreRoutine = null; } _selectedRadarPositionRestored = false; _originalHealthRestored = false; _originalCooknessRestored = false; _activeBoat = null; LoadBoatSave(); if (_save.boats != null) { _nextBoatName = GetNextCustomBoatName(); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded boat data for map/save " + contextKey + " from " + _savePath)); return true; } private static bool TryGetGameSaveContextKey(out string contextKey) { contextKey = null; object obj = AccessTools.Property(typeof(SaveManager), "CurServerSave")?.GetValue(null, null); if (obj == null) { return false; } Type type = obj.GetType(); string[] array = new string[27] { "SaveGuid", "SaveGUID", "SaveId", "SaveID", "WorldGuid", "WorldGUID", "WorldId", "WorldID", "MapGuid", "MapGUID", "MapId", "MapID", "WorldSeed", "MapSeed", "Seed", "SaveName", "FileName", "SavePath", "SlotId", "SlotID", "SaveSlot", "Slot", "Guid", "GUID", "Id", "ID", "Name" }; List list = new List(); for (int i = 0; i < array.Length; i++) { if (TryReadStableSaveMember(obj, type, array[i], out var value)) { list.Add(array[i] + "=" + value); string text = array[i].ToLowerInvariant(); if (text.Contains("guid") || text.Contains("seed") || text.Contains("path") || text.Contains("file") || text.EndsWith("id")) { break; } } } if (list.Count == 0) { List list2 = new List(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int j = 0; j < fields.Length; j++) { if (LooksLikeSaveIdentityName(fields[j].Name) && TryFormatStableIdentityValue(fields[j].GetValue(obj), out var value2)) { list2.Add(fields[j].Name + "=" + value2); } } PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.GetIndexParameters().Length != 0 || !propertyInfo.CanRead || !LooksLikeSaveIdentityName(propertyInfo.Name)) { continue; } try { if (TryFormatStableIdentityValue(propertyInfo.GetValue(obj, null), out var value3)) { list2.Add(propertyInfo.Name + "=" + value3); } } catch { } } list2.Sort(StringComparer.OrdinalIgnoreCase); for (int l = 0; l < list2.Count && l < 12; l++) { list.Add(list2[l]); } } if (list.Count == 0) { return false; } string value4 = type.FullName + "|" + string.Join("|", list); contextKey = ComputeStableContextHash(value4); return !string.IsNullOrEmpty(contextKey); } private static bool TryReadStableSaveMember(object save, Type saveType, string name, out string value) { value = null; FieldInfo field = saveType.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { try { if (TryFormatStableIdentityValue(field.GetValue(save), out value)) { return true; } } catch { } } PropertyInfo property = saveType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanRead && property.GetIndexParameters().Length == 0) { try { if (TryFormatStableIdentityValue(property.GetValue(save, null), out value)) { return true; } } catch { } } return false; } private static bool TryFormatStableIdentityValue(object raw, out string value) { value = null; if (raw == null) { return false; } Type type = raw.GetType(); if (raw is string text) { if (string.IsNullOrWhiteSpace(text)) { return false; } value = text.Trim(); return true; } if (raw is Guid guid) { value = guid.ToString("N"); return guid != Guid.Empty; } if (type.IsEnum || raw is byte || raw is sbyte || raw is short || raw is ushort || raw is int || raw is uint || raw is long || raw is ulong) { value = Convert.ToString(raw, CultureInfo.InvariantCulture); return true; } return false; } private static bool LooksLikeSaveIdentityName(string name) { if (string.IsNullOrEmpty(name)) { return false; } string text = name.ToLowerInvariant(); return text.Contains("save") || text.Contains("world") || text.Contains("map") || text.Contains("seed") || text.Contains("slot") || text.Contains("guid") || text.Contains("file") || text.Contains("path") || text == "id" || text.EndsWith("id") || text == "name"; } private static string ComputeStableContextHash(string value) { if (string.IsNullOrEmpty(value)) { return null; } ulong num = 14695981039346656037uL; byte[] bytes = Encoding.UTF8.GetBytes(value); for (int i = 0; i < bytes.Length; i++) { num ^= bytes[i]; num *= 1099511628211L; } return num.ToString("x16", CultureInfo.InvariantCulture); } private void LoadBoatSave() { try { if (File.Exists(_savePath)) { _save = DeserializeSave(File.ReadAllLines(_savePath)); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Loaded {_save.boats.Count} custom boat record(s) for {_saveContextKey} from {_savePath}"); } else { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Boat save file does not exist yet; it will be created at " + _savePath)); } if (_save.boats == null) { _save.boats = new List(); } for (int i = 0; i < _save.boats.Count; i++) { _save.boats[i].boatName = NormalizeCustomBoatName(_save.boats[i].boatName, i + 1); } _nextBoatName = GetNextCustomBoatName(); BoatCruiseRouting.ConfigurePersistence(_save.hasCruisePower ? _save.cruisePower : 1f, RememberCruisePower); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Could not load boat save: {arg}"); _save = new BoatSaveFile(); _nextBoatName = "Custom Boat 1"; } } private void SaveBoats() { //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(_savePath) || string.IsNullOrEmpty(_saveContextKey) || _save == null) { return; } try { string directoryName = Path.GetDirectoryName(_savePath); if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(directoryName); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Could not prepare boat save folder: {arg}"); return; } _save.hasAnchor = true; _save.anchorX = SpawnManager.BoatSpawnPos.x; _save.anchorY = SpawnManager.BoatSpawnPos.y; _save.anchorZ = SpawnManager.BoatSpawnPos.z; Boat locallyDrivenBoat = GetLocallyDrivenBoat(); Boat cachedOriginalBoat = GetCachedOriginalBoat(); if ((Object)(object)cachedOriginalBoat != (Object)null && ((NetworkBehaviour)cachedOriginalBoat).IsSpawned) { _save.hasOriginalHealth = true; _save.originalHealth = BoatDamageRouting.GetHealth(cachedOriginalBoat); _save.hasOriginalFuel = true; _save.originalFuel = BoatFuelRouting.GetFuel(cachedOriginalBoat); } if ((Object)(object)cachedOriginalBoat != (Object)null && ((NetworkBehaviour)cachedOriginalBoat).IsSpawned) { byte skinIndex = BoatMotorSkinRouting.GetSkinIndex(cachedOriginalBoat); if (skinIndex != byte.MaxValue) { _save.hasSelectedMotorSkin = true; _save.selectedMotorSkinIndex = skinIndex; } } if ((Object)(object)cachedOriginalBoat != (Object)null && ((NetworkBehaviour)cachedOriginalBoat).IsSpawned && !_save.hasSelectedSkin) { _save.hasSelectedSkin = true; _save.selectedSkinIndex = BoatSkinRouting.GetSkinIndex(cachedOriginalBoat); _save.selectedSkinStyleMode = BoatSkinRouting.GetStyleMode(cachedOriginalBoat); _save.selectedStripeSecondarySkinIndex = BoatSkinRouting.GetStripeSecondarySkinIndex(cachedOriginalBoat); } if ((Object)(object)locallyDrivenBoat != (Object)null) { _save.hasSelectedMotor = true; _save.selectedMotorIndex = locallyDrivenBoat.MotorIndex; _save.hasSelectedRadar = true; _save.selectedRadarVisible = BoatGpsRouting.IsVisible(locallyDrivenBoat); bool flag = false; foreach (Boat value2 in _savedBoats.Values) { if ((Object)(object)value2 == (Object)(object)locallyDrivenBoat) { flag = true; break; } } if (!flag) { Vector3 radarOffset = BoatGpsRouting.GetRadarOffset(locallyDrivenBoat); _save.hasSelectedRadarPosition = true; _save.selectedRadarOffsetX = radarOffset.x; _save.selectedRadarOffsetY = radarOffset.y; _save.selectedRadarOffsetZ = radarOffset.z; } } for (int i = 0; i < _save.boats.Count; i++) { if (_savedBoats.TryGetValue(_save.boats[i].id, out var value) && (Object)(object)value != (Object)null && !_restoringCustomBoats.Contains(value)) { UpdateRecordTransform(_save.boats[i], value); } } try { File.WriteAllLines(_savePath, SerializeSave()); ((BaseUnityPlugin)this).Logger.LogDebug((object)$"Saved {_save.boats.Count} custom boat record(s) for {_saveContextKey} to {_savePath}"); } catch (Exception arg2) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Could not save boats: {arg2}"); } } private static void UpdateRecordTransform(BoatSaveRecord record, Boat boat) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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) //IL_0018: 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_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_0078: 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_0090: 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_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0157: 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) Vector3 position = ((Component)boat).transform.position; Quaternion rotation = ((Component)boat).transform.rotation; Rigidbody val = boat.HiddenPhysicsRig; if ((Object)(object)val == (Object)null) { val = ((Component)boat).GetComponentInChildren(); } if ((Object)(object)val != (Object)null) { position = val.position; rotation = val.rotation; } record.x = position.x; record.y = position.y; record.z = position.z; record.qx = rotation.x; record.qy = rotation.y; record.qz = rotation.z; record.qw = rotation.w; record.motorIndex = boat.MotorIndex; record.skinIndex = BoatSkinRouting.GetSkinIndex(boat); record.skinStyleMode = BoatSkinRouting.GetStyleMode(boat); record.stripeSecondarySkinIndex = BoatSkinRouting.GetStripeSecondarySkinIndex(boat); record.controlSkinIndex = BoatControlSkinRouting.GetSkinIndex(boat); record.motorSkinIndex = BoatMotorSkinRouting.GetSkinIndex(boat); record.motorFinishMode = BoatMotorSkinRouting.GetFinishMode(boat); record.radarSkinIndex = BoatRadarSkinRouting.GetSkinIndex(boat); record.motorMountUsesControls = BoatControlSkinRouting.IsMotorMountUsingControls(boat); record.skinMetallic = BoatSkinRouting.IsMetallicFinish(boat); record.radarUnlocked = BoatGpsRouting.HasRadar(boat); record.radarVisible = BoatGpsRouting.IsVisible(boat); Vector3 radarOffset = BoatGpsRouting.GetRadarOffset(boat); record.radarOffsetX = radarOffset.x; record.radarOffsetY = radarOffset.y; record.radarOffsetZ = radarOffset.z; record.health = BoatDamageRouting.GetHealth(boat); record.fuel = BoatFuelRouting.GetFuel(boat); } private IEnumerable SerializeSave() { yield return string.Join("|", "ANCHOR", _save.anchorX.ToString("R", CultureInfo.InvariantCulture), _save.anchorY.ToString("R", CultureInfo.InvariantCulture), _save.anchorZ.ToString("R", CultureInfo.InvariantCulture)); if (_save.hasSelectedMotor) { yield return string.Join("|", "MOTOR", _save.selectedMotorIndex.ToString(CultureInfo.InvariantCulture)); } if (_save.hasSelectedRadar) { yield return string.Join("|", "RADAR", _save.selectedRadarVisible ? "1" : "0"); } if (_save.hasSelectedSkin) { yield return string.Join("|", "SELECTEDSKIN", _save.selectedSkinIndex.ToString(CultureInfo.InvariantCulture), _save.selectedSkinStyleMode.ToString(CultureInfo.InvariantCulture), _save.selectedStripeSecondarySkinIndex.ToString(CultureInfo.InvariantCulture)); } if (_save.hasSelectedControlSkin) { yield return string.Join("|", "SELECTEDCONTROLSKIN", _save.selectedControlSkinIndex.ToString(CultureInfo.InvariantCulture)); } if (_save.hasSelectedMotorSkin) { yield return string.Join("|", "SELECTEDMOTORSKIN", _save.selectedMotorSkinIndex.ToString(CultureInfo.InvariantCulture)); } if (_save.hasSelectedMotorFinish) { yield return string.Join("|", "SELECTEDMOTORFINISH", _save.selectedMotorFinish.ToString(CultureInfo.InvariantCulture)); } if (_save.hasSelectedMotorMountMode) { yield return string.Join("|", "SELECTEDMOTORMOUNT", _save.selectedMotorMountUsesControls ? "1" : "0"); } if (_save.hasSelectedRadarSkin) { yield return string.Join("|", "SELECTEDRADARSKIN", _save.selectedRadarSkinIndex.ToString(CultureInfo.InvariantCulture)); } if (_save.hasSelectedRadarPosition) { yield return string.Join("|", "RADARPOS", _save.selectedRadarOffsetX.ToString("R", CultureInfo.InvariantCulture), _save.selectedRadarOffsetY.ToString("R", CultureInfo.InvariantCulture), _save.selectedRadarOffsetZ.ToString("R", CultureInfo.InvariantCulture)); } if (_save.hasCruisePower) { yield return string.Join("|", "CRUISEPOWER", _save.cruisePower.ToString("0.0", CultureInfo.InvariantCulture)); } if (_save.hasOriginalHealth) { yield return string.Join("|", "ORIGINALHEALTH", _save.originalHealth.ToString("R", CultureInfo.InvariantCulture)); } if (_save.hasOriginalFuel) { yield return string.Join("|", "ORIGINALFUEL", _save.originalFuel.ToString("R", CultureInfo.InvariantCulture)); } for (int i = 0; i < _save.boats.Count; i++) { BoatSaveRecord record = _save.boats[i]; yield return string.Join("|", record.id ?? string.Empty, EncodeText(record.ownerId), EncodeText(record.boatName), record.x.ToString("R", CultureInfo.InvariantCulture), record.y.ToString("R", CultureInfo.InvariantCulture), record.z.ToString("R", CultureInfo.InvariantCulture), record.qx.ToString("R", CultureInfo.InvariantCulture), record.qy.ToString("R", CultureInfo.InvariantCulture), record.qz.ToString("R", CultureInfo.InvariantCulture), record.qw.ToString("R", CultureInfo.InvariantCulture), record.leftBehind ? "1" : "0", record.leavingBoatModel ? "1" : "0", record.motorIndex.ToString(CultureInfo.InvariantCulture), record.radarVisible ? "1" : "0", record.radarUnlocked ? "1" : "0", record.radarOffsetX.ToString("R", CultureInfo.InvariantCulture), record.radarOffsetY.ToString("R", CultureInfo.InvariantCulture), record.radarOffsetZ.ToString("R", CultureInfo.InvariantCulture), record.skinIndex.ToString(CultureInfo.InvariantCulture), record.skinStyleMode.ToString(CultureInfo.InvariantCulture), record.stripeSecondarySkinIndex.ToString(CultureInfo.InvariantCulture), record.health.ToString("R", CultureInfo.InvariantCulture), record.fuel.ToString("R", CultureInfo.InvariantCulture), record.controlSkinIndex.ToString(CultureInfo.InvariantCulture), record.motorSkinIndex.ToString(CultureInfo.InvariantCulture), record.radarSkinIndex.ToString(CultureInfo.InvariantCulture), record.motorMountUsesControls ? "1" : "0", record.motorFinishMode.ToString(CultureInfo.InvariantCulture)); } } private static BoatSaveFile DeserializeSave(string[] lines) { BoatSaveFile boatSaveFile = new BoatSaveFile(); for (int i = 0; i < lines.Length; i++) { string[] array = lines[i].Split('|'); float result19; float result20; float result21; float result22; float result23; float result24; float result25; if (array.Length == 4 && array[0] == "ANCHOR") { if (float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { boatSaveFile.hasAnchor = true; boatSaveFile.anchorX = result; boatSaveFile.anchorY = result2; boatSaveFile.anchorZ = result3; } } else if (array.Length == 2 && array[0] == "MOTOR") { if (byte.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result4)) { boatSaveFile.hasSelectedMotor = true; boatSaveFile.selectedMotorIndex = result4; } } else if (array.Length == 2 && array[0] == "RADAR") { boatSaveFile.hasSelectedRadar = true; boatSaveFile.selectedRadarVisible = array[1] == "1"; } else if (array.Length == 4 && array[0] == "SELECTEDSKIN") { if (byte.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result5) && byte.TryParse(array[2], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result6) && byte.TryParse(array[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result7)) { boatSaveFile.hasSelectedSkin = true; boatSaveFile.selectedSkinIndex = result5; boatSaveFile.selectedSkinStyleMode = result6; boatSaveFile.selectedStripeSecondarySkinIndex = result7; } } else if (array.Length == 2 && array[0] == "SELECTEDCONTROLSKIN") { if (byte.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result8)) { boatSaveFile.hasSelectedControlSkin = true; boatSaveFile.selectedControlSkinIndex = BoatControlSkinRouting.NormalizeSkinIndex(result8); } } else if (array.Length == 2 && array[0] == "SELECTEDMOTORSKIN") { if (byte.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result9)) { boatSaveFile.hasSelectedMotorSkin = true; boatSaveFile.selectedMotorSkinIndex = BoatMotorSkinRouting.NormalizeSkinIndex(result9); } } else if (array.Length == 2 && array[0] == "SELECTEDMOTORFINISH") { if (byte.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result10)) { boatSaveFile.hasSelectedMotorFinish = true; boatSaveFile.selectedMotorFinish = BoatMotorSkinRouting.NormalizeFinishMode(result10); } } else if (array.Length == 2 && array[0] == "SELECTEDMOTORMOUNT") { boatSaveFile.hasSelectedMotorMountMode = true; boatSaveFile.selectedMotorMountUsesControls = array[1] == "1"; } else if (array.Length == 2 && array[0] == "SELECTEDRADARSKIN") { if (byte.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result11)) { boatSaveFile.hasSelectedRadarSkin = true; boatSaveFile.selectedRadarSkinIndex = BoatRadarSkinRouting.NormalizeSkinIndex(result11); } } else if (array.Length == 4 && array[0] == "RADARPOS") { if (float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result12) && float.TryParse(array[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result13) && float.TryParse(array[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result14)) { boatSaveFile.hasSelectedRadarPosition = true; boatSaveFile.selectedRadarOffsetX = result12; boatSaveFile.selectedRadarOffsetY = result13; boatSaveFile.selectedRadarOffsetZ = result14; } } else if (array.Length == 2 && array[0] == "CRUISEPOWER") { if (float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result15)) { boatSaveFile.hasCruisePower = true; boatSaveFile.cruisePower = Mathf.Round(Mathf.Clamp(result15, 0f, 2f) * 10f) * 0.1f; } } else if (array.Length == 2 && array[0] == "ORIGINALCOOKNESS") { if (float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result16)) { boatSaveFile.hasOriginalCookness = true; boatSaveFile.originalCookness = Mathf.Clamp01(result16); } } else if (array.Length == 2 && array[0] == "ORIGINALHEALTH") { if (float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result17)) { boatSaveFile.hasOriginalHealth = true; boatSaveFile.originalHealth = Mathf.Clamp(result17, 0f, 7500f); } } else if (array.Length == 2 && array[0] == "ORIGINALFUEL") { if (float.TryParse(array[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result18)) { boatSaveFile.hasOriginalFuel = true; boatSaveFile.originalFuel = Mathf.Clamp(result18, 0f, 5f); } } else if (array.Length >= 10 && float.TryParse(array[3], NumberStyles.Float, CultureInfo.InvariantCulture, out result19) && float.TryParse(array[4], NumberStyles.Float, CultureInfo.InvariantCulture, out result20) && float.TryParse(array[5], NumberStyles.Float, CultureInfo.InvariantCulture, out result21) && float.TryParse(array[6], NumberStyles.Float, CultureInfo.InvariantCulture, out result22) && float.TryParse(array[7], NumberStyles.Float, CultureInfo.InvariantCulture, out result23) && float.TryParse(array[8], NumberStyles.Float, CultureInfo.InvariantCulture, out result24) && float.TryParse(array[9], NumberStyles.Float, CultureInfo.InvariantCulture, out result25)) { boatSaveFile.boats.Add(new BoatSaveRecord { id = array[0], ownerId = DecodeText(array[1]), boatName = DecodeText(array[2]), x = result19, y = result20, z = result21, qx = result22, qy = result23, qz = result24, qw = result25, leftBehind = (array.Length >= 11 && array[10] == "1"), leavingBoatModel = (array.Length >= 12 && array[11] == "1"), motorIndex = ParseSavedMotorIndex(array), radarVisible = (array.Length >= 14 && array[13] == "1"), radarUnlocked = ((array.Length >= 15) ? (array[14] == "1") : (array.Length >= 14 && array[13] == "1")), radarOffsetX = ParseSavedRadarOffset(array, 15, allowLegacySideOffset: false), radarOffsetY = ParseSavedRadarOffset(array, 16, allowLegacySideOffset: false), radarOffsetZ = ParseSavedRadarOffset(array, (array.Length >= 18) ? 17 : 15, allowLegacySideOffset: true), skinIndex = ParseSavedSkinIndex(array), skinStyleMode = ParseSavedSkinStyleMode(array), stripeSecondarySkinIndex = ParseSavedStripeSecondarySkinIndex(array), health = ParseSavedHealth(array), fuel = ParseSavedFuel(array), controlSkinIndex = (byte)((array.Length >= 24) ? BoatControlSkinRouting.ParseSavedSkinIndex(array[23]) : 14), motorSkinIndex = ((array.Length >= 25) ? BoatMotorSkinRouting.ParseSavedSkinIndex(array[24]) : byte.MaxValue), radarSkinIndex = ((array.Length >= 26) ? BoatRadarSkinRouting.ParseSavedSkinIndex(array[25]) : byte.MaxValue), motorMountUsesControls = (array.Length >= 27 && array[26] == "1"), motorFinishMode = (byte)((array.Length >= 28) ? BoatMotorSkinRouting.ParseSavedFinishMode(array[27]) : 0), cookness = 1f }); } } return boatSaveFile; } private static byte ParseSavedSkinIndex(string[] parts) { if (parts != null && parts.Length >= 19 && byte.TryParse(parts[18], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return result; } return 0; } private static byte ParseSavedSkinStyleMode(string[] parts) { if (parts != null && parts.Length >= 20 && byte.TryParse(parts[19], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return result; } return 0; } private static byte ParseSavedStripeSecondarySkinIndex(string[] parts) { if (parts != null && parts.Length >= 21 && byte.TryParse(parts[20], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return result; } return 14; } private static float ParseSavedCookness(string[] parts) { if (parts != null && parts.Length >= 23 && float.TryParse(parts[22], NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { if (result <= 0.001f) { return 1f; } return Mathf.Clamp(result, 0.1f, 1.5f); } return 0f; } private static float ParseSavedHealth(string[] parts) { if (parts != null && parts.Length >= 22 && float.TryParse(parts[21], NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return Mathf.Clamp(result, 0f, 7500f); } return 7500f; } private static float ParseSavedFuel(string[] parts) { if (parts != null && parts.Length >= 23 && float.TryParse(parts[22], NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return Mathf.Clamp(result, 0f, 5f); } return 5f; } private static float ParseSavedRadarOffset(string[] parts, int index, bool allowLegacySideOffset) { if (parts == null) { return 0f; } if (allowLegacySideOffset && parts.Length == 16) { index = 15; } if (index >= 0 && index < parts.Length && float.TryParse(parts[index], NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return result; } return 0f; } private static byte ParseSavedMotorIndex(string[] parts) { if (parts != null && parts.Length >= 13 && byte.TryParse(parts[12], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return result; } return 0; } private void RememberCustomBoatRadarSkin(Boat boat, byte radarSkinIndex) { if ((Object)(object)boat == (Object)null || _save == null || _save.boats == null) { return; } foreach (KeyValuePair pair in _savedBoats) { if ((Object)(object)pair.Value != (Object)(object)boat) { continue; } BoatSaveRecord boatSaveRecord = _save.boats.Find((BoatSaveRecord item) => item != null && item.id == pair.Key); if (boatSaveRecord != null) { boatSaveRecord.radarSkinIndex = BoatRadarSkinRouting.NormalizeSkinIndex(radarSkinIndex); } break; } } private void RememberSelectedRadarSkin(Boat boat) { if ((Object)(object)boat == (Object)null) { return; } bool flag = false; foreach (Boat value in _savedBoats.Values) { if ((Object)(object)value == (Object)(object)boat) { flag = true; break; } } if (!flag) { _save.hasSelectedRadarSkin = true; _save.selectedRadarSkinIndex = BoatRadarSkinRouting.GetSkinIndex(boat); } } private void RestoreSelectedRadarSkinIfNeeded() { if (!_save.hasSelectedRadarSkin || !InstanceFinder.IsServerStarted || (Object)(object)BoatManager.Instance == (Object)null) { return; } HashSet hashSet = new HashSet(); foreach (Boat value in _savedBoats.Values) { if ((Object)(object)value != (Object)null) { hashSet.Add(value); } } Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Boat val in array) { if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).IsSpawned && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy && !hashSet.Contains(val) && !_restoringCustomBoats.Contains(val) && !IsSavedCustomBoatName(((Object)val).name)) { BoatRadarSkinRouting.EnsureDesiredSkin(val, _save.selectedRadarSkinIndex); } } } private void RememberSelectedRadar(bool visible, bool saveImmediately) { _save.hasSelectedRadar = true; _save.selectedRadarVisible = visible; if (saveImmediately && InstanceFinder.IsServerStarted && _savePath != null) { SaveBoats(); } } private IEnumerator ReapplyControlsAfterMotorChange(Boat boat) { if ((Object)(object)boat == (Object)null) { yield break; } int[] frameDelays = new int[6] { 0, 1, 3, 8, 15, 30 }; int previousFrame = 0; foreach (int targetFrame in frameDelays) { for (int frame = previousFrame; frame < targetFrame; frame++) { yield return null; } previousFrame = targetFrame; if ((Object)(object)boat == (Object)null || !((NetworkBehaviour)boat).IsSpawned) { break; } byte selectedControlSkin = BoatControlSkinRouting.GetSkinIndex(boat); if (selectedControlSkin != byte.MaxValue) { BoatControlSkinRouting.ApplySkin(boat, selectedControlSkin); } else { BoatControlSkinRouting.EnsureDesiredSkin(boat, selectedControlSkin); } } } private void RememberSelectedMotor(byte motorIndex, bool saveImmediately) { _save.hasSelectedMotor = true; _save.selectedMotorIndex = motorIndex; if (saveImmediately && InstanceFinder.IsServerStarted && _savePath != null) { SaveBoats(); } } private void RememberCruisePower(float power) { if (_save != null) { _save.hasCruisePower = true; _save.cruisePower = Mathf.Round(Mathf.Clamp(power, 0f, 2f) * 10f) * 0.1f; if (InstanceFinder.IsServerStarted && _savePath != null) { SaveBoats(); } } } private void RememberSelectedSkin(Boat boat) { if (!((Object)(object)boat == (Object)null)) { Boat cachedOriginalBoat = GetCachedOriginalBoat(); if (!((Object)(object)cachedOriginalBoat == (Object)null) && !((Object)(object)boat != (Object)(object)cachedOriginalBoat)) { _save.hasSelectedSkin = true; _save.selectedSkinIndex = BoatSkinRouting.GetSkinIndex(boat); _save.selectedSkinStyleMode = BoatSkinRouting.GetStyleMode(boat); _save.selectedStripeSecondarySkinIndex = BoatSkinRouting.GetStripeSecondarySkinIndex(boat); _selectedSkinRestored = false; } } } private void RememberMotorFinish(Boat boat) { if ((Object)(object)boat == (Object)null || _save == null) { return; } byte finishMode = BoatMotorSkinRouting.GetFinishMode(boat); foreach (KeyValuePair pair in _savedBoats) { if ((Object)(object)pair.Value != (Object)(object)boat) { continue; } BoatSaveRecord boatSaveRecord = _save.boats.Find((BoatSaveRecord item) => item != null && item.id == pair.Key); if (boatSaveRecord != null) { boatSaveRecord.motorFinishMode = BoatMotorSkinRouting.NormalizeFinishMode(finishMode); } return; } _save.hasSelectedMotorFinish = true; _save.selectedMotorFinish = BoatMotorSkinRouting.NormalizeFinishMode(finishMode); } private void RememberSelectedMotorSkin(Boat boat) { if ((Object)(object)boat == (Object)null) { return; } bool flag = false; foreach (Boat value in _savedBoats.Values) { if ((Object)(object)value == (Object)(object)boat) { flag = true; break; } } if (!flag) { _save.hasSelectedMotorSkin = true; _save.selectedMotorSkinIndex = BoatMotorSkinRouting.GetSkinIndex(boat); } } private void RestoreSelectedMotorSkinIfNeeded() { if (!_save.hasSelectedMotorSkin || !InstanceFinder.IsServerStarted || (Object)(object)BoatManager.Instance == (Object)null) { return; } HashSet hashSet = new HashSet(_savedBoats.Values); Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Boat val in array) { if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).IsSpawned && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy && !hashSet.Contains(val) && !_restoringCustomBoats.Contains(val) && !IsSavedCustomBoatName(((Object)val).name)) { if (_save.hasSelectedMotorFinish) { BoatMotorSkinRouting.SetFinishMode(val, _save.selectedMotorFinish, reapplySkin: false); } BoatMotorSkinRouting.EnsureDesiredSkin(val, _save.selectedMotorSkinIndex); if (_save.hasSelectedControlSkin) { BoatControlSkinRouting.EnsureDesiredSkin(val, _save.selectedControlSkinIndex); } } } } private void RememberCustomBoatControlSkin(Boat boat, byte controlSkinIndex) { if ((Object)(object)boat == (Object)null || _save == null || _save.boats == null) { return; } foreach (KeyValuePair pair in _savedBoats) { if ((Object)(object)pair.Value != (Object)(object)boat) { continue; } BoatSaveRecord boatSaveRecord = _save.boats.Find((BoatSaveRecord item) => item != null && item.id == pair.Key); if (boatSaveRecord != null) { boatSaveRecord.controlSkinIndex = BoatControlSkinRouting.NormalizeSkinIndex(controlSkinIndex); } break; } } private bool IsSavedCustomBoatName(string boatName) { if (string.IsNullOrWhiteSpace(boatName) || _save == null || _save.boats == null) { return false; } string a = boatName.Trim(); for (int i = 0; i < _save.boats.Count; i++) { BoatSaveRecord boatSaveRecord = _save.boats[i]; if (boatSaveRecord != null) { string b = NormalizeCustomBoatName(boatSaveRecord.boatName, i + 1); if (string.Equals(a, b, StringComparison.Ordinal)) { return true; } } } return false; } private void RememberMotorMountMode(Boat boat) { if ((Object)(object)boat == (Object)null || _save == null) { return; } foreach (KeyValuePair pair in _savedBoats) { if ((Object)(object)pair.Value != (Object)(object)boat) { continue; } BoatSaveRecord boatSaveRecord = _save.boats.Find((BoatSaveRecord item) => item != null && item.id == pair.Key); if (boatSaveRecord != null) { boatSaveRecord.motorMountUsesControls = BoatControlSkinRouting.IsMotorMountUsingControls(boat); } return; } _save.hasSelectedMotorMountMode = true; _save.selectedMotorMountUsesControls = BoatControlSkinRouting.IsMotorMountUsingControls(boat); _selectedMotorMountRestored = true; _selectedMotorMountRestoredBoat = boat; } private void RestoreSelectedMotorMountModeIfNeeded() { if (!_save.hasSelectedMotorMountMode || !InstanceFinder.IsServerStarted || (Object)(object)BoatManager.Instance == (Object)null) { return; } Boat cachedOriginalBoat = GetCachedOriginalBoat(); if ((Object)(object)cachedOriginalBoat == (Object)null || !((NetworkBehaviour)cachedOriginalBoat).IsSpawned) { _selectedMotorMountRestored = false; _selectedMotorMountRestoredBoat = null; return; } bool selectedMotorMountUsesControls = _save.selectedMotorMountUsesControls; if ((Object)(object)_selectedMotorMountRestoredBoat != (Object)(object)cachedOriginalBoat || !_selectedMotorMountRestored || BoatControlSkinRouting.IsMotorMountUsingControls(cachedOriginalBoat) != selectedMotorMountUsesControls) { BoatControlSkinRouting.SetMotorMountMode(cachedOriginalBoat, selectedMotorMountUsesControls, reapplyControls: true); _selectedMotorMountRestored = true; _selectedMotorMountRestoredBoat = cachedOriginalBoat; } } private void RememberSelectedControlSkin(Boat boat) { if (!((Object)(object)boat == (Object)null)) { Boat cachedOriginalBoat = GetCachedOriginalBoat(); if (!((Object)(object)cachedOriginalBoat == (Object)null) && !((Object)(object)boat != (Object)(object)cachedOriginalBoat)) { _save.hasSelectedControlSkin = true; _save.selectedControlSkinIndex = BoatControlSkinRouting.GetSkinIndex(boat); _selectedControlSkinRestored = false; _selectedControlSkinRestoredBoat = null; } } } private void RestoreSelectedControlSkinIfNeeded() { if (!_save.hasSelectedControlSkin || !InstanceFinder.IsServerStarted || (Object)(object)BoatManager.Instance == (Object)null) { return; } Boat cachedOriginalBoat = GetCachedOriginalBoat(); if ((Object)(object)cachedOriginalBoat == (Object)null || !((NetworkBehaviour)cachedOriginalBoat).IsSpawned) { _selectedControlSkinRestored = false; _selectedControlSkinRestoredBoat = null; return; } byte skinIndex = BoatControlSkinRouting.NormalizeSkinIndex(_save.selectedControlSkinIndex); bool flag = BoatControlSkinRouting.IsSkinActuallyApplied(cachedOriginalBoat, skinIndex); if ((Object)(object)_selectedControlSkinRestoredBoat != (Object)(object)cachedOriginalBoat || !_selectedControlSkinRestored || !flag) { BoatControlSkinRouting.EnsureDesiredSkin(cachedOriginalBoat, skinIndex); if (BoatControlSkinRouting.IsSkinActuallyApplied(cachedOriginalBoat, skinIndex)) { _selectedControlSkinRestored = true; _selectedControlSkinRestoredBoat = cachedOriginalBoat; } else { _selectedControlSkinRestored = false; _selectedControlSkinRestoredBoat = null; } } } private void RestoreSelectedSkinIfNeeded() { if (_selectedSkinRestored || !_save.hasSelectedSkin || !InstanceFinder.IsServerStarted || (Object)(object)BoatManager.Instance == (Object)null) { return; } Boat cachedOriginalBoat = GetCachedOriginalBoat(); if ((Object)(object)cachedOriginalBoat == (Object)null) { return; } byte b = _save.selectedSkinIndex; if (b > 64) { b = 0; } BoatSkinRouting.SetSavedFinish(cachedOriginalBoat, _save.selectedSkinStyleMode); BoatSkinRouting.SetSavedStripeSecondarySkin(cachedOriginalBoat, _save.selectedStripeSecondarySkinIndex); if (BoatSkinRouting.ApplySkin(cachedOriginalBoat, b)) { _selectedSkinRestored = true; if ((_save.selectedSkinStyleMode == 6 || _save.selectedSkinStyleMode == 8) && b > 13) { ((MonoBehaviour)this).StartCoroutine(RebuildOriginalSpecialFinishAfterLoad(cachedOriginalBoat, b, _save.selectedSkinStyleMode)); } } } private IEnumerator RebuildOriginalSpecialFinishAfterLoad(Boat boat, byte skinIndex, byte styleMode) { if (styleMode != 6 && styleMode != 8) { yield break; } for (int readyFrame = 0; readyFrame < 180; readyFrame++) { if (!((Object)(object)boat == (Object)null) && ((NetworkBehaviour)boat).IsSpawned && BoatSkinRouting.AreSkinRenderersReady(boat)) { break; } yield return null; } if ((Object)(object)boat == (Object)null || !((NetworkBehaviour)boat).IsSpawned) { yield break; } for (int retry = 0; retry < 6; retry++) { for (int settleFrame = 0; settleFrame < 15; settleFrame++) { yield return null; } if ((Object)(object)boat == (Object)null || !((NetworkBehaviour)boat).IsSpawned) { break; } BoatSkinRouting.SetSavedFinish(boat, styleMode); BoatSkinRouting.RebuildSavedSpecialFinishLikeManualSelection(boat, skinIndex); } } private void RestoreSelectedRadarPositionIfNeeded() { //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) if (!_save.hasSelectedRadarPosition || !InstanceFinder.IsServerStarted || (Object)(object)BoatManager.Instance == (Object)null) { return; } Vector3 offset = default(Vector3); ((Vector3)(ref offset))..ctor(_save.selectedRadarOffsetX, _save.selectedRadarOffsetY, _save.selectedRadarOffsetZ); HashSet hashSet = new HashSet(); foreach (Boat value in _savedBoats.Values) { if ((Object)(object)value != (Object)null) { hashSet.Add(value); } } Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); bool selectedRadarPositionRestored = false; foreach (Boat val in array) { if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).IsSpawned && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy && !hashSet.Contains(val) && !_restoringCustomBoats.Contains(val)) { if (!BoatGpsRouting.IsRadarOffsetApplied(val, offset)) { BoatGpsRouting.SetRadarOffset(val, offset); } if (BoatGpsRouting.IsRadarOffsetApplied(val, offset)) { selectedRadarPositionRestored = true; } } } _selectedRadarPositionRestored = selectedRadarPositionRestored; } private void RestoreOriginalHealthIfNeeded() { if (!_originalHealthRestored && _save != null && _save.hasOriginalHealth && InstanceFinder.IsServerStarted) { Boat cachedOriginalBoat = GetCachedOriginalBoat(); if (!((Object)(object)cachedOriginalBoat == (Object)null) && ((NetworkBehaviour)cachedOriginalBoat).IsSpawned) { BoatDamageRouting.SetSavedHealth(cachedOriginalBoat, _save.originalHealth); _originalHealthRestored = true; } } } private void RestoreOriginalFuelIfNeeded() { if (!_originalFuelRestored && _save != null && InstanceFinder.IsServerStarted) { Boat cachedOriginalBoat = GetCachedOriginalBoat(); if (!((Object)(object)cachedOriginalBoat == (Object)null) && ((NetworkBehaviour)cachedOriginalBoat).IsSpawned) { BoatFuelRouting.SetFuel(cachedOriginalBoat, _save.hasOriginalFuel ? _save.originalFuel : 1.5f); _originalFuelRestored = true; } } } private void RestoreOriginalCooknessIfNeeded() { if (!_originalCooknessRestored && _save != null && _save.hasOriginalCookness && InstanceFinder.IsServerStarted) { Boat cachedOriginalBoat = GetCachedOriginalBoat(); if (!((Object)(object)cachedOriginalBoat == (Object)null) && ((NetworkBehaviour)cachedOriginalBoat).IsSpawned) { BoatCookingRouting.SetSavedCookness(cachedOriginalBoat, _save.originalCookness); _originalCooknessRestored = true; } } } private void RestoreSelectedMotorIfNeeded() { if (!_selectedMotorRestored && _save.hasSelectedMotor && InstanceFinder.IsServerStarted && !((Object)(object)BoatManager.Instance == (Object)null) && !((Object)(object)BoatManager.Boat == (Object)null) && ((NetworkBehaviour)BoatManager.Boat).IsSpawned) { _selectedMotorRestored = true; MotorRouting.ApplyMotor(BoatManager.Boat, _save.selectedMotorIndex); if (_save.hasSelectedRadar) { BoatGpsRouting.SetVisible(BoatManager.Boat, _save.selectedRadarVisible); } } } private static string EncodeText(string value) { return Convert.ToBase64String(Encoding.UTF8.GetBytes(value ?? string.Empty)); } private static string DecodeText(string value) { try { return Encoding.UTF8.GetString(Convert.FromBase64String(value)); } catch { return string.Empty; } } } internal sealed class SkinKeywordNoiseLogHandler : ILogHandler { private readonly ILogHandler _inner; internal SkinKeywordNoiseLogHandler(ILogHandler inner) { _inner = inner; } private static bool ShouldSuppress(LogType logType, string message) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) if ((int)logType != 0 || string.IsNullOrEmpty(message)) { return false; } if (message.IndexOf("comes from a different shader", StringComparison.OrdinalIgnoreCase) < 0) { return false; } return message.IndexOf("Local keyword _SKIN_TYPE_", StringComparison.Ordinal) >= 0 || message.IndexOf("Local keyword _SKIN_AFFECTS_", StringComparison.Ordinal) >= 0; } public void LogFormat(LogType logType, Object context, string format, params object[] args) { //IL_002f: 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) string message = format; try { if (args != null && args.Length != 0) { message = string.Format(CultureInfo.InvariantCulture, format, args); } } catch { message = format; } if (!ShouldSuppress(logType, message) && _inner != null) { _inner.LogFormat(logType, context, format, args); } } public void LogException(Exception exception, Object context) { if (_inner != null) { _inner.LogException(exception, context); } } } [Serializable] internal sealed class BoatSaveFile { public List boats = new List(); public bool hasAnchor; public float anchorX; public float anchorY; public float anchorZ; public bool hasSelectedMotor; public byte selectedMotorIndex; public bool hasSelectedRadar; public bool selectedRadarVisible; public bool hasSelectedSkin; public byte selectedSkinIndex; public byte selectedSkinStyleMode; public byte selectedStripeSecondarySkinIndex = 14; public bool hasSelectedControlSkin; public byte selectedControlSkinIndex = 14; public bool hasSelectedMotorMountMode; public bool selectedMotorMountUsesControls; public bool hasSelectedMotorSkin; public byte selectedMotorSkinIndex = byte.MaxValue; public bool hasSelectedMotorFinish; public byte selectedMotorFinish; public bool hasSelectedRadarSkin; public byte selectedRadarSkinIndex = byte.MaxValue; public bool hasSelectedRadarPosition; public float selectedRadarOffsetX; public float selectedRadarOffsetY; public float selectedRadarOffsetZ; public bool hasCruisePower; public float cruisePower = 1f; public bool hasOriginalHealth; public float originalHealth = 7500f; public bool hasOriginalFuel; public float originalFuel = 1.5f; public bool hasOriginalCookness; public float originalCookness = 1f; } [Serializable] internal sealed class BoatSaveRecord { public string id; public string ownerId; public string boatName; public float x; public float y; public float z; public float qx; public float qy; public float qz; public float qw = 1f; public bool leftBehind; public bool leavingBoatModel; public byte motorIndex; public byte skinIndex; public byte skinStyleMode; public byte stripeSecondarySkinIndex; public byte controlSkinIndex = 14; public byte motorSkinIndex = byte.MaxValue; public byte motorFinishMode; public byte radarSkinIndex = byte.MaxValue; public bool motorMountUsesControls; public bool skinMetallic; public bool radarVisible; public bool radarUnlocked; public float radarOffsetX; public float radarOffsetY; public float radarOffsetZ; public float health = 7500f; public float fuel = 5f; public float cookness = 1f; } internal static class BoatRouting { internal static void ReleaseOtherBoat(Player player, Boat selectedBoat) { if ((Object)(object)player == (Object)null) { return; } Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Boat val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)selectedBoat) && !((Object)(object)val.Driver != (Object)(object)player)) { Plugin.StopBoatInputAndMotion(val, stopMotion: false); val.TrySetDriver((Player)null); } } } internal static Boat FindBestBoat(Player player) { //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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)player.Transform == (Object)null) { return null; } Boat contextBoatNearPlayer = BoatClosestPhysicsRouting.GetContextBoatNearPlayer(player, 3f); if ((Object)(object)contextBoatNearPlayer != (Object)null && ((NetworkBehaviour)contextBoatNearPlayer).IsSpawned && contextBoatNearPlayer.BoatUnlocked) { return contextBoatNearPlayer; } Transform transform = player.Transform; Vector3 val = transform.position + Vector3.up; RaycastHit[] array = Physics.RaycastAll(val, transform.forward, 15f, -5, (QueryTriggerInteraction)2); Array.Sort(array, (RaycastHit left, RaycastHit right) => ((RaycastHit)(ref left)).distance.CompareTo(((RaycastHit)(ref right)).distance)); for (int num = 0; num < array.Length; num++) { if (!((Object)(object)((RaycastHit)(ref array[num])).collider == (Object)null) && !BoatHitboxRouting.IsCollisionProxy(((Component)((RaycastHit)(ref array[num])).collider).transform)) { Boat componentInParent = ((Component)((RaycastHit)(ref array[num])).collider).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && ((NetworkBehaviour)componentInParent).IsSpawned && componentInParent.BoatUnlocked) { return componentInParent; } } } Boat result = null; float num2 = float.MaxValue; Boat[] array2 = Object.FindObjectsByType((FindObjectsSortMode)0); Vector3 position = transform.position; foreach (Boat val2 in array2) { if (!((Object)(object)val2 == (Object)null) && ((NetworkBehaviour)val2).IsSpawned && val2.BoatUnlocked) { Vector3 val3 = ((Component)val2).transform.position - position; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude < num2) { num2 = sqrMagnitude; result = val2; } } } return result; } } internal static class BoatCommandRouting { internal const byte ResetSignal = 239; private static Boat _pendingBoat; private static int _resetUntilFrame; internal static bool ResetToDefaultSpawn(Boat boat) { if ((Object)(object)boat == (Object)null) { return false; } Plugin.StopBoatInputAndMotion(boat, stopMotion: true); _pendingBoat = boat; _resetUntilFrame = Time.frameCount + 6; ApplyResetPose(boat); BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(boat), boat); return true; } internal static void UpdatePendingResets() { if ((Object)(object)_pendingBoat == (Object)null || Time.frameCount > _resetUntilFrame) { _pendingBoat = null; } else { ApplyResetPose(_pendingBoat); } } private static void ApplyResetPose(Boat boat) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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) //IL_0014: 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_0037: 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_004b: Unknown result type (might be due to invalid IL or missing references) Vector3 boatSpawnPos = SpawnManager.BoatSpawnPos; Quaternion boatSpawnRot = SpawnManager.BoatSpawnRot; ((Component)boat).transform.SetPositionAndRotation(boatSpawnPos, boatSpawnRot); Rigidbody hiddenPhysicsRig = boat.HiddenPhysicsRig; if ((Object)(object)hiddenPhysicsRig != (Object)null) { hiddenPhysicsRig.position = boatSpawnPos; hiddenPhysicsRig.rotation = boatSpawnRot; hiddenPhysicsRig.linearVelocity = Vector3.zero; hiddenPhysicsRig.angularVelocity = Vector3.zero; hiddenPhysicsRig.WakeUp(); } } } internal static class MotorRouting { internal const byte DualSuperBigMotorRequest = 236; internal const byte SuperBigMotorRequest = 237; internal const byte NoMotorRequest = 238; internal const byte RequestBase = 240; internal const byte DualSuperBigMotorIndex = 253; internal const byte SuperBigMotorIndex = 254; internal const byte NoMotorIndex = byte.MaxValue; private static readonly FieldInfo MotorIndexField = AccessTools.Field(typeof(Boat), "_motorIndex"); private static readonly MethodInfo MotorChangeMethod = AccessTools.Method(typeof(Boat), "OnMotorChange", (Type[])null, (Type[])null); private static readonly FieldInfo CurrentMotorField = AccessTools.Field(typeof(Boat), "_curMotor"); private static readonly FieldInfo MotorsField = AccessTools.Field(typeof(Boat), "_motors"); internal static byte PurchasedMaximum { get; private set; } = 0; internal static void ObservePurchasedMotor(Boat boat) { RefreshPurchasedMaximumFromSave(); } private static void RefreshPurchasedMaximumFromSave() { object obj = AccessTools.Property(typeof(SaveManager), "CurServerSave")?.GetValue(null, null); if (obj == null) { return; } object obj2 = obj.GetType().GetField("MotorIndex", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj); byte b; if (obj2 is byte) { b = (byte)obj2; } else { if (!(obj2 is int)) { return; } b = (byte)Mathf.Clamp((int)obj2, 0, 2); } PurchasedMaximum = (byte)Mathf.Clamp((int)b, 0, 2); } internal static void ObservePurchasedMotor(byte motorIndex) { RefreshPurchasedMaximumFromSave(); } internal static bool IsMotorUnlocked(byte motorIndex) { RefreshPurchasedMaximumFromSave(); if (motorIndex == byte.MaxValue || motorIndex == 254 || motorIndex == 253) { return PurchasedMaximum >= 2; } return motorIndex <= PurchasedMaximum; } internal static bool IsMotorRequest(byte value) { return value == 236 || value == 237 || value == 238 || value >= 240; } internal static byte EncodeMotorRequest(byte motorIndex) { return motorIndex switch { 253 => 236, 254 => 237, byte.MaxValue => 238, _ => (byte)(240 + motorIndex), }; } internal static byte DecodeMotorRequest(byte value) { return value switch { 236 => 253, 237 => 254, 238 => byte.MaxValue, _ => (byte)(value - 240), }; } internal static bool HasNoMotor(Boat boat) { return (Object)(object)boat != (Object)null && boat.MotorIndex == byte.MaxValue; } internal static bool HasSuperBigMotor(Boat boat) { return (Object)(object)boat != (Object)null && boat.MotorIndex == 254; } internal static bool HasDualSuperBigMotors(Boat boat) { return (Object)(object)boat != (Object)null && boat.MotorIndex == 253; } internal static float GetFuelUseMultiplier(Boat boat) { if ((Object)(object)boat == (Object)null || HasNoMotor(boat)) { return 0f; } if (HasSuperBigMotor(boat) || HasDualSuperBigMotors(boat)) { return 1f; } return boat.MotorIndex switch { 0 => 0.5f, 1 => 0.75f, 2 => 1f, _ => 1f, }; } internal static string GetDisplayName(Boat boat) { if ((Object)(object)boat == (Object)null || HasNoMotor(boat)) { return "No Motor"; } if (HasSuperBigMotor(boat)) { return "Super Big Motor"; } if (HasDualSuperBigMotors(boat)) { return "Dual Super Big Motors"; } if (boat.MotorIndex == 0) { return "Default Motor"; } if (boat.MotorIndex == 1) { return "Big Motor"; } return "Dual Motors"; } internal static float GetSelectedMotorMass(Boat boat) { if ((Object)(object)boat == (Object)null || HasNoMotor(boat)) { return 0f; } if (HasSuperBigMotor(boat) || HasDualSuperBigMotors(boat)) { GameObject motorObject = GetMotorObject(boat, 1); float objectRigidbodyMass = GetObjectRigidbodyMass(motorObject, boat.HiddenPhysicsRig); return HasDualSuperBigMotors(boat) ? (objectRigidbodyMass * 2f) : objectRigidbodyMass; } GameObject val = GetCurrentMotorObject(boat); if ((Object)(object)val == (Object)null) { val = GetMotorObject(boat, boat.MotorIndex); } return GetObjectRigidbodyMass(val, boat.HiddenPhysicsRig); } internal static GameObject GetCurrentMotorObject(Boat boat) { if ((Object)(object)boat == (Object)null) { return null; } object obj = CurrentMotorField?.GetValue(boat); GameObject val = (GameObject)((obj is GameObject) ? obj : null); if ((Object)(object)val != (Object)null) { return val; } Component val2 = (Component)((obj is Component) ? obj : null); return ((Object)(object)val2 != (Object)null) ? val2.gameObject : null; } internal static GameObject GetMotorObject(Boat boat, int motorIndex) { if ((Object)(object)boat == (Object)null || motorIndex < 0) { return null; } object obj = MotorsField?.GetValue(boat); if (obj == null) { return null; } PropertyInfo property = obj.GetType().GetProperty("Item", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property == null) { return null; } object obj2; try { obj2 = property.GetValue(obj, new object[1] { motorIndex }); } catch { obj2 = null; } GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null); if ((Object)(object)val != (Object)null) { return val; } Component val2 = (Component)((obj2 is Component) ? obj2 : null); return ((Object)(object)val2 != (Object)null) ? val2.gameObject : null; } private static float GetObjectRigidbodyMass(GameObject root, Rigidbody boatBody) { if ((Object)(object)root == (Object)null) { return 0f; } Rigidbody[] array; try { array = root.GetComponentsInChildren(true); } catch { array = null; } if (array == null || array.Length == 0) { return 0f; } float num = 0f; HashSet hashSet = new HashSet(); foreach (Rigidbody val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)boatBody) && hashSet.Add(val)) { num += Mathf.Max(0f, val.mass); } } return num; } internal static bool TryGetCycledMotor(Boat boat, int direction, out byte motorIndex) { motorIndex = 0; if ((Object)(object)boat == (Object)null) { return false; } RefreshPurchasedMaximumFromSave(); int purchasedMaximum = PurchasedMaximum; if (purchasedMaximum < 1) { return false; } int num2; if (purchasedMaximum < 2) { int num = ((boat.MotorIndex <= purchasedMaximum) ? boat.MotorIndex : purchasedMaximum); num2 = num + direction; if (num2 < 0) { num2 = purchasedMaximum; } else if (num2 > purchasedMaximum) { num2 = 0; } } else if (HasNoMotor(boat)) { num2 = ((direction <= 0) ? 253 : 0); } else if (HasSuperBigMotor(boat)) { num2 = ((direction > 0) ? 253 : purchasedMaximum); } else if (HasDualSuperBigMotors(boat)) { num2 = ((direction > 0) ? 255 : 254); } else { num2 = boat.MotorIndex + direction; if (num2 < 0) { num2 = 255; } else if (num2 > purchasedMaximum) { num2 = 254; } } motorIndex = (byte)num2; return motorIndex != boat.MotorIndex && IsMotorUnlocked(motorIndex); } internal static bool ApplyMotor(Boat boat, byte motorIndex) { if ((Object)(object)boat == (Object)null) { return false; } RefreshPurchasedMaximumFromSave(); if (!IsMotorUnlocked(motorIndex)) { return false; } BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(boat), boat); byte motorIndex2 = boat.MotorIndex; object obj = MotorIndexField?.GetValue(boat); PropertyInfo propertyInfo = obj?.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (propertyInfo == null) { return false; } try { propertyInfo.SetValue(obj, motorIndex, null); } catch { return false; } if (motorIndex2 != motorIndex && MotorChangeMethod != null) { try { MotorChangeMethod.Invoke(boat, new object[3] { motorIndex2, motorIndex, true }); } catch { } } return true; } } internal static class BoatDamageVisualRouting { private sealed class VisualState { internal readonly List Smokes = new List(); internal readonly List Anchors = new List(); internal byte MotorIndex; } private const float SmokeHealthPercent = 0.2f; private const float SmokeHeightAboveMotor = 0.45f; private const float SmokeVisualScale = 0.7f; private static readonly FieldInfo MotorRotationTargetsField = AccessTools.Field(typeof(BoatMotor), "_toRotate"); private static readonly Dictionary States = new Dictionary(); private static bool _templatesResolved; private static ParticleSystem _smokeTemplate; internal static void Update() { ResolveTemplates(); Boat[] array; try { array = Object.FindObjectsByType((FindObjectsSortMode)0); } catch { return; } HashSet hashSet = new HashSet(); if (array != null) { foreach (Boat val in array) { if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).IsSpawned && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { hashSet.Add(val); UpdateBoat(val); } } } if (States.Count == 0) { return; } List list = null; foreach (KeyValuePair state in States) { if (!((Object)(object)state.Key != (Object)null) || !hashSet.Contains(state.Key)) { if (list == null) { list = new List(); } list.Add(state.Key); DestroyState(state.Value); } } if (list != null) { for (int j = 0; j < list.Count; j++) { States.Remove(list[j]); } } } internal static void ClearForBoat(Boat boat) { if (!((Object)(object)boat == (Object)null) && States.TryGetValue(boat, out var value)) { DestroyState(value); States.Remove(boat); } } private static void UpdateBoat(Boat boat) { //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: 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_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null) { return; } float health = BoatDamageRouting.GetHealth(boat); float num = Mathf.Clamp01(health / 7500f); bool flag = BoatDamageRouting.IsSinking(boat); bool flag2 = !MotorRouting.HasNoMotor(boat) && (flag || num <= 0.2f); if (!States.TryGetValue(boat, out var value) || value == null) { if (!flag2) { return; } value = new VisualState(); States[boat] = value; } if (!flag2) { DestroyState(value); States.Remove(boat); return; } List list = ResolveMotorSmokeAnchors(boat); if (list.Count == 0) { DestroySmokeObjects(value); value.Anchors.Clear(); value.MotorIndex = boat.MotorIndex; return; } bool flag3 = value.MotorIndex != boat.MotorIndex || value.Anchors.Count != list.Count; if (!flag3) { for (int i = 0; i < list.Count; i++) { if ((Object)(object)value.Anchors[i] != (Object)(object)list[i]) { flag3 = true; break; } } } if (flag3 || value.Smokes.Count != list.Count) { DestroySmokeObjects(value); value.Anchors.Clear(); for (int j = 0; j < list.Count; j++) { Transform val = list[j]; if (!((Object)(object)val == (Object)null)) { GameObject val2 = CreateGameParticleClone(boat, _smokeTemplate, (list.Count > 1) ? $"Untamo Boat Damage Smoke {j + 1}" : "Untamo Boat Damage Smoke"); if (!((Object)(object)val2 == (Object)null)) { value.Anchors.Add(val); value.Smokes.Add(val2); } } } value.MotorIndex = boat.MotorIndex; } int num2 = Mathf.Min(value.Smokes.Count, value.Anchors.Count); for (int k = 0; k < num2; k++) { GameObject val3 = value.Smokes[k]; Transform val4 = value.Anchors[k]; if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val4 == (Object)null)) { val3.transform.position = val4.position + ((Component)boat).transform.up * 0.45f; val3.transform.rotation = Quaternion.identity; EnsurePlaying(val3); } } } private static List ResolveMotorSmokeAnchors(Boat boat) { List list = new List(); if ((Object)(object)boat == (Object)null || MotorRouting.HasNoMotor(boat)) { return list; } if (MotorRouting.HasDualSuperBigMotors(boat)) { Transform val = FindBoatChildByName(boat, "Untamo Dual Super Big Motor Left"); Transform val2 = FindBoatChildByName(boat, "Untamo Dual Super Big Motor Right"); if ((Object)(object)val != (Object)null) { list.Add(val); } if ((Object)(object)val2 != (Object)null) { list.Add(val2); } if (list.Count > 0) { return list; } } else if (MotorRouting.HasSuperBigMotor(boat)) { Transform val3 = FindBoatChildByName(boat, "Untamo Super Big Motor"); if ((Object)(object)val3 != (Object)null) { list.Add(val3); return list; } } GameObject val4 = MotorRouting.GetCurrentMotorObject(boat); if ((Object)(object)val4 == (Object)null && boat.MotorIndex <= 2) { val4 = MotorRouting.GetMotorObject(boat, boat.MotorIndex); } if ((Object)(object)val4 == (Object)null) { return list; } if (boat.MotorIndex == 2) { BoatMotor val5 = val4.GetComponent(); if ((Object)(object)val5 == (Object)null) { val5 = val4.GetComponentInChildren(true); } Transform[] array = (((Object)(object)val5 == (Object)null) ? null : (MotorRotationTargetsField?.GetValue(val5) as Transform[])); if (array != null) { foreach (Transform val6 in array) { if ((Object)(object)val6 != (Object)null && !list.Contains(val6)) { list.Add(val6); } } } if (list.Count > 0) { return list; } } list.Add(val4.transform); return list; } private static Transform FindBoatChildByName(Boat boat, string exactName) { if ((Object)(object)boat == (Object)null || string.IsNullOrEmpty(exactName)) { return null; } Transform[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } if (array == null) { return null; } foreach (Transform val in array) { if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, exactName, StringComparison.Ordinal)) { return val; } } return null; } private static void ResolveTemplates() { if (_templatesResolved && (Object)(object)_smokeTemplate != (Object)null) { return; } _templatesResolved = true; GrillBox[] array; try { array = Resources.FindObjectsOfTypeAll(); } catch { array = null; } if (array == null) { return; } FieldInfo field = typeof(GrillBox).GetField("_smokeParticles", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (GrillBox val in array) { if (!((Object)(object)val == (Object)null)) { if ((Object)(object)_smokeTemplate == (Object)null) { _smokeTemplate = FindParticleSystemFromField(field, val); } if ((Object)(object)_smokeTemplate != (Object)null) { break; } } } } private static ParticleSystem FindParticleSystemFromField(FieldInfo field, object owner) { if (field == null || owner == null) { return null; } object value; try { value = field.GetValue(owner); } catch { return null; } if (value == null) { return null; } ParticleSystem val = (ParticleSystem)((value is ParticleSystem) ? value : null); if ((Object)(object)val != (Object)null) { return val; } GameObject val2 = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val2 != (Object)null) { return val2.GetComponentInChildren(true); } Component val3 = (Component)((value is Component) ? value : null); if ((Object)(object)val3 != (Object)null) { return val3.GetComponentInChildren(true); } if (value is IEnumerable enumerable) { foreach (object item in enumerable) { ParticleSystem val4 = (ParticleSystem)((item is ParticleSystem) ? item : null); if ((Object)(object)val4 != (Object)null) { return val4; } Component val5 = (Component)((item is Component) ? item : null); if ((Object)(object)val5 != (Object)null) { val4 = val5.GetComponentInChildren(true); if ((Object)(object)val4 != (Object)null) { return val4; } } GameObject val6 = (GameObject)((item is GameObject) ? item : null); if ((Object)(object)val6 != (Object)null) { val4 = val6.GetComponentInChildren(true); if ((Object)(object)val4 != (Object)null) { return val4; } } } } return null; } private static GameObject CreateGameParticleClone(Boat boat, ParticleSystem template, string name) { //IL_0092: 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_00b4: 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) if ((Object)(object)boat == (Object)null || (Object)(object)template == (Object)null || (Object)(object)((Component)template).gameObject == (Object)null) { return null; } Transform val = (((Object)(object)boat.VisualBoat != (Object)null) ? ((Component)boat.VisualBoat).transform : ((Component)boat).transform); GameObject val2; try { val2 = Object.Instantiate(((Component)template).gameObject, val, false); } catch { return null; } if ((Object)(object)val2 == (Object)null) { return null; } ((Object)val2).name = name; val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.transform.localScale = Vector3.one * 0.7f; AudioSource[] componentsInChildren = val2.GetComponentsInChildren(true); if (componentsInChildren != null) { for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null) { componentsInChildren[i].Stop(); ((Behaviour)componentsInChildren[i]).enabled = false; } } } MonoBehaviour[] componentsInChildren2 = val2.GetComponentsInChildren(true); if (componentsInChildren2 != null) { foreach (MonoBehaviour val3 in componentsInChildren2) { if (!((Object)(object)val3 == (Object)null)) { ((Behaviour)val3).enabled = false; } } } val2.SetActive(true); EnsurePlaying(val2); return val2; } private static void EnsurePlaying(GameObject root) { if ((Object)(object)root == (Object)null) { return; } ParticleSystem[] componentsInChildren = root.GetComponentsInChildren(true); if (componentsInChildren == null) { return; } foreach (ParticleSystem val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } try { if (!((Component)val).gameObject.activeSelf) { ((Component)val).gameObject.SetActive(true); } if (!val.isPlaying) { val.Play(true); } } catch { } } } private static void DestroySmokeObjects(VisualState state) { if (state == null) { return; } for (int i = 0; i < state.Smokes.Count; i++) { GameObject val = state.Smokes[i]; if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } state.Smokes.Clear(); } private static void DestroyState(VisualState state) { if (state != null) { DestroySmokeObjects(state); state.Anchors.Clear(); } } } internal static class BoatFuelRouting { private sealed class FuelState { internal float Fuel = 5f; internal float Throttle; internal float BoostFuelMultiplier = 1f; internal float LastInputTime = -10f; } internal const float MaximumFuel = 5f; private const float LitersPerSecondAtFullThrottle = 1f / 75f; private static readonly Dictionary States = new Dictionary(); internal static float GetFuel(Boat boat) { if ((Object)(object)boat == (Object)null) { return 0f; } return GetState(boat).Fuel; } internal static bool HasFuel(Boat boat) { return GetFuel(boat) > 0.0001f; } internal static void SetFuel(Boat boat, float fuel) { if (!((Object)(object)boat == (Object)null)) { FuelState state = GetState(boat); state.Fuel = Mathf.Clamp(fuel, 0f, 5f); if (state.Fuel <= 0.0001f) { state.Fuel = 0f; state.Throttle = 0f; state.BoostFuelMultiplier = 1f; } } } internal static void RecordThrottle(Boat boat, float throttle) { RecordThrottle(boat, throttle, 1f); } internal static void RecordThrottle(Boat boat, float throttle, float boostFuelMultiplier) { if (!((Object)(object)boat == (Object)null)) { FuelState state = GetState(boat); state.Throttle = Mathf.Max(0f, Mathf.Abs(throttle)); state.BoostFuelMultiplier = Mathf.Clamp(boostFuelMultiplier, 1f, 5f); state.LastInputTime = Time.unscaledTime; } } internal static void Update() { if (States.Count == 0) { return; } List list = null; float num = Mathf.Max(0f, Time.unscaledDeltaTime); foreach (KeyValuePair state in States) { Boat key = state.Key; FuelState value = state.Value; if ((Object)(object)key == (Object)null || (Object)(object)((Component)key).gameObject == (Object)null) { if (list == null) { list = new List(); } list.Add(key); } else { if (value == null || value.Fuel <= 0f) { continue; } if (Time.unscaledTime - value.LastInputTime > 0.35f) { value.Throttle = 0f; value.BoostFuelMultiplier = 1f; } else { if (value.Throttle <= 0.001f || MotorRouting.HasNoMotor(key)) { continue; } float fuelUseMultiplier = MotorRouting.GetFuelUseMultiplier(key); if (!(fuelUseMultiplier <= 0f)) { float num2 = 1f / 75f * value.Throttle * fuelUseMultiplier * value.BoostFuelMultiplier * num; value.Fuel = Mathf.Max(0f, value.Fuel - num2); if (value.Fuel <= 0.0001f) { value.Fuel = 0f; value.Throttle = 0f; } } } } } if (list != null) { for (int i = 0; i < list.Count; i++) { States.Remove(list[i]); } } } internal static void ClearForBoat(Boat boat) { if (!((Object)(object)boat == (Object)null)) { BoatDamageVisualRouting.ClearForBoat(boat); States.Remove(boat); } } private static FuelState GetState(Boat boat) { if (!States.TryGetValue(boat, out var value) || value == null) { value = new FuelState(); States[boat] = value; } return value; } } internal static class BoatFleetTextEffectRouting { internal static string WrapColor(string value, Color color) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(value)) { return value ?? string.Empty; } return "" + value + ""; } internal static string BuildAlternatingText(string value, Color first, Color second) { //IL_005e: 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_005f: 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) if (string.IsNullOrEmpty(value)) { return value ?? string.Empty; } StringBuilder stringBuilder = new StringBuilder(value.Length * 28); int num = 0; foreach (char c in value) { if (char.IsWhiteSpace(c)) { stringBuilder.Append(c); continue; } Color val = (((num & 1) == 0) ? first : second); stringBuilder.Append(""); stringBuilder.Append(c); stringBuilder.Append(""); num++; } return stringBuilder.ToString(); } internal static string BuildDripText(string value) { //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_0041: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(value)) { return value ?? string.Empty; } float num = Mathf.Repeat(Time.unscaledTime / 14f, 1f); Color color = Color.HSVToRGB(num, 0.92f, 1f); return WrapColor(value, color); } } internal static class BoatSkinRouting { private const byte MinimumSkinIndex = 0; private const byte MaximumGameSkinIndex = 13; private const byte RedSkinIndex = 14; private const byte BlueSkinIndex = 15; private const byte GreenSkinIndex = 16; private const byte YellowSkinIndex = 17; private const byte OrangeSkinIndex = 18; private const byte PurpleSkinIndex = 19; private const byte PinkSkinIndex = 20; private const byte BrownSkinIndex = 21; private const byte BlackSkinIndex = 22; private const byte WhiteSkinIndex = 23; private const byte GraySkinIndex = 24; private const byte CyanSkinIndex = 25; private const byte MagentaSkinIndex = 26; private const byte TealSkinIndex = 27; private const byte NavySkinIndex = 28; private const byte MaroonSkinIndex = 29; private const byte BeigeSkinIndex = 30; private const byte GoldSkinIndex = 31; private const byte SilverSkinIndex = 32; private const byte CoralSkinIndex = 33; private const byte TurquoiseSkinIndex = 34; private const byte LavenderSkinIndex = 35; private const byte IndigoSkinIndex = 36; private const byte VioletSkinIndex = 37; private const byte MintSkinIndex = 38; private const byte PeachSkinIndex = 39; private const byte CrimsonSkinIndex = 40; private const byte ScarletSkinIndex = 41; private const byte BurgundySkinIndex = 42; private const byte OliveSkinIndex = 43; private const byte LimeSkinIndex = 44; private const byte AquaSkinIndex = 45; private const byte AmberSkinIndex = 46; private const byte IvorySkinIndex = 47; private const byte KhakiSkinIndex = 48; private const byte PlumSkinIndex = 49; private const byte RoseSkinIndex = 50; private const byte RubySkinIndex = 51; private const byte EmeraldSkinIndex = 52; private const byte SapphireSkinIndex = 53; private const byte MustardSkinIndex = 54; private const byte CharcoalSkinIndex = 55; private const byte TanSkinIndex = 56; private const byte CopperSkinIndex = 57; private const byte BronzeSkinIndex = 58; private const byte LilacSkinIndex = 59; private const byte PeriwinkleSkinIndex = 60; private const byte FuchsiaSkinIndex = 61; private const byte SlateSkinIndex = 62; private const byte MochaSkinIndex = 63; private const byte RainbowSkinIndex = 64; internal const byte MaximumSkinIndex = 64; private const string CustomMaterialPrefix = "UntamoBoatSkin_"; private const string SkinDumpFolderName = "Untamo_Boats_Skins"; private static readonly Dictionary PreStripesSkinSlots = new Dictionary(); private static readonly Dictionary CustomSkinSlots = new Dictionary(); private static readonly Dictionary LastCustomSkinSlots = new Dictionary(); private static readonly Dictionary LastCustomStyleModes = new Dictionary(); private static readonly Dictionary LastCustomStripeSecondarySkinSlots = new Dictionary(); private const byte FinishModeWood = 0; private const byte FinishModeMetallic = 1; private const byte FinishModeCamo = 2; private const byte FinishModeCamoMetallic = 3; private const byte FinishModeStripes = 4; private const byte FinishModeStripesMetallic = 5; private const byte FinishModeGlass = 6; private const byte FinishModeChrome = 7; private const byte FinishModeMatte = 8; private const byte FinishModeControlsMaterial = 9; private const byte MaximumFinishMode = 9; private static readonly Dictionary SkinStyleModes = new Dictionary(); private static readonly Dictionary StripeSecondarySkinSlots = new Dictionary(); private static readonly Dictionary> OriginalMaterials = new Dictionary>(); private static readonly Dictionary TintedTextureCache = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary ProceduralCamoTextureCache = new Dictionary(StringComparer.Ordinal); private static float _nextCustomRefresh; private static Boat _activeMaterialBuildBoat; internal static byte GetSkinIndex(Boat boat) { if ((Object)(object)boat == (Object)null) { return 0; } if (CustomSkinSlots.TryGetValue(boat, out var value)) { return value; } byte curSkin = boat.CurSkin; return (byte)((curSkin <= 13) ? curSkin : 0); } internal static string GetSkinDisplayName(Boat boat) { byte skinIndex = GetSkinIndex(boat); if (skinIndex == 64) { return "Rainbow"; } return skinIndex.ToString(CultureInfo.InvariantCulture); } internal static bool IsRainbowSkin(Boat boat) { return (Object)(object)boat != (Object)null && GetSkinIndex(boat) == 64; } internal static bool IsStripeStyle(Boat boat) { if ((Object)(object)boat == (Object)null) { return false; } return IsStripesStyle(GetStyleMode(boat)); } internal static bool TryGetHudSkinColor(byte skinIndex, out Color color) { //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) color = Color.white; if (skinIndex < 14 || skinIndex >= 64) { return false; } byte baseGameSkin; float tintStrength; return GetCustomSkinProfile(skinIndex, out color, out baseGameSkin, out tintStrength); } internal static byte GetStyleMode(Boat boat) { if ((Object)(object)boat == (Object)null) { return 0; } if (!SkinStyleModes.TryGetValue(boat, out var value)) { return 0; } return NormalizeStyleMode(value); } internal static byte GetStripeSecondarySkinIndex(Boat boat) { if ((Object)(object)boat == (Object)null) { return 14; } if (!StripeSecondarySkinSlots.TryGetValue(boat, out var value)) { return 14; } return NormalizeStripeSecondarySkinIndex(value); } internal static bool IsMetallicFinish(Boat boat) { byte styleMode = GetStyleMode(boat); return styleMode == 1 || styleMode == 3 || styleMode == 5 || styleMode == 7; } internal static string GetFinishHudText(Boat boat) { if ((Object)(object)boat == (Object)null || GetSkinIndex(boat) <= 13) { return string.Empty; } return " " + GetFinishModeName(GetStyleMode(boat)); } internal static string GetStripeSecondaryHudText(Boat boat) { if ((Object)(object)boat == (Object)null || GetSkinIndex(boat) <= 13) { return string.Empty; } byte styleMode = GetStyleMode(boat); if (!IsStripesStyle(styleMode)) { return string.Empty; } return " / " + GetStripeSecondarySkinIndex(boat).ToString(CultureInfo.InvariantCulture); } internal static void SetSavedFinish(Boat boat, byte styleMode) { if (!((Object)(object)boat == (Object)null)) { SkinStyleModes[boat] = NormalizeStyleMode(styleMode); } } internal static void SetSavedStripeSecondarySkin(Boat boat, byte skinIndex) { if (!((Object)(object)boat == (Object)null)) { StripeSecondarySkinSlots[boat] = NormalizeStripeSecondarySkinIndex(skinIndex); } } internal static bool ToggleFinish(Boat boat, int direction, ManualLogSource logger) { if ((Object)(object)boat == (Object)null) { return false; } byte b = GetSkinIndex(boat); if (b <= 13) { if (logger != null) { logger.LogInfo((object)"J finish toggle works on custom skins 14-63."); } return false; } int styleMode = GetStyleMode(boat); if (b == 64) { byte b2 = ((styleMode != 1) ? ((byte)1) : ((byte)0)); SkinStyleModes[boat] = b2; RestoreOriginalMaterials(boat); if (!SetNativeBaseSkin(boat, 0)) { return false; } CustomSkinSlots[boat] = b; bool flag = RebuildCustomSkin(boat, b, captureOriginals: true); if (flag && logger != null) { logger.LogInfo((object)("Rainbow finish: " + GetFinishModeName(b2) + ".")); } return flag; } int num = styleMode; do { num += ((direction >= 0) ? 1 : (-1)); if (num > 9) { num = 0; } else if (num < 0) { num = 9; } } while (num == 6 || num == 8); byte b3 = (byte)num; bool flag2 = IsStripesStyle(b3) && !IsStripesStyle((byte)styleMode); bool flag3 = !IsStripesStyle(b3) && IsStripesStyle((byte)styleMode); byte value; if (flag2 && b == 23) { PreStripesSkinSlots[boat] = 23; b = 24; } else if (flag3 && PreStripesSkinSlots.TryGetValue(boat, out value) && value == 23) { b = 23; PreStripesSkinSlots.Remove(boat); } SkinStyleModes[boat] = b3; RestoreOriginalMaterials(boat); byte styleBaseGameSkin = GetStyleBaseGameSkin(boat); if (!SetNativeBaseSkin(boat, styleBaseGameSkin)) { return false; } CustomSkinSlots[boat] = b; bool flag4 = RebuildCustomSkin(boat, b, captureOriginals: true); if (flag4) { RememberLastCustomSelection(boat); if (logger != null) { logger.LogInfo((object)("Custom skin finish: " + GetFinishModeName(b3) + ".")); } } return flag4; } internal static bool CopySkinFromBoat(Boat source, Boat target) { if ((Object)(object)source == (Object)null || (Object)(object)target == (Object)null) { return false; } byte skinIndex = GetSkinIndex(source); if (skinIndex < 0 || skinIndex > 64) { return false; } if (skinIndex <= 13) { return ApplySkin(target, skinIndex); } byte styleMode = GetStyleMode(source); byte stripeSecondarySkinIndex = GetStripeSecondarySkinIndex(source); SetSavedFinish(target, styleMode); SetSavedStripeSecondarySkin(target, stripeSecondarySkinIndex); return ApplySkin(target, skinIndex); } internal static bool RebuildSavedSpecialFinishLikeManualSelection(Boat boat, byte skinIndex) { if ((Object)(object)boat == (Object)null || skinIndex <= 13) { return false; } byte styleMode = GetStyleMode(boat); if (styleMode != 6 && styleMode != 8) { return false; } RestoreOriginalMaterials(boat); byte styleBaseGameSkin = GetStyleBaseGameSkin(boat); if (!SetNativeBaseSkin(boat, styleBaseGameSkin)) { return false; } CustomSkinSlots[boat] = skinIndex; return RebuildCustomSkin(boat, skinIndex, captureOriginals: true); } internal static bool ToggleStripeSecondaryColor(Boat boat, int direction, ManualLogSource logger) { if ((Object)(object)boat == (Object)null) { return false; } byte skinIndex = GetSkinIndex(boat); if (skinIndex <= 13) { if (logger != null) { logger.LogInfo((object)"Ö stripe color toggle works on custom skins 14-63."); } return false; } byte styleMode = GetStyleMode(boat); if (!IsStripesStyle(styleMode)) { if (logger != null) { logger.LogInfo((object)"Ö changes the second color only in Stripes / Stripes Metallic."); } return false; } byte nextStripeSecondarySkinIndex = GetNextStripeSecondarySkinIndex(GetStripeSecondarySkinIndex(boat), direction); StripeSecondarySkinSlots[boat] = nextStripeSecondarySkinIndex; bool flag = RebuildCustomSkin(boat, skinIndex, captureOriginals: false); if (flag && logger != null) { logger.LogInfo((object)$"Second pattern color slot: {nextStripeSecondarySkinIndex}."); } return flag; } private static byte NormalizeStyleMode(byte mode) { if (mode == 6 || mode == 8) { return 0; } return (byte)((mode <= 9) ? mode : 0); } private static string GetFinishModeName(byte mode) { return NormalizeStyleMode(mode) switch { 1 => "Metallic", 2 => "Camo", 3 => "Camo Metallic", 4 => "Stripes", 5 => "Stripes Metallic", 6 => "Glass", 7 => "Chrome", 8 => "Matte", 9 => "Controls", _ => "Wood", }; } private static byte GetStyleBaseGameSkin(Boat boat) { switch (GetStyleMode(boat)) { case 2: case 3: return 5; case 4: case 5: return 9; default: return 0; } } private static bool IsStripesStyle(byte mode) { return mode == 4 || mode == 5; } private static bool IsCamoStyle(byte mode) { return mode == 2 || mode == 3; } private static bool UsesSecondaryColorStyle(byte mode) { return IsStripesStyle(mode); } private static byte NormalizeStripeSecondarySkinIndex(byte skinIndex) { if (skinIndex < 14 || skinIndex > 64 || skinIndex == 23) { return 14; } return skinIndex; } private static byte GetNextStripeSecondarySkinIndex(byte current, int direction) { current = NormalizeStripeSecondarySkinIndex(current); byte b = current; do { b = (byte)((direction >= 0) ? ((b >= 64) ? 14 : ((byte)(b + 1))) : ((b <= 14) ? 64 : ((byte)(b - 1)))); } while (b == 23); return b; } private static Color GetStripeSecondaryTintColor(Boat boat) { //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_0017: 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_0025: Unknown result type (might be due to invalid IL or missing references) if (GetCustomSkinProfile(GetStripeSecondarySkinIndex(boat), out var color, out var _, out var _)) { return color; } return Color.white; } private static void RememberLastCustomSelection(Boat boat) { if (!((Object)(object)boat == (Object)null) && CustomSkinSlots.TryGetValue(boat, out var value) && value >= 14 && value <= 63) { LastCustomSkinSlots[boat] = value; LastCustomStyleModes[boat] = GetStyleMode(boat); LastCustomStripeSecondarySkinSlots[boat] = GetStripeSecondarySkinIndex(boat); } } private static bool TryPrepareRememberedCustomSelection(Boat boat, out byte skinIndex) { skinIndex = 14; if ((Object)(object)boat == (Object)null) { return false; } if (!LastCustomSkinSlots.TryGetValue(boat, out var value) || value < 14 || value > 63) { return false; } if (LastCustomStyleModes.TryGetValue(boat, out var value2)) { SkinStyleModes[boat] = NormalizeStyleMode(value2); } if (LastCustomStripeSecondarySkinSlots.TryGetValue(boat, out var value3)) { StripeSecondarySkinSlots[boat] = NormalizeStripeSecondarySkinIndex(value3); } skinIndex = value; return true; } internal static bool TryGetCycledSkin(Boat boat, int direction, out byte skinIndex) { skinIndex = 14; if ((Object)(object)boat == (Object)null || direction == 0) { return false; } bool flag = IsStripesStyle(GetStyleMode(boat)); int skinIndex2 = GetSkinIndex(boat); if (skinIndex2 < 14 || skinIndex2 > 63) { skinIndex = (byte)((direction > 0) ? 14 : 63); if (flag && skinIndex == 23) { skinIndex = (byte)((direction > 0) ? 24 : 22); } if (flag) { PreStripesSkinSlots.Remove(boat); } return true; } int num = skinIndex2; do { num += ((direction > 0) ? 1 : (-1)); if (num > 63) { num = 14; } else if (num < 14) { num = 63; } } while (flag && num == 23); skinIndex = (byte)num; if (flag) { PreStripesSkinSlots.Remove(boat); } return skinIndex != GetSkinIndex(boat); } internal static bool AreSkinRenderersReady(Boat boat) { if ((Object)(object)boat == (Object)null) { return false; } Renderer[] componentsInChildren; try { componentsInChildren = ((Component)boat).GetComponentsInChildren(true); } catch { return false; } if (componentsInChildren == null || componentsInChildren.Length == 0) { return false; } HashSet hashSet = FindHullRenderers(componentsInChildren); if (hashSet == null || hashSet.Count == 0) { return false; } foreach (Renderer item in hashSet) { if ((Object)(object)item == (Object)null) { return false; } Material[] sharedMaterials; try { sharedMaterials = item.sharedMaterials; } catch { return false; } if (sharedMaterials == null || sharedMaterials.Length == 0) { return false; } bool flag = false; for (int i = 0; i < sharedMaterials.Length; i++) { if ((Object)(object)sharedMaterials[i] != (Object)null) { flag = true; break; } } if (!flag) { return false; } } return true; } internal static bool ApplySkin(Boat boat, byte skinIndex) { if ((Object)(object)boat == (Object)null) { return false; } if (skinIndex < 0 || skinIndex > 64) { return false; } if (skinIndex <= 13) { RestoreOriginalMaterials(boat); CustomSkinSlots.Remove(boat); SkinStyleModes.Remove(boat); StripeSecondarySkinSlots.Remove(boat); try { boat.ServerSetSkin(skinIndex); return boat.CurSkin == skinIndex; } catch { return false; } } if (!GetCustomSkinProfile(skinIndex, out var _, out var baseGameSkin, out var _)) { return false; } baseGameSkin = GetStyleBaseGameSkin(boat); RestoreOriginalMaterials(boat); if (!SetNativeBaseSkin(boat, baseGameSkin)) { return false; } CustomSkinSlots[boat] = skinIndex; if (!SkinStyleModes.ContainsKey(boat)) { SkinStyleModes[boat] = 0; } if (skinIndex == 64) { byte styleMode = GetStyleMode(boat); if (styleMode != 0 && styleMode != 1) { SkinStyleModes[boat] = 0; } } bool flag = RebuildCustomSkin(boat, skinIndex, captureOriginals: true); if (!flag) { CustomSkinSlots.Remove(boat); } else { RememberLastCustomSelection(boat); } return flag; } internal static void UpdateRainbowSkins() { //IL_0038: 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_01ab: 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) if (CustomSkinSlots.Count == 0) { return; } float num = Mathf.Repeat(Time.unscaledTime / 14f, 1f); Color rainbow = Color.HSVToRGB(num, 0.92f, 1f); foreach (KeyValuePair customSkinSlot in CustomSkinSlots) { if (customSkinSlot.Value != 64) { continue; } Boat key = customSkinSlot.Key; if ((Object)(object)key == (Object)null || (Object)(object)((Component)key).gameObject == (Object)null || !((Component)key).gameObject.activeInHierarchy) { continue; } Renderer[] componentsInChildren; try { componentsInChildren = ((Component)key).GetComponentsInChildren(true); } catch { continue; } if (componentsInChildren == null) { continue; } HashSet hashSet = FindHullRenderers(componentsInChildren); bool metallic = GetStyleMode(key) == 1; foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null || !hashSet.Contains(val)) { continue; } Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { continue; } if (sharedMaterials == null) { continue; } foreach (Material val2 in sharedMaterials) { if (!((Object)(object)val2 == (Object)null) && !string.IsNullOrWhiteSpace(((Object)val2).name) && ((Object)val2).name.StartsWith("UntamoBoatSkin_", StringComparison.Ordinal)) { ApplyRainbowColorToMaterial(val2, rainbow, metallic); } } ApplyRainbowPropertyBlock(val, sharedMaterials, rainbow); } } } private static void ApplyRainbowColorToMaterial(Material material, Color rainbow, bool metallic) { //IL_0029: 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) if ((Object)(object)material == (Object)null) { return; } try { if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", rainbow); } if (material.HasProperty("_Color")) { material.SetColor("_Color", rainbow); } if (material.HasProperty("_Metallic")) { material.SetFloat("_Metallic", metallic ? 0.85f : 0f); } if (material.HasProperty("_Smoothness")) { material.SetFloat("_Smoothness", metallic ? 0.68f : 0.28f); } if (material.HasProperty("_Glossiness")) { material.SetFloat("_Glossiness", metallic ? 0.68f : 0.28f); } } catch { } } private static void ApplyRainbowPropertyBlock(Renderer renderer, Material[] materials, Color rainbow) { //IL_0096: 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_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Invalid comparison between Unknown and I4 //IL_0175: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)renderer == (Object)null || materials == null) { return; } MaterialPropertyBlock val = new MaterialPropertyBlock(); for (int i = 0; i < materials.Length; i++) { Material val2 = materials[i]; if ((Object)(object)val2 == (Object)null || (Object)(object)val2.shader == (Object)null || string.IsNullOrWhiteSpace(((Object)val2).name) || !((Object)val2).name.StartsWith("UntamoBoatSkin_", StringComparison.Ordinal)) { continue; } try { renderer.GetPropertyBlock(val, i); } catch { val.Clear(); } try { val.SetColor("_BaseColor", rainbow); val.SetColor("_Color", rainbow); } catch { } Shader shader = val2.shader; int num; try { num = shader.GetPropertyCount(); } catch { num = 0; } for (int j = 0; j < num; j++) { string propertyName; try { ShaderPropertyType propertyType = shader.GetPropertyType(j); if ((int)propertyType > 0) { continue; } propertyName = shader.GetPropertyName(j); goto IL_0107; } catch { } continue; IL_0107: if (string.IsNullOrWhiteSpace(propertyName)) { continue; } string text = propertyName.ToLowerInvariant(); if (!text.Contains("emission") && !text.Contains("emissive") && !text.Contains("glow") && !text.Contains("cook") && !text.Contains("burn")) { try { val.SetColor(propertyName, rainbow); } catch { } } } try { renderer.SetPropertyBlock(val, i); } catch { } val.Clear(); } } internal static void EnsureSavedFinishMaterialState(Boat boat) { EnsureFinishMaterialState(boat); } internal static void UpdateCustomSkins() { if (CustomSkinSlots.Count == 0 || Time.unscaledTime < _nextCustomRefresh) { return; } _nextCustomRefresh = Time.unscaledTime + 0.2f; List list = null; foreach (KeyValuePair customSkinSlot in CustomSkinSlots) { Boat key = customSkinSlot.Key; Color color; byte baseGameSkin; float tintStrength; if ((Object)(object)key == (Object)null || (Object)(object)((Component)key).gameObject == (Object)null || !((Component)key).gameObject.activeInHierarchy) { if (list == null) { list = new List(); } list.Add(key); } else if (GetCustomSkinProfile(customSkinSlot.Value, out color, out baseGameSkin, out tintStrength)) { baseGameSkin = GetStyleBaseGameSkin(key); bool flag = key.CurSkin != baseGameSkin; if (flag) { RestoreOriginalMaterials(key); SetNativeBaseSkin(key, baseGameSkin); } if (flag || !HasForcedSkinMaterials(key, customSkinSlot.Value)) { RebuildCustomSkin(key, customSkinSlot.Value, captureOriginals: false); } EnsureFinishMaterialState(key); } } if (list == null) { return; } for (int i = 0; i < list.Count; i++) { Boat val = list[i]; CustomSkinSlots.Remove(val); SkinStyleModes.Remove(val); StripeSecondarySkinSlots.Remove(val); if ((Object)(object)val != (Object)null) { OriginalMaterials.Remove(val); } } } internal static void ClearForBoat(Boat boat) { if (!((Object)(object)boat == (Object)null)) { RestoreOriginalMaterials(boat); CustomSkinSlots.Remove(boat); SkinStyleModes.Remove(boat); StripeSecondarySkinSlots.Remove(boat); OriginalMaterials.Remove(boat); } } private static bool GetCustomSkinProfile(byte skinIndex, out Color color, out byte baseGameSkin, out float tintStrength) { //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_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: 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_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: 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_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03cc: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) //IL_040f: Unknown result type (might be due to invalid IL or missing references) //IL_0414: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) //IL_045c: Unknown result type (might be due to invalid IL or missing references) //IL_0482: Unknown result type (might be due to invalid IL or missing references) //IL_0487: Unknown result type (might be due to invalid IL or missing references) //IL_04a6: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04ca: Unknown result type (might be due to invalid IL or missing references) //IL_04cf: Unknown result type (might be due to invalid IL or missing references) //IL_04ee: Unknown result type (might be due to invalid IL or missing references) //IL_04f3: Unknown result type (might be due to invalid IL or missing references) //IL_0519: Unknown result type (might be due to invalid IL or missing references) //IL_051e: Unknown result type (might be due to invalid IL or missing references) //IL_0544: Unknown result type (might be due to invalid IL or missing references) //IL_0549: Unknown result type (might be due to invalid IL or missing references) //IL_056f: Unknown result type (might be due to invalid IL or missing references) //IL_0574: Unknown result type (might be due to invalid IL or missing references) //IL_0593: Unknown result type (might be due to invalid IL or missing references) //IL_0598: Unknown result type (might be due to invalid IL or missing references) //IL_05b7: Unknown result type (might be due to invalid IL or missing references) //IL_05bc: Unknown result type (might be due to invalid IL or missing references) //IL_05db: Unknown result type (might be due to invalid IL or missing references) //IL_05e0: Unknown result type (might be due to invalid IL or missing references) //IL_05ff: Unknown result type (might be due to invalid IL or missing references) //IL_0604: Unknown result type (might be due to invalid IL or missing references) //IL_062a: Unknown result type (might be due to invalid IL or missing references) //IL_062f: Unknown result type (might be due to invalid IL or missing references) //IL_064e: Unknown result type (might be due to invalid IL or missing references) //IL_0653: Unknown result type (might be due to invalid IL or missing references) //IL_0679: Unknown result type (might be due to invalid IL or missing references) //IL_067e: Unknown result type (might be due to invalid IL or missing references) //IL_069d: Unknown result type (might be due to invalid IL or missing references) //IL_06a2: Unknown result type (might be due to invalid IL or missing references) //IL_06c8: Unknown result type (might be due to invalid IL or missing references) //IL_06cd: Unknown result type (might be due to invalid IL or missing references) //IL_06f3: Unknown result type (might be due to invalid IL or missing references) //IL_06f8: Unknown result type (might be due to invalid IL or missing references) //IL_071e: Unknown result type (might be due to invalid IL or missing references) //IL_0723: Unknown result type (might be due to invalid IL or missing references) //IL_0742: Unknown result type (might be due to invalid IL or missing references) //IL_0747: Unknown result type (might be due to invalid IL or missing references) //IL_076d: Unknown result type (might be due to invalid IL or missing references) //IL_0772: Unknown result type (might be due to invalid IL or missing references) //IL_0791: Unknown result type (might be due to invalid IL or missing references) //IL_0796: Unknown result type (might be due to invalid IL or missing references) //IL_07b5: Unknown result type (might be due to invalid IL or missing references) //IL_07ba: Unknown result type (might be due to invalid IL or missing references) //IL_07d9: Unknown result type (might be due to invalid IL or missing references) //IL_07de: Unknown result type (might be due to invalid IL or missing references) //IL_07fd: Unknown result type (might be due to invalid IL or missing references) //IL_0802: Unknown result type (might be due to invalid IL or missing references) //IL_081e: Unknown result type (might be due to invalid IL or missing references) //IL_0823: Unknown result type (might be due to invalid IL or missing references) //IL_083f: Unknown result type (might be due to invalid IL or missing references) //IL_0844: Unknown result type (might be due to invalid IL or missing references) //IL_0860: Unknown result type (might be due to invalid IL or missing references) //IL_0865: 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) color = Color.white; baseGameSkin = 0; tintStrength = 0.9f; switch (skinIndex) { case 64: color = Color.white; baseGameSkin = 0; tintStrength = 0f; break; case 14: color = new Color(0.8f, 0.1f, 0.1f, 1f); break; case 15: color = new Color(0.1f, 0.28f, 0.8f, 1f); break; case 16: color = new Color(0.1f, 0.55f, 0.18f, 1f); break; case 17: color = new Color(0.92f, 0.78f, 0.1f, 1f); break; case 18: color = new Color(0.95f, 0.42f, 0.08f, 1f); break; case 19: color = new Color(0.45f, 0.16f, 0.62f, 1f); break; case 20: color = new Color(0.92f, 0.42f, 0.62f, 1f); break; case 21: color = new Color(0.4f, 0.24f, 0.12f, 1f); break; case 22: color = new Color(0.01f, 0.01f, 0.015f, 1f); tintStrength = 0.94f; break; case 23: color = new Color(1f, 1f, 1f, 1f); tintStrength = 0.9f; break; case 24: color = new Color(0.48f, 0.5f, 0.52f, 1f); break; case 25: color = new Color(0.1f, 0.78f, 0.82f, 1f); break; case 26: color = new Color(0.82f, 0.1f, 0.65f, 1f); break; case 27: color = new Color(0.06f, 0.48f, 0.46f, 1f); break; case 28: color = new Color(0.05f, 0.1f, 0.28f, 1f); tintStrength = 0.9f; break; case 29: color = new Color(0.36f, 0.06f, 0.1f, 1f); tintStrength = 0.9f; break; case 30: color = new Color(0.78f, 0.7f, 0.56f, 1f); break; case 31: color = new Color(0.84f, 0.62f, 0.12f, 1f); break; case 32: color = new Color(0.66f, 0.68f, 0.72f, 1f); break; case 33: color = new Color(0.9f, 0.38f, 0.3f, 1f); break; case 34: color = new Color(0.14f, 0.7f, 0.66f, 1f); break; case 35: color = new Color(0.68f, 0.58f, 0.82f, 1f); break; case 36: color = new Color(0.22f, 0.16f, 0.56f, 1f); tintStrength = 0.9f; break; case 37: color = new Color(0.55f, 0.28f, 0.78f, 1f); break; case 38: color = new Color(0.5f, 0.82f, 0.64f, 1f); break; case 39: color = new Color(0.92f, 0.64f, 0.46f, 1f); break; case 40: color = new Color(0.62f, 0.06f, 0.14f, 1f); tintStrength = 0.9f; break; case 41: color = new Color(0.78f, 0.08f, 0.08f, 1f); tintStrength = 0.9f; break; case 42: color = new Color(0.34f, 0.05f, 0.12f, 1f); tintStrength = 0.9f; break; case 43: color = new Color(0.38f, 0.4f, 0.1f, 1f); break; case 44: color = new Color(0.46f, 0.82f, 0.12f, 1f); break; case 45: color = new Color(0.12f, 0.72f, 0.72f, 1f); break; case 46: color = new Color(0.9f, 0.58f, 0.06f, 1f); break; case 47: color = new Color(0.9f, 0.88f, 0.74f, 1f); tintStrength = 0.9f; break; case 48: color = new Color(0.62f, 0.58f, 0.34f, 1f); break; case 49: color = new Color(0.42f, 0.16f, 0.38f, 1f); tintStrength = 0.9f; break; case 50: color = new Color(0.82f, 0.34f, 0.48f, 1f); break; case 51: color = new Color(0.62f, 0.05f, 0.18f, 1f); tintStrength = 0.9f; break; case 52: color = new Color(0.04f, 0.48f, 0.26f, 1f); tintStrength = 0.9f; break; case 53: color = new Color(0.06f, 0.24f, 0.62f, 1f); tintStrength = 0.9f; break; case 54: color = new Color(0.7f, 0.56f, 0.1f, 1f); break; case 55: color = new Color(0.18f, 0.2f, 0.22f, 1f); tintStrength = 0.9f; break; case 56: color = new Color(0.64f, 0.46f, 0.3f, 1f); break; case 57: color = new Color(0.66f, 0.32f, 0.16f, 1f); break; case 58: color = new Color(0.52f, 0.38f, 0.18f, 1f); break; case 59: color = new Color(0.72f, 0.58f, 0.82f, 1f); break; case 60: color = new Color(0.52f, 0.6f, 0.88f, 1f); break; case 61: color = new Color(0.88f, 0.12f, 0.62f, 1f); break; case 62: color = new Color(0.32f, 0.38f, 0.46f, 1f); break; case 63: color = new Color(0.38f, 0.26f, 0.2f, 1f); break; default: return false; } return true; } internal static Material CreateMetallicMotorMaterial(Material source, Material controlTemplate, byte skinIndex, int rendererIndex, int materialIndex) { Material source2 = (((Object)(object)controlTemplate != (Object)null) ? controlTemplate : source); Material val = CreateSolidControlMaterial(source2, skinIndex, rendererIndex, materialIndex); if ((Object)(object)val == (Object)null) { return null; } ApplyFinishProperties(val, metallic: true); return val; } internal static Material CreateMotorFinishMaterial(Material source, Material controlTemplate, byte skinIndex, byte finishMode, int rendererIndex, int materialIndex) { Material source2 = ((finishMode == 0) ? source : (((Object)(object)controlTemplate != (Object)null) ? controlTemplate : source)); Material val = CreateSolidControlMaterial(source2, skinIndex, rendererIndex, materialIndex); if ((Object)(object)val == (Object)null) { return null; } switch (finishMode) { case 1: ApplyFinishProperties(val, metallic: true); break; case 2: ApplyFinishProperties(val, metallic: true); ApplyMaterialStyleProperties(val, 7); break; } return val; } internal static Material CreateSolidControlMaterial(Material source, byte skinIndex, int rendererIndex, int materialIndex) { //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null || skinIndex < 14 || skinIndex >= 64) { return null; } if (!GetCustomSkinProfile(skinIndex, out var color, out var _, out var tintStrength)) { return null; } if (skinIndex == 23) { ((Color)(ref color))..ctor(0.42f, 0.42f, 0.42f, 1f); tintStrength = Mathf.Min(tintStrength, 0.42f); } Material val = null; try { val = new Material(source); ((Object)val).name = $"{((Object)source).name} Untamo Control {skinIndex}"; bool flag = false; string[] array = null; try { array = source.GetTexturePropertyNames(); } catch { array = null; } if (array != null) { foreach (string text in array) { if (string.IsNullOrWhiteSpace(text) || ShouldSkipTintTextureProperty(text)) { continue; } Texture val2 = null; try { val2 = source.GetTexture(text); } catch { val2 = null; } if ((Object)(object)val2 == (Object)null || val2.width <= 0 || val2.height <= 0) { continue; } Texture2D tintedTexture = GetTintedTexture(val2, color, skinIndex, 0, 14, color, text, tintStrength); if ((Object)(object)tintedTexture == (Object)null) { continue; } try { val.SetTexture(text, (Texture)(object)tintedTexture); if (source.HasProperty(text) && val.HasProperty(text)) { val.SetTextureScale(text, source.GetTextureScale(text)); val.SetTextureOffset(text, source.GetTextureOffset(text)); } flag = true; } catch { } } } flag |= ApplyShaderGraphColorProperties(val, color); if (skinIndex == 23) { ReduceWhiteControlGlow(val); } if (!flag) { Object.Destroy((Object)(object)val); return null; } } catch { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } return null; } return val; } private static bool SetNativeBaseSkin(Boat boat, byte baseGameSkin) { if ((Object)(object)boat == (Object)null || baseGameSkin > 13) { return false; } try { if (boat.CurSkin != baseGameSkin) { boat.ServerSetSkin(baseGameSkin); } return boat.CurSkin == baseGameSkin; } catch { return false; } } private static bool ApplyFinishProperties(Material material, bool metallic) { //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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Invalid comparison between Unknown and I4 //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Invalid comparison between Unknown and I4 if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null) { return false; } bool result = false; Shader shader = material.shader; int propertyCount; try { propertyCount = shader.GetPropertyCount(); } catch { return false; } for (int i = 0; i < propertyCount; i++) { ShaderPropertyType propertyType; string propertyName; try { propertyType = shader.GetPropertyType(i); propertyName = shader.GetPropertyName(i); } catch { continue; } if (((int)propertyType != 2 && (int)propertyType != 3) || string.IsNullOrWhiteSpace(propertyName)) { continue; } string text = propertyName.ToLowerInvariant(); bool flag = true; float num; if (text.Contains("metal")) { num = (metallic ? 0.82f : 0.02f); } else if (text.Contains("smooth") || text.Contains("gloss")) { num = (metallic ? 0.58f : 0.24f); } else if (text.Contains("rough")) { num = (metallic ? 0.28f : 0.72f); } else { flag = false; num = 0f; } if (flag) { try { material.SetFloat(propertyName, num); result = true; } catch { } } } return result; } private static bool ApplyMaterialStyleProperties(Material material, byte styleMode) { //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_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: 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_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null) { return false; } bool result = false; float num = 0.02f; float num2 = 0.24f; switch (styleMode) { case 6: num = 0f; num2 = 0.96f; break; case 7: num = 1f; num2 = 0.95f; break; case 8: num = 0f; num2 = 0.1f; break; default: return false; } string[] array = new string[2] { "_Metallic", "_MetallicMetallicness" }; string[] array2 = new string[5] { "_Smoothness", "_MetallicSmoothness", "_PlasticSmoothness", "_Glossiness", "_GlossMapScale" }; for (int i = 0; i < array.Length; i++) { try { if (material.HasProperty(array[i])) { material.SetFloat(array[i], num); result = true; } } catch { } } for (int j = 0; j < array2.Length; j++) { try { if (material.HasProperty(array2[j])) { material.SetFloat(array2[j], num2); result = true; } } catch { } } if (styleMode == 6) { try { if (material.HasProperty("_BaseColor")) { Color color = material.GetColor("_BaseColor"); color.a = 0.99f; material.SetColor("_BaseColor", color); result = true; } if (material.HasProperty("_Color")) { Color color2 = material.GetColor("_Color"); color2.a = 0.99f; material.SetColor("_Color", color2); result = true; } if (material.HasProperty("_Surface")) { material.SetFloat("_Surface", 1f); } if (material.HasProperty("_Blend")) { material.SetFloat("_Blend", 0f); } if (material.HasProperty("_Metallic")) { material.SetFloat("_Metallic", 0.02f); } if (material.HasProperty("_Smoothness")) { material.SetFloat("_Smoothness", 0.98f); result = true; } if (material.HasProperty("_Glossiness")) { material.SetFloat("_Glossiness", 0.98f); result = true; } if (material.HasProperty("_SpecColor")) { material.SetColor("_SpecColor", new Color(1f, 1f, 1f, 1f)); result = true; } if (material.HasProperty("_SpecularHighlights")) { material.SetFloat("_SpecularHighlights", 1f); } if (material.HasProperty("_EnvironmentReflections")) { material.SetFloat("_EnvironmentReflections", 1f); } if (material.HasProperty("_BlendModePreserveSpecular")) { material.SetFloat("_BlendModePreserveSpecular", 1f); } if (material.HasProperty("_SrcBlend")) { material.SetFloat("_SrcBlend", 5f); } if (material.HasProperty("_DstBlend")) { material.SetFloat("_DstBlend", 10f); } if (material.HasProperty("_SrcBlendAlpha")) { material.SetFloat("_SrcBlendAlpha", 1f); } if (material.HasProperty("_DstBlendAlpha")) { material.SetFloat("_DstBlendAlpha", 10f); } if (material.HasProperty("_ZWrite")) { material.SetFloat("_ZWrite", 0f); } if (material.HasProperty("_Cull")) { material.SetFloat("_Cull", 2f); } if (material.HasProperty("_AlphaClip")) { material.SetFloat("_AlphaClip", 0f); } if (material.HasProperty("_Cutoff")) { material.SetFloat("_Cutoff", 0f); } material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); material.DisableKeyword("_ALPHATEST_ON"); material.SetOverrideTag("RenderType", "Transparent"); material.renderQueue = 3000; } catch { } } else { try { if (material.HasProperty("_Surface")) { material.SetFloat("_Surface", 0f); } if (material.HasProperty("_ZWrite")) { material.SetFloat("_ZWrite", 1f); } material.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); material.renderQueue = -1; } catch { } } return result; } private static bool RebuildCustomSkin(Boat boat, byte skinIndex, bool captureOriginals) { //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) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: 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_024e: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null) { return false; } if (OriginalMaterials.ContainsKey(boat)) { RestoreOriginalMaterials(boat); } if (!GetCustomSkinProfile(skinIndex, out var color, out var baseGameSkin, out var tintStrength)) { return false; } baseGameSkin = GetStyleBaseGameSkin(boat); byte styleMode = GetStyleMode(boat); bool metallicFinish = IsMetallicFinish(boat); if (!StripeSecondarySkinSlots.ContainsKey(boat)) { StripeSecondarySkinSlots[boat] = 14; } byte stripeSecondarySkinIndex = GetStripeSecondarySkinIndex(boat); Color stripeSecondaryTintColor = GetStripeSecondaryTintColor(boat); Renderer[] componentsInChildren; try { componentsInChildren = ((Component)boat).GetComponentsInChildren(true); } catch { return false; } if (componentsInChildren == null || componentsInChildren.Length == 0) { return false; } Dictionary dictionary = new Dictionary(); HashSet hashSet = FindHullRenderers(componentsInChildren); if (hashSet.Count == 0) { return false; } _activeMaterialBuildBoat = boat; int num = 0; for (int i = 0; i < componentsInChildren.Length; i++) { Renderer val = componentsInChildren[i]; if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || !hashSet.Contains(val)) { continue; } Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { continue; } if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; Array.Copy(sharedMaterials, array, sharedMaterials.Length); Material[] array2 = (Material[])(object)new Material[sharedMaterials.Length]; bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { Material val2 = sharedMaterials[j]; if ((Object)(object)val2 == (Object)null) { array2[j] = null; continue; } if (ShouldKeepOriginalMaterial(val2)) { array2[j] = val2; continue; } Material val3 = CreateForcedMaterial(val2, color, skinIndex, styleMode, stripeSecondarySkinIndex, stripeSecondaryTintColor, i, j, tintStrength, metallicFinish); if ((Object)(object)val3 == (Object)null) { array2[j] = val2; continue; } array2[j] = val3; flag = true; } if (!flag) { DestroyClonedMaterials(array2, sharedMaterials); continue; } try { dictionary[val] = array; ShadowCastingMode shadowCastingMode = val.shadowCastingMode; bool receiveShadows = val.receiveShadows; val.SetPropertyBlock((MaterialPropertyBlock)null); val.sharedMaterials = array2; val.shadowCastingMode = shadowCastingMode; val.receiveShadows = receiveShadows; val.enabled = false; val.enabled = true; num++; } catch { dictionary.Remove(val); DestroyClonedMaterials(array2, sharedMaterials); } } _activeMaterialBuildBoat = null; if (num == 0) { return false; } OriginalMaterials[boat] = dictionary; return true; } private static Material CreateForcedMaterial(Material source, Color color, byte skinIndex, byte styleMode, byte stripeSecondarySkinIndex, Color stripeSecondaryTint, int rendererIndex, int materialIndex, float tintStrength, bool metallicFinish) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null) { return null; } if (skinIndex == 64) { return CreateRainbowMaterial(source, styleMode, rendererIndex, materialIndex); } switch (styleMode) { case 6: return CreateGlassMaterial(source, color, skinIndex, rendererIndex, materialIndex, tintStrength); case 8: return CreateSpecialOpaqueMaterial(source, color, skinIndex, styleMode, rendererIndex, materialIndex, tintStrength); case 9: { Material[] controlTemplateMaterials = BoatControlSkinRouting.GetControlTemplateMaterials(_activeMaterialBuildBoat); Material val3 = null; if (controlTemplateMaterials != null && controlTemplateMaterials.Length != 0) { int num = Mathf.Clamp(materialIndex, 0, controlTemplateMaterials.Length - 1); val3 = controlTemplateMaterials[num]; } Material val4 = CreateSolidControlMaterial(((Object)(object)val3 != (Object)null) ? val3 : source, skinIndex, rendererIndex, materialIndex); if ((Object)(object)val4 != (Object)null) { ((Object)val4).name = string.Format("{0}{1}_CONTROLS_R{2}_M{3}", "UntamoBoatSkin_", skinIndex, rendererIndex, materialIndex); } return val4; } default: { Material val = null; try { val = new Material(source); ((Object)val).name = string.Format("{0}{1}_S{2}_R{3}_M{4}", "UntamoBoatSkin_", skinIndex, styleMode, rendererIndex, materialIndex); bool flag = false; string[] array = null; try { array = source.GetTexturePropertyNames(); } catch { array = null; } if (array != null) { foreach (string text in array) { if (string.IsNullOrWhiteSpace(text) || ShouldSkipTintTextureProperty(text)) { continue; } Texture val2 = null; try { val2 = source.GetTexture(text); } catch { val2 = null; } if ((Object)(object)val2 == (Object)null || val2.width <= 0 || val2.height <= 0 || (IsStripesStyle(styleMode) && !IsStripePaletteTexture(text, val2))) { continue; } Texture2D tintedTexture = GetTintedTexture(val2, color, skinIndex, styleMode, stripeSecondarySkinIndex, stripeSecondaryTint, text, tintStrength); if ((Object)(object)tintedTexture == (Object)null) { continue; } try { val.SetTexture(text, (Texture)(object)tintedTexture); if (source.HasProperty(text) && val.HasProperty(text)) { val.SetTextureScale(text, source.GetTextureScale(text)); val.SetTextureOffset(text, source.GetTextureOffset(text)); } flag = true; } catch { } } } flag = ((!IsStripesStyle(styleMode)) ? (flag | ApplyShaderGraphColorProperties(val, color)) : (flag | NeutralizeStripesShaderColorProperties(val))); flag |= ApplyFinishProperties(val, metallicFinish); if (!(flag | ApplyMaterialStyleProperties(val, styleMode))) { try { Object.Destroy((Object)(object)val); } catch { } return null; } return val; } catch { if ((Object)(object)val != (Object)null) { try { Object.Destroy((Object)(object)val); } catch { } } return null; } } } } private static Material CreateRainbowMaterial(Material source, byte styleMode, int rendererIndex, int materialIndex) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //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_00ae: 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) Shader val = Shader.Find("Universal Render Pipeline/Lit"); if ((Object)(object)val == (Object)null) { val = FindForcedShader(((Object)(object)source != (Object)null) ? source.shader : null); } if ((Object)(object)val == (Object)null) { return null; } Material val2 = null; try { val2 = new Material(val); ((Object)val2).name = string.Format("{0}{1}_RAINBOW_S{2}_R{3}_M{4}", "UntamoBoatSkin_", (byte)64, styleMode, rendererIndex, materialIndex); Color value = Color.HSVToRGB(0f, 0.92f, 1f); SetColorIfPresent(val2, "_BaseColor", value); SetColorIfPresent(val2, "_Color", value); Texture val3 = null; string firstVisibleColorTextureProperty = GetFirstVisibleColorTextureProperty(source); if (!string.IsNullOrWhiteSpace(firstVisibleColorTextureProperty)) { try { val3 = source.GetTexture(firstVisibleColorTextureProperty); } catch { val3 = null; } } if ((Object)(object)val3 != (Object)null) { SetTextureIfPresent(val2, "_BaseMap", val3); SetTextureIfPresent(val2, "_MainTex", val3); } bool flag = styleMode == 1; try { if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", flag ? 0.85f : 0f); } if (val2.HasProperty("_Smoothness")) { val2.SetFloat("_Smoothness", flag ? 0.68f : 0.28f); } if (val2.HasProperty("_Glossiness")) { val2.SetFloat("_Glossiness", flag ? 0.68f : 0.28f); } if (val2.HasProperty("_Surface")) { val2.SetFloat("_Surface", 0f); } } catch { } CopyMaterialRenderSettings(source, val2); return val2; } catch { if ((Object)(object)val2 != (Object)null) { try { Object.Destroy((Object)(object)val2); } catch { } } return null; } } private static Color GetSpecialFinishSurfaceColor(Color authoredColor) { //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_0005: 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_0029: 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_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_004a: Unknown result type (might be due to invalid IL or missing references) Color val = authoredColor; val.r = Mathf.Clamp01(val.r); val.g = Mathf.Clamp01(val.g); val.b = Mathf.Clamp01(val.b); val.a = authoredColor.a; return val; } private static Material CreateSpecialOpaqueMaterial(Material source, Color selectedColor, byte skinIndex, byte styleMode, int rendererIndex, int materialIndex, float tintStrength) { //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_009c: 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) //IL_0028: Expected O, but got Unknown //IL_010e: 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_017c: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("Universal Render Pipeline/Lit"); if ((Object)(object)val == (Object)null) { return null; } Material val2 = null; try { val2 = new Material(val); try { val2.shaderKeywords = new string[0]; } catch { } string text = GetFinishModeName(styleMode).Replace(" ", string.Empty); ((Object)val2).name = string.Format("{0}{1}_{2}_R{3}_M{4}", "UntamoBoatSkin_", skinIndex, text, rendererIndex, materialIndex); Color specialFinishSurfaceColor = GetSpecialFinishSurfaceColor(selectedColor); float num = 0f; float num2 = 0.15f; float num3 = 0.35f; if (styleMode == 8) { num = 0f; num2 = 0.1f; num3 = 0.18f; } SetTextureIfPresent(val2, "_BaseMap", (Texture)(object)Texture2D.whiteTexture); SetTextureIfPresent(val2, "_MainTex", (Texture)(object)Texture2D.whiteTexture); if (val2.HasProperty("_EmissionColor")) { val2.SetColor("_EmissionColor", Color.black); } val2.DisableKeyword("_EMISSION"); string firstVisibleColorTextureProperty = GetFirstVisibleColorTextureProperty(source); Texture val3 = null; if (!string.IsNullOrWhiteSpace(firstVisibleColorTextureProperty)) { try { val3 = source.GetTexture(firstVisibleColorTextureProperty); } catch { val3 = null; } } if ((Object)(object)val3 != (Object)null && styleMode != 8) { Texture2D tintedTexture = GetTintedTexture(val3, specialFinishSurfaceColor, skinIndex, styleMode, 14, Color.red, firstVisibleColorTextureProperty, Mathf.Min(tintStrength, 0.38f)); if ((Object)(object)tintedTexture != (Object)null) { if (val2.HasProperty("_BaseMap")) { val2.SetTexture("_BaseMap", (Texture)(object)tintedTexture); } if (val2.HasProperty("_MainTex")) { val2.SetTexture("_MainTex", (Texture)(object)tintedTexture); } } } specialFinishSurfaceColor.a = 1f; if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", specialFinishSurfaceColor); } if (val2.HasProperty("_Color")) { val2.SetColor("_Color", specialFinishSurfaceColor); } if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", num); } if (val2.HasProperty("_Smoothness")) { val2.SetFloat("_Smoothness", num2); } if (val2.HasProperty("_Glossiness")) { val2.SetFloat("_Glossiness", num2); } if (val2.HasProperty("_EnvironmentReflections")) { val2.SetFloat("_EnvironmentReflections", num3); } if (val2.HasProperty("_SpecularHighlights")) { val2.SetFloat("_SpecularHighlights", (styleMode == 8) ? 0.35f : 1f); } if (val2.HasProperty("_Surface")) { val2.SetFloat("_Surface", 0f); } if (val2.HasProperty("_ZWrite")) { val2.SetFloat("_ZWrite", 1f); } val2.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); val2.SetOverrideTag("RenderType", "Opaque"); val2.renderQueue = -1; return val2; } catch { if ((Object)(object)val2 != (Object)null) { try { Object.Destroy((Object)(object)val2); } catch { } } return null; } } private static Material CreateGlassMaterial(Material source, Color color, byte skinIndex, int rendererIndex, int materialIndex, float tintStrength) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_00cb: 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_00d1: 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_00dc: 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_00b3: 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_012d: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("Universal Render Pipeline/Lit"); if ((Object)(object)val == (Object)null) { return null; } Material val2 = null; try { val2 = new Material(val); try { val2.shaderKeywords = new string[0]; } catch { } ((Object)val2).name = string.Format("{0}{1}_GLASS_R{2}_M{3}", "UntamoBoatSkin_", skinIndex, rendererIndex, materialIndex); SetTextureIfPresent(val2, "_BaseMap", (Texture)(object)Texture2D.whiteTexture); SetTextureIfPresent(val2, "_MainTex", (Texture)(object)Texture2D.whiteTexture); if (val2.HasProperty("_EmissionColor")) { val2.SetColor("_EmissionColor", Color.black); } val2.DisableKeyword("_EMISSION"); Color specialFinishSurfaceColor = GetSpecialFinishSurfaceColor(color); Color val3 = default(Color); ((Color)(ref val3))..ctor(specialFinishSurfaceColor.r, specialFinishSurfaceColor.g, specialFinishSurfaceColor.b, 0.95f); if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", val3); } if (val2.HasProperty("_Color")) { val2.SetColor("_Color", val3); } if (val2.HasProperty("_Surface")) { val2.SetFloat("_Surface", 1f); } if (val2.HasProperty("_Blend")) { val2.SetFloat("_Blend", 0f); } if (val2.HasProperty("_SrcBlend")) { val2.SetFloat("_SrcBlend", 5f); } if (val2.HasProperty("_DstBlend")) { val2.SetFloat("_DstBlend", 10f); } if (val2.HasProperty("_SrcBlendAlpha")) { val2.SetFloat("_SrcBlendAlpha", 1f); } if (val2.HasProperty("_DstBlendAlpha")) { val2.SetFloat("_DstBlendAlpha", 10f); } if (val2.HasProperty("_ZWrite")) { val2.SetFloat("_ZWrite", 0f); } if (val2.HasProperty("_AlphaClip")) { val2.SetFloat("_AlphaClip", 0f); } if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", 0f); } if (val2.HasProperty("_Smoothness")) { val2.SetFloat("_Smoothness", 0.96f); } if (val2.HasProperty("_SpecularHighlights")) { val2.SetFloat("_SpecularHighlights", 1f); } if (val2.HasProperty("_EnvironmentReflections")) { val2.SetFloat("_EnvironmentReflections", 1f); } val2.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); val2.DisableKeyword("_ALPHATEST_ON"); val2.SetOverrideTag("RenderType", "Transparent"); val2.renderQueue = 3000; return val2; } catch { if ((Object)(object)val2 != (Object)null) { try { Object.Destroy((Object)(object)val2); } catch { } } return null; } } private static Material CreateProceduralCamoMaterial(Material source, Color primaryColor, byte primarySkinIndex, byte secondarySkinIndex, Color secondaryColor, int rendererIndex, int materialIndex, bool metallicFinish) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_006d: 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_0111: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) Shader val = Shader.Find("Universal Render Pipeline/Lit"); if ((Object)(object)val == (Object)null) { return null; } Material val2 = null; try { val2 = new Material(val); ((Object)val2).name = string.Format("{0}{1}_CAMO_{2}_R{3}_M{4}", "UntamoBoatSkin_", primarySkinIndex, secondarySkinIndex, rendererIndex, materialIndex); Texture2D proceduralCamoTexture = GetProceduralCamoTexture(primaryColor, primarySkinIndex); if ((Object)(object)proceduralCamoTexture == (Object)null) { Object.Destroy((Object)(object)val2); return null; } if (val2.HasProperty("_BaseMap")) { val2.SetTexture("_BaseMap", (Texture)(object)proceduralCamoTexture); } if (val2.HasProperty("_MainTex")) { val2.SetTexture("_MainTex", (Texture)(object)proceduralCamoTexture); } if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", Color.white); } if (val2.HasProperty("_Color")) { val2.SetColor("_Color", Color.white); } string firstVisibleColorTextureProperty = GetFirstVisibleColorTextureProperty(source); if (!string.IsNullOrWhiteSpace(firstVisibleColorTextureProperty)) { try { Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(2.6f, 2.6f); Vector2 zero = Vector2.zero; if (val2.HasProperty("_BaseMap")) { val2.SetTextureScale("_BaseMap", val3); val2.SetTextureOffset("_BaseMap", zero); } if (val2.HasProperty("_MainTex")) { val2.SetTextureScale("_MainTex", val3); val2.SetTextureOffset("_MainTex", zero); } } catch { } } Texture firstTexture = GetFirstTexture(source, "_Normal_Map", "_BumpMap"); if ((Object)(object)firstTexture != (Object)null && val2.HasProperty("_BumpMap")) { val2.SetTexture("_BumpMap", firstTexture); if (val2.HasProperty("_BumpScale")) { float num = 1f; try { if (source.HasProperty("_Normal_Strength")) { num = source.GetFloat("_Normal_Strength"); } else if (source.HasProperty("_BumpScale")) { num = source.GetFloat("_BumpScale"); } } catch { num = 1f; } val2.SetFloat("_BumpScale", Mathf.Max(0.05f, num)); } val2.EnableKeyword("_NORMALMAP"); } if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", metallicFinish ? 0.82f : 0.02f); } if (val2.HasProperty("_Smoothness")) { val2.SetFloat("_Smoothness", metallicFinish ? 0.58f : 0.24f); } return val2; } catch { if ((Object)(object)val2 != (Object)null) { try { Object.Destroy((Object)(object)val2); } catch { } } return null; } } private static string GetFirstVisibleColorTextureProperty(Material material) { if ((Object)(object)material == (Object)null) { return null; } string[] array = new string[3] { "_BaseMap", "_Colors", "_MainTex" }; foreach (string text in array) { try { if (material.HasProperty(text) && (Object)(object)material.GetTexture(text) != (Object)null) { return text; } } catch { } } return null; } private static Texture GetFirstTexture(Material material, params string[] propertyNames) { if ((Object)(object)material == (Object)null || propertyNames == null) { return null; } foreach (string text in propertyNames) { try { if (!string.IsNullOrWhiteSpace(text) && material.HasProperty(text)) { Texture texture = material.GetTexture(text); if ((Object)(object)texture != (Object)null) { return texture; } } } catch { } } return null; } private static Texture2D GetProceduralCamoTexture(Color primaryColor, byte primarySkinIndex) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0157: 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_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017b: 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) //IL_0184: Unknown result type (might be due to invalid IL or missing references) string key = "single_" + primarySkinIndex.ToString(CultureInfo.InvariantCulture); if (ProceduralCamoTextureCache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null) { return value; } Texture2D val = new Texture2D(256, 256, (TextureFormat)4, false); Color[] array = (Color[])(object)new Color[65536]; float num = 13.73f; float num2 = 41.29f; for (int i = 0; i < 256; i++) { float num3 = (float)i / 256f; for (int j = 0; j < 256; j++) { float num4 = (float)j / 256f; float num5 = Mathf.PerlinNoise(num + num4 * 3.4f, num2 + num3 * 3.4f); float num6 = Mathf.PerlinNoise(num * 1.71f + num4 * 7.6f, num2 * 1.37f + num3 * 7.6f); float num7 = num5 * 0.78f + num6 * 0.22f; float num8 = Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.48f, 0.56f, num7)); float num9 = Mathf.PerlinNoise(91.7f + num4 * 18f, 27.3f + num3 * 18f); float shade = Mathf.Lerp(0.72f, 0.9f, num9); float shade2 = Mathf.Lerp(0.34f, 0.54f, num9); Color val2 = ApplyPatternShade(primaryColor, primarySkinIndex, shade); Color val3 = ApplyPatternShade(primaryColor, primarySkinIndex, shade2); array[i * 256 + j] = Color.Lerp(val2, val3, num8); } } val.SetPixels(array); val.Apply(false, true); ((Object)val).name = $"UntamoCamoSingle_{primarySkinIndex}"; ((Texture)val).wrapMode = (TextureWrapMode)0; ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).anisoLevel = 4; ProceduralCamoTextureCache[key] = val; return val; } private static Color ApplyPatternShade(Color color, byte skinIndex, float shade) { //IL_0033: 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_0079: 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_0093: 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_0071: 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_00ad: Unknown result type (might be due to invalid IL or missing references) switch (skinIndex) { case 22: { float num2 = Mathf.Lerp(0.008f, 0.045f, Mathf.InverseLerp(0.9f, 1.04f, shade)); return new Color(num2, num2, num2, 1f); } case 23: { float num = Mathf.Lerp(0.86f, 1f, Mathf.InverseLerp(0.9f, 1.04f, shade)); return new Color(num, num, num, 1f); } default: return new Color(Mathf.Clamp01(color.r * shade), Mathf.Clamp01(color.g * shade), Mathf.Clamp01(color.b * shade), 1f); } } private static bool IsStripePaletteTexture(string propertyName, Texture texture) { if ((Object)(object)texture == (Object)null) { return false; } string text = (string.IsNullOrWhiteSpace(propertyName) ? string.Empty : propertyName.ToLowerInvariant()); bool flag = text.Contains("color") || text.Contains("palette") || text.Contains("lookup") || text.Contains("lut"); bool flag2 = texture.width <= 64 && texture.height <= 64; return flag || flag2; } private static bool ShouldSkipTintTextureProperty(string propertyName) { if (string.IsNullOrWhiteSpace(propertyName)) { return true; } string text = propertyName.ToLowerInvariant(); return text.Contains("normal") || text.Contains("bump") || text.Contains("mask") || text.Contains("metal") || text.Contains("rough") || text.Contains("smooth") || text.Contains("gloss") || text.Contains("spec") || text.Contains("occlusion") || text.Contains("ao") || text.Contains("height") || text.Contains("parallax") || text.Contains("emission") || text.Contains("emissive") || text.Contains("noise") || text.Contains("foam") || text.Contains("distort") || text.Contains("flow"); } private static float GetHueDistanceToRed(float hue) { float num = Mathf.Abs(hue); float num2 = Mathf.Abs(1f - hue); return Mathf.Min(num, num2); } private static float GetStripesPrimaryWeight(Color pixel, float luminance) { //IL_0001: 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_003f: 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) float hue = default(float); float num = default(float); float num2 = default(float); Color.RGBToHSV(pixel, ref hue, ref num, ref num2); float num3 = 1f - Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.025f, 0.16f, GetHueDistanceToRed(hue))); float num4 = Mathf.Clamp01(pixel.r - Mathf.Max(pixel.g, pixel.b)); float num5 = num3 * Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.15f, 0.55f, num)) * Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.08f, 0.45f, num4)); float num6 = 1f - Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.08f, 0.5f, num)); float num7 = num6 * Mathf.Lerp(0.35f, 1f, Mathf.Clamp01(luminance)); float num8 = num7 + num5; if (num8 <= 0.0001f) { return Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.3f, 0.72f, luminance)); } return Mathf.Clamp01(num7 / num8); } private static float GetCamoPrimaryWeight(Color pixel, float luminance) { return 1f - Mathf.SmoothStep(0f, 1f, Mathf.InverseLerp(0.36f, 0.41f, luminance)); } private static Color BuildPatternColor(Color target, byte targetSkinIndex, float luminance, float alpha, bool darkerRegion) { //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_00be: 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_009b: 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_00b6: 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_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) switch (targetSkinIndex) { case 22: return new Color(0f, 0f, 0f, alpha); case 23: { float num2 = (darkerRegion ? Mathf.Lerp(0.7f, 0.94f, luminance) : Mathf.Lerp(0.78f, 1f, luminance)); return new Color(num2, num2, num2, alpha); } default: { float num = (darkerRegion ? Mathf.Lerp(0.34f, 0.88f, luminance) : Mathf.Lerp(0.48f, 1.04f, luminance)); return new Color(Mathf.Clamp01(target.r * num), Mathf.Clamp01(target.g * num), Mathf.Clamp01(target.b * num), alpha); } } } private static Texture2D GetTintedTexture(Texture source, Color tint, byte skinIndex, byte styleMode, byte stripeSecondarySkinIndex, Color stripeSecondaryTint, string propertyName, float tintStrength) { //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected O, but got Unknown //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_0368: 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_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: 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_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null) { return null; } string key = ((Object)source).GetInstanceID().ToString(CultureInfo.InvariantCulture) + "_" + skinIndex.ToString(CultureInfo.InvariantCulture) + "_" + styleMode.ToString(CultureInfo.InvariantCulture) + "_" + stripeSecondarySkinIndex.ToString(CultureInfo.InvariantCulture) + "_" + propertyName; if (TintedTextureCache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null) { return value; } RenderTexture val = null; RenderTexture active = RenderTexture.active; Texture2D val2 = null; try { int num = Mathf.Max(1, source.width); int num2 = Mathf.Max(1, source.height); val = RenderTexture.GetTemporary(num, num2, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)0); Graphics.Blit(source, val); RenderTexture.active = val; val2 = new Texture2D(num, num2, (TextureFormat)4, false); val2.ReadPixels(new Rect(0f, 0f, (float)num, (float)num2), 0, 0, false); val2.Apply(false, false); Color[] pixels = val2.GetPixels(); Color val6 = default(Color); for (int i = 0; i < pixels.Length; i++) { Color val3 = pixels[i]; float num3 = val3.r * 0.299f + val3.g * 0.587f + val3.b * 0.114f; float num4 = Mathf.Lerp(0.55f, 1.18f, num3); bool flag = IsStripesStyle(styleMode); bool flag2 = styleMode == 6; if (flag) { float stripesPrimaryWeight = GetStripesPrimaryWeight(val3, num3); Color val4 = BuildPatternColor(tint, skinIndex, num3, val3.a, darkerRegion: false); Color val5 = BuildPatternColor(stripeSecondaryTint, stripeSecondarySkinIndex, num3, val3.a, darkerRegion: true); float num5 = ((stripesPrimaryWeight >= 0.5f) ? 1f : 0f); val6 = Color.Lerp(val5, val4, num5); } else { switch (skinIndex) { case 22: { float num8 = Mathf.Lerp(0.015f, 0.18f, num3); ((Color)(ref val6))..ctor(num8, num8, num8 * 1.03f, val3.a); break; } case 23: { float num7 = Mathf.Lerp(0.62f, 1f, num3); ((Color)(ref val6))..ctor(num7, num7, num7, val3.a); break; } default: { float num6 = Mathf.Lerp(0.28f, 1.08f, num3); ((Color)(ref val6))..ctor(Mathf.Clamp01(tint.r * num6), Mathf.Clamp01(tint.g * num6), Mathf.Clamp01(tint.b * num6), val3.a); break; } } } Color val7 = Color.Lerp(val3, val6, flag ? 1f : Mathf.Clamp01(tintStrength)); if (flag2) { val7.a = Mathf.Clamp01(val3.a * 0.95f); } pixels[i] = val7; } val2.SetPixels(pixels); val2.Apply(false, true); ((Object)val2).name = $"UntamoSkin{skinIndex}_{propertyName}_{((Object)source).name}"; ((Texture)val2).wrapMode = source.wrapMode; ((Texture)val2).filterMode = source.filterMode; ((Texture)val2).anisoLevel = source.anisoLevel; TintedTextureCache[key] = val2; val2 = null; return TintedTextureCache[key]; } catch { return null; } finally { RenderTexture.active = active; if ((Object)(object)val != (Object)null) { RenderTexture.ReleaseTemporary(val); } if ((Object)(object)val2 != (Object)null) { try { Object.Destroy((Object)(object)val2); } catch { } } } } private static bool ApplyCamoShaderGraphColorProperties(Material material, Color primaryTint, Color secondaryTint) { //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_0067: Invalid comparison between Unknown and I4 //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0155: 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) //IL_02bf: 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) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: 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) if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null) { return false; } Shader shader = material.shader; int propertyCount; try { propertyCount = shader.GetPropertyCount(); } catch { return false; } List list = new List(); List list2 = new List(); for (int i = 0; i < propertyCount; i++) { string propertyName; try { ShaderPropertyType propertyType = shader.GetPropertyType(i); if ((int)propertyType > 0) { continue; } propertyName = shader.GetPropertyName(i); goto IL_0086; } catch { } continue; IL_0086: if (string.IsNullOrWhiteSpace(propertyName)) { continue; } string text = propertyName.ToLowerInvariant(); if (!text.Contains("emission") && !text.Contains("emissive") && !text.Contains("glow")) { try { list.Add(propertyName); list2.Add(material.GetColor(propertyName)); } catch { } } } if (list.Count == 0) { return false; } bool result = false; if (list.Count == 1) { try { Color val = list2[0]; material.SetColor(list[0], new Color(1f, 1f, 1f, val.a)); return true; } catch { return false; } } float num = float.MaxValue; float num2 = float.MinValue; int num3 = 0; int num4 = 0; for (int j = 0; j < list2.Count; j++) { Color val2 = list2[j]; float num5 = val2.r * 0.299f + val2.g * 0.587f + val2.b * 0.114f; if (num5 < num) { num = num5; num3 = j; } if (num5 > num2) { num2 = num5; num4 = j; } } if (num2 - num < 0.08f) { for (int k = 0; k < list.Count; k++) { try { Color val3 = list2[k]; material.SetColor(list[k], new Color(1f, 1f, 1f, val3.a)); result = true; } catch { } } return result; } for (int l = 0; l < list.Count; l++) { try { Color val4 = list2[l]; Color val5; if (l == num3) { val5 = primaryTint; } else if (l == num4) { val5 = secondaryTint; } else { float num6 = val4.r * 0.299f + val4.g * 0.587f + val4.b * 0.114f; float num7 = Mathf.InverseLerp(num, num2, num6); val5 = Color.Lerp(primaryTint, secondaryTint, num7); } val5.a = val4.a; material.SetColor(list[l], val5); result = true; } catch { } } return result; } private static void ReduceWhiteControlGlow(Material material) { //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) //IL_009f: Invalid comparison between Unknown and I4 //IL_0107: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null) { return; } Color val = default(Color); ((Color)(ref val))..ctor(0f, 0f, 0f, 1f); try { if (material.HasProperty("_EmissionColor")) { material.SetColor("_EmissionColor", val); } material.DisableKeyword("_EMISSION"); } catch { } Shader shader = material.shader; int propertyCount; try { propertyCount = shader.GetPropertyCount(); } catch { return; } for (int i = 0; i < propertyCount; i++) { try { if ((int)shader.GetPropertyType(i) > 0) { continue; } string propertyName = shader.GetPropertyName(i); if (!string.IsNullOrWhiteSpace(propertyName)) { string text = propertyName.ToLowerInvariant(); if (text.Contains("emission") || text.Contains("emissive") || text.Contains("glow")) { material.SetColor(propertyName, val); } } } catch { } } } private static bool NeutralizeStripesShaderColorProperties(Material material) { //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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 //IL_00cf: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null) { return false; } Shader shader = material.shader; int propertyCount; try { propertyCount = shader.GetPropertyCount(); } catch { return false; } bool result = false; for (int i = 0; i < propertyCount; i++) { string propertyName; try { ShaderPropertyType propertyType = shader.GetPropertyType(i); if ((int)propertyType > 0) { continue; } propertyName = shader.GetPropertyName(i); goto IL_007d; } catch { } continue; IL_007d: if (string.IsNullOrWhiteSpace(propertyName)) { continue; } string text = propertyName.ToLowerInvariant(); if (!text.Contains("emission") && !text.Contains("emissive") && !text.Contains("glow")) { try { Color color = material.GetColor(propertyName); material.SetColor(propertyName, new Color(1f, 1f, 1f, color.a)); result = true; } catch { } } } return result; } private static bool ApplyShaderGraphColorProperties(Material material, Color tint) { //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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null) { return false; } Shader shader = material.shader; int propertyCount; try { propertyCount = shader.GetPropertyCount(); } catch { return false; } bool result = false; for (int i = 0; i < propertyCount; i++) { string propertyName; try { ShaderPropertyType propertyType = shader.GetPropertyType(i); if ((int)propertyType > 0) { continue; } propertyName = shader.GetPropertyName(i); goto IL_0077; } catch { } continue; IL_0077: if (string.IsNullOrWhiteSpace(propertyName)) { continue; } string text = propertyName.ToLowerInvariant(); if (!text.Contains("emission") && !text.Contains("emissive") && !text.Contains("glow")) { try { material.SetColor(propertyName, tint); result = true; } catch { } } } return result; } private static bool SetColorIfPresentReturning(Material material, string property, Color value) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null) { return false; } try { if (!material.HasProperty(property)) { return false; } material.SetColor(property, value); return true; } catch { return false; } } private static void CopyMaterialRenderSettings(Material source, Material destination) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null || (Object)(object)destination == (Object)null) { return; } try { destination.renderQueue = source.renderQueue; } catch { } try { destination.enableInstancing = source.enableInstancing; } catch { } try { destination.doubleSidedGI = source.doubleSidedGI; } catch { } try { destination.globalIlluminationFlags = source.globalIlluminationFlags; } catch { } } private static Shader FindForcedShader(Shader sourceShader) { if ((Object)(object)sourceShader != (Object)null && sourceShader.isSupported) { return sourceShader; } string[] array = new string[6] { "Universal Render Pipeline/Lit", "HDRP/Lit", "Standard", "Universal Render Pipeline/Unlit", "HDRP/Unlit", "Unlit/Color" }; for (int i = 0; i < array.Length; i++) { Shader val = null; try { val = Shader.Find(array[i]); } catch { val = null; } if ((Object)(object)val != (Object)null && val.isSupported) { return val; } } return null; } private static void SetColorIfPresent(Material material, string property, Color value) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)material == (Object)null) { return; } try { if (material.HasProperty(property)) { material.SetColor(property, value); } } catch { } } private static void SetTextureIfPresent(Material material, string property, Texture value) { if ((Object)(object)material == (Object)null || (Object)(object)value == (Object)null) { return; } try { if (material.HasProperty(property)) { material.SetTexture(property, value); } } catch { } } private static void SetFloatIfPresent(Material material, string property, float value) { if ((Object)(object)material == (Object)null) { return; } try { if (material.HasProperty(property)) { material.SetFloat(property, value); } } catch { } } private static void EnsureFinishMaterialState(Boat boat) { if ((Object)(object)boat == (Object)null) { return; } byte styleMode = GetStyleMode(boat); bool flag = styleMode == 1 || styleMode == 3 || styleMode == 5 || styleMode == 7; Renderer[] componentsInChildren; try { componentsInChildren = ((Component)boat).GetComponentsInChildren(true); } catch { return; } if (componentsInChildren == null || componentsInChildren.Length == 0) { return; } HashSet hashSet = FindHullRenderers(componentsInChildren); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null || !hashSet.Contains(val)) { continue; } Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { continue; } if (sharedMaterials == null) { continue; } foreach (Material val2 in sharedMaterials) { if ((Object)(object)val2 == (Object)null || string.IsNullOrWhiteSpace(((Object)val2).name) || !((Object)val2).name.StartsWith("UntamoBoatSkin_", StringComparison.Ordinal)) { continue; } ApplyFinishProperties(val2, flag); if (styleMode == 7 || styleMode == 6 || styleMode == 8) { ApplyMaterialStyleProperties(val2, styleMode); } try { if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", flag ? 0.82f : 0.02f); } if (val2.HasProperty("_MetallicMetallicness")) { val2.SetFloat("_MetallicMetallicness", flag ? 0.82f : 0.02f); } if (val2.HasProperty("_Smoothness")) { val2.SetFloat("_Smoothness", flag ? 0.58f : 0.24f); } if (val2.HasProperty("_MetallicSmoothness")) { val2.SetFloat("_MetallicSmoothness", flag ? 0.58f : 0.24f); } if (val2.HasProperty("_PlasticSmoothness")) { val2.SetFloat("_PlasticSmoothness", flag ? 0.58f : 0.24f); } if (val2.HasProperty("_Glossiness")) { val2.SetFloat("_Glossiness", flag ? 0.58f : 0.24f); } } catch { } } } } private static bool HasForcedSkinMaterials(Boat boat, byte skinIndex) { if ((Object)(object)boat == (Object)null) { return false; } Renderer[] componentsInChildren; try { componentsInChildren = ((Component)boat).GetComponentsInChildren(true); } catch { return false; } if (componentsInChildren == null) { return false; } byte styleMode = GetStyleMode(boat); string value = string.Format("{0}{1}_S{2}_", "UntamoBoatSkin_", skinIndex, styleMode); string value2 = string.Format("{0}CAMO_{1}_", "UntamoBoatSkin_", skinIndex); HashSet hashSet = FindHullRenderers(componentsInChildren); int num = 0; int num2 = 0; foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null || !hashSet.Contains(val)) { continue; } Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { continue; } if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } bool flag = false; bool flag2 = false; foreach (Material val2 in sharedMaterials) { if ((Object)(object)val2 == (Object)null || ShouldKeepOriginalMaterial(val2)) { continue; } flag = true; if (!string.IsNullOrWhiteSpace(((Object)val2).name)) { string arg = GetFinishModeName(styleMode).Replace(" ", string.Empty); string value3 = string.Format("{0}{1}_{2}_", "UntamoBoatSkin_", skinIndex, arg); string value4 = string.Format("{0}{1}_GLASS_", "UntamoBoatSkin_", skinIndex); if (((Object)val2).name.StartsWith(value, StringComparison.Ordinal) || ((Object)val2).name.StartsWith(value3, StringComparison.Ordinal) || ((Object)val2).name.StartsWith(value4, StringComparison.Ordinal) || ((Object)val2).name.StartsWith(value2, StringComparison.Ordinal)) { flag2 = true; } } } if (flag) { num++; if (flag2) { num2++; } } } return num > 0 && num2 == num; } internal static void DumpCustomSkinTargets(Boat boat, ManualLogSource logger) { if ((Object)(object)boat == (Object)null) { if (logger != null) { logger.LogWarning((object)"F10 pattern material dump: no boat selected."); } return; } byte skinIndex = GetSkinIndex(boat); byte styleMode = GetStyleMode(boat); byte stripeSecondarySkinIndex = GetStripeSecondarySkinIndex(boat); try { string text = Path.Combine(Paths.PluginPath, "Untamo_Boats_Skins"); Directory.CreateDirectory(text); string text2 = Path.Combine(text, $"PatternMaterials_Skin5_Skin9_{DateTime.Now:yyyyMMdd_HHmmss}"); Directory.CreateDirectory(text2); RestoreOriginalMaterials(boat); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Untamo.Boats native pattern material debugger"); stringBuilder.AppendLine("Only native Skin 5 (Camo) and Skin 9 (Stripes) are included."); stringBuilder.AppendLine("Boat: " + ((Object)boat).name); stringBuilder.AppendLine($"Previous effective skin: {skinIndex}"); stringBuilder.AppendLine($"Previous style mode: {styleMode}"); stringBuilder.AppendLine($"Previous secondary color slot: {stripeSecondarySkinIndex}"); stringBuilder.AppendLine(); DumpNativePatternSkin(boat, 5, "CAMO", text2, stringBuilder); stringBuilder.AppendLine(); stringBuilder.AppendLine("============================================================"); stringBuilder.AppendLine(); DumpNativePatternSkin(boat, 9, "STRIPES", text2, stringBuilder); string path = Path.Combine(text2, "PatternMaterials_Skin5_Skin9.txt"); File.WriteAllText(path, stringBuilder.ToString(), Encoding.UTF8); if (logger != null) { logger.LogInfo((object)("F10 Skin 5/9 pattern material dump saved: " + text2)); } } catch (Exception arg) { if (logger != null) { logger.LogError((object)$"F10 Skin 5/9 pattern material dump failed: {arg}"); } } finally { try { if (skinIndex <= 13) { RestoreOriginalMaterials(boat); boat.ServerSetSkin(skinIndex); } else { SkinStyleModes[boat] = NormalizeStyleMode(styleMode); StripeSecondarySkinSlots[boat] = NormalizeStripeSecondarySkinIndex(stripeSecondarySkinIndex); ApplySkin(boat, skinIndex); } } catch (Exception arg2) { if (logger != null) { logger.LogError((object)$"F10 pattern debugger could not restore previous skin: {arg2}"); } } } } private static void DumpNativePatternSkin(Boat boat, byte nativeSkinIndex, string label, string runFolder, StringBuilder builder) { //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: 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_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) builder.AppendLine($"===== {label} | NATIVE SKIN {nativeSkinIndex} ====="); string text = Path.Combine(runFolder, $"Skin{nativeSkinIndex}_{label}_Textures"); try { Directory.CreateDirectory(text); } catch { } if ((Object)(object)boat == (Object)null) { builder.AppendLine(""); return; } try { boat.ServerSetSkin(nativeSkinIndex); } catch (Exception arg) { builder.AppendLine($"ServerSetSkin({nativeSkinIndex}) failed: {arg}"); return; } builder.AppendLine($"boat.CurSkin={boat.CurSkin}"); Renderer[] componentsInChildren; try { componentsInChildren = ((Component)boat).GetComponentsInChildren(true); } catch (Exception arg2) { builder.AppendLine($"Renderer read failed: {arg2}"); return; } HashSet hashSet = FindHullRenderers(componentsInChildren); int num = 0; foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || !hashSet.Contains(val)) { continue; } num++; builder.AppendLine(); builder.AppendLine($"[RENDERER {num}] {GetRendererPath(((Component)val).transform, ((Component)boat).transform)}"); builder.AppendLine("GameObject=" + ((Object)((Component)val).gameObject).name); builder.AppendLine("RendererType=" + ((object)val).GetType().FullName); Bounds bounds = val.bounds; Vector3 size = ((Bounds)(ref bounds)).size; builder.AppendLine($"BoundsSize={size.x:R},{size.y:R},{size.z:R}"); Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch (Exception arg3) { builder.AppendLine($"sharedMaterials read failed: {arg3}"); continue; } if (sharedMaterials == null || sharedMaterials.Length == 0) { builder.AppendLine(""); continue; } for (int j = 0; j < sharedMaterials.Length; j++) { DumpMaterialDetails(sharedMaterials[j], nativeSkinIndex, label, num, j, text, builder); } } builder.AppendLine(); builder.AppendLine($"TargetRendererCount={num}"); } private static void DumpMaterialDetails(Material material, byte nativeSkinIndex, string label, int rendererIndex, int materialIndex, string textureFolder, StringBuilder builder) { //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0179: 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_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0184: 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_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Expected I4, but got Unknown //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_0442: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) //IL_0460: Unknown result type (might be due to invalid IL or missing references) builder.AppendLine(); builder.AppendLine($" [MATERIAL {materialIndex}]"); if ((Object)(object)material == (Object)null) { builder.AppendLine(" "); return; } builder.AppendLine(" Name=" + ((Object)material).name); Shader shader = material.shader; builder.AppendLine(" Shader=" + (((Object)(object)shader == (Object)null) ? "" : ((Object)shader).name)); string[] array = null; try { array = material.GetTexturePropertyNames(); } catch { array = null; } builder.AppendLine(" TEXTURES:"); if (array == null || array.Length == 0) { builder.AppendLine(" "); } else { foreach (string text in array) { Texture val = null; try { val = material.GetTexture(text); } catch { } if ((Object)(object)val == (Object)null) { builder.AppendLine(" " + text + "="); continue; } string fullName = ((object)val).GetType().FullName; string text2 = string.Empty; Texture2D val2 = (Texture2D)(object)((val is Texture2D) ? val : null); if ((Object)(object)val2 != (Object)null) { text2 = $" format={val2.format} readable={((Texture)val2).isReadable}"; } Vector2 val3 = Vector2.one; Vector2 val4 = Vector2.zero; try { val3 = material.GetTextureScale(text); val4 = material.GetTextureOffset(text); } catch { } builder.AppendLine($" {text} | name={((Object)val).name} | type={fullName} | size={val.width}x{val.height}{text2} | scale={val3.x:R},{val3.y:R} | offset={val4.x:R},{val4.y:R}"); string text3 = ExportTextureAsPng(val, nativeSkinIndex, label, rendererIndex, materialIndex, text, textureFolder); if (!string.IsNullOrWhiteSpace(text3)) { builder.AppendLine(" PNG=" + text3); } } } builder.AppendLine(" SHADER_PROPERTIES:"); if ((Object)(object)shader == (Object)null) { builder.AppendLine(" "); return; } int propertyCount; try { propertyCount = shader.GetPropertyCount(); } catch (Exception arg) { builder.AppendLine($" GetPropertyCount failed: {arg}"); return; } for (int j = 0; j < propertyCount; j++) { string propertyName; string propertyDescription; ShaderPropertyType propertyType; try { propertyName = shader.GetPropertyName(j); propertyDescription = shader.GetPropertyDescription(j); propertyType = shader.GetPropertyType(j); } catch (Exception arg2) { builder.AppendLine($" P{j} read failed: {arg2}"); continue; } builder.Append($" P{j} | {propertyType} | {propertyName}"); if (!string.IsNullOrWhiteSpace(propertyDescription)) { builder.Append(" | desc=" + propertyDescription); } try { ShaderPropertyType val5 = propertyType; ShaderPropertyType val6 = val5; switch ((int)val6) { case 0: { Color color = material.GetColor(propertyName); builder.Append($" | value=RGBA({color.r:R},{color.g:R},{color.b:R},{color.a:R})"); break; } case 2: case 3: { float num = material.GetFloat(propertyName); builder.Append($" | value={num:R}"); break; } case 1: { Vector4 vector = material.GetVector(propertyName); builder.Append($" | value=({vector.x:R},{vector.y:R},{vector.z:R},{vector.w:R})"); break; } case 4: { Texture texture = material.GetTexture(propertyName); builder.Append(" | value=" + (((Object)(object)texture == (Object)null) ? "" : ((Object)texture).name)); break; } } } catch (Exception ex) { builder.Append(" | value-read-failed=" + ex.GetType().Name + ": " + ex.Message); } builder.AppendLine(); } } private static string ExportTextureAsPng(Texture source, byte nativeSkinIndex, string label, int rendererIndex, int materialIndex, string propertyName, string textureFolder) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null || string.IsNullOrWhiteSpace(textureFolder)) { return null; } RenderTexture val = null; RenderTexture active = RenderTexture.active; Texture2D val2 = null; try { int num = Mathf.Max(1, source.width); int num2 = Mathf.Max(1, source.height); val = RenderTexture.GetTemporary(num, num2, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)0); Graphics.Blit(source, val); RenderTexture.active = val; val2 = new Texture2D(num, num2, (TextureFormat)4, false); val2.ReadPixels(new Rect(0f, 0f, (float)num, (float)num2), 0, 0, false); val2.Apply(false, false); byte[] array = ImageConversion.EncodeToPNG(val2); if (array == null || array.Length == 0) { return null; } string text = SanitizeDumpFileName(label); string text2 = SanitizeDumpFileName(propertyName); string text3 = SanitizeDumpFileName(((Object)source).name); string path = $"Skin{nativeSkinIndex}_{text}_R{rendererIndex}_M{materialIndex}_{text2}_{text3}.png"; string text4 = Path.Combine(textureFolder, path); File.WriteAllBytes(text4, array); return text4; } catch { return null; } finally { RenderTexture.active = active; if ((Object)(object)val != (Object)null) { RenderTexture.ReleaseTemporary(val); } if ((Object)(object)val2 != (Object)null) { try { Object.Destroy((Object)(object)val2); } catch { } } } } private static string SanitizeDumpFileName(string value) { if (string.IsNullOrWhiteSpace(value)) { return "unnamed"; } char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); StringBuilder stringBuilder = new StringBuilder(value.Length); foreach (char c in value) { bool flag = false; for (int j = 0; j < invalidFileNameChars.Length; j++) { if (c == invalidFileNameChars[j]) { flag = true; break; } } stringBuilder.Append(flag ? '_' : c); } return stringBuilder.ToString(); } private static HashSet FindHullRenderers(Renderer[] renderers) { HashSet hashSet = new HashSet(); if (renderers == null || renderers.Length == 0) { return hashSet; } foreach (Renderer val in renderers) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && !ShouldSkipRenderer(val)) { string a = (string.IsNullOrWhiteSpace(((Object)((Component)val).gameObject).name) ? string.Empty : ((Object)((Component)val).gameObject).name); if (string.Equals(a, "Plank", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "Boat", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "Boat.001", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "Boat2", StringComparison.OrdinalIgnoreCase)) { hashSet.Add(val); } } } return hashSet; } private static string GetRendererSearchName(Renderer renderer) { if ((Object)(object)renderer == (Object)null) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(); Transform val = ((Component)renderer).transform; int num = 0; while ((Object)(object)val != (Object)null && num < 5) { if (!string.IsNullOrWhiteSpace(((Object)val).name)) { stringBuilder.Append(((Object)val).name.ToLowerInvariant()); stringBuilder.Append(" "); } val = val.parent; num++; } Material[] sharedMaterials = renderer.sharedMaterials; if (sharedMaterials != null) { foreach (Material val2 in sharedMaterials) { if (!((Object)(object)val2 == (Object)null) && !string.IsNullOrWhiteSpace(((Object)val2).name)) { stringBuilder.Append(((Object)val2).name.ToLowerInvariant()); stringBuilder.Append(" "); } } } return stringBuilder.ToString(); } private static string GetRendererPath(Transform transform, Transform root) { if ((Object)(object)transform == (Object)null) { return ""; } List list = new List(); Transform val = transform; while ((Object)(object)val != (Object)null) { list.Add(((Object)val).name); if ((Object)(object)val == (Object)(object)root) { break; } val = val.parent; } list.Reverse(); return string.Join("/", list.ToArray()); } private static bool ShouldSkipRenderer(Renderer renderer) { if ((Object)(object)renderer == (Object)null || (Object)(object)((Component)renderer).gameObject == (Object)null) { return true; } Transform val = ((Component)renderer).transform; int num = 0; while ((Object)(object)val != (Object)null && num < 6) { string text = (string.IsNullOrWhiteSpace(((Object)val).name) ? string.Empty : ((Object)val).name.ToLowerInvariant()); if (text.Contains("radar") || text.Contains("gps") || text.Contains("motor") || text.Contains("engine") || text.Contains("propeller") || text.Contains("propellor") || text.Contains("audio") || text.Contains("light") || text.Contains("seat") || text.Contains("chair") || text.Contains("steer") || text.Contains("wheel") || text.Contains("console") || text.Contains("rail") || text.Contains("rope") || text.Contains("canopy") || text.Contains("roof")) { return true; } val = val.parent; num++; } return false; } private static bool ShouldKeepOriginalMaterial(Material material) { if ((Object)(object)material == (Object)null) { return true; } string text = (string.IsNullOrWhiteSpace(((Object)material).name) ? string.Empty : ((Object)material).name.ToLowerInvariant()); return text.Contains("glass") || text.Contains("window") || text.Contains("transparent") || text.Contains("water"); } private static void RestoreOriginalMaterials(Boat boat) { if ((Object)(object)boat == (Object)null || !OriginalMaterials.TryGetValue(boat, out var value) || value == null) { return; } foreach (KeyValuePair item in value) { Renderer key = item.Key; if (!((Object)(object)key == (Object)null)) { Material[] array = null; try { array = key.sharedMaterials; key.SetPropertyBlock((MaterialPropertyBlock)null); key.sharedMaterials = item.Value; key.enabled = false; key.enabled = true; } catch { continue; } DestroyClonedMaterials(array, item.Value); } } OriginalMaterials.Remove(boat); } private static void DestroyClonedMaterials(Material[] candidates, Material[] originals) { if (candidates == null) { return; } foreach (Material val in candidates) { if ((Object)(object)val == (Object)null) { continue; } bool flag = false; if (originals != null) { for (int j = 0; j < originals.Length; j++) { if ((Object)(object)val == (Object)(object)originals[j]) { flag = true; break; } } } if (!flag && !string.IsNullOrWhiteSpace(((Object)val).name) && ((Object)val).name.StartsWith("UntamoBoatSkin_", StringComparison.Ordinal)) { try { Object.Destroy((Object)(object)val); } catch { } } } } } internal static class BoatControlSkinRouting { private const byte MinimumControlSkinIndex = 14; private const byte MaximumControlSkinIndex = 63; private const byte OriginalControlSkinIndex = byte.MaxValue; private static readonly Dictionary DesiredSkins = new Dictionary(); private static readonly Dictionary MotorMountUsesControls = new Dictionary(); private static readonly Dictionary AppliedSkins = new Dictionary(); private static readonly Dictionary> OriginalMaterials = new Dictionary>(); private static readonly Dictionary> MotorMountStockMaterials = new Dictionary>(); private static readonly FieldInfo SteeringWheelField = AccessTools.Field(typeof(Boat), "_steeringWheel"); private static readonly FieldInfo WheelField = AccessTools.Field(typeof(Boat), "_wheel"); private static float _nextRefresh; internal static byte NormalizeSkinIndex(byte skinIndex) { int result; switch (skinIndex) { case byte.MaxValue: return byte.MaxValue; case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: result = skinIndex; break; default: result = 14; break; } return (byte)result; } internal static byte ParseSavedSkinIndex(string value) { byte result; return (byte)(byte.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result) ? NormalizeSkinIndex(result) : 14); } internal static byte GetSkinIndex(Boat boat) { if ((Object)(object)boat == (Object)null) { return 14; } byte value; return (byte)(DesiredSkins.TryGetValue(boat, out value) ? NormalizeSkinIndex(value) : 14); } internal static string GetSkinDisplayName(Boat boat) { byte skinIndex = GetSkinIndex(boat); return (skinIndex == byte.MaxValue) ? "Original" : skinIndex.ToString(CultureInfo.InvariantCulture); } internal static bool IsMotorMountUsingControls(Boat boat) { if ((Object)(object)boat == (Object)null) { return false; } bool value; return MotorMountUsesControls.TryGetValue(boat, out value) && value; } internal static string GetMotorMountModeName(Boat boat) { return IsMotorMountUsingControls(boat) ? "Original/Controls" : "Original/Mount"; } internal static void SetMotorMountMode(Boat boat, bool useControls, bool reapplyControls) { if (!((Object)(object)boat == (Object)null)) { MotorMountUsesControls[boat] = useControls; if (reapplyControls) { ApplySkin(boat, GetSkinIndex(boat)); } } } internal static bool ToggleMotorMountMode(Boat boat) { if ((Object)(object)boat == (Object)null || MotorRouting.HasNoMotor(boat)) { return false; } MotorMountUsesControls[boat] = !IsMotorMountUsingControls(boat); return ApplySkin(boat, GetSkinIndex(boat)); } internal static bool TryGetCycledSkin(Boat boat, int direction, out byte skinIndex) { skinIndex = GetSkinIndex(boat); if ((Object)(object)boat == (Object)null || direction == 0) { return false; } int num = ((skinIndex == byte.MaxValue) ? ((direction > 0) ? 14 : 63) : ((direction <= 0) ? ((skinIndex <= 14) ? 255 : (skinIndex - 1)) : ((skinIndex >= 63) ? 255 : (skinIndex + 1)))); skinIndex = (byte)num; return skinIndex != GetSkinIndex(boat); } internal static void EnsureDesiredSkin(Boat boat, byte skinIndex) { if (!((Object)(object)boat == (Object)null)) { skinIndex = NormalizeSkinIndex(skinIndex); DesiredSkins[boat] = skinIndex; if (!IsSkinActuallyApplied(boat, skinIndex)) { AppliedSkins.Remove(boat); RestoreOriginalMaterials(boat); ApplySkin(boat, skinIndex); } } } internal static bool IsSkinActuallyApplied(Boat boat, byte skinIndex) { if ((Object)(object)boat == (Object)null || !((NetworkBehaviour)boat).IsSpawned) { return false; } skinIndex = NormalizeSkinIndex(skinIndex); if (skinIndex == byte.MaxValue) { List renderers = FindControlRenderers(boat); CaptureMotorMountStockMaterials(boat, renderers); if (IsMotorMountUsingControls(boat)) { return true; } return AreMotorMountsUsingStockMaterials(boat); } string value = "Untamo Control " + skinIndex.ToString(CultureInfo.InvariantCulture); List list = FindControlRenderers(boat); if (list.Count == 0) { return false; } bool result = false; for (int i = 0; i < list.Count; i++) { Renderer val = list[i]; if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || val is ParticleSystemRenderer) { continue; } Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { return false; } if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } bool flag = false; bool flag2 = false; foreach (Material val2 in sharedMaterials) { if (!((Object)(object)val2 == (Object)null)) { flag = true; if (!string.IsNullOrEmpty(((Object)val2).name) && ((Object)val2).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { flag2 = true; break; } } } if (flag && (!BoatMotorSkinRouting.IsMotorMountRenderer(boat, val) || IsMotorMountUsingControls(boat))) { result = true; if (!flag2) { return false; } } } return result; } internal static bool CopySkinFromBoat(Boat source, Boat target) { if ((Object)(object)source == (Object)null || (Object)(object)target == (Object)null) { return false; } return ApplySkin(target, GetSkinIndex(source)); } internal static bool ApplySkin(Boat boat, byte skinIndex) { if ((Object)(object)boat == (Object)null) { return false; } skinIndex = NormalizeSkinIndex(skinIndex); DesiredSkins[boat] = skinIndex; RestoreOriginalMaterials(boat); List list = FindControlRenderers(boat); CaptureMotorMountStockMaterials(boat, list); if (skinIndex == byte.MaxValue) { if (IsMotorMountUsingControls(boat)) { ApplyMotorMountFromControlTemplate(boat); } else { RestoreMotorMountStockMaterials(boat); } AppliedSkins[boat] = byte.MaxValue; return true; } if (list.Count == 0) { return false; } Material[] controlTemplateMaterials = GetControlTemplateMaterials(boat); Dictionary dictionary = new Dictionary(); int num = 0; for (int i = 0; i < list.Count; i++) { Renderer val = list[i]; if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null) { continue; } bool flag = BoatMotorSkinRouting.IsMotorMountRenderer(boat, val); Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { continue; } if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; Array.Copy(sharedMaterials, array, sharedMaterials.Length); Material[] array2 = (Material[])(object)new Material[sharedMaterials.Length]; bool flag2 = false; for (int j = 0; j < sharedMaterials.Length; j++) { Material val2 = sharedMaterials[j]; if ((Object)(object)val2 == (Object)null) { array2[j] = null; continue; } Material val3 = val2; if (flag && controlTemplateMaterials != null && controlTemplateMaterials.Length != 0) { int num2 = Mathf.Clamp(j, 0, controlTemplateMaterials.Length - 1); Material val4 = controlTemplateMaterials[num2]; if ((Object)(object)val4 != (Object)null) { val3 = val4; } } Material val5 = BoatSkinRouting.CreateSolidControlMaterial(val3, skinIndex, i, j); if ((Object)(object)val5 != (Object)null && flag) { ((Object)val5).name = $"{((Object)val3).name} Untamo Control {skinIndex} MotorMount"; } array2[j] = (((Object)(object)val5 != (Object)null) ? val5 : val2); flag2 |= (Object)(object)val5 != (Object)null; } if (flag2) { try { dictionary[val] = array; val.SetPropertyBlock((MaterialPropertyBlock)null); val.sharedMaterials = array2; num++; } catch { } } } if (num == 0) { return false; } OriginalMaterials[boat] = dictionary; if (!IsMotorMountUsingControls(boat)) { RestoreMotorMountStockMaterials(boat); } AppliedSkins[boat] = skinIndex; return true; } internal static void Update() { if (Time.unscaledTime < _nextRefresh) { return; } _nextRefresh = Time.unscaledTime + 0.5f; if (DesiredSkins.Count == 0) { return; } List list = new List(DesiredSkins.Keys); for (int i = 0; i < list.Count; i++) { Boat val = list[i]; if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned) { ClearForBoat(val); continue; } byte skinIndex = GetSkinIndex(val); if (!AppliedSkins.TryGetValue(val, out var value) || value != skinIndex || !IsSkinActuallyApplied(val, skinIndex)) { EnsureDesiredSkin(val, skinIndex); } } } internal static void ClearForBoat(Boat boat) { if (!((Object)(object)boat == (Object)null)) { RestoreOriginalMaterials(boat); RestoreMotorMountStockMaterials(boat); MotorMountStockMaterials.Remove(boat); MotorMountUsesControls.Remove(boat); DesiredSkins.Remove(boat); AppliedSkins.Remove(boat); } } private static void CaptureMotorMountStockMaterials(Boat boat, List renderers) { if ((Object)(object)boat == (Object)null || renderers == null) { return; } if (!MotorMountStockMaterials.TryGetValue(boat, out var value) || value == null) { value = new Dictionary(); MotorMountStockMaterials[boat] = value; } for (int i = 0; i < renderers.Count; i++) { Renderer val = renderers[i]; if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || val is ParticleSystemRenderer || !BoatMotorSkinRouting.IsMotorMountRenderer(boat, val) || value.ContainsKey(val)) { continue; } Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { continue; } if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } bool flag = false; foreach (Material val2 in sharedMaterials) { if (!((Object)(object)val2 == (Object)null) && !string.IsNullOrEmpty(((Object)val2).name) && (((Object)val2).name.IndexOf("Untamo Control ", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)val2).name.IndexOf("Untamo Motor ", StringComparison.OrdinalIgnoreCase) >= 0)) { flag = true; break; } } if (!flag) { Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; Array.Copy(sharedMaterials, array, sharedMaterials.Length); value[val] = array; } } } private static void ApplyMotorMountFromControlTemplate(Boat boat) { if ((Object)(object)boat == (Object)null) { return; } HashSet hashSet = new HashSet(); BoatMotorSkinRouting.AddMotorMountRenderers(boat, hashSet); Material[] controlTemplateMaterials = GetControlTemplateMaterials(boat); if (controlTemplateMaterials == null || controlTemplateMaterials.Length == 0) { return; } foreach (Renderer item in hashSet) { if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null) { continue; } Material[] sharedMaterials; try { sharedMaterials = item.sharedMaterials; } catch { continue; } if (sharedMaterials != null && sharedMaterials.Length != 0) { Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; for (int i = 0; i < array.Length; i++) { Material val = controlTemplateMaterials[Mathf.Clamp(i, 0, controlTemplateMaterials.Length - 1)]; array[i] = (((Object)(object)val != (Object)null) ? val : sharedMaterials[i]); } try { item.SetPropertyBlock((MaterialPropertyBlock)null); item.sharedMaterials = array; } catch { } } } } private static void RestoreMotorMountStockMaterials(Boat boat) { if ((Object)(object)boat == (Object)null || !MotorMountStockMaterials.TryGetValue(boat, out var value) || value == null) { return; } foreach (KeyValuePair item in value) { Renderer key = item.Key; if (!((Object)(object)key == (Object)null) && !((Object)(object)((Component)key).gameObject == (Object)null)) { try { key.SetPropertyBlock((MaterialPropertyBlock)null); key.sharedMaterials = item.Value; } catch { } } } } private static bool AreMotorMountsUsingStockMaterials(Boat boat) { if ((Object)(object)boat == (Object)null) { return false; } List renderers = FindControlRenderers(boat); CaptureMotorMountStockMaterials(boat, renderers); if (!MotorMountStockMaterials.TryGetValue(boat, out var value) || value == null || value.Count == 0) { return true; } bool flag = false; foreach (KeyValuePair item in value) { Renderer key = item.Key; if ((Object)(object)key == (Object)null || (Object)(object)((Component)key).gameObject == (Object)null || !((Component)key).gameObject.activeInHierarchy) { continue; } Material[] sharedMaterials; try { sharedMaterials = key.sharedMaterials; } catch { return false; } Material[] value2 = item.Value; if (sharedMaterials == null || value2 == null || sharedMaterials.Length != value2.Length) { return false; } flag = true; for (int i = 0; i < sharedMaterials.Length; i++) { if ((Object)(object)sharedMaterials[i] != (Object)(object)value2[i]) { return false; } } } return flag || value.Count == 0; } internal static Material[] GetControlTemplateMaterials(Boat boat) { if ((Object)(object)boat == (Object)null) { return null; } HashSet hashSet = new HashSet(); AddRenderersFromField(boat, SteeringWheelField, hashSet); AddRenderersFromField(boat, WheelField, hashSet); foreach (Renderer item in hashSet) { if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).gameObject == (Object)null || item is ParticleSystemRenderer || BoatMotorSkinRouting.IsMotorMountRenderer(boat, item)) { continue; } Material[] sharedMaterials; try { sharedMaterials = item.sharedMaterials; } catch { continue; } if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } for (int i = 0; i < sharedMaterials.Length; i++) { if ((Object)(object)sharedMaterials[i] != (Object)null) { Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; Array.Copy(sharedMaterials, array, sharedMaterials.Length); return array; } } } Renderer[] array2; try { array2 = ((Component)boat).GetComponentsInChildren(true); } catch { array2 = null; } if (array2 == null) { return null; } foreach (Renderer val in array2) { if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).transform == (Object)null || val is ParticleSystemRenderer || BoatMotorSkinRouting.IsMotorMountRenderer(boat, val)) { continue; } string lowerPath = GetLowerPath(((Component)val).transform); if (!lowerPath.Contains("steer") && !lowerPath.Contains("steering") && !lowerPath.Contains("wheel") && !lowerPath.Contains("throttle") && !lowerPath.Contains("lever")) { continue; } try { Material[] sharedMaterials2 = val.sharedMaterials; if (sharedMaterials2 != null && sharedMaterials2.Length != 0) { return sharedMaterials2; } } catch { } } return null; } private static List FindControlRenderers(Boat boat) { HashSet hashSet = new HashSet(); AddRenderersFromField(boat, SteeringWheelField, hashSet); AddRenderersFromField(boat, WheelField, hashSet); Renderer[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } if (array != null) { foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).transform == (Object)null)) { string lowerPath = GetLowerPath(((Component)val).transform); if (!lowerPath.Contains("motor") && !lowerPath.Contains("propeller") && !lowerPath.Contains("propellor") && (lowerPath.Contains("steer") || lowerPath.Contains("steering") || lowerPath.Contains("wheel") || lowerPath.Contains("throttle") || lowerPath.Contains("lever"))) { hashSet.Add(val); } } } } BoatMotorSkinRouting.AddMotorMountRenderers(boat, hashSet); return new List(hashSet); } private static void AddRenderersFromField(Boat boat, FieldInfo field, HashSet result) { if ((Object)(object)boat == (Object)null || field == null || result == null) { return; } object value; try { value = field.GetValue(boat); } catch { return; } GameObject val = (GameObject)((value is GameObject) ? value : null); Component val2 = (Component)((value is Component) ? value : null); Transform val3 = (Transform)((value is Transform) ? value : null); if ((Object)(object)val == (Object)null && (Object)(object)val2 != (Object)null) { val = val2.gameObject; } if ((Object)(object)val == (Object)null && (Object)(object)val3 != (Object)null) { val = ((Component)val3).gameObject; } if ((Object)(object)val == (Object)null) { return; } Renderer[] componentsInChildren; try { componentsInChildren = val.GetComponentsInChildren(true); } catch { return; } for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null) { result.Add(componentsInChildren[i]); } } } private static string GetLowerPath(Transform transform) { StringBuilder stringBuilder = new StringBuilder(); Transform val = transform; int num = 0; while ((Object)(object)val != (Object)null && num < 8) { if (stringBuilder.Length > 0) { stringBuilder.Insert(0, '/'); } stringBuilder.Insert(0, ((Object)val).name ?? string.Empty); val = val.parent; num++; } return stringBuilder.ToString().ToLowerInvariant(); } private static void RestoreOriginalMaterials(Boat boat) { if ((Object)(object)boat == (Object)null || !OriginalMaterials.TryGetValue(boat, out var value) || value == null) { return; } foreach (KeyValuePair item in value) { Renderer key = item.Key; if (!((Object)(object)key == (Object)null)) { Material[] candidates = null; try { candidates = key.sharedMaterials; key.SetPropertyBlock((MaterialPropertyBlock)null); key.sharedMaterials = item.Value; } catch { } DestroyControlMaterials(candidates, item.Value); } } OriginalMaterials.Remove(boat); } private static void DestroyControlMaterials(Material[] candidates, Material[] originals) { if (candidates == null) { return; } foreach (Material val in candidates) { if ((Object)(object)val == (Object)null) { continue; } bool flag = false; if (originals != null) { for (int j = 0; j < originals.Length; j++) { if ((Object)(object)val == (Object)(object)originals[j]) { flag = true; break; } } } if (!flag) { try { Object.Destroy((Object)(object)val); } catch { } } } } } internal static class BoatMotorSkinRouting { private const byte MinimumSkinIndex = 14; private const byte MaximumSkinIndex = 63; internal const byte OriginalSkinIndex = byte.MaxValue; private const byte FinishOriginal = 0; internal const byte FinishOriginalForMaterial = 0; private const byte FinishMetallic = 1; private const byte FinishChrome = 2; private const byte FinishControls = 3; private static readonly Dictionary DesiredFinishes = new Dictionary(); private static readonly Dictionary DesiredSkins = new Dictionary(); private static readonly Dictionary> OriginalMaterials = new Dictionary>(); private static readonly Dictionary AppliedMotorObjects = new Dictionary(); private static readonly FieldInfo MotorRotationTargetsField = AccessTools.Field(typeof(BoatMotor), "_toRotate"); private static float _nextRefresh; internal static byte NormalizeSkinIndex(byte skinIndex) { int result; switch (skinIndex) { case byte.MaxValue: return byte.MaxValue; case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: result = skinIndex; break; default: result = 14; break; } return (byte)result; } internal static byte ParseSavedSkinIndex(string value) { byte result; return byte.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result) ? NormalizeSkinIndex(result) : byte.MaxValue; } internal static byte GetSkinIndex(Boat boat) { if ((Object)(object)boat == (Object)null) { return byte.MaxValue; } byte value; return DesiredSkins.TryGetValue(boat, out value) ? NormalizeSkinIndex(value) : byte.MaxValue; } internal static string GetSkinDisplayName(Boat boat) { byte skinIndex = GetSkinIndex(boat); return (skinIndex == byte.MaxValue) ? "Original" : ("Skin " + skinIndex.ToString(CultureInfo.InvariantCulture)); } internal static byte NormalizeFinishMode(byte finish) { return (byte)((finish > 3) ? 1 : finish); } internal static byte ParseSavedFinishMode(string value) { byte result; return (byte)((!byte.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result)) ? 1 : NormalizeFinishMode(result)); } internal static void SetFinishMode(Boat boat, byte finish, bool reapplySkin) { if (!((Object)(object)boat == (Object)null)) { DesiredFinishes[boat] = NormalizeFinishMode(finish); if (reapplySkin) { ApplySkin(boat, GetSkinIndex(boat)); } } } internal static byte GetFinishMode(Boat boat) { if ((Object)(object)boat == (Object)null) { return 1; } byte value; return (byte)((!DesiredFinishes.TryGetValue(boat, out value) || value > 3) ? 1 : value); } internal static string GetFinishName(Boat boat) { return GetFinishMode(boat) switch { 0 => "Original", 2 => "Chrome", 3 => "Controls", _ => "Metallic", }; } internal static bool ToggleFinish(Boat boat, int direction) { if ((Object)(object)boat == (Object)null || direction == 0) { return false; } int finishMode = GetFinishMode(boat); finishMode += ((direction >= 0) ? 1 : (-1)); if (finishMode > 3) { finishMode = 0; } else if (finishMode < 0) { finishMode = 3; } DesiredFinishes[boat] = (byte)finishMode; return ApplySkin(boat, GetSkinIndex(boat)); } internal static string GetHudDisplayName(Boat boat) { byte skinIndex = GetSkinIndex(boat); if (skinIndex == byte.MaxValue) { return "Original"; } return GetSkinDisplayName(boat) + " " + GetFinishName(boat); } internal static bool TryGetCycledSkin(Boat boat, int direction, out byte skinIndex) { skinIndex = GetSkinIndex(boat); if ((Object)(object)boat == (Object)null || direction == 0) { return false; } int num = ((skinIndex == byte.MaxValue) ? ((direction > 0) ? 14 : 63) : ((direction <= 0) ? ((skinIndex <= 14) ? 255 : (skinIndex - 1)) : ((skinIndex >= 63) ? 255 : (skinIndex + 1)))); skinIndex = (byte)num; return skinIndex != GetSkinIndex(boat); } internal static void EnsureDesiredSkin(Boat boat, byte skinIndex) { if (!((Object)(object)boat == (Object)null)) { skinIndex = NormalizeSkinIndex(skinIndex); DesiredSkins[boat] = skinIndex; GameObject liveMotorObject = GetLiveMotorObject(boat); if (!AppliedMotorObjects.TryGetValue(boat, out var value) || !((Object)(object)value == (Object)(object)liveMotorObject) || !((Object)(object)liveMotorObject != (Object)null) || !IsSkinActuallyApplied(boat, skinIndex)) { ApplySkin(boat, skinIndex); } } } internal static bool ApplySkin(Boat boat, byte skinIndex) { if ((Object)(object)boat == (Object)null) { return false; } skinIndex = NormalizeSkinIndex(skinIndex); DesiredSkins[boat] = skinIndex; RestoreOriginalMaterials(boat); GameObject liveMotorObject = GetLiveMotorObject(boat); if (skinIndex == byte.MaxValue) { AppliedMotorObjects[boat] = liveMotorObject; return true; } List list = FindMotorAndMountRenderers(boat); if (list.Count == 0) { return false; } Material[] controlTemplateMaterials = BoatControlSkinRouting.GetControlTemplateMaterials(boat); Dictionary dictionary = new Dictionary(); int num = 0; for (int i = 0; i < list.Count; i++) { Renderer val = list[i]; if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || val is ParticleSystemRenderer) { continue; } Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { continue; } if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; Array.Copy(sharedMaterials, array, sharedMaterials.Length); Material[] array2 = (Material[])(object)new Material[sharedMaterials.Length]; bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { Material val2 = sharedMaterials[j]; if ((Object)(object)val2 == (Object)null) { array2[j] = null; continue; } Material controlTemplate = null; if (controlTemplateMaterials != null && controlTemplateMaterials.Length != 0) { int num2 = Mathf.Clamp(j, 0, controlTemplateMaterials.Length - 1); controlTemplate = controlTemplateMaterials[num2]; } Material val3 = BoatSkinRouting.CreateMotorFinishMaterial(val2, controlTemplate, skinIndex, GetFinishMode(boat), i, j); if ((Object)(object)val3 != (Object)null) { ((Object)val3).name = $"{((Object)val2).name} Untamo Motor {skinIndex} {GetFinishName(boat)}"; } array2[j] = (((Object)(object)val3 != (Object)null) ? val3 : val2); flag |= (Object)(object)val3 != (Object)null; } if (flag) { try { dictionary[val] = array; val.SetPropertyBlock((MaterialPropertyBlock)null); val.sharedMaterials = array2; num++; } catch { } } } if (num == 0) { return false; } OriginalMaterials[boat] = dictionary; AppliedMotorObjects[boat] = liveMotorObject; return true; } internal static bool IsSkinActuallyApplied(Boat boat, byte skinIndex) { if ((Object)(object)boat == (Object)null || !((NetworkBehaviour)boat).IsSpawned) { return false; } skinIndex = NormalizeSkinIndex(skinIndex); GameObject liveMotorObject = GetLiveMotorObject(boat); if (!AppliedMotorObjects.TryGetValue(boat, out var value) || (Object)(object)value != (Object)(object)liveMotorObject || (Object)(object)liveMotorObject == (Object)null) { return false; } if (skinIndex == byte.MaxValue) { return !HasUntamoMotorMaterial(boat); } string value2 = "Untamo Motor " + skinIndex.ToString(CultureInfo.InvariantCulture); List list = FindMotorAndMountRenderers(boat); for (int i = 0; i < list.Count; i++) { Renderer val = list[i]; if ((Object)(object)val == (Object)null) { continue; } Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { continue; } if (sharedMaterials == null) { continue; } foreach (Material val2 in sharedMaterials) { if ((Object)(object)val2 != (Object)null && !string.IsNullOrEmpty(((Object)val2).name) && ((Object)val2).name.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } return false; } internal static void Update() { if (Time.unscaledTime < _nextRefresh) { return; } _nextRefresh = Time.unscaledTime + 0.5f; if (DesiredSkins.Count == 0) { return; } List list = new List(DesiredSkins.Keys); for (int i = 0; i < list.Count; i++) { Boat val = list[i]; if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned) { ClearForBoat(val); continue; } byte skinIndex = GetSkinIndex(val); EnsureDesiredSkin(val, skinIndex); } } internal static void ClearForBoat(Boat boat) { if (!((Object)(object)boat == (Object)null)) { RestoreOriginalMaterials(boat); DesiredSkins.Remove(boat); DesiredFinishes.Remove(boat); AppliedMotorObjects.Remove(boat); } } internal static void ClearAllRuntime() { List list = new List(DesiredSkins.Keys); for (int i = 0; i < list.Count; i++) { Boat val = list[i]; if ((Object)(object)val != (Object)null) { RestoreOriginalMaterials(val); } } DesiredSkins.Clear(); DesiredFinishes.Clear(); AppliedMotorObjects.Clear(); OriginalMaterials.Clear(); _nextRefresh = 0f; } private static List FindMotorAndMountRenderers(Boat boat) { HashSet hashSet = new HashSet(); if ((Object)(object)boat == (Object)null) { return new List(); } if (MotorRouting.HasDualSuperBigMotors(boat)) { AddCustomMotorSiblingRenderers(boat, "Untamo Dual Super Big Motor Left", hashSet); AddCustomMotorSiblingRenderers(boat, "Untamo Dual Super Big Motor Right", hashSet); if (hashSet.Count > 0) { return new List(hashSet); } } else if (MotorRouting.HasSuperBigMotor(boat)) { AddCustomMotorSiblingRenderers(boat, "Untamo Super Big Motor", hashSet); if (hashSet.Count > 0) { return new List(hashSet); } } GameObject liveMotorObject = GetLiveMotorObject(boat); AddNativeMotorModelRenderers(liveMotorObject, hashSet); if (hashSet.Count == 0) { AddRenderers(liveMotorObject, hashSet); } return new List(hashSet); } private static void AddCustomMotorSiblingRenderers(Boat boat, string motorName, HashSet result) { if ((Object)(object)boat == (Object)null || string.IsNullOrEmpty(motorName) || result == null) { return; } GameObject currentMotorObject = MotorRouting.GetCurrentMotorObject(boat); Transform val = (((Object)(object)currentMotorObject != (Object)null) ? currentMotorObject.transform.parent : null); Transform val2 = (((Object)(object)val != (Object)null) ? val.Find(motorName) : null); if ((Object)(object)val2 == (Object)null) { Transform[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } if (array != null) { foreach (Transform val3 in array) { if ((Object)(object)val3 != (Object)null && string.Equals(((Object)val3).name, motorName, StringComparison.Ordinal)) { val2 = val3; break; } } } } if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null)) { AddNativeMotorModelRenderers(((Component)val2).gameObject, result); if (result.Count == 0) { AddRenderers(((Component)val2).gameObject, result); } } } private static void AddNativeMotorModelRenderers(GameObject motorRoot, HashSet result) { if ((Object)(object)motorRoot == (Object)null || result == null) { return; } BoatMotor val = motorRoot.GetComponent(); if ((Object)(object)val == (Object)null) { val = motorRoot.GetComponentInChildren(true); } Transform[] array = (((Object)(object)val == (Object)null) ? null : (MotorRotationTargetsField?.GetValue(val) as Transform[])); if (array == null || array.Length == 0) { return; } foreach (Transform val2 in array) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).gameObject == (Object)null)) { AddRenderers(((Component)val2).gameObject, result); } } } private static void AddRawNativeMotorModelRenderers(GameObject motorRoot, HashSet result) { if ((Object)(object)motorRoot == (Object)null || result == null) { return; } BoatMotor val = motorRoot.GetComponent(); if ((Object)(object)val == (Object)null) { val = motorRoot.GetComponentInChildren(true); } Transform[] array = (((Object)(object)val == (Object)null) ? null : (MotorRotationTargetsField?.GetValue(val) as Transform[])); if (array == null) { return; } foreach (Transform val2 in array) { if ((Object)(object)val2 == (Object)null) { continue; } Renderer[] componentsInChildren; try { componentsInChildren = ((Component)val2).GetComponentsInChildren(true); } catch { continue; } foreach (Renderer val3 in componentsInChildren) { if ((Object)(object)val3 != (Object)null && !(val3 is ParticleSystemRenderer)) { result.Add(val3); } } } } internal static bool IsMotorMountRenderer(Boat boat, Renderer renderer) { if ((Object)(object)boat == (Object)null || (Object)(object)renderer == (Object)null) { return false; } HashSet hashSet = new HashSet(); AddMotorMountRenderers(boat, hashSet); return hashSet.Contains(renderer); } internal static void AddMotorMountRenderers(Boat boat, HashSet result) { if (!((Object)(object)boat == (Object)null) && result != null && !MotorRouting.HasNoMotor(boat)) { if (MotorRouting.HasDualSuperBigMotors(boat)) { AddCustomMotorMountSiblingRenderers(boat, "Untamo Dual Super Big Motor Left", result); AddCustomMotorMountSiblingRenderers(boat, "Untamo Dual Super Big Motor Right", result); } else if (MotorRouting.HasSuperBigMotor(boat)) { AddCustomMotorMountSiblingRenderers(boat, "Untamo Super Big Motor", result); } else { GameObject liveMotorObject = GetLiveMotorObject(boat); AddMotorMountRenderersFromRoot(liveMotorObject, result); } } } private static void AddCustomMotorMountSiblingRenderers(Boat boat, string motorName, HashSet result) { if ((Object)(object)boat == (Object)null || string.IsNullOrEmpty(motorName) || result == null) { return; } GameObject currentMotorObject = MotorRouting.GetCurrentMotorObject(boat); Transform val = (((Object)(object)currentMotorObject != (Object)null) ? currentMotorObject.transform.parent : null); Transform val2 = (((Object)(object)val != (Object)null) ? val.Find(motorName) : null); if ((Object)(object)val2 == (Object)null) { Transform[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } if (array != null) { foreach (Transform val3 in array) { if ((Object)(object)val3 != (Object)null && string.Equals(((Object)val3).name, motorName, StringComparison.Ordinal)) { val2 = val3; break; } } } } if ((Object)(object)val2 != (Object)null && (Object)(object)((Component)val2).gameObject != (Object)null) { AddMotorMountRenderersFromRoot(((Component)val2).gameObject, result); } } private static void AddMotorMountRenderersFromRoot(GameObject motorRoot, HashSet result) { if ((Object)(object)motorRoot == (Object)null || result == null) { return; } HashSet hashSet = new HashSet(); AddRawNativeMotorModelRenderers(motorRoot, hashSet); Renderer[] array; try { array = motorRoot.GetComponentsInChildren(true); } catch { array = null; } if (array == null) { return; } foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && !(val is ParticleSystemRenderer) && (!hashSet.Contains(val) || LooksLikeMotorMountBracket(val))) { result.Add(val); } } } private static bool LooksLikeMotorMountBracket(Renderer renderer) { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: 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_00f1: 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_0109: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)renderer == (Object)null || (Object)(object)((Component)renderer).transform == (Object)null || renderer is ParticleSystemRenderer) { return false; } string text = (((Object)((Component)renderer).transform).name ?? string.Empty).ToLowerInvariant(); if (text.Contains("propeller") || text.Contains("propellor") || text.Contains("blade") || text.Contains("fan")) { return false; } if (text.Contains("mount") || text.Contains("bracket") || text.Contains("holder") || text.Contains("support")) { return true; } Vector3 size; try { Bounds bounds = renderer.bounds; size = ((Bounds)(ref bounds)).size; } catch { return false; } float num = Mathf.Abs(size.x); float num2 = Mathf.Abs(size.y); float num3 = Mathf.Abs(size.z); float num4 = Mathf.Max(num, Mathf.Max(num2, num3)); float num5 = Mathf.Min(num, Mathf.Min(num2, num3)); float num6 = num + num2 + num3 - num4 - num5; if (num6 <= 0.0001f) { return false; } return num4 >= num6 * 2.25f; } private static GameObject GetLiveMotorObject(Boat boat) { if ((Object)(object)boat == (Object)null) { return null; } GameObject currentMotorObject = MotorRouting.GetCurrentMotorObject(boat); if ((Object)(object)currentMotorObject != (Object)null && currentMotorObject.activeInHierarchy) { return currentMotorObject; } GameObject motorObject = MotorRouting.GetMotorObject(boat, boat.MotorIndex); if ((Object)(object)motorObject != (Object)null && motorObject.activeInHierarchy) { return motorObject; } return null; } private static void AddRenderers(GameObject root, HashSet result) { if ((Object)(object)root == (Object)null || result == null) { return; } Renderer[] componentsInChildren; try { componentsInChildren = root.GetComponentsInChildren(true); } catch { return; } foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !(val is ParticleSystemRenderer) && !LooksLikeMotorMountBracket(val)) { result.Add(val); } } } private static string GetLowerPath(Transform transform) { StringBuilder stringBuilder = new StringBuilder(); Transform val = transform; int num = 0; while ((Object)(object)val != (Object)null && num < 10) { if (stringBuilder.Length > 0) { stringBuilder.Insert(0, '/'); } stringBuilder.Insert(0, ((Object)val).name ?? string.Empty); val = val.parent; num++; } return stringBuilder.ToString().ToLowerInvariant(); } private static bool HasUntamoMotorMaterial(Boat boat) { List list = FindMotorAndMountRenderers(boat); for (int i = 0; i < list.Count; i++) { Renderer val = list[i]; if ((Object)(object)val == (Object)null) { continue; } Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { continue; } if (sharedMaterials == null) { continue; } foreach (Material val2 in sharedMaterials) { if ((Object)(object)val2 != (Object)null && !string.IsNullOrEmpty(((Object)val2).name) && ((Object)val2).name.IndexOf("Untamo Motor ", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } return false; } private static void RestoreOriginalMaterials(Boat boat) { if ((Object)(object)boat == (Object)null || !OriginalMaterials.TryGetValue(boat, out var value) || value == null) { return; } foreach (KeyValuePair item in value) { Renderer key = item.Key; if (!((Object)(object)key == (Object)null)) { Material[] candidates = null; try { candidates = key.sharedMaterials; key.SetPropertyBlock((MaterialPropertyBlock)null); key.sharedMaterials = item.Value; } catch { } DestroyMotorMaterials(candidates, item.Value); } } OriginalMaterials.Remove(boat); } private static void DestroyMotorMaterials(Material[] candidates, Material[] originals) { if (candidates == null) { return; } foreach (Material val in candidates) { if ((Object)(object)val == (Object)null) { continue; } bool flag = false; if (originals != null) { for (int j = 0; j < originals.Length; j++) { if ((Object)(object)val == (Object)(object)originals[j]) { flag = true; break; } } } if (!flag && (((Object)val).name == null || ((Object)val).name.IndexOf("Untamo Motor ", StringComparison.OrdinalIgnoreCase) >= 0)) { try { Object.Destroy((Object)(object)val); } catch { } } } } } internal static class BoatRadarSkinRouting { private const byte MinimumSkinIndex = 14; private const byte MaximumSkinIndex = 63; internal const byte OriginalSkinIndex = byte.MaxValue; private static readonly Dictionary DesiredSkins = new Dictionary(); private static readonly Dictionary> OriginalMaterials = new Dictionary>(); private static float _nextRefresh; internal static byte NormalizeSkinIndex(byte skinIndex) { int result; switch (skinIndex) { case byte.MaxValue: return byte.MaxValue; case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: case 48: case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: case 58: case 59: case 60: case 61: case 62: case 63: result = skinIndex; break; default: result = 14; break; } return (byte)result; } internal static byte ParseSavedSkinIndex(string value) { byte result; return byte.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result) ? NormalizeSkinIndex(result) : byte.MaxValue; } internal static byte GetSkinIndex(Boat boat) { if ((Object)(object)boat == (Object)null) { return byte.MaxValue; } byte value; return DesiredSkins.TryGetValue(boat, out value) ? NormalizeSkinIndex(value) : byte.MaxValue; } internal static string GetSkinDisplayName(Boat boat) { byte skinIndex = GetSkinIndex(boat); return (skinIndex == byte.MaxValue) ? "Original" : ("Skin " + skinIndex.ToString(CultureInfo.InvariantCulture)); } internal static bool TryGetCycledSkin(Boat boat, int direction, out byte skinIndex) { skinIndex = GetSkinIndex(boat); if ((Object)(object)boat == (Object)null || direction == 0) { return false; } int num = ((skinIndex == byte.MaxValue) ? ((direction > 0) ? 14 : 63) : ((direction <= 0) ? ((skinIndex <= 14) ? 255 : (skinIndex - 1)) : ((skinIndex >= 63) ? 255 : (skinIndex + 1)))); skinIndex = (byte)num; return skinIndex != GetSkinIndex(boat); } internal static void EnsureDesiredSkin(Boat boat, byte skinIndex) { if (!((Object)(object)boat == (Object)null)) { skinIndex = NormalizeSkinIndex(skinIndex); DesiredSkins[boat] = skinIndex; if (!IsSkinActuallyApplied(boat, skinIndex)) { ApplySkin(boat, skinIndex); } } } internal static bool ApplySkin(Boat boat, byte skinIndex) { if ((Object)(object)boat == (Object)null) { return false; } skinIndex = NormalizeSkinIndex(skinIndex); DesiredSkins[boat] = skinIndex; RestoreOriginalMaterials(boat); if (skinIndex == byte.MaxValue) { return true; } List list = FindRadarRenderers(boat); if (list.Count == 0) { return false; } Dictionary dictionary = new Dictionary(); int num = 0; for (int i = 0; i < list.Count; i++) { Renderer val = list[i]; if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || val is ParticleSystemRenderer) { continue; } Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { continue; } if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } Material[] array = (Material[])(object)new Material[sharedMaterials.Length]; Array.Copy(sharedMaterials, array, sharedMaterials.Length); Material[] array2 = (Material[])(object)new Material[sharedMaterials.Length]; bool flag = false; for (int j = 0; j < sharedMaterials.Length; j++) { Material val2 = sharedMaterials[j]; if ((Object)(object)val2 == (Object)null) { array2[j] = null; continue; } if (IsRadarScreenMaterial(val2)) { array2[j] = val2; continue; } Material val3 = BoatSkinRouting.CreateSolidControlMaterial(val2, skinIndex, i, j); if ((Object)(object)val3 != (Object)null) { ((Object)val3).name = $"{((Object)val2).name} Untamo Radar {skinIndex}"; } array2[j] = (((Object)(object)val3 != (Object)null) ? val3 : val2); flag |= (Object)(object)val3 != (Object)null; } if (flag) { try { dictionary[val] = array; val.sharedMaterials = array2; num++; } catch { } } } if (num == 0) { return false; } OriginalMaterials[boat] = dictionary; return true; } internal static bool IsSkinActuallyApplied(Boat boat, byte skinIndex) { if ((Object)(object)boat == (Object)null || !((NetworkBehaviour)boat).IsSpawned) { return false; } skinIndex = NormalizeSkinIndex(skinIndex); if (skinIndex == byte.MaxValue) { return true; } string value = "Untamo Radar " + skinIndex.ToString(CultureInfo.InvariantCulture); List list = FindRadarRenderers(boat); if (list.Count == 0) { return false; } for (int i = 0; i < list.Count; i++) { Renderer val = list[i]; if ((Object)(object)val == (Object)null) { continue; } Material[] sharedMaterials; try { sharedMaterials = val.sharedMaterials; } catch { return false; } if (sharedMaterials == null) { continue; } foreach (Material val2 in sharedMaterials) { if (!((Object)(object)val2 == (Object)null) && !IsRadarScreenMaterial(val2) && !string.IsNullOrEmpty(((Object)val2).name) && ((Object)val2).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } } return false; } internal static void Update() { if (Time.unscaledTime < _nextRefresh) { return; } _nextRefresh = Time.unscaledTime + 0.5f; if (DesiredSkins.Count == 0) { return; } List list = new List(DesiredSkins.Keys); for (int i = 0; i < list.Count; i++) { Boat val = list[i]; if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned) { ClearForBoat(val); continue; } byte skinIndex = GetSkinIndex(val); if (!IsSkinActuallyApplied(val, skinIndex)) { ApplySkin(val, skinIndex); } } } internal static void ClearForBoat(Boat boat) { if (!((Object)(object)boat == (Object)null)) { RestoreOriginalMaterials(boat); DesiredSkins.Remove(boat); } } private static bool IsRadarScreenMaterial(Material material) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Invalid comparison between Unknown and I4 if ((Object)(object)material == (Object)null) { return false; } try { if (material.HasProperty("_MainTex")) { return true; } } catch { } Shader shader = material.shader; if ((Object)(object)shader == (Object)null) { return false; } int propertyCount; try { propertyCount = shader.GetPropertyCount(); } catch { return false; } for (int i = 0; i < propertyCount; i++) { try { if ((int)shader.GetPropertyType(i) == 4) { string propertyName = shader.GetPropertyName(i); Texture texture = material.GetTexture(propertyName); if (texture is RenderTexture) { return true; } } } catch { } } return false; } private static List FindRadarRenderers(Boat boat) { HashSet hashSet = new HashSet(); if ((Object)(object)boat == (Object)null) { return new List(); } GameObject radarHolderObjectForSkin = BoatGpsRouting.GetRadarHolderObjectForSkin(boat); if ((Object)(object)radarHolderObjectForSkin == (Object)null) { return new List(); } Renderer[] array; try { array = radarHolderObjectForSkin.GetComponentsInChildren(true); } catch { array = null; } if (array != null) { foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && !(val is ParticleSystemRenderer)) { hashSet.Add(val); } } } return new List(hashSet); } private static void RestoreOriginalMaterials(Boat boat) { if ((Object)(object)boat == (Object)null || !OriginalMaterials.TryGetValue(boat, out var value) || value == null) { return; } foreach (KeyValuePair item in value) { Renderer key = item.Key; if (!((Object)(object)key == (Object)null)) { Material[] candidates = null; try { candidates = key.sharedMaterials; key.sharedMaterials = item.Value; } catch { } DestroyRadarMaterials(candidates, item.Value); } } OriginalMaterials.Remove(boat); } private static void DestroyRadarMaterials(Material[] candidates, Material[] originals) { if (candidates == null) { return; } foreach (Material val in candidates) { if ((Object)(object)val == (Object)null) { continue; } bool flag = false; if (originals != null) { for (int j = 0; j < originals.Length; j++) { if ((Object)(object)val == (Object)(object)originals[j]) { flag = true; break; } } } if (!flag && (((Object)val).name == null || ((Object)val).name.IndexOf("Untamo Radar ", StringComparison.OrdinalIgnoreCase) >= 0)) { try { Object.Destroy((Object)(object)val); } catch { } } } } } internal static class BoatGpsRouting { private static readonly Dictionary RadarOwnership = new Dictionary(); private static readonly Dictionary RadarBaseLocalPosition = new Dictionary(); private static readonly Dictionary RadarOffsets = new Dictionary(); private static readonly Dictionary RadarHolderObjects = new Dictionary(); private static readonly FieldInfo RadarHolderField = AccessTools.Field(typeof(Boat), "_radarHolder"); internal static GameObject GetRadarHolderObjectForSkin(Boat boat) { return GetHolderObject(boat); } internal static void MoveRadar(Boat boat, Vector3 localDelta) { //IL_000a: 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_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) if (!((Object)(object)boat == (Object)null) && !(localDelta == Vector3.zero)) { SetRadarOffset(boat, GetRadarOffset(boat) + localDelta); } } internal static Vector3 GetRadarOffset(Boat boat) { //IL_000c: 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_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_002c: 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_0038: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null) { return Vector3.zero; } EnsureRadarBasePosition(boat); if (RadarOffsets.TryGetValue(boat, out var value)) { return value; } return Vector3.zero; } internal static bool IsRadarOffsetApplied(Boat boat, Vector3 offset) { //IL_0058: 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_0094: 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_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_00b7: 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_00c4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null) { return false; } GameObject holderObject = GetHolderObject(boat); if ((Object)(object)holderObject == (Object)null) { return false; } EnsureRadarBasePosition(boat); if (!RadarBaseLocalPosition.TryGetValue(boat, out var value)) { return false; } offset.x = Mathf.Round(offset.x * 10f) * 0.1f; offset.y = Mathf.Round(offset.y * 10f) * 0.1f; offset.z = Mathf.Round(offset.z * 10f) * 0.1f; Vector3 val = value + offset; return Vector3.SqrMagnitude(holderObject.transform.localPosition - val) <= 0.0001f; } internal static bool SetRadarOffset(Boat boat, Vector3 offset) { //IL_005b: 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_0097: 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_00c6: 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_00c8: 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) if ((Object)(object)boat == (Object)null) { return false; } GameObject holderObject = GetHolderObject(boat); if ((Object)(object)holderObject == (Object)null) { return false; } EnsureRadarBasePosition(boat); if (!RadarBaseLocalPosition.TryGetValue(boat, out var value)) { value = holderObject.transform.localPosition; } offset.x = Mathf.Round(offset.x * 10f) * 0.1f; offset.y = Mathf.Round(offset.y * 10f) * 0.1f; offset.z = Mathf.Round(offset.z * 10f) * 0.1f; RadarOffsets[boat] = offset; holderObject.transform.localPosition = value + offset; return true; } private static void EnsureRadarBasePosition(Boat boat) { //IL_0074: 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) if ((Object)(object)boat == (Object)null) { return; } GameObject holderObject = GetHolderObject(boat); if (!((Object)(object)holderObject == (Object)null) && (!RadarHolderObjects.TryGetValue(boat, out var value) || !((Object)(object)value == (Object)(object)holderObject) || !RadarBaseLocalPosition.ContainsKey(boat))) { RadarHolderObjects[boat] = holderObject; RadarBaseLocalPosition[boat] = holderObject.transform.localPosition; if (!RadarOffsets.ContainsKey(boat)) { RadarOffsets[boat] = Vector3.zero; } } } internal static void Toggle(Boat boat, ManualLogSource logger) { if ((Object)(object)boat == (Object)null) { return; } if (!HasRadar(boat)) { if (logger != null) { logger.LogWarning((object)"This boat's GPS/radar has not been purchased."); } return; } GameObject holderObject = GetHolderObject(boat); if ((Object)(object)holderObject == (Object)null) { if (logger != null) { logger.LogWarning((object)"The boat GPS/radar display could not be found."); } } else { SetVisible(boat, !holderObject.activeSelf); } } internal static bool SetRadarUnlocked(Boat boat, bool unlocked) { if ((Object)(object)boat == (Object)null) { return false; } RadarOwnership[boat] = unlocked; GameObject holderObject = GetHolderObject(boat); if (!unlocked && (Object)(object)holderObject != (Object)null) { holderObject.SetActive(false); } return true; } internal static void ClearExplicitRadarOwnership(Boat boat) { if ((Object)(object)boat != (Object)null) { RadarOwnership.Remove(boat); } } internal static void ClearAllExplicitRadarOwnership() { RadarOwnership.Clear(); RadarBaseLocalPosition.Clear(); RadarOffsets.Clear(); RadarHolderObjects.Clear(); } internal static void ClearRadarPositionRuntimeCache() { RadarBaseLocalPosition.Clear(); RadarOffsets.Clear(); } internal static bool HasRadar(Boat boat) { if ((Object)(object)boat == (Object)null) { return false; } if (RadarOwnership.TryGetValue(boat, out var value)) { return value; } return boat.BoatRadarUnlocked; } internal static bool IsVisible(Boat boat) { if ((Object)(object)boat == (Object)null || !HasRadar(boat)) { return false; } GameObject holderObject = GetHolderObject(boat); return (Object)(object)holderObject != (Object)null && holderObject.activeSelf; } internal static void SetVisible(Boat boat, bool visible) { if (!((Object)(object)boat == (Object)null) && HasRadar(boat)) { GameObject holderObject = GetHolderObject(boat); if ((Object)(object)holderObject != (Object)null && holderObject.activeSelf != visible) { holderObject.SetActive(visible); } } } internal static string GetVisibilityText(Boat boat) { return IsVisible(boat) ? "Visible" : "Hidden"; } private static GameObject GetHolderObject(Boat boat) { if ((Object)(object)boat == (Object)null) { return null; } object obj = RadarHolderField?.GetValue(boat); GameObject val = (GameObject)((obj is GameObject) ? obj : null); Component val2 = (Component)((obj is Component) ? obj : null); if ((Object)(object)val == (Object)null && (Object)(object)val2 != (Object)null) { val = val2.gameObject; } return val; } } [HarmonyPatch(typeof(Boat), "OnMotorChange")] internal static class BoatNoMotorVisualPatch { private static readonly FieldInfo CurrentMotorField = AccessTools.Field(typeof(Boat), "_curMotor"); private static readonly FieldInfo MotorsField = AccessTools.Field(typeof(Boat), "_motors"); private static readonly FieldInfo MotorRotationTargetsField = AccessTools.Field(typeof(BoatMotor), "_toRotate"); private static bool Prefix(Boat __instance, byte __1) { if ((Object)(object)__instance == (Object)null) { return true; } object obj = CurrentMotorField?.GetValue(__instance); GameObject val = (GameObject)((obj is GameObject) ? obj : null); Component val2 = (Component)((obj is Component) ? obj : null); if ((Object)(object)val == (Object)null && (Object)(object)val2 != (Object)null) { val = val2.gameObject; } Transform val3 = (((Object)(object)val == (Object)null) ? null : val.transform.parent); Transform val4 = ((val3 != null) ? val3.Find("Untamo Super Big Motor") : null); if ((Object)(object)val4 != (Object)null) { Object.Destroy((Object)(object)((Component)val4).gameObject); } Transform val5 = ((val3 != null) ? val3.Find("Untamo Dual Super Big Motor Left") : null); if ((Object)(object)val5 != (Object)null) { Object.Destroy((Object)(object)((Component)val5).gameObject); } Transform val6 = ((val3 != null) ? val3.Find("Untamo Dual Super Big Motor Right") : null); if ((Object)(object)val6 != (Object)null) { Object.Destroy((Object)(object)((Component)val6).gameObject); } if (__1 != 254 && __1 != 253 && (Object)(object)val != (Object)null) { Renderer[] componentsInChildren = val.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = true; } val.SetActive(true); } if (__1 != byte.MaxValue) { return true; } if ((Object)(object)val != (Object)null) { val.SetActive(false); } Plugin.StopBoatInputAndMotion(__instance, stopMotion: false); return false; } private static void Postfix(Boat __instance, byte __1) { //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: 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_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0254: 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_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (__1 != 254 && __1 != 253)) { return; } object obj = CurrentMotorField?.GetValue(__instance); GameObject val = (GameObject)((obj is GameObject) ? obj : null); Component val2 = (Component)((obj is Component) ? obj : null); if ((Object)(object)val == (Object)null && (Object)(object)val2 != (Object)null) { val = val2.gameObject; } GameObject motorPrefab = GetMotorPrefab(__instance, 1); if ((Object)(object)val == (Object)null || (Object)(object)motorPrefab == (Object)null || (Object)(object)val.transform.parent == (Object)null) { return; } Renderer[] componentsInChildren = val.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } val.SetActive(true); AudioSource[] componentsInChildren2 = val.GetComponentsInChildren(true); for (int j = 0; j < componentsInChildren2.Length; j++) { ((Behaviour)componentsInChildren2[j]).enabled = true; } int num = ((__1 != 253) ? 1 : 2); BoatMotor val3 = (BoatMotor)(((object)((val2 is BoatMotor) ? val2 : null)) ?? ((object)val.GetComponent())); Transform[] array = (((Object)(object)val3 == (Object)null) ? null : (MotorRotationTargetsField?.GetValue(val3) as Transform[])); for (int k = 0; k < num; k++) { GameObject val4 = Object.Instantiate(motorPrefab, val.transform.parent); ((Object)val4).name = ((num == 1) ? "Untamo Super Big Motor" : ((k == 0) ? "Untamo Dual Super Big Motor Left" : "Untamo Dual Super Big Motor Right")); Transform transform = val4.transform; Vector3 val5 = ((num == 2) ? val.transform.parent.InverseTransformVector(((Component)__instance).transform.forward * 0.11f) : Vector3.zero); if (num == 2 && array != null && k < array.Length && (Object)(object)array[k] != (Object)null) { transform.localPosition = val.transform.parent.InverseTransformPoint(array[k].position) + val5; } else { float num2 = ((num == 1) ? 0f : ((k == 0) ? (-1.25f) : 1.25f)); transform.localPosition = val.transform.localPosition + Vector3.right * num2 + val5; } transform.localRotation = val.transform.localRotation; transform.localScale = motorPrefab.transform.localScale * 1.6f; Collider[] componentsInChildren3 = val4.GetComponentsInChildren(true); for (int l = 0; l < componentsInChildren3.Length; l++) { Object.Destroy((Object)(object)componentsInChildren3[l]); } Rigidbody[] componentsInChildren4 = val4.GetComponentsInChildren(true); for (int m = 0; m < componentsInChildren4.Length; m++) { Object.Destroy((Object)(object)componentsInChildren4[m]); } AudioSource[] componentsInChildren5 = val4.GetComponentsInChildren(true); for (int n = 0; n < componentsInChildren5.Length; n++) { ((Behaviour)componentsInChildren5[n]).enabled = false; } val4.SetActive(true); SuperBigMotorSteeringFollower superBigMotorSteeringFollower = val4.AddComponent(); superBigMotorSteeringFollower.Initialize(__instance, val4.GetComponent()); } } private static GameObject GetMotorPrefab(Boat boat, int motorIndex) { object obj = MotorsField?.GetValue(boat); object obj2 = (obj?.GetType().GetProperty("Item"))?.GetValue(obj, new object[1] { motorIndex }); GameObject val = (GameObject)((obj2 is GameObject) ? obj2 : null); Component val2 = (Component)((obj2 is Component) ? obj2 : null); return ((Object)(object)val != (Object)null) ? val : ((val2 != null) ? val2.gameObject : null); } } public sealed class SuperBigMotorSteeringFollower : MonoBehaviour { private static readonly FieldInfo SmoothedInputField = AccessTools.Field(typeof(Boat), "_curSmoothedInput"); private Boat _boat; private BoatMotor _motor; internal void Initialize(Boat boat, BoatMotor motor) { _boat = boat; _motor = motor; } private void LateUpdate() { //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_005f: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_boat == (Object)null) && !((Object)(object)_motor == (Object)null) && !(SmoothedInputField == null) && SmoothedInputField.GetValue(_boat) is Vector2 val) { _motor.SetRotation(val.x); } } } internal static class BoatHornRouting { private static AudioClip _dynamiteClip; private static bool _searched; internal static void Play(Boat boat, ManualLogSource logger) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_00a3: 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) if ((Object)(object)boat == (Object)null) { return; } AudioClip val = FindDynamiteClip(); if ((Object)(object)val == (Object)null) { if (logger != null) { logger.LogWarning((object)"Could not find a loaded dynamite/explosion AudioClip."); } return; } Transform val2 = (((Object)(object)boat.HiddenPhysicsRig != (Object)null) ? ((Component)boat.HiddenPhysicsRig).transform : ((Component)boat).transform); Transform val3 = val2.Find("Untamo Boat Horn Audio"); GameObject val4; if ((Object)(object)val3 != (Object)null) { val4 = ((Component)val3).gameObject; } else { val4 = new GameObject("Untamo Boat Horn Audio"); val4.transform.SetParent(val2, false); val4.transform.localPosition = Vector3.zero; val4.transform.localRotation = Quaternion.identity; } AudioSource val5 = val4.GetComponent(); if ((Object)(object)val5 == (Object)null) { val5 = val4.AddComponent(); } val5.spatialBlend = 1f; val5.playOnAwake = false; val5.loop = false; val5.volume = 0.5f; val5.minDistance = 2f; val5.maxDistance = 45f; val5.rolloffMode = (AudioRolloffMode)1; val5.dopplerLevel = 0f; val5.PlayOneShot(val, 1f); } private static AudioClip FindDynamiteClip() { if ((Object)(object)_dynamiteClip != (Object)null) { return _dynamiteClip; } if (_searched) { return null; } _searched = true; AudioClip[] array = Resources.FindObjectsOfTypeAll(); foreach (AudioClip val in array) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((Object)val).name)) { string text = ((Object)val).name.ToLowerInvariant(); if (text.Contains("dynamite")) { _dynamiteClip = val; return val; } } } foreach (AudioClip val2 in array) { if (!((Object)(object)val2 == (Object)null) && !string.IsNullOrEmpty(((Object)val2).name)) { string text2 = ((Object)val2).name.ToLowerInvariant(); if (text2.Contains("explosion") || text2.Contains("explode") || text2.Contains("blast")) { _dynamiteClip = val2; return val2; } } } return null; } } internal static class BoatSpeedRouting { internal static float GetSpeedKmh(Boat boat) { //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) if ((Object)(object)boat == (Object)null) { return 0f; } Rigidbody val = boat.HiddenPhysicsRig; if ((Object)(object)val == (Object)null) { val = ((Component)boat).GetComponentInChildren(); } if ((Object)(object)val == (Object)null) { return 0f; } Vector3 linearVelocity = val.linearVelocity; return ((Vector3)(ref linearVelocity)).magnitude * 3.6f; } internal static string GetSpeedText(Boat boat) { return $"{GetSpeedKmh(boat):0.0} km/h"; } } internal static class BoatClosestPhysicsRouting { private const float MaximumContextDistance = 5f; private static float _nextRefresh; private static readonly Dictionary _contextByPlayer = new Dictionary(); internal static void Update() { //IL_010e: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime < _nextRefresh) { return; } _nextRefresh = Time.unscaledTime + 0.1f; Boat[] boats = Object.FindObjectsByType((FindObjectsSortMode)0); Player[] array = Object.FindObjectsByType((FindObjectsSortMode)0); HashSet hashSet = new HashSet(); foreach (Player val in array) { if ((Object)(object)val == (Object)null || (Object)(object)val.Transform == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null || !((Component)val).gameObject.activeInHierarchy) { continue; } hashSet.Add(val); Boat val2 = FindDrivenBoat(val, boats); if ((Object)(object)val2 != (Object)null) { _contextByPlayer[val] = val2; if ((Object)(object)val == (Object)(object)Player.LocalPlayer && (Object)(object)BoatManager.Instance != (Object)null && (Object)(object)BoatManager.Boat != (Object)(object)val2) { BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(val2), val2); } continue; } float closestDistance; Boat val3 = FindClosestBoat(val.Transform.position, boats, out closestDistance); if ((Object)(object)val3 != (Object)null && closestDistance <= 5f) { _contextByPlayer[val] = val3; if ((Object)(object)val == (Object)(object)Player.LocalPlayer && (Object)(object)BoatManager.Instance != (Object)null && (Object)(object)BoatManager.Boat != (Object)(object)val3) { BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(val3), val3); } } else { _contextByPlayer.Remove(val); } } Player[] array2 = (Player[])(object)new Player[_contextByPlayer.Count]; _contextByPlayer.Keys.CopyTo(array2, 0); foreach (Player val4 in array2) { if ((Object)(object)val4 == (Object)null || !hashSet.Contains(val4)) { _contextByPlayer.Remove(val4); } } } internal static void ClearContext(Player player) { if ((Object)(object)player != (Object)null) { _contextByPlayer.Remove(player); } _nextRefresh = 0f; } internal static void ForceRefresh() { _nextRefresh = 0f; Update(); } internal static Boat FindNearestPhysicalBoat(Player player, float maximumDistance) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)player.Transform == (Object)null) { return null; } Boat[] boats = Object.FindObjectsByType((FindObjectsSortMode)0); float closestDistance; Boat val = FindClosestBoat(player.Transform.position, boats, out closestDistance); if ((Object)(object)val == (Object)null || closestDistance > maximumDistance) { return null; } return val; } internal static Boat GetContextBoat(Player player) { if ((Object)(object)player == (Object)null) { return null; } if (_contextByPlayer.TryGetValue(player, out var value) && (Object)(object)value != (Object)null && ((NetworkBehaviour)value).IsSpawned) { return value; } return null; } internal static Boat GetContextBoatNearPlayer(Player player, float maximumDistance) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)player.Transform == (Object)null) { return null; } Boat contextBoat = GetContextBoat(player); if ((Object)(object)contextBoat == (Object)null) { return null; } float distanceToNativeBoat = GetDistanceToNativeBoat(contextBoat, player.Transform.position); return (distanceToNativeBoat <= maximumDistance) ? contextBoat : null; } internal static bool IsClosestInteractBoat(Player player, Boat boat, float maximumDistance) { if ((Object)(object)player == (Object)null || (Object)(object)boat == (Object)null || (Object)(object)player.Transform == (Object)null) { return false; } Boat val = FindDrivenBoat(player, Object.FindObjectsByType((FindObjectsSortMode)0)); if ((Object)(object)val != (Object)null) { return (Object)(object)val == (Object)(object)boat; } Boat contextBoatNearPlayer = GetContextBoatNearPlayer(player, maximumDistance); return (Object)(object)contextBoatNearPlayer == (Object)(object)boat; } private static Boat FindDrivenBoat(Player player, Boat[] boats) { if ((Object)(object)player == (Object)null || boats == null) { return null; } foreach (Boat val in boats) { if ((Object)(object)val != (Object)null && ((NetworkBehaviour)val).IsSpawned && (Object)(object)val.Driver == (Object)(object)player) { return val; } } return null; } private static Boat FindClosestBoat(Vector3 playerPosition, Boat[] boats, out float closestDistance) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) closestDistance = float.MaxValue; Boat result = null; if (boats == null) { return null; } foreach (Boat val in boats) { if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).IsSpawned && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { float distanceToNativeBoat = GetDistanceToNativeBoat(val, playerPosition); if (distanceToNativeBoat < closestDistance) { closestDistance = distanceToNativeBoat; result = val; } } } return result; } private static float GetDistanceToNativeBoat(Boat boat, Vector3 playerPosition) { //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_0057: 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_005b: 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_00c5: 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) Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(boat); float num = float.MaxValue; bool flag = false; foreach (Collider val in managerColliders) { if (!((Object)(object)val == (Object)null) && val.enabled && !val.isTrigger && !BoatHitboxRouting.IsCollisionProxy(((Component)val).transform)) { Vector3 val2 = val.ClosestPoint(playerPosition); Vector3 val3 = val2 - playerPosition; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; flag = true; } } } if (flag) { return Mathf.Sqrt(num); } Transform val4 = (((Object)(object)boat.HiddenPhysicsRig != (Object)null) ? ((Component)boat.HiddenPhysicsRig).transform : ((Component)boat).transform); return Vector3.Distance(playerPosition, val4.position); } } internal static class BoatInteractionRouting { private const float ClosestInteractDistance = 2.5f; private static float _nextRefresh; internal static Collider[] GetManagerColliders(Boat boat) { if ((Object)(object)boat == (Object)null) { return Array.Empty(); } Collider[] componentsInChildren = ((Component)boat).GetComponentsInChildren(true); List list = new List(); foreach (Collider val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !BoatHitboxRouting.IsCollisionProxy(((Component)val).transform)) { list.Add(val); } } return list.ToArray(); } internal static void Update() { if (Time.unscaledTime < _nextRefresh) { return; } _nextRefresh = Time.unscaledTime + 0.1f; Player localPlayer = Player.LocalPlayer; Boat val = (((Object)(object)localPlayer == (Object)null) ? null : BoatClosestPhysicsRouting.GetContextBoatNearPlayer(localPlayer, 2.5f)); Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Boat val2 in array) { if (!((Object)(object)val2 == (Object)null) && ((NetworkBehaviour)val2).IsSpawned && !((Object)(object)((Component)val2).gameObject == (Object)null) && ((Component)val2).gameObject.activeInHierarchy && (!((Object)(object)val2.Driver != (Object)null) || !((Object)(object)val2.Driver != (Object)(object)localPlayer)) && ((Object)(object)val2.Driver == (Object)null || (Object)(object)val2 == (Object)(object)val || (Object)(object)val2.Driver == (Object)(object)localPlayer)) { EnableBoatInteractables(val2); } } } internal static void ForceRefresh() { _nextRefresh = 0f; Update(); } internal static bool IsLocalClosestInteractBoat(Boat boat) { Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)boat == (Object)null) { return false; } return BoatClosestPhysicsRouting.IsClosestInteractBoat(localPlayer, boat, 2.5f); } private static void EnableBoatInteractables(Boat boat) { BoatInteractable[] componentsInChildren = ((Component)boat).GetComponentsInChildren(true); foreach (BoatInteractable val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } GameObject gameObject = ((Component)val).gameObject; if (!gameObject.activeSelf) { gameObject.SetActive(true); } Behaviour val2 = (Behaviour)(object)val; if ((Object)(object)val2 != (Object)null && !val2.enabled) { val2.enabled = true; } Collider[] componentsInChildren2 = gameObject.GetComponentsInChildren(true); foreach (Collider val3 in componentsInChildren2) { if ((Object)(object)val3 != (Object)null && !BoatHitboxRouting.IsCollisionProxy(((Component)val3).transform)) { val3.enabled = true; } } } } } internal static class BoatAnchorRouting { private sealed class AnchorState { internal Vector3 Center; internal Vector3 Forward; internal Vector3 Right; } private const float HorizontalHalfExtent = 5f; private static readonly Dictionary Anchors = new Dictionary(); internal static void Toggle(Boat boat, ManualLogSource logger) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: 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_0136: 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_013d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null || !((NetworkBehaviour)boat).IsSpawned) { return; } if (Anchors.ContainsKey(boat)) { Anchors.Remove(boat); if (logger != null) { logger.LogInfo((object)"Boat anchor raised."); } return; } if (!InstanceFinder.IsServerStarted) { if (logger != null) { logger.LogWarning((object)"Boat anchor can only be changed on the host/server."); } return; } Rigidbody val = ResolveBody(boat); if ((Object)(object)val == (Object)null) { if (logger != null) { logger.LogWarning((object)"Boat anchor could not find the boat physics body."); } return; } Vector3 val2 = val.rotation * Vector3.forward; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f) { val2 = Vector3.forward; } else { ((Vector3)(ref val2)).Normalize(); } Vector3 right = Vector3.Cross(Vector3.up, val2); if (((Vector3)(ref right)).sqrMagnitude < 0.0001f) { right = Vector3.right; } else { ((Vector3)(ref right)).Normalize(); } Anchors[boat] = new AnchorState { Center = val.position, Forward = val2, Right = right }; val.WakeUp(); if (logger != null) { logger.LogInfo((object)"Boat anchor dropped. Drift area: 10 m x 10 m (5 m each direction)."); } } internal static bool IsAnchored(Boat boat) { return (Object)(object)boat != (Object)null && Anchors.ContainsKey(boat); } internal static string GetStateText(Boat boat) { return IsAnchored(boat) ? "Dropped" : "Raised"; } internal static void FixedUpdate() { //IL_00de: 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_00e5: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0111: 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_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0184: 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_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: 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_01ba: 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_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0250: 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_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) if (!InstanceFinder.IsServerStarted || Anchors.Count == 0) { return; } List list = null; Vector3 val4 = default(Vector3); foreach (KeyValuePair anchor in Anchors) { Boat key = anchor.Key; AnchorState value = anchor.Value; if ((Object)(object)key == (Object)null || value == null || !((NetworkBehaviour)key).IsSpawned || (Object)(object)((Component)key).gameObject == (Object)null || !((Component)key).gameObject.activeInHierarchy || BoatDamageRouting.IsSinking(key)) { if (list == null) { list = new List(); } list.Add(key); continue; } Rigidbody val = ResolveBody(key); if ((Object)(object)val == (Object)null || val.isKinematic) { continue; } Vector3 position = val.position; Vector3 val2 = position - value.Center; val2.y = 0f; float num = Vector3.Dot(val2, value.Forward); float num2 = Vector3.Dot(val2, value.Right); float num3 = Mathf.Clamp(num, -5f, 5f); float num4 = Mathf.Clamp(num2, -5f, 5f); bool flag = !Mathf.Approximately(num3, num); bool flag2 = !Mathf.Approximately(num4, num2); if (flag || flag2) { Vector3 val3 = value.Center + value.Forward * num3 + value.Right * num4; val.position = new Vector3(val3.x, position.y, val3.z); Vector3 linearVelocity = val.linearVelocity; ((Vector3)(ref val4))..ctor(linearVelocity.x, 0f, linearVelocity.z); float num5 = Vector3.Dot(val4, value.Forward); float num6 = Vector3.Dot(val4, value.Right); if ((num > 5f && num5 > 0f) || (num < -5f && num5 < 0f)) { val4 -= value.Forward * num5; } if ((num2 > 5f && num6 > 0f) || (num2 < -5f && num6 < 0f)) { val4 -= value.Right * num6; } linearVelocity.x = val4.x; linearVelocity.z = val4.z; val.linearVelocity = linearVelocity; val.WakeUp(); } } if (list != null) { for (int i = 0; i < list.Count; i++) { Anchors.Remove(list[i]); } } } private static Rigidbody ResolveBody(Boat boat) { if ((Object)(object)boat == (Object)null) { return null; } Rigidbody hiddenPhysicsRig = boat.HiddenPhysicsRig; if ((Object)(object)hiddenPhysicsRig != (Object)null) { return hiddenPhysicsRig; } try { return ((Component)boat).GetComponentInChildren(); } catch { return null; } } } internal static class BoatPhysicsKeepAlive { private static float _nextRefresh; internal static void Update() { if (!InstanceFinder.IsServerStarted || Time.unscaledTime < _nextRefresh) { return; } _nextRefresh = Time.unscaledTime + 0.5f; Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Boat val in array) { if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).IsSpawned && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { Rigidbody hiddenPhysicsRig = val.HiddenPhysicsRig; if (!((Object)(object)hiddenPhysicsRig == (Object)null) && !hiddenPhysicsRig.isKinematic) { hiddenPhysicsRig.sleepThreshold = 0f; hiddenPhysicsRig.detectCollisions = true; hiddenPhysicsRig.WakeUp(); } } } } } internal static class BoatNativeAttackBridge { private static readonly HashSet PatchedMethods = new HashSet(); private static ManualLogSource _logger; private static MethodInfo _nativeDamageTextMethod; private static object _nativeDamageTextInstance; private static bool _nativePopupSearched; private static float _lastAttackTime; private static object _lastAttackSource; internal static void Install(Harmony harmony, ManualLogSource logger) { //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown if (harmony == null) { return; } _logger = logger; MethodInfo methodInfo = AccessTools.Method(typeof(BoatNativeAttackBridge), "ExactNativeAttackPostfix", (Type[])null, (Type[])null); if (methodInfo == null) { return; } HashSet hashSet = new HashSet(StringComparer.Ordinal) { "FireBullet" }; Assembly assembly = typeof(Creature).Assembly; Type[] array; try { array = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types; } catch { array = null; } int num = 0; if (array != null) { foreach (Type type in array) { if (type == null) { continue; } MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } if (methods == null) { continue; } foreach (MethodInfo methodInfo2 in methods) { if (methodInfo2 == null || methodInfo2.IsAbstract || methodInfo2.IsGenericMethodDefinition || !hashSet.Contains(methodInfo2.Name) || PatchedMethods.Contains(methodInfo2)) { continue; } try { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); PatchedMethods.Add(methodInfo2); num++; if (logger != null) { logger.LogInfo((object)("Boat damage hooked native attack: " + type.Name + "." + methodInfo2.Name)); } } catch { } } } } FindNativeDamagePopupFast(); if (logger != null) { logger.LogInfo((object)$"Boat damage exact native bridge hooked {num} attack method(s)."); } } private static void ExactNativeAttackPostfix(object __instance, object[] __args, MethodBase __originalMethod) { if (!(__originalMethod == null)) { string text = __originalMethod.Name ?? string.Empty; bool meleeLike = text.IndexOf("Punch", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Fist", StringComparison.OrdinalIgnoreCase) >= 0; BoatDamageRouting.HandleExactNativeAttack(__instance, __args, __originalMethod, meleeLike); } } private static int InstallCreatureDamagePathHooks(Harmony harmony) { //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Expected O, but got Unknown if (harmony == null) { return 0; } MethodInfo methodInfo = AccessTools.Method(typeof(BoatNativeAttackBridge), "CreatureDamagePathPostfix", (Type[])null, (Type[])null); if (methodInfo == null) { return 0; } MethodInfo[] methods; try { methods = typeof(Creature).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { return 0; } HashSet hashSet = new HashSet(); foreach (MethodInfo methodInfo2 in methods) { if (methodInfo2 != null && methodInfo2.Name == "LocalHit") { hashSet.Add(methodInfo2); } } if (hashSet.Count == 0) { return 0; } Assembly assembly = typeof(Creature).Assembly; MethodBase[] patchableGameMethods = GetPatchableGameMethods(assembly); if (patchableGameMethods == null || patchableGameMethods.Length == 0) { return 0; } HashSet hashSet2 = new HashSet(); for (int j = 0; j < 4; j++) { if (hashSet.Count <= 0) { break; } HashSet hashSet3 = new HashSet(); foreach (MethodBase methodBase in patchableGameMethods) { if (!(methodBase == null) && !hashSet2.Contains(methodBase) && !hashSet.Contains(methodBase) && MethodCallsAny(methodBase, hashSet)) { hashSet2.Add(methodBase); hashSet3.Add(methodBase); } } hashSet = hashSet3; } int num = 0; foreach (MethodBase item in hashSet2) { if (!(item == null) && !PatchedMethods.Contains(item)) { try { harmony.Patch(item, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); PatchedMethods.Add(item); num++; } catch { } } } return num; } private static MethodBase[] GetPatchableGameMethods(Assembly assembly) { if (assembly == null) { return Array.Empty(); } Type[] types; try { types = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { types = ex.Types; } catch { return Array.Empty(); } if (types == null) { return Array.Empty(); } List list = new List(); foreach (Type type in types) { if (type == null) { continue; } MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } if (methods == null) { continue; } foreach (MethodInfo methodInfo in methods) { if (!(methodInfo == null) && !methodInfo.IsAbstract && !methodInfo.IsGenericMethodDefinition && methodInfo.GetMethodBody() != null) { list.Add(methodInfo); } } } return list.ToArray(); } private static bool MethodCallsAny(MethodBase method, HashSet targets) { if (method == null || targets == null || targets.Count == 0) { return false; } MethodBody methodBody; try { methodBody = method.GetMethodBody(); } catch { return false; } if (methodBody == null) { return false; } byte[] iLAsByteArray; try { iLAsByteArray = methodBody.GetILAsByteArray(); } catch { return false; } if (iLAsByteArray == null || iLAsByteArray.Length < 5) { return false; } Module module = method.Module; for (int i = 0; i <= iLAsByteArray.Length - 5; i++) { byte b = iLAsByteArray[i]; if (b != 40 && b != 111 && b != 115) { continue; } int metadataToken = iLAsByteArray[i + 1] | (iLAsByteArray[i + 2] << 8) | (iLAsByteArray[i + 3] << 16) | (iLAsByteArray[i + 4] << 24); MethodBase methodBase; try { methodBase = module.ResolveMethod(metadataToken); } catch { continue; } if (methodBase == null) { continue; } foreach (MethodBase target in targets) { if (!(target == null)) { if (methodBase == target) { return true; } if (methodBase.MetadataToken == target.MetadataToken && methodBase.Module == target.Module) { return true; } } } } return false; } private static void CreatureDamagePathPostfix(object __instance, object[] __args, MethodBase __originalMethod) { BoatDamageRouting.HandleCreatureDamagePathAttack(__instance, __args, __originalMethod); } private static void NativeAttackPostfix(object __instance, MethodBase __originalMethod) { if (!(__originalMethod == null) && (_lastAttackSource != __instance || !(Time.unscaledTime - _lastAttackTime < 0.025f))) { _lastAttackSource = __instance; _lastAttackTime = Time.unscaledTime; bool meleeLike = LooksLikeMelee(__originalMethod.DeclaringType, __originalMethod.Name); BoatDamageRouting.HandleNativeAttack(__instance, meleeLike); } } private static bool LooksLikeAttackType(Type type) { if (type == null || type.IsAbstract || type.IsGenericTypeDefinition) { return false; } if (!typeof(MonoBehaviour).IsAssignableFrom(type)) { return false; } string text = type.Name.ToLowerInvariant(); return text.Contains("gun") || text.Contains("weapon") || text.Contains("firearm") || text.Contains("rifle") || text.Contains("pistol") || text.Contains("shotgun") || text.Contains("revolver") || text.Contains("bow") || text.Contains("crossbow") || text.Contains("harpoon") || text.Contains("melee") || text.Contains("fist") || text.Contains("punch") || text.Contains("hands"); } private static bool LooksLikeAttackMethod(MethodInfo method) { if (method == null || method.IsAbstract || method.IsGenericMethodDefinition || method.IsSpecialName) { return false; } if (method.ReturnType == typeof(IEnumerator)) { return false; } string text = method.Name.ToLowerInvariant(); if (text.Contains("can") || text.Contains("get") || text.Contains("set") || text.Contains("update") || text.Contains("reload") || text.Contains("equip") || text.Contains("unequip") || text.Contains("animation")) { return false; } int result; switch (text) { default: if (!text.Contains("shoot") && !text.Contains("fire") && !text.Contains("primaryattack") && !text.Contains("primaryuse") && !text.Contains("doattack")) { result = (text.Contains("performattack") ? 1 : 0); break; } goto case "shoot"; case "shoot": case "fire": case "attack": case "punch": case "hit": case "use": result = 1; break; } return (byte)result != 0; } private static bool LooksLikeMelee(Type type, string methodName) { string text = ((type == null) ? string.Empty : type.Name.ToLowerInvariant()); string text2 = (string.IsNullOrEmpty(methodName) ? string.Empty : methodName.ToLowerInvariant()); return text.Contains("melee") || text.Contains("fist") || text.Contains("punch") || text.Contains("hands") || text2.Contains("punch") || text2.Contains("melee"); } internal static bool TryShowNativeDamageText(Vector3 worldPosition, float damage) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return TryShowNativeDamageText(worldPosition, damage, lethalHit: false); } internal static bool TryShowNativeDamageText(Vector3 worldPosition, float damage, bool lethalHit) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) if (!_nativePopupSearched) { FindNativeDamagePopupFast(); } if (_nativeDamageTextMethod == null) { return false; } try { ParameterInfo[] parameters = _nativeDamageTextMethod.GetParameters(); object[] array = new object[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { Type parameterType = parameters[i].ParameterType; if (parameterType == typeof(Vector3)) { array[i] = worldPosition; } else if (parameterType == typeof(float)) { array[i] = damage; } else if (parameterType == typeof(double)) { array[i] = (double)damage; } else if (parameterType == typeof(int)) { array[i] = Mathf.RoundToInt(damage); } else if (parameterType == typeof(string)) { array[i] = Mathf.RoundToInt(damage).ToString(CultureInfo.InvariantCulture); } else if (parameterType == typeof(Color)) { array[i] = (object)new Color(1f, 0.25f, 0.15f, 1f); } else if (parameterType == typeof(bool)) { string text = parameters[i].Name ?? string.Empty; string text2 = text.ToLowerInvariant(); if (text2.Contains("kill") || text2.Contains("dead") || text2.Contains("death") || text2.Contains("lethal") || text2.Contains("overkill")) { array[i] = lethalHit; continue; } int num = 0; for (int j = 0; j < parameters.Length; j++) { if (parameters[j].ParameterType == typeof(bool)) { num++; } } array[i] = num == 1 && lethalHit; } else if (parameters[i].HasDefaultValue) { array[i] = parameters[i].DefaultValue; } else if (parameterType.IsValueType) { array[i] = Activator.CreateInstance(parameterType); } else { array[i] = null; } } _nativeDamageTextMethod.Invoke(_nativeDamageTextMethod.IsStatic ? null : _nativeDamageTextInstance, array); return true; } catch { _nativeDamageTextMethod = null; _nativeDamageTextInstance = null; return false; } } private static void FindNativeDamagePopupFast() { if (_nativePopupSearched) { return; } _nativePopupSearched = true; Assembly assembly = typeof(Creature).Assembly; Type[] array; try { array = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types; } catch { array = null; } if (array == null) { return; } foreach (Type type in array) { if (type == null) { continue; } MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } if (methods == null) { continue; } foreach (MethodInfo methodInfo in methods) { if (methodInfo == null || methodInfo.Name != "AddDamageNumber" || methodInfo.IsGenericMethodDefinition) { continue; } object obj3 = null; if (!methodInfo.IsStatic) { obj3 = FindRuntimeInstance(type); if (obj3 == null) { continue; } } _nativeDamageTextMethod = methodInfo; _nativeDamageTextInstance = obj3; ManualLogSource logger = _logger; if (logger != null) { logger.LogInfo((object)("Using native damage text: " + type.Name + "." + methodInfo.Name)); } return; } } } private static void FindNativeDamagePopup() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); int num = 0; foreach (Assembly assembly in assemblies) { if (assembly == null || assembly == typeof(Plugin).Assembly) { continue; } Type[] types; try { types = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { types = ex.Types; } catch { continue; } if (types == null) { continue; } foreach (Type type in types) { if (type == null) { continue; } MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } foreach (MethodInfo methodInfo in methods) { int num2 = ScoreDamagePopupMethod(type, methodInfo); if (num2 <= num) { continue; } object obj3 = null; if (!methodInfo.IsStatic) { obj3 = FindRuntimeInstance(type); if (obj3 == null) { continue; } } num = num2; _nativeDamageTextMethod = methodInfo; _nativeDamageTextInstance = obj3; } } } if (_nativeDamageTextMethod != null) { ManualLogSource logger = _logger; if (logger != null) { logger.LogInfo((object)("Using native damage text: " + _nativeDamageTextMethod.DeclaringType?.Name + "." + _nativeDamageTextMethod.Name)); } } } private static int ScoreDamagePopupMethod(Type type, MethodInfo method) { if (type == null || method == null || method.IsGenericMethodDefinition) { return 0; } string text = type.Name.ToLowerInvariant(); string text2 = method.Name.ToLowerInvariant(); bool flag = text2.Contains("damage") || text2.Contains("hit"); bool flag2 = text2.Contains("text") || text2.Contains("popup") || text2.Contains("number") || text2.Contains("indicator") || text2.Contains("feedback") || text.Contains("damage") || text.Contains("popup") || text.Contains("floating"); if (!flag || !flag2) { return 0; } ParameterInfo[] parameters = method.GetParameters(); bool flag3 = false; bool flag4 = false; for (int i = 0; i < parameters.Length; i++) { Type parameterType = parameters[i].ParameterType; if (parameterType == typeof(Vector3)) { flag3 = true; } if (parameterType == typeof(float) || parameterType == typeof(double) || parameterType == typeof(int) || parameterType == typeof(string)) { flag4 = true; } } if (!flag3 || !flag4) { return 0; } int num = 20; if (text2.Contains("damage")) { num += 20; } if (text2.Contains("popup") || text2.Contains("text") || text2.Contains("number")) { num += 20; } if (text.Contains("damage") || text.Contains("popup")) { num += 10; } return num; } private static object FindRuntimeInstance(Type type) { if (type == null || !typeof(Object).IsAssignableFrom(type)) { return null; } try { return Object.FindFirstObjectByType(type, (FindObjectsInactive)1); } catch { try { Object[] array = Resources.FindObjectsOfTypeAll(type); if (array != null && array.Length != 0) { return array[0]; } } catch { } } return null; } } internal sealed class BoatCreatureProxyMarker : MonoBehaviour { internal Boat Boat; internal Creature ProxyCreature; } internal static class BoatCreatureProxyRouting { private static readonly Dictionary ProxyBoats = new Dictionary(); private static readonly HashSet LifecyclePatched = new HashSet(); private static ManualLogSource _logger; private static bool _unsupportedLogged; internal static void InstallLifecycleGuards(Harmony harmony, ManualLogSource logger) { //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown _logger = logger; if (harmony == null) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(BoatCreatureProxyRouting), "CreatureLifecyclePrefix", (Type[])null, (Type[])null); if (methodInfo == null) { return; } string[] array = new string[8] { "Awake", "Start", "OnEnable", "Update", "FixedUpdate", "LateUpdate", "OnDisable", "OnDestroy" }; MethodInfo[] array2; try { array2 = typeof(Creature).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { array2 = null; } if (array2 == null) { return; } foreach (MethodInfo methodInfo2 in array2) { if (methodInfo2 == null || methodInfo2.IsAbstract || methodInfo2.IsGenericMethodDefinition || LifecyclePatched.Contains(methodInfo2)) { continue; } bool flag = false; for (int j = 0; j < array.Length; j++) { if (methodInfo2.Name == array[j]) { flag = true; break; } } if (flag) { try { harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); LifecyclePatched.Add(methodInfo2); } catch { } } } } private static bool CreatureLifecyclePrefix(Creature __instance) { return !IsProxy(__instance); } internal static void EnsureForBoat(Boat boat) { //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: 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_021a: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //IL_00e8: 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_010c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null || !((NetworkBehaviour)boat).IsSpawned) { return; } Type typeFromHandle = typeof(Creature); if (typeFromHandle.IsAbstract || !typeof(Component).IsAssignableFrom(typeFromHandle)) { if (!_unsupportedLogged) { _unsupportedLogged = true; ManualLogSource logger = _logger; if (logger != null) { logger.LogWarning((object)"Boat Creature proxy unavailable because Creature cannot be added as a Unity component in this game build."); } } return; } ResolveNativeCreatureTargeting(out var layer, out var tag); Transform val = ((Component)boat).transform.Find("Untamo Boat Creature Target"); GameObject val2 = (((Object)(object)val == (Object)null) ? null : ((Component)val).gameObject); if ((Object)(object)val2 == (Object)null) { val2 = new GameObject("Untamo Boat Creature Target"); val2.transform.SetParent(((Component)boat).transform, false); val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.transform.localScale = Vector3.one; } if (layer >= 0 && layer <= 31) { val2.layer = layer; } if (!string.IsNullOrEmpty(tag)) { try { val2.tag = tag; } catch { } } if (!TryGetBoatProxyBounds(boat, out var bounds)) { return; } BoxCollider val3 = val2.GetComponent(); if ((Object)(object)val3 == (Object)null) { val3 = val2.AddComponent(); } Vector3 center = val2.transform.InverseTransformPoint(((Bounds)(ref bounds)).center); Vector3 lossyScale = val2.transform.lossyScale; val3.center = center; val3.size = new Vector3(((Bounds)(ref bounds)).size.x / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.x)), ((Bounds)(ref bounds)).size.y / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.y)), ((Bounds)(ref bounds)).size.z / Mathf.Max(0.0001f, Mathf.Abs(lossyScale.z))); ((Collider)val3).isTrigger = true; ((Collider)val3).enabled = true; BoatCreatureProxyMarker boatCreatureProxyMarker = val2.GetComponent(); if ((Object)(object)boatCreatureProxyMarker == (Object)null) { boatCreatureProxyMarker = val2.AddComponent(); } boatCreatureProxyMarker.Boat = boat; Creature val4 = boatCreatureProxyMarker.ProxyCreature; if ((Object)(object)val4 == (Object)null) { val4 = val2.GetComponent(); if ((Object)(object)val4 == (Object)null) { try { Component obj2 = val2.AddComponent(typeFromHandle); val4 = (Creature)(object)((obj2 is Creature) ? obj2 : null); } catch (Exception ex) { if (!_unsupportedLogged) { _unsupportedLogged = true; ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)("Could not create Boat Creature target proxy: " + ex.Message)); } } return; } } boatCreatureProxyMarker.ProxyCreature = val4; } if (!((Object)(object)val4 == (Object)null)) { try { ((Behaviour)val4).enabled = false; } catch { } InitializeProxyCreature(val4); ProxyBoats[val4] = boat; } } private static void ResolveNativeCreatureTargeting(out int layer, out string tag) { layer = -1; tag = string.Empty; Creature[] array; try { array = Object.FindObjectsByType((FindObjectsSortMode)0); } catch { array = null; } if (array == null) { return; } foreach (Creature val in array) { if (!((Object)(object)val == (Object)null) && !IsProxy(val) && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { Collider componentInChildren = ((Component)val).GetComponentInChildren(); GameObject val2 = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).gameObject : ((Component)val).gameObject); layer = val2.layer; try { tag = val2.tag; break; } catch { tag = string.Empty; break; } } } } private static bool TryGetBoatProxyBounds(Boat boat, out Bounds bounds) { //IL_0002: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_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) bounds = default(Bounds); if ((Object)(object)boat == (Object)null) { return false; } Renderer[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } bool flag = false; if (array != null) { foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && val.enabled && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy && !(((Object)((Component)val).gameObject).name == "Untamo Boat Creature Target")) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } } if (flag) { ((Bounds)(ref bounds)).Expand(new Vector3(0.2f, 0.2f, 0.2f)); return true; } Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(boat); if (managerColliders == null) { return false; } foreach (Collider val2 in managerColliders) { if (!((Object)(object)val2 == (Object)null) && val2.enabled && !BoatHitboxRouting.IsCollisionProxy(((Component)val2).transform)) { if (!flag) { bounds = val2.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val2.bounds); } } } return flag; } private static void InitializeProxyCreature(Creature creature) { if ((Object)(object)creature == (Object)null) { return; } Type type = ((object)creature).GetType(); while (type != null && type != typeof(MonoBehaviour)) { FieldInfo[] array; try { array = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { array = null; } if (array != null) { foreach (FieldInfo fieldInfo in array) { if (fieldInfo == null || fieldInfo.IsInitOnly) { continue; } string text = fieldInfo.Name.ToLowerInvariant(); try { if ((text == "health" || text.Contains("currenthealth")) && fieldInfo.FieldType == typeof(float)) { fieldInfo.SetValue(creature, 7500f); } else if ((text == "health" || text.Contains("currenthealth")) && fieldInfo.FieldType == typeof(int)) { fieldInfo.SetValue(creature, Mathf.RoundToInt(7500f)); } else if (text.Contains("dead") && fieldInfo.FieldType == typeof(bool)) { fieldInfo.SetValue(creature, false); } else if (text.Contains("alive") && fieldInfo.FieldType == typeof(bool)) { fieldInfo.SetValue(creature, true); } } catch { } } } type = type.BaseType; } } internal static bool TryGetBoat(Creature creature, out Boat boat) { boat = null; if ((Object)(object)creature == (Object)null) { return false; } if (ProxyBoats.TryGetValue(creature, out boat) && (Object)(object)boat != (Object)null) { return true; } BoatCreatureProxyMarker component = ((Component)creature).GetComponent(); if ((Object)(object)component == (Object)null || (Object)(object)component.Boat == (Object)null) { return false; } boat = component.Boat; ProxyBoats[creature] = boat; return true; } internal static bool IsProxy(Creature creature) { Boat boat; return TryGetBoat(creature, out boat); } internal static void DisableForSinking(Boat boat) { if ((Object)(object)boat == (Object)null) { return; } Transform val = ((Component)boat).transform.Find("Untamo Boat Creature Target"); if (!((Object)(object)val == (Object)null)) { Collider component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { component.enabled = false; } } } internal static void ForgetBoat(Boat boat) { if ((Object)(object)boat == (Object)null || ProxyBoats.Count == 0) { return; } List list = new List(); foreach (KeyValuePair proxyBoat in ProxyBoats) { if ((Object)(object)proxyBoat.Key == (Object)null || (Object)(object)proxyBoat.Value == (Object)null || (Object)(object)proxyBoat.Value == (Object)(object)boat) { list.Add(proxyBoat.Key); } } for (int i = 0; i < list.Count; i++) { ProxyBoats.Remove(list[i]); } } } internal sealed class BoatDamagePopup : MonoBehaviour { private TextMesh _text; private float _bornAt; internal void Initialize(TextMesh text) { _text = text; _bornAt = Time.unscaledTime; } private void LateUpdate() { //IL_002c: 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_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_00bc: 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_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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_006b: 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_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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_text == (Object)null) { return; } float num = Time.unscaledTime - _bornAt; Transform transform = ((Component)this).transform; transform.position += Vector3.up * (0.72f * Time.unscaledDeltaTime); Camera main = Camera.main; if ((Object)(object)main != (Object)null) { Vector3 val = ((Component)this).transform.position - ((Component)main).transform.position; if (((Vector3)(ref val)).sqrMagnitude > 0.0001f) { ((Component)this).transform.rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up); } } Color color = _text.color; color.a = 1f - Mathf.Clamp01(num / 1f); _text.color = color; float num2 = 1f + Mathf.Sin(Mathf.Clamp01(num / 0.18f) * MathF.PI) * 0.22f; ((Component)this).transform.localScale = Vector3.one * num2; } } internal static class BoatAdditionalDamageBridge { private static readonly HashSet Patched = new HashSet(); private static ManualLogSource _logger; private static float _lastExplosionAt = -10f; private static Vector3 _lastExplosionPosition; private static float _lastPunchAt = -10f; private static float _lastMeleeAt = -10f; internal static void Install(Harmony harmony, ManualLogSource logger) { _logger = logger; if (harmony != null) { PatchNamedMethods(harmony, typeof(ExplosionManager), new string[3] { "CreateExplosion", "ObserverExplosionHit", "RpcLogic___ObserverExplosionHit___2627372740" }, "ExplosionPostfix"); } } private static void PatchNamedMethods(Harmony harmony, Type type, string[] names, string postfixName) { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown if (type == null || names == null) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(BoatAdditionalDamageBridge), postfixName, (Type[])null, (Type[])null); if (methodInfo == null) { return; } MethodInfo[] methods; try { methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { return; } if (methods == null) { return; } foreach (MethodInfo methodInfo2 in methods) { if (methodInfo2 == null || methodInfo2.IsAbstract || methodInfo2.IsGenericMethodDefinition || methodInfo2.GetMethodBody() == null || Patched.Contains(methodInfo2)) { continue; } bool flag = false; for (int j = 0; j < names.Length; j++) { if (methodInfo2.Name == names[j]) { flag = true; break; } } if (!flag) { continue; } try { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Patched.Add(methodInfo2); ManualLogSource logger = _logger; if (logger != null) { logger.LogInfo((object)("Boat damage hooked " + type.Name + "." + methodInfo2.Name + ".")); } } catch (Exception ex) { ManualLogSource logger2 = _logger; if (logger2 != null) { logger2.LogWarning((object)("Boat damage could not hook " + type.Name + "." + methodInfo2.Name + ": " + ex.Message)); } } } } private static void ExplosionPostfix(object __instance, object[] __args, MethodBase __originalMethod) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00e9: 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_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_013c: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) Vector3 position = Vector3.zero; float damage = -1f; float radius = -1f; ParameterInfo[] array = null; try { array = ((__originalMethod == null) ? null : __originalMethod.GetParameters()); } catch { } if (__args != null) { for (int i = 0; i < __args.Length; i++) { object value = __args[i]; string memberName = ((array != null && i < array.Length && array[i] != null) ? (array[i].Name ?? string.Empty) : string.Empty); ExtractExplosionContext(value, memberName, 0, ref position, ref damage, ref radius); } } ExtractExplosionContext(__instance, string.Empty, 0, ref position, ref damage, ref radius); if (position == Vector3.zero) { Component val = (Component)((__instance is Component) ? __instance : null); if (val != null) { position = val.transform.position; } } ResolveExplosionValues(__instance, ref damage, ref radius); if (!(position == Vector3.zero)) { if (radius <= 0f) { radius = 8f; } if (damage <= 0f) { damage = 1000f; } if (!(Time.unscaledTime - _lastExplosionAt < 0.18f) || !(Vector3.Distance(position, _lastExplosionPosition) < 1.5f)) { _lastExplosionAt = Time.unscaledTime; _lastExplosionPosition = position; BoatDamageRouting.ApplyExplosionDamage(position, damage, radius); } } } private static void ExtractExplosionContext(object value, string memberName, int depth, ref Vector3 position, ref float damage, ref float radius) { //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_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_0090: 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) if (value == null || depth > 2) { return; } string text = (memberName ?? string.Empty).ToLowerInvariant(); if (value is Vector3 val) { if (position == Vector3.zero || text.Contains("position") || text.Contains("point") || text.Contains("origin") || text.Contains("center")) { position = val; } return; } float num = ((value is int num2) ? ((float)num2) : ((value is float num3) ? num3 : ((!(value is double num4) || 1 == 0) ? float.NaN : ((float)num4)))); if (!float.IsNaN(num) && num > 0f) { if ((text.Contains("radius") || text.Contains("range")) && radius <= 0f) { radius = num; } else if (text.Contains("damage") && damage <= 0f) { damage = num; } return; } Type type = value.GetType(); if (type.IsPrimitive || type.IsEnum || type == typeof(string)) { return; } FieldInfo[] array; try { array = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { array = null; } if (array != null) { foreach (FieldInfo fieldInfo in array) { if (!(fieldInfo == null) && !fieldInfo.IsStatic) { try { ExtractExplosionContext(fieldInfo.GetValue(value), fieldInfo.Name, depth + 1, ref position, ref damage, ref radius); } catch { } } } } PropertyInfo[] array2; try { array2 = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { array2 = null; } if (array2 == null) { return; } foreach (PropertyInfo propertyInfo in array2) { if (propertyInfo == null || !propertyInfo.CanRead || propertyInfo.GetIndexParameters().Length != 0) { continue; } string text2 = propertyInfo.Name.ToLowerInvariant(); if (text2.Contains("position") || text2.Contains("point") || text2.Contains("origin") || text2.Contains("center") || text2.Contains("damage") || text2.Contains("radius") || text2.Contains("range") || text2.Contains("explosion")) { try { ExtractExplosionContext(propertyInfo.GetValue(value, null), propertyInfo.Name, depth + 1, ref position, ref damage, ref radius); } catch { } } } } private static void ResolveExplosionValues(object source, ref float damage, ref float radius) { if (source == null) { return; } Type type = source.GetType(); FieldInfo[] fields; try { fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { return; } foreach (FieldInfo fieldInfo in fields) { if (fieldInfo == null) { continue; } string text = fieldInfo.Name.ToLowerInvariant(); try { object value = fieldInfo.GetValue(source); float num2; if (value is int num) { num2 = num; goto IL_00a9; } if (value is float num3) { num2 = num3; goto IL_00a9; } goto end_IL_0057; IL_00a9: if (damage <= 0f && text.Contains("damage") && num2 > 0f) { damage = num2; } if (radius <= 0f && text.Contains("radius") && num2 > 0f) { radius = num2; } end_IL_0057:; } catch { } } } private static void PunchPostfix(object __instance, object[] __args) { Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Component val = (Component)((__instance is Component) ? __instance : null); if (val != null) { Player componentInParent = val.GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent != (Object)(object)localPlayer) { return; } } if (!(Time.unscaledTime - _lastPunchAt < 0.22f)) { _lastPunchAt = Time.unscaledTime; float damage = ResolveMeleeDamage(__instance, __args, 25f); BoatDamageRouting.ApplyMeleeDamageFromPlayer(localPlayer, damage); } } private static void MeleePostfix(object __instance, object[] __args) { Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Component val = (Component)((__instance is Component) ? __instance : null); if (val != null) { Player componentInParent = val.GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent != (Object)(object)localPlayer) { return; } } if (!(Time.unscaledTime - _lastMeleeAt < 0.22f)) { _lastMeleeAt = Time.unscaledTime; float damage = ResolveMeleeDamage(__instance, __args, 50f); BoatDamageRouting.ApplyMeleeDamageFromPlayer(localPlayer, damage); } } private static float ResolveMeleeDamage(object source, object[] args, float fallback) { if (args != null) { for (int i = 0; i < args.Length; i++) { if (args[i] is int num && num > 0 && num < 5000) { return num; } if (args[i] is float num2 && num2 > 0f && num2 < 7500f) { return num2; } } } if (source != null) { Type type = source.GetType(); FieldInfo[] array; try { array = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { array = null; } if (array != null) { foreach (FieldInfo fieldInfo in array) { if (fieldInfo == null || !fieldInfo.Name.ToLowerInvariant().Contains("damage")) { continue; } try { object value = fieldInfo.GetValue(source); if (value is int num3 && num3 > 0) { return num3; } if (value is float num4 && num4 > 0f) { return num4; } } catch { } } } } return fallback; } } internal static class BoatExactFistHitBridge { private static FieldInfo _damageField; private static FieldInfo _curTargetField; private static FieldInfo _targetHitPointField; internal static void Install(Harmony harmony, ManualLogSource logger) { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown if (harmony == null) { return; } MethodInfo method = typeof(PlayerPunching).GetMethod("HitTarget", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null); if (method == null || method.IsAbstract) { if (logger != null) { logger.LogWarning((object)"Boat fist damage: exact PlayerPunching.HitTarget(int) was not found."); } return; } _damageField = typeof(PlayerPunching).GetField("_damage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _curTargetField = typeof(PlayerPunching).GetField("_curTarget", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _targetHitPointField = typeof(PlayerPunching).GetField("_targetHitPoint", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo = AccessTools.Method(typeof(BoatExactFistHitBridge), "HitTargetPrefix", (Type[])null, (Type[])null); if (methodInfo == null) { return; } try { harmony.Patch((MethodBase)method, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); if (logger != null) { logger.LogInfo((object)"Boat fist damage hooked exact PlayerPunching.HitTarget(int)."); } } catch (Exception ex) { if (logger != null) { logger.LogWarning((object)("Boat fist damage could not hook PlayerPunching.HitTarget(int): " + ex.Message)); } } } private static void HitTargetPrefix(PlayerPunching __instance, int __0) { //IL_0098: 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) if ((Object)(object)__instance == (Object)null || __0 < 0) { return; } Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Player componentInParent = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && (Object)(object)componentInParent != (Object)(object)localPlayer) { return; } Transform targetAt = GetTargetAt(__instance, __0); if (!((Object)(object)targetAt == (Object)null)) { Boat val = ResolveBoat(targetAt); if (!((Object)(object)val == (Object)null) && !BoatDamageRouting.IsSinking(val)) { float damage = 1f; Vector3 hitPoint = ResolveWorldHitPoint(__instance, targetAt, __0); BoatDamageRouting.ApplyExactFistDamage(val, damage, hitPoint); } } } private static Transform GetTargetAt(PlayerPunching punching, int index) { if ((Object)(object)punching == (Object)null || index < 0 || _curTargetField == null) { return null; } object value; try { value = _curTargetField.GetValue(punching); } catch { return null; } if (value is Transform[] array) { if (index >= array.Length) { return null; } return array[index]; } if (!(value is Array array2) || index >= array2.Length) { return null; } try { object? value2 = array2.GetValue(index); return (Transform)((value2 is Transform) ? value2 : null); } catch { return null; } } private static float ResolveRealFistDamage(PlayerPunching punching) { if ((Object)(object)punching == (Object)null || _damageField == null) { return -1f; } object value; try { value = _damageField.GetValue(punching); } catch { return -1f; } if (value is int num && num > 0) { return num; } if (value is float num2 && num2 > 0f) { return num2; } return -1f; } private static Vector3 ResolveWorldHitPoint(PlayerPunching punching, Transform targetTransform, int index) { //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_00ed: 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_0033: 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_0040: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00d6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)punching == (Object)null || (Object)(object)targetTransform == (Object)null || index < 0 || _targetHitPointField == null) { return ((Object)(object)targetTransform != (Object)null) ? targetTransform.position : Vector3.zero; } object obj; try { obj = _targetHitPointField.GetValue(punching); } catch { obj = null; } if (obj is Vector3[] array && index < array.Length) { return targetTransform.TransformPoint(array[index]); } if (obj is Array array2 && index < array2.Length) { try { if (array2.GetValue(index) is Vector3 val) { return targetTransform.TransformPoint(val); } } catch { } } return targetTransform.position; } private static Boat ResolveBoat(Transform targetTransform) { //IL_0033: 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_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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_00f3: 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_00f8: 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_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)targetTransform == (Object)null) { return null; } Boat componentInParent = ((Component)targetTransform).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { return componentInParent; } Vector3 position = targetTransform.position; Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); Boat val = null; float num = float.MaxValue; foreach (Boat val2 in array) { if ((Object)(object)val2 == (Object)null || !((NetworkBehaviour)val2).IsSpawned) { continue; } Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(val2); if (managerColliders == null) { continue; } foreach (Collider val3 in managerColliders) { if (!((Object)(object)val3 == (Object)null)) { Transform transform = ((Component)val3).transform; if ((Object)(object)targetTransform == (Object)(object)transform || targetTransform.IsChildOf(transform) || transform.IsChildOf(targetTransform)) { return val2; } Bounds bounds = val3.bounds; Vector3 val4 = ((Bounds)(ref bounds)).ClosestPoint(position); float num2 = Vector3.Distance(position, val4); if (num2 < num) { num = num2; val = val2; } } } } LayerMask boatLayer = GameInfo.BoatLayer; if ((((LayerMask)(ref boatLayer)).value & (1 << ((Component)targetTransform).gameObject.layer)) != 0 && (Object)(object)val != (Object)null && num <= 1.25f) { return val; } return null; } } internal static class BoatExactMeleeHitBridge { private static FieldInfo _curTargetField; private static FieldInfo _targetHitPointField; private static MethodInfo _getCurSharpnessMethod; private static PropertyInfo _sharpnessDamageProperty; private static FieldInfo _sharpnessDamageField; internal static void Install(Harmony harmony, ManualLogSource logger) { //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown if (harmony == null) { return; } MethodInfo method = typeof(Melee).GetMethod("HitTarget", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null); if (method == null || method.IsAbstract) { if (logger != null) { logger.LogWarning((object)"Boat melee damage: exact Melee.HitTarget(int) was not found."); } return; } _curTargetField = typeof(Melee).GetField("_curTarget", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _targetHitPointField = typeof(Melee).GetField("_targetHitPoint", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _getCurSharpnessMethod = typeof(Melee).GetMethod("GetCurSharpness", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); if (_getCurSharpnessMethod != null) { Type returnType = _getCurSharpnessMethod.ReturnType; _sharpnessDamageProperty = returnType.GetProperty("Damage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _sharpnessDamageField = returnType.GetField("_damage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } MethodInfo methodInfo = AccessTools.Method(typeof(BoatExactMeleeHitBridge), "HitTargetPrefix", (Type[])null, (Type[])null); if (methodInfo == null) { return; } try { harmony.Patch((MethodBase)method, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); if (logger != null) { logger.LogInfo((object)"Boat melee damage hooked exact Melee.HitTarget(int)."); } } catch (Exception ex) { if (logger != null) { logger.LogWarning((object)("Boat melee damage could not hook Melee.HitTarget(int): " + ex.Message)); } } } private static void HitTargetPrefix(Melee __instance, int __0) { //IL_00f8: 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)(object)__instance == (Object)null || __0 < 0) { return; } Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Component val = (Component)(object)(((Object)(object)localPlayer.Holding == (Object)null) ? null : localPlayer.Holding.HeldItem); if ((Object)(object)val != (Object)null && !((Object)(object)val == (Object)(object)__instance) && !((Component)__instance).transform.IsChildOf(val.transform) && !val.transform.IsChildOf(((Component)__instance).transform)) { return; } Transform targetAt = GetTargetAt(__instance, __0); if ((Object)(object)targetAt == (Object)null) { return; } Boat val2 = ResolveBoat(targetAt); if (!((Object)(object)val2 == (Object)null) && !BoatDamageRouting.IsSinking(val2)) { float num = ResolveRealDamage(__instance); if (!(num <= 0f)) { Vector3 hitPoint = ResolveWorldHitPoint(__instance, targetAt, __0); BoatDamageRouting.ApplyExactMeleeDamage(val2, num, hitPoint); } } } private static Transform GetTargetAt(Melee melee, int index) { if ((Object)(object)melee == (Object)null || index < 0 || _curTargetField == null) { return null; } object value; try { value = _curTargetField.GetValue(melee); } catch { return null; } if (value is Transform[] array) { if (index >= array.Length) { return null; } return array[index]; } if (!(value is Array array2) || index >= array2.Length) { return null; } try { object? value2 = array2.GetValue(index); return (Transform)((value2 is Transform) ? value2 : null); } catch { return null; } } private static Vector3 ResolveWorldHitPoint(Melee melee, Transform targetTransform, int index) { //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_00ed: 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_0033: 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_0040: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00d6: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)melee == (Object)null || (Object)(object)targetTransform == (Object)null || index < 0 || _targetHitPointField == null) { return ((Object)(object)targetTransform != (Object)null) ? targetTransform.position : Vector3.zero; } object obj; try { obj = _targetHitPointField.GetValue(melee); } catch { obj = null; } if (obj is Vector3[] array && index < array.Length) { return targetTransform.TransformPoint(array[index]); } if (obj is Array array2 && index < array2.Length) { try { if (array2.GetValue(index) is Vector3 val) { return targetTransform.TransformPoint(val); } } catch { } } return targetTransform.position; } private static Boat ResolveBoat(Transform targetTransform) { //IL_0033: 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_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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_00f3: 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_00f8: 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_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)targetTransform == (Object)null) { return null; } Boat componentInParent = ((Component)targetTransform).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { return componentInParent; } Vector3 position = targetTransform.position; Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); Boat val = null; float num = float.MaxValue; foreach (Boat val2 in array) { if ((Object)(object)val2 == (Object)null || !((NetworkBehaviour)val2).IsSpawned) { continue; } Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(val2); if (managerColliders == null) { continue; } foreach (Collider val3 in managerColliders) { if (!((Object)(object)val3 == (Object)null)) { Transform transform = ((Component)val3).transform; if ((Object)(object)targetTransform == (Object)(object)transform || targetTransform.IsChildOf(transform) || transform.IsChildOf(targetTransform)) { return val2; } Bounds bounds = val3.bounds; Vector3 val4 = ((Bounds)(ref bounds)).ClosestPoint(position); float num2 = Vector3.Distance(position, val4); if (num2 < num) { num = num2; val = val2; } } } } LayerMask boatLayer = GameInfo.BoatLayer; if ((((LayerMask)(ref boatLayer)).value & (1 << ((Component)targetTransform).gameObject.layer)) != 0 && (Object)(object)val != (Object)null && num <= 1.25f) { return val; } return null; } private static float ResolveRealDamage(Melee melee) { if ((Object)(object)melee == (Object)null || _getCurSharpnessMethod == null) { return -1f; } object obj; try { obj = _getCurSharpnessMethod.Invoke(melee, null); } catch { return -1f; } if (obj == null) { return -1f; } object value = null; if (_sharpnessDamageProperty != null && _sharpnessDamageProperty.CanRead) { try { value = _sharpnessDamageProperty.GetValue(obj, null); } catch { value = null; } } if (TryConvertDamage(value, out var damage)) { return damage; } if (_sharpnessDamageField != null) { try { value = _sharpnessDamageField.GetValue(obj); } catch { value = null; } if (TryConvertDamage(value, out damage)) { return damage; } } return -1f; } private static bool TryConvertDamage(object value, out float damage) { damage = -1f; if (value is int num) { damage = num; } else if (value is float num2) { damage = num2; } else if (value is double num3) { damage = (float)num3; } else if (value is byte b) { damage = (int)b; } else { if (!(value is short num4) || 1 == 0) { return false; } damage = num4; } return damage > 0f && damage < 100000f; } } [HarmonyPatch(typeof(GameInfo), "get_ProjectileHitLayer")] internal static class BoatProjectileHitLayerPatch { private static void Postfix(ref LayerMask __result) { //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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) int value = ((LayerMask)(ref __result)).value; LayerMask boatLayer = GameInfo.BoatLayer; __result = LayerMask.op_Implicit(value | ((LayerMask)(ref boatLayer)).value); } } [HarmonyPatch(typeof(GameInfo), "get_NpcProjectileHitLayer")] internal static class BoatNpcProjectileHitLayerPatch { private static void Postfix(ref LayerMask __result) { //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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) int value = ((LayerMask)(ref __result)).value; LayerMask boatLayer = GameInfo.BoatLayer; __result = LayerMask.op_Implicit(value | ((LayerMask)(ref boatLayer)).value); } } [HarmonyPatch(typeof(ProjectileManager), "Hit")] internal static class BoatProjectileManagerHitPatch { private sealed class ProjectileBoatHitState { internal Boat HitBoat; internal Boat PreviousManagerBoat; internal bool ManagerWasRedirected; } private static bool Prefix(Projectile __0, ProjectileType __1, RaycastHit __2, out ProjectileBoatHitState __state) { //IL_008d: 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) __state = null; if (__0 == null) { return false; } Collider collider = ((RaycastHit)(ref __2)).collider; Transform transform = ((RaycastHit)(ref __2)).transform; if ((Object)(object)collider == (Object)null || (Object)(object)transform == (Object)null) { return false; } try { if (!collider.enabled || (Object)(object)((Component)collider).gameObject == (Object)null || !((Component)collider).gameObject.activeInHierarchy) { return false; } } catch { return false; } Boat val = BoatDamageRouting.FindBoatForProjectileHit(__2); try { BoatDamageRouting.TryApplyProjectileDamage(__0, __1, __2); } catch (MissingReferenceException) { return false; } catch (NullReferenceException) { return false; } if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned || (Object)(object)BoatManager.Instance == (Object)null) { return true; } ProjectileBoatHitState projectileBoatHitState = new ProjectileBoatHitState(); projectileBoatHitState.HitBoat = val; projectileBoatHitState.PreviousManagerBoat = BoatManager.Boat; if ((Object)(object)projectileBoatHitState.PreviousManagerBoat != (Object)(object)val) { try { BoatManagerContactGuard.AllowExplicitSwitch(val); BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(val), val); projectileBoatHitState.ManagerWasRedirected = (Object)(object)BoatManager.Boat == (Object)(object)val; } catch { projectileBoatHitState.ManagerWasRedirected = false; } } __state = projectileBoatHitState; return true; } private static void Postfix(ProjectileBoatHitState __state) { if (__state == null || !__state.ManagerWasRedirected || (Object)(object)BoatManager.Instance == (Object)null) { return; } try { Boat previousManagerBoat = __state.PreviousManagerBoat; if ((Object)(object)previousManagerBoat != (Object)null && ((NetworkBehaviour)previousManagerBoat).IsSpawned && (Object)(object)((Component)previousManagerBoat).gameObject != (Object)null && ((Component)previousManagerBoat).gameObject.activeInHierarchy) { BoatManagerContactGuard.AllowExplicitSwitch(previousManagerBoat); BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(previousManagerBoat), previousManagerBoat); } else { BoatManager.SetBoat(Array.Empty(), (Boat)null); } } catch { } finally { BoatManagerContactGuard.ClearExplicitSwitch(__state.HitBoat); if ((Object)(object)__state.PreviousManagerBoat != (Object)null) { BoatManagerContactGuard.ClearExplicitSwitch(__state.PreviousManagerBoat); } } } } [HarmonyPatch(typeof(Disc), "OnCollisionEnter")] internal static class BoatDiscNativeCollisionPatch { private sealed class ThrowState { internal bool WasHeld; internal bool Consumed; } private static readonly Dictionary ThrowStates = new Dictionary(); private static readonly FieldInfo DiscMinimumDamageMagnitudeField = AccessTools.Field(typeof(Disc), "_minDamageMagnitude"); private static readonly FieldInfo DiscHitThisUpdateField = AccessTools.Field(typeof(Disc), "_hitThisUpdate"); private static readonly FieldInfo ItemRigidbodyField = AccessTools.Field(typeof(Item), "_rig"); internal static void UpdateThrowState() { Player localPlayer = Player.LocalPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)localPlayer.Holding == (Object)null)) { Item heldItem = localPlayer.Holding.HeldItem; Disc val = (Disc)(object)((heldItem is Disc) ? heldItem : null); if (!((Object)(object)val == (Object)null)) { ThrowState state = GetState(val); state.WasHeld = true; state.Consumed = false; } } } private static void Prefix(Disc __instance, Collision __0) { //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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_017f: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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_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_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || __0 == null || __0.contactCount <= 0) { return; } ThrowState state = GetState(__instance); if (!state.WasHeld || state.Consumed) { return; } Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer != (Object)null && (Object)(object)localPlayer.Holding != (Object)null && (Object)(object)localPlayer.Holding.HeldItem == (Object)(object)__instance) { return; } Boat val = FindHitBoat(__0); if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned || BoatDamageRouting.IsSinking(val)) { return; } Rigidbody val2 = ReadBody(__instance); if ((Object)(object)val2 == (Object)null) { return; } Vector3 linearVelocity = val2.linearVelocity; Vector2 val3 = new Vector2(linearVelocity.x, linearVelocity.z); float magnitude = ((Vector2)(ref val3)).magnitude; float num = ReadMinimumMagnitude(__instance); float num2 = Mathf.Max(num * 1.35f, num + 0.75f); if (magnitude < num2) { return; } state.Consumed = true; Vector3 hitPoint; try { ContactPoint contact = __0.GetContact(0); hitPoint = ((ContactPoint)(ref contact)).point; } catch { Vector3 val4; if (!((Object)(object)__0.collider != (Object)null)) { val4 = ((Component)val).transform.position; } else { Bounds bounds = __0.collider.bounds; val4 = ((Bounds)(ref bounds)).center; } hitPoint = val4; } BoatDamageRouting.ApplyDiscDamage(val, 30f, hitPoint); try { if (DiscHitThisUpdateField != null) { DiscHitThisUpdateField.SetValue(__instance, true); } } catch { } } private static ThrowState GetState(Disc disc) { if (!ThrowStates.TryGetValue(disc, out var value) || value == null) { value = new ThrowState(); ThrowStates[disc] = value; } return value; } private static Rigidbody ReadBody(Disc disc) { try { if (ItemRigidbodyField != null) { object? value = ItemRigidbodyField.GetValue(disc); Rigidbody val = (Rigidbody)((value is Rigidbody) ? value : null); if ((Object)(object)val != (Object)null) { return val; } } } catch { } try { return ((Component)disc).GetComponent(); } catch { return null; } } private static float ReadMinimumMagnitude(Disc disc) { float num = 3f; try { if (DiscMinimumDamageMagnitudeField != null) { num = Convert.ToSingle(DiscMinimumDamageMagnitudeField.GetValue(disc), CultureInfo.InvariantCulture); } } catch { num = 3f; } return Mathf.Max(0f, num); } private static Boat FindHitBoat(Collision collision) { if (collision == null) { return null; } Collider collider = collision.collider; if ((Object)(object)collider != (Object)null) { Boat componentInParent = ((Component)collider).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null && ((NetworkBehaviour)componentInParent).IsSpawned) { return componentInParent; } } Transform transform = collision.transform; if ((Object)(object)transform != (Object)null) { Boat componentInParent2 = ((Component)transform).GetComponentInParent(); if ((Object)(object)componentInParent2 != (Object)null && ((NetworkBehaviour)componentInParent2).IsSpawned) { return componentInParent2; } } Boat[] array; try { array = Object.FindObjectsByType((FindObjectsSortMode)0); } catch { return null; } if (array == null) { return null; } foreach (Boat val in array) { if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned) { continue; } Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(val); if (managerColliders == null) { continue; } foreach (Collider val2 in managerColliders) { if ((Object)(object)val2 == (Object)null) { continue; } if ((Object)(object)val2 == (Object)(object)collider) { return val; } Transform transform2; try { transform2 = ((Component)val2).transform; } catch { continue; } if ((Object)(object)transform2 == (Object)null || (Object)(object)transform == (Object)null) { continue; } try { if ((Object)(object)transform2 == (Object)(object)transform || transform.IsChildOf(transform2) || transform2.IsChildOf(transform)) { return val; } } catch { } } } return null; } } internal sealed class BoatDamageReceiver : MonoBehaviour { internal Boat Boat; private void OnCollisionEnter(Collision collision) { //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_0072: 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_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) //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_004e: 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) if ((Object)(object)Boat == (Object)null || collision == null) { return; } Collider collider = collision.collider; Bounds bounds = collider.bounds; Vector3 value = ((Bounds)(ref bounds)).center; try { if (collision.contactCount > 0) { ContactPoint contact = collision.GetContact(0); value = ((ContactPoint)(ref contact)).point; } } catch { } Boat boat = Boat; Vector3 relativeVelocity = collision.relativeVelocity; BoatDamageRouting.TryApplyImpactDamage(boat, collider, ((Vector3)(ref relativeVelocity)).magnitude, value); } private void OnTriggerEnter(Collider other) { //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) if (!((Object)(object)Boat == (Object)null) && !((Object)(object)other == (Object)null)) { float impactSpeed = 0f; Rigidbody attachedRigidbody = other.attachedRigidbody; if ((Object)(object)attachedRigidbody != (Object)null) { Vector3 linearVelocity = attachedRigidbody.linearVelocity; impactSpeed = ((Vector3)(ref linearVelocity)).magnitude; } BoatDamageRouting.TryApplyImpactDamage(Boat, other, impactSpeed); } } } internal static class BoatCooknessInspectRouting { private static readonly MethodInfo NativeShowInspectInfo = typeof(PlayerUI).GetMethod("ShowInspectInfo", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3] { typeof(Purchasable), typeof(string), typeof(string) }, null); private static Boat _inspectedBoat; private static float _inspectHideAt; private static float _nextTextRefresh; private static bool _wasHoldingInspect; private static object _weaponUiInstance; private static bool _weaponUiSearched; internal static void Update() { //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Invalid comparison between Unknown and I4 Player localPlayer = Player.LocalPlayer; if ((Object)(object)_inspectedBoat != (Object)null) { Boat val = (((Object)(object)localPlayer == (Object)null) ? null : FindInspectableBoat(localPlayer)); if ((Object)(object)localPlayer == (Object)null || !((NetworkBehaviour)_inspectedBoat).IsSpawned || (Object)(object)val != (Object)(object)_inspectedBoat || ((Object)(object)localPlayer.Holding != (Object)null && (Object)(object)localPlayer.Holding.HeldItem != (Object)null)) { HideNativeInspect(); return; } if (Input.GetKey((KeyCode)102)) { _inspectHideAt = Time.unscaledTime + 2.25f; _wasHoldingInspect = true; } else { if (_wasHoldingInspect) { _inspectHideAt = Time.unscaledTime + 2.25f; _wasHoldingInspect = false; } if (Time.unscaledTime >= _inspectHideAt) { HideNativeInspect(); return; } } if (Time.unscaledTime >= _nextTextRefresh) { _nextTextRefresh = Time.unscaledTime + 0.1f; RefreshVisibleInspectText(_inspectedBoat); } } if (!((Object)(object)localPlayer == (Object)null) && (int)Cursor.lockState == 1) { Boat val2 = FindInspectableBoat(localPlayer); if (!((Object)(object)val2 == (Object)null) && (!((Object)(object)localPlayer.Holding != (Object)null) || !((Object)(object)localPlayer.Holding.HeldItem != (Object)null)) && Input.GetKeyDown((KeyCode)102)) { ShowNativeBoatInspect(val2); } } } private static Boat FindInspectableBoat(Player player) { if ((Object)(object)player == (Object)null) { return null; } Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); if (array != null) { foreach (Boat val in array) { if ((Object)(object)val != (Object)null && ((NetworkBehaviour)val).IsSpawned && (Object)(object)val.Driver == (Object)(object)player) { return val; } } } Boat val2 = BoatClosestPhysicsRouting.FindNearestPhysicalBoat(player, 3.5f); if ((Object)(object)val2 == (Object)null || !((NetworkBehaviour)val2).IsSpawned || (Object)(object)((Component)val2).gameObject == (Object)null || !((Component)val2).gameObject.activeInHierarchy) { return null; } return val2; } private static void ShowNativeBoatInspect(Boat boat) { if ((Object)(object)boat == (Object)null || NativeShowInspectInfo == null) { return; } string text = BuildDescription(boat); try { string text2 = (((Object)(object)Plugin.Instance != (Object)null) ? Plugin.Instance.GetBoatDisplayName(boat) : "Original Boat"); NativeShowInspectInfo.Invoke(null, new object[3] { null, text2, text }); _inspectedBoat = boat; _inspectHideAt = Time.unscaledTime + 2.25f; _wasHoldingInspect = Input.GetKey((KeyCode)102); _nextTextRefresh = Time.unscaledTime + 0.05f; _weaponUiSearched = false; _weaponUiInstance = null; } catch { _inspectedBoat = null; } } private static string BuildDescription(Boat boat) { if ((Object)(object)boat == (Object)null) { return string.Empty; } float health = BoatDamageRouting.GetHealth(boat); int num = (((Object)(object)Plugin.Instance != (Object)null) ? Plugin.Instance.GetBoatSellValue(boat) : 0); num = ((!((Object)(object)Plugin.Instance != (Object)null) || !string.Equals(Plugin.Instance.GetBoatDisplayName(boat), "Original Boat", StringComparison.OrdinalIgnoreCase)) ? (num + Plugin.GetFuelSellRefundValue(boat)) : 200); int num2 = (((Object)(object)Plugin.Instance != (Object)null) ? Plugin.Instance.GetBoatRepairCost(boat) : 0); float fuel = BoatFuelRouting.GetFuel(boat); float hullWeight = GetHullWeight(boat); float inspectMotorWeight = GetInspectMotorWeight(boat); float num3 = hullWeight + inspectMotorWeight; string skinDisplayName = BoatSkinRouting.GetSkinDisplayName(boat); string displayName = MotorRouting.GetDisplayName(boat); string skinDisplayName2 = BoatControlSkinRouting.GetSkinDisplayName(boat); string skinDisplayName3 = BoatRadarSkinRouting.GetSkinDisplayName(boat); string finishHudText = BoatSkinRouting.GetFinishHudText(boat); string stripeSecondaryHudText = BoatSkinRouting.GetStripeSecondaryHudText(boat); string text = ((skinDisplayName == "Original") ? "Original" : ("Skin " + skinDisplayName + stripeSecondaryHudText + finishHudText)); string text2 = ((skinDisplayName2 == "Original") ? "Original" : ("Skin " + skinDisplayName2)); string text3 = ((skinDisplayName3 == "Original") ? "Original" : (skinDisplayName3.StartsWith("Skin ", StringComparison.OrdinalIgnoreCase) ? skinDisplayName3 : ("Skin " + skinDisplayName3))); string hudDisplayName = BoatMotorSkinRouting.GetHudDisplayName(boat); return string.Format(CultureInfo.InvariantCulture, "Value: {2}\nRepair: {3}\n\nBoat\nBoat: {4}\nRadar: {5}\nControls: {6}\nWeight: {7:0.##}kg\n\nMotor\nType: {8}\nMotor: {9}\nWeight: {10:0.##}kg\n\nStats\nHealth: {11:0}\nFuel: {12:0.##}/5 Liter\nWeight: {13:0.##}kg", "#FF5A16", "#FFFFFF", num, num2, text, text3, text2, hullWeight, displayName, hudDisplayName, inspectMotorWeight, health, fuel, num3); } private static float GetHullWeight(Boat boat) { if ((Object)(object)boat == (Object)null) { return 0f; } return 200f; } private static float GetInspectMotorWeight(Boat boat) { if ((Object)(object)boat == (Object)null || MotorRouting.HasNoMotor(boat)) { return 0f; } string displayName = MotorRouting.GetDisplayName(boat); if (string.IsNullOrWhiteSpace(displayName)) { return 0f; } if (displayName.IndexOf("Dual Super Big", StringComparison.OrdinalIgnoreCase) >= 0) { return 90f; } if (displayName.IndexOf("Super Big", StringComparison.OrdinalIgnoreCase) >= 0) { return 45f; } if (displayName.IndexOf("Dual", StringComparison.OrdinalIgnoreCase) >= 0) { return 60f; } if (displayName.IndexOf("Big", StringComparison.OrdinalIgnoreCase) >= 0) { return 30f; } if (displayName.IndexOf("Default", StringComparison.OrdinalIgnoreCase) >= 0) { return 15f; } return 15f; } private static float GetBoatWeight(Boat boat) { return GetHullWeight(boat) + GetInspectMotorWeight(boat); } private static string GetBoatSkinText(Boat boat) { if ((Object)(object)boat == (Object)null) { return "0"; } byte skinIndex = BoatSkinRouting.GetSkinIndex(boat); string text = BoatSkinRouting.GetSkinDisplayName(boat); string finishHudText = BoatSkinRouting.GetFinishHudText(boat); string stripeSecondaryHudText = BoatSkinRouting.GetStripeSecondaryHudText(boat); if (!string.IsNullOrEmpty(stripeSecondaryHudText)) { text += stripeSecondaryHudText; } if (!string.IsNullOrEmpty(finishHudText)) { text += finishHudText; } return text; } private static void RefreshVisibleInspectText(Boat boat) { if ((Object)(object)boat == (Object)null) { return; } object weaponUiInstance = GetWeaponUiInstance(); if (weaponUiInstance == null) { return; } string value = BuildDescription(boat); string[] array = new string[4] { "_inspectedWeaponText", "_itemInfoText", "_descriptionText", "_itemText" }; bool flag = false; for (int i = 0; i < array.Length; i++) { FieldInfo field = weaponUiInstance.GetType().GetField(array[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!(field == null)) { object value2; try { value2 = field.GetValue(weaponUiInstance); } catch { continue; } if (TrySetNativeText(value2, value)) { flag = true; break; } } } if (flag) { return; } Component val = (Component)((weaponUiInstance is Component) ? weaponUiInstance : null); if ((Object)(object)val == (Object)null) { return; } Component[] array2; try { array2 = val.GetComponentsInChildren(true); } catch { array2 = null; } if (array2 == null) { return; } foreach (Component val2 in array2) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.gameObject == (Object)null)) { string text = ((Object)val2.gameObject).name.ToLowerInvariant(); if ((text.Contains("inspect") || text.Contains("info")) && TrySetNativeText(val2, value)) { break; } } } } private static bool TrySetNativeText(object textComponent, string value) { if (textComponent == null) { return false; } try { PropertyInfo property = textComponent.GetType().GetProperty("richText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.CanWrite && property.PropertyType == typeof(bool)) { property.SetValue(textComponent, true, null); } PropertyInfo property2 = textComponent.GetType().GetProperty("supportRichText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property2 != null && property2.CanWrite && property2.PropertyType == typeof(bool)) { property2.SetValue(textComponent, true, null); } } catch { } PropertyInfo property3 = textComponent.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property3 == null || !property3.CanWrite || property3.PropertyType != typeof(string)) { return false; } try { property3.SetValue(textComponent, value, null); return true; } catch { return false; } } private static object GetWeaponUiInstance() { if (_weaponUiInstance != null) { return _weaponUiInstance; } if (_weaponUiSearched) { return null; } _weaponUiSearched = true; Type type = typeof(Player).Assembly.GetType("WeaponUI", throwOnError: false); if (type == null) { return null; } Object[] array; try { array = Resources.FindObjectsOfTypeAll(type); } catch { array = null; } if (array == null) { return null; } foreach (Object obj2 in array) { Component val = (Component)(object)((obj2 is Component) ? obj2 : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val.gameObject == (Object)null) && val.gameObject.activeInHierarchy) { _weaponUiInstance = val; return val; } } return null; } private static void HideNativeInspect() { InvokeHideMethods(typeof(PlayerUI), null, "HideInspectInfo"); object weaponUiInstance = GetWeaponUiInstance(); if (weaponUiInstance != null) { InvokeHideMethods(weaponUiInstance.GetType(), weaponUiInstance, "HideInspectText"); } _inspectedBoat = null; _inspectHideAt = 0f; _nextTextRefresh = 0f; _wasHoldingInspect = false; } private static void InvokeHideMethods(Type type, object instance, string methodName) { if (type == null) { return; } MethodInfo[] array; try { array = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { array = null; } if (array == null) { return; } foreach (MethodInfo methodInfo in array) { if (methodInfo == null || methodInfo.Name != methodName || methodInfo.IsGenericMethodDefinition || (!methodInfo.IsStatic && instance == null)) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); object[] array2 = new object[parameters.Length]; bool flag = true; for (int j = 0; j < parameters.Length; j++) { Type parameterType = parameters[j].ParameterType; if (parameters[j].HasDefaultValue) { array2[j] = parameters[j].DefaultValue; } else if (parameterType == typeof(bool)) { array2[j] = true; } else if (parameterType == typeof(float)) { array2[j] = 0f; } else if (parameterType == typeof(double)) { array2[j] = 0.0; } else if (parameterType == typeof(int)) { array2[j] = 0; } else if (parameterType.IsValueType) { try { array2[j] = Activator.CreateInstance(parameterType); } catch { flag = false; break; } } else { array2[j] = null; } } if (flag) { try { methodInfo.Invoke(methodInfo.IsStatic ? null : instance, array2); break; } catch { } } } } } internal static class BoatCookingRouting { private sealed class CookState { internal float Cookness = 1f; internal bool CoolingDownFromBurn; internal float NextCookAt; internal float NextVisualAt; } private sealed class OriginalMaterialVisual { internal bool HasColor; internal Color Color; internal bool HasBaseColor; internal Color BaseColor; } private static readonly Dictionary States = new Dictionary(); private static readonly List HeatSources = new List(); private static Type _mainLavaType; private static Type _extraLavaType; private static Type _grillBoxType; private static readonly FieldInfo BoatIsInWaterField = typeof(Boat).GetField("_isInWater", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static float _nextSourceRefresh; private const float LavaRange = 4.5f; private const float GrillRange = 3.25f; private const float CookTickInterval = 0.5f; private const float CookPerLavaTick = 0.09f; private const float CookPerGrillTick = 0.05f; private static readonly HashSet CookRendererNames = new HashSet(StringComparer.Ordinal) { "Plank", "Boat", "Boat.001", "Boat2", "Motor", "Motor.001", "Motor2", "Motor3", "Engine", "Engine.001", "Propeller", "Propeller.001", "Propeller2" }; private static readonly Dictionary OriginalMaterialVisuals = new Dictionary(); private static readonly FieldInfo GrillCookPerTickField = typeof(GrillBox).GetField("_cookPerTick", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal static void CookFromGrill(Boat boat, GrillBox grill, Vector3 hitPoint) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null || (Object)(object)grill == (Object)null || BoatDamageRouting.IsSinking(boat)) { return; } float num = 0f; if (GrillCookPerTickField != null) { try { if (GrillCookPerTickField.GetValue(grill) is float num2) { num = num2; } } catch { } } if (!(num <= 0f)) { AddCookness(boat, num, hitPoint); } } internal static void CookFromLava(Boat boat, Vector3 hitPoint) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null || BoatDamageRouting.IsSinking(boat)) { return; } CookState orCreateState = GetOrCreateState(boat); if (orCreateState == null) { return; } if (!orCreateState.CoolingDownFromBurn) { orCreateState.Cookness += 0.15f; if (orCreateState.Cookness >= 1.5f) { orCreateState.Cookness = 1.5f; orCreateState.CoolingDownFromBurn = true; } } else { orCreateState.Cookness = Mathf.Max(0.1f, orCreateState.Cookness - 0.15f); } ApplyCooknessVisual(boat, orCreateState, force: true); BoatDamageRouting.ApplyHeatDamage(boat, 1f, hitPoint); } private static void AddCookness(Boat boat, float amount, Vector3 hitPoint) { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null || amount <= 0f) { return; } CookState orCreateState = GetOrCreateState(boat); if (orCreateState == null) { return; } if (!orCreateState.CoolingDownFromBurn) { orCreateState.Cookness += amount; if (orCreateState.Cookness >= 1.5f) { orCreateState.Cookness = 1.5f; orCreateState.CoolingDownFromBurn = true; } } else { orCreateState.Cookness -= amount; if (orCreateState.Cookness <= 0.1f) { orCreateState.Cookness = 0.1f; } } ApplyCooknessVisual(boat, orCreateState, force: true); BoatDamageRouting.ApplyHeatDamage(boat, 1f, hitPoint); } private static CookState GetOrCreateState(Boat boat) { if ((Object)(object)boat == (Object)null) { return null; } if (!States.TryGetValue(boat, out var value) || value == null) { value = new CookState(); States[boat] = value; } return value; } internal static void Update() { if (!InstanceFinder.IsServerStarted) { HeatSources.Clear(); return; } if (Time.unscaledTime >= _nextSourceRefresh) { _nextSourceRefresh = Time.unscaledTime + 1f; RefreshHeatSources(); } Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); if (array == null) { return; } HashSet hashSet = new HashSet(); foreach (Boat val in array) { if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).IsSpawned && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { hashSet.Add(val); UpdateBoat(val); } } if (States.Count <= hashSet.Count) { return; } List list = new List(); foreach (KeyValuePair state in States) { if ((Object)(object)state.Key == (Object)null || !hashSet.Contains(state.Key)) { list.Add(state.Key); } } for (int j = 0; j < list.Count; j++) { States.Remove(list[j]); } } internal static float GetCookness(Boat boat) { if ((Object)(object)boat == (Object)null) { return 0f; } if (!States.TryGetValue(boat, out var value) || value == null) { return 0f; } return Mathf.Clamp(value.Cookness, 0.1f, 1.5f); } internal static void SetSavedCookness(Boat boat, float cookness) { if (!((Object)(object)boat == (Object)null)) { if (!States.TryGetValue(boat, out var value) || value == null) { value = new CookState(); States[boat] = value; } if (cookness <= 0.001f) { cookness = 1f; } value.Cookness = Mathf.Clamp(cookness, 0.1f, 1.5f); value.CoolingDownFromBurn = value.Cookness < 1f; ApplyCooknessVisual(boat, value, force: true); } } internal static void ResetCookness(Boat boat) { if (!((Object)(object)boat == (Object)null)) { if (!States.TryGetValue(boat, out var value) || value == null) { value = new CookState(); States[boat] = value; } if (Mathf.Abs(value.Cookness - 1f) <= 0.001f && !value.CoolingDownFromBurn) { ApplyCooknessVisual(boat, value, force: true); return; } value.Cookness = 1f; value.CoolingDownFromBurn = false; value.NextCookAt = 0f; ApplyCooknessVisual(boat, value, force: true); } } private static void RefreshHeatSources() { HeatSources.Clear(); Assembly assembly = typeof(Creature).Assembly; if (_mainLavaType == null) { _mainLavaType = assembly.GetType("MainLava", throwOnError: false); } if (_extraLavaType == null) { _extraLavaType = assembly.GetType("ExtraLava", throwOnError: false); } if (_grillBoxType == null) { _grillBoxType = assembly.GetType("GrillBox", throwOnError: false); } AddHeatSourcesOfType(_mainLavaType); AddHeatSourcesOfType(_extraLavaType); AddHeatSourcesOfType(_grillBoxType); } private static void AddHeatSourcesOfType(Type type) { //IL_0076: 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) if (type == null || !typeof(Component).IsAssignableFrom(type)) { return; } Object[] array; try { array = Resources.FindObjectsOfTypeAll(type); } catch { array = null; } if (array == null) { return; } foreach (Object obj2 in array) { Component val = (Component)(object)((obj2 is Component) ? obj2 : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val.gameObject == (Object)null)) { Scene scene = val.gameObject.scene; if (((Scene)(ref scene)).IsValid() && val.gameObject.activeInHierarchy) { HeatSources.Add(val); } } } } private static void UpdateBoat(Boat boat) { //IL_008b: 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_01d8: 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_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_020e: 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_013b: 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_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null) { return; } CookState orCreateState = GetOrCreateState(boat); if (orCreateState == null) { return; } if (IsBoatInWater(boat)) { if (Mathf.Abs(orCreateState.Cookness - 1f) > 0.001f || orCreateState.CoolingDownFromBurn) { orCreateState.Cookness = 1f; orCreateState.CoolingDownFromBurn = false; orCreateState.NextCookAt = 0f; ApplyCooknessVisual(boat, orCreateState, force: true); } return; } Vector3 boatHeatPoint = GetBoatHeatPoint(boat); Component val = null; float num = float.MaxValue; bool flag = false; for (int i = 0; i < HeatSources.Count; i++) { Component val2 = HeatSources[i]; if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.gameObject == (Object)null) && val2.gameObject.activeInHierarchy) { bool flag2 = (_mainLavaType != null && _mainLavaType.IsInstanceOfType(val2)) || (_extraLavaType != null && _extraLavaType.IsInstanceOfType(val2)); float num2 = (flag2 ? 4.5f : 3.25f); Vector3 sourceHeatPoint = GetSourceHeatPoint(val2, boatHeatPoint); float num3 = Vector3.Distance(boatHeatPoint, sourceHeatPoint); if (!(num3 > num2) && !(num3 >= num)) { num = num3; val = val2; flag = flag2; } } } if ((Object)(object)val == (Object)null) { ApplyCooknessVisual(boat, orCreateState, force: false); return; } if (Time.unscaledTime < orCreateState.NextCookAt) { ApplyCooknessVisual(boat, orCreateState, force: false); return; } orCreateState.NextCookAt = Time.unscaledTime + 0.5f; Vector3 sourceHeatPoint2 = GetSourceHeatPoint(val, boatHeatPoint); if (flag) { CookFromLava(boat, sourceHeatPoint2); return; } GrillBox val3 = (GrillBox)(object)((val is GrillBox) ? val : null); if ((Object)(object)val3 != (Object)null) { CookFromGrill(boat, val3, sourceHeatPoint2); } } private static bool IsBoatInWater(Boat boat) { if ((Object)(object)boat == (Object)null || BoatIsInWaterField == null) { return false; } try { if (BoatIsInWaterField.GetValue(boat) is bool result) { return result; } } catch { } return false; } private static Vector3 GetBoatHeatPoint(Boat boat) { //IL_000c: 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_002c: 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_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_00a4: 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) if ((Object)(object)boat == (Object)null) { return Vector3.zero; } Rigidbody hiddenPhysicsRig = boat.HiddenPhysicsRig; if ((Object)(object)hiddenPhysicsRig != (Object)null) { return hiddenPhysicsRig.worldCenterOfMass; } Renderer[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } if (array != null && array.Length != 0) { Bounds val = default(Bounds); bool flag = false; foreach (Renderer val2 in array) { if (!((Object)(object)val2 == (Object)null)) { if (!flag) { val = val2.bounds; flag = true; } else { ((Bounds)(ref val)).Encapsulate(val2.bounds); } } } if (flag) { return ((Bounds)(ref val)).center; } } return ((Component)boat).transform.position; } private static Renderer[] GetCookRenderers(Boat boat) { if ((Object)(object)boat == (Object)null) { return Array.Empty(); } Renderer[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } if (array == null || array.Length == 0) { return Array.Empty(); } List list = new List(); foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && IsCookRenderer(((Component)val).transform)) { list.Add(val); } } return list.ToArray(); } private static bool IsCookRenderer(Transform transform) { if ((Object)(object)transform == (Object)null) { return false; } Transform val = transform; int num = 0; while ((Object)(object)val != (Object)null && num < 5) { string text = (((Object)(object)((Component)val).gameObject == (Object)null) ? string.Empty : ((Object)((Component)val).gameObject).name); if (CookRendererNames.Contains(text)) { return true; } string text2 = text.ToLowerInvariant(); if (text2.Contains("motor") || text2.Contains("engine") || text2.Contains("propeller")) { return true; } val = val.parent; num++; } return false; } private static Vector3 GetSourceHeatPoint(Component source, Vector3 boatPoint) { //IL_000c: 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_002e: 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_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_00bd: 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_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_007e: 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_0084: 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_0087: 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_00a1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null) { return boatPoint; } Collider[] array; try { array = source.GetComponentsInChildren(true); } catch { array = null; } Vector3 val = source.transform.position; float num = Vector3.Distance(boatPoint, val); if (array != null) { foreach (Collider val2 in array) { if (!((Object)(object)val2 == (Object)null) && val2.enabled) { Bounds bounds = val2.bounds; Vector3 val3 = ((Bounds)(ref bounds)).ClosestPoint(boatPoint); float num2 = Vector3.Distance(boatPoint, val3); if (num2 < num) { num = num2; val = val3; } } } } return val; } private static void ApplyCooknessVisual(Boat boat, CookState state, bool force) { //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null || state == null || (!force && Time.unscaledTime < state.NextVisualAt)) { return; } state.NextVisualAt = Time.unscaledTime + 0.2f; Renderer[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } if (array == null || array.Length == 0) { return; } int num = Shader.PropertyToID("_Cookness"); int num2 = Shader.PropertyToID("_Color"); int num3 = Shader.PropertyToID("_BaseColor"); Color val3 = default(Color); Color val4 = default(Color); foreach (Renderer val in array) { if ((Object)(object)val == (Object)null) { continue; } Material[] array2; try { array2 = val.materials; } catch { array2 = null; } if (array2 == null) { continue; } bool flag = true; foreach (Material val2 in array2) { if ((Object)(object)val2 == (Object)null) { continue; } bool flag2 = val2.HasProperty(num); if (flag2) { val2.SetFloat(num, state.Cookness); } if (flag2 || !flag) { continue; } if (!OriginalMaterialVisuals.TryGetValue(val2, out var value) || value == null) { value = new OriginalMaterialVisual(); if (val2.HasProperty(num2)) { value.HasColor = true; value.Color = val2.GetColor(num2); } if (val2.HasProperty(num3)) { value.HasBaseColor = true; value.BaseColor = val2.GetColor(num3); } OriginalMaterialVisuals[val2] = value; } float num4 = ((!(state.Cookness >= 1f)) ? Mathf.Clamp01((1f - state.Cookness) / 0.9f) : Mathf.Clamp01((state.Cookness - 1f) / 0.5f)); ((Color)(ref val3))..ctor(0.2f, 0.075f, 0.02f, 1f); ((Color)(ref val4))..ctor(0.015f, 0.009f, 0.006f, 1f); float num5 = ((state.Cookness < 1f) ? Mathf.Clamp01((1f - state.Cookness) / 0.9f) : Mathf.Clamp01((state.Cookness - 1.35f) / 0.15f)); Color val5 = Color.Lerp(val3, val4, num5); if (value.HasColor) { Color val6 = Color.Lerp(value.Color, val5, Mathf.Lerp(num4 * 0.82f, 0.97f, num5)); val6.a = value.Color.a; val2.SetColor(num2, val6); } if (value.HasBaseColor) { Color val7 = Color.Lerp(value.BaseColor, val5, Mathf.Lerp(num4 * 0.82f, 0.97f, num5)); val7.a = value.BaseColor.a; val2.SetColor(num3, val7); } } } } private static void RestoreOriginalMaterialColor(Material material, OriginalMaterialVisual original, int colorId, int baseColorId) { //IL_0032: 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) if (!((Object)(object)material == (Object)null) && original != null) { if (original.HasColor && material.HasProperty(colorId)) { material.SetColor(colorId, original.Color); } if (original.HasBaseColor && material.HasProperty(baseColorId)) { material.SetColor(baseColorId, original.BaseColor); } } } } internal static class BoatNativeHitFeedbackRouting { private static readonly FieldInfo MeleeLevelHitSoundField = AccessTools.Field(typeof(Melee), "_levelHitSound"); private static readonly FieldInfo MeleeLevelHitSoundVolField = AccessTools.Field(typeof(Melee), "_levelHitSoundVol"); private static readonly FieldInfo PunchLevelHitSoundField = AccessTools.Field(typeof(PlayerPunching), "_levelHitSound"); private static readonly FieldInfo PunchLevelHitSoundVolField = AccessTools.Field(typeof(PlayerPunching), "_levelHitSoundVol"); internal static void Show(Vector3 hitPoint, float damage, bool killed) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) Show(hitPoint, damage, killed, null); } internal static void Show(Vector3 hitPoint, float damage, bool killed, ProjectileType projectileType) { //IL_0002: 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) try { PlayerUI.AddHitMarker(hitPoint, killed); } catch { } if (TryGetActiveLevelHitSound(out var sound, out var volume) || TryGetProjectileHitSound(projectileType, out sound, out volume)) { PlayNativeLevelHitSound(sound, hitPoint, volume); } } private static bool TryGetActiveLevelHitSound(out string sound, out float volume) { sound = null; volume = 1f; Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } if ((Object)(object)localPlayer.Holding != (Object)null && (Object)(object)localPlayer.Holding.HeldItem != (Object)null) { Component heldItem = (Component)(object)localPlayer.Holding.HeldItem; if ((Object)(object)heldItem != (Object)null) { if (TryReadLevelHitSound(heldItem, out sound, out volume)) { return true; } Component[] array; try { array = heldItem.GetComponentsInChildren(true); } catch { array = null; } if (array != null) { foreach (Component val in array) { if (!((Object)(object)val == (Object)null) && TryReadLevelHitSound(val, out sound, out volume)) { return true; } } } } } Component[] array2; try { array2 = ((Component)localPlayer).GetComponentsInChildren(true); } catch { array2 = null; } if (array2 != null) { foreach (Component val2 in array2) { if (!((Object)(object)val2 == (Object)null) && TryReadLevelHitSound(val2, out sound, out volume)) { return true; } } } return false; } private static bool TryReadLevelHitSound(object source, out string sound, out float volume) { sound = null; volume = 1f; if (source == null) { return false; } Type type = source.GetType(); FieldInfo field = type.GetField("_levelHitSound", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); FieldInfo field2 = type.GetField("_levelHitSoundVol", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { PropertyInfo property = type.GetProperty("LevelHitSound", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { try { sound = property.GetValue(source, null) as string; } catch { sound = null; } } } else { try { sound = field.GetValue(source) as string; } catch { sound = null; } } if (string.IsNullOrWhiteSpace(sound)) { return false; } try { object obj3 = ((field2 != null) ? field2.GetValue(source) : null); if (obj3 == null) { PropertyInfo property2 = type.GetProperty("LevelHitSoundVol", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property2 != null) { obj3 = property2.GetValue(source, null); } } if (obj3 != null) { volume = Convert.ToSingle(obj3, CultureInfo.InvariantCulture); } } catch { volume = 1f; } if (float.IsNaN(volume) || float.IsInfinity(volume) || volume <= 0f) { volume = 1f; } return true; } private static bool TryGetProjectileHitSound(ProjectileType projectileType, out string sound, out float volume) { sound = null; volume = 1f; if (projectileType == null) { return false; } try { sound = projectileType.HitSound; volume = projectileType.HitSoundVolume; } catch { return false; } return !string.IsNullOrWhiteSpace(sound); } private static bool TryGetCurrentMeleeHitSound(out string sound, out float volume) { sound = null; volume = 1f; Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer.Holding == (Object)null) { return false; } Item heldItem = localPlayer.Holding.HeldItem; Melee val = (Melee)(object)((heldItem is Melee) ? heldItem : null); if ((Object)(object)val == (Object)null) { return false; } try { if (MeleeLevelHitSoundField != null) { sound = MeleeLevelHitSoundField.GetValue(val) as string; } if (MeleeLevelHitSoundVolField != null) { object value = MeleeLevelHitSoundVolField.GetValue(val); if (value != null) { volume = Convert.ToSingle(value, CultureInfo.InvariantCulture); } } } catch { return false; } return !string.IsNullOrWhiteSpace(sound); } private static bool TryGetPunchHitSound(out string sound, out float volume) { sound = null; volume = 1f; Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } PlayerPunching val = null; try { val = ((Component)localPlayer).GetComponentInChildren(true); } catch { val = null; } if ((Object)(object)val == (Object)null) { return false; } try { if (PunchLevelHitSoundField != null) { sound = PunchLevelHitSoundField.GetValue(val) as string; } if (PunchLevelHitSoundVolField != null) { object value = PunchLevelHitSoundVolField.GetValue(val); if (value != null) { volume = Convert.ToSingle(value, CultureInfo.InvariantCulture); } } } catch { return false; } return !string.IsNullOrWhiteSpace(sound); } private static void PlayNativeLevelHitSound(string sound, Vector3 hitPoint, float volume) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrWhiteSpace(sound)) { return; } if (float.IsNaN(volume) || float.IsInfinity(volume) || volume <= 0f) { volume = 1f; } try { AudioManager.PlayClipAt(sound, hitPoint, true, (AudioDistance)0, volume, 0.1f); } catch { } } } internal static class BoatDamageRouting { private sealed class DamageState { internal float Health = 7500f; internal bool Sinking; internal float DeleteAt; internal Rigidbody Body; internal Vector3 SinkAngularVelocity; internal Quaternion SinkRotation; } private sealed class ReferenceEqualityComparer : IEqualityComparer { internal static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer(); public new bool Equals(object left, object right) { return left == right; } public int GetHashCode(object value) { return RuntimeHelpers.GetHashCode(value); } } internal const float MaximumHealth = 7500f; private const float FallbackShotDamage = 250f; private const float FallbackFistDamage = 0f; private const float SinkDeleteDelay = 10f; private const float MinimumImpactSpeed = 3.5f; private static readonly Dictionary States = new Dictionary(); private static readonly Dictionary RecentImpactObjects = new Dictionary(); private static readonly Dictionary RecentDirectShots = new Dictionary(); private static float _lastObservedNativeCreatureDamage; private static float _lastObservedNativeCreatureDamageAt; private static float _nextRefresh; internal static void Update() { if (Time.unscaledTime >= _nextRefresh) { _nextRefresh = Time.unscaledTime + 0.5f; Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { EnsureBoat(array[i]); } CleanupDeadReferences(); CleanupImpactDebounce(); } ProcessExpiredSinkingBoats(); } internal static void FixedUpdate() { //IL_00ad: 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_00c2: 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_00d2: 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_00f7: 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) if (States.Count == 0) { return; } List list = new List(States.Keys); for (int i = 0; i < list.Count; i++) { Boat val = list[i]; if ((Object)(object)val == (Object)null || !States.TryGetValue(val, out var value) || value == null || !value.Sinking) { continue; } Rigidbody val2 = ResolveBody(val, value); if (!((Object)(object)val2 == (Object)null)) { if (!val2.isKinematic) { val2.isKinematic = true; } val2.detectCollisions = false; Vector3 position = val2.position + Vector3.down * (2.25f * Time.fixedDeltaTime); value.SinkRotation *= Quaternion.Euler(0.2f, 0.03f, 0.34f); val2.position = position; val2.rotation = value.SinkRotation; } } } internal static bool IsSinking(Boat boat) { if ((Object)(object)boat == (Object)null) { return false; } DamageState value; return States.TryGetValue(boat, out value) && value != null && value.Sinking; } internal static float GetHealth(Boat boat) { if ((Object)(object)boat == (Object)null) { return 0f; } DamageState damageState = EnsureBoat(boat); if (damageState == null) { return 0f; } return Mathf.Clamp(damageState.Health, 0f, 7500f); } internal static void SetSavedHealth(Boat boat, float health) { if (!((Object)(object)boat == (Object)null)) { DamageState damageState = EnsureBoat(boat); if (damageState != null && (damageState.Health = Mathf.Clamp(health, 0f, 7500f)) <= 0f && !damageState.Sinking) { BeginSinking(boat, damageState); } } } internal static string GetHealthText(Boat boat) { if ((Object)(object)boat == (Object)null) { return "0"; } DamageState damageState = EnsureBoat(boat); if (damageState == null) { return "0"; } return Mathf.RoundToInt(Mathf.Max(0f, damageState.Health)).ToString(CultureInfo.InvariantCulture); } internal static void ForgetBoat(Boat boat) { if (!((Object)(object)boat == (Object)null)) { States.Remove(boat); } } internal static void ShowCollisionStyleDamageText(Vector3 worldPosition, float damage) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ShowCollisionStyleDamageText(worldPosition, damage, lethalHit: false); } internal static void ShowCollisionStyleDamageText(Vector3 worldPosition, float damage, bool lethalHit) { //IL_0001: 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) if (!BoatNativeAttackBridge.TryShowNativeDamageText(worldPosition, damage, lethalHit)) { ShowDamagePopup(worldPosition, damage, lethalHit); } } internal static void ApplyDiscDamage(Boat boat, float damage, Vector3 hitPoint) { //IL_0034: 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) if (!((Object)(object)boat == (Object)null) && !(damage <= 0f) && !IsSinking(boat) && ApplyDamage(boat, damage)) { BoatNativeHitFeedbackRouting.Show(hitPoint, damage, IsSinking(boat)); ShowCollisionStyleDamageText(hitPoint, damage, IsSinking(boat)); } } internal static void ApplyHeatDamage(Boat boat, float damage, Vector3 hitPoint) { //IL_003f: 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)(object)boat == (Object)null) && !(damage <= 0f) && !IsSinking(boat)) { if (ApplyDamage(boat, damage)) { BoatNativeHitFeedbackRouting.Show(hitPoint, damage, IsSinking(boat)); } ShowCollisionStyleDamageText(hitPoint, damage, IsSinking(boat)); } } internal static void ApplyExactFistDamage(Boat boat, float damage, Vector3 hitPoint) { //IL_003f: 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)(object)boat == (Object)null) && !(damage <= 0f) && !IsSinking(boat)) { if (ApplyDamage(boat, damage)) { BoatNativeHitFeedbackRouting.Show(hitPoint, damage, IsSinking(boat)); } ShowCollisionStyleDamageText(hitPoint, damage, IsSinking(boat)); } } internal static void ApplyExactMeleeDamage(Boat boat, float damage, Vector3 hitPoint) { //IL_003f: 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)(object)boat == (Object)null) && !(damage <= 0f) && !IsSinking(boat)) { if (ApplyDamage(boat, damage)) { BoatNativeHitFeedbackRouting.Show(hitPoint, damage, IsSinking(boat)); } ShowCollisionStyleDamageText(hitPoint, damage, IsSinking(boat)); } } internal static void ApplyExplosionDamage(Vector3 explosionPosition, float damage, float radius) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_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_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) if (radius <= 0f) { radius = 8f; } if (damage <= 0f) { damage = 1000f; } Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); if (array == null) { return; } foreach (Boat val in array) { if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned || IsSinking(val) || !TryGetBoatDamageBounds(val, out var bounds)) { continue; } Vector3 val2 = ((Bounds)(ref bounds)).ClosestPoint(explosionPosition); float num = Vector3.Distance(explosionPosition, val2); if (!(num > radius)) { float num2 = 1f - Mathf.Clamp01(num / Mathf.Max(0.01f, radius)); float num3 = Mathf.Max(1f, damage * Mathf.Lerp(0.35f, 1f, num2)); if (ApplyDamage(val, num3)) { BoatNativeHitFeedbackRouting.Show(val2, num3, IsSinking(val)); } ShowCollisionStyleDamageText(val2, num3, IsSinking(val)); } } } internal static void ApplyMeleeDamageFromPlayer(Player player, float damage) { //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) //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_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_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_00ec: 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_00f2: 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_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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_0162: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { player = Player.LocalPlayer; } Camera main = Camera.main; if ((Object)(object)player == (Object)null || (Object)(object)main == (Object)null) { return; } if (damage <= 0f) { damage = 0f; } Vector3 position = ((Component)main).transform.position; Vector3 val = ((Component)main).transform.forward; Vector3 normalized = ((Vector3)(ref val)).normalized; Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); if (array == null) { return; } Boat val2 = null; Vector3 val3 = Vector3.zero; float num = float.MaxValue; foreach (Boat val4 in array) { if ((Object)(object)val4 == (Object)null || !((NetworkBehaviour)val4).IsSpawned || IsSinking(val4) || !TryGetBoatDamageBounds(val4, out var bounds)) { continue; } Vector3 val5 = ((Bounds)(ref bounds)).center - position; float num2 = Vector3.Dot(val5, normalized); if (num2 < -0.25f) { continue; } val = ((Bounds)(ref bounds)).extents; if (num2 > 5f + ((Vector3)(ref val)).magnitude) { continue; } float num3 = Mathf.Clamp(num2, 0f, 5f); Vector3 val6 = position + normalized * num3; Vector3 val7 = ((Bounds)(ref bounds)).ClosestPoint(val6); float num4 = Vector3.Distance(val6, val7); if (!(num4 > 1.15f)) { float num5 = num3 + num4 * 2f; if (!(num5 >= num)) { num = num5; val2 = val4; val3 = val7; } } } if (!((Object)(object)val2 == (Object)null) && (!RecentDirectShots.TryGetValue(val2, out var value) || !(Time.unscaledTime - value < 0.12f))) { RecentDirectShots[val2] = Time.unscaledTime; if (ApplyDamage(val2, damage)) { BoatNativeHitFeedbackRouting.Show(val3, damage, IsSinking(val2)); } ShowCollisionStyleDamageText(val3, damage, IsSinking(val2)); } } private static bool TryGetBoatDamageBounds(Boat boat, out Bounds bounds) { //IL_0002: 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_0095: 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_013e: Unknown result type (might be due to invalid IL or missing references) //IL_012b: 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) bounds = default(Bounds); if ((Object)(object)boat == (Object)null) { return false; } bool flag = false; Renderer[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } if (array != null) { foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && val.enabled && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } } if (flag) { return true; } Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(boat); if (managerColliders == null) { return false; } foreach (Collider val2 in managerColliders) { if (!((Object)(object)val2 == (Object)null) && val2.enabled) { if (!flag) { bounds = val2.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val2.bounds); } } } return flag; } internal static Boat FindBoatForProjectileHit(RaycastHit hit) { Collider collider = ((RaycastHit)(ref hit)).collider; Transform transform = ((RaycastHit)(ref hit)).transform; if ((Object)(object)collider == (Object)null || (Object)(object)transform == (Object)null) { return null; } Boat val = null; try { val = ((Component)collider).GetComponentInParent(); } catch { val = null; } if ((Object)(object)val == (Object)null) { try { val = ((Component)transform).GetComponentInParent(); } catch { val = null; } } if ((Object)(object)val == (Object)null) { Boat[] array; try { array = Object.FindObjectsByType((FindObjectsSortMode)0); } catch { array = null; } if (array != null) { for (int i = 0; i < array.Length; i++) { if (!((Object)(object)val == (Object)null)) { break; } Boat val2 = array[i]; if ((Object)(object)val2 == (Object)null || !((NetworkBehaviour)val2).IsSpawned) { continue; } Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(val2); if (managerColliders == null) { continue; } foreach (Collider val3 in managerColliders) { if ((Object)(object)val3 == (Object)null) { continue; } Transform transform2; try { transform2 = ((Component)val3).transform; } catch { continue; } if ((Object)(object)transform2 == (Object)null) { continue; } bool flag = (Object)(object)val3 == (Object)(object)collider || (Object)(object)transform2 == (Object)(object)transform; if (!flag) { try { flag = transform.IsChildOf(transform2) || transform2.IsChildOf(transform); } catch { flag = false; } } if (!flag) { continue; } val = val2; break; } } } } return ((Object)(object)val != (Object)null && ((NetworkBehaviour)val).IsSpawned) ? val : null; } internal static void TryApplyProjectileDamage(Projectile projectile, ProjectileType projectileType, RaycastHit hit) { //IL_007e: 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_00c2: 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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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_00ee: 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_00f3: Unknown result type (might be due to invalid IL or missing references) if (projectile == null) { return; } Collider collider = ((RaycastHit)(ref hit)).collider; Transform transform = ((RaycastHit)(ref hit)).transform; if ((Object)(object)collider == (Object)null || (Object)(object)transform == (Object)null) { return; } try { if (!collider.enabled || (Object)(object)((Component)collider).gameObject == (Object)null || !((Component)collider).gameObject.activeInHierarchy) { return; } } catch { return; } Boat val = FindBoatForProjectileHit(hit); if (!((Object)(object)val == (Object)null) && !IsSinking(val)) { float num = Mathf.Max(1f, (float)projectile.Damage); bool flag = ApplyDamage(val, num); Vector3 val2 = ((RaycastHit)(ref hit)).point; if (val2 == Vector3.zero) { val2 = (((Object)(object)transform != (Object)null) ? transform.position : ((Component)val).transform.position); } if (flag) { BoatNativeHitFeedbackRouting.Show(val2, num, IsSinking(val), projectileType); } ShowCollisionStyleDamageText(val2, num, IsSinking(val)); } } internal static void TryApplyImpactDamage(Boat boat, Collider other, float impactSpeed, Vector3? hitPoint = null) { //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0124: 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_012f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null || (Object)(object)other == (Object)null) { return; } Boat componentInParent = ((Component)other).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)(object)boat) { return; } Disc componentInParent2 = ((Component)other).GetComponentInParent(); if ((Object)(object)componentInParent2 != (Object)null || (!((Object)(object)componentInParent != (Object)null) && LooksLikeProjectile(other)) || impactSpeed < 3.5f) { return; } int impactIdentity = GetImpactIdentity(other); if (!RecentImpactObjects.TryGetValue(impactIdentity, out var value) || !(Time.unscaledTime - value < 0.2f)) { RecentImpactObjects[impactIdentity] = Time.unscaledTime; float num = Mathf.Max(0f, impactSpeed - 2.5f); float num2 = Mathf.Clamp(num * num * 2f, 2f, 500f); bool flag = ApplyDamage(boat, num2); Vector3 val; if (!hitPoint.HasValue) { Bounds bounds = other.bounds; val = ((Bounds)(ref bounds)).center; } else { val = hitPoint.Value; } Vector3 val2 = val; if (flag) { BoatNativeHitFeedbackRouting.Show(val2, num2, IsSinking(boat)); } ShowCollisionStyleDamageText(val2, num2, IsSinking(boat)); } } private static void TryApplyUniversalAttackFallback() { //IL_0098: 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_00a6: 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_00cb: Unknown result type (might be due to invalid IL or missing references) if (!Input.GetMouseButtonDown(0)) { return; } Player localPlayer = Player.LocalPlayer; Camera main = Camera.main; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)main == (Object)null)) { Component val = (Component)(object)(((Object)(object)localPlayer.Holding == (Object)null) ? null : localPlayer.Holding.HeldItem); bool flag = (Object)(object)val == (Object)null; float maximumDistance = (flag ? 3.5f : 250f); Ray val2 = main.ScreenPointToRay(new Vector3((float)Screen.width * 0.5f, (float)Screen.height * 0.5f, 0f)); if (TryFindBoatNearAimLine(((Ray)(ref val2)).origin, ((Ray)(ref val2)).direction, maximumDistance, out var targetBoat, out var hitPoint)) { ApplyAttackToBoat(targetBoat, hitPoint, ((Object)(object)val != (Object)null) ? ((object)val) : ((object)localPlayer), flag); } } } private static bool TryFindBoatNearAimLine(Vector3 origin, Vector3 direction, float maximumDistance, out Boat targetBoat, out Vector3 hitPoint) { //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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00d7: 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_00fe: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011b: 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_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) targetBoat = null; hitPoint = Vector3.zero; if (((Vector3)(ref direction)).sqrMagnitude < 0.0001f) { return false; } ((Vector3)(ref direction)).Normalize(); Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); float num = float.MaxValue; foreach (Boat val in array) { if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned || (Object)(object)((Component)val).gameObject == (Object)null || !((Component)val).gameObject.activeInHierarchy) { continue; } DamageState damageState = EnsureBoat(val); if ((damageState != null && damageState.Sinking) || !TryGetBoatWorldBounds(val, out var bounds)) { continue; } Vector3 val2 = ((Bounds)(ref bounds)).center - origin; float num2 = Vector3.Dot(val2, direction); if (num2 < 0f || num2 > maximumDistance) { continue; } Vector3 val3 = origin + direction * num2; Vector3 val4 = ((Bounds)(ref bounds)).ClosestPoint(val3); float num3 = Vector3.Distance(val3, val4); Vector3 extents = ((Bounds)(ref bounds)).extents; float num4 = Mathf.Max(0.65f, Mathf.Min(2.5f, ((Vector3)(ref extents)).magnitude * 0.3f)); Vector3 normalized = ((Vector3)(ref val2)).normalized; float num5 = Vector3.Angle(direction, normalized); extents = ((Bounds)(ref bounds)).extents; float num6 = Mathf.Clamp(2f + ((Vector3)(ref extents)).magnitude / Mathf.Max(2f, num2) * 20f, 2f, 9f); bool flag = num3 <= num4; bool flag2 = num5 <= num6; if (flag || flag2) { float num7 = num2 + num3 * 4f + num5 * 2f; if (!(num7 >= num)) { num = num7; targetBoat = val; hitPoint = (flag ? val4 : ((Bounds)(ref bounds)).center); } } } return (Object)(object)targetBoat != (Object)null; } private static bool TryGetBoatWorldBounds(Boat boat, out Bounds bounds) { //IL_0002: 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_0095: 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_013e: Unknown result type (might be due to invalid IL or missing references) //IL_012b: 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) bounds = default(Bounds); if ((Object)(object)boat == (Object)null) { return false; } bool flag = false; Renderer[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } if (array != null) { foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && val.enabled && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { if (!flag) { bounds = val.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } } } } if (flag) { return true; } Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(boat); if (managerColliders == null) { return false; } foreach (Collider val2 in managerColliders) { if (!((Object)(object)val2 == (Object)null) && val2.enabled) { if (!flag) { bounds = val2.bounds; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val2.bounds); } } } return flag; } private static void ApplyAttackToBoat(Boat targetBoat, Vector3 hitPoint, object damageSource, bool meleeLike) { //IL_0080: 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_0091: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)targetBoat == (Object)null) && (!RecentDirectShots.TryGetValue(targetBoat, out var value) || !(Time.unscaledTime - value < 0.055f))) { RecentDirectShots[targetBoat] = Time.unscaledTime; float num = ResolveRealDamageDeep(damageSource, meleeLike ? 0f : 250f); if (ApplyDamage(targetBoat, num)) { BoatNativeHitFeedbackRouting.Show(hitPoint, num, IsSinking(targetBoat)); } if (!BoatNativeAttackBridge.TryShowNativeDamageText(hitPoint, num)) { ShowDamagePopup(hitPoint, num); } } } internal static void HandleExactNativeAttack(object attackSource, object[] arguments, MethodBase originalMethod, bool meleeLike) { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.LocalPlayer; Camera main = Camera.main; if ((Object)(object)localPlayer == (Object)null || (Object)(object)main == (Object)null) { return; } Component val = (Component)(object)(((Object)(object)localPlayer.Holding == (Object)null) ? null : localPlayer.Holding.HeldItem); string text = ((originalMethod == null) ? string.Empty : originalMethod.Name); if ((text == "FindPunchTarget" || text == "PunchInput" || text == "UpdateFist") && !Input.GetMouseButtonDown(0)) { return; } float maximumDistance = (meleeLike ? 3.75f : 300f); Ray val2 = main.ScreenPointToRay(new Vector3((float)Screen.width * 0.5f, (float)Screen.height * 0.5f, 0f)); if (!TryFindBoatNearAimLine(((Ray)(ref val2)).origin, ((Ray)(ref val2)).direction, maximumDistance, out var targetBoat, out var hitPoint)) { return; } if (!TryResolveDamageFromNativeArguments(originalMethod, arguments, out var damage)) { float num = ResolveRealDamageDeep(attackSource, -1f); if (num <= 0f && (Object)(object)val != (Object)null) { num = ResolveRealDamageDeep(val, -1f); } if (num <= 0f) { num = ResolveRealDamageFromPlayerHierarchy(localPlayer); } damage = ((num > 0f) ? num : ((!(_lastObservedNativeCreatureDamage > 0f) || !(Time.unscaledTime - _lastObservedNativeCreatureDamageAt < 1f)) ? (meleeLike ? 0f : 250f) : _lastObservedNativeCreatureDamage)); } ApplyNativeDamagePathToBoat(targetBoat, hitPoint, damage); } private static float ResolveRealDamageFromPlayerHierarchy(Player player) { if ((Object)(object)player == (Object)null) { return -1f; } Component[] componentsInChildren; try { componentsInChildren = ((Component)player).GetComponentsInChildren(true); } catch { return -1f; } if (componentsInChildren == null) { return -1f; } float result = -1f; int num = int.MinValue; foreach (Component val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { Type type = ((object)val).GetType(); string text = type.Name.ToLowerInvariant(); int num2 = ((text.Contains("shoot") || text.Contains("gun") || text.Contains("weapon")) ? 50 : ((text.Contains("punch") || text.Contains("melee")) ? 30 : 0)); if (TryReadDamageValue(val, out var damage) && num2 > num) { num = num2; result = damage; } } } return result; } internal static void HandleCreatureProxyHit(Boat boat, Creature proxy, object[] arguments, MethodBase originalMethod) { //IL_0113: 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_018d: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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_0187: 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) if ((Object)(object)boat == (Object)null || (Object)(object)proxy == (Object)null || IsSinking(boat)) { return; } if (!TryResolveDamageFromNativeArguments(originalMethod, arguments, out var damage)) { Player localPlayer = Player.LocalPlayer; Component val = (Component)(object)(((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer.Holding == (Object)null) ? null : localPlayer.Holding.HeldItem); damage = ResolveRealDamageDeep(((Object)(object)val != (Object)null) ? ((object)val) : ((object)localPlayer), -1f); if (damage <= 0f && (Object)(object)localPlayer != (Object)null) { damage = ResolveRealDamageFromPlayerHierarchy(localPlayer); } if (damage <= 0f && _lastObservedNativeCreatureDamage > 0f && Time.unscaledTime - _lastObservedNativeCreatureDamageAt < 1f) { damage = _lastObservedNativeCreatureDamage; } if (damage <= 0f) { damage = (((Object)(object)val == (Object)null) ? 0f : 250f); } } Vector3 hitPoint = ((Component)proxy).transform.position; Camera main = Camera.main; if ((Object)(object)main != (Object)null) { Ray val2 = main.ScreenPointToRay(new Vector3((float)Screen.width * 0.5f, (float)Screen.height * 0.5f, 0f)); if (TryFindBoatNearAimLine(((Ray)(ref val2)).origin, ((Ray)(ref val2)).direction, 300f, out var targetBoat, out var hitPoint2) && (Object)(object)targetBoat == (Object)(object)boat) { hitPoint = hitPoint2; } } ApplyNativeDamagePathToBoat(boat, hitPoint, damage); } internal static void ObserveNativeCreatureHit(Creature creature, object[] arguments, MethodBase originalMethod) { if (!((Object)(object)creature == (Object)null) && !BoatCreatureProxyRouting.IsProxy(creature) && TryResolveDamageFromNativeArguments(originalMethod, arguments, out var damage)) { _lastObservedNativeCreatureDamage = damage; _lastObservedNativeCreatureDamageAt = Time.unscaledTime; } } internal static void HandleCreatureDamagePathAttack(object attackSource, object[] arguments, MethodBase originalMethod) { //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: 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_0137: 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) Player localPlayer = Player.LocalPlayer; Camera main = Camera.main; if ((Object)(object)localPlayer == (Object)null || (Object)(object)main == (Object)null) { return; } Component val = (Component)(object)(((Object)(object)localPlayer.Holding == (Object)null) ? null : localPlayer.Holding.HeldItem); bool flag = (Object)(object)val == (Object)null; if (originalMethod != null) { string text = ((originalMethod.DeclaringType == null) ? string.Empty : originalMethod.DeclaringType.Name); string name = originalMethod.Name; string text2 = (text + " " + name).ToLowerInvariant(); if (text2.Contains("fist") || text2.Contains("punch") || text2.Contains("melee") || text2.Contains("hands") || text2.Contains("kick")) { flag = true; } } float maximumDistance = (flag ? 3.5f : 250f); Ray val2 = main.ScreenPointToRay(new Vector3((float)Screen.width * 0.5f, (float)Screen.height * 0.5f, 0f)); if (TryFindBoatNearAimLine(((Ray)(ref val2)).origin, ((Ray)(ref val2)).direction, maximumDistance, out var targetBoat, out var hitPoint)) { if (!TryResolveDamageFromNativeArguments(originalMethod, arguments, out var damage)) { float num = ResolveRealDamageDeep((attackSource != null) ? attackSource : (((Object)(object)val != (Object)null) ? ((object)val) : ((object)localPlayer)), -1f); damage = ((num > 0f) ? num : ((!(_lastObservedNativeCreatureDamage > 0f) || !(Time.unscaledTime - _lastObservedNativeCreatureDamageAt < 0.75f)) ? (flag ? 0f : 250f) : _lastObservedNativeCreatureDamage)); } ApplyNativeDamagePathToBoat(targetBoat, hitPoint, damage); } } private static void ApplyNativeDamagePathToBoat(Boat targetBoat, Vector3 hitPoint, float damage) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)targetBoat == (Object)null) && !(damage <= 0f) && (!RecentDirectShots.TryGetValue(targetBoat, out var value) || !(Time.unscaledTime - value < 0.045f))) { RecentDirectShots[targetBoat] = Time.unscaledTime; if (ApplyDamage(targetBoat, damage)) { BoatNativeHitFeedbackRouting.Show(hitPoint, damage, IsSinking(targetBoat)); } if (!BoatNativeAttackBridge.TryShowNativeDamageText(hitPoint, damage)) { ShowDamagePopup(hitPoint, damage); } } } private static bool TryResolveDamageFromNativeArguments(MethodBase method, object[] arguments, out float damage) { damage = 0f; if (arguments == null || arguments.Length == 0) { return false; } ParameterInfo[] array = null; try { array = method?.GetParameters(); } catch { array = null; } int num = int.MinValue; float num2 = 0f; for (int i = 0; i < arguments.Length; i++) { object obj2 = arguments[i]; if (obj2 == null) { continue; } string name = ((array != null && i < array.Length && array[i] != null) ? array[i].Name : string.Empty); int nativeDamageParameterScore = GetNativeDamageParameterScore(name); if (nativeDamageParameterScore > 0 && TryConvertPositiveDamage(obj2, out var value) && value <= 100000f && nativeDamageParameterScore > num) { num = nativeDamageParameterScore; num2 = value; } if (TryReadDamageValue(obj2, out var damage2) && damage2 > 0f && damage2 <= 100000f) { int num3 = Math.Max(40, nativeDamageParameterScore); if (num3 > num) { num = num3; num2 = damage2; } } } if (num <= 0 || num2 <= 0f) { return false; } damage = num2; return true; } private static int GetNativeDamageParameterScore(string name) { if (string.IsNullOrEmpty(name)) { return 0; } string text = name.ToLowerInvariant(); if (text == "damage" || text == "dmg") { return 100; } if (text.Contains("damage") || text.Contains("dmg")) { return 90; } if (text.Contains("hitpower") || text.Contains("attackpower") || text.Contains("power")) { return 70; } if (text.Contains("amount") || text.Contains("value")) { return 35; } return 0; } internal static void HandleNativeAttack(object attackSource, bool meleeLike) { //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_008a: 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_0095: 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) Player localPlayer = Player.LocalPlayer; Camera main = Camera.main; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)main == (Object)null)) { Component val = (Component)(object)(((Object)(object)localPlayer.Holding == (Object)null) ? null : localPlayer.Holding.HeldItem); float maximumDistance = ((meleeLike || (Object)(object)val == (Object)null) ? 3.5f : 250f); Ray val2 = main.ScreenPointToRay(new Vector3((float)Screen.width * 0.5f, (float)Screen.height * 0.5f, 0f)); if (TryFindBoatNearAimLine(((Ray)(ref val2)).origin, ((Ray)(ref val2)).direction, maximumDistance, out var targetBoat, out var hitPoint)) { ApplyAttackToBoat(targetBoat, hitPoint, (attackSource != null) ? attackSource : (((Object)(object)val != (Object)null) ? ((object)val) : ((object)localPlayer)), meleeLike || (Object)(object)val == (Object)null); } } } private static bool TryFindAimedBoat(Ray ray, float maximumDistance, out Boat targetBoat, out Vector3 hitPoint) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_009d: Unknown result type (might be due to invalid IL or missing references) targetBoat = null; hitPoint = Vector3.zero; Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); float maximumDistance2 = maximumDistance; foreach (Boat val in array) { if (!((Object)(object)val == (Object)null) && ((NetworkBehaviour)val).IsSpawned && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { DamageState damageState = EnsureBoat(val); if ((damageState == null || !damageState.Sinking) && TryIntersectBoatVisualBounds(val, ray, maximumDistance2, out var distance, out var hitPoint2)) { maximumDistance2 = distance; targetBoat = val; hitPoint = hitPoint2; } } } return (Object)(object)targetBoat != (Object)null; } private static bool TryIntersectBoatVisualBounds(Boat boat, Ray ray, float maximumDistance, out float distance, out Vector3 hitPoint) { //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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_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_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) distance = maximumDistance; hitPoint = Vector3.zero; bool flag = false; Renderer[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } Bounds bounds; if (array != null) { float num = default(float); foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && val.enabled && !((Object)(object)((Component)val).gameObject == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { bounds = val.bounds; if (((Bounds)(ref bounds)).IntersectRay(ray, ref num) && !(num < 0f) && !(num > distance)) { flag = true; distance = num; hitPoint = ((Ray)(ref ray)).GetPoint(num); } } } } Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(boat); if (managerColliders != null) { float num2 = default(float); foreach (Collider val2 in managerColliders) { if (!((Object)(object)val2 == (Object)null) && val2.enabled && !((Object)(object)((Component)val2).gameObject == (Object)null) && ((Component)val2).gameObject.activeInHierarchy) { bounds = val2.bounds; if (((Bounds)(ref bounds)).IntersectRay(ray, ref num2) && !(num2 < 0f) && !(num2 > distance)) { flag = true; distance = num2; hitPoint = ((Ray)(ref ray)).GetPoint(num2); } } } } return flag && distance <= maximumDistance; } private static void ShowDamagePopup(Vector3 worldPosition, float damage, bool lethalHit = false) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_0012: 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) //IL_001d: 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) //IL_0099: 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) GameObject val = new GameObject("Untamo Boat Damage Text"); val.transform.position = worldPosition + Vector3.up * 0.35f; TextMesh val2 = val.AddComponent(); val2.text = Mathf.Max(1, Mathf.RoundToInt(damage)).ToString(CultureInfo.InvariantCulture); val2.anchor = (TextAnchor)4; val2.alignment = (TextAlignment)1; val2.fontSize = 42; val2.characterSize = 0.055f; val2.color = (Color)(lethalHit ? Color.red : new Color(1f, 0.28f, 0.18f, 1f)); val2.fontStyle = (FontStyle)1; MeshRenderer component = val.GetComponent(); if ((Object)(object)component != (Object)null) { ((Renderer)component).sortingOrder = 5000; } BoatDamagePopup boatDamagePopup = val.AddComponent(); boatDamagePopup.Initialize(val2); Object.Destroy((Object)(object)val, 1.05f); } private static DamageState EnsureBoat(Boat boat) { if ((Object)(object)boat == (Object)null || !((NetworkBehaviour)boat).IsSpawned) { return null; } if (!States.TryGetValue(boat, out var value) || value == null) { value = new DamageState(); value.Body = boat.HiddenPhysicsRig ?? ((Component)boat).GetComponentInChildren(); States[boat] = value; } Transform val = (((Object)(object)value.Body != (Object)null) ? ((Component)value.Body).transform : ((Component)boat).transform); BoatDamageReceiver boatDamageReceiver = ((Component)val).GetComponent(); if ((Object)(object)boatDamageReceiver == (Object)null) { boatDamageReceiver = ((Component)val).gameObject.AddComponent(); } boatDamageReceiver.Boat = boat; return value; } private static Rigidbody ResolveBody(Boat boat, DamageState state) { if ((Object)(object)state.Body == (Object)null) { state.Body = boat.HiddenPhysicsRig ?? ((Component)boat).GetComponentInChildren(); } return state.Body; } private static bool ApplyDamage(Boat boat, float amount) { if ((Object)(object)boat == (Object)null || amount <= 0f) { return false; } DamageState damageState = EnsureBoat(boat); if (damageState == null || damageState.Sinking) { return false; } float health = damageState.Health; damageState.Health = Mathf.Max(0f, damageState.Health - amount); bool result = damageState.Health < health; if (damageState.Health <= 0f) { BeginSinking(boat, damageState); } return result; } private static void BeginSinking(Boat boat, DamageState state) { //IL_00d4: 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_0105: 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_0053: 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_007f: 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_0084: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null || state == null || state.Sinking) { return; } state.Health = 0f; state.Sinking = true; state.DeleteAt = Time.unscaledTime + 10f; state.SinkAngularVelocity = new Vector3(0.16f, 0.05f, 0.24f); state.SinkRotation = (((Object)(object)boat.HiddenPhysicsRig != (Object)null) ? boat.HiddenPhysicsRig.rotation : ((Component)boat).transform.rotation); BoatFollowRouting.ClearForBoat(boat); BoatCruiseRouting.DisableForBoat(boat); try { if ((Object)(object)boat.Driver != (Object)null) { boat.TrySetDriver((Player)null); } } catch { } DisableWaterBuoyancy(boat); Rigidbody val = ResolveBody(boat, state); if ((Object)(object)val != (Object)null) { val.linearVelocity = Vector3.zero; val.angularVelocity = Vector3.zero; val.useGravity = false; val.detectCollisions = false; val.isKinematic = true; state.SinkRotation = val.rotation; } } private static void DisableWaterBuoyancy(Boat boat) { if ((Object)(object)boat == (Object)null) { return; } Behaviour[] array; try { array = ((Component)boat).GetComponentsInChildren(true); } catch { array = null; } if (array != null) { foreach (Behaviour val in array) { if ((Object)(object)val == (Object)null || (Object)(object)val == (Object)(object)boat) { continue; } string name = ((object)val).GetType().Name; string value = (((Object)(object)((Component)val).gameObject == (Object)null) ? string.Empty : ((Object)((Component)val).gameObject).name); if (LooksLikeWaterBuoyancyName(name) || LooksLikeWaterBuoyancyName(value)) { try { val.enabled = false; } catch { } } } } Collider[] array2; try { array2 = ((Component)boat).GetComponentsInChildren(true); } catch { array2 = null; } if (array2 == null) { return; } foreach (Collider val2 in array2) { if (!((Object)(object)val2 == (Object)null) && val2.isTrigger) { try { val2.enabled = false; } catch { } } } } private static bool LooksLikeWaterBuoyancyName(string value) { if (string.IsNullOrEmpty(value)) { return false; } string text = value.ToLowerInvariant(); return text.Contains("buoy") || text.Contains("float") || text.Contains("water") || text.Contains("ocean") || text.Contains("sea"); } private static void ProcessExpiredSinkingBoats() { if (States.Count == 0 || (Object)(object)Plugin.Instance == (Object)null || !InstanceFinder.IsServerStarted) { return; } List list = new List(); foreach (KeyValuePair state in States) { Boat key = state.Key; DamageState value = state.Value; if (!((Object)(object)key == (Object)null) && value != null && value.Sinking && Time.unscaledTime >= value.DeleteAt) { list.Add(key); } } for (int i = 0; i < list.Count; i++) { Boat val = list[i]; if (!((Object)(object)val == (Object)null)) { Plugin.Instance.HandleDestroyedBoatAfterSink(val); } } } private static float ResolveRealDamageDeep(object source, float fallback) { if (source == null) { return fallback; } if (TryReadDamageValue(source, out var damage)) { return damage; } Component val = (Component)((source is Component) ? source : null); if ((Object)(object)val != (Object)null) { damage = ResolveRealDamage(val, -1f); if (damage > 0f) { return damage; } } Queue queue = new Queue(); HashSet hashSet = new HashSet(ReferenceEqualityComparer.Instance); queue.Enqueue(source); hashSet.Add(source); int num = 0; while (queue.Count > 0 && num < 96) { object obj = queue.Dequeue(); num++; if (obj == null) { continue; } if (obj != source && TryReadDamageValue(obj, out damage)) { return damage; } Type type = obj.GetType(); FieldInfo[] array; try { array = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { array = null; } if (array != null) { foreach (FieldInfo fieldInfo in array) { if (!(fieldInfo == null) && ShouldInspectNestedDamageMember(fieldInfo.Name, fieldInfo.FieldType)) { object value; try { value = fieldInfo.GetValue(obj); } catch { continue; } if (value != null && !hashSet.Contains(value)) { hashSet.Add(value); queue.Enqueue(value); } } } } PropertyInfo[] array2; try { array2 = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { array2 = null; } if (array2 == null) { continue; } foreach (PropertyInfo propertyInfo in array2) { if (!(propertyInfo == null) && propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0 && ShouldInspectNestedDamageMember(propertyInfo.Name, propertyInfo.PropertyType)) { object value2; try { value2 = propertyInfo.GetValue(obj, null); } catch { continue; } if (value2 != null && !hashSet.Contains(value2)) { hashSet.Add(value2); queue.Enqueue(value2); } } } } return fallback; } private static bool ShouldInspectNestedDamageMember(string memberName, Type memberType) { if (memberType == null || memberType.IsPrimitive || memberType.IsEnum || memberType == typeof(string)) { return false; } if (typeof(Object).IsAssignableFrom(memberType) && !typeof(Component).IsAssignableFrom(memberType) && !typeof(ScriptableObject).IsAssignableFrom(memberType)) { return false; } string text = (string.IsNullOrEmpty(memberName) ? string.Empty : memberName.ToLowerInvariant()); return text.Contains("item") || text.Contains("data") || text.Contains("stat") || text.Contains("config") || text.Contains("weapon") || text.Contains("gun") || text.Contains("ammo") || text.Contains("projectile") || text.Contains("attack") || text.Contains("damage") || text.Contains("definition") || text.Contains("settings"); } private static float ResolveRealDamage(Component source, float fallback) { if ((Object)(object)source == (Object)null) { return fallback; } if (TryReadDamageValue(source, out var damage)) { return damage; } Component[] array; try { array = source.GetComponents(); } catch { array = null; } if (array != null) { foreach (Component val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)source) && TryReadDamageValue(val, out damage)) { return damage; } } } Component[] array2; try { array2 = source.GetComponentsInChildren(true); } catch { array2 = null; } if (array2 != null) { foreach (Component val2 in array2) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)source) && TryReadDamageValue(val2, out damage)) { return damage; } } } Rigidbody val3 = null; Collider val4 = (Collider)(object)((source is Collider) ? source : null); if ((Object)(object)val4 != (Object)null) { val3 = val4.attachedRigidbody; } if ((Object)(object)val3 == (Object)null) { try { val3 = source.GetComponentInParent(); } catch { val3 = null; } } if ((Object)(object)val3 == (Object)null) { try { val3 = source.GetComponent(); } catch { val3 = null; } } if ((Object)(object)val3 != (Object)null) { Component[] array3; try { array3 = ((Component)val3).GetComponentsInChildren(true); } catch { array3 = null; } if (array3 != null) { foreach (Component val5 in array3) { if (!((Object)(object)val5 == (Object)null) && TryReadDamageValue(val5, out damage)) { return damage; } } } } return fallback; } private static bool TryReadDamageValue(object source, out float damage) { damage = 0f; if (source == null) { return false; } Type type = source.GetType(); FieldInfo[] array; try { array = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { array = null; } float num = 0f; int num2 = int.MinValue; if (array != null) { foreach (FieldInfo fieldInfo in array) { if (fieldInfo == null) { continue; } int damageMemberScore = GetDamageMemberScore(fieldInfo.Name); if (damageMemberScore > 0) { object value; try { value = fieldInfo.GetValue(source); } catch { continue; } if (TryConvertPositiveDamage(value, out var value2) && damageMemberScore > num2) { num2 = damageMemberScore; num = value2; } } } } PropertyInfo[] array2; try { array2 = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { array2 = null; } if (array2 != null) { foreach (PropertyInfo propertyInfo in array2) { if (propertyInfo == null || !propertyInfo.CanRead || propertyInfo.GetIndexParameters().Length != 0) { continue; } int damageMemberScore2 = GetDamageMemberScore(propertyInfo.Name); if (damageMemberScore2 > 0) { object value3; try { value3 = propertyInfo.GetValue(source, null); } catch { continue; } if (TryConvertPositiveDamage(value3, out var value4) && damageMemberScore2 > num2) { num2 = damageMemberScore2; num = value4; } } } } if (num2 <= 0 || num <= 0f || float.IsNaN(num) || float.IsInfinity(num)) { return false; } damage = num; return true; } private static int GetDamageMemberScore(string memberName) { if (string.IsNullOrEmpty(memberName)) { return 0; } string text = memberName.ToLowerInvariant().Replace("_", string.Empty).Replace(" ", string.Empty); if (text == "damage" || text == "dmg") { return 100; } switch (text) { default: if (!(text == "directdamage")) { if (text.EndsWith("damage") && !text.Contains("multiplier") && !text.Contains("scale") && !text.Contains("radius") && !text.Contains("falloff")) { return 80; } if ((text.Contains("damage") || text.Contains("dmg")) && !text.Contains("multiplier") && !text.Contains("scale") && !text.Contains("radius") && !text.Contains("falloff") && !text.Contains("received")) { return 60; } return 0; } goto case "projectiledamage"; case "projectiledamage": case "bulletdamage": case "weapondamage": case "hitdamage": case "basedamage": return 95; } } private static bool TryConvertPositiveDamage(object raw, out float value) { value = 0f; if (raw == null) { return false; } try { if (raw is float num) { value = num; } else if (raw is double num2) { value = (float)num2; } else if (raw is int num3) { value = num3; } else if (raw is uint num4) { value = num4; } else if (raw is short num5) { value = num5; } else if (raw is ushort num6) { value = (int)num6; } else if (raw is byte b) { value = (int)b; } else { if (!(raw is long num7) || 1 == 0) { return false; } value = num7; } } catch { return false; } return value > 0f && !float.IsNaN(value) && !float.IsInfinity(value); } private static bool LooksLikeWeapon(Component component) { if ((Object)(object)component == (Object)null) { return false; } if (ContainsWeaponWord(((Object)component).name)) { return true; } Component[] componentsInChildren = component.GetComponentsInChildren(true); foreach (Component val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && (ContainsWeaponWord(((object)val).GetType().Name) || ContainsWeaponWord(((Object)val).name))) { return true; } } return false; } private static bool LooksLikeProjectile(Collider collider) { if ((Object)(object)collider == (Object)null) { return false; } if (ContainsProjectileWord(((Object)collider).name)) { return true; } Transform root = ((Component)collider).transform.root; if ((Object)(object)root != (Object)null && ContainsProjectileWord(((Object)root).name)) { return true; } Component[] componentsInParent = ((Component)collider).GetComponentsInParent(true); foreach (Component val in componentsInParent) { if (!((Object)(object)val == (Object)null) && (ContainsProjectileWord(((object)val).GetType().Name) || ContainsProjectileWord(((Object)val).name))) { return true; } } return false; } private static bool ContainsWeaponWord(string value) { if (string.IsNullOrEmpty(value)) { return false; } string text = value.ToLowerInvariant(); return text.Contains("gun") || text.Contains("weapon") || text.Contains("rifle") || text.Contains("pistol") || text.Contains("shotgun") || text.Contains("revolver") || text.Contains("firearm") || text.Contains("crossbow") || text.Contains("bow") || text.Contains("harpoon"); } private static bool ContainsProjectileWord(string value) { if (string.IsNullOrEmpty(value)) { return false; } string text = value.ToLowerInvariant(); return text.Contains("bullet") || text.Contains("projectile") || text.Contains("pellet") || text.Contains("arrow") || text.Contains("bolt") || text.Contains("harpoon") || text.Contains("ammo") || text.Contains("round") || text.Contains("shell"); } private static int GetImpactIdentity(Collider collider) { if ((Object)(object)collider == (Object)null) { return 0; } Rigidbody attachedRigidbody = collider.attachedRigidbody; if ((Object)(object)attachedRigidbody != (Object)null) { return ((Object)((Component)attachedRigidbody).gameObject).GetInstanceID(); } Transform root = ((Component)collider).transform.root; return ((Object)(object)root != (Object)null) ? ((Object)((Component)root).gameObject).GetInstanceID() : ((Object)((Component)collider).gameObject).GetInstanceID(); } private static void CleanupDeadReferences() { if (States.Count == 0) { return; } List list = new List(); foreach (KeyValuePair state in States) { Boat key = state.Key; if ((Object)(object)key == (Object)null || (Object)(object)((Component)key).gameObject == (Object)null || !((Component)key).gameObject.activeInHierarchy || !((NetworkBehaviour)key).IsSpawned) { list.Add(key); } } for (int i = 0; i < list.Count; i++) { States.Remove(list[i]); } } private static void CleanupImpactDebounce() { if (RecentImpactObjects.Count == 0) { return; } float num = Time.unscaledTime - 2f; List list = new List(); foreach (KeyValuePair recentImpactObject in RecentImpactObjects) { if (recentImpactObject.Value < num) { list.Add(recentImpactObject.Key); } } for (int i = 0; i < list.Count; i++) { RecentImpactObjects.Remove(list[i]); } if (RecentDirectShots.Count <= 0) { return; } List list2 = new List(); foreach (KeyValuePair recentDirectShot in RecentDirectShots) { if ((Object)(object)recentDirectShot.Key == (Object)null || recentDirectShot.Value < num) { list2.Add(recentDirectShot.Key); } } for (int j = 0; j < list2.Count; j++) { RecentDirectShots.Remove(list2[j]); } } } internal static class BoatHitboxRouting { private const string HitboxRootName = "Untamo Stable Boat Hitbox"; private static int _hitboxLayer = -1; private static float _nextRefresh; internal static void Update() { if (Time.unscaledTime < _nextRefresh) { return; } _nextRefresh = Time.unscaledTime + 1f; EnsureDedicatedLayer(); if (_hitboxLayer >= 0) { Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { EnsureStableHitbox(array[i]); } } } private static void EnsureDedicatedLayer() { if (_hitboxLayer >= 0) { return; } for (int num = 31; num >= 8; num--) { if (string.IsNullOrEmpty(LayerMask.LayerToName(num))) { _hitboxLayer = num; break; } } if (_hitboxLayer >= 0) { for (int i = 0; i < 32; i++) { Physics.IgnoreLayerCollision(_hitboxLayer, i, i != _hitboxLayer); } } } private static void EnsureStableHitbox(Boat boat) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_00b8: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_015b: 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) if (!((Object)(object)boat == (Object)null) && ((NetworkBehaviour)boat).IsSpawned) { Transform val = (((Object)(object)boat.HiddenPhysicsRig != (Object)null) ? ((Component)boat.HiddenPhysicsRig).transform : ((Component)boat).transform); Transform val2 = val.Find("Untamo Stable Boat Hitbox"); Bounds bounds; if ((Object)(object)val2 != (Object)null) { ((Component)val2).gameObject.layer = _hitboxLayer; } else if (TryGetNativeColliderBounds(boat, val, out bounds)) { GameObject val3 = new GameObject("Untamo Stable Boat Hitbox"); val3.layer = _hitboxLayer; val3.transform.SetParent(val, false); val3.transform.localPosition = ((Bounds)(ref bounds)).center; val3.transform.localRotation = Quaternion.identity; val3.transform.localScale = Vector3.one; BoxCollider val4 = val3.AddComponent(); Vector3 size = ((Bounds)(ref bounds)).size; size.x *= 0.62f; size.y *= 0.42f; size.z *= 0.68f; val4.size = new Vector3(Mathf.Max(0.65f, size.x), Mathf.Max(0.45f, size.y), Mathf.Max(1.2f, size.z)); val4.center = Vector3.zero; ((Collider)val4).isTrigger = false; } } } private static bool TryGetNativeColliderBounds(Boat boat, Transform physicsRoot, out Bounds bounds) { //IL_0002: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0163: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_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_0093: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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) bounds = default(Bounds); Collider[] managerColliders = BoatInteractionRouting.GetManagerColliders(boat); bool flag = false; Vector3 val = Vector3.zero; Vector3 val2 = Vector3.zero; foreach (Collider val3 in managerColliders) { if ((Object)(object)val3 == (Object)null || !val3.enabled || val3.isTrigger || IsCollisionProxy(((Component)val3).transform)) { continue; } Bounds bounds2 = val3.bounds; Vector3 center = ((Bounds)(ref bounds2)).center; Vector3 extents = ((Bounds)(ref bounds2)).extents; for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { for (int l = -1; l <= 1; l += 2) { Vector3 val4 = center + Vector3.Scale(extents, new Vector3((float)j, (float)k, (float)l)); Vector3 val5 = physicsRoot.InverseTransformPoint(val4); if (!flag) { val = val5; val2 = val5; flag = true; } else { val = Vector3.Min(val, val5); val2 = Vector3.Max(val2, val5); } } } } } if (!flag) { return false; } bounds = new Bounds((val + val2) * 0.5f, val2 - val); return true; } internal static bool IsCollisionProxy(Transform transform) { Transform val = transform; while ((Object)(object)val != (Object)null) { if (((Object)val).name == "Untamo Stable Boat Hitbox" || ((Object)val).name == "Untamo Boat Model Hitboxes" || ((Object)val).name == "Untamo Boat Collision Hitbox") { return true; } val = val.parent; } return false; } } internal static class BoatFollowRouting { private static readonly Dictionary Followers = new Dictionary(StringComparer.Ordinal); private static readonly Dictionary FollowerBodies = new Dictionary(); internal static bool IsSelectedFollower(Boat boat) { if ((Object)(object)boat == (Object)null) { return false; } if (Followers.ContainsValue(boat)) { return true; } return !string.IsNullOrWhiteSpace(((Object)boat).name) && Followers.ContainsKey(((Object)boat).name); } internal static Boat[] GetSelectedFollowers() { ResolveFollowers(); List list = new List(); foreach (KeyValuePair follower in Followers) { Boat value = follower.Value; if ((Object)(object)value != (Object)null && ((NetworkBehaviour)value).IsSpawned && (Object)(object)((Component)value).gameObject != (Object)null && ((Component)value).gameObject.activeInHierarchy) { list.Add(value); } } return list.ToArray(); } internal static void ToggleFollower(Boat boat, ManualLogSource logger) { if ((Object)(object)boat == (Object)null) { if (logger != null) { logger.LogWarning((object)"Follow selection: stand on or next to the boat you want to select."); } return; } if ((Object)(object)boat.Driver != (Object)null) { if (logger != null) { logger.LogWarning((object)"Follow selection: the follower boat must be unattended."); } return; } string text = (string.IsNullOrWhiteSpace(((Object)boat).name) ? ((Object)boat).GetInstanceID().ToString(CultureInfo.InvariantCulture) : ((Object)boat).name); if (IsSelectedFollower(boat)) { string text2 = null; foreach (KeyValuePair follower in Followers) { if ((Object)(object)follower.Value == (Object)(object)boat || string.Equals(follower.Key, text, StringComparison.Ordinal)) { text2 = follower.Key; break; } } if (text2 != null) { Followers.Remove(text2); } FollowerBodies.Remove(boat); if (logger != null) { logger.LogInfo((object)("Follow boat deselected: " + ((Object)boat).name + ".")); } } else { Followers[text] = boat; BoatCruiseRouting.DisableForBoat(boat); if (logger != null) { logger.LogInfo((object)$"Follow boat selected: {((Object)boat).name}. Total followers: {Followers.Count}."); } } } internal static void ClearForBoat(Boat boat) { if ((Object)(object)boat == (Object)null) { return; } string text = null; foreach (KeyValuePair follower in Followers) { if ((Object)(object)follower.Value == (Object)(object)boat || string.Equals(follower.Key, ((Object)boat).name, StringComparison.Ordinal)) { text = follower.Key; break; } } if (text != null) { Followers.Remove(text); } FollowerBodies.Remove(boat); } private static void ResolveFollowers() { if (Followers.Count == 0) { return; } bool flag = false; foreach (KeyValuePair follower in Followers) { Boat value = follower.Value; if ((Object)(object)value == (Object)null || !((NetworkBehaviour)value).IsSpawned || (Object)(object)((Component)value).gameObject == (Object)null || !((Component)value).gameObject.activeInHierarchy) { flag = true; break; } } if (!flag) { return; } Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); string[] array2 = new string[Followers.Count]; Followers.Keys.CopyTo(array2, 0); foreach (string text in array2) { Boat val = Followers[text]; if ((Object)(object)val != (Object)null && ((NetworkBehaviour)val).IsSpawned && (Object)(object)((Component)val).gameObject != (Object)null && ((Component)val).gameObject.activeInHierarchy) { continue; } Followers[text] = null; foreach (Boat val2 in array) { if (!((Object)(object)val2 == (Object)null) && ((NetworkBehaviour)val2).IsSpawned && !((Object)(object)((Component)val2).gameObject == (Object)null) && ((Component)val2).gameObject.activeInHierarchy && string.Equals(((Object)val2).name, text, StringComparison.Ordinal)) { Followers[text] = val2; break; } } } } internal static void Update() { //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_00cd: 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_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_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_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: 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_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0236: 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_024e: 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_0259: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_0457: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_046c: Unknown result type (might be due to invalid IL or missing references) //IL_0473: Unknown result type (might be due to invalid IL or missing references) //IL_047d: Unknown result type (might be due to invalid IL or missing references) //IL_049f: Unknown result type (might be due to invalid IL or missing references) //IL_04a4: Unknown result type (might be due to invalid IL or missing references) //IL_04c6: Unknown result type (might be due to invalid IL or missing references) //IL_04cd: Unknown result type (might be due to invalid IL or missing references) //IL_04d2: Unknown result type (might be due to invalid IL or missing references) //IL_04d6: Unknown result type (might be due to invalid IL or missing references) //IL_04df: Unknown result type (might be due to invalid IL or missing references) //IL_04e9: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: Unknown result type (might be due to invalid IL or missing references) ResolveFollowers(); if (Followers.Count == 0) { return; } Boat val = Plugin.GetLocallyDrivenBoat(); if ((Object)(object)val == (Object)null) { val = BoatCruiseRouting.GetActiveBoat(); } if ((Object)(object)val == (Object)null || !((NetworkBehaviour)val).IsSpawned || !InstanceFinder.IsServerStarted) { return; } Rigidbody val2 = val.HiddenPhysicsRig; if ((Object)(object)val2 == (Object)null) { val2 = ((Component)val).GetComponentInChildren(); } if ((Object)(object)val2 == (Object)null) { return; } Vector3 forward = ((Component)val).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f) { forward = Vector3.forward; } ((Vector3)(ref forward)).Normalize(); Vector3 right = ((Component)val).transform.right; right.y = 0f; if (((Vector3)(ref right)).sqrMagnitude < 0.0001f) { right = Vector3.right; } ((Vector3)(ref right)).Normalize(); int num = 0; foreach (KeyValuePair follower in Followers) { Boat value = follower.Value; if ((Object)(object)value == (Object)null || (Object)(object)value == (Object)(object)val || !((NetworkBehaviour)value).IsSpawned || (Object)(object)value.Driver != (Object)null) { num++; continue; } Rigidbody value2 = null; if (!FollowerBodies.TryGetValue(value, out value2) || (Object)(object)value2 == (Object)null) { value2 = value.HiddenPhysicsRig; if ((Object)(object)value2 == (Object)null) { value2 = ((Component)value).GetComponentInChildren(); } if ((Object)(object)value2 != (Object)null) { FollowerBodies[value] = value2; } } if ((Object)(object)value2 == (Object)null || value2.isKinematic) { num++; continue; } float num2 = ((num % 2 == 0) ? (-1f) : 1f); float num3 = 1f + (float)(num / 2); Vector3 val3 = val2.position - forward * (6f + num3 * 3f) + right * num2 * (3.5f + num3 * 1.5f); Vector3 val4 = val3 - value2.position; val4.y = 0f; float magnitude = ((Vector3)(ref val4)).magnitude; if (magnitude < 2.5f) { Vector3 linearVelocity = value2.linearVelocity; linearVelocity.y = 0f; value2.AddForce(-linearVelocity * 1.5f, (ForceMode)5); num++; continue; } Vector3 normalized = ((Vector3)(ref val4)).normalized; Vector3 val5 = ((Component)value2).transform.forward; val5.y = 0f; if (((Vector3)(ref val5)).sqrMagnitude < 0.0001f) { val5 = normalized; } ((Vector3)(ref val5)).Normalize(); float num4 = Vector3.SignedAngle(val5, normalized, Vector3.up); float num5 = Mathf.Clamp(num4 / 30f, -1f, 1f); float num6 = Mathf.Clamp01(Vector3.Dot(val5, normalized)); float num7 = 1f; if (MotorRouting.HasNoMotor(value)) { num7 = 0f; } else if (MotorRouting.HasSuperBigMotor(value)) { num7 = 1.25f; } else if (MotorRouting.HasDualSuperBigMotors(value)) { num7 = 1.5f; } Vector3 linearVelocity2 = val2.linearVelocity; linearVelocity2.y = 0f; float magnitude2 = ((Vector3)(ref linearVelocity2)).magnitude; float throttle = BoatCruiseRouting.GetThrottle(val); float num8 = 12f * throttle; float num9 = Mathf.Max(magnitude2, num8); float num10 = ((magnitude > 45f) ? 3.5f : ((magnitude > 25f) ? 2f : ((magnitude > 10f) ? 1f : 0f))); float num11 = num9 + num10; Vector3 linearVelocity3 = value2.linearVelocity; linearVelocity3.y = 0f; float num12 = num11 - ((Vector3)(ref linearVelocity3)).magnitude; float num13 = Mathf.Clamp(num12 * 1.8f, -4f, 6f) * num7 * Mathf.Lerp(0.45f, 1f, num6); value2.AddForce(((Component)value2).transform.forward * num13, (ForceMode)5); value2.AddTorque(Vector3.up * num5 * 1.8f, (ForceMode)5); float num14 = Mathf.Max(num11 + 1.5f, 2f); Vector3 linearVelocity4 = value2.linearVelocity; linearVelocity4.y = 0f; if (((Vector3)(ref linearVelocity4)).magnitude > num14) { Vector3 val6 = ((Vector3)(ref linearVelocity4)).normalized * num14; value2.linearVelocity = new Vector3(val6.x, value2.linearVelocity.y, val6.z); } value2.WakeUp(); num++; } } } internal static class BoatCruiseRouting { private static Boat _boat; private static bool _enabled; private static float _heldThrottle; private static float _smoothedThrottle; private static float _lastRawThrottle; private static float _preferredThrottle = 1f; private static Action _persistThrottle; private static Vector3 _heldHeading; private static float _lastManualSteerTime = -10f; private static readonly FieldInfo CurrentMotorField = AccessTools.Field(typeof(Boat), "_curMotor"); private static readonly HashSet AutopilotStartedAudio = new HashSet(); private static Boat _cachedAudioBoat; private static GameObject _cachedAudioMotorObject; private static AudioSource[] _cachedAutopilotAudio = Array.Empty(); private static float _nextAutopilotAudioRefresh; internal static void ConfigurePersistence(float savedThrottle, Action persistThrottle) { _preferredThrottle = Mathf.Round(Mathf.Clamp(savedThrottle, 0f, 2f) * 10f) * 0.1f; _persistThrottle = persistThrottle; } internal static bool EnabledFor(Boat boat) { return _enabled && (Object)(object)boat != (Object)null && (Object)(object)_boat == (Object)(object)boat; } internal static Boat GetActiveBoat() { if (!_enabled || (Object)(object)_boat == (Object)null || !((NetworkBehaviour)_boat).IsSpawned || (Object)(object)((Component)_boat).gameObject == (Object)null || !((Component)_boat).gameObject.activeInHierarchy) { return null; } return _boat; } internal static void Toggle(Boat boat, ManualLogSource logger) { //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boat == (Object)null) { return; } if (_enabled && (Object)(object)_boat == (Object)(object)boat) { _preferredThrottle = Mathf.Round(Mathf.Clamp(_heldThrottle, 0f, 2f) * 10f) * 0.1f; _persistThrottle?.Invoke(_preferredThrottle); _enabled = false; _boat = null; StopAutopilotMotorSound(); _heldThrottle = 0f; _smoothedThrottle = 0f; _heldHeading = Vector3.zero; _lastManualSteerTime = -10f; if (logger != null) { logger.LogInfo((object)"Cruise control disabled."); } return; } float preferredThrottle = _preferredThrottle; _boat = boat; _heldThrottle = Mathf.Round(Mathf.Clamp(Mathf.Abs(preferredThrottle), 0f, 2f) * 10f) * 0.1f; _preferredThrottle = _heldThrottle; _smoothedThrottle = (((Object)(object)boat.Driver == (Object)(object)Player.LocalPlayer) ? Mathf.Clamp(Mathf.Abs(_lastRawThrottle), 0f, 2f) : 0f); _heldHeading = ((Component)boat).transform.forward; _heldHeading.y = 0f; if (((Vector3)(ref _heldHeading)).sqrMagnitude < 0.0001f) { _heldHeading = Vector3.forward; } ((Vector3)(ref _heldHeading)).Normalize(); _lastManualSteerTime = -10f; _enabled = true; _persistThrottle?.Invoke(_preferredThrottle); if (logger != null) { logger.LogInfo((object)$"Cruise control enabled at {_heldThrottle:0.##} throttle."); } } internal static string GetStateText(Boat boat) { return EnabledFor(boat) ? "On" : "Off"; } internal static void AdjustThrottle(Boat boat, float delta) { if (_enabled && !((Object)(object)boat == (Object)null) && !((Object)(object)_boat != (Object)(object)boat)) { _heldThrottle = Mathf.Round(Mathf.Clamp(_heldThrottle + delta, 0f, 2f) * 10f) * 0.1f; _preferredThrottle = _heldThrottle; _persistThrottle?.Invoke(_preferredThrottle); } } internal static string GetThrottleText(Boat boat) { if (!EnabledFor(boat)) { return "0.0"; } return Mathf.Clamp(_heldThrottle, 0f, 2f).ToString("0.0"); } internal static float GetThrottle(Boat boat) { if (!EnabledFor(boat)) { return 0f; } return Mathf.Clamp(_heldThrottle, 0f, 2f); } internal static void AdjustAutopilotHeading(Boat boat, float degrees) { //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_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_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_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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) if (_enabled && !((Object)(object)boat == (Object)null) && !((Object)(object)_boat != (Object)(object)boat) && !((Object)(object)_boat.Driver != (Object)null) && !Mathf.Approximately(degrees, 0f)) { Vector3 val = _heldHeading; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { val = ((Component)_boat).transform.forward; } val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { val = Vector3.forward; } ((Vector3)(ref val)).Normalize(); _heldHeading = Quaternion.AngleAxis(degrees, Vector3.up) * val; _heldHeading.y = 0f; ((Vector3)(ref _heldHeading)).Normalize(); } } internal static void DisableForBoat(Boat boat) { //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) if (_enabled && !((Object)(object)boat == (Object)null) && !((Object)(object)_boat != (Object)(object)boat)) { StopAutopilotMotorSound(); _enabled = false; _boat = null; _heldThrottle = 0f; _smoothedThrottle = 0f; _heldHeading = Vector3.zero; } } internal static void ProcessOutgoingInput(Boat boat, ref half horizontal, ref half vertical) { //IL_0002: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_00ff: Unknown result type (might be due to invalid IL or missing references) float lastRawThrottle = Mathf.Clamp(half.op_Implicit(vertical), -1f, 1f); if (!_enabled) { _lastRawThrottle = lastRawThrottle; } else { if ((Object)(object)boat == (Object)null) { return; } if ((Object)(object)boat != (Object)(object)_boat) { _lastRawThrottle = lastRawThrottle; return; } float num = Mathf.Clamp(half.op_Implicit(horizontal), -1f, 1f); if (Mathf.Abs(num) > 0.05f) { _lastManualSteerTime = Time.unscaledTime; } if (Mathf.Abs(num) > 0.05f || Time.unscaledTime - _lastManualSteerTime <= 0.35f) { Vector3 forward = ((Component)boat).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude > 0.0001f) { ((Vector3)(ref forward)).Normalize(); _heldHeading = forward; } } vertical = (half)_heldThrottle; } } internal static void UpdatePersistentCruise() { //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_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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_026a: 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_02b2: 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_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) if (!_enabled || (Object)(object)_boat == (Object)null) { return; } if (!((NetworkBehaviour)_boat).IsSpawned || (Object)(object)((Component)_boat).gameObject == (Object)null || !((Component)_boat).gameObject.activeInHierarchy) { StopAutopilotMotorSound(); _enabled = false; _boat = null; _heldThrottle = 0f; _smoothedThrottle = 0f; _heldHeading = Vector3.zero; } else if ((Object)(object)_boat.Driver != (Object)null) { StopAutopilotMotorSound(); if ((Object)(object)_boat.Driver == (Object)(object)Player.LocalPlayer) { _smoothedThrottle = Mathf.MoveTowards(_smoothedThrottle, _heldThrottle, Time.unscaledDeltaTime / 1.5f * 2f); Vector3 forward = ((Component)_boat).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude > 0.0001f) { ((Vector3)(ref forward)).Normalize(); _heldHeading = forward; } } } else { if (!InstanceFinder.IsServerStarted) { return; } Rigidbody val = _boat.HiddenPhysicsRig; if ((Object)(object)val == (Object)null) { val = ((Component)_boat).GetComponentInChildren(); } if (!((Object)(object)val == (Object)null) && !val.isKinematic) { float num = 1.3333334f; _smoothedThrottle = Mathf.MoveTowards(_smoothedThrottle, _heldThrottle, num * Time.unscaledDeltaTime); float num2 = _smoothedThrottle; if (MotorRouting.HasNoMotor(_boat) || !BoatFuelRouting.HasFuel(_boat)) { num2 = 0f; _smoothedThrottle = 0f; } float num3 = 1f; if (MotorRouting.HasSuperBigMotor(_boat)) { num3 = 1.5f; } else if (MotorRouting.HasDualSuperBigMotors(_boat)) { num3 = 2f; } BoatFuelRouting.RecordThrottle(_boat, Mathf.Abs(num2) * num3); UpdateAutopilotMotorSound(_boat, num2); Vector3 val2 = _heldHeading; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f) { val2 = ((Component)_boat).transform.forward; } ((Vector3)(ref val2)).Normalize(); Vector3 val3 = ((Component)val).transform.forward; val3.y = 0f; if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f) { val3 = val2; } ((Vector3)(ref val3)).Normalize(); float num4 = Vector3.SignedAngle(val3, val2, Vector3.up); float num5 = Mathf.Clamp(num4 / 20f, -1f, 1f); if (num2 < 0f) { num5 = 0f - num5; } float num6 = 5.5f * num3 * Mathf.Abs(num2); if (!Mathf.Approximately(num2, 0f)) { Vector3 val4 = ((num2 > 0f) ? ((Component)val).transform.forward : (-((Component)val).transform.forward)); val.AddForce(val4 * num6, (ForceMode)5); } val.AddTorque(Vector3.up * num5 * 2.5f, (ForceMode)5); float num7 = 12f * num3 * Mathf.Max(1f, Mathf.Clamp(Mathf.Abs(num2), 0f, 2f)); Vector3 linearVelocity = val.linearVelocity; linearVelocity.y = 0f; if (((Vector3)(ref linearVelocity)).magnitude > num7) { Vector3 val5 = ((Vector3)(ref linearVelocity)).normalized * num7; val.linearVelocity = new Vector3(val5.x, val.linearVelocity.y, val5.z); } val.WakeUp(); } } } private static void UpdateAutopilotMotorSound(Boat boat, float throttle) { if ((Object)(object)boat == (Object)null || MotorRouting.HasNoMotor(boat) || Mathf.Abs(throttle) < 0.01f) { StopAutopilotMotorSound(); return; } if ((Object)(object)_cachedAudioBoat != (Object)(object)boat || (Object)(object)_cachedAudioMotorObject == (Object)null || Time.unscaledTime >= _nextAutopilotAudioRefresh) { _nextAutopilotAudioRefresh = Time.unscaledTime + 1f; object obj = CurrentMotorField?.GetValue(boat); GameObject val = (GameObject)((obj is GameObject) ? obj : null); Component val2 = (Component)((obj is Component) ? obj : null); if ((Object)(object)val == (Object)null && (Object)(object)val2 != (Object)null) { val = val2.gameObject; } if ((Object)(object)_cachedAudioBoat != (Object)(object)boat || (Object)(object)_cachedAudioMotorObject != (Object)(object)val) { _cachedAudioBoat = boat; _cachedAudioMotorObject = val; _cachedAutopilotAudio = (((Object)(object)val == (Object)null) ? Array.Empty() : val.GetComponentsInChildren(true)); } } AudioSource[] cachedAutopilotAudio = _cachedAutopilotAudio; if (cachedAutopilotAudio == null || cachedAutopilotAudio.Length == 0) { return; } float num = Mathf.Clamp01(Mathf.Abs(throttle) / 2f); foreach (AudioSource val3 in cachedAutopilotAudio) { if ((Object)(object)val3 == (Object)null || (Object)(object)val3.clip == (Object)null) { continue; } if (!((Behaviour)val3).enabled) { ((Behaviour)val3).enabled = true; } if (((Component)val3).gameObject.activeInHierarchy) { if (!val3.isPlaying) { val3.loop = true; val3.Play(); AutopilotStartedAudio.Add(val3); } val3.pitch = Mathf.Lerp(0.85f, 1.2f, num); if (val3.volume <= 0.01f) { val3.volume = 1f; } } } } private static void StopAutopilotMotorSound() { if (AutopilotStartedAudio.Count == 0) { return; } AudioSource[] array = (AudioSource[])(object)new AudioSource[AutopilotStartedAudio.Count]; AutopilotStartedAudio.CopyTo(array); AutopilotStartedAudio.Clear(); _cachedAudioBoat = null; _cachedAudioMotorObject = null; _cachedAutopilotAudio = Array.Empty(); _nextAutopilotAudioRefresh = 0f; foreach (AudioSource val in array) { if (!((Object)(object)val == (Object)null)) { try { val.Stop(); } catch { } } } } private static float ReadKeyboardThrottle() { bool flag = Input.GetKey((KeyCode)119) || Input.GetKey((KeyCode)273); bool flag2 = Input.GetKey((KeyCode)115) || Input.GetKey((KeyCode)274); if (flag == flag2) { return 0f; } return flag ? 1f : (-1f); } } internal static class BoatBoostRouting { internal static float SelectedMultiplier = 1.25f; internal const float PacketStep = 100f; internal static void Stabilize(Boat boat, float multiplier) { //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_0054: 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_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_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_00b2: 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_00d3: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)boat == (Object)null)) { Rigidbody val = boat.HiddenPhysicsRig; if ((Object)(object)val == (Object)null) { val = ((Component)boat).GetComponentInChildren(); } if (!((Object)(object)val == (Object)null)) { Vector3 val2 = ((Component)val).transform.InverseTransformDirection(val.angularVelocity); val2.x = Mathf.Clamp(val2.x, -0.45f, 0.45f); val2.z = Mathf.Clamp(val2.z, -0.45f, 0.45f); val.angularVelocity = ((Component)val).transform.TransformDirection(val2); Vector3 val3 = Vector3.Cross(((Component)val).transform.up, Vector3.up); float num = Mathf.Lerp(6f, 18f, (multiplier - 1.25f) / 3.75f); val.AddTorque(val3 * num, (ForceMode)5); } } } } internal static class BoatHuntingBonusRouting { internal static Creature ActiveCreature; internal static bool IsOnBoat() { if ((Object)(object)Plugin.GetLocallyDrivenBoat() != (Object)null) { return true; } Player localPlayer = Player.LocalPlayer; return (Object)(object)localPlayer != (Object)null && (Object)(object)BoatClosestPhysicsRouting.GetContextBoatNearPlayer(localPlayer, 2.5f) != (Object)null; } internal static bool IsBonusCreature(Creature creature) { return (Object)(object)creature != (Object)null; } } internal sealed class BoatFishValueBonus : MonoBehaviour { } [HarmonyPatch(typeof(Creature), "LocalHit")] internal static class BoatCreatureProxyLocalHitPatch { private static bool Prefix(Creature __instance, object[] __args, MethodBase __originalMethod) { if (!BoatCreatureProxyRouting.TryGetBoat(__instance, out var boat)) { return true; } BoatDamageRouting.HandleCreatureProxyHit(boat, __instance, __args, __originalMethod); return false; } } [HarmonyPatch(typeof(Creature), "LocalHit")] internal static class BoatNativeCreatureHitProbePatch { private static void Prefix(Creature __instance, object[] __args, MethodBase __originalMethod) { BoatDamageRouting.ObserveNativeCreatureHit(__instance, __args, __originalMethod); } } [HarmonyPatch(typeof(Creature), "LocalHit")] internal static class BoatHuntingCatchContextPatch { private static void Prefix(Creature __instance) { if (BoatCreatureProxyRouting.IsProxy(__instance)) { BoatHuntingBonusRouting.ActiveCreature = null; } else { BoatHuntingBonusRouting.ActiveCreature = ((BoatHuntingBonusRouting.IsOnBoat() && BoatHuntingBonusRouting.IsBonusCreature(__instance)) ? __instance : null); } } private static void Postfix() { BoatHuntingBonusRouting.ActiveCreature = null; } } [HarmonyPatch(typeof(PlayerKillScore), "AddKillScore")] internal static class BoatHuntingScoreBonusPatch { private static void Prefix(ref int __1) { Creature activeCreature = BoatHuntingBonusRouting.ActiveCreature; if (!((Object)(object)activeCreature == (Object)null)) { __1 *= 3; Fish val = (Fish)(object)((activeCreature is Fish) ? activeCreature : null); if ((Object)(object)val != (Object)null && (Object)(object)((Component)val).GetComponent() == (Object)null) { ((Component)val).gameObject.AddComponent(); } } } } [HarmonyPatch(typeof(MoneyManager), "SellItem")] internal static class BoatFishMoneyBonusPatch { private static void Prefix(Item __0, out int __state) { __state = ((__0 is Fish && (Object)(object)((Component)__0).GetComponent() != (Object)null) ? (__0.TotalWorth * 2) : 0); } private static void Postfix(int __state) { if (__state > 0) { MoneyManager.AddMoney(__state, (Player)null); } } } [HarmonyPatch(typeof(PlayerHolding), "MoveItemToHoldPosRot")] internal static class BoatHeldItemFollowPatch { private static readonly FieldInfo PlayerField = AccessTools.Field(typeof(PlayerHolding), "_player"); private static readonly Func TargetPosition = (Func)Delegate.CreateDelegate(typeof(Func), AccessTools.Method(typeof(PlayerHolding), "CalculateHoldTargetPos", (Type[])null, (Type[])null)); private static readonly Func TargetRotation = (Func)Delegate.CreateDelegate(typeof(Func), AccessTools.Method(typeof(PlayerHolding), "CalculateHoldTargetRot", (Type[])null, (Type[])null)); private static bool Prefix(PlayerHolding __instance) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_00e2: 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_00f8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.HeldItem == (Object)null) { return true; } object? obj = PlayerField?.GetValue(__instance); Player val = (Player)((obj is Player) ? obj : null); Boat val2 = null; Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null && (Object)(object)array[i].Driver == (Object)(object)val) { val2 = array[i]; break; } } if ((Object)(object)val2 == (Object)null) { return true; } Rigidbody rig = __instance.HeldItem.Rig; if ((Object)(object)rig == (Object)null) { return true; } Vector3 position = TargetPosition(__instance); Quaternion rotation = TargetRotation(__instance); rig.position = position; rig.rotation = rotation; rig.linearVelocity = val2.Velocity; rig.angularVelocity = Vector3.zero; return false; } } [HarmonyPatch(typeof(PlayerHolding), "ChangeSkinInput")] internal static class BoatOnlySkinInputPatch { private static readonly FieldInfo PlayerField = AccessTools.Field(typeof(PlayerHolding), "_player"); private static bool Prefix(PlayerHolding __instance) { Player val = (Player)(((Object)(object)__instance == (Object)null) ? null : /*isinst with value type is only supported in some contexts*/); if ((Object)(object)val == (Object)null) { return true; } Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); for (int i = 0; i < array.Length; i++) { if ((Object)(object)array[i] != (Object)null && (Object)(object)array[i].Driver == (Object)(object)val) { return false; } } return true; } } [HarmonyPatch(typeof(Server), "RpcLogic___SetBoatSkin___1246646286")] internal static class BoatSkinLogicRoutingPatch { private static bool Prefix(byte __0) { Boat locallyDrivenBoat = Plugin.GetLocallyDrivenBoat(); if ((Object)(object)locallyDrivenBoat == (Object)null) { return true; } if (__0 == 239) { BoatCommandRouting.ResetToDefaultSpawn(locallyDrivenBoat); return false; } if (MotorRouting.IsMotorRequest(__0)) { MotorRouting.ApplyMotor(locallyDrivenBoat, MotorRouting.DecodeMotorRequest(__0)); return false; } BoatSkinRouting.ApplySkin(locallyDrivenBoat, __0); return false; } } [HarmonyPatch(typeof(Server), "RpcReader___SetBoatSkin___1246646286")] internal static class BoatSkinReaderRoutingPatch { private static bool Prefix(PooledReader __0, NetworkConnection __2) { if (__0 == null) { return false; } byte b = ((Reader)__0).ReadUInt8Unpacked(); Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Boat val in array) { Player val2 = (((Object)(object)val == (Object)null) ? null : val.Driver); bool num; if (!(__2 != (NetworkConnection)null)) { if (!((Object)(object)val2 != (Object)null)) { continue; } num = (Object)(object)val2 == (Object)(object)Player.LocalPlayer; } else { if (!((Object)(object)val2 != (Object)null)) { continue; } num = object.Equals(((NetworkBehaviour)val2).Owner, __2); } if (!num) { continue; } if (b == 239) { BoatCommandRouting.ResetToDefaultSpawn(val); } else if (MotorRouting.IsMotorRequest(b)) { MotorRouting.ApplyMotor(val, MotorRouting.DecodeMotorRequest(b)); } else { BoatSkinRouting.ApplySkin(val, b); } break; } return false; } } [HarmonyPatch(typeof(Boat), "OnSkinChange")] internal static class BoatSkinColliderRefreshPatch { private static void Postfix(Boat __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.Driver != (Object)(object)Player.LocalPlayer)) { BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(__instance), __instance); } } } [HarmonyPatch(typeof(PlayerHands), "CurrentHandTransforms")] internal static class BoatHeldItemHandsPatch { private static readonly PropertyInfo DrivenBoatProperty = AccessTools.Property(typeof(PlayerHands), "_drivenBoat"); private static readonly PropertyInfo HeldItemProperty = AccessTools.Property(typeof(PlayerHands), "_heldItem"); private static bool Prefix(PlayerHands __instance, bool __0, ref HandTransforms __result) { if ((Object)(object)__instance == (Object)null) { return true; } object? obj = DrivenBoatProperty?.GetValue(__instance, null); Boat val = (Boat)((obj is Boat) ? obj : null); object? obj2 = HeldItemProperty?.GetValue(__instance, null); Item val2 = (Item)((obj2 is Item) ? obj2 : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return true; } __result = (__0 ? val2.HandTransformsRight : val2.HandTransformsLeft); return false; } } internal static class BoatManagerContactGuard { private static Boat _explicitTarget; private static int _explicitUntilFrame; internal static void AllowExplicitSwitch(Boat boat) { _explicitTarget = boat; _explicitUntilFrame = Time.frameCount + 30; } internal static bool IsExplicitSwitchAllowed(Boat boat) { if ((Object)(object)boat == (Object)null || (Object)(object)_explicitTarget == (Object)null || Time.frameCount > _explicitUntilFrame) { if (Time.frameCount > _explicitUntilFrame) { _explicitTarget = null; } return false; } return (Object)(object)boat == (Object)(object)_explicitTarget; } internal static void ClearAllExplicitSwitches() { _explicitTarget = null; _explicitUntilFrame = 0; } internal static void ClearExplicitSwitch(Boat boat) { if ((Object)(object)_explicitTarget == (Object)(object)boat) { _explicitTarget = null; _explicitUntilFrame = 0; } } } [HarmonyPatch(typeof(BoatManager), "SetBoat")] internal static class BoatManagerSetBoatContactGuardPatch { private static bool Prefix(Boat __1) { if ((Object)(object)__1 == (Object)null) { return true; } Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer == (Object)null) { return true; } Boat locallyDrivenBoat = Plugin.GetLocallyDrivenBoat(); if ((Object)(object)locallyDrivenBoat != (Object)null) { if ((Object)(object)__1 == (Object)(object)locallyDrivenBoat) { return true; } return BoatManagerContactGuard.IsExplicitSwitchAllowed(__1); } return true; } } [HarmonyPatch(typeof(BoatInteractable), "Interact")] internal static class BoatInteractablePatch { private static void Prefix(BoatInteractable __instance) { if (!((Object)(object)__instance == (Object)null)) { Boat componentInParent = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { BoatManagerContactGuard.AllowExplicitSwitch(componentInParent); BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(componentInParent), componentInParent); } } } } [HarmonyPatch(typeof(Boat), "TrySetDriver")] internal static class BoatHeldItemDriverPatch { private static bool Prefix(Boat __instance, Player __0) { if ((Object)(object)__instance != (Object)null && (Object)(object)__0 == (Object)null && (Object)(object)Player.LocalPlayer != (Object)null && (Object)(object)__instance.Driver == (Object)(object)Player.LocalPlayer && Input.GetKey((KeyCode)113)) { return false; } return true; } private static void Postfix(Boat __instance, Player __0) { Plugin.InvalidateDrivenBoatCache(); if ((Object)(object)__instance == (Object)null) { return; } if ((Object)(object)__0 == (Object)null) { if (BoatCruiseRouting.EnabledFor(__instance)) { BoatCruiseRouting.UpdatePersistentCruise(); } else { Plugin.StopBoatInputAndMotion(__instance, stopMotion: false); } } else if (!((Object)(object)__0 != (Object)(object)Player.LocalPlayer)) { if ((Object)(object)__instance.Driver == (Object)(object)__0 && (Object)(object)BoatManager.Instance != (Object)null) { BoatManager.SetBoat(BoatInteractionRouting.GetManagerColliders(__instance), __instance); } BoatManagerContactGuard.ClearExplicitSwitch(__instance); } } } [HarmonyPatch(typeof(BoatInteractable), "Hover")] internal static class BoatInteractableHoverPatch { private static bool Prefix(BoatInteractable __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)((Component)__instance).gameObject == (Object)null || !((Component)__instance).gameObject.activeInHierarchy) { return false; } Boat componentInParent = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null || (Object)(object)((Component)componentInParent).gameObject == (Object)null || !((Component)componentInParent).gameObject.activeInHierarchy) { return false; } if (BoatInteractionRouting.IsLocalClosestInteractBoat(componentInParent)) { return true; } return true; } } [HarmonyPatch(typeof(Server), "RpcReader___SendBoatInput___1949707525")] internal static class BoatInputRpcPatch { private static bool Prefix(PooledReader __0, NetworkConnection __2) { //IL_0015: 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_003d: 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_0099: 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_00bd: 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_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: 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_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: 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_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) if (__0 == null) { return false; } half val = new half { value = ((Reader)__0).ReadUInt16() }; half val2 = new half { value = ((Reader)__0).ReadUInt16() }; float num = half.op_Implicit(val); bool flag = num >= 100f; float num2 = 1f; if (flag) { num2 = Mathf.Clamp(Mathf.Round(num / 100f * 4f) * 0.25f, 1.25f, 5f); val = (half)(num - num2 * 100f); if (!Mathf.Approximately(half.op_Implicit(val2), 0f)) { val2 = (half)(half.op_Implicit(val2) * num2); } } Boat[] array = Object.FindObjectsByType((FindObjectsSortMode)0); foreach (Boat val3 in array) { Player val4 = (((Object)(object)val3 == (Object)null) ? null : val3.Driver); bool num3; if (!(__2 != (NetworkConnection)null)) { if (!((Object)(object)val4 != (Object)null)) { continue; } num3 = (Object)(object)val4 == (Object)(object)Player.LocalPlayer; } else { if (!((Object)(object)val4 != (Object)null)) { continue; } num3 = object.Equals(((NetworkBehaviour)val4).Owner, __2); } if (num3) { if (MotorRouting.HasNoMotor(val3) || !BoatFuelRouting.HasFuel(val3)) { val2 = (half)0f; } else if (MotorRouting.HasSuperBigMotor(val3)) { val2 = (half)(half.op_Implicit(val2) * 1.5f); } else if (MotorRouting.HasDualSuperBigMotors(val3)) { val2 = (half)(half.op_Implicit(val2) * 2f); } float num4 = Mathf.Abs(half.op_Implicit(val2)); if (flag && num2 > 0f) { num4 /= num2; } BoatFuelRouting.RecordThrottle(val3, num4, flag ? num2 : 1f); val3.ServerSetInput(val, val2); if (flag && !Mathf.Approximately(half.op_Implicit(val2), 0f)) { BoatBoostRouting.Stabilize(val3, num2); } break; } } return false; } } [HarmonyPatch(typeof(Server), "RpcWriter___SendBoatInput___1949707525")] internal static class BoatInputWriterPatch { private static void Prefix(ref half __0, ref half __1) { //IL_0030: 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) Boat locallyDrivenBoat = Plugin.GetLocallyDrivenBoat(); BoatCruiseRouting.ProcessOutgoingInput(locallyDrivenBoat, ref __0, ref __1); if (Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)) { __0 = (half)(half.op_Implicit(__0) + BoatBoostRouting.SelectedMultiplier * 100f); } } } [HarmonyPatch(typeof(SaveManager), "SaveServer", new Type[] { typeof(bool) })] internal static class SaveServerBoatNullPatch { private static readonly MethodInfo BoatUnlockedGetter = AccessTools.PropertyGetter(typeof(Boat), "BoatUnlocked"); private static readonly MethodInfo BoatRadarUnlockedGetter = AccessTools.PropertyGetter(typeof(Boat), "BoatRadarUnlocked"); private static readonly MethodInfo MotorIndexGetter = AccessTools.PropertyGetter(typeof(Boat), "MotorIndex"); private static readonly MethodInfo CurSkinGetter = AccessTools.PropertyGetter(typeof(Boat), "CurSkin"); private static IEnumerable Transpiler(IEnumerable instructions) { foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, BoatUnlockedGetter)) { instruction.opcode = OpCodes.Call; instruction.operand = AccessTools.Method(typeof(SaveServerBoatNullPatch), "GetBoatUnlocked", (Type[])null, (Type[])null); } else if (CodeInstructionExtensions.Calls(instruction, BoatRadarUnlockedGetter)) { instruction.opcode = OpCodes.Call; instruction.operand = AccessTools.Method(typeof(SaveServerBoatNullPatch), "GetBoatRadarUnlocked", (Type[])null, (Type[])null); } else if (CodeInstructionExtensions.Calls(instruction, MotorIndexGetter)) { instruction.opcode = OpCodes.Call; instruction.operand = AccessTools.Method(typeof(SaveServerBoatNullPatch), "GetMotorIndex", (Type[])null, (Type[])null); } else if (CodeInstructionExtensions.Calls(instruction, CurSkinGetter)) { instruction.opcode = OpCodes.Call; instruction.operand = AccessTools.Method(typeof(SaveServerBoatNullPatch), "GetBoatSkin", (Type[])null, (Type[])null); } yield return instruction; } } private static bool GetBoatUnlocked(Boat boat) { return ((Object)(object)boat != (Object)null) ? boat.BoatUnlocked : ReadPreviousSaveValue("UnlockedBoat", fallback: false); } private static bool GetBoatRadarUnlocked(Boat boat) { return ((Object)(object)boat != (Object)null) ? boat.BoatRadarUnlocked : ReadPreviousSaveValue("UnlockedBoatRadar", fallback: false); } private static byte GetMotorIndex(Boat boat) { byte motorIndex = ReadPreviousSaveValue("MotorIndex", (byte)0); MotorRouting.ObservePurchasedMotor(motorIndex); MotorRouting.ObservePurchasedMotor(boat); return MotorRouting.PurchasedMaximum; } private static byte GetBoatSkin(Boat boat) { return ((Object)(object)boat != (Object)null) ? boat.CurSkin : ReadPreviousSaveValue("BoatSkin", (byte)0); } private static T ReadPreviousSaveValue(string fieldName, T fallback) { object obj = AccessTools.Property(typeof(SaveManager), "CurServerSave")?.GetValue(null, null); if (obj == null) { return fallback; } return (AccessTools.Field(obj.GetType(), fieldName)?.GetValue(obj) is T val) ? val : fallback; } } }