Wink.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 Photon.Pun;
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: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("Vippy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+f87475f264960c77a77b1f34d93f988a339b4b75")]
[assembly: AssemblyProduct("Wink")]
[assembly: AssemblyTitle("Wink")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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;
		}
	}
	[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 Wink
{
	internal static class BuildInfo
	{
		public const string Version = "1.0.1";
	}
	internal static class WinkState
	{
		internal static EyeSettings? Closed;

		internal static void EnsureClosed(List<ExpressionSettings> expressions)
		{
			if (Closed != null || expressions == null)
			{
				return;
			}
			float num = float.NegativeInfinity;
			EyeSettings val = null;
			foreach (ExpressionSettings expression in expressions)
			{
				if (expression == null)
				{
					continue;
				}
				EyeSettings[] array = (EyeSettings[])(object)new EyeSettings[2] { expression.leftEye, expression.rightEye };
				foreach (EyeSettings val2 in array)
				{
					if (val2 != null && val2.upperLidClosedPercent > num)
					{
						num = val2.upperLidClosedPercent;
						val = val2;
					}
				}
			}
			if (val != null)
			{
				Closed = Copy(val);
			}
		}

		private static EyeSettings Copy(EyeSettings s)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Expected O, but got Unknown
			return new EyeSettings
			{
				upperLidAngle = s.upperLidAngle,
				upperLidClosedPercent = s.upperLidClosedPercent,
				upperLidClosedPercentJitterAmount = s.upperLidClosedPercentJitterAmount,
				upperLidClosedPercentJitterSpeed = s.upperLidClosedPercentJitterSpeed,
				lowerLidAngle = s.lowerLidAngle,
				lowerLidClosedPercent = s.lowerLidClosedPercent,
				lowerLidClosedPercentJitterAmount = s.lowerLidClosedPercentJitterAmount,
				lowerLidClosedPercentJitterSpeed = s.lowerLidClosedPercentJitterSpeed,
				pupilSize = s.pupilSize,
				pupilSizeJitterAmount = s.pupilSizeJitterAmount,
				pupilSizeJitterSpeed = s.pupilSizeJitterSpeed,
				pupilPositionJitter = s.pupilPositionJitter,
				pupilPositionJitterAmount = s.pupilPositionJitterAmount,
				pupilOffsetRotationX = s.pupilOffsetRotationX,
				pupilOffsetRotationY = s.pupilOffsetRotationY
			};
		}
	}
	internal enum WinkStyle
	{
		Normal,
		Seductive
	}
	internal static class WinkAnim
	{
		private class Anim
		{
			public bool WaitUp;

			public float LeadIn;

			public float Timer;

			public float Dur;

			public float Hold;

			public WinkStyle Style;

			public float Amount;
		}

		private const float PreviewUpThreshold = 0.95f;

		private static readonly Dictionary<PlayerExpression, Anim> _anims = new Dictionary<PlayerExpression, Anim>();

		private static readonly List<PlayerExpression> _dead = new List<PlayerExpression>();

		public static void Start(PlayerExpression pe, WinkStyle style, float leadIn = 0f, float hold = 0f, bool waitForPreviewUp = false)
		{
			foreach (PlayerExpression key in _anims.Keys)
			{
				if ((Object)(object)key == (Object)null)
				{
					_dead.Add(key);
				}
			}
			foreach (PlayerExpression item in _dead)
			{
				_anims.Remove(item);
			}
			_dead.Clear();
			float num = Mathf.Max(0.05f, (style == WinkStyle.Seductive) ? WinkConfig.SeductiveDuration.Value : WinkConfig.NormalDuration.Value);
			_anims[pe] = new Anim
			{
				WaitUp = waitForPreviewUp,
				LeadIn = Mathf.Max(0f, leadIn),
				Timer = num,
				Dur = num,
				Hold = Mathf.Max(0f, hold),
				Style = style
			};
		}

		public static void Tick(PlayerExpression pe)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			if (!_anims.TryGetValue(pe, out Anim value))
			{
				return;
			}
			if (value.WaitUp)
			{
				PlayerExpressionsUI instance = PlayerExpressionsUI.instance;
				if ((Object)(object)instance != (Object)null && (Object)(object)instance.rectShrink != (Object)null && ((Transform)instance.rectShrink).localScale.x < 0.95f)
				{
					value.Amount = 0f;
					return;
				}
				value.WaitUp = false;
			}
			if (value.LeadIn > 0f)
			{
				value.LeadIn -= Time.deltaTime;
				value.Amount = 0f;
				return;
			}
			if (value.Timer > 0f)
			{
				value.Timer -= Time.deltaTime;
				if (value.Timer > 0f)
				{
					value.Amount = Mathf.Sin(MathF.PI * (1f - value.Timer / value.Dur));
					return;
				}
				value.Amount = 0f;
			}
			if (value.Hold > 0f)
			{
				value.Hold -= Time.deltaTime;
				value.Amount = 0f;
			}
			else
			{
				_anims.Remove(pe);
			}
		}

		public static bool TryGet(PlayerExpression pe, out float amount, out WinkStyle style)
		{
			if (_anims.TryGetValue(pe, out Anim value))
			{
				amount = value.Amount;
				style = value.Style;
				return true;
			}
			amount = 0f;
			style = WinkStyle.Normal;
			return false;
		}
	}
	[HarmonyPatch(typeof(PlayerExpression), "Start")]
	internal static class WinkSetupPatch
	{
		private static bool _logged;

		[HarmonyPostfix]
		public static void Postfix(PlayerExpression __instance)
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			List<ExpressionSettings> expressions = __instance.expressions;
			if (expressions != null)
			{
				WinkState.EnsureClosed(expressions);
				if (!_logged)
				{
					_logged = true;
					WinkPlugin.Log.LogInfo((object)$"[Wink] {expressions.Count} expressions, wink on {WinkConfig.WinkKey.Value}");
				}
				float value = WinkConfig.EyelidSpeed.Value;
				SetSpeed(__instance.leftUpperLidClosedAngle, value);
				SetSpeed(__instance.leftLowerLidClosedAngle, value);
				SetSpeed(__instance.rightUpperLidClosedAngle, value);
				SetSpeed(__instance.rightLowerLidClosedAngle, value);
			}
		}

		private static void SetSpeed(SpringFloat? spring, float spd)
		{
			if (spring != null)
			{
				spring.speed = spd;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerExpression), "Update")]
	internal static class WinkUpdatePatch
	{
		private const float HeldFaceMinWeight = 5f;

		private const float KeepAliveTimer = 0.1f;

		[HarmonyPostfix]
		public static void Postfix(PlayerExpression __instance)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			List<ExpressionSettings> expressions = __instance.expressions;
			if (expressions == null || expressions.Count == 0)
			{
				return;
			}
			PlayerAvatarVisuals playerVisuals = __instance.playerVisuals;
			bool flag = __instance.isLocal && (Object)(object)playerVisuals != (Object)null && !playerVisuals.isMenuAvatar && (Object)(object)__instance.playerAvatar != (Object)null && (Object)(object)__instance == (Object)(object)__instance.playerAvatar.playerExpression;
			if (flag && (Object)(object)MenuManager.instance != (Object)null && !Object.op_Implicit((Object)(object)MenuManager.instance.currentMenuPage) && Input.GetKeyDown(WinkConfig.WinkKey.Value))
			{
				WinkStyle style = ((WinkConfig.Style.Value == "Seductive") ? WinkStyle.Seductive : WinkStyle.Normal);
				WinkAnim.Start(__instance, style);
				PlayerExpressionsUI instance = PlayerExpressionsUI.instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.ShrinkReset();
					if ((Object)(object)instance.playerExpression != (Object)null)
					{
						WinkAnim.Start(instance.playerExpression, style, WinkConfig.PreviewLeadIn.Value, WinkConfig.PreviewHold.Value, waitForPreviewUp: true);
					}
				}
				if (!__instance.onlyVisualRepresentation)
				{
					WinkNet.Send(__instance.playerAvatar, style);
				}
			}
			WinkAnim.Tick(__instance);
			float amount;
			WinkStyle style2;
			bool flag2 = WinkAnim.TryGet(__instance, out amount, out style2);
			bool flag3 = false;
			PlayerExpressionsUI instance2 = PlayerExpressionsUI.instance;
			if ((Object)(object)instance2 != (Object)null && (Object)(object)instance2.playerExpression != (Object)null && WinkAnim.TryGet(instance2.playerExpression, out var _, out var _))
			{
				if ((Object)(object)instance2.playerExpression == (Object)(object)__instance || flag)
				{
					instance2.ShrinkReset();
				}
				flag3 = flag;
			}
			if (!flag2 && !flag3)
			{
				return;
			}
			expressions[0].timer = Mathf.Max(expressions[0].timer, 0.1f);
			float num = 0f;
			for (int i = 1; i < expressions.Count; i++)
			{
				if (i != 4)
				{
					num += expressions[i].weight;
				}
			}
			if (num < 5f)
			{
				expressions[0].weight = 100f;
			}
			if (flag2 && (Object)(object)playerVisuals != (Object)null && style2 == WinkStyle.Seductive)
			{
				playerVisuals.HeadTiltOverride(WinkConfig.HeadTilt.Value * amount);
			}
		}
	}
	[HarmonyPatch(typeof(PlayerExpression), "BlendEyeSettings")]
	internal static class WinkBlendPatch
	{
		[HarmonyPostfix]
		public static void Postfix(PlayerExpression __instance, bool isLeft, EyeSettings __result)
		{
			if (!WinkAnim.TryGet(__instance, out var amount, out var style) || amount <= 0f)
			{
				return;
			}
			EyeSettings closed = WinkState.Closed;
			if (closed == null || __result == null)
			{
				return;
			}
			List<ExpressionSettings> expressions = __instance.expressions;
			int num = 4;
			if (expressions == null || num >= expressions.Count)
			{
				return;
			}
			float num2 = 0f;
			for (int i = 0; i < expressions.Count; i++)
			{
				num2 += expressions[i].weight;
			}
			float num3 = expressions[num]?.weight ?? 0f;
			if (num3 > 0.5f && num2 > 0.001f)
			{
				float num4 = num2 - num3;
				EyeSettings val = (isLeft ? expressions[num].leftEye : expressions[num].rightEye);
				if (num4 > 0.5f && val != null)
				{
					__result.upperLidClosedPercent = (__result.upperLidClosedPercent * num2 - val.upperLidClosedPercent * num3) / num4;
					__result.lowerLidClosedPercent = (__result.lowerLidClosedPercent * num2 - val.lowerLidClosedPercent * num3) / num4;
					__result.upperLidAngle = (__result.upperLidAngle * num2 - val.upperLidAngle * num3) / num4;
					__result.lowerLidAngle = (__result.lowerLidAngle * num2 - val.lowerLidAngle * num3) / num4;
					__result.pupilSize = (__result.pupilSize * num2 - val.pupilSize * num3) / num4;
				}
			}
			bool num5 = isLeft == WinkConfig.WinkLeftEye.Value;
			bool flag = style == WinkStyle.Seductive;
			float num6 = (num5 ? amount : (flag ? (amount * WinkConfig.SultryLid.Value) : 0f));
			float num7 = (num5 ? amount : 0f);
			__result.upperLidClosedPercent = Mathf.Lerp(__result.upperLidClosedPercent, closed.upperLidClosedPercent, num6);
			__result.lowerLidClosedPercent = Mathf.Lerp(__result.lowerLidClosedPercent, closed.lowerLidClosedPercent, num6);
			__result.upperLidAngle = Mathf.Lerp(__result.upperLidAngle, closed.upperLidAngle, num7);
			__result.lowerLidAngle = Mathf.Lerp(__result.lowerLidAngle, closed.lowerLidAngle, num7);
			__result.pupilSize = Mathf.Lerp(__result.pupilSize, closed.pupilSize, num7);
		}
	}
	[HarmonyPatch(typeof(PunManager), "Awake")]
	internal static class PunManagerWinkPatch
	{
		[HarmonyPostfix]
		public static void Postfix(PunManager __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<WinkNet>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<WinkNet>();
			}
		}
	}
	[BepInPlugin("Vippy.Wink", "Wink", "1.0.1")]
	public class WinkPlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			((Component)this).gameObject.transform.parent = null;
			((Object)((Component)this).gameObject).hideFlags = (HideFlags)61;
			WinkConfig.Init(((BaseUnityPlugin)this).Config);
			new Harmony("Vippy.Wink").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Wink v1.0.1 loaded");
		}
	}
	internal class WinkNet : MonoBehaviour
	{
		private const float BlinkSeconds = 0.3f;

		private static float _blinkStopAt;

		public static void Send(PlayerAvatar avatar, WinkStyle style)
		{
			if (PhotonNetwork.InRoom && PhotonNetwork.CurrentRoom.PlayerCount > 1)
			{
				PunManager.instance.photonView.RPC("WinkRPC", (RpcTarget)1, new object[2]
				{
					SemiFunc.PhotonViewIDPlayerAvatarLocal(),
					(int)style
				});
				if (WinkConfig.BlinkForOthers.Value)
				{
					avatar.PlayerExpressionSet(4, 100f);
					_blinkStopAt = Time.time + 0.3f;
				}
			}
		}

		[PunRPC]
		public void WinkRPC(int _avatarViewID, int _style, PhotonMessageInfo _info = default(PhotonMessageInfo))
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			PlayerAvatar val = SemiFunc.PlayerAvatarGetFromPhotonID(_avatarViewID);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val.playerExpression == (Object)null) && _info.Sender != null && !((Object)(object)val.photonView == (Object)null) && val.photonView.Owner == _info.Sender)
			{
				WinkAnim.Start(val.playerExpression, (_style == 1) ? WinkStyle.Seductive : WinkStyle.Normal);
			}
		}

		private void Update()
		{
			if (_blinkStopAt > 0f && Time.time >= _blinkStopAt)
			{
				_blinkStopAt = 0f;
				if ((Object)(object)PlayerAvatar.instance != (Object)null)
				{
					PlayerAvatar.instance.PlayerExpressionStop(4);
				}
			}
		}
	}
	internal static class WinkConfig
	{
		public const int BlinkSlot = 4;

		public const string StyleNormal = "Normal";

		public const string StyleSeductive = "Seductive";

		public static ConfigEntry<KeyCode> WinkKey;

		public static ConfigEntry<string> Style;

		public static ConfigEntry<bool> BlinkForOthers;

		public static ConfigEntry<bool> WinkLeftEye;

		public static ConfigEntry<float> NormalDuration;

		public static ConfigEntry<float> SeductiveDuration;

		public static ConfigEntry<float> EyelidSpeed;

		public static ConfigEntry<float> SultryLid;

		public static ConfigEntry<float> HeadTilt;

		public static ConfigEntry<float> PreviewLeadIn;

		public static ConfigEntry<float> PreviewHold;

		public static void Init(ConfigFile config)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Expected O, but got Unknown
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Expected O, but got Unknown
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Expected O, but got Unknown
			//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Expected O, but got Unknown
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Expected O, but got Unknown
			WinkKey = config.Bind<KeyCode>("Wink", "Wink key", (KeyCode)52, "Key that plays the wink. This is a NEW expression on its own key, nothing the game ships with is changed: the inventory keys (1-3) and the six vanilla expression keys (5-0) stay exactly as they are. Default is Alpha4, which is Unity's name for the 4 key on the number row (not the numpad). Pick which wink it plays with the 'Wink style' setting.");
			Style = config.Bind<string>("Wink", "Wink style", "Normal", new ConfigDescription("Normal is a quick close-and-reopen. Seductive is slower - the other eye goes half-lidded and the head tilts.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[2] { "Normal", "Seductive" }), Array.Empty<object>()));
			BlinkForOthers = config.Bind<bool>("Wink", "Blink for unmodded players", true, "Also flash the vanilla closed-eyes face for a split second so players WITHOUT the mod see a quick blink instead of nothing. Players with the mod always see the real one-eyed wink.");
			WinkLeftEye = config.Bind<bool>("Wink", "Wink the left eye", false, "Close the LEFT eye instead of the right.");
			NormalDuration = config.Bind<float>("Wink", "Normal wink duration", 0.35f, new ConfigDescription("Seconds for the normal wink's close-and-reopen.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.15f, 1f), Array.Empty<object>()));
			SeductiveDuration = config.Bind<float>("Wink", "Seductive wink duration", 0.7f, new ConfigDescription("Seconds for the seductive wink's close-and-reopen. Higher = slower, more deliberate.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 2f), Array.Empty<object>()));
			EyelidSpeed = config.Bind<float>("Wink", "Eyelid speed", 18f, new ConfigDescription("Eyelid spring smoothing (vanilla 20). Lower is softer.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 60f), Array.Empty<object>()));
			SultryLid = config.Bind<float>("Wink", "Sultry lid", 0.4f, new ConfigDescription("Seductive wink only: how far the OTHER eye half-closes (bedroom eyes). 0 = wide open.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.85f), Array.Empty<object>()));
			HeadTilt = config.Bind<float>("Wink", "Head tilt", 10f, new ConfigDescription("Seductive wink only: head tilt in degrees (sign flips direction). 0 = none.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-25f, 25f), Array.Empty<object>()));
			PreviewLeadIn = config.Bind<float>("Wink", "Preview lead-in", 0.5f, new ConfigDescription("Seconds the bottom preview holds your face open AFTER it has fully risen, before the wink plays. The wink already waits for the preview to finish rising; this is the extra beat on top of that. Preview only - the wink others see in-world stays instant.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
			PreviewHold = config.Bind<float>("Wink", "Preview hold", 0.9f, new ConfigDescription("Seconds the bottom preview lingers after the wink finishes, before it settles back. Preview only - your in-world wink is unaffected.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>()));
		}
	}
}