Decompiled source of UnloxAppearance v1.0.0

BepInEx/plugins/Unlox Appearance/LoxMore.dll

Decompiled 2 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 HarmonyLib;
using Jotunn.Managers;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("LoxMore")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LoxMore")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8509a45a-86cf-4453-ac15-4ec66967a603")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace LoxMore;

public sealed class LoxAppearanceController : MonoBehaviour
{
	private const string AppearanceZdoKey = "Moddermother.LoxMore.Appearance";

	private const float NetworkCheckInterval = 0.2f;

	private ZNetView _networkView;

	private string _appliedAppearanceId = string.Empty;

	private IEnumerator Start()
	{
		_networkView = ((Component)this).GetComponent<ZNetView>();
		if ((Object)(object)_networkView == (Object)null)
		{
			yield break;
		}
		while (!_networkView.IsValid() || _networkView.GetZDO() == null)
		{
			yield return null;
		}
		ZDO zdo = _networkView.GetZDO();
		string appearanceId = zdo.GetString("Moddermother.LoxMore.Appearance", string.Empty);
		if (string.IsNullOrEmpty(appearanceId) && _networkView.IsOwner())
		{
			LoxMorePlugin plugin = LoxMorePlugin.Instance;
			if ((Object)(object)plugin == (Object)null)
			{
				yield break;
			}
			if (!plugin.TryConsumePendingGrowup(((Component)this).transform.position, out appearanceId))
			{
				appearanceId = plugin.ChooseInitialAdultAppearance();
			}
			zdo.Set("Moddermother.LoxMore.Appearance", appearanceId);
		}
		while (string.IsNullOrEmpty(appearanceId))
		{
			yield return (object)new WaitForSeconds(0.2f);
			if ((Object)(object)_networkView == (Object)null || !_networkView.IsValid())
			{
				yield break;
			}
			zdo = _networkView.GetZDO();
			if (zdo != null)
			{
				appearanceId = zdo.GetString("Moddermother.LoxMore.Appearance", string.Empty);
			}
		}
		ApplyAppearance(appearanceId);
	}

	public string GetStoredAppearanceId()
	{
		if ((Object)(object)_networkView == (Object)null)
		{
			_networkView = ((Component)this).GetComponent<ZNetView>();
		}
		if ((Object)(object)_networkView == (Object)null || !_networkView.IsValid() || _networkView.GetZDO() == null)
		{
			return string.Empty;
		}
		return _networkView.GetZDO().GetString("Moddermother.LoxMore.Appearance", string.Empty);
	}

	private void ApplyAppearance(string appearanceId)
	{
		if (!string.IsNullOrEmpty(appearanceId) && !string.Equals(_appliedAppearanceId, appearanceId, StringComparison.OrdinalIgnoreCase))
		{
			LoxMorePlugin instance = LoxMorePlugin.Instance;
			if (!((Object)(object)instance == (Object)null) && instance.ApplyAdultAppearance(((Component)this).gameObject, appearanceId))
			{
				_appliedAppearanceId = appearanceId;
			}
		}
	}
}
public sealed class LoxCalfAppearanceController : MonoBehaviour
{
	private const string FutureAdultZdoKey = "Moddermother.LoxMore.FutureAppearance";

	private const string CalfColorZdoKey = "Moddermother.LoxMore.CalfColor";

	private const float AssignmentWaitSeconds = 0.8f;

	private const float NetworkCheckInterval = 0.2f;

	private const float GrowCheckInterval = 0.5f;

	private const float RegisterGrowupWhenSecondsLeft = 3f;

	private ZNetView _networkView;

	private string _appliedCalfColor = string.Empty;

