Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of WorldPreGenerator v1.0.14
BepInEx/plugins/WorldPreGenerator/WorldPreGenerator.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
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