Decompiled source of WorldPreGenerator v1.0.14

BepInEx/plugins/WorldPreGenerator/WorldPreGenerator.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WorldPreGenerator")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("WorldPreGenerator")]
[assembly: AssemblyTitle("WorldPreGenerator")]
[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 WorldPreGenerator
{
	[BepInPlugin("com.kimbauer.valheim.worldpregen", "World Pre-Generator", "1.0.13")]
	[BepInProcess("valheim.exe")]
	[BepInProcess("valheim_server.exe")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Id = "com.kimbauer.valheim.worldpregen";

		public const string Version = "1.0.13";

		internal static Plugin Instance;

		internal static ConfigEntry<bool> ShowMenuButton;

		internal static ConfigEntry<float> DefaultRadius;

		internal static ConfigEntry<bool> ShowChunkGrid;

		internal static ConfigEntry<bool> HideUnexploredLocationIcons;

		internal static ConfigEntry<float> MaxMillisecondsPerFrame;

		internal static ConfigEntry<int> SaveEveryZones;

		internal static ConfigEntry<int> ZonesPerBatch;

		internal static ConfigEntry<int> MaxConcurrentZoneRequests;

		internal static ConfigEntry<float> BatchPauseSeconds;

		internal static WorldPreGeneratorController Controller;

		private Harmony harmony;

		private void Awake()
		{
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Expected O, but got Unknown
			Instance = this;
			ShowMenuButton = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowMenuButton", true, "Exibe o botão Pré-gerar mundo no menu de pausa (ESC).");
			ShowChunkGrid = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowChunkGrid", false, "Exibe no mapa M o estado das zonas sem revelar o terreno não explorado.");
			HideUnexploredLocationIcons = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "HideUnexploredLocationIcons", true, "Oculta ícones de pontos de interesse até que a área seja explorada pelo jogador.");
			DefaultRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Generation", "DefaultRadius", 10000f, "Raio padrão em metros quando Mundo completo estiver desmarcado.");
			MaxMillisecondsPerFrame = ((BaseUnityPlugin)this).Config.Bind<float>("Generation", "MaxMillisecondsPerFrame", 6f, "Tempo máximo por quadro usado para gerar zonas. Valores menores reduzem travamentos.");
			SaveEveryZones = ((BaseUnityPlugin)this).Config.Bind<int>("Generation", "SaveEveryZones", 250, "Salva o mundo a cada quantidade de zonas concluídas. Use 0 para salvar somente ao terminar.");
			ZonesPerBatch = ((BaseUnityPlugin)this).Config.Bind<int>("Generation", "ZonesPerBatch", 4, "Quantidade máxima de zonas processadas antes de ceder o controle ao jogo. Valores menores são mais estáveis.");
			MaxConcurrentZoneRequests = ((BaseUnityPlugin)this).Config.Bind<int>("Generation", "MaxConcurrentZoneRequests", 4, "Quantidade máxima de zonas aguardando terreno pronto. Limite baixo reduz o uso de memória.");
			BatchPauseSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Generation", "BatchPauseSeconds", 0.05f, "Pausa entre lotes de zonas em segundos. Aumente se o jogo ficar pesado.");
			GameObject val = new GameObject("WorldPreGeneratorController");
			Object.DontDestroyOnLoad((Object)val);
			Controller = val.AddComponent<WorldPreGeneratorController>();
			harmony = new Harmony("com.kimbauer.valheim.worldpregen");
			harmony.PatchAll();
			WorldPreGeneratorCommands.Register();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"World Pre-Generator 1.0.13 carregado.");
		}

		internal static void Report(Exception exception)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogError((object)exception);
			}
		}

		internal static void Warn(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogWarning((object)message);
			}
		}

		internal static void WriteInfo(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)message);
			}
		}

		private void OnDestroy()
		{
			try
			{
				Controller?.CancelForServerShutdown();
			}
			catch (Exception exception)
			{
				Report(exception);
			}
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			if (Object.op_Implicit((Object)(object)Controller))
			{
				Object.Destroy((Object)(object)((Component)Controller).gameObject);
			}
			Controller = null;
			Instance = null;
		}
	}
	internal static class MenuFields
	{
		internal static readonly FieldInfo Root = AccessTools.Field(typeof(Menu), "m_root");

		internal static readonly FieldInfo Entries = AccessTools.Field(typeof(Menu), "menuEntriesParent");

		internal static readonly FieldInfo SaveButton = AccessTools.Field(typeof(Menu), "m_saveButton");
	}
	internal static class WorldPreGeneratorNetwork
	{
		private const string RequestCheckName = "WorldPreGenerator_RequestCheck";

		private const string RequestStartName = "WorldPreGenerator_RequestStart";

		private const string RequestCancelName = "WorldPreGenerator_RequestCancel";

		private const string RequestStatusName = "WorldPreGenerator_RequestStatus";

		private const string RequestGridName = "WorldPreGenerator_RequestGrid";

		private const string RequestHelloName = "WorldPreGenerator_Hello";

		private const string StateName = "WorldPreGenerator_State";

		private const string GridStateName = "WorldPreGenerator_GridState";

		private static readonly FieldInfo PeerUidField = AccessTools.Field(typeof(ZNetPeer), "m_uid");

		private static readonly FieldInfo PeerPlayerIdField = AccessTools.Field(typeof(ZNetPeer), "m_playerID");

		private static readonly FieldInfo PeerPlayerNameField = AccessTools.Field(typeof(ZNetPeer), "m_playerName");

		private static readonly FieldInfo PeerPlayFabIdField = AccessTools.Field(typeof(ZNetPeer), "m_playfabId");

		private static readonly FieldInfo PeerRpcField = AccessTools.Field(typeof(ZNetPeer), "m_rpc");

		private static readonly FieldInfo PeerSocketField = AccessTools.Field(typeof(ZNetPeer), "m_socket");

		private static readonly MethodInfo SocketHostNameMethod = ((PeerSocketField != null) ? AccessTools.Method(PeerSocketField.FieldType, "GetHostName", (Type[])null, (Type[])null) : null);

		private static readonly MethodInfo GetServerPeerIdMethod = AccessTools.Method(typeof(ZRoutedRpc), "GetServerPeerID", (Type[])null, (Type[])null);

		private static readonly MethodInfo PlayerIsAdminMethod = AccessTools.Method(typeof(ZNet), "PlayerIsAdmin", (Type[])null, (Type[])null);

		private static readonly Type PlatformUserIdType;

		private static readonly MethodInfo PlatformUserIdTryParseMethod;

		private static readonly MethodInfo GetPlayerListMethod;

		private static readonly Type PlayerInfoType;

		private static readonly Type CrossNetworkUserInfoType;

		private static readonly FieldInfo PlayerInfoNameField;

		private static readonly FieldInfo PlayerInfoUserInfoField;

		private static readonly FieldInfo UserInfoIdField;

		private static bool registered;

		private static ZRoutedRpc registeredRouter;

		private static ZNet directRpcNet;

		private static float nextRegistrationAttempt;

		private static float nextBroadcast;

		private static bool chatProgressActive;

		private static float nextChatProgress;

		private static readonly HashSet<ZRpc> directRegistered;

		private static readonly HashSet<long> modPeers;

		private static byte[] cachedGridBits;

		private static string cachedGridWorld;

		private static int cachedGridMax;

		private static float cachedGridZoneSize;

		private static float gridCacheExpires;

		internal static bool IsRemoteClient
		{
			get
			{
				try
				{
					return (Object)(object)ZNet.instance != (Object)null && !ZNet.IsSinglePlayer && !ZNet.instance.IsServer();
				}
				catch
				{
					return false;
				}
			}
		}

		internal static bool RemoteCanManage { get; private set; }

		internal static bool RemotePermissionKnown { get; private set; }

		internal static void Tick()
		{
			RefreshNetworkContext();
			EnsureRegistered();
			EnsureDirectRpc();
			if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer() && !((Object)(object)Plugin.Controller == (Object)null) && (Plugin.Controller.IsChecking || Plugin.Controller.IsGenerating) && !(Time.realtimeSinceStartup < nextBroadcast))
			{
				nextBroadcast = Time.realtimeSinceStartup + 5f;
				BroadcastState();
			}
		}

		internal static void EnsureRegistered()
		{
			RefreshNetworkContext();
			if (registered || ZRoutedRpc.instance == null)
			{
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (realtimeSinceStartup < nextRegistrationAttempt)
			{
				return;
			}
			nextRegistrationAttempt = realtimeSinceStartup + 2f;
			try
			{
				ZRoutedRpc.instance.Register<ZPackage>("WorldPreGenerator_RequestCheck", (Action<long, ZPackage>)HandleCheck);
				ZRoutedRpc.instance.Register<ZPackage>("WorldPreGenerator_RequestStart", (Action<long, ZPackage>)HandleStart);
				ZRoutedRpc.instance.Register<ZPackage>("WorldPreGenerator_RequestCancel", (Action<long, ZPackage>)HandleCancel);
				ZRoutedRpc.instance.Register<ZPackage>("WorldPreGenerator_RequestStatus", (Action<long, ZPackage>)HandleStatus);
				ZRoutedRpc.instance.Register<ZPackage>("WorldPreGenerator_RequestGrid", (Action<long, ZPackage>)HandleGrid);
				ZRoutedRpc.instance.Register<ZPackage>("WorldPreGenerator_Hello", (Action<long, ZPackage>)delegate(long sender, ZPackage package)
				{
					HandleHello(sender);
				});
				ZRoutedRpc.instance.Register<ZPackage>("WorldPreGenerator_State", (Action<long, ZPackage>)HandleState);
				ZRoutedRpc.instance.Register<ZPackage>("WorldPreGenerator_GridState", (Action<long, ZPackage>)delegate(long sender, ZPackage package)
				{
					HandleGridState(sender, package);
				});
				registered = true;
				nextBroadcast = 0f;
				Plugin.WriteInfo("RPC do servidor registrado.");
			}
			catch (ArgumentException)
			{
				registered = true;
				nextBroadcast = 0f;
				Plugin.WriteInfo("RPC do servidor já estava registrado nesta sessão.");
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		internal static void RequestStatus()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			SendToServer("WorldPreGenerator_RequestStatus", new ZPackage());
		}

		internal static void RequestGrid()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			SendToServer("WorldPreGenerator_RequestGrid", new ZPackage());
		}

		internal static void RequestCheck(bool fullWorld, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(fullWorld);
			val.Write(radius);
			SendToServer("WorldPreGenerator_RequestCheck", val);
		}

		internal static void RequestStart(bool fullWorld, float radius)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(fullWorld);
			val.Write(radius);
			SendToServer("WorldPreGenerator_RequestStart", val);
		}

		internal static void RequestCancel()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			SendToServer("WorldPreGenerator_RequestCancel", new ZPackage());
		}

		internal static void ClearRemoteState()
		{
			chatProgressActive = false;
			nextChatProgress = 0f;
			RemoteCanManage = false;
			RemotePermissionKnown = false;
			MinimapGridOverlay.ClearRemoteGrid();
			WorldPreGeneratorUi.ClearRemoteState();
		}

		internal static void PublishState()
		{
			nextBroadcast = 0f;
			try
			{
				if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
				{
					BroadcastState();
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		private static void SendToServer(string rpcName, ZPackage package)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Expected O, but got Unknown
			try
			{
				EnsureRegistered();
				if (!IsRemoteClient)
				{
					return;
				}
				ZRpc serverRPC = ZNet.instance.GetServerRPC();
				if (serverRPC != null)
				{
					if (!string.Equals(rpcName, "WorldPreGenerator_Hello", StringComparison.Ordinal))
					{
						serverRPC.Invoke("WorldPreGenerator_Hello", new object[1] { (object)new ZPackage() });
					}
					serverRPC.Invoke(rpcName, new object[1] { package });
				}
				else
				{
					if (ZRoutedRpc.instance == null)
					{
						return;
					}
					if (GetServerPeerIdMethod != null && GetServerPeerIdMethod.Invoke(ZRoutedRpc.instance, null) is long num)
					{
						if (!string.Equals(rpcName, "WorldPreGenerator_Hello", StringComparison.Ordinal))
						{
							ZRoutedRpc.instance.InvokeRoutedRPC(num, "WorldPreGenerator_Hello", new object[1] { (object)new ZPackage() });
						}
						ZRoutedRpc.instance.InvokeRoutedRPC(num, rpcName, new object[1] { package });
					}
					else
					{
						if (!string.Equals(rpcName, "WorldPreGenerator_Hello", StringComparison.Ordinal))
						{
							ZRoutedRpc.instance.InvokeRoutedRPC("WorldPreGenerator_Hello", new object[1] { (object)new ZPackage() });
						}
						ZRoutedRpc.instance.InvokeRoutedRPC(rpcName, new object[1] { package });
					}
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		private static void HandleHello(long sender)
		{
			if (sender != 0L)
			{
				modPeers.Add(sender);
			}
		}

		private static void HandleCheck(long sender, ZPackage package)
		{
			HandleHello(sender);
			Plugin.WriteInfo($"Solicitação de verificação recebida via RPC (peer {sender}).");
			if (!Authorize(sender))
			{
				Plugin.WriteInfo($"Solicitação de verificação recusada (peer {sender}: host/admin necessário).");
				SendState(sender, "@WPG:StatusNeedAdmin");
				return;
			}
			WorldPreGeneratorController controller = Plugin.Controller;
			if ((Object)(object)controller == (Object)null)
			{
				SendState(sender);
				return;
			}
			bool fullWorld = package != null && package.ReadBool();
			float radius = ((package != null) ? package.ReadSingle() : WorldPreGeneratorController.GetWorldRadius());
			controller.BeginCheck(null, fullWorld, radius);
			SendState(sender);
		}

		private static void HandleStart(long sender, ZPackage package)
		{
			HandleHello(sender);
			Plugin.WriteInfo($"Solicitação de geração recebida via RPC (peer {sender}).");
			if (!Authorize(sender))
			{
				Plugin.WriteInfo($"Solicitação de geração recusada (peer {sender}: host/admin necessário).");
				SendState(sender, "@WPG:StatusNeedAdmin");
				return;
			}
			WorldPreGeneratorController controller = Plugin.Controller;
			if ((Object)(object)controller == (Object)null)
			{
				SendState(sender);
				return;
			}
			bool fullWorld = package != null && package.ReadBool();
			float radius = ((package != null) ? package.ReadSingle() : WorldPreGeneratorController.GetWorldRadius());
			controller.BeginGeneration(null, fullWorld, radius);
			SendState(sender);
		}

		private static void HandleCancel(long sender, ZPackage package)
		{
			HandleHello(sender);
			Plugin.WriteInfo($"Solicitação de cancelamento recebida via RPC (peer {sender}).");
			if (!Authorize(sender))
			{
				Plugin.WriteInfo($"Solicitação de cancelamento recusada (peer {sender}: host/admin necessário).");
				SendState(sender, "@WPG:StatusNeedAdmin");
			}
			else
			{
				Plugin.Controller?.CancelGeneration();
				SendState(sender);
			}
		}

		private static void HandleStatus(long sender, ZPackage package)
		{
			HandleHello(sender);
			if (!Authorize(sender))
			{
				SendState(sender, "@WPG:StatusNeedAdmin");
			}
			else
			{
				SendState(sender);
			}
		}

		private static void HandleState(long sender, ZPackage package)
		{
			if (!IsRemoteClient || package == null)
			{
				return;
			}
			try
			{
				WorldPreGeneratorRemoteState worldPreGeneratorRemoteState = new WorldPreGeneratorRemoteState
				{
					WorldName = package.ReadString(),
					Status = Translations.DecodeRemoteStatus(package.ReadString()),
					IsChecking = package.ReadBool(),
					IsGenerating = package.ReadBool(),
					Total = package.ReadInt(),
					Generated = package.ReadInt(),
					Missing = package.ReadInt(),
					Processed = package.ReadInt(),
					Failed = package.ReadInt(),
					EtaSeconds = package.ReadDouble(),
					CanManage = false
				};
				try
				{
					worldPreGeneratorRemoteState.CanManage = package.ReadBool();
				}
				catch
				{
					worldPreGeneratorRemoteState.CanManage = (Object)(object)Plugin.Controller != (Object)null && Plugin.Controller.CanCheck;
				}
				RemoteCanManage = worldPreGeneratorRemoteState.CanManage;
				RemotePermissionKnown = true;
				UpdateChatProgress(worldPreGeneratorRemoteState);
				WorldPreGeneratorUi.ApplyRemoteState(worldPreGeneratorRemoteState);
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		private static void HandleGrid(long sender, ZPackage package)
		{
			HandleHello(sender);
			SendGridState(sender, Authorize(sender));
		}

		private static void HandleGridState(long sender, ZPackage package)
		{
			if (!IsRemoteClient || package == null)
			{
				return;
			}
			try
			{
				WorldPreGeneratorGridState obj = new WorldPreGeneratorGridState
				{
					WorldName = package.ReadString(),
					ZoneSize = package.ReadSingle(),
					MaxZone = package.ReadInt(),
					CanManage = package.ReadBool(),
					GeneratedBits = package.ReadByteArray()
				};
				RemoteCanManage = obj.CanManage;
				RemotePermissionKnown = true;
				MinimapGridOverlay.ApplyRemoteGrid(obj);
				WorldPreGeneratorUi.ApplyRemoteGrid(obj);
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		private static void UpdateChatProgress(WorldPreGeneratorRemoteState state)
		{
			if (state == null || !state.IsGenerating)
			{
				chatProgressActive = false;
				nextChatProgress = 0f;
				return;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!chatProgressActive)
			{
				chatProgressActive = true;
				nextChatProgress = realtimeSinceStartup + 30f;
			}
			else if (!(realtimeSinceStartup < nextChatProgress))
			{
				nextChatProgress = realtimeSinceStartup + 30f;
				ShowChatProgress(state);
			}
		}

		internal static void TickLocalChat(WorldPreGeneratorController controller)
		{
			if (!IsRemoteClient && !((Object)(object)controller == (Object)null))
			{
				if (!controller.IsGenerating)
				{
					chatProgressActive = false;
					nextChatProgress = 0f;
					return;
				}
				UpdateChatProgress(new WorldPreGeneratorRemoteState
				{
					WorldName = controller.ActiveWorldName,
					Status = controller.Status,
					IsGenerating = true,
					CanManage = controller.CanCheck,
					Total = controller.Total,
					Generated = controller.Generated,
					Missing = controller.Missing,
					Processed = controller.Processed,
					Failed = controller.Failed,
					EtaSeconds = controller.EstimatedSecondsRemaining
				});
			}
		}

		private static void ShowChatProgress(WorldPreGeneratorRemoteState state)
		{
			try
			{
				Chat instance = Chat.instance;
				if (!((Object)(object)instance == (Object)null))
				{
					string text = ((state.EtaSeconds >= 0.0) ? Translations.Format("Eta", WorldPreGeneratorModal.FormatDuration(state.EtaSeconds)) : Translations.Text("EtaCalculating"));
					string text2 = Translations.Text("StatusGenerating") + "\n" + Translations.Format("Counts", state.Total, state.Generated, state.Missing) + "\n" + text;
					((Terminal)instance).AddString(text2);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		private static void BroadcastState()
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			List<ZNetPeer> peers = instance.GetPeers();
			if (peers == null)
			{
				return;
			}
			for (int i = 0; i < peers.Count; i++)
			{
				ZNetPeer peer = peers[i];
				long peerLong = GetPeerLong(PeerUidField, peer);
				if (peerLong != 0L && modPeers.Contains(peerLong))
				{
					SendState(peerLong);
				}
			}
		}

		private static void SendGridState(long target, bool canManage)
		{
			try
			{
				if (target != 0L && !((Object)(object)Plugin.Controller == (Object)null))
				{
					ZPackage val = CreateGridPackage(Plugin.Controller, canManage);
					ZRpc peerRpc = GetPeerRpc(ZNet.instance.GetPeer(target));
					if (peerRpc != null)
					{
						peerRpc.Invoke("WorldPreGenerator_GridState", new object[1] { val });
					}
					else if (ZRoutedRpc.instance != null)
					{
						ZRoutedRpc.instance.InvokeRoutedRPC(target, "WorldPreGenerator_GridState", new object[1] { val });
					}
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		private static ZPackage CreateGridPackage(WorldPreGeneratorController controller, bool canManage)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			string text = (((Object)(object)controller != (Object)null) ? controller.ActiveWorldName : string.Empty);
			if (string.IsNullOrEmpty(text))
			{
				try
				{
					text = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : string.Empty);
				}
				catch
				{
					text = string.Empty;
				}
			}
			float zoneSize = WorldPreGeneratorController.GetZoneSize();
			int num = Mathf.CeilToInt(WorldPreGeneratorController.GetWorldRadius() / zoneSize) + 1;
			byte[] array = (canManage ? GetGeneratedGridBits(text, zoneSize, num) : Array.Empty<byte>());
			val.Write(text ?? string.Empty);
			val.Write(zoneSize);
			val.Write(num);
			val.Write(canManage);
			val.Write(array ?? Array.Empty<byte>());
			return val;
		}

		private static byte[] GetGeneratedGridBits(string world, float zoneSize, int max)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (cachedGridBits != null && string.Equals(cachedGridWorld, world, StringComparison.Ordinal) && cachedGridMax == max && Math.Abs(cachedGridZoneSize - zoneSize) < 0.01f && realtimeSinceStartup < gridCacheExpires)
			{
				return cachedGridBits;
			}
			int num = max * 2 + 1;
			byte[] array = new byte[(num * num + 7) / 8];
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance != (Object)null)
			{
				for (int i = -max; i <= max; i++)
				{
					for (int j = -max; j <= max; j++)
					{
						if (WorldPreGeneratorController.IsZoneGeneratedForOverlay(instance, new Vector2s(i, j)))
						{
							int num2 = (i + max) * num + (j + max);
							array[num2 >> 3] |= (byte)(1 << (num2 & 7));
						}
					}
				}
			}
			cachedGridBits = array;
			cachedGridWorld = world;
			cachedGridMax = max;
			cachedGridZoneSize = zoneSize;
			gridCacheExpires = realtimeSinceStartup + 5f;
			return array;
		}

		private static void SendState(long target, string statusOverride = null)
		{
			try
			{
				if (target != 0L && !((Object)(object)Plugin.Controller == (Object)null))
				{
					ZPackage val = CreateStatePackage(Plugin.Controller, statusOverride, Authorize(target, logFailure: false));
					ZRpc peerRpc = GetPeerRpc(ZNet.instance.GetPeer(target));
					if (peerRpc != null)
					{
						peerRpc.Invoke("WorldPreGenerator_State", new object[1] { val });
					}
					else if (ZRoutedRpc.instance != null)
					{
						ZRoutedRpc.instance.InvokeRoutedRPC(target, "WorldPreGenerator_State", new object[1] { val });
					}
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		private static bool Authorize(long sender, bool logFailure = true)
		{
			try
			{
				ZNet instance = ZNet.instance;
				if ((Object)(object)instance == (Object)null || !instance.IsServer())
				{
					return false;
				}
				if (sender == ZNet.GetUID())
				{
					return true;
				}
				ZNetPeer peer = instance.GetPeer(sender);
				if (peer == null)
				{
					return false;
				}
				string text = PeerPlayerNameField?.GetValue(peer) as string;
				if (!string.IsNullOrEmpty(text) && instance.IsAdmin(text))
				{
					return true;
				}
				long peerLong = GetPeerLong(PeerPlayerIdField, peer);
				string text2 = PeerPlayFabIdField?.GetValue(peer) as string;
				string peerSocketHostName = GetPeerSocketHostName(peer);
				List<string> adminList = instance.GetAdminList();
				string[] array = new string[8]
				{
					GetPeerLong(PeerUidField, peer).ToString(CultureInfo.InvariantCulture),
					peerLong.ToString(CultureInfo.InvariantCulture),
					(peerLong > 0) ? ("Steam_" + peerLong.ToString(CultureInfo.InvariantCulture)) : null,
					text2,
					IsNumericIdentifier(text2) ? ("Steam_" + text2) : null,
					peerSocketHostName,
					IsNumericIdentifier(peerSocketHostName) ? ("Steam_" + peerSocketHostName) : null,
					text
				};
				if (IsPlatformAdmin(instance, array) || IsPlayerListAdmin(instance, text))
				{
					return true;
				}
				if (adminList == null || adminList.Count == 0)
				{
					return false;
				}
				for (int i = 0; i < array.Length; i++)
				{
					for (int j = 0; j < adminList.Count; j++)
					{
						if (AdminIdentifierMatches(adminList[j], array[i]))
						{
							return true;
						}
					}
				}
				if (logFailure)
				{
					Plugin.WriteInfo(string.Format("Autorização recusada: peer={0}, nome='{1}', playerId={2}, playFab='{3}', socket='{4}', adminlist=[{5}].", sender, text, peerLong, text2, peerSocketHostName, string.Join(",", adminList)));
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
			return false;
		}

		private static string GetPeerSocketHostName(ZNetPeer peer)
		{
			if (peer == null || PeerSocketField == null || SocketHostNameMethod == null)
			{
				return null;
			}
			try
			{
				object value = PeerSocketField.GetValue(peer);
				return (value != null) ? (SocketHostNameMethod.Invoke(value, null) as string) : null;
			}
			catch
			{
				return null;
			}
		}

		private static bool IsPlatformAdmin(ZNet net, string[] identifiers)
		{
			if ((Object)(object)net == (Object)null || PlayerIsAdminMethod == null || PlatformUserIdType == null || PlatformUserIdTryParseMethod == null)
			{
				return false;
			}
			bool flag = default(bool);
			foreach (string text in identifiers)
			{
				if (string.IsNullOrWhiteSpace(text))
				{
					continue;
				}
				try
				{
					object[] array = new object[2]
					{
						text,
						Activator.CreateInstance(PlatformUserIdType)
					};
					object obj = PlatformUserIdTryParseMethod.Invoke(null, array);
					if (obj is bool && (bool)obj)
					{
						obj = PlayerIsAdminMethod.Invoke(net, new object[1] { array[1] });
						int num;
						if (obj is bool)
						{
							flag = (bool)obj;
							num = 1;
						}
						else
						{
							num = 0;
						}
						if (((uint)num & (flag ? 1u : 0u)) != 0)
						{
							return true;
						}
					}
				}
				catch
				{
				}
			}
			return false;
		}

		private static bool IsPlayerListAdmin(ZNet net, string playerName)
		{
			if ((Object)(object)net == (Object)null || string.IsNullOrWhiteSpace(playerName) || GetPlayerListMethod == null || PlayerInfoNameField == null || PlayerInfoUserInfoField == null || UserInfoIdField == null || PlayerIsAdminMethod == null)
			{
				return false;
			}
			try
			{
				if (!(GetPlayerListMethod.Invoke(net, null) is IEnumerable enumerable))
				{
					return false;
				}
				bool flag = default(bool);
				foreach (object item in enumerable)
				{
					if (!string.Equals(PlayerInfoNameField.GetValue(item) as string, playerName, StringComparison.OrdinalIgnoreCase))
					{
						continue;
					}
					object value = PlayerInfoUserInfoField.GetValue(item);
					object value2 = UserInfoIdField.GetValue(value);
					int num;
					if (value2 != null)
					{
						object obj = PlayerIsAdminMethod.Invoke(net, new object[1] { value2 });
						if (obj is bool)
						{
							flag = (bool)obj;
							num = 1;
						}
						else
						{
							num = 0;
						}
					}
					else
					{
						num = 0;
					}
					if (((uint)num & (flag ? 1u : 0u)) != 0)
					{
						return true;
					}
				}
			}
			catch
			{
			}
			return false;
		}

		private static bool IsNumericIdentifier(string value)
		{
			if (string.IsNullOrWhiteSpace(value))
			{
				return false;
			}
			for (int i = 0; i < value.Length; i++)
			{
				if (value[i] < '0' || value[i] > '9')
				{
					return false;
				}
			}
			return true;
		}

		private static bool AdminIdentifierMatches(string allowed, string candidate)
		{
			if (string.IsNullOrWhiteSpace(allowed) || string.IsNullOrWhiteSpace(candidate))
			{
				return false;
			}
			if (string.Equals(allowed.Trim(), candidate.Trim(), StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			return string.Equals(NormalizeAdminIdentifier(allowed), NormalizeAdminIdentifier(candidate), StringComparison.OrdinalIgnoreCase);
		}

		private static string NormalizeAdminIdentifier(string value)
		{
			string text = value.Trim();
			string[] array = new string[6] { "steam_", "xbox_", "playfab_", "psn_", "ps_", "epic_" };
			for (int i = 0; i < array.Length; i++)
			{
				if (text.StartsWith(array[i], StringComparison.OrdinalIgnoreCase))
				{
					return text.Substring(array[i].Length);
				}
			}
			return text;
		}

		private static long GetPeerLong(FieldInfo field, ZNetPeer peer)
		{
			try
			{
				return (field?.GetValue(peer) is long num) ? num : 0;
			}
			catch
			{
				return 0L;
			}
		}

		private static ZPackage CreateStatePackage(WorldPreGeneratorController controller, string statusOverride = null, bool canManage = false)
		{
			//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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			val.Write(controller.ActiveWorldName ?? string.Empty);
			val.Write(Translations.EncodeRemoteStatus(statusOverride ?? controller.Status ?? string.Empty));
			val.Write(controller.IsChecking);
			val.Write(controller.IsGenerating);
			val.Write(controller.Total);
			val.Write(controller.Generated);
			val.Write(controller.Missing);
			val.Write(controller.Processed);
			val.Write(controller.Failed);
			val.Write(controller.EstimatedSecondsRemaining);
			val.Write(canManage);
			return val;
		}

		private static ZRpc GetPeerRpc(ZNetPeer peer)
		{
			try
			{
				object? obj = PeerRpcField?.GetValue(peer);
				return (ZRpc)((obj is ZRpc) ? obj : null);
			}
			catch
			{
				return null;
			}
		}

		private static void EnsureDirectRpc()
		{
			try
			{
				RefreshNetworkContext();
				ZNet instance = ZNet.instance;
				if ((Object)(object)instance == (Object)null)
				{
					return;
				}
				if (instance.IsServer())
				{
					List<ZNetPeer> peers = instance.GetPeers();
					if (peers != null)
					{
						for (int i = 0; i < peers.Count; i++)
						{
							RegisterServerRpc(GetPeerRpc(peers[i]));
						}
					}
				}
				else if (!ZNet.IsSinglePlayer)
				{
					RegisterClientRpc(instance.GetServerRPC());
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		private static void RefreshNetworkContext()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			ZNet instance2 = ZNet.instance;
			bool flag = instance != registeredRouter;
			bool flag2 = instance2 != directRpcNet;
			if (flag || flag2)
			{
				if (flag)
				{
					registeredRouter = instance;
					registered = false;
				}
				if (flag2)
				{
					directRpcNet = instance2;
					directRegistered.Clear();
					modPeers.Clear();
					RemoteCanManage = false;
					RemotePermissionKnown = false;
				}
				nextBroadcast = 0f;
				nextRegistrationAttempt = 0f;
			}
		}

		private static void RegisterServerRpc(ZRpc rpc)
		{
			if (rpc != null && directRegistered.Add(rpc))
			{
				rpc.Register<ZPackage>("WorldPreGenerator_RequestCheck", (Action<ZRpc, ZPackage>)delegate(ZRpc source, ZPackage package)
				{
					HandleCheck(GetSenderUid(source), package);
				});
				rpc.Register<ZPackage>("WorldPreGenerator_RequestStart", (Action<ZRpc, ZPackage>)delegate(ZRpc source, ZPackage package)
				{
					HandleStart(GetSenderUid(source), package);
				});
				rpc.Register<ZPackage>("WorldPreGenerator_RequestCancel", (Action<ZRpc, ZPackage>)delegate(ZRpc source, ZPackage package)
				{
					HandleCancel(GetSenderUid(source), package);
				});
				rpc.Register<ZPackage>("WorldPreGenerator_RequestStatus", (Action<ZRpc, ZPackage>)delegate(ZRpc source, ZPackage package)
				{
					HandleStatus(GetSenderUid(source), package);
				});
				rpc.Register<ZPackage>("WorldPreGenerator_RequestGrid", (Action<ZRpc, ZPackage>)delegate(ZRpc source, ZPackage package)
				{
					HandleGrid(GetSenderUid(source), package);
				});
				rpc.Register<ZPackage>("WorldPreGenerator_Hello", (Action<ZRpc, ZPackage>)delegate(ZRpc source, ZPackage package)
				{
					HandleHello(GetSenderUid(source));
				});
				Plugin.WriteInfo("RPC direto registrado para um cliente.");
			}
		}

		private static void RegisterClientRpc(ZRpc rpc)
		{
			if (rpc != null && directRegistered.Add(rpc))
			{
				rpc.Register<ZPackage>("WorldPreGenerator_State", (Action<ZRpc, ZPackage>)delegate(ZRpc source, ZPackage package)
				{
					HandleState(-1L, package);
				});
				rpc.Register<ZPackage>("WorldPreGenerator_GridState", (Action<ZRpc, ZPackage>)delegate(ZRpc source, ZPackage package)
				{
					HandleGridState(-1L, package);
				});
				Plugin.WriteInfo("RPC direto do servidor registrado no cliente.");
			}
		}

		private static long GetSenderUid(ZRpc rpc)
		{
			try
			{
				ZNet instance = ZNet.instance;
				List<ZNetPeer> list = ((instance != null) ? instance.GetPeers() : null);
				if (list == null)
				{
					return 0L;
				}
				for (int i = 0; i < list.Count; i++)
				{
					ZNetPeer peer = list[i];
					if (GetPeerRpc(peer) == rpc)
					{
						return GetPeerLong(PeerUidField, peer);
					}
				}
				return 0L;
			}
			catch
			{
				return 0L;
			}
		}

		static WorldPreGeneratorNetwork()
		{
			MethodInfo playerIsAdminMethod = PlayerIsAdminMethod;
			PlatformUserIdType = (((object)playerIsAdminMethod != null && playerIsAdminMethod.GetParameters().Length == 1) ? PlayerIsAdminMethod.GetParameters()[0].ParameterType : null);
			PlatformUserIdTryParseMethod = ((PlatformUserIdType != null) ? AccessTools.Method(PlatformUserIdType, "TryParse", (Type[])null, (Type[])null) : null);
			GetPlayerListMethod = AccessTools.Method(typeof(ZNet), "GetPlayerList", (Type[])null, (Type[])null);
			PlayerInfoType = AccessTools.TypeByName("ZNet+PlayerInfo");
			CrossNetworkUserInfoType = AccessTools.TypeByName("ZNet+CrossNetworkUserInfo");
			PlayerInfoNameField = ((PlayerInfoType != null) ? AccessTools.Field(PlayerInfoType, "m_name") : null);
			PlayerInfoUserInfoField = ((PlayerInfoType != null) ? AccessTools.Field(PlayerInfoType, "m_userInfo") : null);
			UserInfoIdField = ((CrossNetworkUserInfoType != null) ? AccessTools.Field(CrossNetworkUserInfoType, "m_id") : null);
			directRegistered = new HashSet<ZRpc>();
			modPeers = new HashSet<long>();
		}
	}
	internal sealed class WorldPreGeneratorRemoteState
	{
		internal string WorldName;

		internal string Status;

		internal bool IsChecking;

		internal bool IsGenerating;

		internal int Total;

		internal int Generated;

		internal int Missing;

		internal int Processed;

		internal int Failed;

		internal double EtaSeconds;

		internal bool CanManage;
	}
	internal sealed class WorldPreGeneratorGridState
	{
		internal string WorldName;

		internal float ZoneSize;

		internal int MaxZone;

		internal bool CanManage;

		internal byte[] GeneratedBits;
	}
	[HarmonyPatch(typeof(Menu), "Show")]
	internal static class MenuShowPatch
	{
		private static void Postfix(Menu __instance)
		{
			try
			{
				WorldPreGeneratorUi.Attach(__instance);
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(Menu), "OnClose")]
	internal static class MenuClosePatch
	{
		private static void Postfix()
		{
			try
			{
				WorldPreGeneratorUi.HideModal();
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(Menu), "OnLogoutYes")]
	internal static class MenuLogoutPatch
	{
		private static void Prefix()
		{
			try
			{
				Plugin.Controller?.HandleWorldExit(saveWorld: false);
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(Game), "Logout")]
	internal static class GameLogoutPatch
	{
		private static void Prefix()
		{
			try
			{
				Plugin.Controller?.HandleWorldExit(saveWorld: false);
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "Shutdown")]
	internal static class ZNetShutdownPatch
	{
		private static void Prefix()
		{
			try
			{
				if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
				{
					Plugin.Controller?.CancelForServerShutdown();
				}
				else
				{
					Plugin.Controller?.HandleWorldExit(saveWorld: false);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "ShutdownWithoutSave")]
	internal static class ZNetShutdownWithoutSavePatch
	{
		private static void Prefix()
		{
			try
			{
				if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
				{
					Plugin.Controller?.CancelForServerShutdown();
				}
				else
				{
					Plugin.Controller?.HandleWorldExit(saveWorld: false);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(ZNet), "OnDestroy")]
	internal static class ZNetDestroyPatch
	{
		private static void Prefix()
		{
			try
			{
				if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())
				{
					Plugin.Controller?.CancelForServerShutdown();
				}
				else
				{
					Plugin.Controller?.HandleWorldExit(saveWorld: false);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(Localization), "SetLanguage")]
	internal static class WorldPreGeneratorLanguagePatch
	{
		private static void Postfix()
		{
			try
			{
				WorldPreGeneratorUi.RefreshLanguage();
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	internal static class TerminalInitPatch
	{
		private static void Postfix()
		{
			try
			{
				WorldPreGeneratorCommands.Register();
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	internal static class WorldPreGeneratorCommands
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static ConsoleEvent <0>__CommandRoot;

			public static ConsoleEvent <1>__CommandStart;

			public static ConsoleEvent <2>__CommandCheck;

			public static ConsoleEvent <3>__CommandCancel;

			public static ConsoleEvent <4>__CommandStatus;
		}

		private static readonly FieldInfo CommandsField = AccessTools.Field(typeof(Terminal), "commands");

		internal static void Register()
		{
			//IL_003b: 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)
			//IL_0046: Expected O, but got Unknown
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			try
			{
				if (CommandsField?.GetValue(null) is IDictionary commands)
				{
					object obj = <>O.<0>__CommandRoot;
					if (obj == null)
					{
						ConsoleEvent val = CommandRoot;
						<>O.<0>__CommandRoot = val;
						obj = (object)val;
					}
					Add(commands, "worldpregen", "worldpregen [start|check|cancel|status] - controla a pré-geração do mundo", (ConsoleEvent)obj);
					object obj2 = <>O.<1>__CommandStart;
					if (obj2 == null)
					{
						ConsoleEvent val2 = CommandStart;
						<>O.<1>__CommandStart = val2;
						obj2 = (object)val2;
					}
					Add(commands, "worldpregen_start", "worldpregen_start [full|raio] - inicia a pré-geração", (ConsoleEvent)obj2);
					object obj3 = <>O.<2>__CommandCheck;
					if (obj3 == null)
					{
						ConsoleEvent val3 = CommandCheck;
						<>O.<2>__CommandCheck = val3;
						obj3 = (object)val3;
					}
					Add(commands, "worldpregen_check", "worldpregen_check [full|raio] - verifica zonas", (ConsoleEvent)obj3);
					object obj4 = <>O.<3>__CommandCancel;
					if (obj4 == null)
					{
						ConsoleEvent val4 = CommandCancel;
						<>O.<3>__CommandCancel = val4;
						obj4 = (object)val4;
					}
					Add(commands, "worldpregen_cancel", "worldpregen_cancel - cancela a pré-geração", (ConsoleEvent)obj4);
					object obj5 = <>O.<4>__CommandStatus;
					if (obj5 == null)
					{
						ConsoleEvent val5 = CommandStatus;
						<>O.<4>__CommandStatus = val5;
						obj5 = (object)val5;
					}
					Add(commands, "worldpregen_status", "worldpregen_status - mostra o progresso", (ConsoleEvent)obj5);
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		private static void Add(IDictionary commands, string name, string description, ConsoleEvent handler)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			commands[name] = (object?)new ConsoleCommand(name, description, handler, false, false, true, false, true, false, (ConsoleOptionsFetcher)null, false, false, true);
		}

		private static void CommandRoot(ConsoleEventArgs args)
		{
			switch ((args != null && args.Length > 1) ? args[1].ToLowerInvariant() : string.Empty)
			{
			case "start":
				CommandStart(args);
				break;
			case "check":
				CommandCheck(args);
				break;
			case "cancel":
				CommandCancel(args);
				break;
			case "status":
				CommandStatus(args);
				break;
			default:
				Write("Uso: worldpregen start [full|raio], worldpregen check [full|raio], worldpregen cancel ou worldpregen status.");
				break;
			}
		}

		private static void CommandStart(ConsoleEventArgs args)
		{
			if (!TryReadArea(args, (args == null || args.Length <= 1 || !args[0].Equals("worldpregen", StringComparison.OrdinalIgnoreCase)) ? 1 : 2, out var fullWorld, out var radius))
			{
				Write("Área inválida. Use 'full' ou um raio em metros.");
				return;
			}
			WorldPreGeneratorController controller = Plugin.Controller;
			if ((Object)(object)controller == (Object)null)
			{
				Write("Controlador ainda não está pronto.");
				return;
			}
			if (controller.IsGenerating)
			{
				Write("Já existe uma pré-geração em andamento.");
				return;
			}
			controller.BeginGeneration(null, fullWorld, radius);
			Write(fullWorld ? "Pré-geração completa solicitada." : $"Pré-geração solicitada para raio {radius:0} m.");
		}

		private static void CommandCheck(ConsoleEventArgs args)
		{
			if (!TryReadArea(args, (args == null || args.Length <= 1 || !args[0].Equals("worldpregen", StringComparison.OrdinalIgnoreCase)) ? 1 : 2, out var fullWorld, out var radius))
			{
				Write("Área inválida. Use 'full' ou um raio em metros.");
				return;
			}
			WorldPreGeneratorController controller = Plugin.Controller;
			if ((Object)(object)controller == (Object)null)
			{
				Write("Controlador ainda não está pronto.");
				return;
			}
			if (controller.IsChecking)
			{
				Write("Já existe uma verificação em andamento.");
				return;
			}
			controller.BeginCheck(null, fullWorld, radius);
			Write(fullWorld ? "Verificação completa solicitada." : $"Verificação solicitada para raio {radius:0} m.");
		}

		private static void CommandCancel(ConsoleEventArgs args)
		{
			WorldPreGeneratorController controller = Plugin.Controller;
			if ((Object)(object)controller == (Object)null)
			{
				Write("Controlador ainda não está pronto.");
				return;
			}
			if (!controller.IsGenerating)
			{
				Write("Nenhuma pré-geração está em andamento.");
				return;
			}
			controller.CancelGeneration();
			Write("Pré-geração cancelada; o progresso já salvo foi preservado.");
		}

		private static void CommandStatus(ConsoleEventArgs args)
		{
			WorldPreGeneratorController controller = Plugin.Controller;
			if ((Object)(object)controller == (Object)null)
			{
				Write("Controlador ainda não está pronto.");
				return;
			}
			double estimatedSecondsRemaining = controller.EstimatedSecondsRemaining;
			string text = ((estimatedSecondsRemaining >= 0.0) ? FormatDuration(estimatedSecondsRemaining) : "calculando");
			Write($"Mundo: {controller.ActiveWorldName} | estado={controller.Status} | total={controller.Total:N0} geradas={controller.Generated:N0} faltantes={controller.Missing:N0} processadas={controller.Processed:N0} falhas={controller.Failed:N0} ETA={text}");
		}

		private static bool TryReadArea(ConsoleEventArgs args, int index, out bool fullWorld, out float radius)
		{
			fullWorld = true;
			radius = ((Plugin.DefaultRadius != null) ? Plugin.DefaultRadius.Value : 10000f);
			if (args == null || args.Length <= index)
			{
				return true;
			}
			string text = args[index] ?? string.Empty;
			if (text.Equals("full", StringComparison.OrdinalIgnoreCase) || text.Equals("completo", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			if (!float.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && !float.TryParse(text, NumberStyles.Float, CultureInfo.GetCultureInfo("pt-BR"), out result))
			{
				return false;
			}
			fullWorld = false;
			radius = WorldPreGeneratorController.ParseRadius(text);
			return result > 0f;
		}

		private static string FormatDuration(double seconds)
		{
			TimeSpan timeSpan = TimeSpan.FromSeconds(Math.Max(0.0, seconds));
			if (timeSpan.TotalDays >= 1.0)
			{
				return $"{(int)timeSpan.TotalDays}d {timeSpan.Hours:00}h";
			}
			if (timeSpan.TotalHours >= 1.0)
			{
				return $"{timeSpan.Hours}h {timeSpan.Minutes:00}min";
			}
			if (timeSpan.TotalMinutes >= 1.0)
			{
				return $"{timeSpan.Minutes}min {timeSpan.Seconds:00}s";
			}
			return $"{Math.Max(1, timeSpan.Seconds)}s";
		}

		private static void Write(string message)
		{
			string text = "[WorldPreGenerator] " + message;
			try
			{
				Terminal.Log((object)text);
			}
			catch
			{
			}
			Plugin.WriteInfo(text);
		}
	}
	[HarmonyPatch(typeof(Achievements), "AchievementEvent", new Type[]
	{
		typeof(Achievement),
		typeof(bool),
		typeof(bool)
	})]
	internal static class AchievementEventGuardPatch
	{
		private static bool Prefix()
		{
			return !WorldPreGeneratorController.SuppressAchievementEvents;
		}
	}
	[HarmonyPatch(typeof(Achievements), "AchievementStatIncrementEvent", new Type[]
	{
		typeof(PlayerStatType),
		typeof(uint)
	})]
	internal static class AchievementStatEnumGuardPatch
	{
		private static bool Prefix()
		{
			return !WorldPreGeneratorController.SuppressAchievementEvents;
		}
	}
	[HarmonyPatch(typeof(Achievements), "AchievementStatIncrementEvent", new Type[]
	{
		typeof(string),
		typeof(uint)
	})]
	internal static class AchievementStatStringGuardPatch
	{
		private static bool Prefix()
		{
			return !WorldPreGeneratorController.SuppressAchievementEvents;
		}
	}
	[HarmonyPatch(typeof(Achievements), "AchievementStatSetEvent", new Type[]
	{
		typeof(PlayerStatType),
		typeof(uint)
	})]
	internal static class AchievementStatSetGuardPatch
	{
		private static bool Prefix()
		{
			return !WorldPreGeneratorController.SuppressAchievementEvents;
		}
	}
	[HarmonyPatch(typeof(Game), "IncrementPlayerStat", new Type[]
	{
		typeof(PlayerStatType),
		typeof(float),
		typeof(bool)
	})]
	internal static class ExplorationStatGuardPatch
	{
		private unsafe static bool Prefix(PlayerStatType stat)
		{
			if (!WorldPreGeneratorController.SuppressAchievementEvents)
			{
				return true;
			}
			return !((object)(*(PlayerStatType*)(&stat))/*cast due to .constrained prefix*/).ToString().StartsWith("Explore", StringComparison.OrdinalIgnoreCase);
		}
	}
	[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
	{
		typeof(int),
		typeof(int)
	})]
	internal static class MinimapExplorePixelGuardPatch
	{
		private static bool Prefix()
		{
			return !WorldPreGeneratorController.SuppressAchievementEvents;
		}
	}
	[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
	{
		typeof(Vector3),
		typeof(float)
	})]
	internal static class MinimapExploreWorldGuardPatch
	{
		private static bool Prefix()
		{
			return !WorldPreGeneratorController.SuppressAchievementEvents;
		}
	}
	[HarmonyPatch(typeof(Minimap), "Start")]
	internal static class MinimapStartPatch
	{
		private static void Postfix(Minimap __instance)
		{
			try
			{
				MinimapGridOverlay.Attach(__instance);
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "SetMapMode")]
	internal static class MinimapMapModePatch
	{
		private static void Postfix(Minimap __instance)
		{
			try
			{
				MinimapGridOverlay.Attach(__instance);
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(ZoneSystem), "GetLocationIcons")]
	internal static class UnexploredLocationIconsPatch
	{
		private static void Postfix(Dictionary<Vector3, string> icons)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (icons == null)
				{
					return;
				}
				List<Vector3> list = null;
				foreach (KeyValuePair<Vector3, string> icon in icons)
				{
					if (WorldPreGeneratorController.ShouldHideLocationIcon(icon.Key))
					{
						if (list == null)
						{
							list = new List<Vector3>();
						}
						list.Add(icon.Key);
					}
				}
				if (list != null)
				{
					for (int i = 0; i < list.Count; i++)
					{
						icons.Remove(list[i]);
					}
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(ZoneSystem), "GetLocationIcon")]
	internal static class UnexploredLocationIconPatch
	{
		private static void Postfix(ref Vector3 pos, ref bool __result)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//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)
			try
			{
				if (__result && WorldPreGeneratorController.ShouldHideLocationIcon(pos))
				{
					__result = false;
					pos = Vector3.zero;
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "UpdateLocationPins")]
	internal static class UnexploredLocationPinsPatch
	{
		private static readonly FieldInfo LocationPinsField = AccessTools.Field(typeof(Minimap), "m_locationPins");

		private static readonly Type PinDataType = AccessTools.TypeByName("Minimap+PinData");

		private static readonly FieldInfo PinUiElementField = ((PinDataType != null) ? AccessTools.Field(PinDataType, "m_uiElement") : null);

		private static void Postfix(Minimap __instance)
		{
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if ((Object)(object)__instance == (Object)null || LocationPinsField == null || PinUiElementField == null || Plugin.HideUnexploredLocationIcons == null || !Plugin.HideUnexploredLocationIcons.Value || !(LocationPinsField.GetValue(__instance) is IDictionary dictionary))
				{
					return;
				}
				foreach (DictionaryEntry item in dictionary)
				{
					if (item.Key is Vector3 position && WorldPreGeneratorController.ShouldHideLocationIcon(position))
					{
						object? value = PinUiElementField.GetValue(item.Value);
						RectTransform val = (RectTransform)((value is RectTransform) ? value : null);
						if (Object.op_Implicit((Object)(object)val))
						{
							((Component)val).gameObject.SetActive(false);
						}
					}
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}
	}
	internal sealed class MinimapGridOverlay : MonoBehaviour
	{
		private readonly struct MapProjection
		{
			private readonly Vector2 origin;

			private readonly Vector2 xPerMeter;

			private readonly Vector2 zPerMeter;

			internal MapProjection(Vector2 origin, Vector2 xPerMeter, Vector2 zPerMeter)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0002: Unknown result type (might be due to invalid IL or missing references)
				//IL_0008: 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: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				this.origin = origin;
				this.xPerMeter = xPerMeter;
				this.zPerMeter = zPerMeter;
			}

			internal Vector2 MapPoint(Vector3 world)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: 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_0012: Unknown result type (might be due to invalid IL or missing references)
				//IL_0017: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0023: Unknown result type (might be due to invalid IL or missing references)
				//IL_0028: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				return origin + world.x * xPerMeter + world.z * zPerMeter;
			}
		}

		private static readonly FieldInfo LargeMapImageField = AccessTools.Field(typeof(Minimap), "m_mapImageLarge");

		private static readonly MethodInfo IsExploredMethod = AccessTools.Method(typeof(Minimap), "IsExplored", (Type[])null, (Type[])null);

		private static readonly MethodInfo WorldToMapPointMethod = AccessTools.Method(typeof(Minimap), "WorldToMapPoint", (Type[])null, (Type[])null);

		private static readonly FieldInfo PlayerLoadingField = AccessTools.Field(typeof(Player), "m_isLoading");

		private const int TextureResolution = 512;

		private static WorldPreGeneratorGridState remoteGridState;

		private Minimap minimap;

		private RawImage mapImage;

		private RawImage gridImage;

		private Texture2D gridTexture;

		private Color32[] pixels;

		private float nextRefresh;

		private bool lastEnabled;

		internal static void ApplyRemoteGrid(WorldPreGeneratorGridState state)
		{
			remoteGridState = state;
		}

		internal static void ClearRemoteGrid()
		{
			remoteGridState = null;
		}

		internal static void Attach(Minimap target)
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: 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_00c8: 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_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.ShowChunkGrid == null || !Plugin.ShowChunkGrid.Value || (!IsGridAuthorized() && (!WorldPreGeneratorNetwork.IsRemoteClient || WorldPreGeneratorNetwork.RemotePermissionKnown)) || !IsWorldReadyForUi() || (Object)(object)target == (Object)null || LargeMapImageField == null)
			{
				return;
			}
			object? value = LargeMapImageField.GetValue(target);
			RawImage val = (RawImage)((value is RawImage) ? value : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				MinimapGridOverlay minimapGridOverlay = ((Component)val).GetComponentInChildren<MinimapGridOverlay>(true);
				if (!Object.op_Implicit((Object)(object)minimapGridOverlay))
				{
					GameObject val2 = new GameObject("WorldPreGeneratorChunkGrid", new Type[2]
					{
						typeof(RectTransform),
						typeof(RawImage)
					});
					val2.transform.SetParent(((Component)val).transform, false);
					RectTransform val3 = (RectTransform)val2.transform;
					val3.anchorMin = Vector2.zero;
					val3.anchorMax = Vector2.one;
					val3.offsetMin = Vector2.zero;
					val3.offsetMax = Vector2.zero;
					RawImage component = val2.GetComponent<RawImage>();
					((Graphic)component).raycastTarget = false;
					((Graphic)component).color = Color.white;
					minimapGridOverlay = val2.AddComponent<MinimapGridOverlay>();
				}
				minimapGridOverlay.Initialize(target, val);
			}
		}

		internal static void SetEnabled(bool enabled)
		{
			Minimap instance = Minimap.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				enabled = enabled && IsGridAuthorized();
				Attach(instance);
				object? obj = LargeMapImageField?.GetValue(instance);
				RawImage val = (RawImage)((obj is RawImage) ? obj : null);
				(Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponentInChildren<MinimapGridOverlay>(true) : null)?.SetGridEnabled(enabled);
			}
		}

		private void Initialize(Minimap target, RawImage image)
		{
			minimap = target;
			mapImage = image;
			if (!Object.op_Implicit((Object)(object)gridImage))
			{
				gridImage = ((Component)this).GetComponent<RawImage>();
			}
			EnsureTexture();
			SetGridEnabled(Plugin.ShowChunkGrid != null && Plugin.ShowChunkGrid.Value && IsGridAuthorized());
		}

		private void EnsureTexture()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)gridTexture) || pixels == null || pixels.Length != 262144)
			{
				if (Object.op_Implicit((Object)(object)gridTexture))
				{
					Object.Destroy((Object)(object)gridTexture);
				}
				gridTexture = new Texture2D(512, 512, (TextureFormat)4, false, true)
				{
					name = "WorldPreGeneratorChunkGridTexture",
					filterMode = (FilterMode)0,
					wrapMode = (TextureWrapMode)1
				};
				pixels = (Color32[])(object)new Color32[262144];
				gridTexture.SetPixels32(pixels);
				gridTexture.Apply(false, false);
				if (Object.op_Implicit((Object)(object)gridImage))
				{
					gridImage.texture = (Texture)(object)gridTexture;
				}
			}
		}

		private void SetGridEnabled(bool enabled)
		{
			lastEnabled = enabled;
			if (!Object.op_Implicit((Object)(object)gridImage))
			{
				gridImage = ((Component)this).GetComponent<RawImage>();
			}
			if (!enabled)
			{
				if (Object.op_Implicit((Object)(object)gridImage))
				{
					((Behaviour)gridImage).enabled = false;
				}
				return;
			}
			if (Object.op_Implicit((Object)(object)gridImage))
			{
				((Behaviour)gridImage).enabled = Minimap.IsOpen();
			}
			nextRefresh = 0f;
		}

		private void Update()
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)minimap) || !Object.op_Implicit((Object)(object)mapImage))
			{
				Minimap instance = Minimap.instance;
				if ((Object)(object)instance != (Object)null)
				{
					Attach(instance);
				}
				return;
			}
			bool flag = IsGridAuthorized() && Plugin.ShowChunkGrid != null && Plugin.ShowChunkGrid.Value;
			if (flag != lastEnabled)
			{
				SetGridEnabled(flag);
			}
			if (flag && !IsWorldReadyForUi())
			{
				if (Object.op_Implicit((Object)(object)gridImage))
				{
					((Behaviour)gridImage).enabled = false;
				}
				return;
			}
			bool flag2 = Minimap.IsOpen();
			if (Object.op_Implicit((Object)(object)gridImage))
			{
				((Behaviour)gridImage).enabled = flag && flag2;
			}
			if (WorldPreGeneratorNetwork.IsRemoteClient && flag2 && !WorldPreGeneratorNetwork.RemotePermissionKnown && Time.realtimeSinceStartup >= nextRefresh)
			{
				nextRefresh = Time.realtimeSinceStartup + 5f;
				WorldPreGeneratorNetwork.RequestStatus();
			}
			if (!flag || !flag2)
			{
				return;
			}
			if (Object.op_Implicit((Object)(object)gridImage) && gridImage.uvRect != mapImage.uvRect)
			{
				gridImage.uvRect = mapImage.uvRect;
			}
			float realtimeSinceStartup = Time.realtimeSinceStartup;
			if (!(realtimeSinceStartup < nextRefresh))
			{
				nextRefresh = realtimeSinceStartup + 5f;
				if (WorldPreGeneratorNetwork.IsRemoteClient)
				{
					WorldPreGeneratorNetwork.RequestGrid();
				}
				RefreshGrid();
			}
		}

		internal static bool IsWorldReadyForUi()
		{
			try
			{
				return (Object)(object)ZNet.instance != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)ZoneSystem.instance != (Object)null && !IsPlayerLoading(Player.m_localPlayer);
			}
			catch
			{
				return false;
			}
		}

		private static bool IsGridAuthorized()
		{
			try
			{
				return WorldPreGeneratorUi.IsGridAuthorized();
			}
			catch
			{
				return false;
			}
		}

		private static bool IsPlayerLoading(Player player)
		{
			if ((Object)(object)player == (Object)null || PlayerLoadingField == null)
			{
				return false;
			}
			try
			{
				object value = PlayerLoadingField.GetValue(player);
				bool flag = default(bool);
				int num;
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
			catch
			{
				return false;
			}
		}

		private void RefreshGrid()
		{
			//IL_033f: Unknown result type (might be due to invalid IL or missing references)
			//IL_034a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e0: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)minimap) || !Object.op_Implicit((Object)(object)gridImage) || !Object.op_Implicit((Object)(object)gridTexture) || pixels == null)
			{
				return;
			}
			ZoneSystem instance = ZoneSystem.instance;
			if ((Object)(object)instance == (Object)null)
			{
				ClearTexture();
				return;
			}
			EnsureTexture();
			Array.Clear(pixels, 0, pixels.Length);
			float zoneSize = WorldPreGeneratorController.GetZoneSize();
			float worldRadius = WorldPreGeneratorController.GetWorldRadius();
			if (!TryCreateProjection(minimap, zoneSize, out var projection))
			{
				ClearTexture();
				return;
			}
			int num = Mathf.CeilToInt(worldRadius / zoneSize) + 1;
			float num2 = worldRadius * worldRadius;
			Vector3 val = default(Vector3);
			for (int i = -num; i <= num; i++)
			{
				for (int j = -num; j <= num; j++)
				{
					((Vector3)(ref val))..ctor(((float)i + 0.5f) * zoneSize, 0f, ((float)j + 0.5f) * zoneSize);
					if (val.x * val.x + val.z * val.z > num2)
					{
						continue;
					}
					bool flag = IsExploredAt(minimap, val);
					bool flag2 = (WorldPreGeneratorNetwork.IsRemoteClient ? IsRemoteZoneGenerated(i, j) : WorldPreGeneratorController.IsZoneGeneratedForOverlay(instance, new Vector2s(i, j)));
					Vector2 val2 = projection.MapPoint(new Vector3((float)i * zoneSize, 0f, (float)j * zoneSize));
					Vector2 val3 = projection.MapPoint(new Vector3((float)(i + 1) * zoneSize, 0f, (float)(j + 1) * zoneSize));
					int num3 = Mathf.Clamp(Mathf.FloorToInt(Mathf.Min(val2.x, val3.x) * 511f), 0, 511);
					int num4 = Mathf.Clamp(Mathf.CeilToInt(Mathf.Max(val2.x, val3.x) * 511f), 0, 511);
					int num5 = Mathf.Clamp(Mathf.FloorToInt(Mathf.Min(val2.y, val3.y) * 511f), 0, 511);
					int num6 = Mathf.Clamp(Mathf.CeilToInt(Mathf.Max(val2.y, val3.y) * 511f), 0, 511);
					if (num4 < num3 || num6 < num5)
					{
						continue;
					}
					Color32 val4 = (flag2 ? new Color32((byte)72, (byte)190, (byte)96, (byte)(flag ? 58 : 42)) : new Color32((byte)232, (byte)190, (byte)48, (byte)(flag ? 66 : 22)));
					Color32 val5 = (flag2 ? new Color32((byte)116, (byte)236, (byte)132, (byte)(flag ? 205 : 165)) : new Color32(byte.MaxValue, (byte)224, (byte)76, (byte)(flag ? 225 : 165)));
					for (int k = num5; k <= num6; k++)
					{
						for (int l = num3; l <= num4; l++)
						{
							bool flag3 = l == num3 || l == num4 || k == num5 || k == num6;
							pixels[k * 512 + l] = (flag3 ? val5 : val4);
						}
					}
				}
			}
			gridTexture.SetPixels32(pixels);
			gridTexture.Apply(false, false);
			if (gridImage.uvRect != mapImage.uvRect)
			{
				gridImage.uvRect = mapImage.uvRect;
			}
		}

		private static bool IsRemoteZoneGenerated(int x, int y)
		{
			WorldPreGeneratorGridState worldPreGeneratorGridState = remoteGridState;
			if (worldPreGeneratorGridState == null || !worldPreGeneratorGridState.CanManage || worldPreGeneratorGridState.GeneratedBits == null || worldPreGeneratorGridState.MaxZone < 0)
			{
				return false;
			}
			if (!string.Equals(worldPreGeneratorGridState.WorldName, ((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetWorldName() : string.Empty, StringComparison.Ordinal))
			{
				return false;
			}
			if (x < -worldPreGeneratorGridState.MaxZone || x > worldPreGeneratorGridState.MaxZone || y < -worldPreGeneratorGridState.MaxZone || y > worldPreGeneratorGridState.MaxZone)
			{
				return false;
			}
			int num = worldPreGeneratorGridState.MaxZone * 2 + 1;
			int num2 = (x + worldPreGeneratorGridState.MaxZone) * num + (y + worldPreGeneratorGridState.MaxZone);
			int num3 = num2 >> 3;
			if (num3 >= 0 && num3 < worldPreGeneratorGridState.GeneratedBits.Length)
			{
				return (worldPreGeneratorGridState.GeneratedBits[num3] & (1 << (num2 & 7))) != 0;
			}
			return false;
		}

		private void ClearTexture()
		{
			if (!((Object)(object)gridTexture == (Object)null) && pixels != null)
			{
				Array.Clear(pixels, 0, pixels.Length);
				gridTexture.SetPixels32(pixels);
				gridTexture.Apply(false, false);
			}
		}

		internal static bool IsExploredAt(Minimap target, Vector3 world)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (IsExploredMethod == null)
			{
				return false;
			}
			try
			{
				object obj = IsExploredMethod.Invoke(target, new object[1] { world });
				bool flag = default(bool);
				int num;
				if (obj is bool)
				{
					flag = (bool)obj;
					num = 1;
				}
				else
				{
					num = 0;
				}
				return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
			}
			catch
			{
				return false;
			}
		}

		private static bool TryCreateProjection(Minimap target, float step, out MapProjection projection)
		{
			//IL_0017: 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_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: 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_006e: 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_0070: 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)
			projection = default(MapProjection);
			if (WorldToMapPointMethod == null)
			{
				return false;
			}
			if (!TryWorldToMapPoint(target, Vector3.zero, out var point))
			{
				return false;
			}
			if (!TryWorldToMapPoint(target, new Vector3(step, 0f, 0f), out var point2))
			{
				return false;
			}
			if (!TryWorldToMapPoint(target, new Vector3(0f, 0f, step), out var point3))
			{
				return false;
			}
			projection = new MapProjection(point, (point2 - point) / step, (point3 - point) / step);
			return true;
		}

		private static bool TryWorldToMapPoint(Minimap target, Vector3 world, out Vector2 point)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			point = Vector2.zero;
			try
			{
				object[] array = new object[3] { world, 0f, 0f };
				WorldToMapPointMethod.Invoke(target, array);
				point = new Vector2(Convert.ToSingle(array[1], CultureInfo.InvariantCulture), Convert.ToSingle(array[2], CultureInfo.InvariantCulture));
				return !float.IsNaN(point.x) && !float.IsInfinity(point.x) && !float.IsNaN(point.y) && !float.IsInfinity(point.y);
			}
			catch
			{
				return false;
			}
		}

		private void OnDestroy()
		{
			if (Object.op_Implicit((Object)(object)gridTexture))
			{
				Object.Destroy((Object)(object)gridTexture);
			}
			gridTexture = null;
			pixels = null;
		}
	}
	internal static class WorldPreGeneratorUi
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static UnityAction <0>__OpenModal;
		}

		private static Button menuButton;

		private static WorldPreGeneratorModal modal;

		private static TMP_FontAsset fallbackFont;

		internal static void Attach(Menu menu)
		{
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			if ((Object)(object)menu == (Object)null)
			{
				return;
			}
			if (!Plugin.ShowMenuButton.Value)
			{
				if (Object.op_Implicit((Object)(object)menuButton))
				{
					Object.Destroy((Object)(object)((Component)menuButton).gameObject);
				}
				menuButton = null;
				return;
			}
			if (Object.op_Implicit((Object)(object)menuButton))
			{
				((Component)menuButton).gameObject.SetActive(true);
				return;
			}
			object? obj = MenuFields.SaveButton?.GetValue(menu);
			Button val = (Button)((obj is Button) ? obj : null);
			Transform val2 = (Transform)(Object.op_Implicit((Object)(object)val) ? ((object)((Component)val).transform.parent) : ((object)/*isinst with value type is only supported in some contexts*/));
			if (Object.op_Implicit((Object)(object)val2))
			{
				GameObject val3;
				if (Object.op_Implicit((Object)(object)val))
				{
					val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, val2, false);
					((Object)val3).name = "WorldPreGeneratorButton";
				}
				else
				{
					val3 = CreateButtonObject(val2, FindSample(menu), Translations.Text("Menu"), new Vector2(0f, 0f));
				}
				menuButton = val3.GetComponent<Button>() ?? val3.AddComponent<Button>();
				((UnityEventBase)menuButton.onClick).RemoveAllListeners();
				ButtonClickedEvent onClick = menuButton.onClick;
				object obj2 = <>O.<0>__OpenModal;
				if (obj2 == null)
				{
					UnityAction val4 = OpenModal;
					<>O.<0>__OpenModal = val4;
					obj2 = (object)val4;
				}
				((UnityEvent)onClick).AddListener((UnityAction)obj2);
				((Selectable)menuButton).interactable = true;
				TMP_Text componentInChildren = val3.GetComponentInChildren<TMP_Text>(true);
				if (Object.op_Implicit((Object)(object)componentInChildren))
				{
					componentInChildren.text = Translations.Text("Menu");
				}
				if (Object.op_Implicit((Object)(object)val))
				{
					val3.transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex() + 1);
				}
			}
		}

		private static TMP_Text FindSample(Menu menu)
		{
			if (!Object.op_Implicit((Object)(object)menu))
			{
				return null;
			}
			TMP_Text[] componentsInChildren = ((Component)menu).GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)componentsInChildren[i]) && Object.op_Implicit((Object)(object)componentsInChildren[i].font))
				{
					return componentsInChildren[i];
				}
			}
			if (componentsInChildren.Length == 0)
			{
				return null;
			}
			return componentsInChildren[0];
		}

		private static GameObject CreateButtonObject(Transform parent, TMP_Text sample, string text, Vector2 size)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("WorldPreGeneratorButton", new Type[3]
			{
				typeof(RectTransform),
				typeof(Image),
				typeof(Button)
			});
			val.transform.SetParent(parent, false);
			((RectTransform)val.transform).sizeDelta = (Vector2)((size == Vector2.zero) ? new Vector2(300f, 42f) : size);
			((Graphic)val.GetComponent<Image>()).color = new Color(0.19f, 0.16f, 0.11f, 0.95f);
			((TMP_Text)CreateLabel("Label", val.transform, sample, 18f, (TextAlignmentOptions)514)).text = text;
			return val;
		}

		internal static void OpenModal()
		{
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Menu instance = Menu.instance;
				Transform val = (Transform)(Object.op_Implicit((Object)(object)instance) ? /*isinst with value type is only supported in some contexts*/: null);
				if (Object.op_Implicit((Object)(object)val))
				{
					if (!Object.op_Implicit((Object)(object)modal))
					{
						GameObject val2 = new GameObject("WorldPreGeneratorModal", new Type[1] { typeof(RectTransform) });
						val2.transform.SetParent(val, false);
						modal = val2.AddComponent<WorldPreGeneratorModal>();
						modal.Initialize(FindSample(instance));
					}
					((Component)modal).gameObject.SetActive(true);
					modal.RefreshFromController();
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		internal static void HideModal()
		{
			if (Object.op_Implicit((Object)(object)modal))
			{
				((Component)modal).gameObject.SetActive(false);
			}
		}

		internal static void DestroyModal()
		{
			if (Object.op_Implicit((Object)(object)modal))
			{
				Object.Destroy((Object)(object)((Component)modal).gameObject);
			}
			modal = null;
		}

		internal static void RefreshLanguage()
		{
			if (Object.op_Implicit((Object)(object)menuButton))
			{
				TMP_Text componentInChildren = ((Component)menuButton).GetComponentInChildren<TMP_Text>(true);
				if (Object.op_Implicit((Object)(object)componentInChildren))
				{
					componentInChildren.text = Translations.Text("Menu");
				}
			}
			modal?.RefreshLanguage();
		}

		internal static void ApplyRemoteState(WorldPreGeneratorRemoteState state)
		{
			modal?.ApplyRemoteState(state);
		}

		internal static void ApplyRemoteGrid(WorldPreGeneratorGridState state)
		{
			if ((Object)(object)modal != (Object)null && state != null)
			{
				modal.SetRemoteGridAccess(state.CanManage);
			}
		}

		internal static bool IsGridAuthorized()
		{
			try
			{
				if ((Object)(object)modal != (Object)null)
				{
					return modal.CanManageGridForOverlay();
				}
				if (WorldPreGeneratorNetwork.IsRemoteClient)
				{
					return WorldPreGeneratorNetwork.RemoteCanManage;
				}
				return (Object)(object)Plugin.Controller != (Object)null && Plugin.Controller.CanCheck;
			}
			catch
			{
				return false;
			}
		}

		internal static void ClearRemoteState()
		{
			modal?.ClearRemoteState();
		}

		internal static TextMeshProUGUI CreateLabel(string name, Transform parent, TMP_Text sample, float size, TextAlignmentOptions alignment)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[2]
			{
				typeof(RectTransform),
				typeof(TextMeshProUGUI)
			});
			val.transform.SetParent(parent, false);
			TextMeshProUGUI component = val.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component).font = ResolveFont(sample);
			((TMP_Text)component).fontSize = size;
			((TMP_Text)component).alignment = alignment;
			((TMP_Text)component).richText = false;
			((Graphic)component).raycastTarget = false;
			((Graphic)component).color = Color.white;
			Stretch((RectTransform)val.transform);
			return component;
		}

		internal static TMP_FontAsset ResolveFont(TMP_Text sample)
		{
			if (Object.op_Implicit((Object)(object)sample) && Object.op_Implicit((Object)(object)sample.font))
			{
				return sample.font;
			}
			if (Object.op_Implicit((Object)(object)fallbackFont))
			{
				return fallbackFont;
			}
			TMP_FontAsset val = null;
			TMP_FontAsset val2 = null;
			TMP_FontAsset[] array = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();
			foreach (TMP_FontAsset val3 in array)
			{
				if (Object.op_Implicit((Object)(object)val3))
				{
					if ((Object)(object)val == (Object)null)
					{
						val = val3;
					}
					string text = ((Object)val3).name ?? string.Empty;
					if (text.IndexOf("Valheim-Averia", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						val2 = val3;
						break;
					}
					if ((Object)(object)val2 == (Object)null && text.IndexOf("Valheim", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						val2 = val3;
					}
					if ((Object)(object)val2 == (Object)null && text.IndexOf("Norse", StringComparison.OrdinalIgnoreCase) >= 0)
					{
						val2 = val3;
					}
				}
			}
			if ((Object)(object)val2 == (Object)null)
			{
				string[] array2 = new string[4] { "Valheim-AveriaSerifLibre SDF", "Valheim-Norse SDF", "NorseBold SDF", "Fonts/Valheim-AveriaSerifLibre SDF" };
				for (int j = 0; j < array2.Length; j++)
				{
					if (!((Object)(object)val2 == (Object)null))
					{
						break;
					}
					val2 = Resources.Load<TMP_FontAsset>(array2[j]);
				}
			}
			fallbackFont = val2 ?? TMP_Settings.defaultFontAsset ?? val;
			return fallbackFont;
		}

		internal static void Stretch(RectTransform rect, float left = 0f, float right = 0f, float bottom = 0f, float top = 0f)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			rect.anchorMin = Vector2.zero;
			rect.anchorMax = Vector2.one;
			rect.offsetMin = new Vector2(left, bottom);
			rect.offsetMax = new Vector2(0f - right, 0f - top);
		}
	}
	public sealed class WorldPreGeneratorController : MonoBehaviour
	{
		private static readonly MethodInfo IsZoneGeneratedMethod = AccessTools.Method(typeof(ZoneSystem), "IsZoneGenerated", (Type[])null, (Type[])null);

		private static readonly MethodInfo SpawnZoneMethod = AccessTools.Method(typeof(ZoneSystem), "SpawnZone", (Type[])null, (Type[])null);

		private static readonly MethodInfo SaveWorldMethod = AccessTools.Method(typeof(ZNet), "SaveWorld", (Type[])null, (Type[])null);

		private readonly List<Vector2s> targetZones = new List<Vector2s>();

		private readonly Dictionary<Vector2s, int> attempts = new Dictionary<Vector2s, int>();

		private readonly HashSet<Vector2s> countedGenerated = new HashSet<Vector2s>();

		private Coroutine checkRoutine;

		private Coroutine generationRoutine;

		private WorldPreGeneratorModal activeModal;

		private bool checking;

		private bool generating;

		private int total;

		private int generated;

		private int missing;

		private int processed;

		private int failed;

		private int skipped;

		private int sinceSave;

		private int generatedDuringRun;

		private float generationStartedAt;

		private float nextProgressUiUpdate;

		private string status = Translations.Text("Ready");

		private string activeWorldName;

		private bool worldExitHandled;

		internal static bool SuppressAchievementEvents { get; private set; }

		public bool IsChecking => checking;

		public bool IsGenerating => generating;

		public int Total => total;

		public int Missing => missing;

		public int Generated => generated;

		public int Processed => processed;

		public int Failed => failed;

		public string Status => status;

		public string ActiveWorldName => activeWorldName ?? string.Empty;

		public bool CanCheck => IsHostOrAdmin();

		public double EstimatedSecondsRemaining
		{
			get
			{
				if (!generating || generatedDuringRun <= 0 || missing <= 0)
				{
					return -1.0;
				}
				float num = Math.Max(0.001f, Time.realtimeSinceStartup - generationStartedAt);
				return Math.Max(0.0, num / (float)generatedDuringRun * (float)missing);
			}
		}

		internal void AttachModal(WorldPreGeneratorModal modal)
		{
			if ((Object)(object)modal != (Object)null)
			{
				activeModal = modal;
			}
		}

		internal void BeginCheck(WorldPreGeneratorModal modal, bool fullWorld, float radius)
		{
			if (checking || checkRoutine != null)
			{
				return;
			}
			if ((Object)(object)modal != (Object)null)
			{
				activeModal = modal;
			}
			if (WorldPreGeneratorNetwork.IsRemoteClient)
			{
				if (!CanCheck)
				{
					status = Translations.Text("StatusNeedAdmin");
					modal?.SetStatus(status);
				}
				else
				{
					WorldPreGeneratorNetwork.RequestCheck(fullWorld, radius);
					modal?.SetStatus(Translations.Text("StatusRequestingServer"));
				}
			}
			else if (!EnsureWorldContext())
			{
				status = Translations.Text("StatusCheckWorld");
				modal?.SetStatus(status);
			}
			else if (!CanCheck)
			{
				status = Translations.Text("StatusNeedAdmin");
				modal?.SetStatus(status);
			}
			else
			{
				if (checkRoutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(checkRoutine);
				}
				checkRoutine = ((MonoBehaviour)this).StartCoroutine(CheckCoroutine(fullWorld ? GetWorldRadius() : radius));
			}
		}

		internal void BeginGeneration(WorldPreGeneratorModal modal, bool fullWorld, float radius)
		{
			if (checking || generating || generationRoutine != null)
			{
				modal?.SetStatus(Translations.Text("StatusAlreadyRunning"));
				return;
			}
			if ((Object)(object)modal != (Object)null)
			{
				activeModal = modal;
			}
			if (WorldPreGeneratorNetwork.IsRemoteClient)
			{
				if (!CanCheck)
				{
					status = Translations.Text("StatusNeedAdmin");
					modal?.SetStatus(status);
				}
				else
				{
					WorldPreGeneratorNetwork.RequestStart(fullWorld, radius);
					modal?.SetStatus(Translations.Text("StatusRequestingServer"));
				}
			}
			else if (!EnsureWorldContext())
			{
				status = Translations.Text("StatusCheckWorld");
				modal?.SetStatus(status);
			}
			else if (!IsHost())
			{
				status = Translations.Text("StatusNeedHost");
				modal?.SetStatus(status);
			}
			else
			{
				generationRoutine = ((MonoBehaviour)this).StartCoroutine(GenerationCoroutine(fullWorld ? GetWorldRadius() : radius));
			}
		}

		internal void CancelGeneration()
		{
			if (WorldPreGeneratorNetwork.IsRemoteClient)
			{
				WorldPreGeneratorNetwork.RequestCancel();
			}
			else
			{
				CancelGeneration(saveWorld: true);
			}
		}

		internal void CancelForServerShutdown()
		{
			if (generating || checking)
			{
				Plugin.WriteInfo("Servidor encerrando; cancelando a pré-geração e preservando o progresso salvo.");
				HandleWorldExit(saveWorld: false);
			}
		}

		private void CancelGeneration(bool saveWorld)
		{
			if (generating)
			{
				if (generationRoutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(generationRoutine);
				}
				generationRoutine = null;
				generating = false;
				if (saveWorld)
				{
					SaveWorld();
				}
				status = Translations.Text("StatusCancel");
				activeModal?.SetStatus(status);
				activeModal?.RefreshFromController();
				if (saveWorld)
				{
					WorldPreGeneratorNetwork.PublishState();
				}
			}
		}

		internal void HandleWorldExit(bool saveWorld = true)
		{
			WorldPreGeneratorNetwork.ClearRemoteState();
			if (!worldExitHandled || generating || checking || !((Object)(object)activeModal == (Object)null) || !string.IsNullOrEmpty(activeWorldName))
			{
				worldExitHandled = true;
				if (generating)
				{
					CancelGeneration(saveWorld);
				}
				else if (generationRoutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(generationRoutine);
					generationRoutine = null;
				}
				if (checking && checkRoutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(checkRoutine);
				}
				checkRoutine = null;
				checking = false;
				generating = false;
				ResetWorldState();
				activeModal?.ResetForWorld();
				activeModal = null;
				activeWorldName = null;
			}
		}

		private void ResetWorldState()
		{
			targetZones.Clear();
			attempts.Clear();
			countedGenerated.Clear();
			total = 0;
			generated = 0;
			missing = 0;
			processed = 0;
			failed = 0;
			skipped = 0;
			sinceSave = 0;
			generatedDuringRun = 0;
			generationStartedAt = 0f;
			nextProgressUiUpdate = 0f;
			status = Translations.Text("Ready");
		}

		private bool EnsureWorldContext()
		{
			string currentWorldName = GetCurrentWorldName();
			if (string.IsNullOrEmpty(currentWorldName))
			{
				return false;
			}
			if (!string.IsNullOrEmpty(activeWorldName) && !string.Equals(activeWorldName, currentWorldName, StringComparison.Ordinal))
			{
				if (generating || checking)
				{
					HandleWorldExit(saveWorld: false);
					return false;
				}
				ResetWorldState();
			}
			activeWorldName = currentWorldName;
			worldExitHandled = false;
			return true;
		}

		private static string GetCurrentWorldName()
		{
			try
			{
				ZNet instance = ZNet.instance;
				return ((Object)(object)instance != (Object)null) ? (instance.GetWorldName() ?? string.Empty) : string.Empty;
			}
			catch
			{
				return string.Empty;
			}
		}

		private IEnumerator CheckCoroutine(float radius)
		{
			checking = true;
			status = Translations.Text("StatusWaiting");
			activeModal?.SetBusy(busy: true);
			activeModal?.SetStatus(status);
			bool runningGeneration = generating;
			ZoneSystem zones = ZoneSystem.instance;
			if ((Object)(object)zones == (Object)null)
			{
				FinishCheck(Translations.Text("StatusCheckWorld"));
				yield break;
			}
			if (!zones.LocationsGenerated)
			{
				zones.GenerateLocationsIfNeeded();
			}
			float waitStart = Time.realtimeSinceStartup;
			while (!zones.LocationsGenerated && Time.realtimeSinceStartup - waitStart < 120f)
			{
				activeModal?.SetStatus(Translations.Text("StatusPreparingLocations"));
				yield return null;
			}
			if (!zones.LocationsGenerated)
			{
				FinishCheck(Translations.Text("StatusCheckTimeout"));
				yield break;
			}
			List<Vector2s> checkZones = new List<Vector2s>();
			BuildZoneList(radius, checkZones);
			int checkTotal = checkZones.Count;
			int checkGenerated = 0;
			int checkMissing = 0;
			int checkProcessed = 0;
			for (int i = 0; i < checkZones.Count; i++)
			{
				if (IsZoneGenerated(zones, checkZones[i]))
				{
					checkGenerated++;
				}
				else
				{
					checkMissing++;
				}
				checkProcessed = i + 1;
				if (checkProcessed % 1000 == 0)
				{
					status = (runningGeneration ? Translations.Format("StatusCheckParallel", checkProcessed, checkTotal) : Translations.Text("StatusCheckProgress"));
					if (!runningGeneration)
					{
						total = checkTotal;
						generated = checkGenerated;
						missing = checkMissing;
						processed = checkProcessed;
						skipped = 0;
						failed = 0;
						activeModal?.SetCounts(total, generated, missing, processed, 0, 0);
					}
					else
					{
						activeModal?.SetStatus(status);
					}
					yield return null;
				}
			}
			if (runningGeneration)
			{
				checking = false;
				checkRoutine = null;
				bool flag = generating;
				string text = ((checkMissing == 0) ? Translations.Text("StatusCheckAll") : (flag ? Translations.Format("StatusCheckMissingRunning", checkMissing) : Translations.Format("StatusCheckMissing", checkMissing)));
				activeModal?.SetBusy(flag);
				activeModal?.SetStatus(text);
				if (!generating)
				{
					activeModal = null;
				}
			}
			else
			{
				total = checkTotal;
				generated = checkGenerated;
				missing = checkMissing;
				processed = checkProcessed;
				skipped = 0;
				failed = 0;
				FinishCheck((missing == 0) ? Translations.Text("StatusCheckAll") : Translations.Text("StatusCheckWaitingGeneration"));
			}
		}

		private IEnumerator GenerationCoroutine(float radius)
		{
			generating = true;
			checking = false;
			status = Translations.Text("StatusPrepareList");
			activeModal?.SetBusy(busy: true);
			activeModal?.SetStatus(status);
			ZoneSystem zones = ZoneSystem.instance;
			if ((Object)(object)zones == (Object)null)
			{
				FinishGeneration(Translations.Text("StatusCheckWorld"));
				yield break;
			}
			if (!zones.LocationsGenerated)
			{
				zones.GenerateLocationsIfNeeded();
			}
			while (!zones.LocationsGenerated)
			{
				status = Translations.Text("StatusPreparingLocations");
				activeModal?.SetStatus(status);
				yield return null;
			}
			targetZones.Clear();
			BuildZoneList(radius, targetZones);
			total = targetZones.Count;
			generated = 0;
			missing = 0;
			processed = 0;
			failed = 0;
			skipped = 0;
			sinceSave = 0;
			attempts.Clear();
			countedGenerated.Clear();
			for (int i = 0; i < targetZones.Count; i++)
			{
				if (IsZoneGenerated(zones, targetZones[i]))
				{
					generated++;
					skipped++;
					countedGenerated.Add(targetZones[i]);
				}
				else
				{
					missing++;
				}
			}
			activeModal?.SetCounts(total, generated, missing, processed, skipped, failed);
			if (missing == 0)
			{
				FinishGeneration(Translations.Text("StatusAlreadyGenerated"));
				yield break;
			}
			status = Translations.Text("StatusGenerating");
			activeModal?.SetStatus(status);
			generatedDuringRun = 0;
			generationStartedAt = Time.realtimeSinceStartup;
			nextProgressUiUpdate = generationStartedAt;
			int index = 0;
			int batchSize = Mathf.Clamp(Plugin.ZonesPerBatch.Value, 1, 64);
			int maxConcurrentRequests = Mathf.Clamp(Plugin.MaxConcurrentZoneRequests.Value, 1, 16);
			Queue<Vector2s> pendingZones = new Queue<Vector2s>();
			float maxMilliseconds = Math.Max(1f, Plugin.MaxMillisecondsPerFrame.Value);
			while (index < targetZones.Count || pendingZones.Count > 0)
			{
				if (!generating)
				{
					yield break;
				}
				if (!Object.op_Implicit((Object)(object)zones))
				{
					FinishGeneration(Translations.Text("StatusWorldClosed"));
					yield break;
				}
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				int num = 0;
				while ((index < targetZones.Count || pendingZones.Count > 0) && num < batchSize && (num <= 0 || !((Time.realtimeSinceStartup - realtimeSinceStartup) * 1000f >= maxMilliseconds)))
				{
					Vector2s val = ((pendingZones.Count < maxConcurrentRequests && index < targetZones.Count) ? targetZones[index++] : pendingZones.Dequeue());
					if (IsZoneGenerated(zones, val))
					{
						if (countedGenerated.Add(val))
						{
							generated++;
							if (missing > 0)
							{
								missing--;
							}
							generatedDuringRun++;
						}
						skipped++;
						processed++;
						attempts.Remove(val);
						continue;
					}
					bool flag = false;
					GameObject root;
					try
					{
						flag = SpawnZone(zones, val, out root);
					}
					catch (Exception ex)
					{
						root = null;
						Plugin.Warn($"Falha ao gerar a zona {val}: {ex.Message}");
					}
					if (Object.op_Implicit((Object)(object)root))
					{
						Object.Destroy((Object)(object)root);
					}
					if (flag || IsZoneGenerated(zones, val))
					{
						if (countedGenerated.Add(val))
						{
							generated++;
							missing = Math.Max(0, missing - 1);
							generatedDuringRun++;
						}
						processed++;
						attempts.Remove(val);
						sinceSave++;
					}
					else
					{
						int value;
						int num2 = ((!attempts.TryGetValue(val, out value)) ? 1 : (value + 1));
						if (num2 < 120)
						{
							attempts[val] = num2;
							pendingZones.Enqueue(val);
						}
						else
						{
							failed++;
							processed++;
							attempts.Remove(val);
						}
					}
					UpdateProgressUi();
					if (Plugin.SaveEveryZones.Value > 0 && sinceSave >= Plugin.SaveEveryZones.Value)
					{
						SaveWorld();
						sinceSave = 0;
					}
					num++;
				}
				UpdateProgressUi();
				float num3 = Plugin.BatchPauseSeconds.Value;
				if (float.IsNaN(num3) || num3 < 0f)
				{
					num3 = 0f;
				}
				if (num3 > 0f)
				{
					yield return (object)new WaitForSecondsRealtime(num3);
				}
				else
				{
					yield return null;
				}
			}
			SaveWorld();
			FinishGeneration((failed == 0) ? Translations.Text("StatusGenerationDone") : Translations.Format("StatusGenerationFailures", failed));
		}

		private void FinishCheck(string message)
		{
			checking = false;
			checkRoutine = null;
			status = message;
			activeModal?.SetBusy(busy: false);
			activeModal?.SetCounts(total, generated, missing, processed, skipped, failed);
			if (total > 0 && processed >= total)
			{
				activeModal?.SetCompleteProgress();
			}
			activeModal?.SetStatus(status);
			if (!generating)
			{
				activeModal = null;
			}
			WorldPreGeneratorNetwork.PublishState();
		}

		private void FinishGeneration(string message)
		{
			generating = false;
			generationRoutine = null;
			status = message;
			activeModal?.SetBusy(busy: false);
			activeModal?.SetCounts(total, generated, missing, processed, skipped, failed);
			activeModal?.SetCompleteProgress();
			activeModal?.SetStatus(status);
			if (!checking)
			{
				activeModal = null;
			}
			WorldPreGeneratorNetwork.PublishState();
		}

		private void SaveWorld()
		{
			try
			{
				if ((Object)(object)ZNet.instance != (Object)null && IsHost() && SaveWorldMethod != null)
				{
					SaveWorldMethod.Invoke(ZNet.instance, new object[1] { false });
				}
			}
			catch (Exception exception)
			{
				Plugin.Report(exception);
			}
		}

		private void UpdateProgressUi()
		{
			if (!((Object)(object)activeModal == (Object)null))
			{
				float realtimeSinceStartup = Time.realtimeSinceStartup;
				if (!(realtimeSinceStartup < nextProgressUiUpdate))
				{
					nextProgressUiUp