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);
}
}
}