Decompiled source of SosigFarce v0.1.3

NGA.SosigFaces.dll

Decompiled 2 months 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.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Sodalite.ModPanel;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyCompany("NGA")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Persistent player progression! Raid, stash loot, and deploy with seemless scene/loadout saving.")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("NGA.SosigFaces")]
[assembly: AssemblyTitle("BepInEx Plugin Title")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace NGA
{
	[BepInPlugin("NGA.SosigFaces", "SosigFaces", "0.0.1")]
	[BepInDependency("nrgill28.Sodalite", "1.0.0")]
	[BepInProcess("h3vr.exe")]
	public class SosigFaces : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(PlayerSosigBody))]
		[HarmonyPatch("Start")]
		public class PlayerSosigBodyAwake : MonoBehaviour
		{
			private static void Postfix(PlayerSosigBody __instance)
			{
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
				if (CheckPlayerSkip())
				{
					return;
				}
				Logger.LogWarning((object)"Trying Player Sosig Start");
				Transform sosig_Head = __instance.Sosig_Head;
				if ((Object)(object)sosig_Head == (Object)null)
				{
					Logger.LogWarning((object)"Player Head not found!");
					return;
				}
				Logger.LogMessage((object)"Doing player face");
				if (!IM.OD.TryGetValue("NGA_PlayerFaceThing", out var value))
				{
					Logger.LogWarning((object)"NGA_FaceThing not found in IM.OD!");
					return;
				}
				GameObject val = Object.Instantiate<GameObject>(((AnvilAsset)value).GetGameObject(), Vector3.zero, Quaternion.identity);
				Logger.LogMessage((object)"Made face");
				val.transform.SetParent(sosig_Head, false);
				Logger.LogMessage((object)"Set face");
				val.transform.localPosition = Vector3.zero;
				val.transform.localRotation = Quaternion.identity;
				FaceLipSync faceLipSync = val.gameObject.AddComponent<FaceLipSync>();
			}
		}

		[HarmonyPatch(typeof(Sosig))]
		[HarmonyPatch("ProcessDamage")]
		[HarmonyPatch(new Type[]
		{
			typeof(float),
			typeof(float),
			typeof(float),
			typeof(float),
			typeof(Vector3),
			typeof(SosigLink)
		})]
		public class SosigProcessDamage : MonoBehaviour
		{
			private static void Postfix(Sosig __instance, float damage_p, float damage_c, float damage_b, float damage_t, Vector3 point, SosigLink link)
			{
				if (!CheckSosigSkip())
				{
					((Component)__instance).GetComponent<EnemyFaceController>().SetState("Damaged");
				}
			}
		}

		[HarmonyPatch(typeof(Sosig))]
		[HarmonyPatch("SosigDies")]
		public class SosigSosigDies : MonoBehaviour
		{
			private static void Postfix(Sosig __instance, DamageClass damClass, SosigDeathType deathType)
			{
				if (!CheckSosigSkip())
				{
					((Component)__instance).GetComponent<EnemyFaceController>().SetState("Dead");
				}
			}
		}

		[HarmonyPatch(typeof(Sosig))]
		[HarmonyPatch("BrainUpdate")]
		public class SosigBrainUpdate : MonoBehaviour
		{
			private static void Postfix(Sosig __instance)
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0053: Expected I4, but got Unknown
				if (!CheckSosigSkip())
				{
					bool flag = false;
					SosigOrder currentOrder = __instance.CurrentOrder;
					SosigOrder val = currentOrder;
					switch ((int)val)
					{
					case 0:
					case 1:
					case 3:
					case 4:
					case 6:
					case 8:
					case 9:
					case 10:
						flag = false;
						break;
					default:
						flag = true;
						break;
					}
					string state = (flag ? "Assaulting" : "Idle");
					((Component)__instance).GetComponent<EnemyFaceController>().SetState(state);
				}
			}
		}

		[HarmonyPatch(typeof(Sosig))]
		[HarmonyPatch("Start")]
		public class SosigAwake : MonoBehaviour
		{
			private static void Postfix(Sosig __instance)
			{
				//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
				//IL_0101: Unknown result type (might be due to invalid IL or missing references)
				//IL_0124: 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)
				if (CheckSosigSkip())
				{
					return;
				}
				bool flag = false;
				foreach (SosigLink link in __instance.Links)
				{
					Transform transform = ((Component)link).transform;
					if (((Object)((Component)link).transform).name != "Sosig_Torso")
					{
						continue;
					}
					if ((Object)(object)((Component)link).transform == (Object)(object)GM.CurrentPlayerBody.Torso)
					{
						flag = true;
					}
					Transform val = transform.Find("Head");
					if ((Object)(object)val == (Object)null)
					{
						Logger.LogWarning((object)"Head not found!");
						break;
					}
					if (flag)
					{
						Logger.LogError((object)"Doing player face when i shouldnt");
						continue;
					}
					if (!IM.OD.TryGetValue("NGA_FaceThing", out var value))
					{
						Logger.LogError((object)"NGA_FaceThing not found in IM.OD!");
						break;
					}
					GameObject val2 = Object.Instantiate<GameObject>(((AnvilAsset)value).GetGameObject(), Vector3.zero, Quaternion.identity);
					val2.transform.SetParent(val, false);
					val2.transform.localPosition = Vector3.zero;
					val2.transform.localRotation = Quaternion.identity;
					EnemyFaceController enemyFaceController = ((Component)__instance).gameObject.AddComponent<EnemyFaceController>();
					enemyFaceController.Init(val2);
				}
			}
		}

		private class FaceThingComponent : MonoBehaviour
		{
			public GameObject attached_face = null;
		}

		public class EnemyFaceController : MonoBehaviour
		{
			private Material faceMaterial;

			private Texture2D idleFace;

			private Texture2D assaultFace;

			private Coroutine damageCoroutine;

			public GameObject attached_face = null;

			private bool dead = false;

			private bool damaged = false;

			public void Init(GameObject face)
			{
				//IL_0044: Unknown result type (might be due to invalid IL or missing references)
				//IL_004e: Expected O, but got Unknown
				attached_face = face;
				Transform val = attached_face.transform.Find("default");
				if ((Object)(object)val != (Object)null)
				{
					Renderer component = ((Component)val).GetComponent<Renderer>();
					if ((Object)(object)component != (Object)null)
					{
						faceMaterial = new Material(component.material);
						component.material = faceMaterial;
					}
					else
					{
						Logger.LogError((object)"Renderer component not found on the 'default' object.");
					}
				}
				else
				{
					Logger.LogError((object)"'Face' object not found among children.");
				}
				SetRandomIdleFace();
			}

			public void SetRandomIdleFace()
			{
				if (!((Object)(object)faceMaterial == (Object)null))
				{
					idleFace = GetRandomTexture(IdleFaces);
					faceMaterial.mainTexture = (Texture)(object)idleFace;
					assaultFace = GetRandomTexture(AssaultingFaces);
				}
			}

			public void SetState(string state)
			{
				if ((Object)(object)faceMaterial == (Object)null || dead)
				{
					return;
				}
				switch (state)
				{
				case "Dead":
					if (damageCoroutine != null)
					{
						((MonoBehaviour)this).StopCoroutine(damageCoroutine);
					}
					faceMaterial.mainTexture = (Texture)(object)GetRandomTexture(DeadFaces);
					dead = true;
					break;
				case "Idle":
					if (!damaged && !((Object)(object)faceMaterial.mainTexture == (Object)(object)idleFace))
					{
						faceMaterial.mainTexture = (Texture)(object)idleFace;
					}
					break;
				case "Assaulting":
					if (!damaged && !((Object)(object)faceMaterial.mainTexture == (Object)(object)assaultFace))
					{
						faceMaterial.mainTexture = (Texture)(object)assaultFace;
					}
					break;
				case "Damaged":
					if (!damaged)
					{
						if (damageCoroutine != null)
						{
							((MonoBehaviour)this).StopCoroutine(damageCoroutine);
						}
						faceMaterial.mainTexture = (Texture)(object)GetRandomTexture(DamagedFaces);
						damageCoroutine = ((MonoBehaviour)this).StartCoroutine(DamageTimeout());
					}
					break;
				}
			}

			private IEnumerator DamageTimeout()
			{
				damaged = true;
				yield return (object)new WaitForSeconds(2f);
				faceMaterial.mainTexture = (Texture)(object)idleFace;
				damaged = false;
			}

			private Texture2D GetRandomTexture(List<Texture2D> textures)
			{
				if (textures.Count == 0)
				{
					Logger.LogError((object)"No textures available for the requested state.");
					return null;
				}
				return textures[Random.Range(0, textures.Count)];
			}
		}

		public class FaceLipSync : MonoBehaviour
		{
			public AudioSource audioSource;

			public Material mouthMaterial;

			public string folderPath;

			public string closedMouthFileName = "mouthClosed.png";

			public string partiallyOpenMouthFileName = "mouthPartiallyOpen.png";

			public string openMouthFileName = "mouthOpen.png";

			public string smileMouthFileName = "mouthSmile.png";

			public string wideOpenMouthFileName = "mouthWideOpen.png";

			public string frownMouthFileName = "mouthFrown.png";

			private Texture2D closedMouthTexture;

			private Texture2D partiallyOpenMouthTexture;

			private Texture2D openMouthTexture;

			private Texture2D smileMouthTexture;

			private Texture2D wideOpenMouthTexture;

			private Texture2D frownMouthTexture;

			private string microphoneName;

			private float lastActiveTime;

			private float lastChosenMouth = Time.time;

			private void Awake()
			{
				if ((Object)(object)audioSource == (Object)null)
				{
					audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
				}
				if ((Object)(object)mouthMaterial == (Object)null)
				{
					Transform val = ((Component)this).transform.Find("mouth");
					if ((Object)(object)val != (Object)null)
					{
						Renderer component = ((Component)val).GetComponent<Renderer>();
						if ((Object)(object)component != (Object)null)
						{
							mouthMaterial = component.material;
						}
						else
						{
							Logger.LogError((object)"Renderer component not found on the 'mouth' object.");
						}
					}
					else
					{
						Logger.LogError((object)"'mouth' object not found among children.");
					}
				}
				LoadTextures();
				InitializeMicrophone();
			}

			private void LoadTextures()
			{
				Logger.LogMessage((object)"LoadTextures");
				folderPath = Paths.PluginPath + "\\NGA-SosigFarce\\";
				Logger.LogMessage((object)("Folder path:" + folderPath + "."));
				Logger.LogMessage((object)("Sample file path:" + folderPath + closedMouthFileName + "."));
				closedMouthTexture = LoadTexture(folderPath + closedMouthFileName);
				partiallyOpenMouthTexture = LoadTexture(folderPath + partiallyOpenMouthFileName);
				openMouthTexture = LoadTexture(folderPath + openMouthFileName);
				smileMouthTexture = LoadTexture(folderPath + smileMouthFileName);
				wideOpenMouthTexture = LoadTexture(folderPath + wideOpenMouthFileName);
				frownMouthTexture = LoadTexture(folderPath + frownMouthFileName);
			}

			private Texture2D LoadTexture(string path)
			{
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Expected O, but got Unknown
				byte[] array = File.ReadAllBytes(path);
				Texture2D val = new Texture2D(2, 2);
				val.LoadImage(array);
				return val;
			}

			private void InitializeMicrophone()
			{
				string[] devices = Microphone.devices;
				foreach (string text in devices)
				{
					Logger.LogMessage((object)("Microphone detected: " + text));
				}
				if (Microphone.devices.Length != 0)
				{
					microphoneName = Microphone.devices[0];
					audioSource.clip = Microphone.Start(microphoneName, true, 1, 44100);
					audioSource.loop = true;
					while (Microphone.GetPosition(microphoneName) <= 0)
					{
					}
					audioSource.Play();
				}
				else
				{
					Logger.LogError((object)"No microphones detected at all!");
				}
			}

			private void Update()
			{
				if ((Object)(object)mouthMaterial == (Object)null)
				{
					return;
				}
				if (Microphone.IsRecording(microphoneName))
				{
					float[] array = new float[64];
					audioSource.GetOutputData(array, 0);
					float num = 0f;
					float num2 = 0f;
					int num3 = 0;
					for (int i = 1; i < array.Length; i++)
					{
						num += Mathf.Abs(array[i]);
						if (array[i - 1] < 0f && array[i] > 0f)
						{
							num3++;
						}
					}
					num /= (float)array.Length;
					num2 = num3;
					Texture2D val = closedMouthTexture;
					val = ((num < mouthClosedV.Value) ? closedMouthTexture : ((num < smileFrownV.Value) ? ((!(num2 < (float)pitchSwap.Value)) ? smileMouthTexture : frownMouthTexture) : ((num < partialOpenV.Value) ? partiallyOpenMouthTexture : ((!(num < normalOpenv.Value)) ? wideOpenMouthTexture : openMouthTexture))));
					lastActiveTime = Time.time;
					if (Time.time - lastChosenMouth > talkDuration.Value)
					{
						lastChosenMouth = Time.time;
						mouthMaterial.mainTexture = (Texture)(object)val;
					}
				}
				if (Time.time - lastActiveTime > silenceDuration.Value)
				{
					mouthMaterial.mainTexture = (Texture)(object)closedMouthTexture;
				}
			}
		}

		private static ConfigEntry<bool> GameEnabled;

		private static ConfigEntry<bool> SosigHaveFaces;

		private static ConfigEntry<bool> PlayerHasFace;

		private static ConfigEntry<float> mouthClosedV;

		private static ConfigEntry<float> smileFrownV;

		private static ConfigEntry<float> partialOpenV;

		private static ConfigEntry<float> normalOpenv;

		private static ConfigEntry<float> talkDuration;

		private static ConfigEntry<float> silenceDuration;

		private static ConfigEntry<int> pitchSwap;

		public static List<Texture2D> IdleFaces = new List<Texture2D>();

		public static List<Texture2D> AssaultingFaces = new List<Texture2D>();

		public static List<Texture2D> DamagedFaces = new List<Texture2D>();

		public static List<Texture2D> DeadFaces = new List<Texture2D>();

		internal static ManualLogSource Logger { get; private set; }

		private void Awake()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			Logger = ((BaseUnityPlugin)this).Logger;
			Harmony val = new Harmony("NGA.SosigFaces");
			Logger.LogMessage((object)"New harmony");
			LoadTextures();
			SetUpConfigFields();
			Logger.LogMessage((object)"Setted the fields");
			val.PatchAll();
			Logger.LogMessage((object)"Hello, world! Sent from NGA.SosigFaces 0.0.1");
		}

		public static void LoadTextures()
		{
			string path = Paths.PluginPath + "\\NGA-SosigFarce\\";
			IdleFaces = LoadTexturesFromFolder(Path.Combine(path, "Idle"));
			AssaultingFaces = LoadTexturesFromFolder(Path.Combine(path, "Assaulting"));
			DamagedFaces = LoadTexturesFromFolder(Path.Combine(path, "Damaged"));
			DeadFaces = LoadTexturesFromFolder(Path.Combine(path, "Dead"));
		}

		private static List<Texture2D> LoadTexturesFromFolder(string folderPath)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			List<Texture2D> list = new List<Texture2D>();
			string[] files = Directory.GetFiles(folderPath, "*.png");
			Logger.LogWarning((object)("Number pngs in " + folderPath + " is " + files.Length));
			string[] array = files;
			foreach (string path in array)
			{
				byte[] array2 = File.ReadAllBytes(path);
				Texture2D val = new Texture2D(2, 2);
				val.LoadImage(array2);
				list.Add(val);
				Logger.LogWarning((object)"Added sosig face texture!");
			}
			return list;
		}

		private void SetUpConfigFields()
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Expected O, but got Unknown
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: Expected O, but got Unknown
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Expected O, but got Unknown
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Expected O, but got Unknown
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Expected O, but got Unknown
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Expected O, but got Unknown
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Expected O, but got Unknown
			//IL_020d: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Expected O, but got Unknown
			//IL_0218: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Expected O, but got Unknown
			GameEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Overall", "ON/OFF.", true, "Turn mod On / Off");
			SosigHaveFaces = ((BaseUnityPlugin)this).Config.Bind<bool>("Overall", "Sosig Faces ON/OFF.", true, "Sosigs have faces");
			PlayerHasFace = ((BaseUnityPlugin)this).Config.Bind<bool>("Overall", "Player Face ON/OFF.", true, "Player has face");
			mouthClosedV = ((BaseUnityPlugin)this).Config.Bind<float>("Volume", "Mouth closed", 0.001f, new ConfigDescription("Mouth closed for values below this.", (AcceptableValueBase)new AcceptableValueFloatRangeStep(0.0001f, 1f, 0.001f), new object[0]));
			smileFrownV = ((BaseUnityPlugin)this).Config.Bind<float>("Volume", "Smile Frown", 0.07f, new ConfigDescription("Smile Frown for values below this.", (AcceptableValueBase)new AcceptableValueFloatRangeStep(0.0001f, 1f, 0.001f), new object[0]));
			partialOpenV = ((BaseUnityPlugin)this).Config.Bind<float>("Volume", "Partial Open", 0.02f, new ConfigDescription("Partial Open for values below this..", (AcceptableValueBase)new AcceptableValueFloatRangeStep(0.0001f, 1f, 0.001f), new object[0]));
			normalOpenv = ((BaseUnityPlugin)this).Config.Bind<float>("Volume", "Normal open", 0.03f, new ConfigDescription("Mouth open normal for values below this.", (AcceptableValueBase)new AcceptableValueFloatRangeStep(0.0001f, 1f, 0.001f), new object[0]));
			talkDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Animation", "Mouth Change", 0.15f, new ConfigDescription("How long before the mouth next updates", (AcceptableValueBase)new AcceptableValueFloatRangeStep(0.0001f, 1f, 0.001f), new object[0]));
			silenceDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Animation", "Silence Change", 0.5f, new ConfigDescription("How long before the mouth closes", (AcceptableValueBase)new AcceptableValueFloatRangeStep(0.0001f, 1f, 0.001f), new object[0]));
			pitchSwap = ((BaseUnityPlugin)this).Config.Bind<int>("Animation", "Pitch Frown or Smile", 1, new ConfigDescription("Pitch needed to swap between smile and frown at same volume.", (AcceptableValueBase)new AcceptableValueIntRangeStep(0, 100, 1), new object[0]));
		}

		private static bool CheckSkip()
		{
			return !GameEnabled.Value;
		}

		private static bool CheckSosigSkip()
		{
			return !GameEnabled.Value || !SosigHaveFaces.Value;
		}

		private static bool CheckPlayerSkip()
		{
			return !GameEnabled.Value || !PlayerHasFace.Value;
		}
	}
}