Decompiled source of AuroraProjectButter v1.3.3

plugins/AuroraProjectButter.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Splatform;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("AuroraProjectButter")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.0.0")]
[assembly: AssemblyInformationalVersion("1.3.0")]
[assembly: AssemblyProduct("AuroraProjectButter")]
[assembly: AssemblyTitle("AuroraProjectButter")]
[assembly: AssemblyVersion("1.3.0.0")]
namespace AuroraProjectButter;

internal static class GhostUserIDRegistry
{
	private static readonly HashSet<string> _ids = new HashSet<string>(StringComparer.Ordinal);

	public static void Register(string userId)
	{
		if (!string.IsNullOrEmpty(userId))
		{
			_ids.Add(userId);
		}
	}

	public static bool IsGhost(string userId)
	{
		if (!string.IsNullOrEmpty(userId))
		{
			return _ids.Contains(userId);
		}
		return false;
	}
}
[HarmonyPatch(typeof(RelationsManager), "CheckPermissionAsync")]
internal static class RelationsManager_CheckPermissionAsync_GhostFilter
{
	[HarmonyPrefix]
	public static bool Prefix(PlatformUserID user)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		if (GhostUserIDRegistry.IsGhost(user.m_userID))
		{
			return false;
		}
		return true;
	}
}
internal static class GhostChatBypass
{
	public static ConfigEntry<string> PermanentGhostName;

	private static readonly string[] KnownGhostNames = new string[122]
	{
		"Bjorn", "Sigrid", "Ragnar", "Freya", "Leif", "Astrid", "Ulf", "Ingrid", "Thorstein", "Gudrun",
		"Ivar", "Helga", "Sven", "Thyra", "Erik", "Hilda", "Harald", "Runa", "Olaf", "Solveig",
		"Gunnar", "Eira", "Knut", "Liv", "Torbjorn", "Sigrun", "Vidar", "Brynhild", "Arne", "Dagny",
		"Halfdan", "Ylva", "Fenrir", "Saga", "Ketil", "Alva", "Hakon", "Jorunn", "Styrbjorn", "Tove",
		"Bjarke", "Revna", "Grim", "Embla", "Thorgrim", "Nanna", "Oddvar", "Sif", "Skjold", "Idun",
		"Bragi", "Sigyn", "Baldur", "Hermod", "Magni", "Modi", "Vali", "Forseti", "Thrud", "Eir",
		"Gefjon", "Skadi", "Ran", "Aegir", "Ironside", "Stormborn", "Shieldmaiden", "Ravenclaw", "Wolfsbane", "Frostbite",
		"Shadowmere", "Nighthawk", "Stonewall", "Firebrand", "Dawnbreaker", "Thunderstrike", "Ashwalker", "Bonecrusher", "Grimjaw", "Bloodraven",
		"Warhammer", "Duskblade", "Starforger", "Voidwalker", "xNordicVibes", "TrollSlayer99", "MeadLord", "VikingChad", "SkadiMain", "OdinFan42",
		"NeckHunter", "GreydwarfGang", "LoxRider", "RuneMaster", "DraugrDave", "FulingKing", "BossHunter", "TreePuncher", "CoinHoarder", "IronPickAxe",
		"SerpentBait", "MushroomGuy", "ThistleQueen", "HoneyBear", "Magnus", "Elara", "Rorik", "Keira", "Thandor", "Lyra",
		"Draven", "Nova", "Caspian", "Ember", "Orion", "Wren", "Axel", "Ivy", "Zeke", "Mira",
		"Knox", "Sage"
	};

