Decompiled source of AshleyRE4Model v1.0.3

AshleyGrahamReplacement.dll

Decompiled 2 weeks ago
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ModelReplacement;
using ModelReplacement.AvatarBodyUpdater;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AshleyGrahamReplacement")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Ashley Graham (Resident Evil 4) character model replacement for Lethal Company")]
[assembly: AssemblyFileVersion("1.0.3.0")]
[assembly: AssemblyInformationalVersion("1.0.3")]
[assembly: AssemblyProduct("AshleyGrahamReplacement")]
[assembly: AssemblyTitle("AshleyGrahamReplacement")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.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 AshleyGrahamReplacement
{
	public class AshleyGrahamModel : BodyReplacementBase
	{
		protected override GameObject LoadAssetsAndReturnModel()
		{
			//IL_0230: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0492: Unknown result type (might be due to invalid IL or missing references)
			//IL_0498: Expected O, but got Unknown
			if ((Object)(object)Assets.MainAssetBundle == (Object)null)
			{
				Plugin.Logger.LogError((object)"Cannot load Ashley Graham model: AssetBundle is null.");
				return null;
			}
			string[] obj = new string[3] { "Ashley Graham", "AshleyGraham", "demo2" };
			GameObject val = null;
			string[] array = obj;
			foreach (string text in array)
			{
				val = Assets.MainAssetBundle.LoadAsset<GameObject>(text);
				if ((Object)(object)val != (Object)null)
				{
					Plugin.Logger.LogInfo((object)("Loaded prefab '" + text + "' from AssetBundle."));
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				string[] allAssetNames = Assets.MainAssetBundle.GetAllAssetNames();
				Plugin.Logger.LogWarning((object)$"Named prefabs not found. Bundle contains {allAssetNames.Length} assets:");
				array = allAssetNames;
				foreach (string text2 in array)
				{
					Plugin.Logger.LogWarning((object)("  - " + text2));
					if ((Object)(object)val == (Object)null)
					{
						GameObject val2 = Assets.MainAssetBundle.LoadAsset<GameObject>(text2);
						if ((Object)(object)val2 != (Object)null)
						{
							val = val2;
							Plugin.Logger.LogInfo((object)("Using asset '" + text2 + "' as model prefab."));
						}
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Logger.LogError((object)"No GameObject prefab found in AssetBundle.");
				return null;
			}
			Animator val3 = val.GetComponentInChildren<Animator>();
			if ((Object)(object)val3 == (Object)null)
			{
				Plugin.Logger.LogWarning((object)"No Animator found on prefab. Adding one to root SkinnedMeshRenderer or root.");
				SkinnedMeshRenderer componentInChildren = val.GetComponentInChildren<SkinnedMeshRenderer>();
				GameObject val4 = (((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).gameObject : val);
				val3 = val4.AddComponent<Animator>();
				Plugin.Logger.LogInfo((object)("Animator added to '" + ((Object)val4).name + "'."));
			}
			OffsetBuilder val5 = ((Component)val3).gameObject.GetComponent<OffsetBuilder>();
			if ((Object)(object)val5 == (Object)null)
			{
				val5 = ((Component)val3).gameObject.AddComponent<OffsetBuilder>();
				val5.rootScale = Vector3.one;
				val5.UseNoPostProcessing = false;
				val5.GenerateViewModel = Plugin.EnableCustomViewModel.Value;
				val5.RemoveHelmet = Plugin.RemoveHelmetSetting.Value;
				Plugin.Logger.LogInfo((object)"OffsetBuilder component injected at runtime.");
			}
			val5.rootPositionOffset = new Vector3(0f, Plugin.RootOffsetY.Value, Plugin.RootOffsetZ.Value);
			Plugin.Logger.LogInfo((object)$"Root position offset set to ({val5.rootPositionOffset.x}, {val5.rootPositionOffset.y}, {val5.rootPositionOffset.z}).");
			RotationOffset component = val.GetComponent<RotationOffset>();
			if ((Object)(object)component != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component);
			}
			SkinnedMeshRenderer[] componentsInChildren = val.GetComponentsInChildren<SkinnedMeshRenderer>(true);
			foreach (SkinnedMeshRenderer val6 in componentsInChildren)
			{
				if ((Object)(object)val6.sharedMesh == (Object)null || !val6.sharedMesh.isReadable)
				{
					continue;
				}
				try
				{
					Material[] sharedMaterials = ((Renderer)val6).sharedMaterials;
					bool flag = false;
					for (int j = 0; j < sharedMaterials.Length; j++)
					{
						if ((Object)(object)sharedMaterials[j] != (Object)null && (((Object)sharedMaterials[j]).name.IndexOf("wetness", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)sharedMaterials[j]).name.IndexOf("AO_m", StringComparison.OrdinalIgnoreCase) >= 0))
						{
							flag = true;
							break;
						}
					}
					if (!flag)
					{
						continue;
					}
					Mesh val7 = Object.Instantiate<Mesh>(val6.sharedMesh);
					for (int k = 0; k < sharedMaterials.Length; k++)
					{
						if ((Object)(object)sharedMaterials[k] != (Object)null && (((Object)sharedMaterials[k]).name.IndexOf("wetness", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)sharedMaterials[k]).name.IndexOf("AO_m", StringComparison.OrdinalIgnoreCase) >= 0))
						{
							val7.SetTriangles(new int[0], k);
							Plugin.Logger.LogInfo((object)$"Runtime: Zeroed out submesh {k} ({((Object)sharedMaterials[k]).name}) on '{((Object)val6).name}' to remove occluding shell.");
						}
					}
					val6.sharedMesh = val7;
				}
				catch (Exception ex)
				{
					Plugin.Logger.LogWarning((object)("Could not clean submeshes on '" + ((Object)val6).name + "' at runtime (already cleaned at build time): " + ex.Message));
				}
			}
			Renderer[] componentsInChildren2 = val.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val8 in componentsInChildren2)
			{
				Material[] sharedMaterials2 = val8.sharedMaterials;
				bool flag2 = false;
				for (int l = 0; l < sharedMaterials2.Length; l++)
				{
					if ((Object)(object)sharedMaterials2[l] == (Object)null)
					{
						flag2 = true;
						Shader val9 = Shader.Find("HDRP/Lit") ?? Shader.Find("Standard") ?? Shader.Find("Sprites/Default");
						if ((Object)(object)val9 != (Object)null)
						{
							sharedMaterials2[l] = new Material(val9);
						}
						ManualLogSource logger = Plugin.Logger;
						string name = ((Object)val8).name;
						object arg = l;
						Material obj2 = sharedMaterials2[l];
						object obj3;
						if (obj2 == null)
						{
							obj3 = null;
						}
						else
						{
							Shader shader = obj2.shader;
							obj3 = ((shader != null) ? ((Object)shader).name : null);
						}
						if (obj3 == null)
						{
							obj3 = "none";
						}
						logger.LogWarning((object)$"Renderer '{name}' had null material at slot {arg}; replaced with fallback shader '{obj3}'.");
					}
				}
				if (flag2)
				{
					val8.sharedMaterials = sharedMaterials2;
				}
			}
			return val;
		}

		protected override void AddModelScripts()
		{
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)base.replacementModel == (Object)null)
			{
				return;
			}
			Renderer[] componentsInChildren = base.replacementModel.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material[] materials = componentsInChildren[i].materials;
				for (int j = 0; j < materials.Length; j++)
				{
					if ((Object)(object)materials[j] != (Object)null && ((Object)materials[j]).name.IndexOf("eyes_m", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						materials[j].EnableKeyword("_EMISSION");
						if (materials[j].HasProperty("_EmissiveColor"))
						{
							materials[j].SetColor("_EmissiveColor", new Color(0.2f, 0.2f, 0.2f, 1f));
						}
						if (materials[j].HasProperty("_EmissionColor"))
						{
							materials[j].SetColor("_EmissionColor", new Color(0.2f, 0.2f, 0.2f, 1f));
						}
						Plugin.Logger.LogInfo((object)("Set natural eye illumination on '" + ((Object)materials[j]).name + "'."));
					}
				}
			}
		}
	}
	public static class Assets
	{
		public const string AssetBundleName = "ashleygraham";

		public const string SecondaryBundleName = "AshleyGrahamRE4bundle";

		public const string PrefabModelName = "Ashley Graham";

		public const string FallbackPrefabModelName = "AshleyGraham";

		public static AssetBundle MainAssetBundle { get; private set; }

		public static void PopulateAssets()
		{
			if ((Object)(object)MainAssetBundle != (Object)null)
			{
				return;
			}
			string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			string[] obj = new string[6]
			{
				Path.Combine(directoryName, "ashleygraham"),
				Path.Combine(directoryName, "AshleyGrahamRE4bundle"),
				Path.Combine(directoryName, "AssetBundles", "ashleygraham"),
				Path.Combine(directoryName, "AssetBundles", "AshleyGrahamRE4bundle"),
				Path.Combine(Directory.GetCurrentDirectory(), "ashleygraham"),
				Path.Combine(Directory.GetCurrentDirectory(), "AshleyGrahamRE4bundle")
			};
			string text = null;
			string[] array = obj;
			foreach (string text2 in array)
			{
				if (File.Exists(text2))
				{
					text = text2;
					break;
				}
			}
			if (text == null)
			{
				Plugin.Logger.LogError((object)"AssetBundle 'ashleygraham' could not be located in plugin directory.");
				return;
			}
			MainAssetBundle = AssetBundle.LoadFromFile(text);
			if ((Object)(object)MainAssetBundle == (Object)null)
			{
				Plugin.Logger.LogError((object)("Failed to load AssetBundle from '" + text + "'."));
			}
			else
			{
				Plugin.Logger.LogInfo((object)("Successfully loaded AssetBundle from '" + text + "'."));
			}
		}
	}
	public static class PluginInfo
	{
		public const string GUID = "com.v0id.ashleygraham";

		public const string NAME = "AshleyGrahamReplacement";

		public const string VERSION = "1.0.3";
	}
	[BepInPlugin("com.v0id.ashleygraham", "AshleyGrahamReplacement", "1.0.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public static Plugin Instance { get; private set; }

		public static ManualLogSource Logger { get; private set; }

		public static ConfigEntry<string> SuitNamesToReplace { get; private set; }

		public static ConfigEntry<bool> EnableCustomViewModel { get; private set; }

		public static ConfigEntry<bool> RemoveHelmetSetting { get; private set; }

		public static ConfigEntry<float> RootOffsetY { get; private set; }

		public static ConfigEntry<float> RootOffsetZ { get; private set; }

		private void Awake()
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			InitConfig();
			try
			{
				Assets.PopulateAssets();
				string[] array = (from s in SuitNamesToReplace.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
					select s.Trim()).ToArray();
				foreach (string text in array)
				{
					ModelReplacementAPI.RegisterSuitModelReplacement(text, typeof(AshleyGrahamModel));
					Logger.LogInfo((object)("Registered Ashley Graham model replacement for suit: '" + text + "'"));
				}
				new Harmony("com.v0id.ashleygraham").PatchAll();
				Logger.LogInfo((object)"AshleyGrahamReplacement v1.0.3 initialized successfully.");
			}
			catch (Exception arg)
			{
				Logger.LogError((object)string.Format("Failed to initialize {0}: {1}", "AshleyGrahamReplacement", arg));
			}
		}

		private void InitConfig()
		{
			SuitNamesToReplace = ((BaseUnityPlugin)this).Config.Bind<string>("Suits", "SuitNames", "Ashley Graham", "Comma-separated list of suit names that will trigger the Ashley Graham model replacement (case-sensitive).");
			EnableCustomViewModel = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "EnableViewModel", true, "Generate first-person arms/viewmodel based on the replacement model.");
			RemoveHelmetSetting = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "RemoveHelmet", true, "Remove the scavenger helmet mesh when the Ashley model is active.");
			RootOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Offsets", "RootOffsetY", 0.38f, "Vertical height offset to prevent model shoes sinking into the ground (in meters).");
			RootOffsetZ = ((BaseUnityPlugin)this).Config.Bind<float>("Offsets", "RootOffsetZ", 0f, "Forward/backward offset for the model root (in meters).");
		}
	}
}