Decompiled source of VRMCompanions v0.1.0

BepInEx/plugins/VRMCompanions/VRMCompanions.dll

Decompiled 10 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using ValheimVRM;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("VRMCompanions")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VRMCompanions")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8aaf6e91-f870-4b1f-a224-b3b681dbbf1f")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("com.vrm.companions", "VRM Companions", "1.0.0")]
public class VRMCompanionsPlugin : BaseUnityPlugin
{
	internal static ManualLogSource Log;

	private void Awake()
	{
		Log = ((BaseUnityPlugin)this).Logger;
		Harmony.CreateAndPatchAll(typeof(CompanionPatch), (string)null);
		Log.LogInfo((object)"VRM Companions loaded");
	}
}
[HarmonyPatch(typeof(Humanoid), "Start")]
public class CompanionPatch
{
	private static void Postfix(Humanoid __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && ((Object)__instance).name.Contains("HC_Companion"))
		{
			LogSafe("✔ Companion detected: " + ((Object)__instance).name);
			((MonoBehaviour)__instance).StartCoroutine(ReplaceVRM(__instance));
		}
	}

	private static IEnumerator ReplaceVRM(Humanoid humanoid)
	{
		yield return null;
		VisEquipment vis = ((Component)humanoid).GetComponent<VisEquipment>();
		if ((Object)(object)vis == (Object)null)
		{
			LogSafe("❌ VisEquipment missing");
			yield break;
		}
		if ((Object)(object)vis.m_bodyModel != (Object)null)
		{
			((Renderer)vis.m_bodyModel).enabled = false;
			LogSafe("✔ Vanilla body hidden");
		}
		string path = Path.Combine(Paths.GameRootPath, "ValheimVRM", "Companion.vrm");
		if (!File.Exists(path))
		{
			LogSafe("❌ VRM not found: " + path);
			yield break;
		}
		Dictionary<string, string> cfg = LoadSettingsFile(path);
		byte[] data = File.ReadAllBytes(path);
		bool done = false;
		yield return VRM.ImportVisualAsync(data, path, 1f, (Action<GameObject>)delegate(GameObject loaded)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)loaded == (Object)null)
			{
				LogSafe("❌ VRM load failed");
				done = true;
			}
			else
			{
				float result = 1f;
				float result2 = 1f;
				float result3 = 1f;
				if (cfg.TryGetValue("ModelScale", out var value))
				{
					float.TryParse(value, out result);
				}
				if (cfg.TryGetValue("SpringBoneStiffness", out var value2))
				{
					float.TryParse(value2, out result2);
				}
				if (cfg.TryGetValue("SpringBoneGravityPower", out var value3))
				{
					float.TryParse(value3, out result3);
				}
				loaded.transform.localScale = Vector3.one * result;
				Animator componentInChildren = ((Component)humanoid).GetComponentInChildren<Animator>();
				VrmSettingsContainer settings = Settings.GetSettings(((Object)humanoid).name);
				loaded.transform.SetParent(((Component)componentInChildren).transform.parent, false);
				loaded.transform.localPosition = Vector3.zero;
				loaded.transform.localRotation = Quaternion.identity;
				LogSafe("✔ VRM attached to companion");
				VRMAnimationSync val = loaded.GetComponent<VRMAnimationSync>();
				if ((Object)(object)val == (Object)null)
				{
					val = loaded.AddComponent<VRMAnimationSync>();
				}
				val.Setup(componentInChildren, settings, false);
				componentInChildren.cullingMode = (AnimatorCullingMode)0;
				componentInChildren.updateMode = (AnimatorUpdateMode)0;
				ForceSpringBoneUpdate(loaded, result2, result3);
				ApplyArmorHide(humanoid);
				MonoBehaviour[] componentsInChildren = loaded.GetComponentsInChildren<MonoBehaviour>(true);
				foreach (MonoBehaviour val2 in componentsInChildren)
				{
					if (((object)val2).GetType().Name.Contains("VRMSpringBone"))
					{
						LogSafe("SpringBone found: " + ((Object)val2).name);
					}
				}
				done = true;
			}
		});
		while (!done)
		{
			yield return null;
		}
	}

	private static void ApplyArmorHide(Humanoid humanoid)
	{
		VisEquipment component = ((Component)humanoid).GetComponent<VisEquipment>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		if ((Object)(object)component.m_helmet != (Object)null)
		{
			((Component)component.m_helmet).gameObject.SetActive(false);
		}
		component.SetHairItem("");
		component.SetBeardItem("");
		SkinnedMeshRenderer[] componentsInChildren = ((Component)humanoid).GetComponentsInChildren<SkinnedMeshRenderer>(true);
		foreach (SkinnedMeshRenderer val in componentsInChildren)
		{
			string text = ((Object)((Component)val).gameObject).name.ToLower();
			if (text.Contains("helmet") || text.Contains("helm") || text.Contains("chest") || text.Contains("armor"))
			{
				((Renderer)val).enabled = false;
			}
		}
	}

	private static void ForceSpringBoneUpdate(GameObject vrmRoot, float springStiffness, float springGravity)
	{
		MonoBehaviour[] componentsInChildren = vrmRoot.GetComponentsInChildren<MonoBehaviour>(true);
		foreach (MonoBehaviour val in componentsInChildren)
		{
			Type type = ((object)val).GetType();
			if (type.Name.Contains("VRMSpringBone"))
			{
				FieldInfo field = type.GetField("m_stiffnessForce");
				FieldInfo field2 = type.GetField("m_gravityPower");
				if (field != null)
				{
					float num = (float)field.GetValue(val);
					field.SetValue(val, num * Mathf.Clamp(springStiffness, 0.1f, 5f));
				}
				if (field2 != null)
				{
					float num2 = (float)field2.GetValue(val);
					field2.SetValue(val, num2 * Mathf.Clamp(springGravity, 0.1f, 5f));
				}
			}
		}
	}

	private static Dictionary<string, string> LoadSettingsFile(string vrmPath)
	{
		string text = Path.Combine(Path.GetDirectoryName(vrmPath), "settings_" + Path.GetFileNameWithoutExtension(vrmPath) + ".txt");
		Dictionary<string, string> dictionary = new Dictionary<string, string>();
		if (!File.Exists(text))
		{
			return dictionary;
		}
		string[] array = File.ReadAllLines(text);
		foreach (string text2 in array)
		{
			if (!string.IsNullOrWhiteSpace(text2) && !text2.StartsWith("//") && text2.Contains("="))
			{
				string[] array2 = text2.Split(new char[1] { '=' });
				if (array2.Length == 2)
				{
					dictionary[array2[0].Trim()] = array2[1].Trim();
				}
			}
		}
		LogSafe("✔ Loaded VRM settings: " + text);
		return dictionary;
	}

	private static void LogSafe(string msg)
	{
		if (VRMCompanionsPlugin.Log != null)
		{
			VRMCompanionsPlugin.Log.LogInfo((object)msg);
		}
		else
		{
			Debug.Log((object)msg);
		}
	}
}