	public static bool IsKnownGhostName(string name)
	{
		if (string.IsNullOrEmpty(name))
		{
			return false;
		}
		string value = PermanentGhostName?.Value ?? "Aurora";
		if (name.Equals(value, StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		for (int i = 0; i < KnownGhostNames.Length; i++)
		{
			if (KnownGhostNames[i].Equals(name, StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
		}
		return false;
	}
}
[HarmonyPatch(typeof(Chat), "RPC_ChatMessage")]
internal static class Chat_RPC_ChatMessage_GhostPatch
{
	[HarmonyPrefix]
	public static bool Prefix(Chat __instance, long sender, Vector3 position, int type, UserInfo userInfo, string text)
	{
		//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c6: Invalid comparison between Unknown and I4
		//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Invalid comparison between Unknown and I4
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_024d: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00be: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
		{
			return true;
		}
		string text2 = userInfo?.Name ?? "";
		if (!GhostChatBypass.IsKnownGhostName(text2))
		{
			return true;
		}
		GhostPlayerInjector.RememberGhost(text2);
		try
		{
			Type val = (Type)type;
			bool flag = false;
			try
			{
				MethodInfo method = typeof(Chat).GetMethod("AddString", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3]
				{
					typeof(PlatformUserID),
					typeof(string),
					typeof(Type)
				}, null);
				if (method != null)
				{
					PlatformUserID val2 = (PlatformUserID)(((??)userInfo?.UserId) ?? new PlatformUserID("Steam", "0"));
					method.Invoke(__instance, new object[3]
					{
						val2,
						text ?? "",
						val
					});
					flag = true;
				}
				else
				{
					ManualLogSource logger = ButterPlugin.Logger;
					if (logger != null)
					{
						logger.LogWarning((object)"[GhostChatBypass] Chat.AddString(PlatformUserID,string,Talker.Type) not found on this Valheim version.");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = ButterPlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("[GhostChatBypass] AddString invoke: " + ex.Message));
				}
			}
			if (!flag)
			{
				string text3 = (((int)val == 2) ? ("<color=yellow>" + text2 + "</color>: <color=yellow><b>" + (text ?? "").ToUpper() + "</b></color>") : ("<color=yellow>" + text2 + "</color>: " + text));
				((Terminal)__instance).AddString(text3);
			}
			try
			{
				typeof(Chat).GetField("m_hideTimer", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(__instance, 0f);
			}
			catch
			{
			}
			if ((Object)(object)Player.m_localPlayer != (Object)null && (int)val != 3)
			{
				try
				{
					Vector3 val3 = position;
					if (val3 == Vector3.zero)
					{
						val3 = ((Component)Player.m_localPlayer).transform.position + Vector3.up * 2.5f;
					}
					MethodInfo method2 = typeof(Chat).GetMethod("AddInworldText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					if (method2 != null && method2.GetParameters().Length == 6)
					{
						method2.Invoke(__instance, new object[6] { null, sender, val3, val, userInfo, text });
					}
				}
				catch
				{
				}
			}
		}
		catch (Exception ex2)
		{
			ManualLogSource logger3 = ButterPlugin.Logger;
			if (logger3 != null)
			{
				logger3.LogWarning((object)("[GhostChatBypass] Failed: " + ex2.Message));
			}
		}
		return false;
	}
}
internal static class GhostPlayerInjector
{
	internal class GhostInjectorMB : MonoBehaviour
	{
		private float _nextPoll;

		private int _pollCount;

		private void Update()
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			if (Time.unscaledTime < _nextPoll)
			{
				return;
			}
			_nextPoll = Time.unscaledTime + 2f;
			try
			{
				ZNet instance = ZNet.instance;
				if ((Object)(object)instance == (Object)null || instance.IsServer())
				{
					return;
				}
				FieldInfo field = typeof(ZNet).GetField("m_players", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null || !(field.GetValue(instance) is List<PlayerInfo> list))
				{
					return;
				}
				int count = list.Count;
				string text = GhostChatBypass.PermanentGhostName?.Value ?? "Aurora";
				string currentRotatingGhostName = GetCurrentRotatingGhostName();
				List<int> list2 = new List<int>();
				FieldInfo field2 = typeof(PlayerInfo).GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field2 != null)
				{
					for (int i = 0; i < list.Count; i++)
					{
						string text2 = field2.GetValue(list[i]) as string;
						if (string.IsNullOrEmpty(text2) || string.Equals(text2, text, StringComparison.OrdinalIgnoreCase) || string.Equals(text2, currentRotatingGhostName, StringComparison.OrdinalIgnoreCase))
						{
							continue;
						}
						bool flag = false;
						for (int j = 0; j < RotatingGhostPool.Length; j++)
						{
							if (RotatingGhostPool[j].Equals(text2, StringComparison.OrdinalIgnoreCase))
							{
								flag = true;
								break;
							}
						}
						if (flag)
						{
							list2.Add(i);
						}
					}
				}
				for (int num = list2.Count - 1; num >= 0; num--)
				{
					list.RemoveAt(list2[num]);
				}
				ZNet_RPC_PlayerList_Patch_AddIfMissing(list, text);
				ZNet_RPC_PlayerList_Patch_AddIfMissing(list, currentRotatingGhostName);
				foreach (string seenGhostName in _seenGhostNames)
				{
					ZNet_RPC_PlayerList_Patch_AddIfMissing(list, seenGhostName);
				}
				_pollCount++;
				if (_pollCount == 1 || _pollCount % 30 == 0)
				{
					ManualLogSource logger = ButterPlugin.Logger;
					if (logger != null)
					{
						logger.LogInfo((object)$"[GhostPlayerInjector-Poll] poll #{_pollCount}: m_players {count} → {list.Count} (added {list.Count - count}). Seen: {_seenGhostNames.Count}");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = ButterPlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("[GhostPlayerInjector-Poll] " + ex.Message));
				}
			}
		}

		private static void ZNet_RPC_PlayerList_Patch_AddIfMissing(List<PlayerInfo> list, string name)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(name))
			{
				return;
			}
			FieldInfo field = typeof(PlayerInfo).GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				return;
			}
			for (int i = 0; i < list.Count; i++)
			{
				if (string.Equals(field.GetValue(list[i]) as string, name, StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
			}
			list.Add(MakeGhostPlayerInfo(name));
		}
	}

	[HarmonyPatch(typeof(ZNet), "RPC_PlayerList")]
	internal static class ZNet_RPC_PlayerList_Patch
	{
		[HarmonyPostfix]
		public static void Postfix(ZNet __instance)
		{
			if ((Object)(object)__instance == (Object)null || __instance.IsServer())
			{
				return;
			}
			try
			{
				FieldInfo field = typeof(ZNet).GetField("m_players", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null)
				{
					if (_postfixRunCount == 0)
					{
						ManualLogSource logger = ButterPlugin.Logger;
						if (logger != null)
						{
							logger.LogWarning((object)"[GhostPlayerInjector] m_players field not found on ZNet.");
						}
					}
					_postfixRunCount++;
					return;
				}
				if (!(field.GetValue(__instance) is List<PlayerInfo> list))
				{
					if (_postfixRunCount == 0)
					{
						ManualLogSource logger2 = ButterPlugin.Logger;
						if (logger2 != null)
						{
							logger2.LogWarning((object)"[GhostPlayerInjector] m_players is null or wrong type.");
						}
					}
					_postfixRunCount++;
					return;
				}
				int count = list.Count;
				string name = GhostChatBypass.PermanentGhostName?.Value ?? "Aurora";
				string currentRotatingGhostName = GetCurrentRotatingGhostName();
				AddIfMissing(list, name);
				AddIfMissing(list, currentRotatingGhostName);
				foreach (string seenGhostName in _seenGhostNames)
				{
					AddIfMissing(list, seenGhostName);
				}
				_postfixRunCount++;
				if (_postfixRunCount == 1 || _postfixRunCount % 20 == 0)
				{
					ManualLogSource logger3 = ButterPlugin.Logger;
					if (logger3 != null)
					{
						logger3.LogInfo((object)$"[GhostPlayerInjector] Postfix run #{_postfixRunCount}. m_players was {count} → {list.Count} (added {list.Count - count} ghost(s)). Seen ghost names: {_seenGhostNames.Count}.");
					}
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger4 = ButterPlugin.Logger;
				if (logger4 != null)
				{
					logger4.LogWarning((object)("[GhostPlayerInjector] Postfix failed: " + ex.Message + "\n" + ex.StackTrace));
				}
			}
		}

		private static void AddIfMissing(List<PlayerInfo> list, string name)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if (string.IsNullOrEmpty(name))
			{
				return;
			}
			for (int i = 0; i < list.Count; i++)
			{
				FieldInfo field = typeof(PlayerInfo).GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				if (field == null)
				{
					break;
				}
				if (string.Equals(field.GetValue(list[i]) as string, name, StringComparison.OrdinalIgnoreCase))
				{
					return;
				}
			}
			list.Add(MakeGhostPlayerInfo(name));
		}
	}

	private static readonly HashSet<string> _seenGhostNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private const int RotationMinutes = 30;

	private static readonly string[] RotatingGhostPool = new string[48]
	{
		"Bjorn", "Sigrid", "Ragnar", "Freya", "Leif", "Astrid", "Ulf", "Ingrid", "Thorstein", "Gudrun",
		"Ivar", "Helga", "Sven", "Thyra", "Erik", "Hilda", "Harald", "Runa", "Olaf", "Solveig",
		"Gunnar", "Eira", "Knut", "Liv", "Torbjorn", "Sigrun", "Vidar", "Brynhild", "Arne", "Dagny",
		"Halfdan", "Ylva", "Fenrir", "Saga", "Ketil", "Alva", "Hakon", "Jorunn", "Styrbjorn", "Tove",
		"Bjarke", "Revna", "Grim", "Embla", "Thorgrim", "Nanna", "Oddvar", "Sif"
	};

	private static bool _diagDumped = false;

	private static readonly HashSet<string> _verifiedGhosts = new HashSet<string>();

	private static int _postfixRunCount = 0;

	public static string GetCurrentRotatingGhostName()
	{
		DateTime dateTime = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc);
		int num = (int)(Math.Abs((long)((DateTime.UtcNow - dateTime).TotalMinutes / 30.0)) % RotatingGhostPool.Length);
		return RotatingGhostPool[num];
	}

	public static void RememberGhost(string name)
	{
		if (!string.IsNullOrEmpty(name))
		{
			_seenGhostNames.Add(name);
		}
	}

	private static Vector3 PositionFor(string name)
	{
		//IL_008b: Unknown result type (might be due to invalid IL or missing references)
		int num = 0;
		string text = name ?? "";
		foreach (char c in text)
		{
			num = num * 31 + c;
		}
		Random random = new Random(num);
		float num2 = (float)(random.NextDouble() * Math.PI * 2.0);
		float num3 = 2000f + (float)(random.NextDouble() * 5000.0);
		float num4 = Mathf.Cos(num2) * num3;
		float num5 = Mathf.Sin(num2) * num3;
		return new Vector3(num4, 30f, num5);
	}

	private static void DumpPlayerInfoSchema()
	{
		if (_diagDumped)
		{
			return;
		}
		_diagDumped = true;
		try
		{
			Type typeFromHandle = typeof(PlayerInfo);
			ManualLogSource logger = ButterPlugin.Logger;
			if (logger != null)
			{
				logger.LogInfo((object)"[Diag] ZNet.PlayerInfo fields:");
			}
			FieldInfo[] fields = typeFromHandle.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo in fields)
			{
				ManualLogSource logger2 = ButterPlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogInfo((object)("  " + fieldInfo.FieldType.FullName + " " + fieldInfo.Name));
				}
			}
			FieldInfo field = typeFromHandle.GetField("m_userInfo", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(field != null))
			{
				return;
			}
			ManualLogSource logger3 = ButterPlugin.Logger;
			if (logger3 != null)
			{
				logger3.LogInfo((object)("[Diag] " + field.FieldType.FullName + " fields:"));
			}
			fields = field.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo2 in fields)
			{
				ManualLogSource logger4 = ButterPlugin.Logger;
				if (logger4 != null)
				{
					logger4.LogInfo((object)("  " + fieldInfo2.FieldType.FullName + " " + fieldInfo2.Name));
				}
			}
			FieldInfo field2 = field.FieldType.GetField("m_id", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (!(field2 != null))
			{
				return;
			}
			ManualLogSource logger5 = ButterPlugin.Logger;
			if (logger5 != null)
			{
				logger5.LogInfo((object)("[Diag] " + field2.FieldType.FullName + " (PlatformUserID) fields:"));
			}
			fields = field2.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo3 in fields)
			{
				ManualLogSource logger6 = ButterPlugin.Logger;
				if (logger6 != null)
				{
					logger6.LogInfo((object)("  " + fieldInfo3.FieldType.FullName + " " + fieldInfo3.Name));
				}
			}
		}
		catch (Exception ex)
		{
			ManualLogSource logger7 = ButterPlugin.Logger;
			if (logger7 != null)
			{
				logger7.LogWarning((object)("[Diag] dump failed: " + ex.Message));
			}
		}
	}

	internal static PlayerInfo MakeGhostPlayerInfo(string name)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0144: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ff: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_037e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0383: Unknown result type (might be due to invalid IL or missing references)
		//IL_0399: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_03e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_028f: Unknown result type (might be due to invalid IL or missing references)
		DumpPlayerInfoSchema();
		object obj = (object)default(PlayerInfo);
		Type typeFromHandle = typeof(PlayerInfo);
		typeFromHandle.GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(obj, name);
		long num = 1879048192L;
		uint num2 = 1u;
		try
		{
			uint num3 = 2166136261u;
			string text = name ?? "";
			foreach (char c in text)
			{
				num3 ^= c;
				num3 *= 16777619;
			}
			num = 0x70000000L | (long)(num3 & 0x7FFFFFFF);
			num2 = num3 % 255 + 1;
		}
		catch
		{
		}
		try
		{
			ConstructorInfo constructor = typeof(ZDOID).GetConstructor(new Type[2]
			{
				typeof(long),
				typeof(uint)
			});
			object value = ((constructor != null) ? constructor.Invoke(new object[2] { num, num2 }) : ((object)ZDOID.None));
			typeFromHandle.GetField("m_characterID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(obj, value);
		}
		catch
		{
			typeFromHandle.GetField("m_characterID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(obj, ZDOID.None);
		}
		typeFromHandle.GetField("m_publicPosition", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(obj, true);
		typeFromHandle.GetField("m_position", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(obj, PositionFor(name));
		typeFromHandle.GetField("m_serverAssignedDisplayName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(obj, name);
		try
		{
			FieldInfo field = typeFromHandle.GetField("m_userInfo", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				object obj4 = Activator.CreateInstance(field.FieldType);
				field.FieldType.GetField("m_displayName")?.SetValue(obj4, name);
				FieldInfo field2 = field.FieldType.GetField("m_id");
				if (field2 != null)
				{
					ulong num4 = 14695981039346656037uL;
					string text = name ?? "";
					foreach (char c2 in text)
					{
						num4 ^= c2;
						num4 *= 1099511628211L;
					}
					string text2 = (76561197960265728L + num4 % 1000000000).ToString();
					object obj5;
					try
					{
						obj5 = (object)new PlatformUserID("Steam", text2);
					}
					catch
					{
						obj5 = Activator.CreateInstance(field2.FieldType);
						FieldInfo field3 = field2.FieldType.GetField("m_platform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
						if (field3 != null)
						{
							try
							{
								ConstructorInfo constructor2 = field3.FieldType.GetConstructor(new Type[1] { typeof(string) });
								if (constructor2 != null)
								{
									field3.SetValue(obj5, constructor2.Invoke(new object[1] { "Steam" }));
								}
							}
							catch
							{
							}
						}
						field2.FieldType.GetField("m_userID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(obj5, text2);
					}
					GhostUserIDRegistry.Register(text2);
					field2.SetValue(obj4, obj5);
				}
				field.SetValue(obj, obj4);
			}
		}
		catch
		{
		}
		if (!_verifiedGhosts.Contains(name))
		{
			_verifiedGhosts.Add(name);
			try
			{
				PlayerInfo val = (PlayerInfo)obj;
				string text3 = typeFromHandle.GetField("m_name", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val) as string;
				object obj9 = typeFromHandle.GetField("m_position", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val);
				object obj10 = typeFromHandle.GetField("m_userInfo", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val);
				string text4 = null;
				string text5 = null;
				string text6 = null;
				if (obj10 != null)
				{
					Type type = obj10.GetType();
					text4 = type.GetField("m_displayName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj10) as string;
					object obj11 = type.GetField("m_id", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj10);
					if (obj11 != null)
					{
						Type type2 = obj11.GetType();
						text6 = (type2.GetField("m_platform", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj11))?.ToString();
						text5 = type2.GetField("m_userID", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj11) as string;
					}
				}
				ManualLogSource logger = ButterPlugin.Logger;
				if (logger != null)
				{
					logger.LogInfo((object)$"[Diag] ghost '{name}' built → m_name='{text3}' m_position={obj9} m_userInfo.m_displayName='{text4}' m_id.m_platform={text6} m_id.m_userID='{text5}'");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource logger2 = ButterPlugin.Logger;
				if (logger2 != null)
				{
					logger2.LogWarning((object)("[Diag] verify failed: " + ex.Message));
				}
			}
		}
		return (PlayerInfo)obj;
	}

	private static void SetField(object target, string name, object value)
	{
		try
		{
			target.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(target, value);
		}
		catch
		{
		}
	}
}
[BepInPlugin("freyja.AuroraProjectButter", "AuroraProjectButter", "1.3.9")]
public class ButterPlugin : BaseUnityPlugin
{
	internal struct DeferredDungeon
	{
		public DungeonGenerator Generator;

		public Vector3 Position;
	}

	[Serializable]
	[CompilerGenerated]
	private sealed class <>c
	{
		public static readonly <>c <>9 = new <>c();

		public static ConsoleEvent <>9__27_0;

		public static Func<MethodInfo, bool> <>9__31_0;

		public static Func<MethodInfo, bool> <>9__31_1;

		public static Func<MethodInfo, bool> <>9__31_2;

		public static Func<MethodInfo, bool> <>9__31_3;

		public static Func<MethodInfo, bool> <>9__32_0;

		public static Func<ParameterInfo, string> <>9__32_1;

		public static Predicate<DeferredDungeon> <>9__37_0;

		internal void <Awake>b__27_0(ConsoleEventArgs args)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			DungeonCleanup();
			Player localPlayer = Player.m_localPlayer;
			float num = ((localPlayer != null) ? ((Component)localPlayer).transform.position.y : float.NaN);
			bool flag = IsPlayerTeleporting();
			bool flag2 = IsInGracePeriod();
			args.Context.AddString("[AuroraProjectButter v1.3.9]");
			args.Context.AddString($"  Dungeon Deferral: {TotalDeferred} deferred, {TotalAllowed} allowed, {Deferred.Count} queued");
			args.Context.AddString($"  Sky Filter: {SkyObjectsBlocked} blocked, {SkyObjectsAllowed} allowed");
			args.Context.AddString($"  Player Y: {num:F1}  Teleporting: {flag}  Grace: {flag2}");
			args.Context.AddString($"  World radius: {WorldRadius.Value}");
		}

		internal bool <ApplyDungeonPatches>b__31_0(MethodInfo m)
		{
			if (m.Name == "Generate")
			{
				return !m.IsAbstract;
			}
			return false;
		}

		internal bool <ApplyDungeonPatches>b__31_1(MethodInfo mi)
		{
			return mi.Name == "Interact";
		}

		internal bool <ApplyDungeonPatches>b__31_2(MethodInfo mi)
		{
			return mi.Name == "HaveTarget";
		}

		internal bool <ApplyDungeonPatches>b__31_3(MethodInfo mi)
		{
			return mi.Name == "OnSpawned";
		}

		internal bool <ApplySkyFilterPatches>b__32_0(MethodInfo m)
		{
			if (m.Name == "CreateObject")
			{
				return !m.IsAbstract;
			}
			return false;
		}

		internal string <ApplySkyFilterPatches>b__32_1(ParameterInfo p)
		{
			return p.ParameterType.Name;
		}

		internal bool <DungeonCleanup>b__37_0(DeferredDungeon d)
		{
			return (Object)(object)d.Generator == (Object)null;
		}
	}

	public const string PluginGUID = "freyja.AuroraProjectButter";

	public const string PluginName = "AuroraProjectButter";

	public const string PluginVersion = "1.3.9";

	internal static ButterPlugin Instance;

	internal static ManualLogSource Logger;

	private Harmony _harmony;

	internal static readonly List<DeferredDungeon> Deferred = new List<DeferredDungeon>();

	internal static bool IsForceLoading;

	internal static bool IsTeleporting;

	internal static float PlayerSpawnTime = -1f;

	internal static float TeleportEndTime = -1f;

	internal static MethodInfo DG_AwakeMethod;

	internal static int TotalDeferred;

	internal static int TotalAllowed;

	internal static int SkyObjectsBlocked;

	internal static int SkyObjectsAllowed;

	public static ConfigEntry<bool> ModEnabled;

	public static ConfigEntry<bool> VerboseLogging;

	public static ConfigEntry<float> SearchRadius;

	public static ConfigEntry<float> TeleportDelay;

	public static ConfigEntry<bool> ShowLoadingMsg;

	public static ConfigEntry<float> SpawnGracePeriod;

	public static ConfigEntry<bool> SkyFilterEnabled;

	public static ConfigEntry<float> SkyThreshold;

	public static ConfigEntry<float> TeleportGracePeriod;

	public static ConfigEntry<float> WorldRadius;

	private void Awake()
	{
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a6: Expected O, but got Unknown
		//IL_026b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0270: Unknown result type (might be due to invalid IL or missing references)
		//IL_0276: Expected O, but got Unknown
		//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: Expected O, but got Unknown
		Instance = this;
		Logger = ((BaseUnityPlugin)this).Logger;
		if (!ServerGuard.Init(this))
		{
			return;
		}
		ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master toggle.");
		VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "Extra logging.");
		GhostChatBypass.PermanentGhostName = ((BaseUnityPlugin)this).Config.Bind<string>("General", "PermanentAI", "Aurora", "Permanent AI player name (server-side AI chat uses this identifier).");
		SearchRadius = ((BaseUnityPlugin)this).Config.Bind<float>("DungeonDeferral", "SearchRadius", 300f, "Max distance from entrance to find deferred dungeon.");
		TeleportDelay = ((BaseUnityPlugin)this).Config.Bind<float>("DungeonDeferral", "TeleportDelay", 2.5f, "Seconds to wait after loading dungeon before teleport.");
		ShowLoadingMsg = ((BaseUnityPlugin)this).Config.Bind<bool>("DungeonDeferral", "ShowLoadingMessage", true, "Show 'Loading dungeon...' message.");
		SpawnGracePeriod = ((BaseUnityPlugin)this).Config.Bind<float>("DungeonDeferral", "SpawnGracePeriod", 2f, "Seconds after login to allow all loading.");
		SkyFilterEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("SkyFilter", "Enabled", true, "Skip creating GameObjects for dungeon interior objects while on surface.");
		SkyThreshold = ((BaseUnityPlugin)this).Config.Bind<float>("SkyFilter", "SkyThresholdY", 1000f, "Objects above this Y are considered dungeon interiors.");
		TeleportGracePeriod = ((BaseUnityPlugin)this).Config.Bind<float>("SkyFilter", "TeleportGracePeriod", 5f, "Seconds after ANY teleport where sky filter is disabled. Prevents loading screen freeze.");
		WorldRadius = ((BaseUnityPlugin)this).Config.Bind<float>("SkyFilter", "WorldRadius", 15000f, "Objects beyond this X/Z distance from world center are never filtered. Set higher than your world radius to protect custom sky zones. Default 15000 covers most Expand World Size configs.");
		_harmony = new Harmony("freyja.AuroraProjectButter");
		Logger.LogInfo((object)"── Dungeon Deferral patches ──");
		ApplyDungeonPatches();
		Logger.LogInfo((object)"── Sky Object Filter patches ──");
		ApplySkyFilterPatches();
		Logger.LogInfo((object)"── Ghost Chat Bypass + Player Injector patches ──");
		try
		{
			_harmony.PatchAll(typeof(Chat_RPC_ChatMessage_GhostPatch));
			Logger.LogInfo((object)"  OK: Chat.RPC_ChatMessage (ghost chat bypass)");
		}
		catch (Exception ex)
		{
			Logger.LogWarning((object)("  FAILED: Chat_RPC_ChatMessage_GhostPatch: " + ex.Message));
		}
		try
		{
			_harmony.PatchAll(typeof(GhostPlayerInjector.ZNet_RPC_PlayerList_Patch));
			Logger.LogInfo((object)"  OK: ZNet.RPC_PlayerList (ghost player injector — F2 menu + map pins)");
		}
		catch (Exception ex2)
		{
			Logger.LogWarning((object)("  FAILED: GhostPlayerInjector.ZNet_RPC_PlayerList_Patch: " + ex2.Message));
		}
		GameObject val = new GameObject("AuroraGhostInjectorPoller");
		Object.DontDestroyOnLoad((Object)val);
		val.AddComponent<GhostPlayerInjector.GhostInjectorMB>();
		Logger.LogInfo((object)"  OK: GhostInjectorMB polling fallback active (checks m_players every 2s)");
		object obj = <>c.<>9__27_0;
		if (obj == null)
		{
			ConsoleEvent val2 = delegate(ConsoleEventArgs args)
			{
				//IL_001a: Unknown result type (might be due to invalid IL or missing references)
				DungeonCleanup();
				Player localPlayer = Player.m_localPlayer;
				float num = ((localPlayer != null) ? ((Component)localPlayer).transform.position.y : float.NaN);
				bool flag = IsPlayerTeleporting();
				bool flag2 = IsInGracePeriod();
				args.Context.AddString("[AuroraProjectButter v1.3.9]");
				args.Context.AddString($"  Dungeon Deferral: {TotalDeferred} deferred, {TotalAllowed} allowed, {Deferred.Count} queued");
				args.Context.AddString($"  Sky Filter: {SkyObjectsBlocked} blocked, {SkyObjectsAllowed} allowed");
				args.Context.AddString($"  Player Y: {num:F1}  Teleporting: {flag}  Grace: {flag2}");
				args.Context.AddString($"  World radius: {WorldRadius.Value}");
			};
			<>c.<>9__27_0 = val2;
			obj = (object)val2;
		}
		new ConsoleCommand("butter_status", "Show AuroraProjectButter stats", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		Logger.LogInfo((object)"=== AuroraProjectButter v1.3.9 loaded ===");
		Logger.LogInfo((object)"  Dungeon Deferral: ON");
		Logger.LogInfo((object)string.Format("  Sky Filter: {0} (Y > {1}, grace {2}s, radius {3})", SkyFilterEnabled.Value ? "ON" : "OFF", SkyThreshold.Value, TeleportGracePeriod.Value, WorldRadius.Value));
	}

	private void OnDestroy()
	{
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
	}

	internal static bool IsPlayerTeleporting()
	{
		if (IsTeleporting)
		{
			return true;
		}
		if (IsForceLoading)
		{
			return true;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return false;
		}
		try
		{
			FieldInfo field = typeof(Player).GetField("m_teleporting", BindingFlags.Instance | BindingFlags.NonPublic);
			if (field != null)
			{
				return (bool)field.GetValue(localPlayer);
			}
		}
		catch
		{
		}
		return false;
	}

	internal static bool IsInGracePeriod()
	{
		float time = Time.time;
		if (PlayerSpawnTime > 0f && time - PlayerSpawnTime < SpawnGracePeriod.Value)
		{
			return true;
		}
		if (TeleportEndTime > 0f && time - TeleportEndTime < TeleportGracePeriod.Value)
		{
			return true;
		}
		return false;
	}

	private void ApplyDungeonPatches()
	{
		//IL_004a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: Expected O, but got Unknown
		//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e0: Expected O, but got Unknown
		//IL_017f: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Expected O, but got Unknown
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0251: Expected O, but got Unknown
		//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_02e5: Expected O, but got Unknown
		//IL_0371: Unknown result type (might be due to invalid IL or missing references)
		//IL_037e: Expected O, but got Unknown
		try
		{
			DG_AwakeMethod = typeof(DungeonGenerator).GetMethod("Awake", BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (DG_AwakeMethod != null)
			{
				_harmony.Patch((MethodBase)DG_AwakeMethod, new HarmonyMethod(typeof(DungeonPatches), "Awake_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Logger.LogInfo((object)"  OK: DungeonGenerator.Awake()");
			}
			else
			{
				Logger.LogError((object)"  FAIL: DungeonGenerator.Awake()");
			}
		}
		catch (Exception arg)
		{
			Logger.LogError((object)$"  DG.Awake: {arg}");
		}
		try
		{
			MethodInfo method = typeof(DungeonGenerator).GetMethod("LoadRoomPrefabsAsync", BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
			if (method != null)
			{
				_harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(DungeonPatches), "LoadAsync_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Logger.LogInfo((object)"  OK: LoadRoomPrefabsAsync() (fallback)");
			}
		}
		catch (Exception ex)
		{
			Logger.LogWarning((object)("  LoadAsync: " + ex.Message));
		}
		try
		{
			List<MethodInfo> list = (from m in typeof(DungeonGenerator).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
				where m.Name == "Generate" && !m.IsAbstract
				select m).ToList();
			MethodInfo method2 = typeof(DungeonPatches).GetMethod("Generate_Prefix", BindingFlags.Static | BindingFlags.Public);
			int num = 0;
			foreach (MethodInfo item in list)
			{
				try
				{
					_harmony.Patch((MethodBase)item, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					num++;
				}
				catch
				{
				}
			}
			Logger.LogInfo((object)$"  OK: {num} Generate overload(s)");
		}
		catch (Exception arg2)
		{
			Logger.LogError((object)$"  Generate: {arg2}");
		}
		try
		{
			MethodInfo methodInfo = typeof(Teleport).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo mi) => mi.Name == "Interact");
			if (methodInfo != null)
			{
				_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DungeonPatches), "Teleport_Interact_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Logger.LogInfo((object)"  OK: Teleport.Interact");
			}
		}
		catch (Exception arg3)
		{
			Logger.LogError((object)$"  Teleport.Interact: {arg3}");
		}
		try
		{
			MethodInfo methodInfo2 = typeof(Teleport).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo mi) => mi.Name == "HaveTarget");
			if (methodInfo2 != null)
			{
				_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(DungeonPatches), "HaveTarget_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Logger.LogInfo((object)"  OK: Teleport.HaveTarget");
			}
		}
		catch (Exception ex2)
		{
			Logger.LogWarning((object)("  HaveTarget: " + ex2.Message));
		}
		try
		{
			MethodInfo methodInfo3 = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo mi) => mi.Name == "OnSpawned");
			if (methodInfo3 != null)
			{
				_harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(DungeonPatches), "Player_OnSpawned_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Logger.LogInfo((object)"  OK: Player.OnSpawned");
			}
		}
		catch (Exception ex3)
		{
			Logger.LogWarning((object)("  Player.OnSpawned: " + ex3.Message));
		}
	}

	private void ApplySkyFilterPatches()
	{
		//IL_0165: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Expected O, but got Unknown
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Expected O, but got Unknown
		if (!SkyFilterEnabled.Value)
		{
			Logger.LogInfo((object)"  Sky Filter DISABLED in config.");
			return;
		}
		try
		{
			List<MethodInfo> list = (from m in typeof(ZNetScene).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
				where m.Name == "CreateObject" && !m.IsAbstract
				select m).ToList();
			MethodInfo method = typeof(SkyFilterPatches).GetMethod("CreateObject_Prefix", BindingFlags.Static | BindingFlags.Public);
			int num = 0;
			foreach (MethodInfo item in list)
			{
				ParameterInfo[] parameters = item.GetParameters();
				if (parameters.Length >= 1 && parameters[0].ParameterType == typeof(ZDO))
				{
					_harmony.Patch((MethodBase)item, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
					string text = string.Join(", ", parameters.Select((ParameterInfo p) => p.ParameterType.Name));
					Logger.LogInfo((object)("  OK: ZNetScene.CreateObject(" + text + ")"));
					num++;
				}
			}
			if (num == 0)
			{
				Logger.LogWarning((object)"  No ZDO-parameter CreateObject found. Trying all overloads...");
				foreach (MethodInfo item2 in list)
				{
					try
					{
						_harmony.Patch((MethodBase)item2, new HarmonyMethod(method), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						num++;
					}
					catch
					{
					}
				}
			}
			if (num == 0)
			{
				Logger.LogError((object)"  FAIL: Could not patch any ZNetScene.CreateObject!");
			}
		}
		catch (Exception arg)
		{
			Logger.LogError((object)$"  ZNetScene.CreateObject: {arg}");
		}
	}

	internal static bool ShouldDefer(string caller, Vector3 genPos)
	{
		//IL_0063: 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_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0134: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		if (!ModEnabled.Value)
		{
			return false;
		}
		if (IsForceLoading)
		{
			return false;
		}
		if ((Object)(object)Player.m_localPlayer == (Object)null)
		{
			if (VerboseLogging.Value)
			{
				Logger.LogInfo((object)$"[ALLOW:no-player] {caller} at {genPos:F0}");
			}
			TotalAllowed++;
			return false;
		}
		Vector3 position = ((Component)Player.m_localPlayer).transform.position;
		if (IsInGracePeriod())
		{
			if (VerboseLogging.Value)
			{
				Logger.LogInfo((object)$"[ALLOW:grace] {caller} at {genPos:F0}");
			}
			TotalAllowed++;
			return false;
		}
		if (position.y > 1000f)
		{
			if (VerboseLogging.Value)
			{
				Logger.LogInfo((object)$"[ALLOW:in-dungeon] {caller} at {genPos:F0}");
			}
			TotalAllowed++;
			return false;
		}
		if (IsPlayerTeleporting())
		{
			if (VerboseLogging.Value)
			{
				Logger.LogInfo((object)$"[ALLOW:teleporting] {caller} at {genPos:F0}");
			}
			TotalAllowed++;
			return false;
		}
		Logger.LogInfo((object)$"[DEFER] {caller} at {genPos:F0}, player Y={position.y:F0}");
		TotalDeferred++;
		return true;
	}

	internal static void DeferDungeon(DungeonGenerator gen)
	{
		//IL_0018: 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_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		Vector3 position = ((Component)gen).transform.position;
		if (!Deferred.Any((DeferredDungeon d) => (Object)(object)d.Generator == (Object)(object)gen))
		{
			Deferred.Add(new DeferredDungeon
			{
				Generator = gen,
				Position = position
			});
		}
	}

	internal static DeferredDungeon? FindNearest(Vector3 origin, float maxDist)
	{
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		DungeonCleanup();
		DeferredDungeon? result = null;
		float num = float.MaxValue;
		foreach (DeferredDungeon item in Deferred)
		{
			float num2 = item.Position.x - origin.x;
			float num3 = item.Position.z - origin.z;
			float num4 = Mathf.Sqrt(num2 * num2 + num3 * num3);
			if (num4 < maxDist && num4 < num)
			{
				num = num4;
				result = item;
			}
		}
		return result;
	}

	internal static void RemoveDeferred(DungeonGenerator gen)
	{
		Deferred.RemoveAll((DeferredDungeon d) => (Object)(object)d.Generator == (Object)(object)gen || (Object)(object)d.Generator == (Object)null);
	}

	internal static void DungeonCleanup()
	{
		Deferred.RemoveAll((DeferredDungeon d) => (Object)(object)d.Generator == (Object)null);
	}

	internal static void ForceLoadDungeon(DungeonGenerator gen)
	{
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		if (DG_AwakeMethod == null)
		{
			Logger.LogError((object)"[REPLAY] No Awake method!");
			return;
		}
		IsForceLoading = true;
		try
		{
			Logger.LogInfo((object)$"[REPLAY] Awake() at {((Component)gen).transform.position:F0}");
			DG_AwakeMethod.Invoke(gen, null);
		}
		finally
		{
			IsForceLoading = false;
		}
	}

	internal static Coroutine RunCoroutine(IEnumerator routine)
	{
		ButterPlugin instance = Instance;
		if (instance == null)
		{
			return null;
		}
		return ((MonoBehaviour)instance).StartCoroutine(routine);
	}
}
internal static class SkyFilterPatches
{
	public static bool CreateObject_Prefix(ZDO __0)
	{
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_006f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00db: Unknown result type (might be due to invalid IL or missing references)
		if (!ButterPlugin.SkyFilterEnabled.Value)
		{
			return true;
		}
		if (__0 == null)
		{
			return true;
		}
		if ((Object)(object)Player.m_localPlayer == (Object)null)
		{
			return true;
		}
		if (ButterPlugin.IsPlayerTeleporting())
		{
			ButterPlugin.SkyObjectsAllowed++;
			return true;
		}
		if (ButterPlugin.IsInGracePeriod())
		{
			ButterPlugin.SkyObjectsAllowed++;
			return true;
		}
		Vector3 position = __0.GetPosition();
		float y = position.y;
		if (y <= ButterPlugin.SkyThreshold.Value)
		{
			return true;
		}
		float num = Mathf.Sqrt(position.x * position.x + position.z * position.z);
		if (num > ButterPlugin.WorldRadius.Value)
		{
			ButterPlugin.SkyObjectsAllowed++;
			if (ButterPlugin.VerboseLogging.Value)
			{
				ButterPlugin.Logger.LogInfo((object)$"[SkyFilter:ALLOW] Outside world radius: Y={y:F0} dist={num:F0}");
			}
			return true;
		}
		if (((Component)Player.m_localPlayer).transform.position.y > ButterPlugin.SkyThreshold.Value)
		{
			ButterPlugin.SkyObjectsAllowed++;
			return true;
		}
		ButterPlugin.SkyObjectsBlocked++;
		if (ButterPlugin.VerboseLogging.Value && ButterPlugin.SkyObjectsBlocked % 100 == 1)
		{
			ButterPlugin.Logger.LogInfo((object)$"[SkyFilter:BLOCK] #{ButterPlugin.SkyObjectsBlocked} Y={y:F0} dist={num:F0}");
		}
		return false;
	}
}
internal static class DungeonPatches
{
	[CompilerGenerated]
	private sealed class <LoadAndTeleport>d__5 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public ButterPlugin.DeferredDungeon deferred;

		public Teleport teleport;

		public Humanoid character;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <LoadAndTeleport>d__5(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				if (ButterPlugin.ShowLoadingMsg.Value)
				{
					Player localPlayer = Player.m_localPlayer;
					if (localPlayer != null)
					{
						((Character)localPlayer).Message((MessageType)2, "Loading dungeon...", 0, (Sprite)null);
					}
				}
				ButterPlugin.TeleportEndTime = Time.time;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				if ((Object)(object)deferred.Generator != (Object)null)
				{
					try
					{
						ButterPlugin.ForceLoadDungeon(deferred.Generator);
					}
					catch (Exception arg2)
					{
						ButterPlugin.Logger.LogError((object)$"[OnDemand] Failed: {arg2}");
					}
					ButterPlugin.RemoveDeferred(deferred.Generator);
				}
				<>2__current = (object)new WaitForSeconds(ButterPlugin.TeleportDelay.Value);
				<>1__state = 2;
				return true;
			case 2:
				<>1__state = -1;
				ButterPlugin.TeleportEndTime = Time.time;
				if ((Object)(object)teleport != (Object)null && (Object)(object)character != (Object)null)
				{
					ButterPlugin.IsTeleporting = true;
					try
					{
						teleport.Interact(character, false, false);
					}
					catch (Exception arg)
					{
						ButterPlugin.Logger.LogError((object)$"[OnDemand] Teleport: {arg}");
					}
					finally
					{
						ButterPlugin.IsTeleporting = false;
					}
				}
				return false;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	public static void Player_OnSpawned_Postfix(Player __instance)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
		{
			ButterPlugin.PlayerSpawnTime = Time.time;
			ButterPlugin.TeleportEndTime = Time.time;
			ButterPlugin.Logger.LogInfo((object)$"[Spawn] Player at {((Component)__instance).transform.position:F0}");
		}
	}

	public static bool Awake_Prefix(DungeonGenerator __instance)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		if (ButterPlugin.ShouldDefer("Awake", ((Component)__instance).transform.position))
		{
			ButterPlugin.DeferDungeon(__instance);
			return false;
		}
		return true;
	}

	public static bool LoadAsync_Prefix(DungeonGenerator __instance)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		if (ButterPlugin.ShouldDefer("LoadAsync", ((Component)__instance).transform.position))
		{
			ButterPlugin.DeferDungeon(__instance);
			return false;
		}
		return true;
	}

	public static bool Generate_Prefix(DungeonGenerator __instance)
	{
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		if (ButterPlugin.ShouldDefer("Generate", ((Component)__instance).transform.position))
		{
			ButterPlugin.DeferDungeon(__instance);
			return false;
		}
		return true;
	}

	public static bool Teleport_Interact_Prefix(Teleport __instance, Humanoid character, bool hold, bool alt)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_0058: 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)
		if (!ButterPlugin.ModEnabled.Value)
		{
			return true;
		}
		if (ButterPlugin.IsTeleporting)
		{
			return true;
		}
		if ((Object)(object)character != (Object)(object)Player.m_localPlayer)
		{
			return true;
		}
		if (hold)
		{
			return true;
		}
		if (((Component)Player.m_localPlayer).transform.position.y > 1000f)
		{
			ButterPlugin.TeleportEndTime = Time.time;
			return true;
		}
		ButterPlugin.DeferredDungeon? deferredDungeon = ButterPlugin.FindNearest(((Component)__instance).transform.position, ButterPlugin.SearchRadius.Value);
		if (!deferredDungeon.HasValue)
		{
			ButterPlugin.TeleportEndTime = Time.time;
			return true;
		}
		ButterPlugin.Logger.LogInfo((object)$"[OnDemand] Entrance → loading dungeon at {deferredDungeon.Value.Position:F0}");
		ButterPlugin.RunCoroutine(LoadAndTeleport(__instance, deferredDungeon.Value, character));
		return false;
	}

	[IteratorStateMachine(typeof(<LoadAndTeleport>d__5))]
	private static IEnumerator LoadAndTeleport(Teleport teleport, ButterPlugin.DeferredDungeon deferred, Humanoid character)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <LoadAndTeleport>d__5(0)
		{
			teleport = teleport,
			deferred = deferred,
			character = character
		};
	}

	public static void HaveTarget_Postfix(Teleport __instance, ref bool __result)
	{
		//IL_0024: 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)
		if (ButterPlugin.ModEnabled.Value && (!((Object)(object)Player.m_localPlayer != (Object)null) || !(((Component)Player.m_localPlayer).transform.position.y > 1000f)) && !__result && ButterPlugin.FindNearest(((Component)__instance).transform.position, ButterPlugin.SearchRadius.Value).HasValue)
		{
			__result = true;
		}
	}
}
internal static class ServerGuard
{
	private const string PasswordHash = "e7aab22a4200ed38c615552e666633ba96140d314df8e1c00d08b886527a1dd4";

	private const string ConfigSection = "Protection";

	private const string ConfigKey = "password";

	private static ConfigEntry<string> _cfgPassword;

	public static bool Init(ButterPlugin plugin)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Invalid comparison between Unknown and I4
		_cfgPassword = ((BaseUnityPlugin)plugin).Config.Bind<string>("Protection", "password", "enter_password_here", "Server password required to run AuroraProjectButter on a dedicated server. Leave as-is on game clients — this check is ignored there.");
		if ((int)SystemInfo.graphicsDeviceType != 4)
		{
			ManualLogSource logger = ButterPlugin.Logger;
			if (logger != null)
			{
				logger.LogInfo((object)"[ServerGuard] Running on client - auth skipped");
			}
			return true;
		}
		if (HashPassword(_cfgPassword.Value?.Trim() ?? string.Empty) == "e7aab22a4200ed38c615552e666633ba96140d314df8e1c00d08b886527a1dd4")
		{
			ManualLogSource logger2 = ButterPlugin.Logger;
			if (logger2 != null)
			{
				logger2.LogInfo((object)"[ServerGuard] Server auth OK.");
			}
			return true;
		}
		ManualLogSource logger3 = ButterPlugin.Logger;
		if (logger3 != null)
		{
			logger3.LogError((object)"══════════════════════════════════════════════════\n  INVALID PASSWORD — AuroraProjectButter will not load.\n  Set the correct password in:\n  BepInEx/config/freyja.AuroraProjectButter.cfg\n  under [Protection] > password\n══════════════════════════════════════════════════");
		}
		return false;
	}

	private static string HashPassword(string input)
	{
		using SHA256 sHA = SHA256.Create();
		byte[] bytes = Encoding.UTF8.GetBytes(input);
		byte[] array = sHA.ComputeHash(bytes);
		StringBuilder stringBuilder = new StringBuilder(64);
		byte[] array2 = array;
		foreach (byte b in array2)
		{
			stringBuilder.Append(b.ToString("x2"));
		}
		return stringBuilder.ToString();
	}
}