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<string, Rigidbody2D> boneBodies = new Dictionary<string, Rigidbody2D>();
private Dictionary<string, Vector2> previousPositions = new Dictionary<string, Vector2>();
private Dictionary<string, Vector2> smoothedVelocities = new Dictionary<string, Vector2>();
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<string, Dictionary<string, float>> jointData;
if (!string.IsNullOrEmpty(json))
{
Dictionary<string, object> dictionary = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
if (!(dictionary["command"]?.ToString() != "BoneUpdate"))
{
jointData = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, float>>>(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<string, float> dictionary2 = jointData[a];
Dictionary<string, float> 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<BoxCollider2D>();
val4 = val3.AddComponent<Rigidbody2D>();
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<SpriteRenderer>();
byte[] array = File.ReadAllBytes(text);
Texture2D val3 = new Texture2D(2, 2, (TextureFormat)4, false);
ImageConversion.LoadImage(val3, Il2CppStructArray<byte>.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}");
}
}
}
}