Decompiled source of LinkMajorasMask3DModel v0.1.1

LinkMM3DTwo.dll

Decompiled an hour ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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 GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("LinkMM3DTwo")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LinkMM3DTwo")]
[assembly: AssemblyTitle("LinkMM3DTwo")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
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 ModelReplacement
{
	internal static class LinkMMExpressionSettings
	{
		internal static readonly ManualLogSource Log;

		private static readonly ConfigEntry<bool> enableExpressions;

		private static readonly ConfigEntry<bool> enableBlink;

		private static readonly ConfigEntry<bool> enableDeathSound;

		private static readonly ConfigEntry<float> deathVolume;

		private static readonly ConfigEntry<bool> enableActionSounds;

		private static readonly ConfigEntry<float> actionVolume;

		internal static bool Expressions => enableExpressions.Value;

		internal static bool Blink => enableBlink.Value;

		internal static bool DeathSoundEnabled => enableDeathSound.Value;

		internal static float DeathVolume => deathVolume.Value;

		internal static bool ActionSoundsEnabled => enableActionSounds.Value;

		internal static float ActionVolume => actionVolume.Value;

		static LinkMMExpressionSettings()
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			Log = Logger.CreateLogSource("LinkMMExpressions");
			ConfigFile val = new ConfigFile(Path.Combine(Paths.ConfigPath, "LinkMM.Expressions.cfg"), true);
			enableExpressions = val.Bind<bool>("Link", "Enable expressions", true, "Turns face expression changes on/off (pointing, dancing, getting hit, dying).");
			enableBlink = val.Bind<bool>("Link", "Enable blinking", true, "Turns blinking on/off while the character is idle.");
			enableDeathSound = val.Bind<bool>("Link", "Enable death sound", true, "Turns the death scream on/off.");
			deathVolume = val.Bind<float>("Link", "Death sound volume", 1f, new ConfigDescription("Volume of the death scream (0 to 1).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			enableActionSounds = val.Bind<bool>("Link", "Enable action sounds", true, "Turns the sounds for picking up an item, dropping an item and getting hit on/off.");
			actionVolume = val.Bind<float>("Link", "Action sounds volume", 1f, new ConfigDescription("Volume of the pickup/drop/hit sounds (0 to 1).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		}
	}
	public class MRMMCLINK : BodyReplacementBase
	{
		protected override GameObject LoadAssetsAndReturnModel()
		{
			string text = "MMCLink";
			GameObject val = Assets.MainAssetBundle.LoadAsset<GameObject>(text);
			if ((Object)(object)val != (Object)null && (LinkMMExpressionSettings.Expressions || LinkMMExpressionSettings.DeathSoundEnabled || LinkMMExpressionSettings.ActionSoundsEnabled) && (Object)(object)val.GetComponent<LinkMMFaceController>() == (Object)null)
			{
				val.AddComponent<LinkMMFaceController>();
			}
			return val;
		}

		protected override void OnEmoteStart(int emoteId)
		{
			LinkMMFaceController face = GetFace(base.replacementModel);
			if ((Object)(object)face != (Object)null)
			{
				face.StartEmote(emoteId);
			}
		}

		protected override void OnEmoteEnd()
		{
			LinkMMFaceController face = GetFace(base.replacementModel);
			if ((Object)(object)face != (Object)null)
			{
				face.EndEmote();
			}
		}

		protected override void OnDeath()
		{
			if (!((Object)(object)base.replacementDeadBody == (Object)null) && (LinkMMExpressionSettings.Expressions || LinkMMExpressionSettings.DeathSoundEnabled))
			{
				LinkMMFaceController linkMMFaceController = GetFace(base.replacementDeadBody);
				if ((Object)(object)linkMMFaceController == (Object)null)
				{
					linkMMFaceController = base.replacementDeadBody.AddComponent<LinkMMFaceController>();
				}
				linkMMFaceController.SetDead();
			}
		}

		private LinkMMFaceController GetFace(GameObject obj)
		{
			if ((Object)(object)obj == (Object)null)
			{
				return null;
			}
			LinkMMFaceController componentInChildren = obj.GetComponentInChildren<LinkMMFaceController>(true);
			if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.Player == (Object)null)
			{
				componentInChildren.Player = ((Component)this).GetComponent<PlayerControllerB>();
			}
			return componentInChildren;
		}
	}
	public class LinkMMFaceController : MonoBehaviour
	{
		private class FacePart
		{
			public string materialName;

			public string keyword;

			public Renderer renderer;

			public int index = -1;

			public MaterialPropertyBlock block = new MaterialPropertyBlock();

			public string current;

			public string textureProperty;

			public bool IsValid => (Object)(object)renderer != (Object)null && index >= 0;

			public FacePart(string name, string key)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				//IL_0012: Expected O, but got Unknown
				materialName = name;
				keyword = key;
			}
		}

		private const string EyesMaterialName = "MM_Link_Eyes";

		private const string MouthMaterialName = "MM_Link_Mouth";

		private const string EyesKeyword = "eye";

		private const string MouthKeyword = "mouth";

		private const string TextureProperty = "_BaseColorMap";

		private const string EyesOpen = "MM_Link_Eyes_Open";

		private const string EyesBlink = "MM_Link_Eyes_Blink";

		private const string EyesPoint = "MM_Link_Eyes_Point";

		private const string EyesDance = "MM_Link_Eyes_Dance";

		private const string EyesDead = "MM_Link_Eyes_Dead";

		private const string MouthNeutral = "MM_Link_Mouth_Neutral";

		private const string MouthPoint = "MM_Link_Mouth_Point";

		private const string MouthDance = "MM_Link_Mouth_Dance";

		private const string MouthDead = "MM_Link_Mouth_Dead";

		private const string DeathClipName = "MM_Link_Death";

		private const string PickupClipName = "MM_Link_Pickup";

		private const string DropClipName = "MM_Link_Drop";

		private const string HitClipName = "MM_Link_Hit";

		private const float HitFlashSeconds = 0.3f;

		private static readonly Dictionary<string, Texture2D> textureCache = new Dictionary<string, Texture2D>();

		private FacePart eyes = new FacePart("MM_Link_Eyes", "eye");

		private FacePart mouth = new FacePart("MM_Link_Mouth", "mouth");

		public PlayerControllerB Player;

		private float notEmotingSince = -1f;

		private bool lastPerforming;

		private int lastNumber;

		private bool animChecked;

		private bool hasEmoteNumber;

		private bool deathSoundPlayed;

		private AudioSource actionSource;

		private int lastHealth = -1;

		private int lastItemCount = -1;

		private float lastHitTime;

		private bool isHitFlashing;

		private float hitFlashEnd;

		private bool partsSearched;

		private bool isEmoting;

		private bool isDead;

		private bool isBlinking;

		private int emoteId;

		private float nextBlinkTime;

		private float blinkEndTime;

		private static readonly Dictionary<string, AudioClip> clipCache = new Dictionary<string, AudioClip>();

		private static bool dumped;

		private static readonly Dictionary<string, Material> materialCache = new Dictionary<string, Material>();

		private bool FaceLocked => isEmoting && (emoteId == 1 || emoteId == 2);

		private void Start()
		{
			if ((Object)(object)Player == (Object)null)
			{
				Player = ((Component)this).GetComponentInParent<PlayerControllerB>(true);
			}
			EnsureParts();
			ApplyCurrentFace();
			ScheduleNextBlink();
		}

		private void Update()
		{
			if (isDead)
			{
				return;
			}
			if ((Object)(object)Player != (Object)null)
			{
				PollPlayer();
				PollActions();
			}
			if (isEmoting && (Object)(object)Player != (Object)null)
			{
				if (Player.performingEmote)
				{
					notEmotingSince = -1f;
				}
				else if (notEmotingSince < 0f)
				{
					notEmotingSince = Time.time;
				}
				else if (Time.time - notEmotingSince > 0.5f)
				{
					LinkMMExpressionSettings.Log.LogInfo((object)"Emote ended without notice; returning to the normal face.");
					EndEmote();
				}
			}
			if (isHitFlashing && Time.time >= hitFlashEnd)
			{
				isHitFlashing = false;
				ApplyCurrentFace();
				ScheduleNextBlink();
			}
			if (!LinkMMExpressionSettings.Expressions || !LinkMMExpressionSettings.Blink || !eyes.IsValid || FaceLocked || isHitFlashing)
			{
				return;
			}
			float time = Time.time;
			if (isBlinking)
			{
				if (time >= blinkEndTime)
				{
					isBlinking = false;
					SetPart(eyes, "MM_Link_Eyes_Open");
					ScheduleNextBlink();
				}
			}
			else if (time >= nextBlinkTime)
			{
				isBlinking = true;
				blinkEndTime = time + 0.12f;
				SetPart(eyes, "MM_Link_Eyes_Blink");
			}
		}

		public void StartEmote(int id)
		{
			if (!isEmoting || emoteId != id)
			{
				LinkMMExpressionSettings.Log.LogInfo((object)("Emote started (id " + id + ")."));
				if (LinkMMExpressionSettings.Expressions && !isDead)
				{
					isEmoting = true;
					isBlinking = false;
					notEmotingSince = -1f;
					emoteId = id;
					ApplyCurrentFace();
				}
			}
		}

		public void EndEmote()
		{
			LinkMMExpressionSettings.Log.LogInfo((object)"Emote ended.");
			isEmoting = false;
			isBlinking = false;
			emoteId = 0;
			notEmotingSince = -1f;
			if (LinkMMExpressionSettings.Expressions && !isDead)
			{
				ApplyCurrentFace();
				ScheduleNextBlink();
			}
		}

		public void SetDead()
		{
			isDead = true;
			isBlinking = false;
			isHitFlashing = false;
			PlayDeathSound();
			if (LinkMMExpressionSettings.Expressions)
			{
				ApplyCurrentFace();
			}
		}

		private void PlayDeathSound()
		{
			if (!deathSoundPlayed && LinkMMExpressionSettings.DeathSoundEnabled)
			{
				deathSoundPlayed = true;
				AudioClip clip = GetClip("MM_Link_Death", warn: true);
				if (!((Object)(object)clip == (Object)null))
				{
					AudioSource val = ((Component)this).gameObject.AddComponent<AudioSource>();
					val.clip = clip;
					val.volume = LinkMMExpressionSettings.DeathVolume;
					val.spatialBlend = 1f;
					val.rolloffMode = (AudioRolloffMode)1;
					val.minDistance = 4f;
					val.maxDistance = 45f;
					val.playOnAwake = false;
					val.Play();
					Object.Destroy((Object)(object)val, clip.length + 0.5f);
				}
			}
		}

		private static AudioClip GetClip(string name, bool warn)
		{
			if (clipCache.TryGetValue(name, out AudioClip value))
			{
				return value;
			}
			AudioClip val = Assets.MainAssetBundle.LoadAsset<AudioClip>(name);
			if ((Object)(object)val == (Object)null && warn)
			{
				LinkMMExpressionSettings.Log.LogWarning((object)("AudioClip '" + name + "' was not found in the AssetBundle."));
			}
			clipCache[name] = val;
			return val;
		}

		private void PlayAction(string baseName, int expected = 1)
		{
			AudioClip[] array = (AudioClip[])(object)new AudioClip[3];
			int num = 0;
			AudioClip clip = GetClip(baseName, warn: true);
			if ((Object)(object)clip != (Object)null)
			{
				array[num++] = clip;
			}
			clip = GetClip(baseName + "2", expected >= 2);
			if ((Object)(object)clip != (Object)null)
			{
				array[num++] = clip;
			}
			clip = GetClip(baseName + "3", expected >= 3);
			if ((Object)(object)clip != (Object)null)
			{
				array[num++] = clip;
			}
			if (num != 0)
			{
				if ((Object)(object)actionSource == (Object)null)
				{
					actionSource = ((Component)this).gameObject.AddComponent<AudioSource>();
					actionSource.playOnAwake = false;
					actionSource.spatialBlend = 1f;
					actionSource.rolloffMode = (AudioRolloffMode)1;
					actionSource.minDistance = 4f;
					actionSource.maxDistance = 45f;
				}
				actionSource.PlayOneShot(array[Random.Range(0, num)], LinkMMExpressionSettings.ActionVolume);
			}
		}

		private void PollActions()
		{
			if (Player.isPlayerDead)
			{
				return;
			}
			bool actionSoundsEnabled = LinkMMExpressionSettings.ActionSoundsEnabled;
			bool expressions = LinkMMExpressionSettings.Expressions;
			if (!actionSoundsEnabled && !expressions)
			{
				return;
			}
			int health = Player.health;
			if (lastHealth >= 0 && health < lastHealth && health > 0)
			{
				if (actionSoundsEnabled && Time.time - lastHitTime > 0.4f)
				{
					lastHitTime = Time.time;
					PlayAction("MM_Link_Hit", 3);
				}
				if (expressions)
				{
					StartHitFlash();
				}
			}
			lastHealth = health;
			if (!actionSoundsEnabled)
			{
				return;
			}
			int num = CountItems();
			if (lastItemCount >= 0)
			{
				if (num > lastItemCount)
				{
					PlayAction("MM_Link_Pickup");
				}
				else if (num < lastItemCount)
				{
					PlayAction("MM_Link_Drop");
				}
			}
			lastItemCount = num;
		}

		private int CountItems()
		{
			GrabbableObject[] itemSlots = Player.ItemSlots;
			if (itemSlots == null)
			{
				return 0;
			}
			int num = 0;
			for (int i = 0; i < itemSlots.Length; i++)
			{
				if ((Object)(object)itemSlots[i] != (Object)null)
				{
					num++;
				}
			}
			return num;
		}

		private void StartHitFlash()
		{
			isHitFlashing = true;
			isBlinking = false;
			hitFlashEnd = Time.time + 0.3f;
			ApplyCurrentFace();
		}

		private void PollPlayer()
		{
			bool performingEmote = Player.performingEmote;
			int num = (performingEmote ? ReadEmoteNumber() : 0);
			if (performingEmote != lastPerforming || num != lastNumber)
			{
				lastPerforming = performingEmote;
				lastNumber = num;
				LinkMMExpressionSettings.Log.LogInfo((object)("Player state changed: performingEmote=" + performingEmote + ", emoteNumber=" + num));
				if (performingEmote)
				{
					StartEmote(num);
				}
				else if (isEmoting)
				{
					EndEmote();
				}
			}
		}

		private int ReadEmoteNumber()
		{
			Animator playerBodyAnimator = Player.playerBodyAnimator;
			if ((Object)(object)playerBodyAnimator == (Object)null)
			{
				return 0;
			}
			if (!animChecked)
			{
				animChecked = true;
				AnimatorControllerParameter[] parameters = playerBodyAnimator.parameters;
				foreach (AnimatorControllerParameter val in parameters)
				{
					if (val.name == "emoteNumber")
					{
						hasEmoteNumber = true;
					}
				}
			}
			return hasEmoteNumber ? playerBodyAnimator.GetInteger("emoteNumber") : 0;
		}

		private void ApplyCurrentFace()
		{
			if (LinkMMExpressionSettings.Expressions)
			{
				EnsureParts();
				if (isDead || isHitFlashing)
				{
					SetPart(eyes, "MM_Link_Eyes_Dead");
					SetPart(mouth, "MM_Link_Mouth_Dead");
				}
				else if (isEmoting && emoteId == 1)
				{
					SetPart(eyes, "MM_Link_Eyes_Dance");
					SetPart(mouth, "MM_Link_Mouth_Dance");
				}
				else if (isEmoting && emoteId == 2)
				{
					SetPart(eyes, "MM_Link_Eyes_Point");
					SetPart(mouth, "MM_Link_Mouth_Point");
				}
				else
				{
					SetPart(eyes, "MM_Link_Eyes_Open");
					SetPart(mouth, "MM_Link_Mouth_Neutral");
				}
			}
		}

		private void EnsureParts()
		{
			if (!partsSearched)
			{
				partsSearched = true;
				bool flag = FindPart(((Component)this).gameObject, eyes);
				bool flag2 = FindPart(((Component)this).gameObject, mouth);
				if (!flag)
				{
					LinkMMExpressionSettings.Log.LogWarning((object)"Material 'MM_Link_Eyes' was not found in the model.");
				}
				if (!flag2)
				{
					LinkMMExpressionSettings.Log.LogWarning((object)"Material 'MM_Link_Mouth' was not found in the model.");
				}
				if ((!flag || !flag2) && !dumped)
				{
					dumped = true;
					DumpRenderers(((Component)this).gameObject);
				}
			}
		}

		private static void DumpRenderers(GameObject root)
		{
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				string text = "";
				Material[] sharedMaterials = val.sharedMaterials;
				foreach (Material val2 in sharedMaterials)
				{
					text = text + (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "null") + " | ";
				}
				LinkMMExpressionSettings.Log.LogInfo((object)("Renderer '" + ((Object)((Component)val).gameObject).name + "' (" + ((object)val).GetType().Name + ") materials: " + text));
			}
		}

		private void ScheduleNextBlink()
		{
			nextBlinkTime = Time.time + Random.Range(2f, 6f);
		}

		private static void SetPart(FacePart part, string assetName)
		{
			if (part == null || !part.IsValid)
			{
				return;
			}
			Material material = GetMaterial(assetName);
			if ((Object)(object)material != (Object)null)
			{
				Material[] sharedMaterials = part.renderer.sharedMaterials;
				if (part.index < sharedMaterials.Length)
				{
					if ((Object)(object)sharedMaterials[part.index] != (Object)(object)material)
					{
						sharedMaterials[part.index] = material;
						part.renderer.sharedMaterials = sharedMaterials;
					}
					part.current = assetName;
				}
			}
			else if (!(part.current == assetName))
			{
				Texture2D texture = GetTexture(assetName);
				if (!((Object)(object)texture == (Object)null))
				{
					part.renderer.GetPropertyBlock(part.block, part.index);
					part.block.SetTexture(part.textureProperty ?? "_BaseColorMap", (Texture)(object)texture);
					part.renderer.SetPropertyBlock(part.block, part.index);
					part.current = assetName;
				}
			}
		}

		private static Material GetMaterial(string name)
		{
			if (materialCache.TryGetValue(name, out Material value))
			{
				return value;
			}
			Material val = Assets.MainAssetBundle.LoadAsset<Material>(name);
			materialCache[name] = val;
			return val;
		}

		private static Texture2D GetTexture(string name)
		{
			if (textureCache.TryGetValue(name, out Texture2D value))
			{
				return value;
			}
			Texture2D val = Assets.MainAssetBundle.LoadAsset<Texture2D>(name);
			if ((Object)(object)val == (Object)null)
			{
				LinkMMExpressionSettings.Log.LogWarning((object)("Neither a material nor a texture named '" + name + "' was found in the AssetBundle."));
			}
			textureCache[name] = val;
			return val;
		}

		private static string ResolveTextureProperty(Material mat)
		{
			if (mat.HasProperty("_BaseColorMap"))
			{
				return "_BaseColorMap";
			}
			string[] array = new string[3] { "_BaseColorMap", "_MainTex", "_BaseMap" };
			string[] array2 = array;
			foreach (string text in array2)
			{
				if (mat.HasProperty(text))
				{
					return text;
				}
			}
			string[] texturePropertyNames = mat.GetTexturePropertyNames();
			foreach (string text2 in texturePropertyNames)
			{
				if (!text2.StartsWith("unity_"))
				{
					return text2;
				}
			}
			return "_BaseColorMap";
		}

		private static bool FindPart(GameObject root, FacePart part)
		{
			if ((Object)(object)root == (Object)null)
			{
				return false;
			}
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				Material[] sharedMaterials = val.sharedMaterials;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if ((Object)(object)sharedMaterials[j] != (Object)null && ((Object)sharedMaterials[j]).name.StartsWith(part.materialName))
					{
						return Assign(part, val, j, sharedMaterials[j]);
					}
				}
			}
			Renderer[] array2 = componentsInChildren;
			foreach (Renderer val2 in array2)
			{
				Material[] sharedMaterials2 = val2.sharedMaterials;
				for (int l = 0; l < sharedMaterials2.Length; l++)
				{
					if (!((Object)(object)sharedMaterials2[l] == (Object)null))
					{
						string text = ((Object)sharedMaterials2[l]).name.ToLowerInvariant();
						string text2 = ((Object)((Component)val2).gameObject).name.ToLowerInvariant();
						if (text.Contains(part.keyword) || text2.Contains(part.keyword))
						{
							return Assign(part, val2, l, sharedMaterials2[l]);
						}
					}
				}
			}
			return false;
		}

		private static bool Assign(FacePart part, Renderer r, int index, Material mat)
		{
			part.renderer = r;
			part.index = index;
			part.textureProperty = ResolveTextureProperty(mat);
			LinkMMExpressionSettings.Log.LogInfo((object)("'" + part.materialName + "' linked to material '" + ((Object)mat).name + "' (object '" + ((Object)((Component)r).gameObject).name + "', property '" + part.textureProperty + "')."));
			return true;
		}
	}
	public class MRMMCLINK_ : BodyReplacementBase
	{
		protected override GameObject LoadAssetsAndReturnModel()
		{
			string text = "MMCLink";
			return Assets.MainAssetBundle.LoadAsset<GameObject>(text);
		}
	}
	[BepInPlugin("linkmmem", "LinkMajorasMask3DModel", "0.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public static ConfigFile config;

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

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

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

		private static void InitConfig()
		{
			enableModelForAllSuits = config.Bind<bool>("Suits to Replace Settings", "Enable Model for all Suits", false, "Enable to model replace every suit. Set to false to specify suits");
			enableModelAsDefault = config.Bind<bool>("Suits to Replace Settings", "Enable Model as default", false, "Enable to model replace every suit that hasn't been otherwise registered.");
			suitNamesToEnableModel = config.Bind<string>("Suits to Replace Settings", "Suits to enable Model for", "linkmmem", "Enter a comma separated list of suit names.(Additionally, [Green suit,Pajama suit,Hazard suit])");
		}

		private void Awake()
		{
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			config = ((BaseUnityPlugin)this).Config;
			InitConfig();
			Assets.PopulateAssets();
			if (enableModelForAllSuits.Value)
			{
				ModelReplacementAPI.RegisterModelReplacementOverride(typeof(MRMMCLINK));
			}
			if (enableModelAsDefault.Value)
			{
				ModelReplacementAPI.RegisterModelReplacementDefault(typeof(MRMMCLINK));
			}
			string[] array = suitNamesToEnableModel.Value.Split(',');
			string[] array2 = array;
			foreach (string text in array2)
			{
				ModelReplacementAPI.RegisterSuitModelReplacement("LinkMM", typeof(MRMMCLINK));
			}
			Harmony val = new Harmony("linkmmem");
			val.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin linkmmem is loaded!");
		}
	}
	public static class Assets
	{
		public static string mainAssetBundleName = "linkmmdbundle";

		public static AssetBundle MainAssetBundle = null;

		private static string GetAssemblyName()
		{
			return Assembly.GetExecutingAssembly().GetName().Name.Replace(" ", "_");
		}

		public static void PopulateAssets()
		{
			if ((Object)(object)MainAssetBundle == (Object)null)
			{
				Console.WriteLine(GetAssemblyName() + "." + mainAssetBundleName);
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetAssemblyName() + "." + mainAssetBundleName);
				MainAssetBundle = AssetBundle.LoadFromStream(stream);
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}