	private IEnumerator Start()
	{
		_networkView = ((Component)this).GetComponent<ZNetView>();
		if ((Object)(object)_networkView == (Object)null)
		{
			yield break;
		}
		while (!_networkView.IsValid() || _networkView.GetZDO() == null)
		{
			yield return null;
		}
		ZDO zdo = _networkView.GetZDO();
		string futureAppearance = zdo.GetString("Moddermother.LoxMore.FutureAppearance", string.Empty);
		string calfColor = zdo.GetString("Moddermother.LoxMore.CalfColor", string.Empty);
		if (string.IsNullOrEmpty(futureAppearance) && _networkView.IsOwner())
		{
			yield return (object)new WaitForSeconds(0.8f);
			LoxMorePlugin plugin = LoxMorePlugin.Instance;
			if ((Object)(object)plugin == (Object)null)
			{
				yield break;
			}
			futureAppearance = plugin.ChooseFutureAdultAppearanceForCalf(this);
			calfColor = plugin.GetCalfColorIdForAdult(futureAppearance);
			zdo.Set("Moddermother.LoxMore.FutureAppearance", futureAppearance);
			zdo.Set("Moddermother.LoxMore.CalfColor", calfColor);
		}
		while (string.IsNullOrEmpty(futureAppearance) || string.IsNullOrEmpty(calfColor))
		{
			yield return (object)new WaitForSeconds(0.2f);
			if ((Object)(object)_networkView == (Object)null || !_networkView.IsValid())
			{
				yield break;
			}
			zdo = _networkView.GetZDO();
			if (zdo != null)
			{
				futureAppearance = zdo.GetString("Moddermother.LoxMore.FutureAppearance", string.Empty);
				calfColor = zdo.GetString("Moddermother.LoxMore.CalfColor", string.Empty);
			}
		}
		ApplyCalfColor(calfColor);
		((MonoBehaviour)this).StartCoroutine(WatchForGrowup(futureAppearance));
	}

	private void ApplyCalfColor(string calfColor)
	{
		if (!string.IsNullOrEmpty(calfColor) && !string.Equals(_appliedCalfColor, calfColor, StringComparison.OrdinalIgnoreCase))
		{
			LoxMorePlugin instance = LoxMorePlugin.Instance;
			if (!((Object)(object)instance == (Object)null) && instance.ApplyCalfAppearance(((Component)this).gameObject, calfColor))
			{
				_appliedCalfColor = calfColor;
			}
		}
	}

