using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FishNet;
using FishNet.Broadcast;
using FishNet.Connection;
using FishNet.Serializing;
using FishNet.Transporting;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.Rendering;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("BlirUBoat")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+faaaf265c0d7028c431d7cc2f1491e5751925c20")]
[assembly: AssemblyProduct("BlirUBoat")]
[assembly: AssemblyTitle("BlirUBoat")]
[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 BlirUBoat
{
internal static class BoatProps
{
private struct Placement
{
public Vector3 Position;
public Quaternion Rotation;
}
private const string RootName = "BlirUBoat_Props";
private const float PlankThickness = 0.09f;
private static Mesh _cubeTemplate;
private static Shader _cachedShader;
public static float PlankThicknessMetres => 0.09f;
private static float PlankTopY => 0.09f;
public static void Attach(Boat boat)
{
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008c: Expected O, but got Unknown
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: 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_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)boat == (Object)null)
{
return;
}
Transform val = ResolveVisualRoot(boat);
if ((Object)(object)val == (Object)null)
{
Plugin.Log.LogWarning((object)"Could not resolve the boat's visual root; props not attached.");
return;
}
Transform val2 = val.Find("BlirUBoat_Props");
if ((Object)(object)val2 != (Object)null)
{
Object.Destroy((Object)(object)((Component)val2).gameObject);
}
Placement? placement = FindBowPlacement(boat, val);
if (!placement.HasValue)
{
Plugin.Log.LogWarning((object)"Could not locate the bow; props not attached.");
return;
}
float scale = Mathf.Max(0.1f, ModConfig.PropScale.Value);
GameObject val3 = new GameObject("BlirUBoat_Props");
val3.transform.SetParent(val, false);
val3.transform.localPosition = placement.Value.Position;
val3.transform.localRotation = placement.Value.Rotation;
float num = ResolvePlankWidth(val);
Material material = MakeMaterial(new Color(0.4f, 0.26f, 0.15f));
Material white = MakeMaterial(new Color(0.93f, 0.92f, 0.89f));
Material red = MakeMaterial(new Color(0.7f, 0.08f, 0.1f));
Material tobacco = MakeMaterial(new Color(0.85f, 0.68f, 0.36f));
Material plateMat = MakeMaterial(new Color(0.16f, 0.16f, 0.18f));
Material capMat = MakeMaterial(new Color(0.78f, 0.09f, 0.09f));
BuildPlank(val3.transform, num, material);
Transform buttonCap = BuildButton(val3.transform, num, scale, plateMat, capMat);
BuildPack(val3.transform, num, scale, white, red, tobacco, buttonCap);
BuildLighter(val3.transform, num, scale);
Plugin.Log.LogInfo((object)($"Bow props attached under '{((Object)val).name}' at local {val3.transform.localPosition}, " + $"plank width {num:F2}m."));
}
private static float ResolvePlankWidth(Transform visualRoot)
{
//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_0036: Unknown result type (might be due to invalid IL or missing references)
float value = ModConfig.PlankWidthOverride.Value;
if (value > 0.01f)
{
return value;
}
Bounds? val = ComputeLocalBounds(visualRoot);
float num;
if (!val.HasValue)
{
num = 3f;
}
else
{
Bounds valueOrDefault = val.GetValueOrDefault();
num = ((Bounds)(ref valueOrDefault)).size.z;
}
return num * 0.34f;
}
private static Transform ResolveVisualRoot(Boat boat)
{
if ((Object)(object)boat.VisualBoat != (Object)null)
{
return boat.VisualBoat;
}
if ((Object)(object)boat.VisualPhysicsRig != (Object)null)
{
return ((Component)boat.VisualPhysicsRig).transform;
}
return ((Component)boat).transform;
}
private static Placement? FindBowPlacement(Boat boat, Transform visualRoot)
{
//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_0025: 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_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: 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_0056: 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_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_00ab: 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_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_00e8: 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_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: 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_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: Unknown result type (might be due to invalid IL or missing references)
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_018d: Unknown result type (might be due to invalid IL or missing references)
//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
//IL_01af: Unknown result type (might be due to invalid IL or missing references)
//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
//IL_01be: Unknown result type (might be due to invalid IL or missing references)
Bounds? val = ComputeLocalBounds(visualRoot);
if (!val.HasValue)
{
return null;
}
Bounds value = val.Value;
bool flag = ((Bounds)(ref value)).size.x >= ((Bounds)(ref value)).size.z;
Vector3 val2 = (flag ? Vector3.right : Vector3.forward);
float num = (flag ? ((Bounds)(ref value)).size.x : ((Bounds)(ref value)).size.z) * 0.5f;
Transform val3 = FindPropeller(boat) ?? boat.DriverPos;
if ((Object)(object)val3 != (Object)null)
{
if (Vector3.Dot(visualRoot.InverseTransformPoint(val3.position) - ((Bounds)(ref value)).center, val2) > 0f)
{
val2 = -val2;
}
}
else
{
Plugin.Log.LogWarning((object)"No propeller or driver position found; bow direction is a guess.");
}
Vector3 up = Vector3.up;
Vector3 val4 = Vector3.Cross(up, val2);
Vector3 normalized = ((Vector3)(ref val4)).normalized;
Vector3 val5 = ((Bounds)(ref value)).center + val2 * (num + ModConfig.OffsetForward.Value) + normalized * ModConfig.OffsetSide.Value;
val5.y = ((Bounds)(ref value)).min.y + ((Bounds)(ref value)).size.y * ModConfig.PlankHeightFraction.Value;
Plugin.Log.LogInfo((object)($"Boat bounds center={((Bounds)(ref value)).center} size={((Bounds)(ref value)).size}; forward={val2} " + string.Format("(long axis {0}); props at {1}.", flag ? "X" : "Z", val5)));
return new Placement
{
Position = val5,
Rotation = Quaternion.LookRotation(val2, up)
};
}
private static Transform FindPropeller(Boat boat)
{
if (!(AccessTools.Field(typeof(Boat), "_motors")?.GetValue(boat) is IEnumerable enumerable))
{
return null;
}
foreach (object item in enumerable)
{
BoatMotor val = (BoatMotor)((item is BoatMotor) ? item : null);
if (val != null && (Object)(object)val.Propeller != (Object)null)
{
return val.Propeller;
}
}
return null;
}
private static Bounds? ComputeLocalBounds(Transform visualRoot)
{
//IL_0042: 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_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: 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_0128: 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_0118: Unknown result type (might be due to invalid IL or missing references)
MeshRenderer[] array = (from r in ((Component)visualRoot).GetComponentsInChildren<MeshRenderer>()
where (Object)(object)r != (Object)null && ((Renderer)r).enabled
select r).ToArray();
if (array.Length == 0)
{
return null;
}
bool flag = false;
Bounds value = default(Bounds);
MeshRenderer[] array2 = array;
foreach (MeshRenderer val in array2)
{
MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
if ((Object)(object)component == (Object)null || (Object)(object)component.sharedMesh == (Object)null)
{
continue;
}
Matrix4x4 val2 = visualRoot.worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
Bounds bounds = component.sharedMesh.bounds;
for (int num2 = 0; num2 < 8; num2++)
{
Vector3 val3 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3(((num2 & 1) == 0) ? (-1f) : 1f, ((num2 & 2) == 0) ? (-1f) : 1f, ((num2 & 4) == 0) ? (-1f) : 1f));
Vector3 val4 = ((Matrix4x4)(ref val2)).MultiplyPoint3x4(val3);
if (!flag)
{
((Bounds)(ref value))..ctor(val4, Vector3.zero);
flag = true;
}
else
{
((Bounds)(ref value)).Encapsulate(val4);
}
}
}
if (!flag)
{
return null;
}
return value;
}
private static void BuildPlank(Transform parent, float width, Material material)
{
//IL_0003: 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)
GameObject obj = MakePrimitive((PrimitiveType)3, parent, material, Vector3.one, new Vector3(0f, 0.045f, 0f));
((Object)obj).name = "Plank";
ShapePlank(obj, width, width, ModConfig.PlankLength.Value);
obj.AddComponent<PlankFitter>();
}
public static void ShapePlank(GameObject plank, float widthAft, float widthFore, float depth)
{
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: 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)
MeshFilter component = plank.GetComponent<MeshFilter>();
if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh == (Object)null))
{
if ((Object)(object)_cubeTemplate == (Object)null)
{
_cubeTemplate = component.sharedMesh;
}
Mesh val = Object.Instantiate<Mesh>(_cubeTemplate);
((Object)val).name = "BlirUBoat_Thwart";
Vector3[] vertices = val.vertices;
for (int i = 0; i < vertices.Length; i++)
{
Vector3 val2 = vertices[i];
float num = Mathf.Clamp01(val2.z + 0.5f);
float num2 = Mathf.Lerp(widthAft, widthFore, num);
vertices[i] = new Vector3(val2.x * num2, val2.y * 0.09f, val2.z * depth);
}
val.vertices = vertices;
val.RecalculateNormals();
val.RecalculateBounds();
Mesh sharedMesh = component.sharedMesh;
component.sharedMesh = val;
if ((Object)(object)sharedMesh != (Object)null && ((Object)sharedMesh).name == "BlirUBoat_Thwart")
{
Object.Destroy((Object)(object)sharedMesh);
}
}
}
private static Transform BuildButton(Transform parent, float plankWidth, float scale, Material plateMat, Material capMat)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_002f: 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_0056: 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_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("Button");
val.transform.SetParent(parent, false);
val.transform.localPosition = new Vector3(plankWidth * 0.28f, 0f, 0f);
((Object)MakePrimitive((PrimitiveType)3, val.transform, plateMat, new Vector3(0.095f, 0.018f, 0.095f) * scale, new Vector3(0f, PlankTopY + 0.009f * scale, 0f))).name = "ButtonBase";
GameObject obj = MakePrimitive((PrimitiveType)2, val.transform, capMat, new Vector3(0.055f, 0.006f, 0.055f) * scale, new Vector3(0f, PlankTopY + 0.024f * scale, 0f));
((Object)obj).name = "ButtonCap";
return obj.transform;
}
private static void BuildPack(Transform parent, float plankWidth, float scale, Material white, Material red, Material tobacco, Transform buttonCap)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_0051: 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_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: 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_0154: Unknown result type (might be due to invalid IL or missing references)
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_0282: 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_02a5: 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_02bb: Expected O, but got Unknown
//IL_02d6: Unknown result type (might be due to invalid IL or missing references)
//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
//IL_01df: Unknown result type (might be due to invalid IL or missing references)
//IL_01e5: 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)
//IL_0240: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("CigarettePack");
val.SetActive(false);
val.transform.SetParent(parent, false);
val.layer = LayerMask.NameToLayer("Interactable");
val.tag = "Interactable";
val.transform.localPosition = new Vector3(plankWidth * -0.26f, PlankTopY, 0f);
val.transform.localRotation = Quaternion.Euler(0f, ModConfig.PackYaw.Value, 0f);
float num = 0.049300004f;
float num2 = 0.0357f;
GameObject val2 = MakePrimitive((PrimitiveType)3, val.transform, white, new Vector3(0.055f, num, 0.024f) * scale, new Vector3(0f, num * 0.5f * scale, 0f));
((Object)val2).name = "PackBody";
GameObject val3 = MakePrimitive((PrimitiveType)3, val.transform, red, new Vector3(0.055549998f, num2, 0.02424f) * scale, new Vector3(0f, (num + num2 * 0.5f) * scale, 0f));
((Object)val3).name = "PackLid";
GameObject val4 = MakePrimitive((PrimitiveType)3, val.transform, red, new Vector3(0.055f, 0.024f, 0.004f) * scale, new Vector3(0f, 0.09508f * scale, -0.01056f * scale));
((Object)val4).name = "PackFlap";
val4.transform.localRotation = Quaternion.Euler(-32f, 0f, 0f);
List<GameObject> list = new List<GameObject> { val2, val3, val4 };
for (int i = 0; i < 3; i++)
{
float num3 = (float)(i - 1) * 0.0135f;
GameObject val5 = MakePrimitive((PrimitiveType)2, val.transform, (i == 1) ? tobacco : white, new Vector3(0.0072f, 0.006f, 0.0072f) * scale, new Vector3(num3 * scale, 0.089f * scale, 0f));
((Object)val5).name = $"Cigarette{i}";
val5.transform.localRotation = Quaternion.Euler(5f * (float)(i - 1), 0f, 4f * (float)(i - 1));
list.Add(val5);
}
BoxCollider val6 = val.AddComponent<BoxCollider>();
((Collider)val6).isTrigger = true;
val6.size = new Vector3(0.16f, 0.16f, 0.16f) * scale;
val6.center = new Vector3(0f, 0.0425f * scale, 0f);
GameObject val7 = new GameObject("HoverTextAnchor");
val7.transform.SetParent(parent, false);
val7.transform.localPosition = val.transform.localPosition + new Vector3(ModConfig.HoverTextSide.Value, ModConfig.HoverTextUp.Value, 0f);
val.AddComponent<CigarettePackInteractable>().Configure((Collider)(object)val6, list.ToArray(), val7.transform, buttonCap);
val.SetActive(true);
}
private static void BuildLighter(Transform parent, float plankWidth, float scale)
{
//IL_003c: 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_0065: 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)
Transform val = VanillaAssets.FindLighter();
if ((Object)(object)val == (Object)null)
{
Plugin.Log.LogInfo((object)"No lighter found inside the Dynamite prefab; skipping it.");
return;
}
GameObject val2 = VanillaAssets.CloneVisual(val, parent, "Lighter");
if (!((Object)(object)val2 == (Object)null))
{
val2.transform.localScale = Vector3.one * scale;
val2.transform.localPosition = new Vector3(plankWidth * -0.09f, PlankTopY, 0.03f * scale);
val2.transform.localRotation = Quaternion.Euler(0f, 68f, 0f);
SeatOnParentSurface(val2);
}
}
private static void SeatOnParentSurface(GameObject go)
{
//IL_000f: 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_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: 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_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
Renderer[] componentsInChildren = go.GetComponentsInChildren<Renderer>();
if (componentsInChildren.Length != 0)
{
Bounds bounds = componentsInChildren[0].bounds;
Renderer[] array = componentsInChildren;
foreach (Renderer val in array)
{
((Bounds)(ref bounds)).Encapsulate(val.bounds);
}
float num = go.transform.position.y - ((Bounds)(ref bounds)).min.y;
Transform transform = go.transform;
transform.localPosition += new Vector3(0f, num, 0f);
}
}
private static GameObject MakePrimitive(PrimitiveType type, Transform parent, Material material, Vector3 scale, Vector3 localPosition)
{
//IL_0000: 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_0026: Unknown result type (might be due to invalid IL or missing references)
GameObject obj = GameObject.CreatePrimitive(type);
obj.transform.SetParent(parent, false);
obj.transform.localPosition = localPosition;
obj.transform.localScale = scale;
Collider component = obj.GetComponent<Collider>();
if ((Object)(object)component != (Object)null)
{
Object.Destroy((Object)(object)component);
}
Renderer component2 = obj.GetComponent<Renderer>();
if ((Object)(object)component2 != (Object)null && (Object)(object)material != (Object)null)
{
component2.material = material;
}
return obj;
}
private static Material MakeMaterial(Color tint)
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Expected O, but got Unknown
//IL_002f: 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)
Shader val = ResolveShader();
if ((Object)(object)val == (Object)null)
{
Plugin.Log.LogWarning((object)"No usable shader found; props will render with the fallback material.");
return null;
}
Material val2 = new Material(val);
int num = 0;
for (int i = 0; i < val.GetPropertyCount(); i++)
{
if ((int)val.GetPropertyType(i) == 0)
{
val2.SetColor(val.GetPropertyNameId(i), tint);
num++;
}
}
if (num == 0)
{
Plugin.Log.LogWarning((object)("Shader '" + ((Object)val).name + "' exposes no colour property; props will render untinted. Try a different Props.ShaderName — F9 lists the candidates."));
}
if (val2.HasProperty("_Smoothness"))
{
val2.SetFloat("_Smoothness", 0.15f);
}
if (val2.HasProperty("_Glossiness"))
{
val2.SetFloat("_Glossiness", 0.15f);
}
if (val2.HasProperty("_Metallic"))
{
val2.SetFloat("_Metallic", 0f);
}
return val2;
}
private static Shader ResolveShader()
{
if ((Object)(object)_cachedShader != (Object)null)
{
return _cachedShader;
}
string[] array = new string[5]
{
ModConfig.ShaderName.Value,
"Universal Render Pipeline/Lit",
"Universal Render Pipeline/Simple Lit",
"Universal Render Pipeline/Unlit",
"Sprites/Default"
};
foreach (string text in array)
{
if (string.IsNullOrEmpty(text))
{
continue;
}
Shader val = Shader.Find(text);
if (!((Object)(object)val == (Object)null))
{
if (HasBaseColour(val))
{
Plugin.Log.LogInfo((object)("Prop shader: '" + text + "'."));
_cachedShader = val;
return val;
}
Plugin.Log.LogInfo((object)("Shader '" + text + "' has no base colour property; trying the next candidate."));
}
}
return null;
}
private static bool HasBaseColour(Shader shader)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
for (int i = 0; i < shader.GetPropertyCount(); i++)
{
if ((int)shader.GetPropertyType(i) == 0)
{
string propertyName = shader.GetPropertyName(i);
if (propertyName == "_BaseColor" || propertyName == "_Color")
{
return true;
}
}
}
return false;
}
}
internal class CigarettePackInteractable : Interactable
{
private Transform _buttonCap;
private Vector3 _capRestPosition;
private string _lastHoverText;
private bool _pressing;
public override bool InteractableWhenHoldingItem => false;
private static bool CanUse
{
get
{
if (DiveController.CanTrigger && (Object)(object)BoatManager.Boat != (Object)null)
{
return BoatManager.Boat.BoatUnlocked;
}
return false;
}
}
public void Configure(Collider interactCollider, GameObject[] outlineTargets, Transform textAnchor, Transform buttonCap)
{
//IL_007f: 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_0084: Unknown result type (might be due to invalid IL or missing references)
AccessTools.Field(typeof(Interactable), "_interactCol")?.SetValue(this, interactCollider);
AccessTools.Field(typeof(Interactable), "_modelsToOutline")?.SetValue(this, outlineTargets);
AccessTools.Field(typeof(Interactable), "_textTarget")?.SetValue(this, textAnchor);
_buttonCap = buttonCap;
_capRestPosition = (((Object)(object)buttonCap != (Object)null) ? buttonCap.localPosition : Vector3.zero);
}
public override void Hover()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: 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)
string text = BuildHoverText();
if (!base._isHovering)
{
PlayerUI.SetLookAtText(text, ((Interactable)this).TextTarget, default(Vector3), false);
PlayerUI.SetLookAtColor(CanUse ? Color.white : GameInfo.RedColor);
}
else if (text != _lastHoverText)
{
PlayerUI.UpdateLookAtText(text);
}
_lastHoverText = text;
((Interactable)this).Hover();
}
public override void UnHover()
{
PlayerUI.HideLookAtText(_lastHoverText);
((Interactable)this).UnHover();
}
public override void Interact(Player player)
{
if (CanUse)
{
((Interactable)this).Interact(player);
if (!_pressing)
{
((MonoBehaviour)this).StartCoroutine(PressAnimation());
}
DiveNet.RequestDive();
}
}
private string BuildHoverText()
{
if ((Object)(object)BoatManager.Boat == (Object)null || !BoatManager.Boat.BoatUnlocked)
{
return "Not your boat yet";
}
if (!DiveController.CanTrigger)
{
if (DiveController.Phase != DivePhase.Cooldown)
{
return "Too late";
}
return "Maybe don't";
}
return "Röökille\n" + SpriteManager.GetPickUpInput();
}
private IEnumerator PressAnimation()
{
_pressing = true;
if ((Object)(object)_buttonCap != (Object)null)
{
for (float t = 0f; t < 0.06f; t += Time.deltaTime)
{
float num = Mathf.Clamp01(t / 0.06f);
_buttonCap.localPosition = _capRestPosition - new Vector3(0f, 0.02f * num, 0f);
yield return null;
}
_buttonCap.localPosition = _capRestPosition - new Vector3(0f, 0.02f, 0f);
yield return (object)new WaitForSeconds(0.5f);
for (float t = 0f; t < 0.25f; t += Time.deltaTime)
{
float num2 = Mathf.Clamp01(t / 0.25f);
_buttonCap.localPosition = _capRestPosition - new Vector3(0f, 0.02f * (1f - num2), 0f);
yield return null;
}
_buttonCap.localPosition = _capRestPosition;
}
_pressing = false;
}
}
internal static class Diagnostics
{
public static void Dump()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("BlirUBoat diagnostics — " + Application.productName + " / Unity " + Application.unityVersion);
stringBuilder.AppendLine();
Section(stringBuilder, "AUDIO CLIPS (AudioManager._realClips)", DumpAudioClips);
Section(stringBuilder, "ITEM PREFABS (Resources.LoadAll<Item>(\"Items\"))", DumpItems);
Section(stringBuilder, "BOAT GEOMETRY + BOW/TRIGGER CHECK", DumpBoat);
Section(stringBuilder, "SHADER AVAILABILITY", DumpShaders);
Section(stringBuilder, "BOAT MATERIALS + TEXTURES", DumpBoatMaterials);
string text = Path.Combine(Paths.ConfigPath, "BlirUBoat-diagnostics.txt");
File.WriteAllText(text, stringBuilder.ToString());
Plugin.Log.LogInfo((object)("Diagnostics written to " + text));
}
private static void Section(StringBuilder sb, string title, Action<StringBuilder> body)
{
sb.AppendLine(new string('=', 78));
sb.AppendLine(title);
sb.AppendLine(new string('=', 78));
try
{
body(sb);
}
catch (Exception ex)
{
sb.AppendLine($" FAILED: {ex}");
Plugin.Log.LogWarning((object)("Diagnostics section '" + title + "' failed: " + ex.Message));
}
sb.AppendLine();
}
private static void DumpAudioClips(StringBuilder sb)
{
FieldInfo fieldInfo = AccessTools.Field(typeof(AudioManager), "_realClips");
if (fieldInfo == null)
{
sb.AppendLine(" AudioManager._realClips not found — field renamed?");
return;
}
if (!(fieldInfo.GetValue(null) is IDictionary dictionary))
{
sb.AppendLine(" _realClips was null or not a dictionary.");
return;
}
IOrderedEnumerable<string> orderedEnumerable = (from object k in dictionary.Keys
select k?.ToString() ?? "<null>").OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase);
sb.AppendLine($" {dictionary.Count} clips:");
foreach (string item in orderedEnumerable)
{
sb.AppendLine(" " + item);
}
}
private static void DumpItems(StringBuilder sb)
{
Item[] array = Resources.LoadAll<Item>("Items");
sb.AppendLine($" {array.Length} item prefabs:");
foreach (string item in array.Select((Item i) => ((Object)i).name).OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase))
{
sb.AppendLine(" " + item);
}
}
private static void DumpBoat(StringBuilder sb)
{
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: 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_0128: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
//IL_01ee: 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_0230: Unknown result type (might be due to invalid IL or missing references)
//IL_023c: Unknown result type (might be due to invalid IL or missing references)
Boat boat = BoatManager.Boat;
if ((Object)(object)boat == (Object)null)
{
sb.AppendLine(" No boat spawned yet — load into a save with the boat present and press the key again.");
return;
}
sb.AppendLine($" Boat: {((Object)boat).name} BoatUnlocked={boat.BoatUnlocked}");
sb.AppendLine(" VisualBoat: " + Describe(boat.VisualBoat));
sb.AppendLine(" DriverPos: " + Describe(boat.DriverPos));
sb.AppendLine();
if (!(AccessTools.Field(typeof(Boat), "_forcePoints")?.GetValue(boat) is Transform[] array) || array.Length == 0)
{
sb.AppendLine(" _forcePoints missing or empty — bow anchoring strategy needs rethinking.");
return;
}
Transform transform = ((Component)boat).transform;
sb.AppendLine($" {array.Length} force points (boat-local space, +Z assumed forward):");
Transform val = null;
float num = float.NegativeInfinity;
Transform[] array2 = array;
foreach (Transform val2 in array2)
{
if (!((Object)(object)val2 == (Object)null))
{
Vector3 val3 = transform.InverseTransformPoint(val2.position);
sb.AppendLine($" {((Object)val2).name,-24} local={Fmt(val3)}");
if (val3.z > num)
{
num = val3.z;
val = val2;
}
}
}
if ((Object)(object)val == (Object)null)
{
sb.AppendLine(" No usable force point found.");
return;
}
sb.AppendLine();
sb.AppendLine($" Bow candidate (max local Z): {((Object)val).name} at local Z {num:F3}");
BoatTrigger boatTrigger = boat.BoatTrigger;
if ((Object)(object)boatTrigger == (Object)null)
{
sb.AppendLine(" BoatTrigger is null — cannot evaluate coverage.");
return;
}
Collider[] componentsInChildren = ((Component)boatTrigger).GetComponentsInChildren<Collider>();
sb.AppendLine($" BoatTrigger '{((Object)boatTrigger).name}' has {componentsInChildren.Length} collider(s):");
bool flag = false;
Collider[] array3 = componentsInChildren;
foreach (Collider val4 in array3)
{
Bounds bounds = val4.bounds;
bool flag2 = ((Bounds)(ref bounds)).Contains(val.position);
flag = flag || flag2;
sb.AppendLine($" {((object)val4).GetType().Name,-18} isTrigger={val4.isTrigger,-5} " + $"center={Fmt(((Bounds)(ref bounds)).center)} extents={Fmt(((Bounds)(ref bounds)).extents)} containsBow={flag2}");
}
sb.AppendLine();
sb.AppendLine(flag ? " RESULT: bow IS inside the boat trigger — vanilla OnBoat covers the button position." : " RESULT: bow is OUTSIDE the boat trigger — drown immunity needs its own occupancy test at the bow (see RESEARCH.md §6.7).");
sb.AppendLine(" NOTE: bounds are axis-aligned approximations; confirm by standing on the bow and checking PlayerMovement.OnBoat.");
}
private static void DumpShaders(StringBuilder sb)
{
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
foreach (string item in new string[8]
{
ModConfig.ShaderName.Value,
"Shader Graphs/DefaultShader",
"Shader Graphs/LevelShader",
"Shader Graphs/CharacterShader",
"Universal Render Pipeline/Lit",
"Universal Render Pipeline/Simple Lit",
"Universal Render Pipeline/Unlit",
"Sprites/Default"
}.Distinct())
{
if (string.IsNullOrEmpty(item))
{
continue;
}
Shader val = Shader.Find(item);
if ((Object)(object)val == (Object)null)
{
sb.AppendLine(" MISSING " + item);
continue;
}
List<string> list = new List<string>();
for (int i = 0; i < val.GetPropertyCount(); i++)
{
if ((int)val.GetPropertyType(i) == 0)
{
list.Add(val.GetPropertyName(i));
}
}
sb.AppendLine(" OK " + item + " colour properties: " + ((list.Count > 0) ? string.Join(", ", list.ToArray()) : "<none>"));
}
}
private static void DumpBoatMaterials(StringBuilder sb)
{
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//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_0132: 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_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Invalid comparison between Unknown and I4
//IL_01bd: 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)
Boat boat = BoatManager.Boat;
if ((Object)(object)boat == (Object)null)
{
sb.AppendLine(" No boat spawned yet.");
return;
}
Transform val = (((Object)(object)boat.VisualBoat != (Object)null) ? boat.VisualBoat : ((Component)boat).transform);
MeshRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<MeshRenderer>();
sb.AppendLine($" {componentsInChildren.Length} renderer(s) under '{((Object)val).name}':");
MeshRenderer[] array = componentsInChildren;
foreach (MeshRenderer val2 in array)
{
Material sharedMaterial = ((Renderer)val2).sharedMaterial;
if ((Object)(object)sharedMaterial == (Object)null)
{
continue;
}
MeshFilter component = ((Component)val2).GetComponent<MeshFilter>();
float num;
if (!((Object)(object)component != (Object)null) || !((Object)(object)component.sharedMesh != (Object)null))
{
num = 0f;
}
else
{
Bounds bounds = component.sharedMesh.bounds;
Vector3 size = ((Bounds)(ref bounds)).size;
num = ((Vector3)(ref size)).magnitude;
}
float num2 = num;
sb.AppendLine($" {((Object)val2).name,-22} mat='{((Object)sharedMaterial).name}' shader='{((Object)sharedMaterial.shader).name}' meshSize={num2:F2}");
Shader shader = sharedMaterial.shader;
for (int j = 0; j < shader.GetPropertyCount(); j++)
{
int propertyNameId = shader.GetPropertyNameId(j);
ShaderPropertyType propertyType = shader.GetPropertyType(j);
if ((int)propertyType == 4)
{
Texture texture = sharedMaterial.GetTexture(propertyNameId);
if ((Object)(object)texture != (Object)null)
{
sb.AppendLine(" tex " + shader.GetPropertyName(j) + " = '" + ((Object)texture).name + "' " + $"({texture.width}x{texture.height})");
}
}
else if ((int)propertyType == 0)
{
sb.AppendLine($" col {shader.GetPropertyName(j)} = {sharedMaterial.GetColor(propertyNameId)}");
}
}
}
}
private static string Describe(Transform t)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)t == (Object)null))
{
return ((Object)t).name + " world=" + Fmt(t.position);
}
return "<null>";
}
private static string Fmt(Vector3 v)
{
//IL_0005: 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_001b: Unknown result type (might be due to invalid IL or missing references)
return $"({v.x:F2}, {v.y:F2}, {v.z:F2})";
}
}
internal enum DivePhase
{
Idle,
Descending,
Submerged,
Ascending,
Cooldown
}
internal static class DiveController
{
private const float ProportionalGain = 9f;
private const float DerivativeGain = 5f;
private const float MaxAcceleration = 28f;
private static float _phaseStart;
private static float _submergedDuration;
private static float _currentTargetDepth;
public static DivePhase Phase { get; private set; }
private static float PhaseElapsed => Time.time - _phaseStart;
public static bool Diving
{
get
{
if (Phase != DivePhase.Descending && Phase != DivePhase.Submerged)
{
return Phase == DivePhase.Ascending;
}
return true;
}
}
public static bool CanTrigger => Phase == DivePhase.Idle;
public static void ServerBeginDive()
{
if (!CanTrigger)
{
Plugin.Log.LogInfo((object)$"Dive requested but phase is {Phase}; ignoring.");
return;
}
_submergedDuration = Random.Range(ModConfig.SubmergedSecondsMin.Value, Mathf.Max(ModConfig.SubmergedSecondsMin.Value, ModConfig.SubmergedSecondsMax.Value));
EnterPhase(DivePhase.Descending);
Plugin.Log.LogInfo((object)($"Dive started — descending over {ModConfig.DescentSeconds.Value:F1}s, " + $"holding {_submergedDuration:F1}s."));
DiveNet.ServerAnnounceDiveStarted();
}
public static void Abort(string reason)
{
if (Phase != DivePhase.Idle)
{
Plugin.Log.LogInfo((object)("Dive aborted: " + reason));
Phase = DivePhase.Idle;
_currentTargetDepth = 0f;
Klaxon.Stop();
}
}
private static void EnterPhase(DivePhase phase)
{
Phase = phase;
_phaseStart = Time.time;
}
public static bool ServerTick(Boat boat)
{
AdvancePhase();
if (!Diving)
{
return false;
}
if ((Object)(object)boat == (Object)null)
{
return false;
}
Rigidbody hiddenPhysicsRig = boat.HiddenPhysicsRig;
if ((Object)(object)hiddenPhysicsRig == (Object)null)
{
return false;
}
ApplyDepthControl(boat, hiddenPhysicsRig);
KeepUpright(boat, hiddenPhysicsRig);
ApplyUnderwaterDamping(boat, hiddenPhysicsRig);
return true;
}
private static void AdvancePhase()
{
switch (Phase)
{
case DivePhase.Descending:
if (PhaseElapsed >= ModConfig.DescentSeconds.Value)
{
EnterPhase(DivePhase.Submerged);
Klaxon.Stop();
}
break;
case DivePhase.Submerged:
if (PhaseElapsed >= _submergedDuration)
{
EnterPhase(DivePhase.Ascending);
Plugin.Log.LogInfo((object)"Surfacing.");
}
break;
case DivePhase.Ascending:
if (PhaseElapsed >= ModConfig.AscentSeconds.Value)
{
EnterPhase(DivePhase.Cooldown);
}
break;
case DivePhase.Cooldown:
if (PhaseElapsed >= ModConfig.CooldownSeconds.Value)
{
Phase = DivePhase.Idle;
Plugin.Log.LogInfo((object)"Boat ready to dive again.");
}
break;
}
}
private static float TargetDepth()
{
float value = ModConfig.DiveDepth.Value;
return Phase switch
{
DivePhase.Descending => value * Smooth(Mathf.Clamp01(PhaseElapsed / Mathf.Max(0.01f, ModConfig.DescentSeconds.Value))),
DivePhase.Submerged => value,
DivePhase.Ascending => value * (1f - Smooth(Mathf.Clamp01(PhaseElapsed / Mathf.Max(0.01f, ModConfig.AscentSeconds.Value)))),
_ => 0f,
};
}
private static float Smooth(float t)
{
return t * t * (3f - 2f * t);
}
private static void ApplyDepthControl(Boat boat, Rigidbody rig)
{
//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_001d: 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_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
_currentTargetDepth = TargetDepth();
Vector3 position = rig.position;
float num = WaterManager.GetWaterHeight(position) - _currentTargetDepth - position.y;
float y = rig.linearVelocity.y;
float num2 = Mathf.Clamp(num * 9f - y * 5f, -28f, 28f);
rig.AddForce(Vector3.up * num2, (ForceMode)5);
}
private static void KeepUpright(Boat boat, Rigidbody rig)
{
//IL_003f: 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)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: 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_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)
if (AccessTools.Field(typeof(Boat), "_antiRollOverForce")?.GetValue(boat) is float num)
{
Quaternion val = Quaternion.Euler(0f, ((Component)rig).transform.eulerAngles.y, 0f);
Vector3 angularVelocityToTarget = DazedUtils.GetAngularVelocityToTarget(rig.rotation, val);
rig.AddTorque(angularVelocityToTarget * num);
}
}
private static void ApplyUnderwaterDamping(Boat boat, Rigidbody rig)
{
object obj = AccessTools.Field(typeof(Boat), "_underwaterLinearDamp")?.GetValue(boat);
object obj2 = AccessTools.Field(typeof(Boat), "_underwaterAngularDamp")?.GetValue(boat);
if (obj is float linearDamping)
{
rig.linearDamping = linearDamping;
}
if (obj2 is float angularDamping)
{
rig.angularDamping = angularDamping;
}
}
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
internal struct DiveRequestBroadcast : IBroadcast
{
}
[StructLayout(LayoutKind.Sequential, Size = 1)]
internal struct DiveStartedBroadcast : IBroadcast
{
}
internal static class DiveNet
{
private static bool _serializersInstalled;
private static bool _serverRegistered;
private static bool _clientRegistered;
public static bool Available { get; private set; }
public static void RequestDive()
{
if (InstanceFinder.IsServerStarted)
{
DiveController.ServerBeginDive();
return;
}
if (!Available)
{
Plugin.Log.LogWarning((object)"Dive requested but this client cannot reach the host (broadcast unavailable). The host must have the mod installed.");
return;
}
try
{
InstanceFinder.ClientManager.Broadcast<DiveRequestBroadcast>(default(DiveRequestBroadcast), (Channel)0);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Failed to send dive request: " + ex.Message));
}
}
public static void ServerAnnounceDiveStarted()
{
if (!InstanceFinder.IsServerStarted)
{
return;
}
Klaxon.Play(((Object)(object)BoatManager.Boat != (Object)null) ? BoatManager.Boat.VisualBoat : null);
if (!Available)
{
return;
}
try
{
InstanceFinder.ServerManager.Broadcast<DiveStartedBroadcast>(default(DiveStartedBroadcast), true, (Channel)0);
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Failed to announce dive to clients: " + ex.Message));
}
}
public static void EnsureRegistered(bool asServer)
{
InstallSerializers();
try
{
if (asServer && !_serverRegistered && (Object)(object)InstanceFinder.ServerManager != (Object)null)
{
InstanceFinder.ServerManager.RegisterBroadcast<DiveRequestBroadcast>((Action<NetworkConnection, DiveRequestBroadcast, Channel>)OnServerDiveRequest, true);
_serverRegistered = true;
Plugin.Log.LogInfo((object)"Registered server broadcast handler.");
}
if (!asServer && !_clientRegistered && (Object)(object)InstanceFinder.ClientManager != (Object)null)
{
InstanceFinder.ClientManager.RegisterBroadcast<DiveStartedBroadcast>((Action<DiveStartedBroadcast, Channel>)OnClientDiveStarted);
_clientRegistered = true;
Plugin.Log.LogInfo((object)"Registered client broadcast handler.");
}
}
catch (Exception ex)
{
Available = false;
Plugin.Log.LogWarning((object)("Broadcast registration failed (" + ex.Message + "). Falling back to host-only triggering."));
}
}
public static void Reset()
{
_serverRegistered = false;
_clientRegistered = false;
}
private static void InstallSerializers()
{
if (_serializersInstalled)
{
return;
}
try
{
InstallSerializer<DiveRequestBroadcast>();
InstallSerializer<DiveStartedBroadcast>();
_serializersInstalled = true;
Available = true;
Plugin.Log.LogInfo((object)"Installed FishNet broadcast serializers.");
}
catch (Exception ex)
{
Available = false;
Plugin.Log.LogWarning((object)("Could not install broadcast serializers (" + ex.Message + "). Host-only triggering will still work."));
}
}
private static void InstallSerializer<T>() where T : struct, IBroadcast
{
Action<Writer, T> value = delegate
{
};
Func<Reader, T> value2 = (Reader reader) => default(T);
SetStaticMember(typeof(GenericWriter<T>), "<Write>k__BackingField", value);
SetStaticMember(typeof(GenericReader<T>), "<Read>k__BackingField", value2);
SetStaticMember(typeof(GenericWriter<T>), "HasCustomSerializer", true, optional: true);
SetStaticMember(typeof(GenericReader<T>), "HasCustomSerializer", true, optional: true);
}
private static void SetStaticMember(Type type, string name, object value, bool optional = false)
{
FieldInfo fieldInfo = AccessTools.Field(type, name);
if (fieldInfo != null)
{
fieldInfo.SetValue(null, value);
return;
}
PropertyInfo propertyInfo = AccessTools.Property(type, name);
if (propertyInfo != null && propertyInfo.CanWrite)
{
propertyInfo.SetValue(null, value, null);
}
else if (!optional)
{
throw new MissingFieldException(type.FullName, name);
}
}
private static void OnServerDiveRequest(NetworkConnection sender, DiveRequestBroadcast msg, Channel channel)
{
Plugin.Log.LogInfo((object)$"Dive requested by client {sender?.ClientId}.");
DiveController.ServerBeginDive();
}
private static void OnClientDiveStarted(DiveStartedBroadcast msg, Channel channel)
{
if (!InstanceFinder.IsServerStarted)
{
Klaxon.Play(((Object)(object)BoatManager.Boat != (Object)null) ? BoatManager.Boat.VisualBoat : null);
}
}
}
internal static class Klaxon
{
private const int SampleRate = 44100;
private const float ToneSeconds = 0.45f;
private static readonly float[] Tones = new float[2] { 620f, 440f };
private static AudioClip _clip;
private static AudioSource _source;
public static void Play(Transform parent)
{
if (!ModConfig.AlarmEnabled.Value)
{
return;
}
try
{
EnsureSource(parent);
if (!((Object)(object)_source == (Object)null))
{
_source.volume = ModConfig.AlarmVolume.Value;
if (!_source.isPlaying)
{
_source.Play();
}
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Could not start alarm: " + ex.Message));
}
}
public static void Stop()
{
if ((Object)(object)_source != (Object)null && _source.isPlaying)
{
_source.Stop();
}
}
private static void EnsureSource(Transform parent)
{
//IL_003e: 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)
if ((Object)(object)_clip == (Object)null)
{
_clip = Generate();
}
if ((Object)(object)_source == (Object)null || (Object)(object)((Component)_source).gameObject == (Object)null)
{
_source = new GameObject("BlirUBoat_Alarm").AddComponent<AudioSource>();
_source.clip = _clip;
_source.loop = true;
_source.playOnAwake = false;
_source.spatialBlend = 1f;
_source.rolloffMode = (AudioRolloffMode)1;
_source.minDistance = 4f;
_source.maxDistance = 90f;
_source.outputAudioMixerGroup = ResolveFxMixerGroup();
}
if ((Object)(object)parent != (Object)null)
{
((Component)_source).transform.SetParent(parent, false);
((Component)_source).transform.localPosition = Vector3.zero;
}
}
private static AudioMixerGroup ResolveFxMixerGroup()
{
object obj = AccessTools.Field(typeof(AudioManager), "_instance")?.GetValue(null);
if (obj == null)
{
Plugin.Log.LogWarning((object)"AudioManager instance not found; alarm will bypass the FX mixer.");
return null;
}
object? obj2 = AccessTools.Field(typeof(AudioManager), "_fxGroup")?.GetValue(obj);
return (AudioMixerGroup)((obj2 is AudioMixerGroup) ? obj2 : null);
}
private static AudioClip Generate()
{
int num = Mathf.RoundToInt(19845f);
float[] array = new float[num * Tones.Length];
for (int i = 0; i < Tones.Length; i++)
{
float num2 = Tones[i];
for (int j = 0; j < num; j++)
{
float num3 = (float)j / 44100f;
float num4 = MathF.PI * 2f * num2 * num3;
float num5 = Mathf.Sin(num4) + 0.45f * Mathf.Sin(2f * num4) + 0.22f * Mathf.Sin(3f * num4);
num5 /= 1.67f;
array[i * num + j] = num5 * Envelope((float)j / (float)num) * 0.8f;
}
}
AudioClip obj = AudioClip.Create("BlirUBoat_Klaxon", array.Length, 1, 44100, false);
obj.SetData(array, 0);
return obj;
}
private static float Envelope(float t)
{
if (t < 0.03f)
{
return t / 0.03f;
}
if (t > 0.9f)
{
return (1f - t) / 0.1f;
}
return 1f;
}
}
internal static class ModConfig
{
public static ConfigEntry<float> DiveDepth;
public static ConfigEntry<float> DescentSeconds;
public static ConfigEntry<float> SubmergedSecondsMin;
public static ConfigEntry<float> SubmergedSecondsMax;
public static ConfigEntry<float> AscentSeconds;
public static ConfigEntry<float> CooldownSeconds;
public static ConfigEntry<bool> AlarmEnabled;
public static ConfigEntry<float> AlarmVolume;
public static ConfigEntry<float> PropScale;
public static ConfigEntry<float> PlankWidthOverride;
public static ConfigEntry<float> PlankInset;
public static ConfigEntry<float> PlankLength;
public static ConfigEntry<float> OffsetForward;
public static ConfigEntry<float> OffsetSide;
public static ConfigEntry<float> PlankHeightFraction;
public static ConfigEntry<float> PackYaw;
public static ConfigEntry<float> HoverTextSide;
public static ConfigEntry<float> HoverTextUp;
public static ConfigEntry<string> ShaderName;
public static ConfigEntry<KeyboardShortcut> DiagnosticsKey;
public static void Bind(ConfigFile cfg)
{
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Expected O, but got Unknown
//IL_0130: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Expected O, but got Unknown
//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
//IL_01b0: Expected O, but got Unknown
//IL_023b: Unknown result type (might be due to invalid IL or missing references)
//IL_0245: Expected O, but got Unknown
//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
//IL_02bb: Expected O, but got Unknown
//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
DiveDepth = cfg.Bind<float>("Dive", "Depth", 4f, "How far below the water surface the boat settles, in metres.");
DescentSeconds = cfg.Bind<float>("Dive", "DescentSeconds", 7f, new ConfigDescription("How long the boat takes to go under.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
SubmergedSecondsMin = cfg.Bind<float>("Dive", "SubmergedSecondsMin", 15f, "Minimum time held underwater before surfacing.");
SubmergedSecondsMax = cfg.Bind<float>("Dive", "SubmergedSecondsMax", 25f, "Maximum time held underwater before surfacing.");
AscentSeconds = cfg.Bind<float>("Dive", "AscentSeconds", 4f, new ConfigDescription("How long the boat takes to come back up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
CooldownSeconds = cfg.Bind<float>("Dive", "CooldownSeconds", 10f, "Delay after surfacing before the button can be used again.");
AlarmEnabled = cfg.Bind<bool>("Audio", "AlarmEnabled", true, "Play the alarm while the boat is going under.");
AlarmVolume = cfg.Bind<float>("Audio", "AlarmVolume", 0.55f, new ConfigDescription("Alarm loudness. Still scaled by the game's own FX volume slider.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
PropScale = cfg.Bind<float>("Props", "Scale", 1f, "Size multiplier for the cigarette pack and button.");
PlankWidthOverride = cfg.Bind<float>("Props", "PlankWidthOverride", 0f, "Fixed plank width across the boat, in metres. Leave at 0 to measure the hull and fit the plank automatically — the hull tapers, so a fixed width punches through the sides near the bow.");
PlankInset = cfg.Bind<float>("Props", "PlankInset", -0.22f, new ConfigDescription("How far short of the measured hull each end of the plank stops, in metres. Small values fit snugly; negative values push the ends into the hull sides.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.5f, 0.5f), Array.Empty<object>()));
PlankLength = cfg.Bind<float>("Props", "PlankDepth", 0.5f, "Plank depth along the boat, in metres.");
OffsetForward = cfg.Bind<float>("Props", "OffsetForward", -1f, "Distance from the very tip of the bow, in metres. Negative moves inboard.");
OffsetSide = cfg.Bind<float>("Props", "OffsetSide", 0f, "Sideways offset across the boat, in metres.");
PackYaw = cfg.Bind<float>("Props", "PackYaw", 204f, new ConfigDescription("Which way the cigarette pack faces, in degrees around the vertical axis.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 360f), Array.Empty<object>()));
HoverTextSide = cfg.Bind<float>("Props", "HoverTextSide", 0.32f, "How far to the side the 'Röökille' prompt sits from the pack, in metres, so the label doesn't cover the model.");
HoverTextUp = cfg.Bind<float>("Props", "HoverTextUp", 0.06f, "How far above the plank the prompt sits, in metres.");
PlankHeightFraction = cfg.Bind<float>("Props", "HeightFraction", 0.5f, new ConfigDescription("How far up the hull the plank sits, as a fraction of the boat's height. 0 is the keel, 1 is the gunwale, 0.5 is halfway up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1.2f), Array.Empty<object>()));
ShaderName = cfg.Bind<string>("Props", "ShaderName", "Universal Render Pipeline/Lit", "Shader used for the props. URP/Lit by default: it is the only candidate confirmed to expose _BaseColor. \"Shader Graphs/DefaultShader\" matches the game art style more closely but exposes no standard colour property. Never use the boat shader.");
DiagnosticsKey = cfg.Bind<KeyboardShortcut>("Diagnostics", "DumpKey", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Writes a report of audio clips, item prefabs and boat geometry to the config folder.");
}
}
[HarmonyPatch(typeof(Boat), "ApplyWaterForce")]
internal static class BoatApplyWaterForcePatch
{
private static bool Prefix(Boat __instance)
{
return !DiveController.ServerTick(__instance);
}
}
[HarmonyPatch(typeof(Boat), "OnStartClient")]
internal static class BoatOnStartClientPatch
{
private static void Postfix(Boat __instance)
{
try
{
DiveNet.EnsureRegistered(asServer: false);
BoatProps.Attach(__instance);
}
catch (Exception arg)
{
Plugin.Log.LogError((object)$"Failed to set up boat props: {arg}");
}
}
}
[HarmonyPatch(typeof(Boat), "OnStartServer")]
internal static class BoatOnStartServerPatch
{
private static void Postfix()
{
DiveNet.EnsureRegistered(asServer: true);
}
}
[HarmonyPatch(typeof(Boat), "OnStopClient")]
internal static class BoatOnStopClientPatch
{
private static void Postfix()
{
DiveController.Abort("boat despawned");
DiveNet.Reset();
}
}
[HarmonyPatch(typeof(BoatManager), "TryMoveBoat")]
internal static class BoatManagerTryMoveBoatPatch
{
private static void Prefix()
{
DiveController.Abort("boat relocated");
}
}
[HarmonyPatch(typeof(BoatManager), "RemoveBoat")]
internal static class BoatManagerRemoveBoatPatch
{
private static void Prefix()
{
DiveController.Abort("boat removed");
}
}
[HarmonyPatch(typeof(PlayerMovement), "UnderWaterCheck")]
internal static class PlayerMovementUnderWaterCheckPatch
{
private static readonly FieldRef<PlayerMovement, float> TimeWentUnderWater = AccessTools.FieldRefAccess<PlayerMovement, float>("_timeWentUnderWater");
private static void Prefix(PlayerMovement __instance)
{
if (!((Object)(object)__instance == (Object)null) && __instance.OnBoat && BoatIsSubmerged())
{
TimeWentUnderWater.Invoke(__instance) = Time.time;
}
}
private static bool BoatIsSubmerged()
{
//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_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
Boat boat = BoatManager.Boat;
if ((Object)(object)boat == (Object)null)
{
return false;
}
Vector3 val = BoatVisualPosition(boat);
return val.y < WaterManager.GetWaterHeight(val) - 0.15f;
}
private static Vector3 BoatVisualPosition(Boat boat)
{
//IL_0014: 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_002e: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)boat.VisualPhysicsRig != (Object)null)
{
return boat.VisualPhysicsRig.position;
}
if ((Object)(object)boat.VisualBoat != (Object)null)
{
return boat.VisualBoat.position;
}
return ((Component)boat).transform.position;
}
}
internal class PlankFitter : MonoBehaviour
{
private const float MaxReach = 3f;
private const float GiveUpAfterSeconds = 5f;
private float _elapsed;
private bool _done;
private void FixedUpdate()
{
if (!_done)
{
_elapsed += Time.fixedDeltaTime;
if (TryFit())
{
_done = true;
Object.Destroy((Object)(object)this);
}
else if (_elapsed >= 5f)
{
Plugin.Log.LogInfo((object)"Could not probe the hull for the plank's shape; leaving it rectangular. Set Props.PlankWidthOverride if it doesn't fit.");
_done = true;
Object.Destroy((Object)(object)this);
}
}
}
private bool TryFit()
{
float value = ModConfig.PlankLength.Value;
float value2 = ModConfig.PlankInset.Value;
if (!TryMeasureAt(value * 0.45f, out var width))
{
return false;
}
if (!TryMeasureAt((0f - value) * 0.45f, out var width2))
{
return false;
}
float num = Mathf.Max(0.15f, width - value2 * 2f);
float num2 = Mathf.Max(0.15f, width2 - value2 * 2f);
BoatProps.ShapePlank(((Component)this).gameObject, num2, num, value);
Plugin.Log.LogInfo((object)($"Plank fitted to hull: {num2:F2}m aft, {num:F2}m fore " + $"(hull spans {width2:F2}m / {width:F2}m)."));
return true;
}
private bool TryMeasureAt(float alongBoat, out float width)
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0023: 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_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: 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_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
width = 0f;
Vector3 origin = ((Component)this).transform.position + ((Component)this).transform.forward * alongBoat + ((Component)this).transform.up * (BoatProps.PlankThicknessMetres * 0.5f);
if (!TryCast(origin, ((Component)this).transform.right, out var distance))
{
return false;
}
if (!TryCast(origin, -((Component)this).transform.right, out var distance2))
{
return false;
}
width = distance + distance2;
return width > 0.05f;
}
private bool TryCast(Vector3 origin, Vector3 direction, out float distance)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
distance = 0f;
RaycastHit[] array = Physics.RaycastAll(origin, direction, 3f, -1, (QueryTriggerInteraction)1);
if (array.Length == 0)
{
return false;
}
Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
RaycastHit[] array2 = array;
for (int num = 0; num < array2.Length; num++)
{
RaycastHit val = array2[num];
if (!((Object)(object)((RaycastHit)(ref val)).collider == (Object)null) && BoatManager.ColToBoat.ContainsKey(((RaycastHit)(ref val)).collider))
{
distance = ((RaycastHit)(ref val)).distance;
return true;
}
}
return false;
}
}
[BepInPlugin("Stendari.BlirUBoat", "BlirUBoat", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "Stendari.BlirUBoat";
public const string PluginName = "BlirUBoat";
public const string PluginVersion = "1.0.0";
internal static ManualLogSource Log;
private Harmony _harmony;
private void Awake()
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
ModConfig.Bind(((BaseUnityPlugin)this).Config);
_harmony = new Harmony("Stendari.BlirUBoat");
_harmony.PatchAll(typeof(Plugin).Assembly);
Log.LogInfo((object)"BlirUBoat 1.0.0 loaded. Press the button.");
}
private void Update()
{
//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)
KeyboardShortcut value = ModConfig.DiagnosticsKey.Value;
if (((KeyboardShortcut)(ref value)).IsDown())
{
Diagnostics.Dump();
}
}
private void OnDestroy()
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
}
internal static class VanillaAssets
{
private static Item[] _items;
private static Item[] Items => _items ?? (_items = Resources.LoadAll<Item>("Items"));
private static Item FindItem(string nameFragment)
{
return ((IEnumerable<Item>)Items).FirstOrDefault((Func<Item, bool>)((Item i) => (Object)(object)i != (Object)null && ((Object)i).name.IndexOf(nameFragment, StringComparison.OrdinalIgnoreCase) >= 0));
}
public static Transform FindLighter()
{
Item val = FindItem("Dynamite");
if ((Object)(object)val == (Object)null)
{
return null;
}
Explosive val2 = ((Component)val).GetComponent<Explosive>() ?? ((Component)val).GetComponentInChildren<Explosive>(true);
if ((Object)(object)val2 == (Object)null)
{
return null;
}
object? obj = AccessTools.Field(typeof(Explosive), "_lighter")?.GetValue(val2);
return (Transform)((obj is Transform) ? obj : null);
}
public static GameObject CloneVisual(Transform source, Transform parent, string name)
{
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Expected O, but got Unknown
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_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)
//IL_00c5: 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_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_00e5: 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_00fc: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)source == (Object)null)
{
return null;
}
MeshRenderer[] array = ((Component)source).GetComponentsInChildren<MeshRenderer>(true).Where(delegate(MeshRenderer r)
{
if ((Object)(object)r != (Object)null)
{
MeshFilter component = ((Component)r).GetComponent<MeshFilter>();
return (Object)(object)((component != null) ? component.sharedMesh : null) != (Object)null;
}
return false;
}).ToArray();
if (array.Length == 0)
{
Plugin.Log.LogWarning((object)("'" + ((Object)source).name + "' has no mesh renderers to clone."));
return null;
}
GameObject val = new GameObject(name);
val.transform.SetParent(parent, false);
MeshRenderer[] array2 = array;
foreach (MeshRenderer val2 in array2)
{
GameObject val3 = new GameObject(((Object)val2).name);
val3.transform.SetParent(val.transform, false);
val3.transform.localPosition = source.InverseTransformPoint(((Component)val2).transform.position);
val3.transform.localRotation = Quaternion.Inverse(source.rotation) * ((Component)val2).transform.rotation;
val3.transform.localScale = ((Component)val2).transform.lossyScale;
val3.AddComponent<MeshFilter>().sharedMesh = ((Component)val2).GetComponent<MeshFilter>().sharedMesh;
((Renderer)val3.AddComponent<MeshRenderer>()).sharedMaterials = ((Renderer)val2).sharedMaterials;
}
Plugin.Log.LogInfo((object)$"Cloned visual from '{((Object)source).name}' ({array.Length} renderer(s)).");
return val;
}
}
}