Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of BetterRowing v0.3.26
BepInEx/plugins/BetterRowing/BetterRowing.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn.Configs; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Unity.Collections; using UnityEngine; using UnityEngine.Animations; using UnityEngine.Audio; using UnityEngine.Experimental.Animations; using UnityEngine.Playables; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("BetterRowing")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.3.26.0")] [assembly: AssemblyInformationalVersion("0.3.26")] [assembly: AssemblyProduct("BetterRowing")] [assembly: AssemblyTitle("BetterRowing")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.3.26.0")] [module: UnverifiableCode] [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 BetterRowing { public sealed class HumanoidRowingLayer : IDisposable { private struct RowingJob : IAnimationJob { public NativeArray<TransformStreamHandle> bones; public NativeArray<Quaternion> rotations; public float weight; public void ProcessRootMotion(AnimationStream stream) { } public void ProcessAnimation(AnimationStream stream) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (weight <= 0f) { return; } for (int i = 0; i < bones.Length; i++) { TransformStreamHandle val = bones[i]; if (((TransformStreamHandle)(ref val)).IsValid(stream)) { ((TransformStreamHandle)(ref val)).SetLocalRotation(stream, Quaternion.Slerp(((TransformStreamHandle)(ref val)).GetLocalRotation(stream), rotations[i], weight)); } } } } private PlayableGraph _graph; private AnimationScriptPlayable _playable; private NativeArray<TransformStreamHandle> _bones; private NativeArray<Quaternion> _rotations; private readonly Quaternion[] _sample; private readonly RowingAnimationProfile _profile; public bool IsAlive { get { //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (((PlayableGraph)(ref _graph)).IsValid()) { return PlayableExtensions.IsValid<AnimationScriptPlayable>(_playable); } return false; } } public HumanoidRowingLayer(Animator animator, RowingAnimationProfile profile) { //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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0126: 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_0133: 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_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_0162: Unknown result type (might be due to invalid IL or missing references) //IL_016d: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0185: 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_00df: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)animator) || !animator.isHuman || !Object.op_Implicit((Object)(object)animator.avatar) || !animator.avatar.isValid || !Object.op_Implicit((Object)(object)animator.runtimeAnimatorController)) { throw new InvalidOperationException("Crew rowing requires the native humanoid Animator."); } _profile = profile; _sample = (Quaternion[])(object)new Quaternion[profile.bones.Length]; try { _bones = new NativeArray<TransformStreamHandle>(profile.bones.Length, (Allocator)4, (NativeArrayOptions)1); _rotations = new NativeArray<Quaternion>(profile.bones.Length, (Allocator)4, (NativeArrayOptions)1); for (int i = 0; i < profile.bones.Length; i++) { Transform val = ((Component)animator).transform.Find(profile.bones[i]); if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("Unsupported character rig: missing " + profile.bones[i]); } _bones[i] = AnimatorJobExtensions.BindStreamTransform(animator, val); _rotations[i] = val.localRotation; } _graph = PlayableGraph.Create("Better Rowing crew animation"); ((PlayableGraph)(ref _graph)).SetTimeUpdateMode((DirectorUpdateMode)1); _playable = AnimationScriptPlayable.Create<RowingJob>(_graph, new RowingJob { bones = _bones, rotations = _rotations, weight = 0f }, 0); ((AnimationScriptPlayable)(ref _playable)).SetProcessInputs(false); AnimationPlayableOutput val2 = AnimationPlayableOutput.Create(_graph, "Better Rowing upper body", animator); AnimationPlayableOutputExtensions.SetAnimationStreamSource(val2, (AnimationStreamSource)1); AnimationPlayableOutputExtensions.SetSortingOrder(val2, (ushort)1000); PlayableOutputExtensions.SetSourcePlayable<AnimationPlayableOutput, AnimationScriptPlayable>(val2, _playable); ((PlayableGraph)(ref _graph)).Play(); } catch { Dispose(); throw; } } public void Sample(float phase, bool reverse, float weight) { //IL_0038: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (!IsAlive) { throw new InvalidOperationException("The rowing animation job was disposed."); } _profile.Pose(phase, reverse, _sample); for (int i = 0; i < _sample.Length; i++) { _rotations[i] = _sample[i]; } ((AnimationScriptPlayable)(ref _playable)).SetJobData<RowingJob>(new RowingJob { bones = _bones, rotations = _rotations, weight = Mathf.Clamp01(weight) }); } public void Dispose() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (((PlayableGraph)(ref _graph)).IsValid()) { ((PlayableGraph)(ref _graph)).Destroy(); } _graph = default(PlayableGraph); if (_bones.IsCreated) { _bones.Dispose(); } if (_rotations.IsCreated) { _rotations.Dispose(); } } } internal static class OarAsset { [Serializable] private sealed class Data { public int schema; public float[] positions = Array.Empty<float>(); public float[] colors = Array.Empty<float>(); public int[] triangles = Array.Empty<int>(); public int[] groups = Array.Empty<int>(); } private static Mesh _mesh; private static readonly Dictionary<string, Material[]> _materials = new Dictionary<string, Material[]>(); private static Texture2D _wood; internal static float BladeReach { get { //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_0024: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)_mesh)) { return 4f; } Bounds bounds = _mesh.bounds; return Mathf.Max(0.1f, ((Bounds)(ref bounds)).max.x); } } internal static GameObject Create(Transform parent, string boat, string seat, int side) { //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_014b: 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: Expected O, but got Unknown //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_009c: Unknown result type (might be due to invalid IL or missing references) EnsureLoaded(); int variant = RowingOarStyle.Variant(boat, seat, side); string key = boat + "/" + variant; if (!_materials.TryGetValue(key, out var value)) { Material template = null; float num = -1f; MeshRenderer[] componentsInChildren = ((Component)parent).GetComponentsInChildren<MeshRenderer>(); foreach (MeshRenderer val in componentsInChildren) { if (((Object)val).name.StartsWith("BetterRowing", StringComparison.Ordinal) || Object.op_Implicit((Object)(object)((Component)val).GetComponentInParent<Player>())) { continue; } Bounds bounds = ((Renderer)val).bounds; Vector3 size = ((Bounds)(ref bounds)).size; float num2 = size.x * size.y * size.z; Material[] sharedMaterials = ((Renderer)val).sharedMaterials; foreach (Material val2 in sharedMaterials) { if (Object.op_Implicit((Object)(object)val2) && val2.renderQueue < 3000 && val2.HasProperty("_Color") && val2.HasProperty("_MainTex") && num2 > num) { template = val2; num = num2; } } } value = RowingOarStyle.Materials(template, _wood, boat, variant); _materials.Add(key, value); } GameObject val3 = new GameObject("BetterRowing_OriginalOar"); val3.transform.SetParent(parent, false); val3.AddComponent<MeshFilter>().sharedMesh = _mesh; ((Renderer)val3.AddComponent<MeshRenderer>()).sharedMaterials = value; return val3; } private static void EnsureLoaded() { //IL_007e: 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_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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown if (Object.op_Implicit((Object)(object)_mesh)) { return; } Data data; using (Stream stream = typeof(OarAsset).Assembly.GetManifestResourceStream("BetterRowing.oar.json")) { data = RowingJson.Read<Data>(stream); } if (data.schema != 1 || data.positions.Length % 3 != 0 || data.triangles.Length % 3 != 0 || data.groups.Length != data.triangles.Length / 3) { throw new InvalidDataException("Invalid oar mesh schema."); } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, true) { name = "BetterRowing_OriginalWeatheredWood", wrapMode = (TextureWrapMode)0, filterMode = (FilterMode)1, anisoLevel = 2 }; try { using (Stream stream2 = typeof(OarAsset).Assembly.GetManifestResourceStream("BetterRowing.oar-weathered-wood.png")) { using MemoryStream memoryStream = new MemoryStream(); if (stream2 == null) { throw new InvalidDataException("Missing original oar wood texture."); } stream2.CopyTo(memoryStream); MethodInfo method = typeof(ImageConversion).GetMethod("LoadImage", new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }); if (method == null || !(bool)method.Invoke(null, new object[3] { val, memoryStream.ToArray(), true })) { throw new InvalidDataException("Oar wood texture did not load."); } } _mesh = RowingOarStyle.BuildMesh(data.positions, data.triangles, data.groups); _wood = val; } catch { Object.Destroy((Object)(object)val); throw; } } internal static void Release() { if (Object.op_Implicit((Object)(object)_mesh)) { Object.Destroy((Object)(object)_mesh); } foreach (Material[] value in _materials.Values) { foreach (Material val in value) { if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } } } if (Object.op_Implicit((Object)(object)_wood)) { Object.Destroy((Object)(object)_wood); } _mesh = null; _wood = null; _materials.Clear(); } } public static class OarPortFrames { public static GameObject Create(Transform boat, RowingPortData[] ports, Material wood) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_0050: 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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_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_0086: 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_00a8: 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_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_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_00dc: 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) GameObject val = new GameObject("BetterRowing_OarPorts"); val.transform.SetParent(boat, false); Mesh mesh = Cube(); foreach (RowingPortData obj in ports) { Vector3 position = obj.position; Vector3 size = obj.size; float num = 0.025f; for (int j = -1; j <= 1; j += 2) { Beam(val.transform, mesh, wood, position + Vector3.up * (float)j * (size.y / 2f + num / 2f), new Vector3(0.12f, num, size.z + num * 2f)); Beam(val.transform, mesh, wood, position + Vector3.forward * (float)j * (size.z / 2f + num / 2f), new Vector3(0.12f, size.y, num)); } } return val; } private static void Beam(Transform parent, Mesh mesh, Material material, Vector3 position, Vector3 size) { //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_0017: 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_0023: 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_0030: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Original wooden port sleeve"); val.transform.SetParent(parent, false); val.transform.localPosition = position; val.transform.localScale = size; val.AddComponent<MeshFilter>().sharedMesh = mesh; ((Renderer)val.AddComponent<MeshRenderer>()).sharedMaterial = material; } private static Mesh Cube() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //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_0046: 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_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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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_00a6: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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_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_00ef: 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_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_0114: 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_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) Mesh val = new Mesh { name = "BetterRowing_PortSleeveCube" }; Vector3[] array = (Vector3[])(object)new Vector3[24]; Vector3[] array2 = (Vector3[])(object)new Vector3[24]; Vector2[] array3 = (Vector2[])(object)new Vector2[24]; int[] array4 = new int[36]; Vector3[] array5 = (Vector3[])(object)new Vector3[6] { Vector3.right, Vector3.left, Vector3.up, Vector3.down, Vector3.forward, Vector3.back }; for (int i = 0; i < 6; i++) { Vector3 val2 = array5[i]; Vector3 val3 = ((i < 2) ? Vector3.forward : Vector3.right); Vector3 val4 = Vector3.Cross(val2, val3); for (int j = 0; j < 4; j++) { float num = ((j != 0 && j != 3) ? 1 : (-1)); float num2 = ((j >= 2) ? 1 : (-1)); array[i * 4 + j] = (val2 + val3 * num + val4 * num2) * 0.5f; array2[i * 4 + j] = val2; array3[i * 4 + j] = new Vector2((num + 1f) / 2f, (num2 + 1f) / 2f); } int num3 = i * 4; int num4 = i * 6; array4[num4] = num3; array4[num4 + 1] = num3 + 1; array4[num4 + 2] = num3 + 2; array4[num4 + 3] = num3; array4[num4 + 4] = num3 + 2; array4[num4 + 5] = num3 + 3; } val.vertices = array; val.normals = array2; val.uv = array3; val.triangles = array4; val.RecalculateBounds(); return val; } } public static class OarPortMesh { private struct Vertex { public Vector3 p; public Vector3 n; public Vector2 uv; public Vector2 uv2; public Vector4 tangent; public Color color; public static Vertex Lerp(Vertex a, Vertex b, float t) { //IL_000b: 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_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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_003d: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_009c: 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) Vertex result = new Vertex { p = Vector3.Lerp(a.p, b.p, t) }; Vector3 val = Vector3.Lerp(a.n, b.n, t); result.n = ((Vector3)(ref val)).normalized; result.uv = Vector2.Lerp(a.uv, b.uv, t); result.uv2 = Vector2.Lerp(a.uv2, b.uv2, t); result.tangent = Vector4.Lerp(a.tangent, b.tangent, t); result.color = Color.Lerp(a.color, b.color, t); return result; } } public static Mesh Cut(Mesh source, Matrix4x4 meshToBoat, Bounds[] ports, bool revealBackfaces = false) { //IL_0012: 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_008d: 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_009c: 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_0470: Unknown result type (might be due to invalid IL or missing references) //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Unknown result type (might be due to invalid IL or missing references) //IL_0494: Expected O, but got Unknown //IL_00c4: 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_00c9: 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_018d: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: 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_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0268: 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_01eb: 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_01f4: 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_0122: 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_0127: 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_0289: 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_0307: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0313: 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_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0324: 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_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03c4: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Unknown result type (might be due to invalid IL or missing references) if (!source.isReadable) { Mesh val = ReadGpuCopy(source); try { return Cut(val, meshToBoat, ports, revealBackfaces); } finally { if (Application.isPlaying) { Object.Destroy((Object)(object)val); } else { Object.DestroyImmediate((Object)(object)val); } } } Vector3[] vertices = source.vertices; Vector3[] normals = source.normals; Vector2[] uv = source.uv; Vector2[] uv2 = source.uv2; Vector4[] tangents = source.tangents; Color[] colors = source.colors; Vertex[] array = new Vertex[vertices.Length]; for (int i = 0; i < array.Length; i++) { array[i] = new Vertex { p = vertices[i], n = ((normals.Length == vertices.Length) ? normals[i] : Vector3.up), uv = ((uv.Length == vertices.Length) ? uv[i] : Vector2.zero), uv2 = ((uv2.Length == vertices.Length) ? uv2[i] : Vector2.zero), tangent = ((tangents.Length == vertices.Length) ? tangents[i] : Vector4.zero), color = ((colors.Length == vertices.Length) ? colors[i] : Color.white) }; } List<Vertex> list = new List<Vertex>(); List<int[]> list2 = new List<int[]>(); Bounds val2 = default(Bounds); for (int j = 0; j < source.subMeshCount; j++) { int[] triangles = source.GetTriangles(j); List<int> list3 = new List<int>(); for (int k = 0; k < triangles.Length; k += 3) { ((Bounds)(ref val2))..ctor(((Matrix4x4)(ref meshToBoat)).MultiplyPoint3x4(array[triangles[k]].p), Vector3.zero); ((Bounds)(ref val2)).Encapsulate(((Matrix4x4)(ref meshToBoat)).MultiplyPoint3x4(array[triangles[k + 1]].p)); ((Bounds)(ref val2)).Encapsulate(((Matrix4x4)(ref meshToBoat)).MultiplyPoint3x4(array[triangles[k + 2]].p)); bool flag = false; Bounds[] array2; if (revealBackfaces) { array2 = ports; for (int l = 0; l < array2.Length; l++) { Bounds val3 = array2[l]; if (((Bounds)(ref val3)).Intersects(val2)) { flag = true; break; } } } List<List<Vertex>> list4 = new List<List<Vertex>> { new List<Vertex> { array[triangles[k]], array[triangles[k + 1]], array[triangles[k + 2]] } }; array2 = ports; foreach (Bounds box in array2) { List<List<Vertex>> list5 = new List<List<Vertex>>(); foreach (List<Vertex> item2 in list4) { Subtract(item2, meshToBoat, box, list5); } list4 = list5; } foreach (List<Vertex> item3 in list4) { for (int m = 1; m + 1 < item3.Count; m++) { Vertex vertex = item3[0]; Vertex vertex2 = item3[m]; Vertex vertex3 = item3[m + 1]; Vector3 val4 = Vector3.Cross(vertex2.p - vertex.p, vertex3.p - vertex.p); if (((Vector3)(ref val4)).sqrMagnitude < 1E-16f) { continue; } list3.Add(list.Count); list.Add(vertex); list3.Add(list.Count); list.Add(vertex2); list3.Add(list.Count); list.Add(vertex3); if (flag) { Vertex[] array3 = new Vertex[3] { vertex3, vertex2, vertex }; for (int l = 0; l < array3.Length; l++) { Vertex item = array3[l]; item.n = -item.n; item.tangent.w = 0f - item.tangent.w; list3.Add(list.Count); list.Add(item); } } } } } list2.Add(list3.ToArray()); } Mesh val5 = new Mesh { name = ((Object)source).name + "_BetterRowingPorts", indexFormat = (IndexFormat)1 }; val5.SetVertices(list.ConvertAll((Vertex v) => v.p)); val5.SetNormals(list.ConvertAll((Vertex v) => v.n)); if (uv.Length == vertices.Length) { val5.SetUVs(0, list.ConvertAll((Vertex v) => v.uv)); } if (uv2.Length == vertices.Length) { val5.SetUVs(1, list.ConvertAll((Vertex v) => v.uv2)); } if (tangents.Length == vertices.Length) { val5.SetTangents(list.ConvertAll((Vertex v) => v.tangent)); } if (colors.Length == vertices.Length) { val5.SetColors(list.ConvertAll((Vertex v) => v.color)); } val5.subMeshCount = list2.Count; for (int num = 0; num < list2.Count; num++) { val5.SetTriangles(list2[num], num); } val5.RecalculateBounds(); return val5; } private static Mesh ReadGpuCopy(Mesh source) { //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_002e: Expected O, but got Unknown //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_00b1: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_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_0128: 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_0154: 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_015f: 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_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017a: 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_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_018d: Unknown result type (might be due to invalid IL or missing references) if (!SystemInfo.supportsAsyncGPUReadback) { throw new InvalidOperationException("This graphics device cannot read the Drakkar hull for cosmetic ports."); } Mesh val = new Mesh { name = ((Object)source).name + "_RowingReadback" }; try { val.SetVertexBufferParams(source.vertexCount, source.GetVertexAttributes()); for (int i = 0; i < source.vertexBufferCount; i++) { GraphicsBuffer vertexBuffer = source.GetVertexBuffer(i); try { AsyncGPUReadbackRequest val2 = AsyncGPUReadback.Request(vertexBuffer, (Action<AsyncGPUReadbackRequest>)null); ((AsyncGPUReadbackRequest)(ref val2)).WaitForCompletion(); if (((AsyncGPUReadbackRequest)(ref val2)).hasError) { throw new InvalidOperationException("Could not read boat vertex buffer."); } NativeArray<byte> data = ((AsyncGPUReadbackRequest)(ref val2)).GetData<byte>(0); val.SetVertexBufferData<byte>(data, 0, 0, data.Length, i, (MeshUpdateFlags)9); } finally { ((IDisposable)vertexBuffer)?.Dispose(); } } GraphicsBuffer indexBuffer = source.GetIndexBuffer(); try { AsyncGPUReadbackRequest val3 = AsyncGPUReadback.Request(indexBuffer, (Action<AsyncGPUReadbackRequest>)null); ((AsyncGPUReadbackRequest)(ref val3)).WaitForCompletion(); if (((AsyncGPUReadbackRequest)(ref val3)).hasError) { throw new InvalidOperationException("Could not read boat index buffer."); } NativeArray<byte> data2 = ((AsyncGPUReadbackRequest)(ref val3)).GetData<byte>(0); val.SetIndexBufferParams(indexBuffer.count, source.indexFormat); val.SetIndexBufferData<byte>(data2, 0, 0, data2.Length, (MeshUpdateFlags)9); } finally { ((IDisposable)indexBuffer)?.Dispose(); } val.subMeshCount = source.subMeshCount; for (int j = 0; j < source.subMeshCount; j++) { val.SetSubMesh(j, source.GetSubMesh(j), (MeshUpdateFlags)9); } val.RecalculateBounds(); Bounds bounds = val.bounds; Vector3 center = ((Bounds)(ref bounds)).center; bounds = source.bounds; if (!(Vector3.Distance(center, ((Bounds)(ref bounds)).center) > 0.1f)) { bounds = val.bounds; Vector3 size = ((Bounds)(ref bounds)).size; bounds = source.bounds; if (!(Vector3.Distance(size, ((Bounds)(ref bounds)).size) > 0.1f)) { return val; } } throw new InvalidOperationException("Boat GPU copy bounds do not match the source."); } catch { if (Application.isPlaying) { Object.Destroy((Object)(object)val); } else { Object.DestroyImmediate((Object)(object)val); } throw; } } private static void Subtract(List<Vertex> polygon, Matrix4x4 matrix, Bounds box, List<List<Vertex>> outside) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) Bounds val = default(Bounds); ((Bounds)(ref val))..ctor(((Matrix4x4)(ref matrix)).MultiplyPoint3x4(polygon[0].p), Vector3.zero); foreach (Vertex item in polygon) { ((Bounds)(ref val)).Encapsulate(((Matrix4x4)(ref matrix)).MultiplyPoint3x4(item.p)); } if (!((Bounds)(ref val)).Intersects(box)) { outside.Add(polygon); return; } List<Vertex> list = polygon; for (int i = 0; i < 3; i++) { if (list.Count < 3) { break; } for (int j = -1; j <= 1; j += 2) { if (list.Count < 3) { break; } Vector3 val2; float num; if (j >= 0) { val2 = ((Bounds)(ref box)).max; num = ((Vector3)(ref val2))[i]; } else { val2 = ((Bounds)(ref box)).min; num = 0f - ((Vector3)(ref val2))[i]; } float edge = num; Split(list, matrix, i, j, edge, out var inside, out var outside2); if (outside2.Count >= 3) { outside.Add(outside2); } list = inside; } } } private static void Split(List<Vertex> polygon, Matrix4x4 matrix, int axis, int sign, float edge, out List<Vertex> inside, out List<Vertex> outside) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_005f: Unknown result type (might be due to invalid IL or missing references) inside = new List<Vertex>(); outside = new List<Vertex>(); Vertex a = polygon[polygon.Count - 1]; Vector3 val = ((Matrix4x4)(ref matrix)).MultiplyPoint3x4(a.p); float num = ((Vector3)(ref val))[axis] * (float)sign - edge; foreach (Vertex item2 in polygon) { val = ((Matrix4x4)(ref matrix)).MultiplyPoint3x4(item2.p); float num2 = ((Vector3)(ref val))[axis] * (float)sign - edge; if (num <= 0f != num2 <= 0f) { Vertex item = Vertex.Lerp(a, item2, num / (num - num2)); inside.Add(item); outside.Add(item); } if (num2 <= 0f) { inside.Add(item2); } else { outside.Add(item2); } a = item2; num = num2; } } } public sealed class OarPorts : MonoBehaviour { private OarPortVisuals _visuals; private bool _failed; private Ship _ship; internal static void Attach(Ship ship) { if (!Application.isBatchMode && Object.op_Implicit((Object)(object)Plugin.Instance) && Object.op_Implicit((Object)(object)ship) && RowingSeatSupport.VisualBoats.Contains(Utils.GetPrefabName(((Component)ship).gameObject)) && !Object.op_Implicit((Object)(object)((Component)ship).GetComponent<OarPorts>())) { ((Component)ship).gameObject.AddComponent<OarPorts>(); } } private void Awake() { _ship = ((Component)this).GetComponent<Ship>(); _visuals = new OarPortVisuals(((Component)this).transform, (MeshFilter f) => Object.op_Implicit((Object)(object)((Component)f).GetComponentInParent<Player>(true))); } private void Start() { Refresh(); } internal static bool Ensure(Ship ship) { if (Application.isBatchMode || !Object.op_Implicit((Object)(object)Plugin.Instance) || !Plugin.Instance.AnimatedOars.Value || !Object.op_Implicit((Object)(object)ship)) { return false; } OarPorts oarPorts = ((Component)ship).GetComponent<OarPorts>(); if (!Object.op_Implicit((Object)(object)oarPorts)) { oarPorts = ((Component)ship).gameObject.AddComponent<OarPorts>(); } if (oarPorts._visuals.Installed) { return true; } if (oarPorts._failed) { return false; } try { oarPorts._visuals.Show(RowingAnimationAssets.Ports(Utils.GetPrefabName(((Component)ship).gameObject)), OarPortWaterMask.LoadShader()); return true; } catch (Exception ex) { oarPorts._visuals.Hide(); oarPorts._failed = true; Plugin.Instance.WarnVisual("Oar ports unavailable on " + Utils.GetPrefabName(((Component)ship).gameObject) + "; crew visuals hidden: " + ex); return false; } } private void Update() { Refresh(); } private void Refresh() { if (!Object.op_Implicit((Object)(object)Plugin.Instance) || !Plugin.Instance.AnimatedOars.Value) { if (_visuals.Installed) { _visuals.Hide(); } _failed = false; } else if (!_visuals.Installed && !_failed && Object.op_Implicit((Object)(object)_ship)) { Ensure(_ship); } } internal static void StopAll() { OarPorts[] array = Object.FindObjectsByType<OarPorts>((FindObjectsSortMode)0); foreach (OarPorts obj in array) { obj._visuals.Dispose(); Object.Destroy((Object)(object)obj); } } private void OnDestroy() { _visuals?.Dispose(); } } public sealed class OarPortVisuals : IDisposable { private readonly Transform _boat; private readonly Func<MeshFilter, bool> _exclude; private readonly List<MeshFilter> _filters = new List<MeshFilter>(); private readonly List<Mesh> _originals = new List<Mesh>(); private readonly List<Mesh> _copies = new List<Mesh>(); private readonly List<MeshRenderer> _maskRenderers = new List<MeshRenderer>(); private readonly List<Material[]> _maskOriginals = new List<Material[]>(); private readonly List<Material[]> _maskCopies = new List<Material[]>(); private GameObject _frames; private Mesh _frameMesh; public bool Installed { get; private set; } public OarPortVisuals(Transform boat, Func<MeshFilter, bool> exclude = null) { _boat = boat; _exclude = exclude; } public void Show(RowingPortData[] ports, Shader waterShader) { if (Installed) { return; } try { Install(ports, waterShader); Installed = true; } catch { Hide(); throw; } } private void Install(RowingPortData[] ports, Shader waterShader) { //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_0116: 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_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_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) if (ports.Length == 0) { throw new InvalidOperationException("No fitted oar-port layout for this boat."); } Bounds[] array = ports.SelectMany((RowingPortData p) => p.Cutters).ToArray(); MeshFilter[] array2 = (from f in ((Component)_boat).GetComponentsInChildren<MeshFilter>(true) where Object.op_Implicit((Object)(object)f.sharedMesh) && (_exclude == null || !_exclude(f)) && !((Object)f).name.StartsWith("BetterRowing", StringComparison.Ordinal) select f).ToArray(); foreach (MeshFilter val in array2) { if (OarPortWaterMask.IsMask(val)) { MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>(); Material[] sharedMaterials = ((Renderer)component).sharedMaterials; Material[] array3 = (Material[])(object)new Material[sharedMaterials.Length]; _maskRenderers.Add(component); _maskOriginals.Add(sharedMaterials); _maskCopies.Add(array3); for (int num2 = 0; num2 < array3.Length; num2++) { array3[num2] = OarPortWaterMask.Create(sharedMaterials[num2], waterShader, ((Component)val).transform, _boat, ports); } ((Renderer)component).sharedMaterials = array3; } else { Matrix4x4 val2 = _boat.worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix; Mesh sharedMesh = val.sharedMesh; Bounds bounds = BoatBounds(sharedMesh.bounds, val2); if (array.Any((Bounds b) => ((Bounds)(ref b)).Intersects(bounds))) { Mesh val3 = OarPortMesh.Cut(sharedMesh, val2, array, revealBackfaces: true); _filters.Add(val); _originals.Add(sharedMesh); _copies.Add(val3); val.sharedMesh = val3; } } } if (_copies.Count == 0) { throw new InvalidOperationException("Port layout does not intersect this boat's meshes."); } Material wood = null; foreach (MeshFilter filter in _filters) { MeshRenderer component2 = ((Component)filter).GetComponent<MeshRenderer>(); if (Object.op_Implicit((Object)(object)component2) && Object.op_Implicit((Object)(object)((Renderer)component2).sharedMaterial)) { wood = ((Renderer)component2).sharedMaterial; break; } } _frames = OarPortFrames.Create(_boat, ports, wood); _frameMesh = _frames.GetComponentInChildren<MeshFilter>().sharedMesh; } private static Bounds BoatBounds(Bounds source, Matrix4x4 matrix) { //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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_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) Bounds result = default(Bounds); ((Bounds)(ref result))..ctor(((Matrix4x4)(ref matrix)).MultiplyPoint3x4(((Bounds)(ref source)).center), Vector3.zero); for (int i = 0; i < 8; i++) { ((Bounds)(ref result)).Encapsulate(((Matrix4x4)(ref matrix)).MultiplyPoint3x4(((Bounds)(ref source)).center + Vector3.Scale(((Bounds)(ref source)).extents, new Vector3((float)(((i & 1) != 0) ? 1 : (-1)), (float)(((i & 2) != 0) ? 1 : (-1)), (float)(((i & 4) != 0) ? 1 : (-1)))))); } return result; } public void Hide() { for (int i = 0; i < _maskRenderers.Count; i++) { if (!Object.op_Implicit((Object)(object)_maskRenderers[i])) { continue; } Material[] sharedMaterials = ((Renderer)_maskRenderers[i]).sharedMaterials; for (int j = 0; j < sharedMaterials.Length && j < _maskCopies[i].Length; j++) { if ((Object)(object)sharedMaterials[j] == (Object)(object)_maskCopies[i][j]) { sharedMaterials[j] = _maskOriginals[i][j]; } } ((Renderer)_maskRenderers[i]).sharedMaterials = sharedMaterials; } foreach (Material[] maskCopy in _maskCopies) { for (int k = 0; k < maskCopy.Length; k++) { Destroy((Object)(object)maskCopy[k]); } } _maskRenderers.Clear(); _maskOriginals.Clear(); _maskCopies.Clear(); for (int l = 0; l < _filters.Count; l++) { if (Object.op_Implicit((Object)(object)_filters[l]) && (Object)(object)_filters[l].sharedMesh == (Object)(object)_copies[l]) { _filters[l].sharedMesh = _originals[l]; } } foreach (Mesh copy in _copies) { Destroy((Object)(object)copy); } _filters.Clear(); _originals.Clear(); _copies.Clear(); Destroy((Object)(object)_frames); Destroy((Object)(object)_frameMesh); _frames = null; _frameMesh = null; Installed = false; } public void Dispose() { Hide(); } private static void Destroy(Object value) { if (Object.op_Implicit(value)) { if (Application.isPlaying) { Object.Destroy(value); } else { Object.DestroyImmediate(value); } } } } public static class OarPortWaterMask { public const string ShaderName = "BetterRowing/WaterMaskWithPorts"; public const string ShaderPath = "Assets/BetterRowing/Rendering/OarPortWaterMask.shader"; private static AssetBundle _bundle; private static Shader _shader; public static bool IsMask(MeshFilter filter) { MeshRenderer component = ((Component)filter).GetComponent<MeshRenderer>(); if (!Object.op_Implicit((Object)(object)component)) { return false; } Material[] sharedMaterials = ((Renderer)component).sharedMaterials; foreach (Material val in sharedMaterials) { if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.shader) && (((Object)val.shader).name == "Custom/WaterMask" || ((Object)val.shader).name == "BetterRowing/WaterMaskWithPorts")) { return true; } } return ((Object)filter).name.IndexOf("watermask", StringComparison.OrdinalIgnoreCase) >= 0; } public static Material Create(Material original, Shader shader, Transform mask, Transform boat, RowingPortData[] ports) { //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_0044: Expected O, but got Unknown //IL_0066: 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_00c1: 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_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)shader) || !shader.isSupported) { throw new InvalidOperationException("Oar-port water-mask shader unavailable."); } if (ports.Length == 0 || ports.Length > 8) { throw new InvalidOperationException("Unexpected water-mask port count."); } Material val = new Material(shader) { name = "BetterRowing_PortWaterMask" }; val.renderQueue = (Object.op_Implicit((Object)(object)original) ? original.renderQueue : 2899); val.SetMatrix("_MaskToBoat", boat.worldToLocalMatrix * mask.localToWorldMatrix); Vector4[] array = (Vector4[])(object)new Vector4[8]; Vector4[] array2 = (Vector4[])(object)new Vector4[8]; for (int i = 0; i < ports.Length; i++) { RowingPortData rowingPortData = ports[i]; array[i] = new Vector4(rowingPortData.position.x, rowingPortData.position.y, rowingPortData.position.z, (float)rowingPortData.side); array2[i] = new Vector4(rowingPortData.size.y * 0.5f, rowingPortData.size.z * 0.5f, 0f, 0f); } val.SetInt("_PortCount", ports.Length); val.SetVectorArray("_PortCentres", array); val.SetVectorArray("_PortSizes", array2); return val; } internal static Shader LoadShader() { if (Object.op_Implicit((Object)(object)_shader)) { return _shader; } using (Stream stream = typeof(OarPortWaterMask).Assembly.GetManifestResourceStream("BetterRowing.rendering.bundle")) { using MemoryStream memoryStream = new MemoryStream(); if (stream == null) { throw new InvalidDataException("Missing port water rendering resource."); } stream.CopyTo(memoryStream); _bundle = AssetBundle.LoadFromMemory(memoryStream.ToArray()); } if (!Object.op_Implicit((Object)(object)_bundle)) { throw new InvalidDataException("Could not load port water rendering resource."); } _shader = _bundle.LoadAsset<Shader>("Assets/BetterRowing/Rendering/OarPortWaterMask.shader"); if (!Object.op_Implicit((Object)(object)_shader) || !_shader.isSupported) { Release(); throw new InvalidDataException("Port water rendering is unsupported on this graphics device."); } return _shader; } internal static void Release() { if (Object.op_Implicit((Object)(object)_bundle)) { _bundle.Unload(true); } _bundle = null; _shader = null; } } [BepInPlugin("curti.valheim.betterrowing", "Better Rowing", "0.3.26")] [BepInDependency("com.jotunn.jotunn", "2.30.2")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "curti.valheim.betterrowing"; public const string Version = "0.3.26"; internal static Plugin Instance; internal static SkillType RowingSkill; internal ConfigEntry<float> Period; internal ConfigEntry<float> Window; internal ConfigEntry<float> Perfect; internal ConfigEntry<float> HelmDrain; internal ConfigEntry<float> StrokeCost; internal ConfigEntry<float> HelmPower; internal ConfigEntry<float> CrewPower; internal ConfigEntry<float> Yaw; internal ConfigEntry<float> SpeedCap; internal ConfigEntry<float> HudY; internal ConfigEntry<float> RaftSpeedCap; internal ConfigEntry<float> KarveSpeedCap; internal ConfigEntry<float> LongshipSpeedCap; internal ConfigEntry<float> DrakkarSpeedCap; internal ConfigEntry<bool> ShowHud; internal ConfigEntry<bool> ShowCrewHud; internal ConfigEntry<bool> AnimatedOars; internal ConfigEntry<bool> AnimateBody; internal ConfigEntry<bool> AdaptToWaves; internal ConfigEntry<bool> WaterEffects; internal ConfigEntry<bool> RowingSounds; internal ConfigEntry<float> RowingVolume; internal ConfigEntry<bool> BeatSound; internal ConfigEntry<float> BeatVolume; internal ConfigEntry<bool> SoloPreview; internal ConfigEntry<bool> SoloTest; private Harmony _harmony; private Texture2D _iconTexture; private Sprite _icon; internal void LoggerForNetwork(string message) { ((BaseUnityPlugin)this).Logger.LogDebug((object)message); } internal void WarnVisual(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); } private ConfigEntry<float> Number(string key, float value, float min, float max, string description) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<float>("Rowing", key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), Array.Empty<object>())); } private void Awake() { //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Expected O, but got Unknown //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Expected O, but got Unknown //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Expected O, but got Unknown //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Expected O, but got Unknown //IL_04b0: Unknown result type (might be due to invalid IL or missing references) //IL_04bf: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: Unknown result type (might be due to invalid IL or missing references) //IL_04d8: Unknown result type (might be due to invalid IL or missing references) //IL_04e3: 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_04fa: Unknown result type (might be due to invalid IL or missing references) //IL_0505: Unknown result type (might be due to invalid IL or missing references) //IL_0515: Expected O, but got Unknown //IL_0510: Unknown result type (might be due to invalid IL or missing references) //IL_0515: Unknown result type (might be due to invalid IL or missing references) //IL_046e: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) Instance = this; if (!Application.isBatchMode) { RowingDrumPattern.WarmUp(); } Period = Number("BeatInterval", 1.2f, 0.8f, 3f, "Seconds between crew strokes. Ship owner publishes timing and stamina settings to everyone aboard."); Window = Number("HitWindow", 0.22f, 0.08f, 0.35f, "Allowed seconds before or after a beat."); Perfect = Number("PerfectWindow", 0.08f, 0.02f, 0.15f, "Perfect timing window in seconds, limited to HitWindow."); HelmDrain = Number("CaptainStaminaPerSecond", 6.5f, 1f, 30f, "Stamina per second of Shift rowing at skill zero. Skill 100 costs 40% less."); StrokeCost = Number("CrewStaminaPerStroke", 6.5f, 1f, 60f, "Stamina per successful crew stroke at skill zero. Skill 100 costs 40% less; misses cost one quarter."); HelmPower = Number("CaptainExtraForce", 0.8f, 0.1f, 3f, "Extra thrust relative to vanilla rowing while holding Shift."); CrewPower = Number("CrewExtraForce", 0.65f, 0.1f, 2f, "Average thrust of each crew member relative to vanilla rowing."); Yaw = Number("SideTurningForce", 0.18f, 0f, 0.6f, "Yaw acceleration from each side's stroke. Port forward strokes turn starboard."); SpeedCap = Number("MaximumBoostedSpeed", 6f, 2f, 12f, "Fallback rowing-thrust cutoff for unrecognized boats in metres per second. Applies to native forward rowing and added thrust. Named boat limits override this; sailing and momentum are preserved."); RaftSpeedCap = Number("RaftMaximumBoostedSpeed", 2.5f, 1f, 12f, "Raft native-forward and added rowing-thrust cutoff in m/s. Tapers over the final 0.75 m/s; does not brake existing momentum."); KarveSpeedCap = Number("KarveMaximumBoostedSpeed", 3f, 1f, 12f, "Karve native-forward and added rowing-thrust cutoff in m/s, for captain and crew together."); LongshipSpeedCap = Number("LongshipMaximumBoostedSpeed", 4.5f, 1f, 12f, "Longship native-forward and added rowing-thrust cutoff in m/s. Extra crew and coordination help reach this; it is not a guaranteed speed."); DrakkarSpeedCap = Number("DrakkarMaximumBoostedSpeed", 4.8f, 1f, 12f, "Drakkar native-forward and added rowing-thrust cutoff in m/s, for captain and crew together."); ShowHud = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowHud", true, "Show the rowing rhythm HUD whenever at least one passenger is seated to row, with or without a helmsman."); ShowCrewHud = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowCrewHud", true, "Show seated crew timing grades and recent coordinated stroke bonuses with at least one rower. A helmsman is optional. Requires ShowHud."); AnimatedOars = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "AnimatedOars", true, "Render crew oars, fitted visual oar ports and owner-confirmed stroke animation. Client cosmetic setting; hull physics is unchanged."); AnimateBody = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "AnimateBody", true, "Humanoid upper-body rowing layer for supported crew seats. The captain keeps the native rudder pose. Disable for animation-mod compatibility."); AdaptToWaves = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "AdaptToWaves", true, "Sample live water at each crew blade and adapt oar pitch and arm reach to boat rocking. Extreme motion is limited by the fitted ports and arm reach. Client cosmetic setting."); WaterEffects = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "WaterEffects", true, "Crew blade entry spray, pull ripples and lift droplets at the live water surface. Client cosmetic setting."); RowingSounds = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "RowingSounds", true, "Spatial crew blade entry, submerged pull and lift sounds. Requires visible animated oars; respects game master/SFX volume."); RowingVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "RowingVolume", 0.65f, new ConfigDescription("Crew water sound volume multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); BeatSound = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "BeatSound", true, "Shared deep Norse-inspired drum cue while seated with sails raised and helm empty, or at forward/backward rowing speed with a captain. Independent of HUD/oars/water sounds; follows game master/SFX volume."); BeatVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "BeatVolume", 0.9f, new ConfigDescription("Listening volume for the 2x-gain acoustic drum mix, with peak protection. Zero mutes only this client's cue.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); HudY = ((BaseUnityPlugin)this).Config.Bind<float>("Display", "VerticalPosition", 0.76f, new ConfigDescription("Legacy setting; the compact rhythm HUD now follows the minimap.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 0.9f), Array.Empty<object>())); SoloPreview = ((BaseUnityPlugin)this).Config.Bind<bool>("Development", "EnableSoloPreview", false, "F8 toggles automatic seated rowing visuals in a closed single-player world. Hold Ctrl for back-rowing. No thrust, stamina use or XP. Ends when leaving the seat; disabled in multiplayer."); SoloTest = ((BaseUnityPlugin)this).Config.Bind<bool>("Development", "EnableSoloRowingTest", false, "F9 enables manual seated rowing in closed single-player with the boat stopped and helm empty. Shift on the beat / Ctrl+Shift use real stamina and crew force without XP. No automatic captain thrust. Ends on dismount, helm use, speed change, menus/focus loss, ownership loss or multiplayer. Local testing only."); _iconTexture = new Texture2D(64, 64, (TextureFormat)4, false); for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { bool flag = Mathf.Abs(j - i) <= 2 && j > 9 && j < 55; bool flag2 = j > 8 && j < 28 && i > 8 && i < 28 && Mathf.Abs(j - i) < 9; _iconTexture.SetPixel(j, i, (Color)((flag || flag2) ? new Color(0.88f, 0.7f, 0.37f) : Color.clear)); } } _iconTexture.Apply(); _icon = Sprite.Create(_iconTexture, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f)); RowingSkill = SkillManager.Instance.AddSkill(new SkillConfig { Identifier = "curti.valheim.betterrowing.rowing", Name = "Rowing", Icon = _icon, IncreaseStep = 4f, Description = "Row faster and spend less stamina. Hold Shift at the helm while paddling forward or backward. Seated crew: tap Shift on the beat; Ctrl + Shift rows in the opposite direction. Chain Perfects for up to 1.5x rowing XP." }); _harmony = Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, "curti.valheim.betterrowing"); ((Component)this).gameObject.AddComponent<RowingInput>(); ((Component)this).gameObject.AddComponent<RowingSoloPreview>(); ((Component)this).gameObject.AddComponent<RowingSoloTest>(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Better Rowing 0.3.26 loaded. Rowing skill: " + ((object)Unsafe.As<SkillType, SkillType>(ref RowingSkill)/*cast due to .constrained prefix*/).ToString() + ".")); } private void OnDestroy() { RowingInput component = ((Component)this).GetComponent<RowingInput>(); if (Object.op_Implicit((Object)(object)component)) { ((Behaviour)component).enabled = false; Object.Destroy((Object)(object)component); } RowingSoloPreview component2 = ((Component)this).GetComponent<RowingSoloPreview>(); if (Object.op_Implicit((Object)(object)component2)) { ((Behaviour)component2).enabled = false; Object.Destroy((Object)(object)component2); } RowingSoloTest component3 = ((Component)this).GetComponent<RowingSoloTest>(); if (Object.op_Implicit((Object)(object)component3)) { ((Behaviour)component3).enabled = false; Object.Destroy((Object)(object)component3); } Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } RowingVisual.StopAll(); RowingWaterEffects.ReleaseAll(); OarPorts.StopAll(); OarPortWaterMask.Release(); RowingAnimationAssets.Release(); OarAsset.Release(); if (Object.op_Implicit((Object)(object)_icon)) { Object.Destroy((Object)(object)_icon); } if (Object.op_Implicit((Object)(object)_iconTexture)) { Object.Destroy((Object)(object)_iconTexture); } Instance = null; } } [HarmonyPatch(typeof(Ship), "Awake")] internal static class ShipAwakePatch { private static void Postfix(Ship __instance) { ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)Plugin.Instance) && Object.op_Implicit((Object)(object)component) && component.IsValid()) { if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<RowingShip>())) { ((Component)__instance).gameObject.AddComponent<RowingShip>(); } OarPorts.Attach(__instance); } } } [HarmonyPatch(typeof(Ship), "CustomFixedUpdate")] internal static class ShipPhysicsPatch { private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown FieldInfo fieldInfo = AccessTools.Field(typeof(Ship), "m_backwardForce"); MethodInfo methodInfo = AccessTools.Method(typeof(ShipPhysicsPatch), "NativePaddle", (Type[])null, (Type[])null); List<CodeInstruction> list = new List<CodeInstruction>(); int num = 0; foreach (CodeInstruction instruction in instructions) { list.Add(instruction); if (CodeInstructionExtensions.LoadsField(instruction, fieldInfo, false)) { list.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null)); list.Add(new CodeInstruction(OpCodes.Call, (object)methodInfo)); num++; } } if (num != 2) { throw new InvalidOperationException("Native rowing layout changed: expected forward/back paddle loads, found " + num); } return list; } private static float NativePaddle(float force, Ship ship) { return ((Component)ship).GetComponent<RowingShip>()?.NativePaddle(force) ?? force; } private static void Postfix(Ship __instance, float fixedDeltaTime) { ((Component)__instance).GetComponent<RowingShip>()?.Tick(fixedDeltaTime); } } [HarmonyPatch(typeof(Player), "SetControls")] internal static class SeatedControlsPatch { private static void Prefix(Player __instance, ref bool crouch, ref bool dodge) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && (Object)(object)RowingInput.FindSeatShip(__instance) != (Object)null) { crouch = false; if (RowingInput.ShiftHeld) { dodge = false; } } } } internal static class RowingAnimationAssets { private static RowingAnimationManifest _manifest; private static void EnsureLoaded() { if (_manifest != null) { return; } using (Stream stream = typeof(RowingAnimationAssets).Assembly.GetManifestResourceStream("BetterRowing.animations.json")) { _manifest = RowingJson.Read<RowingAnimationManifest>(stream); } try { if (_manifest.schema == 1) { RowingAnimationProfile[] profiles = _manifest.profiles; if (profiles != null && profiles.Length == 30) { RowingPortData[] ports = _manifest.ports; if (ports != null && ports.Length == 16) { RowingPortData[] ports2 = _manifest.ports; foreach (RowingPortData rowingPortData in ports2) { if (!rowingPortData.seat.StartsWith("interactive/sit_", StringComparison.Ordinal) || Math.Abs(rowingPortData.side) != 1 || rowingPortData.size.x <= 0f || rowingPortData.size.y <= 0f || rowingPortData.size.z <= 0f || !RowingMath.Finite(rowingPortData.cutSlope) || (rowingPortData.boat == "VikingShip_Ashlands" && (rowingPortData.cutSlope <= 0f || rowingPortData.cutSlope > 2f))) { throw new InvalidDataException("Invalid crew oar port."); } } RowingAnimationProfile[] profiles2 = _manifest.profiles; foreach (RowingAnimationProfile rowingAnimationProfile in profiles2) { int num = RowingSeatSupport.PoseSamples(rowingAnimationProfile.boat); if (!rowingAnimationProfile.seat.StartsWith("interactive/sit_", StringComparison.Ordinal) || rowingAnimationProfile.bones.Length == 0 || rowingAnimationProfile.forwardPoses.Length != num || rowingAnimationProfile.reversePoses.Length != num || rowingAnimationProfile.forwardOars.Length != num || rowingAnimationProfile.reverseOars.Length != num) { throw new InvalidDataException("Invalid crew pose profile."); } string[] bones = rowingAnimationProfile.bones; foreach (string text in bones) { if (!text.Contains("/Spine") || text.Contains("/Head") || text.Contains("/Neck")) { throw new InvalidDataException("Rowing poses must affect only the upper body."); } } RowingBoneFrame[][] array = new RowingBoneFrame[2][] { rowingAnimationProfile.forwardPoses, rowingAnimationProfile.reversePoses }; foreach (RowingBoneFrame[] array2 in array) { for (int k = 0; k < array2.Length; k++) { if (array2[k].rotations.Length != rowingAnimationProfile.bones.Length) { throw new InvalidDataException("Incomplete rowing bone frame."); } } } } return; } } } string[] obj = new string[7] { "Unsupported rowing pose/port manifest: schema=", _manifest.schema.ToString(), ", profiles=", null, null, null, null }; RowingAnimationProfile[] profiles3 = _manifest.profiles; obj[3] = ((profiles3 != null) ? profiles3.Length : 0).ToString(); obj[4] = ", ports="; RowingPortData[] ports3 = _manifest.ports; obj[5] = ((ports3 != null) ? ports3.Length : 0).ToString(); obj[6] = "."; throw new InvalidDataException(string.Concat(obj)); } catch { _manifest = null; throw; } } internal static RowingAnimationProfile Find(string boat, string seat, string body) { EnsureLoaded(); RowingAnimationProfile[] profiles = _manifest.profiles; foreach (RowingAnimationProfile rowingAnimationProfile in profiles) { if (rowingAnimationProfile.boat == boat && rowingAnimationProfile.seat == seat && rowingAnimationProfile.body == body) { return rowingAnimationProfile; } } return null; } internal static void Release() { _manifest = null; } internal static RowingPortData[] Ports(string boat) { EnsureLoaded(); List<RowingPortData> list = new List<RowingPortData>(); RowingPortData[] ports = _manifest.ports; foreach (RowingPortData rowingPortData in ports) { if (rowingPortData.boat == boat) { list.Add(rowingPortData); } } return list.ToArray(); } } [Serializable] public sealed class RowingAnimationManifest { public int schema = 1; public string editor = "6000.0.75f1"; public RowingAnimationProfile[] profiles = Array.Empty<RowingAnimationProfile>(); public RowingPortData[] ports = Array.Empty<RowingPortData>(); } [Serializable] public sealed class RowingPortData { public string boat; public string seat; public int side; public Vector3 position; public Vector3 size; public float cutSlope; public Bounds Bounds => new Bounds(position, size); public IEnumerable<Bounds> Cutters { get { yield return Bounds; if (!(boat != "VikingShip_Ashlands")) { for (int i = 0; i < 7; i++) { float num = 0.3f + (float)i * 0.2f; yield return new Bounds(position + new Vector3((float)(-side) * num, num * (cutSlope - 0.08f), 0f), new Vector3(0.22f, size.y + num * 0.22f, size.z + num * 0.12f)); } } } } } [Serializable] public sealed class RowingAnimationProfile { public string boat; public string seat; public string body; public int side; public float reach; public string[] bones = Array.Empty<string>(); public RowingBoneFrame[] forwardPoses = Array.Empty<RowingBoneFrame>(); public RowingBoneFrame[] reversePoses = Array.Empty<RowingBoneFrame>(); public RowingOarFrame[] forwardOars = Array.Empty<RowingOarFrame>(); public RowingOarFrame[] reverseOars = Array.Empty<RowingOarFrame>(); public RowingOarFrame Oars(float phase, bool back) { RowingOarFrame[] array = (back ? reverseOars : forwardOars); float num = Mathf.Clamp01(phase) * (float)(array.Length - 1); int num2 = Mathf.FloorToInt(num); int num3 = Mathf.Min(num2 + 1, array.Length - 1); return RowingOarFrame.Lerp(array[num2], array[num3], num - (float)num2); } public void Pose(float phase, bool back, Quaternion[] rotations) { //IL_0047: 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_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) RowingBoneFrame[] array = (back ? reversePoses : forwardPoses); float num = Mathf.Clamp01(phase) * (float)(array.Length - 1); int num2 = Mathf.FloorToInt(num); int num3 = Mathf.Min(num2 + 1, array.Length - 1); for (int i = 0; i < rotations.Length; i++) { rotations[i] = Quaternion.Slerp(array[num2].rotations[i], array[num3].rotations[i], num - (float)num2); } } } [Serializable] public sealed class RowingBoneFrame { public Quaternion[] rotations; } [Serializable] public struct RowingOarFrame { public Vector3 position; public Vector3 secondPosition; public Quaternion rotation; public Quaternion secondRotation; public static RowingOarFrame Lerp(RowingOarFrame a, RowingOarFrame b, float t) { //IL_000b: 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_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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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) //IL_0056: 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_0062: 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) return new RowingOarFrame { position = Vector3.Lerp(a.position, b.position, t), rotation = Quaternion.Slerp(a.rotation, b.rotation, t), secondPosition = Vector3.Lerp(a.secondPosition, b.secondPosition, t), secondRotation = Quaternion.Slerp(a.secondRotation, b.secondRotation, t) }; } } public sealed class RowingBeatAudio : IDisposable { private sealed class Voice { public AudioSource Source; public AudioClip[] Clips; public int Variation; public bool Pending; public double Due; public long LastBeat = -1L; public int Scheduled; public int Cancelled; private double _ownerDue; private readonly RowingBeatPlanner _planner = new RowingBeatPlanner(); public void Tick(RowingRhythm rhythm, double ownerTime, double dsp, double tolerance) { if (Pending) { if (dsp >= Due) { Pending = false; } else { double num = _ownerDue - ownerTime; double num2 = dsp + num; if (num < 0.0 - tolerance || num > 0.44999999999999996 || (Due - dsp <= 0.06 && Math.Abs(num2 - Due) > tolerance)) { Source.Stop(); Pending = false; Cancelled++; } else if (Due - dsp > 0.06 && num > 0.06 && Math.Abs(num2 - Due) > tolerance) { Source.SetScheduledStartTime(num2); Due = num2; } } } if (!Pending && _planner.Next(rhythm, ownerTime, dsp, out var beat, out var target)) { Variation = (int)(beat & 1); Source.clip = Clips[Variation]; Source.PlayScheduled(target); Due = target; _ownerDue = rhythm.At(beat); Pending = true; LastBeat = beat; Scheduled++; } } public void Stop() { if (Pending) { Cancelled++; } if (Object.op_Implicit((Object)(object)Source)) { Source.Stop(); } Pending = false; _planner.Reset(); } } public const int Rate = 48000; public const int Channels = 2; private readonly Voice _main = new Voice(); private readonly Voice _pickup = new Voice(); private GameObject _root; private AudioClip[] _clips; private AudioClip[] _pickupClips; private long _revision; private float _period; private float _window; private double _previousDsp = double.NaN; private double _clockTolerance = 0.025; private bool _listening; public int ScheduledCount => _main.Scheduled; public int PickupScheduledCount => _pickup.Scheduled; public int CancelledCount => _main.Cancelled + _pickup.Cancelled; public long LastBeat => _main.LastBeat; public long LastPickupBeat => _pickup.LastBeat; public double ScheduledDsp => _main.Due; public double PickupScheduledDsp => _pickup.Due; public bool Pending => _main.Pending; public bool PickupPending => _pickup.Pending; public bool MainPlaying { get { if (Object.op_Implicit((Object)(object)_main.Source)) { return _main.Source.isPlaying; } return false; } } public bool PickupPlaying { get { if (Object.op_Implicit((Object)(object)_pickup.Source)) { return _pickup.Source.isPlaying; } return false; } } public bool Playing { get { if (!MainPlaying) { return PickupPlaying; } return true; } } public float Volume { get { if (!Object.op_Implicit((Object)(object)_main.Source)) { return 0f; } return _main.Source.volume; } } public int SamplePosition { get { if (!Object.op_Implicit((Object)(object)_main.Source)) { return 0; } return _main.Source.timeSamples; } } public int PickupSamplePosition { get { if (!Object.op_Implicit((Object)(object)_pickup.Source)) { return 0; } return _pickup.Source.timeSamples; } } public int MainVariation => _main.Variation; public int PickupVariation => _pickup.Variation; public static float[] Samples(float period = 3f, int variation = 0) { return RowingDrumPattern.Hit(period, variation); } public static AudioClip CreateClip(float period = 3f, int variation = 0) { return Clip("Better Rowing acoustic drum " + variation, Samples(period, variation)); } private static AudioClip Clip(string name, float[] data) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown int offset = 0; return AudioClip.Create(name, data.Length / 2, 2, 48000, false, (PCMReaderCallback)delegate(float[] buffer) { int num = Math.Min(buffer.Length, data.Length - offset); if (num > 0) { Array.Copy(data, offset, buffer, 0, num); } offset += num; if (num < buffer.Length) { Array.Clear(buffer, num, buffer.Length - num); } }); } private AudioSource Source() { AudioSource obj = _root.AddComponent<AudioSource>(); obj.playOnAwake = false; obj.loop = false; obj.spatialBlend = 0f; obj.dopplerLevel = 0f; obj.pitch = 1f; obj.priority = 32; obj.ignoreListenerPause = false; return obj; } private void EnsureAudio(RowingRhythm rhythm) { //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_0025: Expected O, but got Unknown //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)_root)) { _root = new GameObject("Better Rowing shared beat") { hideFlags = (HideFlags)61 }; _main.Source = Source(); _pickup.Source = Source(); } if (_clips == null || !Object.op_Implicit((Object)(object)_clips[0]) || _period != rhythm.Period || _window != rhythm.Window) { _main.Stop(); _pickup.Stop(); DestroyClips(_clips); DestroyClips(_pickupClips); _period = rhythm.Period; _window = rhythm.Window; _clips = (AudioClip[])(object)new AudioClip[2] { CreateClip(_period), CreateClip(_period, 1) }; _main.Clips = _clips; _pickupClips = (AudioClip[])(object)((!RowingDrumPattern.HasPickups(_period)) ? null : new AudioClip[2] { Clip("Better Rowing acoustic pickups 0", RowingDrumPattern.Pickups(_period, _window)), Clip("Better Rowing acoustic pickups 1", RowingDrumPattern.Pickups(_period, _window, 1)) }); _pickup.Clips = _pickupClips; } if (!_listening) { int num = default(int); int num2 = default(int); AudioSettings.GetDSPBufferSize(ref num, ref num2); _clockTolerance = Math.Max(0.025, (double)num / (double)Math.Max(1, AudioSettings.outputSampleRate) + 0.01); AudioSettings.OnAudioConfigurationChanged += new AudioConfigurationChangeHandler(AudioChanged); _listening = true; } } private void AudioChanged(bool deviceWasChanged) { Dispose(); } public void Tick(RowingRhythm rhythm, double ownerTime, double dsp, bool enabled, float volume) { if (!enabled || !rhythm.Valid || !RowingVisualWire.Finite(ownerTime) || !RowingVisualWire.Finite(dsp) || AudioListener.pause || volume <= 0f) { Stop(); return; } if (dsp < _previousDsp) { Stop(); } if (_revision != rhythm.Revision) { Stop(); _revision = rhythm.Revision; } _previousDsp = dsp; EnsureAudio(rhythm); AudioSource source = _main.Source; float volume2 = (_pickup.Source.volume = Mathf.Clamp01(volume)); source.volume = volume2; _main.Tick(rhythm, ownerTime, dsp, _clockTolerance); if (_pickupClips != null) { _pickup.Tick(rhythm, ownerTime + RowingDrumPattern.PickupLead(rhythm.Period, rhythm.Window), dsp, _clockTolerance); } } public void Stop() { _main.Stop(); _pickup.Stop(); _revision = 0L; _previousDsp = double.NaN; } public void Dispose() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown Stop(); if (_listening) { AudioSettings.OnAudioConfigurationChanged -= new AudioConfigurationChangeHandler(AudioChanged); _listening = false; } if (Object.op_Implicit((Object)(object)_root)) { Object.Destroy((Object)(object)_root); } DestroyClips(_clips); DestroyClips(_pickupClips); _root = null; _clips = null; _pickupClips = null; _main.Clips = null; _pickup.Clips = null; _main.Source = null; _pickup.Source = null; } private static void DestroyClips(AudioClip[] clips) { if (clips == null) { return; } foreach (AudioClip val in clips) { if (Object.op_Implicit((Object)(object)val)) { Object.Destroy((Object)(object)val); } } } } internal static class RowingBlend { internal static float Weight(double now, double started, float duration) { if (!RowingMath.Finite(now) || !RowingMath.Finite(started) || !RowingMath.Finite(duration) || duration <= 0f) { return 0f; } double num = now - started; if (num <= 0.0 || num >= (double)duration) { return 0f; } double num2 = Math.Min(0.12, (double)duration * 0.2); double num3 = Math.Min(1.0, Math.Min(num / num2, ((double)duration - num) / num2)); return (float)(num3 * num3 * (3.0 - 2.0 * num3)); } } public struct RowingCrewRow { public long Player; public long Beat; public int Seat; public int Side; public int Direction; public int PerfectChain; public string Name; public float Quality; public float Offset; } public struct RowingCrewBonus { public long Beat; public int Count; public double At; } public sealed class RowingCrewFrame { public long Owner; public long Revision; public long Rhythm; public double Sent; public bool Active; public RowingCrewRow[] Rows = new RowingCrewRow[0]; public RowingCrewBonus Forward; public RowingCrewBonus Back; } public static class RowingCrewRules { public static bool ShowCoordination(RowingCrewFrame frame, RowingRhythm rhythm, double now) { if (Fresh(frame, rhythm, now)) { RowingCrewRow[] rows = frame.Rows; return ((rows != null && rows.Length != 0) ? 1 : 0) > (false ? 1 : 0); } return false; } public static bool Coordinates(long beat, long rhythm, int direction, long otherBeat, long otherRhythm, int otherDirection, float quality, double age, float duration) { if (beat == otherBeat && rhythm == otherRhythm && direction == otherDirection && quality >= 0.8f && age >= 0.0) { return age < (double)duration; } return false; } public static int BonusPercent(int count) { return (int)Math.Round((RowingMath.TeamBonus(count) - 1f) * 100f); } public static bool Fresh(RowingCrewFrame frame, RowingRhythm rhythm, double now) { if (frame != null && rhythm.Valid && frame.Owner == rhythm.Owner && frame.Rhythm == rhythm.Revision && RowingMath.Finite(now) && now - frame.Sent >= -0.25) { return now - frame.Sent <= 2.5; } return false; } public static bool Recent(RowingCrewRow row, RowingRhythm rhythm, double now) { if (row.Beat >= 0 && now - rhythm.At(row.Beat) <= Math.Max(1.5, (double)rhythm.Period * 1.5)) { return now - rhythm.At(row.Beat) >= (double)(0f - rhythm.Period) * 0.5; } return false; } public static bool Recent(RowingCrewBonus bonus, RowingRhythm rhythm, double now) { if (bonus.Count >= 2 && now - bonus.At >= -0.15) { return now - bonus.At <= Math.Max(1.5, rhythm.Period); } return false; } public static string Grade(RowingCrewRow row) { if (!(row.Quality >= 0.99f)) { if (!(row.Quality > 0f)) { return "MISS"; } return "GOOD"; } return "PERFECT"; } public static string GradeLabel(RowingCrewRow row, RowingRhythm rhythm, double now, bool soloTest = false) { if (!(row.Quality >= 0.99f)) { if (!(row.Quality > 0f)) { return "Miss"; } return "Good"; } return "Perfect" + ((row.PerfectChain > 0 && RowingPerfectCombo.Pending(row.Beat, rhythm, now)) ? (" " + RowingPerfectCombo.Multiplier(row.PerfectChain).ToString("0.0", CultureInfo.InvariantCulture) + "×" + (soloTest ? "" : " XP")) : ""); } public static string SafeName(string name) { StringBuilder stringBuilder = new StringBuilder(); string text = name ?? ""; foreach (char c in text) { if (!char.IsControl(c) && !char.IsSurrogate(c) && stringBuilder.Length < 32) { stringBuilder.Append(c); } } if (stringBuilder.Length != 0) { return stringBuilder.ToString(); } return "Rower"; } } public static class RowingCrewWire { public const int MaxRows = 32; public const int MaxBytes = 6144; private static readonly UTF8Encoding Utf8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); public static bool Valid(RowingCrewFrame frame) { if (frame == null || frame.Owner == 0L || frame.Revision <= 0 || frame.Rhythm <= 0 || !RowingMath.Finite(frame.Sent) || frame.Sent < 0.0 || frame.Sent > 1000000000000.0 || frame.Rows == null || frame.Rows.Length > 32 || !ValidBonus(frame.Forward, frame.Sent) || !ValidBonus(frame.Back, frame.Sent)) { return false; } HashSet<long> hashSet = new HashSet<long>(); HashSet<int> hashSet2 = new HashSet<int>(); RowingCrewRow[] rows = frame.Rows; for (int i = 0; i < rows.Length; i++) { RowingCrewRow rowingCrewRow = rows[i]; if (rowingCrewRow.Player == 0L || !hashSet.Add(rowingCrewRow.Player) || rowingCrewRow.Seat < 0 || rowingCrewRow.Seat > 4095 || !hashSet2.Add(rowingCrewRow.Seat) || rowingCrewRow.Side < -1 || rowingCrewRow.Side > 1 || rowingCrewRow.Name == null || rowingCrewRow.Name != RowingCrewRules.SafeName(rowingCrewRow.Name) || rowingCrewRow.Beat < -1 || !RowingMath.Finite(rowingCrewRow.Quality) || rowingCrewRow.Quality < 0f || rowingCrewRow.Quality > 1f || !RowingMath.Finite(rowingCrewRow.Offset) || Math.Abs(rowingCrewRow.Offset) > 1.51f || rowingCrewRow.PerfectChain < 0 || rowingCrewRow.PerfectChain > 6 || (rowingCrewRow.PerfectChain > 0 && (!frame.Active || rowingCrewRow.Beat < 0 || rowingCrewRow.Quality < 0.99f))) { return false; } bool num; if (rowingCrewRow.Beat >= 0) { if (rowingCrewRow.Direction == 1) { continue; } num = rowingCrewRow.Direction != -1; } else { if (rowingCrewRow.Direction != 0 || rowingCrewRow.Quality != 0f) { goto IL_0231; } num = rowingCrewRow.Offset != 0f; } if (!num) { continue; } goto IL_0231; IL_0231: return false; } return true; } private static bool ValidBonus(RowingCrewBonus bonus, double sent) { if (bonus.Count != 0) { if (bonus.Count >= 2 && bonus.Count <= 32 && bonus.Beat >= 0 && RowingMath.Finite(bonus.At) && bonus.At >= 0.0) { return bonus.At <= sent + 0.001; } return false; } if (bonus.At == 0.0) { return bonus.Beat == 0; } return false; } public static byte[] Encode(RowingCrewFrame frame) { if (!Valid(frame)) { throw new ArgumentException("Invalid crew snapshot"); } using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(2); binaryWriter.Write(frame.Owner); binaryWriter.Write(frame.Revision); binaryWriter.Write(frame.Rhythm); binaryWriter.Write(frame.Sent); binaryWriter.Write(frame.Active); WriteBonus(binaryWriter, frame.Forward); WriteBonus(binaryWriter, frame.Back); binaryWriter.Write((byte)frame.Rows.Length); RowingCrewRow[] rows = frame.Rows; for (int i = 0; i < rows.Length; i++) { RowingCrewRow rowingCrewRow = rows[i]; binaryWriter.Write(rowingCrewRow.Player); binaryWriter.Write(rowingCrewRow.Seat); binaryWriter.Write(rowingCrewRow.Side); byte[] bytes = Utf8.GetBytes(rowingCrewRow.Name); binaryWriter.Write((byte)bytes.Length); binaryWriter.Write(bytes); binaryWriter.Write(rowingCrewRow.Beat); binaryWriter.Write(rowingCrewRow.Quality); binaryWriter.Write(rowingCrewRow.Offset); binaryWriter.Write(rowingCrewRow.Direction); binaryWriter.Write((byte)rowingCrewRow.PerfectChain); } return memoryStream.ToArray(); } private static void WriteBonus(BinaryWriter writer, RowingCrewBonus value) { writer.Write(value.Beat); writer.Write(value.Count); writer.Write(value.At); } private static RowingCrewBonus ReadBonus(BinaryReader reader) { return new RowingCrewBonus { Beat = reader.ReadInt64(), Count = reader.ReadInt32(), At = reader.ReadDouble() }; } public static bool TryDecode(byte[] bytes, out RowingCrewFrame frame) { frame = null; if (bytes == null || bytes.Length < 78 || bytes.Length > 6144) { return false; } try { using MemoryStream memoryStream = new MemoryStream(bytes); using BinaryReader binaryReader = new BinaryReader(memoryStream); if (binaryReader.ReadInt32() != 2) { return false; } RowingCrewFrame rowingCrewFrame = new RowingCrewFrame { Owner = binaryReader.ReadInt64(), Revision = binaryReader.ReadInt64(), Rhythm = binaryReader.ReadInt64(), Sent = binaryReader.ReadDouble() }; byte b = binaryReader.ReadByte(); if (b > 1) { return false; } rowingCrewFrame.Active = b == 1; rowingCrewFrame.Forward = ReadBonus(binaryReader); rowingCrewFrame.Back = ReadBonus(binaryReader); int num = binaryReader.ReadByte(); if (num > 32) { return false; } rowingCrewFrame.Rows = new RowingCrewRow[num]; for (int i = 0; i < num; i++) { RowingCrewRow rowingCrewRow = new RowingCrewRow { Player = binaryReader.ReadInt64(), Seat = binaryReader.ReadInt32(), Side = binaryReader.ReadInt32() }; int num2 = binaryReader.ReadByte(); if (num2 == 0 || num2 > 96 || num2 > memoryStream.Length - memoryStream.Position) { return false; } rowingCrewRow.Name = Utf8.GetString(binaryReader.ReadBytes(num2)); rowingCrewRow.Beat = binaryReader.ReadInt64(); rowingCrewRow.Quality = binaryReader.ReadSingle(); rowingCrewRow.Offset = binaryReader.ReadSingle(); rowingCrewRow.Direction = binaryReader.ReadInt32(); rowingCrewRow.PerfectChain = binaryReader.ReadByte(); rowingCrewFrame.Rows[i] = rowingCrewRow; } if (memoryStream.Position != memoryStream.Length || !Valid(rowingCrewFrame)) { return false; } frame = rowingCrewFrame; return true; } catch (IOException) { return false; } catch (ArgumentException) { return false; } } } public sealed class RowingCrewState { private long _owner; public long HighestRevision { get; private set; } public RowingCrewFrame Current { get; private set; } public void ObserveOwner(long owner) { if (owner != _owner) { _owner = owner; Current = null; } } public bool Accept(RowingCrewFrame frame, long sender) { if (!RowingCrewWire.Valid(frame) || sender != _owner || frame.Owner != _owner || frame.Revision <= HighestRevision) { return false; } HighestRevision = frame.Revision; Current = frame; return true; } } public sealed class RowingCrewHud : IDisposable { public const float Width = 244f; public const float RowHeight = 24f; public static readonly Color PerfectColor = Color32.op_Implicit(new Color32(byte.MaxValue, (byte)209, (byte)102, byte.MaxValue)); public static readonly Color GoodColor = Color32.op_Implicit(new Color32((byte)102, (byte)224, (byte)128, byte.MaxValue)); public static readonly Color MissColor = Color32.op_Implicit(new Color32(byte.MaxValue, (byte)100, (byte)100, byte.MaxValue)); private GUIStyle _heading; private GUIStyle _small; private GUIStyle _name; private GUIStyle _grade; private Texture2D _drum; private Vector2 _scroll; private static readonly Color Gold = new Color(0.89f, 0.72f, 0.42f); private static readonly Color Muted = new Color(0.59f, 0.65f, 0.68f); public static Rect Layout(Rect minimap, float width, float height, int count) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Min(244f, width - 24f); float num2 = Mathf.Max(12f, ((Rect)(ref minimap)).yMax + 10f); float num3 = Mathf.Min(80f + (float)Mathf.Clamp(count, 1, 8) * 24f, Mathf.Max(0f, height - num2 - 12f)); return new Rect(Mathf.Clamp(((Rect)(ref minimap)).xMax - num, 12f, Mathf.Max(12f, width - num - 12f)), num2, num, num3); } private void Styles() { //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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_005f: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_008a: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing referen