	private IEnumerator WatchForGrowup(string futureAppearance)
	{
		Growup growup = ((Component)this).GetComponent<Growup>();
		if ((Object)(object)growup == (Object)null)
		{
			yield break;
		}
		while (true)
		{
			yield return (object)new WaitForSeconds(0.5f);
			if ((Object)(object)_networkView == (Object)null || !_networkView.IsValid() || !_networkView.IsOwner())
			{
				continue;
			}
			ZDO zdo = _networkView.GetZDO();
			if (zdo == null || (Object)(object)ZNet.instance == (Object)null)
			{
				continue;
			}
			long spawnTicks = zdo.GetLong(ZDOVars.s_spawnTime, 0L);
			if (spawnTicks <= 0)
			{
				continue;
			}
			long nowTicks = ZNet.instance.GetTime().Ticks;
			double ageSeconds = (double)(nowTicks - spawnTicks) / 10000000.0;
			double secondsLeft = (double)growup.m_growTime - ageSeconds;
			if (secondsLeft <= 3.0)
			{
				LoxMorePlugin plugin = LoxMorePlugin.Instance;
				if ((Object)(object)plugin != (Object)null)
				{
					plugin.RegisterPendingGrowup(((Object)this).GetInstanceID(), ((Component)this).transform.position, futureAppearance);
				}
			}
		}
	}
}
[BepInPlugin("Moddermother.LoxMore", "Lox More", "0.3.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class LoxMorePlugin : BaseUnityPlugin
{
	public enum CalfColor
	{
		Vanilla,
		Black,
		BlackWhite,
		White
	}

	private sealed class LoxVariantDefinition
	{
		public string AppearanceId { get; }

		public GameObject Prefab { get; }

		public bool IsHorned { get; }

		public CalfColor CalfColor { get; }

		public LoxVariantDefinition(string appearanceId, GameObject prefab, bool isHorned, CalfColor calfColor)
		{
			AppearanceId = appearanceId;
			Prefab = prefab;
			IsHorned = isHorned;
			CalfColor = calfColor;
		}
	}

	private sealed class PendingGrowupRecord
	{
		public int CalfInstanceId;

		public Vector3 Position;

		public string AppearanceId;

		public float Timestamp;
	}

	public const string ModGuid = "Moddermother.LoxMore";

	public const string ModName = "Lox More";

	public const string ModVersion = "0.3.0";

	public const string VanillaAppearanceId = "vanilla";

	private const string BundleFileName = "loxmore";

	private const string AdultPrefabName = "Lox";

	private const string CalfPrefabName = "Lox_Calf";

	private const string AdultRagdollPrefabName = "lox_ragdoll";

	private const float PendingGrowupMaxAgeSeconds = 8f;

	private const float PendingGrowupMaxDistance = 3f;

	private readonly List<LoxVariantDefinition> _adultVariants = new List<LoxVariantDefinition>();

	private readonly Dictionary<string, GameObject> _calfPrefabs = new Dictionary<string, GameObject>(StringComparer.OrdinalIgnoreCase);

	private readonly List<PendingGrowupRecord> _pendingGrowups = new List<PendingGrowupRecord>();

	private AssetBundle _assetBundle;

	private Harmony _harmony;

	private float _baseAdultTamingTime = -1f;

	public static LoxMorePlugin Instance { get; private set; }

	private void Awake()
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0018: Expected O, but got Unknown
		Instance = this;
		_harmony = new Harmony("Moddermother.LoxMore");
		_harmony.PatchAll();
		LoadAssetBundle();
		LoadAdultVariants();
		LoadCalfVariants();
		PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable;
		((BaseUnityPlugin)this).Logger.LogInfo((object)("[Lox More] Loaded " + _adultVariants.Count + " custom adult variants."));
	}

	private void LoadAdultVariants()
	{
		_adultVariants.Clear();
		AddAdultVariant("lox2", "lox2.prefab", isHorned: true, CalfColor.Vanilla);
		AddAdultVariant("lox3", "lox3.prefab", isHorned: true, CalfColor.Vanilla);
		AddAdultVariant("loxblack", "loxblack.prefab", isHorned: true, CalfColor.Black);
		AddAdultVariant("loxblack2", "loxblack2.prefab", isHorned: false, CalfColor.Black);
		AddAdultVariant("loxblack3", "loxblack3.prefab", isHorned: true, CalfColor.Black);
		AddAdultVariant("loxblackwhite", "loxblackwhite.prefab", isHorned: true, CalfColor.BlackWhite);
		AddAdultVariant("loxblackwhite2", "loxblackwhite2.prefab", isHorned: true, CalfColor.BlackWhite);
		AddAdultVariant("loxblackwhite3", "loxblackwhite3.prefab", isHorned: false, CalfColor.BlackWhite);
		AddAdultVariant("loxwhite", "loxwhite.prefab", isHorned: true, CalfColor.White);
		AddAdultVariant("loxwhite2", "loxwhite2.prefab", isHorned: false, CalfColor.White);
		AddAdultVariant("loxwhite3", "loxwhite3.prefab", isHorned: true, CalfColor.White);
	}

	private void LoadCalfVariants()
	{
		_calfPrefabs.Clear();
		AddCalfVariant(CalfColor.Black, "Lox_CalfBlack.prefab");
		AddCalfVariant(CalfColor.BlackWhite, "Lox_CalfBlackWhite.prefab");
		AddCalfVariant(CalfColor.White, "Lox_CalfWhite.prefab");
	}

	private void AddAdultVariant(string appearanceId, string prefabFileName, bool isHorned, CalfColor calfColor)
	{
		GameObject val = LoadPrefabFromBundle(prefabFileName);
		if ((Object)(object)val == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[Lox More] Failed to load adult variant: " + prefabFileName));
		}
		else
		{
			_adultVariants.Add(new LoxVariantDefinition(appearanceId, val, isHorned, calfColor));
		}
	}

	private void AddCalfVariant(CalfColor calfColor, string prefabFileName)
	{
		GameObject val = LoadPrefabFromBundle(prefabFileName);
		if ((Object)(object)val == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[Lox More] Failed to load calf variant: " + prefabFileName));
		}
		else
		{
			_calfPrefabs[calfColor.ToString()] = val;
		}
	}

	private void LoadAssetBundle()
	{
		string directoryName = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
		if (string.IsNullOrEmpty(directoryName))
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"[Lox More] DLL folder not found.");
			return;
		}
		string text = Path.Combine(directoryName, "loxmore");
		if (!File.Exists(text))
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[Lox More] Missing AssetBundle: " + text));
			return;
		}
		_assetBundle = AssetBundle.LoadFromFile(text);
		if ((Object)(object)_assetBundle == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"[Lox More] Failed to load AssetBundle.");
		}
	}

	private GameObject LoadPrefabFromBundle(string fileName)
	{
		if ((Object)(object)_assetBundle == (Object)null)
		{
			return null;
		}
		string text = FindAssetPath(fileName);
		if (string.IsNullOrEmpty(text))
		{
			return null;
		}
		return _assetBundle.LoadAsset<GameObject>(text);
	}

	private string FindAssetPath(string fileName)
	{
		if ((Object)(object)_assetBundle == (Object)null)
		{
			return null;
		}
		string[] allAssetNames = _assetBundle.GetAllAssetNames();
		foreach (string text in allAssetNames)
		{
			if (text.EndsWith("/" + fileName, StringComparison.OrdinalIgnoreCase) || string.Equals(text, fileName, StringComparison.OrdinalIgnoreCase))
			{
				return text;
			}
		}
		return null;
	}

	private void OnVanillaPrefabsAvailable()
	{
		PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
		GameObject prefab = PrefabManager.Instance.GetPrefab("Lox");
		GameObject prefab2 = PrefabManager.Instance.GetPrefab("Lox_Calf");
		GameObject prefab3 = PrefabManager.Instance.GetPrefab("lox_ragdoll");
		if ((Object)(object)prefab == (Object)null || (Object)(object)prefab2 == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"[Lox More] Missing Lox or Lox_Calf prefab.");
			return;
		}
		CacheBaseAdultTamingTime(prefab);
		EnableLoxFollowCommands(prefab);
		if ((Object)(object)prefab.GetComponent<LoxAppearanceController>() == (Object)null)
		{
			prefab.AddComponent<LoxAppearanceController>();
		}
		if ((Object)(object)prefab2.GetComponent<LoxCalfAppearanceController>() == (Object)null)
		{
			prefab2.AddComponent<LoxCalfAppearanceController>();
		}
		if ((Object)(object)prefab3 == (Object)null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"[Lox More] Missing lox_ragdoll prefab.");
		}
		else if ((Object)(object)prefab3.GetComponent<LoxRagdollAppearanceController>() == (Object)null)
		{
			prefab3.AddComponent<LoxRagdollAppearanceController>();
		}
	}

	public string ChooseInitialAdultAppearance()
	{
		return ChooseRandomAnyAppearance();
	}

	public string ChooseFutureAdultAppearanceForCalf(LoxCalfAppearanceController self)
	{
		return (Random.value < 0.5f) ? ChooseRandomHornedAppearance() : ChooseRandomNonHornedAppearance();
	}

	private string ChooseRandomAnyAppearance()
	{
		int num = _adultVariants.Count + 1;
		int num2 = Random.Range(0, num);
		if (num2 == 0)
		{
			return "vanilla";
		}
		return _adultVariants[num2 - 1].AppearanceId;
	}

	private string ChooseRandomHornedAppearance()
	{
		List<LoxVariantDefinition> list = _adultVariants.FindAll((LoxVariantDefinition variant) => variant.IsHorned);
		if (list.Count == 0)
		{
			return "vanilla";
		}
		return list[Random.Range(0, list.Count)].AppearanceId;
	}

	private string ChooseRandomNonHornedAppearance()
	{
		List<string> list = new List<string> { "vanilla" };
		foreach (LoxVariantDefinition adultVariant in _adultVariants)
		{
			if (!adultVariant.IsHorned)
			{
				list.Add(adultVariant.AppearanceId);
			}
		}
		return list[Random.Range(0, list.Count)];
	}

	public bool ApplyAdultAppearance(GameObject loxInstance, string appearanceId)
	{
		if ((Object)(object)loxInstance == (Object)null)
		{
			return false;
		}
		if (string.IsNullOrEmpty(appearanceId) || string.Equals(appearanceId, "vanilla", StringComparison.OrdinalIgnoreCase))
		{
			ConfigureTamingTime(loxInstance, isHorned: false);
			return true;
		}
		LoxVariantDefinition loxVariantDefinition = FindAdultVariant(appearanceId);
		if (loxVariantDefinition == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[Lox More] Unknown adult appearance: " + appearanceId));
			return false;
		}
		if (!ReplaceSkinnedRenderers(loxInstance, loxVariantDefinition.Prefab))
		{
			return false;
		}
		ConfigureTamingTime(loxInstance, loxVariantDefinition.IsHorned);
		return true;
	}

	private void CacheBaseAdultTamingTime(GameObject adultPrefab)
	{
		Component val = FindComponentByTypeName(adultPrefab, "Tameable");
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		FieldInfo field = ((object)val).GetType().GetField("m_tamingTime", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (!(field == null))
		{
			object value = field.GetValue(val);
			if (value is float)
			{
				_baseAdultTamingTime = (float)value;
			}
		}
	}

	private void ConfigureTamingTime(GameObject lox, bool isHorned)
	{
		Component val = FindComponentByTypeName(lox, "Tameable");
		if ((Object)(object)val == (Object)null)
		{
			return;
		}
		FieldInfo field = ((object)val).GetType().GetField("m_tamingTime", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field == null)
		{
			return;
		}
		float num = _baseAdultTamingTime;
		if (num <= 0f)
		{
			object value = field.GetValue(val);
			if (!(value is float))
			{
				return;
			}
			num = (float)value;
		}
		field.SetValue(val, isHorned ? (num * 2f) : num);
	}

	public bool ApplyAdultRagdollAppearance(GameObject ragdollInstance, string appearanceId)
	{
		if ((Object)(object)ragdollInstance == (Object)null)
		{
			return false;
		}
		if (string.IsNullOrEmpty(appearanceId) || string.Equals(appearanceId, "vanilla", StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		LoxVariantDefinition loxVariantDefinition = FindAdultVariant(appearanceId);
		if (loxVariantDefinition == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[Lox More] Unknown ragdoll appearance: " + appearanceId));
			return false;
		}
		return ReplaceSkinnedRenderers(ragdollInstance, loxVariantDefinition.Prefab);
	}

	public string GetCalfColorIdForAdult(string adultAppearanceId)
	{
		if (string.IsNullOrEmpty(adultAppearanceId) || string.Equals(adultAppearanceId, "vanilla", StringComparison.OrdinalIgnoreCase))
		{
			return CalfColor.Vanilla.ToString();
		}
		LoxVariantDefinition loxVariantDefinition = FindAdultVariant(adultAppearanceId);
		return (loxVariantDefinition == null) ? CalfColor.Vanilla.ToString() : loxVariantDefinition.CalfColor.ToString();
	}

	public bool ApplyCalfAppearance(GameObject calfInstance, string calfColorId)
	{
		if ((Object)(object)calfInstance == (Object)null)
		{
			return false;
		}
		if (string.IsNullOrEmpty(calfColorId) || string.Equals(calfColorId, CalfColor.Vanilla.ToString(), StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		if (!_calfPrefabs.TryGetValue(calfColorId, out var value))
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[Lox More] Unknown calf appearance: " + calfColorId));
			return false;
		}
		return ReplaceSkinnedRenderers(calfInstance, value);
	}

	public void RegisterPendingGrowup(int calfInstanceId, Vector3 position, string futureAdultAppearanceId)
	{
		//IL_0069: 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_0037: 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)
		CleanupPendingGrowups();
		PendingGrowupRecord pendingGrowupRecord = _pendingGrowups.Find((PendingGrowupRecord record) => record.CalfInstanceId == calfInstanceId);
		if (pendingGrowupRecord != null)
		{
			pendingGrowupRecord.Position = position;
			pendingGrowupRecord.AppearanceId = futureAdultAppearanceId;
			pendingGrowupRecord.Timestamp = Time.realtimeSinceStartup;
		}
		else
		{
			_pendingGrowups.Add(new PendingGrowupRecord
			{
				CalfInstanceId = calfInstanceId,
				Position = position,
				AppearanceId = futureAdultAppearanceId,
				Timestamp = Time.realtimeSinceStartup
			});
		}
	}

	public bool TryConsumePendingGrowup(Vector3 adultPosition, out string appearanceId)
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		CleanupPendingGrowups();
		appearanceId = string.Empty;
		PendingGrowupRecord pendingGrowupRecord = null;
		float num = float.MaxValue;
		foreach (PendingGrowupRecord pendingGrowup in _pendingGrowups)
		{
			float num2 = Vector3.Distance(adultPosition, pendingGrowup.Position);
			if (!(num2 > 3f) && num2 < num)
			{
				pendingGrowupRecord = pendingGrowup;
				num = num2;
			}
		}
		if (pendingGrowupRecord == null)
		{
			return false;
		}
		appearanceId = pendingGrowupRecord.AppearanceId;
		_pendingGrowups.Remove(pendingGrowupRecord);
		return true;
	}

	private void CleanupPendingGrowups()
	{
		float now = Time.realtimeSinceStartup;
		_pendingGrowups.RemoveAll((PendingGrowupRecord record) => now - record.Timestamp > 8f);
	}

	private static string GetRendererRole(string rendererName)
	{
		if (string.IsNullOrWhiteSpace(rendererName))
		{
			return string.Empty;
		}
		string text = rendererName.Trim();
		if (text.StartsWith("Body", StringComparison.OrdinalIgnoreCase))
		{
			return "Body";
		}
		if (text.StartsWith("Furr1", StringComparison.OrdinalIgnoreCase))
		{
			return "Furr1";
		}
		return string.Empty;
	}

	private bool ReplaceSkinnedRenderers(GameObject targetObject, GameObject sourcePrefab)
	{
		//IL_023a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0253: Unknown result type (might be due to invalid IL or missing references)
		//IL_026c: Unknown result type (might be due to invalid IL or missing references)
		//IL_027b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0293: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)targetObject == (Object)null || (Object)(object)sourcePrefab == (Object)null)
		{
			return false;
		}
		SkinnedMeshRenderer[] componentsInChildren = sourcePrefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		SkinnedMeshRenderer[] componentsInChildren2 = targetObject.GetComponentsInChildren<SkinnedMeshRenderer>(true);
		Dictionary<string, SkinnedMeshRenderer> dictionary = new Dictionary<string, SkinnedMeshRenderer>(StringComparer.OrdinalIgnoreCase);
		SkinnedMeshRenderer[] array = componentsInChildren2;
		foreach (SkinnedMeshRenderer val in array)
		{
			if (!((Object)(object)val == (Object)null))
			{
				string rendererRole = GetRendererRole(((Object)val).name);
				if (!string.IsNullOrEmpty(rendererRole) && !dictionary.ContainsKey(rendererRole))
				{
					dictionary.Add(rendererRole, val);
				}
			}
		}
		Dictionary<string, Transform> targetBones = BuildBoneMap(targetObject);
		int num = 0;
		SkinnedMeshRenderer[] array2 = componentsInChildren;
		foreach (SkinnedMeshRenderer val2 in array2)
		{
			if ((Object)(object)val2 == (Object)null)
			{
				continue;
			}
			string rendererRole2 = GetRendererRole(((Object)val2).name);
			if (string.IsNullOrEmpty(rendererRole2))
			{
				continue;
			}
			if (!dictionary.TryGetValue(rendererRole2, out var value))
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[Lox More] Missing target renderer: " + rendererRole2));
				continue;
			}
			if ((Object)(object)val2.sharedMesh == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[Lox More] Missing source mesh in " + ((Object)sourcePrefab).name + ": " + ((Object)val2).name));
				continue;
			}
			Transform[] array3 = MapBones(val2, targetBones);
			if (array3 == null)
			{
				continue;
			}
			Transform val3 = FindMappedRootBone(val2, targetBones);
			if ((Object)(object)val2.rootBone != (Object)null && (Object)(object)val3 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[Lox More] Failed to map root bone: " + ((Object)val2.rootBone).name));
				continue;
			}
			bool enabled = ((Renderer)value).enabled;
			value.sharedMesh = val2.sharedMesh;
			((Renderer)value).sharedMaterials = CopyMaterialArray(((Renderer)val2).sharedMaterials);
			value.bones = array3;
			if ((Object)(object)val3 != (Object)null)
			{
				value.rootBone = val3;
			}
			((Component)value).transform.localPosition = ((Component)val2).transform.localPosition;
			((Component)value).transform.localRotation = ((Component)val2).transform.localRotation;
			((Component)value).transform.localScale = ((Component)val2).transform.localScale;
			((Renderer)value).localBounds = ((Renderer)val2).localBounds;
			value.updateWhenOffscreen = true;
			((Renderer)value).shadowCastingMode = ((Renderer)val2).shadowCastingMode;
			((Renderer)value).receiveShadows = ((Renderer)val2).receiveShadows;
			((Renderer)value).enabled = enabled;
			num++;
		}
		if (num == 0)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("[Lox More] No renderers replaced for: " + ((Object)sourcePrefab).name));
		}
		return num > 0;
	}

	private static Material[] CopyMaterialArray(Material[] sourceMaterials)
	{
		if (sourceMaterials == null)
		{
			return (Material[])(object)new Material[0];
		}
		Material[] array = (Material[])(object)new Material[sourceMaterials.Length];
		Array.Copy(sourceMaterials, array, sourceMaterials.Length);
		return array;
	}

	private Dictionary<string, Transform> BuildBoneMap(GameObject target)
	{
		Dictionary<string, Transform> dictionary = new Dictionary<string, Transform>(StringComparer.Ordinal);
		Transform[] componentsInChildren = target.GetComponentsInChildren<Transform>(true);
		foreach (Transform val in componentsInChildren)
		{
			if (!((Object)(object)val == (Object)null))
			{
				string text = NormalizeBoneName(((Object)val).name);
				if (!string.IsNullOrEmpty(text) && !dictionary.ContainsKey(text))
				{
					dictionary.Add(text, val);
				}
			}
		}
		return dictionary;
	}

	private static string NormalizeBoneName(string boneName)
	{
		if (string.IsNullOrWhiteSpace(boneName))
		{
			return string.Empty;
		}
		string text = boneName.Trim();
		if (text.EndsWith("_l", StringComparison.OrdinalIgnoreCase))
		{
			text = text.Substring(0, text.Length - 2) + ".l";
		}
		else if (text.EndsWith("_r", StringComparison.OrdinalIgnoreCase))
		{
			text = text.Substring(0, text.Length - 2) + ".r";
		}
		if (text.Length > 4)
		{
			int num = text.Length - 4;
			if (text[num] == '_' && char.IsDigit(text[num + 1]) && char.IsDigit(text[num + 2]) && char.IsDigit(text[num + 3]))
			{
				text = text.Substring(0, num) + "." + text.Substring(num + 1);
			}
		}
		return text.ToLowerInvariant();
	}

	private Transform[] MapBones(SkinnedMeshRenderer source, Dictionary<string, Transform> targetBones)
	{
		Transform[] array = (Transform[])(object)new Transform[source.bones.Length];
		for (int i = 0; i < source.bones.Length; i++)
		{
			Transform val = source.bones[i];
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			string key = NormalizeBoneName(((Object)val).name);
			if (!targetBones.TryGetValue(key, out var value))
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("[Lox More] Missing target bone: " + ((Object)val).name));
				return null;
			}
			array[i] = value;
		}
		return array;
	}

	private Transform FindMappedRootBone(SkinnedMeshRenderer source, Dictionary<string, Transform> targetBones)
	{
		if ((Object)(object)source.rootBone == (Object)null)
		{
			return null;
		}
		if (targetBones.TryGetValue(NormalizeBoneName(((Object)source.rootBone).name), out var value))
		{
			return value;
		}
		return null;
	}

	private LoxVariantDefinition FindAdultVariant(string appearanceId)
	{
		foreach (LoxVariantDefinition adultVariant in _adultVariants)
		{
			if (string.Equals(adultVariant.AppearanceId, appearanceId, StringComparison.OrdinalIgnoreCase))
			{
				return adultVariant;
			}
		}
		return null;
	}

	private static Component FindComponentByTypeName(GameObject gameObject, string typeName)
	{
		Component[] components = gameObject.GetComponents<Component>();
		foreach (Component val in components)
		{
			if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == typeName)
			{
				return val;
			}
		}
		return null;
	}

	private void EnableLoxFollowCommands(GameObject loxPrefab)
	{
		Component val = FindComponentByTypeName(loxPrefab, "Tameable");
		if (!((Object)(object)val == (Object)null))
		{
			FieldInfo field = ((object)val).GetType().GetField("m_commandable", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				field.SetValue(val, true);
			}
		}
	}

	private void OnDestroy()
	{
		PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable;
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
			_harmony = null;
		}
		if ((Object)(object)_assetBundle != (Object)null)
		{
			_assetBundle.Unload(false);
			_assetBundle = null;
		}
		if ((Object)(object)Instance == (Object)(object)this)
		{
			Instance = null;
		}
	}
}
public sealed class LoxRagdollAppearanceController : MonoBehaviour
{
	private const string AppearanceZdoKey = "Moddermother.LoxMore.Appearance";

