using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Pipes; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using Il2CppInterop.Runtime.InteropTypes.Arrays; using MelonLoader; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using PuttlerFullBodyTracking; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(PuttlerFullBodyTrackingPlugin), "Full Body Tracking", "2.0", "Squidforge Productions", null)] [assembly: MelonGame(null, null)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("PuttlerFullBodyTracking")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("PuttlerFullBodyTracking")] [assembly: AssemblyTitle("PuttlerFullBodyTracking")] [assembly: AssemblyVersion("1.0.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace PuttlerFullBodyTracking { public class PuttlerFullBodyTrackingPlugin : MelonMod { private float BoneThickness = 7f; private StreamReader reader; private Thread pipeThread; private string json = null; private GameObject parentObject; private NamedPipeServerStream server = new NamedPipeServerStream("PuttlerFBTPipe", PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); private Process trackerProcess; private Dictionary boneBodies = new Dictionary(); private Dictionary previousPositions = new Dictionary(); private Dictionary smoothedVelocities = new Dictionary(); private string basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); public override void OnInitializeMelon() { MelonLogger.Msg("=================================="); MelonLogger.Msg(" Full Body Tracking "); MelonLogger.Msg(" By Squidforge productions "); MelonLogger.Msg("=================================="); MelonLogger.Msg("Starting tracker application..."); string text = Path.Combine(basePath, "FullBodyTracking", "Tracker", "FullBodyTracker.exe"); trackerProcess = new Process { StartInfo = new ProcessStartInfo { FileName = text, WorkingDirectory = Path.GetDirectoryName(text), UseShellExecute = true } }; trackerProcess.Start(); MelonLogger.Msg("Awaiting pipe connection..."); Thread thread = new Thread((ThreadStart)delegate { try { server.WaitForConnection(); MelonLogger.Msg("Pipe connected!"); reader = new StreamReader(server, Encoding.UTF8); pipeThread = new Thread(ReadPipe); pipeThread.IsBackground = true; pipeThread.Start(); } catch (Exception value) { MelonLogger.Error($"Pipe connection failed: {value}"); } }); thread.IsBackground = true; thread.Start(); } private void ReadPipe() { while (true) { try { json = reader.ReadLine(); } catch { } } } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) ((MelonBase)this).LoggerInstance.Msg("Scene Loaded: " + sceneName); parentObject = new GameObject("Skeleton Parent"); parentObject.transform.position = new Vector3(-12f, 7f, 0f); } public override void OnFixedUpdate() { Dictionary> jointData; if (!string.IsNullOrEmpty(json)) { Dictionary dictionary = JsonConvert.DeserializeObject>(json); if (!(dictionary["command"]?.ToString() != "BoneUpdate")) { jointData = JsonConvert.DeserializeObject>>(dictionary["data"].ToString()); Draw("ShoulderLeft", "ElbowLeft"); Draw("ElbowLeft", "WristLeft"); Draw("ShoulderRight", "ElbowRight"); Draw("ElbowRight", "WristRight"); Draw("ShoulderLeft", "ShoulderRight"); Draw("ShoulderLeft", "HipLeft"); Draw("ShoulderRight", "HipRight"); Draw("HipLeft", "HipRight"); Draw("HipLeft", "KneeLeft"); Draw("KneeLeft", "AnkleLeft"); Draw("HipRight", "KneeRight"); Draw("KneeRight", "AnkleRight"); } } void Draw(string a, string b) { if (jointData.ContainsKey(a) && jointData.ContainsKey(b)) { Dictionary dictionary2 = jointData[a]; Dictionary dictionary3 = jointData[b]; DrawBone(a + "_" + b, dictionary2["x"], dictionary2["y"], dictionary2["z"], dictionary3["x"], dictionary3["y"], dictionary3["z"]); } } } private void DrawBone(string boneKey, float joint0x, float joint0y, float joint0z, float joint1x, float joint1y, float joint1z) { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(joint0x, joint0y * -1f, joint0z); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(joint1x, joint1y * -1f, joint1z); string text = "Bone_" + boneKey; GameObject val3 = GameObject.Find(text); Rigidbody2D val4; if ((Object)(object)val3 == (Object)null) { val3 = LoadCustomImage("FullBodyTracking/solidWhite.png"); ((Object)val3).name = text; val3.AddComponent(); val4 = val3.AddComponent(); val4.bodyType = (RigidbodyType2D)1; val4.gravityScale = 0f; val4.interpolation = (RigidbodyInterpolation2D)1; val4.collisionDetectionMode = (CollisionDetectionMode2D)1; val3.transform.parent = parentObject.transform; boneBodies[boneKey] = val4; previousPositions[boneKey] = val4.position; smoothedVelocities[boneKey] = Vector2.zero; } else { val4 = boneBodies[boneKey]; } Vector2 val5 = Vector2.op_Implicit((val + val2) / 2f / 100f * 3f + parentObject.transform.position); Vector2 val6 = Vector2.op_Implicit(val2 - val); float num = Mathf.Atan2(val6.y, val6.x) * 57.29578f; float magnitude = ((Vector2)(ref val6)).magnitude; if (!previousPositions.ContainsKey(boneKey)) { previousPositions[boneKey] = val4.position; } if (!smoothedVelocities.ContainsKey(boneKey)) { smoothedVelocities[boneKey] = Vector2.zero; } float num2 = 0.05f; float num3 = 0f; float num4 = 0.4f; Vector2 val7 = (val5 - previousPositions[boneKey]) / Time.fixedDeltaTime; Vector2 val8 = Vector2.Lerp(smoothedVelocities[boneKey], val7, num4); val8 *= num2; val8 = Vector2.ClampMagnitude(val8, num3); smoothedVelocities[boneKey] = val8; val4.MovePosition(val5); val4.MoveRotation(num); val4.velocity = val8; val3.transform.localScale = new Vector3(magnitude, BoneThickness, BoneThickness) * 3f; previousPositions[boneKey] = val5; } private GameObject LoadCustomImage(string imagePath) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) string text = Path.Combine(basePath, imagePath); if (!File.Exists(text)) { MelonLogger.Error("Texture not found: " + text); return null; } GameObject val = new GameObject(imagePath); SpriteRenderer val2 = val.AddComponent(); byte[] array = File.ReadAllBytes(text); Texture2D val3 = new Texture2D(2, 2, (TextureFormat)4, false); ImageConversion.LoadImage(val3, Il2CppStructArray.op_Implicit(array)); val2.sprite = Sprite.Create(val3, new Rect(0f, 0f, (float)((Texture)val3).width, (float)((Texture)val3).height), new Vector2(0.5f, 0.5f)); val.transform.parent = parentObject.transform; return val; } public override void OnApplicationQuit() { try { if (trackerProcess != null && !trackerProcess.HasExited) { trackerProcess.CloseMainWindow(); if (!trackerProcess.WaitForExit(2000)) { trackerProcess.Kill(entireProcessTree: true); } trackerProcess.Dispose(); trackerProcess = null; } } catch (Exception value) { MelonLogger.Error($"Failed to stop tracker process: {value}"); } } } }