Decompiled source of ShareChangedEyeState v1.0.2

BepInEx/plugins/smolMods.EyeState.dll

Decompiled 14 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Mirror;
using SmolMods.Core;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("smolMods.EyeState")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+a3231e664cf7d257a8601fb862a89ade69b41d83")]
[assembly: AssemblyProduct("smolMods.EyeState")]
[assembly: AssemblyTitle("smolMods.EyeState")]
[assembly: AssemblyVersion("1.0.0.0")]
[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 SmolMods.EyeState
{
	internal static class EyeChannelPayload
	{
		private const byte Subtype = 2;

		private static readonly Dictionary<int, (ulong netId, int mood, bool still)> HostMoods = new Dictionary<int, (ulong, int, bool)>();

		internal static void Register()
		{
			ModChannel.Register((byte)2, (Action<int, byte[]>)OnServerFrame, (Action<byte[]>)OnClientFrame);
			ModChannel.PeerHello += OnPeerHello;
			ModChannel.PeerLeft += OnPeerLeft;
			ModChannel.SessionReset += OnSessionReset;
		}

		internal static void SendEyeState(int mood, ulong ourNetId, bool stillAnimated)
		{
			if (ModChannel.IsServer)
			{
				ModChannel.Broadcast((byte)2, Body(mood, ourNetId, stillAnimated), -1);
			}
			else
			{
				ModChannel.SendToHost((byte)2, Body(mood, ourNetId, stillAnimated));
			}
		}

		private static bool FlagOf(byte[] body)
		{
			if (body.Length >= 10)
			{
				return (body[9] & 1) != 0;
			}
			return true;
		}

		private static void OnServerFrame(int connId, byte[] body)
		{
			if (body.Length >= 1)
			{
				int num = (sbyte)body[0];
				bool flag = FlagOf(body);
				EyeStateSync.SetRemoteMood(ModChannel.EpicIdOf(connId), num, flag);
				ulong num2 = ModChannel.NetIdOf(connId);
				EyeStateSync.SetRemoteMoodByNetId(num2, num, flag);
				if (connId > 0)
				{
					HostMoods[connId] = (num2, num, flag);
				}
				ModChannel.Broadcast((byte)2, Body(num, num2, flag), connId);
			}
		}

		private static void OnClientFrame(byte[] body)
		{
			if (body.Length >= 9)
			{
				ulong num = 0uL;
				for (int i = 0; i < 8; i++)
				{
					num |= (ulong)body[1 + i] << 8 * i;
				}
				EyeStateSync.SetRemoteMoodByNetId(num, (sbyte)body[0], FlagOf(body));
			}
		}

		private static void OnPeerHello(int connId)
		{
			if (connId < 0)
			{
				EyeStateFeature.MarkDirty();
				return;
			}
			int localMood = EyeStateFeature.LocalMood;
			ulong num = NetIds.LocalNetId();
			if (num != 0L)
			{
				ModChannel.SendToConnection(connId, (byte)2, Body(localMood, num, EyeStateFeature.LocalStillAnimated));
			}
			foreach (KeyValuePair<int, (ulong, int, bool)> hostMood in HostMoods)
			{
				if (hostMood.Key != connId && hostMood.Value.Item1 != 0L)
				{
					ModChannel.SendToConnection(connId, (byte)2, Body(hostMood.Value.Item2, hostMood.Value.Item1, hostMood.Value.Item3));
				}
			}
		}

		private static void OnPeerLeft(int connId)
		{
			if (HostMoods.TryGetValue(connId, out (ulong, int, bool) value))
			{
				HostMoods.Remove(connId);
				if (value.Item1 != 0L)
				{
					ModChannel.Broadcast((byte)2, Body(-1, value.Item1, stillAnimated: true), -1);
				}
			}
		}

		private static void OnSessionReset()
		{
			HostMoods.Clear();
			EyeStateFeature.MarkDirty();
			EyeStateSync.ClearAll();
		}

		private static byte[] Body(int mood, ulong netId, bool stillAnimated)
		{
			byte[] array = new byte[10]
			{
				(byte)(sbyte)mood,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0,
				0
			};
			for (int i = 0; i < 8; i++)
			{
				array[1 + i] = (byte)(netId >> 8 * i);
			}
			array[9] = (stillAnimated ? ((byte)1) : ((byte)0));
			return array;
		}
	}
	internal static class EyeMoods
	{
		internal const int NoOverride = -1;

		internal static readonly (int Value, string Label)[] Moods = new(int, string)[12]
		{
			(-1, "Default"),
			(0, "Normal"),
			(4, "Squint >.<"),
			(6, "Dead x_x"),
			(3, "Sleepy u.u"),
			(1, "Line -.-"),
			(2, "wobbly *.*"),
			(5, "Ring O.O"),
			(7, "Beady ·.·"),
			(8, "Square"),
			(9, "Thick Ring o.o"),
			(10, "Spiral @.@")
		};

		internal static string LabelFor(int v)
		{
			(int, string)[] moods = Moods;
			for (int i = 0; i < moods.Length; i++)
			{
				(int, string) tuple = moods[i];
				if (tuple.Item1 == v)
				{
					return tuple.Item2;
				}
			}
			return "Default";
		}

		internal static string GlyphFor(int mood)
		{
			string result = "o";
			string text;
			switch (mood)
			{
			case 0:
				text = "o";
				break;
			case 1:
				text = "-";
				break;
			case 2:
				text = "*";
				break;
			case 3:
				text = "u";
				break;
			case 4:
				text = "<";
				break;
			case 5:
				text = "O";
				break;
			case 6:
				text = "x";
				break;
			case 7:
				text = "·";
				break;
			case 8:
				text = "■";
				result = "#";
				break;
			case 9:
				text = "◎";
				result = "O";
				break;
			case 10:
				text = "@";
				break;
			default:
				return "";
			}
			try
			{
				TMP_FontAsset menuGlyphFont = ModSettingsApi.MenuGlyphFont;
				if ((Object)(object)menuGlyphFont != (Object)null && !menuGlyphFont.HasCharacter(text[0], false, false))
				{
					return result;
				}
			}
			catch
			{
			}
			return text;
		}
	}
	[HarmonyPatch]
	internal static class EyeStateFeature
	{
		private static ModRowDef _row;

		private static ModRowDef _stillAnimatedRow;

		private static ModRowDef _shareRow;

		private static PlayerEyes _localEyes;

		private static float _nextSyncTick;

		private static int _moodMirror = -1;

		private static bool _stillMirror = true;

		private static bool _shareMirror;

		private static int _lastSentMood = int.MinValue;

		private static bool _lastSentStill = true;

		private static bool _loggedMoodReadFailure;

		internal static int LocalMood => _moodMirror;

		internal static bool LocalStillAnimated => _stillMirror;

		internal static void Register()
		{
			int[] array = new int[EyeMoods.Moods.Length];
			for (int i = 0; i < EyeMoods.Moods.Length; i++)
			{
				array[i] = EyeMoods.Moods[i].Value;
			}
			_row = ModSettingsApi.AddArrayRow(200, "Eye state", "settings_mod_eyeState", -1, array, (Func<int, string>)EyeMoods.LabelFor, (Action<int>)delegate(int v)
			{
				_moodMirror = v;
			}, (Func<int, Color?>)null);
			_stillAnimatedRow = ModSettingsApi.AddArrayRow(200, "Still animated", "settings_mod_eyesStillAnimated", 1, new int[2] { 0, 1 }, (Func<int, string>)((int v) => (v != 1) ? "Off" : "On"), (Action<int>)delegate(int v)
			{
				_stillMirror = v == 1;
				MarkDirty();
			}, (Func<int, Color?>)null);
			_shareRow = ModSettingsApi.AddArrayRow(200, "Share eye state", "settings_mod_shareEyeState", 1, new int[2] { 0, 1 }, (Func<int, string>)((int v) => (v != 1) ? "Off" : "On"), (Action<int>)delegate(int v)
			{
				_shareMirror = v == 1;
				ModChannel.SetEnabled(v == 1);
				if (v != 1)
				{
					EyeStateSync.ClearAll();
				}
			}, (Func<int, Color?>)null);
			EyeChannelPayload.Register();
			ModSettingsApi.AddTicker((Action)TickSync);
			ModSettingsApi.RequestCharacterPreview();
			ModSettingsApi.SetPreviewGlyphProvider((Func<string>)(() => EyeMoods.GlyphFor(LocalMood)));
			ModSettingsApi.AddNoteLine(200, (Func<string>)(() => "Vanilla users do not sync Eye states."));
		}

		internal static void TickSync()
		{
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			try
			{
				if (!_shareMirror)
				{
					return;
				}
				ModChannel.Tick();
				if (Time.unscaledTime < _nextSyncTick)
				{
					return;
				}
				_nextSyncTick = Time.unscaledTime + 0.5f;
				int localMood = LocalMood;
				bool localStillAnimated = LocalStillAnimated;
				if (localMood != _lastSentMood || localStillAnimated != _lastSentStill)
				{
					PlayerCharacter val = LocalPlayerCharacter();
					if (!((Object)(object)val == (Object)null))
					{
						_lastSentMood = localMood;
						_lastSentStill = localStillAnimated;
						EyeChannelPayload.SendEyeState(localMood, ((NetworkBehaviour)val).netId, localStillAnimated);
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger = Plugin.Logger;
				if (logger != null)
				{
					bool flag = default(bool);
					BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(22, 1, ref flag);
					if (flag)
					{
						((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Eye sync tick failed: ");
						((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
					}
					logger.LogWarning(val2);
				}
			}
		}

		internal static void MarkDirty()
		{
			_lastSentMood = int.MinValue;
			_lastSentStill = true;
		}

		private static PlayerCharacter LocalPlayerCharacter()
		{
			try
			{
				List<PlayerCharacter> allPlayerCharacters = PlayerCharacter.allPlayerCharacters;
				if (allPlayerCharacters == null)
				{
					return null;
				}
				for (int i = 0; i < allPlayerCharacters.Count; i++)
				{
					if ((Object)(object)allPlayerCharacters[i] != (Object)null && ((NetworkBehaviour)allPlayerCharacters[i]).isLocalPlayer)
					{
						return allPlayerCharacters[i];
					}
				}
			}
			catch
			{
			}
			return null;
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerCharacter), "Start")]
		private static void PlayerStart_Postfix(PlayerCharacter __instance)
		{
			try
			{
				if (((NetworkBehaviour)__instance).isLocalPlayer && __instance.playerEyes != null)
				{
					_localEyes = __instance.playerEyes;
				}
			}
			catch
			{
			}
		}

		private static bool GameWantsSpecialEyes(PlayerEyes eyes)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Invalid comparison between Unknown and I4
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			try
			{
				return (int)eyes.moodLeft != 0 || (int)eyes.moodRight > 0;
			}
			catch (Exception ex)
			{
				if (!_loggedMoodReadFailure)
				{
					_loggedMoodReadFailure = true;
					ManualLogSource logger = Plugin.Logger;
					if (logger != null)
					{
						bool flag = default(bool);
						BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(64, 1, ref flag);
						if (flag)
						{
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Reading the game's eye mood failed (");
							((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
							((BepInExLogInterpolatedStringHandler)val).AppendLiteral("); 'Still animated' inactive");
						}
						logger.LogWarning(val);
					}
				}
				return false;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayerEyes), "Update")]
		private static void EyesUpdate_Postfix(PlayerEyes __instance)
		{
			try
			{
				int num;
				bool flag;
				if (_localEyes == null || !(((Il2CppObjectBase)__instance).Pointer == ((Il2CppObjectBase)_localEyes).Pointer))
				{
					(num, flag) = EyeStateSync.StateFor(__instance);
				}
				else
				{
					num = _moodMirror;
					flag = _stillMirror;
				}
				if (num >= 0 && (!flag || !GameWantsSpecialEyes(__instance)))
				{
					__instance.SetEyeMood((PlayerEyeMood)num);
				}
			}
			catch
			{
			}
		}
	}
	internal static class EyeStateSync
	{
		private static readonly Dictionary<string, (int mood, bool still)> RemoteMoods = new Dictionary<string, (int, bool)>();

		private static readonly Dictionary<IntPtr, PlayerCharacter> EyesOwner = new Dictionary<IntPtr, PlayerCharacter>();

		private static readonly Dictionary<ulong, (int mood, bool still)> RemoteMoodsByNetId = new Dictionary<ulong, (int, bool)>();

		internal static void SetRemoteMoodByNetId(ulong netId, int mood, bool stillAnimated)
		{
			if (netId != 0L)
			{
				if (mood < 0)
				{
					RemoteMoodsByNetId.Remove(netId);
				}
				else
				{
					RemoteMoodsByNetId[netId] = (mood, stillAnimated);
				}
			}
		}

		internal static void SetRemoteMood(string epicUserId, int mood, bool stillAnimated)
		{
			if (!string.IsNullOrEmpty(epicUserId))
			{
				if (mood < 0)
				{
					RemoteMoods.Remove(epicUserId);
				}
				else
				{
					RemoteMoods[epicUserId] = (mood, stillAnimated);
				}
			}
		}

		internal static void ClearAll()
		{
			RemoteMoods.Clear();
			RemoteMoodsByNetId.Clear();
		}

		internal static (int mood, bool still) StateFor(PlayerEyes eyes)
		{
			if (eyes == null || (RemoteMoods.Count == 0 && RemoteMoodsByNetId.Count == 0))
			{
				return (mood: -1, still: true);
			}
			PlayerCharacter val = OwnerOf(eyes);
			if ((Object)(object)val == (Object)null)
			{
				return (mood: -1, still: true);
			}
			try
			{
				if (RemoteMoodsByNetId.Count > 0 && ((NetworkBehaviour)val).netId != 0 && RemoteMoodsByNetId.TryGetValue(((NetworkBehaviour)val).netId, out (int, bool) value))
				{
					return value;
				}
			}
			catch
			{
			}
			if ((Object)(object)val.playerNetworking == (Object)null)
			{
				return (mood: -1, still: true);
			}
			string epicUserId = val.playerNetworking.epicUserId;
			if (string.IsNullOrEmpty(epicUserId))
			{
				return (mood: -1, still: true);
			}
			if (!RemoteMoods.TryGetValue(epicUserId, out (int, bool) value2))
			{
				return (mood: -1, still: true);
			}
			return value2;
		}

		private static PlayerCharacter OwnerOf(PlayerEyes eyes)
		{
			IntPtr pointer = ((Il2CppObjectBase)eyes).Pointer;
			if (EyesOwner.TryGetValue(pointer, out var value))
			{
				if ((Object)(object)value != (Object)null)
				{
					return value;
				}
				EyesOwner.Remove(pointer);
			}
			try
			{
				List<PlayerCharacter> allPlayerCharacters = PlayerCharacter.allPlayerCharacters;
				if (allPlayerCharacters == null)
				{
					return null;
				}
				for (int i = 0; i < allPlayerCharacters.Count; i++)
				{
					PlayerCharacter val = allPlayerCharacters[i];
					if (!((Object)(object)val == (Object)null) && val.playerEyes != null && ((Il2CppObjectBase)val.playerEyes).Pointer == pointer)
					{
						EyesOwner[pointer] = val;
						return val;
					}
				}
			}
			catch
			{
			}
			return null;
		}
	}
	[BepInPlugin("com.smolmods.eyestate", "smolMods.ShareChangedEyeState", "1.0.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BasePlugin
	{
		public const string PluginGuid = "com.smolmods.eyestate";

		public const string PluginName = "smolMods.ShareChangedEyeState";

		public const string PluginVersion = "1.0.2";

		internal static ManualLogSource Logger;

		public override void Load()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			Logger = ((BasePlugin)this).Log;
			EyeStateFeature.Register();
			Harmony val = new Harmony("com.smolmods.eyestate");
			val.PatchAll(typeof(Plugin).Assembly);
			int num = 0;
			foreach (MethodBase patchedMethod in val.GetPatchedMethods())
			{
				_ = patchedMethod;
				num++;
			}
			ManualLogSource log = ((BasePlugin)this).Log;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(27, 3, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("smolMods.ShareChangedEyeState");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.0.2");
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded, ");
				((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
				((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" methods patched.");
			}
			log.LogInfo(val2);
		}
	}
}