	private const float NetworkCheckInterval = 0.1f;

	private const int MaxNetworkChecks = 50;

	private ZNetView _networkView;

	private string _sourceAppearanceId = string.Empty;

	private string _appliedAppearanceId = string.Empty;

	public void SetAppearanceFromSource(string appearanceId)
	{
		_sourceAppearanceId = appearanceId ?? string.Empty;
	}

	private IEnumerator Start()
	{
		_networkView = ((Component)this).GetComponent<ZNetView>();
		if ((Object)(object)_networkView == (Object)null)
		{
			yield break;
		}
		while (!_networkView.IsValid() || _networkView.GetZDO() == null)
		{
			yield return null;
		}
		ZDO zdo = _networkView.GetZDO();
		if (_networkView.IsOwner() && !string.IsNullOrEmpty(_sourceAppearanceId))
		{
			zdo.Set("Moddermother.LoxMore.Appearance", _sourceAppearanceId);
		}
		string appearanceId = zdo.GetString("Moddermother.LoxMore.Appearance", string.Empty);
		int checks = 0;
		while (string.IsNullOrEmpty(appearanceId) && checks < 50)
		{
			checks++;
			if (!string.IsNullOrEmpty(_sourceAppearanceId))
			{
				appearanceId = _sourceAppearanceId;
				if (_networkView.IsOwner())
				{
					zdo.Set("Moddermother.LoxMore.Appearance", appearanceId);
				}
				break;
			}
			yield return (object)new WaitForSeconds(0.1f);
			if ((Object)(object)_networkView == (Object)null || !_networkView.IsValid())
			{
				yield break;
			}
			zdo = _networkView.GetZDO();
			if (zdo != null)
			{
				appearanceId = zdo.GetString("Moddermother.LoxMore.Appearance", string.Empty);
			}
		}
		if (string.IsNullOrEmpty(appearanceId))
		{
			appearanceId = "vanilla";
		}
		ApplyAppearance(appearanceId);
	}

	private void ApplyAppearance(string appearanceId)
	{
		if (!string.Equals(_appliedAppearanceId, appearanceId, StringComparison.OrdinalIgnoreCase))
		{
			LoxMorePlugin instance = LoxMorePlugin.Instance;
			if (!((Object)(object)instance == (Object)null) && instance.ApplyAdultRagdollAppearance(((Component)this).gameObject, appearanceId))
			{
				_appliedAppearanceId = appearanceId;
			}
		}
	}
}
[HarmonyPatch(typeof(Humanoid), "OnRagdollCreated")]
internal static class LoxRagdollCreatedPatch
{
	private static void Postfix(Humanoid __instance, Ragdoll ragdoll)
	{
		if ((Object)(object)__instance == (Object)null || (Object)(object)ragdoll == (Object)null)
		{
			return;
		}
		LoxAppearanceController component = ((Component)__instance).GetComponent<LoxAppearanceController>();
		if (!((Object)(object)component == (Object)null))
		{
			string text = component.GetStoredAppearanceId();
			if (string.IsNullOrEmpty(text))
			{
				text = "vanilla";
			}
			LoxRagdollAppearanceController loxRagdollAppearanceController = ((Component)ragdoll).GetComponent<LoxRagdollAppearanceController>();
			if ((Object)(object)loxRagdollAppearanceController == (Object)null)
			{
				loxRagdollAppearanceController = ((Component)ragdoll).gameObject.AddComponent<LoxRagdollAppearanceController>();
			}
			loxRagdollAppearanceController.SetAppearanceFromSource(text);
		}
	}
}