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 RecipeGate v1.0.11
RecipeGate.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Reflection; using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Text; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: AssemblyFileVersion("1.0.11.0")] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyTitle("RecipeGate")] [assembly: AssemblyProduct("RecipeGate")] [assembly: AssemblyVersion("1.0.11.0")] namespace RecipeGate; public static class EnglishConfiguration { public static void Migrate(ConfigFile config, ManualLogSource logger) { if (config == null) { throw new ArgumentNullException("config"); } string configFilePath = config.ConfigFilePath; if (!File.Exists(configFilePath)) { return; } Dictionary<string, Dictionary<string, string>> sections = ReadEntries(configFilePath); bool flag = Move(sections, "Geral", "Ativo", "General", "Enabled"); flag = Move(sections, "Geral", "Log detalhado", "General", "Detailed logging") || flag; if (!Move(sections, "Servidor", "Sobrescricoes", "Server", "Overrides") && !flag) { return; } string text = configFilePath + ".before-english.bak"; if (File.Exists(text)) { text = configFilePath + ".before-english-" + Guid.NewGuid().ToString("N") + ".bak"; } string text2 = configFilePath + ".english-" + Guid.NewGuid().ToString("N") + ".tmp"; try { File.WriteAllText(text2, Serialize(sections), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); File.Replace(text2, configFilePath, text, ignoreMetadataErrors: true); config.Reload(); if (logger != null) { logger.LogInfo((object)("Migrated configuration to English. Original backup: " + text)); } } catch (Exception ex) { if (logger != null) { logger.LogError((object)("Could not migrate configuration to English; initialization stopped to protect existing settings. " + ex.Message)); } throw; } finally { try { if (File.Exists(text2)) { File.Delete(text2); } } catch { } } } private static Dictionary<string, Dictionary<string, string>> ReadEntries(string path) { Dictionary<string, Dictionary<string, string>> dictionary = new Dictionary<string, Dictionary<string, string>>(StringComparer.Ordinal); string key = ""; string[] array = File.ReadAllLines(path); foreach (string text in array) { string text2 = text.Trim(); if (text2.Length == 0 || text2.StartsWith("#", StringComparison.Ordinal)) { continue; } if (text2.StartsWith("[", StringComparison.Ordinal) && text2.EndsWith("]", StringComparison.Ordinal)) { key = text2.Substring(1, text2.Length - 2); continue; } int num = text2.IndexOf('='); if (num < 0) { continue; } string text3 = text2.Substring(0, num).Trim(); if (text3.Length != 0) { if (!dictionary.TryGetValue(key, out var value)) { value = new Dictionary<string, string>(StringComparer.Ordinal); dictionary.Add(key, value); } value[text3] = text2.Substring(num + 1).Trim(); } } return dictionary; } private static bool Move(Dictionary<string, Dictionary<string, string>> sections, string oldSection, string oldKey, string newSection, string newKey) { if (!sections.TryGetValue(oldSection, out var value) || !value.TryGetValue(oldKey, out var value2)) { return false; } if (!sections.TryGetValue(newSection, out var value3)) { value3 = new Dictionary<string, string>(StringComparer.Ordinal); sections.Add(newSection, value3); } if (!value3.ContainsKey(newKey)) { value3.Add(newKey, value2); } value.Remove(oldKey); if (value.Count == 0) { sections.Remove(oldSection); } return true; } private static string Serialize(Dictionary<string, Dictionary<string, string>> sections) { StringBuilder stringBuilder = new StringBuilder(); List<string> list = new List<string>(sections.Keys); list.Sort(StringComparer.Ordinal); foreach (string item in list) { if (item.Length != 0) { stringBuilder.Append('[').Append(item).AppendLine("]"); } List<string> list2 = new List<string>(sections[item].Keys); list2.Sort(StringComparer.Ordinal); foreach (string item2 in list2) { stringBuilder.Append(item2).Append(" = ").AppendLine(sections[item][item2]); } stringBuilder.AppendLine(); } return stringBuilder.ToString(); } } internal static class PrefabNames { internal static string Get(GameObject value) { if ((Object)(object)value == (Object)null) { return string.Empty; } string text = ((Object)value).name ?? string.Empty; if (text.EndsWith("(Clone)", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "(Clone)".Length); } return text; } } public static class CacheNucleo { private const int Magica = 843269970; public const int Formato = 2; public const int MaxArquivo = 262144; private const int MaxTexto = 128; public static byte[] Montar(string versao, string assinatura, int quantas, byte[] bruto, int maxBruto, int maxComprimido) { if (string.IsNullOrEmpty(versao) || string.IsNullOrEmpty(assinatura) || quantas <= 0 || bruto == null || bruto.Length == 0 || bruto.Length > maxBruto) { throw new InvalidDataException("invalid cache data"); } byte[] array = RedeNucleo.Comprimir(bruto); if (array.Length == 0 || array.Length > maxComprimido) { throw new InvalidDataException("compressed cache exceeds the limit"); } using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream, Encoding.UTF8); binaryWriter.Write(843269970); binaryWriter.Write(2); EscreverTexto(binaryWriter, versao); EscreverTexto(binaryWriter, assinatura); binaryWriter.Write(quantas); binaryWriter.Write(bruto.Length); byte[] array2 = RedeNucleo.Hash(bruto); binaryWriter.Write(array2.Length); binaryWriter.Write(array2); binaryWriter.Write(array.Length); binaryWriter.Write(array); binaryWriter.Flush(); if (memoryStream.Length > 262144) { throw new InvalidDataException("cache file exceeds the limit"); } return memoryStream.ToArray(); } public static bool TentarLer(byte[] arquivo, string versaoEsperada, string assinaturaEsperada, int maxBruto, int maxComprimido, out int quantas, out byte[] bruto) { quantas = 0; bruto = null; if (arquivo == null || arquivo.Length == 0 || arquivo.Length > 262144 || string.IsNullOrEmpty(versaoEsperada) || string.IsNullOrEmpty(assinaturaEsperada)) { return false; } try { using MemoryStream memoryStream = new MemoryStream(arquivo, writable: false); using BinaryReader binaryReader = new BinaryReader(memoryStream, Encoding.UTF8); if (binaryReader.ReadInt32() != 843269970 || binaryReader.ReadInt32() != 2) { return false; } string text = LerTexto(binaryReader); string text2 = LerTexto(binaryReader); int num = binaryReader.ReadInt32(); int num2 = binaryReader.ReadInt32(); int num3 = binaryReader.ReadInt32(); if (text != versaoEsperada || text2 != assinaturaEsperada || num <= 0 || num > 100000 || num2 <= 0 || num2 > maxBruto || num3 != 32) { return false; } byte[] a = LerExato(binaryReader, num3); int num4 = binaryReader.ReadInt32(); if (num4 <= 0 || num4 > maxComprimido || num4 > memoryStream.Length - memoryStream.Position) { return false; } byte[] comprimido = LerExato(binaryReader, num4); if (memoryStream.Position != memoryStream.Length) { return false; } byte[] array = RedeNucleo.Descomprimir(comprimido, num2, maxBruto); if (!RedeNucleo.Iguais(a, RedeNucleo.Hash(array))) { return false; } quantas = num; bruto = array; return true; } catch { quantas = 0; bruto = null; return false; } } private static void EscreverTexto(BinaryWriter writer, string valor) { byte[] bytes = Encoding.UTF8.GetBytes(valor); if (bytes.Length == 0 || bytes.Length > 128) { throw new InvalidDataException("invalid cache header"); } writer.Write(bytes.Length); writer.Write(bytes); } private static string LerTexto(BinaryReader reader) { int num = reader.ReadInt32(); if (num <= 0 || num > 128) { throw new InvalidDataException("invalid cache header"); } return Encoding.UTF8.GetString(LerExato(reader, num)); } private static byte[] LerExato(BinaryReader reader, int tamanho) { byte[] array = reader.ReadBytes(tamanho); if (array.Length != tamanho) { throw new EndOfStreamException(); } return array; } } public static class EstadoCacheNucleo { private const string Cabecalho = "RGS1"; public static byte[] Montar(bool ligado, string overrides, string map) { if (map == null) { throw new ArgumentNullException("map"); } overrides = overrides ?? ""; string text = Convert.ToBase64String(Encoding.UTF8.GetBytes(overrides)); return Encoding.UTF8.GetBytes("RGS1\n" + (ligado ? "1" : "0") + "\n" + text + "\n" + map); } public static bool TentarLer(byte[] dados, int maxOverrides, out bool ligado, out string overrides, out string mapa) { ligado = true; overrides = ""; mapa = null; if (dados == null || dados.Length == 0) { return false; } try { string text = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetString(dados); int num = text.IndexOf('\n'); int num2 = ((num < 0) ? (-1) : text.IndexOf('\n', num + 1)); int num3 = ((num2 < 0) ? (-1) : text.IndexOf('\n', num2 + 1)); if (num < 0 || num2 < 0 || num3 < 0 || text.Substring(0, num) != "RGS1") { return false; } string text2 = text.Substring(num + 1, num2 - num - 1); if (text2 != "0" && text2 != "1") { return false; } byte[] array = Convert.FromBase64String(text.Substring(num2 + 1, num3 - num2 - 1)); if (array.Length > maxOverrides) { return false; } string text3 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetString(array); string text4 = text.Substring(num3 + 1); if (text4.Length == 0) { return false; } ligado = text2 == "1"; overrides = text3; mapa = text4; return true; } catch { ligado = true; overrides = ""; mapa = null; return false; } } } internal static class DumpSpawns { private class Bicho { public string Prefab; public List<string> Biomas = new List<string>(); public List<string> Chaves = new List<string>(); public List<string> Drops = new List<string>(); public int MenorTier = 99; public int MaiorTier = -1; } private static bool _feito; private static readonly Biome[] TierBiomes = (Biome[])(object)new Biome[8] { (Biome)1, (Biome)8, (Biome)2, (Biome)4, (Biome)16, (Biome)512, (Biome)32, (Biome)64 }; private static readonly string[] Nomes = new string[8] { "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands", "DeepNorth" }; internal static void Escrever(SpawnSystem sistema) { //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) if (_feito || (Object)(object)sistema == (Object)null || sistema.m_spawnLists == null) { return; } _feito = true; Dictionary<string, Bicho> dictionary = new Dictionary<string, Bicho>(StringComparer.OrdinalIgnoreCase); int num = 0; for (int i = 0; i < sistema.m_spawnLists.Count; i++) { SpawnSystemList val = sistema.m_spawnLists[i]; if ((Object)(object)val == (Object)null || val.m_spawners == null) { continue; } for (int j = 0; j < val.m_spawners.Count; j++) { SpawnData val2 = val.m_spawners[j]; if (val2 == null || (Object)(object)val2.m_prefab == (Object)null) { continue; } num++; string text = PrefabNames.Get(val2.m_prefab); if (!dictionary.TryGetValue(text, out var value)) { value = new Bicho(); value.Prefab = text; value.Drops = Drops(val2.m_prefab); dictionary[text] = value; } string text2 = ((!val2.m_enabled) ? " [disabled]" : "") + (val2.m_devDisabled ? " [devDisabled]" : ""); for (int k = 0; k < TierBiomes.Length; k++) { if ((val2.m_biome & TierBiomes[k]) == 0) { continue; } string item = Nomes[k] + text2; if (!value.Biomas.Contains(item)) { value.Biomas.Add(item); } if (val2.m_enabled && !val2.m_devDisabled) { if (k < value.MenorTier) { value.MenorTier = k; } if (k > value.MaiorTier) { value.MaiorTier = k; } } } if (!string.IsNullOrEmpty(val2.m_requiredGlobalKey)) { string requiredGlobalKey = val2.m_requiredGlobalKey; if (!value.Chaves.Contains(requiredGlobalKey)) { value.Chaves.Add(requiredGlobalKey); } } } } Salvar(dictionary, num); } private static string Ingredientes(ObjectDB db, GameObject produto) { if (db.m_recipes == null) { return "-"; } for (int i = 0; i < db.m_recipes.Count; i++) { Recipe val = db.m_recipes[i]; if ((Object)(object)val == (Object)null || (Object)(object)val.m_item == (Object)null || (Object)(object)((Component)val.m_item).gameObject != (Object)(object)produto) { continue; } if (val.m_resources == null) { return "-"; } List<string> list = new List<string>(); for (int j = 0; j < val.m_resources.Length; j++) { Requirement val2 = val.m_resources[j]; if (val2 != null && (Object)(object)val2.m_resItem != (Object)null) { list.Add(PrefabNames.Get(((Component)val2.m_resItem).gameObject)); } } if (list.Count <= 0) { return "-"; } return string.Join(" + ", list.ToArray()); } return "-"; } private static void DaTabela(List<string> saida, DropTable t) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (t != null && t.m_drops != null) { for (int i = 0; i < t.m_drops.Count; i++) { Junta(saida, t.m_drops[i].m_item); } } } private static void Junta(List<string> saida, GameObject item) { if (!((Object)(object)item == (Object)null)) { string text = PrefabNames.Get(item); if (!string.IsNullOrEmpty(text) && !saida.Contains(text)) { saida.Add(text); } } } private static List<string> Drops(GameObject prefab) { List<string> list = new List<string>(); CharacterDrop component = prefab.GetComponent<CharacterDrop>(); if ((Object)(object)component == (Object)null || component.m_drops == null) { return list; } for (int i = 0; i < component.m_drops.Count; i++) { Drop val = component.m_drops[i]; if (val != null && !((Object)(object)val.m_prefab == (Object)null)) { string item = PrefabNames.Get(val.m_prefab); if (!list.Contains(item)) { list.Add(item); } } } return list; } private static void Salvar(Dictionary<string, Bicho> bichos, int entradas) { try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# RecipeGate - spawn list read from the game"); stringBuilder.AppendLine("# generated at " + DateTime.Now.ToString("yyyy-MM-dd HH:mm")); stringBuilder.AppendLine("# source: SpawnSystem.m_spawnLists (the same list traversed by UpdateSpawning)"); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# " + bichos.Count + " creatures in " + entradas + " spawn entries"); stringBuilder.AppendLine(); List<Bicho> list = new List<Bicho>(bichos.Values); list.Sort((Bicho a, Bicho b) => (a.MenorTier == b.MenorTier) ? string.Compare(a.Prefab, b.Prefab, StringComparison.OrdinalIgnoreCase) : (a.MenorTier - b.MenorTier)); stringBuilder.AppendLine("## creatures in more than one tier (the lowest-tier rule may be misleading here)"); stringBuilder.AppendLine(); int num = 0; for (int num2 = 0; num2 < list.Count; num2++) { Bicho bicho = list[num2]; if (bicho.MaiorTier > bicho.MenorTier && bicho.MaiorTier >= 0) { num++; stringBuilder.AppendLine(" " + bicho.Prefab.PadRight(24) + Nomes[bicho.MenorTier] + " .. " + Nomes[bicho.MaiorTier]); stringBuilder.AppendLine(" biomes: " + string.Join(", ", bicho.Biomas.ToArray())); if (bicho.Chaves.Count > 0) { stringBuilder.AppendLine(" requires key: " + string.Join(", ", bicho.Chaves.ToArray())); } if (bicho.Drops.Count > 0) { stringBuilder.AppendLine(" drops: " + string.Join(", ", bicho.Drops.ToArray())); } } } if (num == 0) { stringBuilder.AppendLine(" (none)"); } stringBuilder.AppendLine(); stringBuilder.AppendLine("## all creatures"); stringBuilder.AppendLine(); for (int num3 = 0; num3 < list.Count; num3++) { Bicho bicho2 = list[num3]; string text = ((bicho2.MenorTier < Nomes.Length) ? Nomes[bicho2.MenorTier] : "-"); stringBuilder.AppendLine(" " + bicho2.Prefab.PadRight(24) + text); stringBuilder.AppendLine(" biomes: " + string.Join(", ", bicho2.Biomas.ToArray())); if (bicho2.Chaves.Count > 0) { stringBuilder.AppendLine(" requires key: " + string.Join(", ", bicho2.Chaves.ToArray())); } if (bicho2.Drops.Count > 0) { stringBuilder.AppendLine(" drops: " + string.Join(", ", bicho2.Drops.ToArray())); } } string text2 = RecipeGatePlugin.CaminhoDeRelatorio("spawns.txt"); File.WriteAllText(text2, stringBuilder.ToString()); RecipeGatePlugin.Log.LogInfo((object)("spawn dump written to " + text2 + " (" + bichos.Count + " creatures, " + num + " spanning tiers).")); } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("could not write the dump: " + ex.Message)); } } } [HarmonyPatch(typeof(SpawnSystem), "Awake")] internal static class SpawnSystemAwakeDumpPatch { private static void Postfix(SpawnSystem __instance) { try { if (RecipeGatePlugin.DumpSpawn != null && RecipeGatePlugin.DumpSpawn.Value) { DumpSpawns.Escrever(__instance); } } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("spawn dump failed: " + ex)); } } } public static class MapaWireNucleo { public const int MaxCaracteres = 4194304; public const int MaxEntradas = 100000; public static bool TentarLer(string texto, int contagemEsperada, out Dictionary<string, Resultado> mapa) { mapa = null; if (string.IsNullOrEmpty(texto) || texto.Length > 4194304) { return false; } Dictionary<string, Resultado> dictionary = new Dictionary<string, Resultado>(StringComparer.OrdinalIgnoreCase); string[] array = texto.Split(new char[1] { '\n' }); if (array.Length > 100001) { return false; } for (int i = 0; i < array.Length; i++) { string text = array[i].TrimEnd(new char[1] { '\r' }); if (text.Length != 0) { string[] array2 = text.Split(new char[1] { '\t' }); if (array2.Length != 4 || array2[0].Length == 0 || array2[0].Length > 256 || array2[2].Length > 256 || array2[3].Length > 512) { return false; } if (!int.TryParse(array2[1], out var result) || result < 0 || result >= MapaNucleo.ChavePorTier.Length || dictionary.ContainsKey(array2[0])) { return false; } dictionary[array2[0]] = new Resultado(result, array2[2], array2[3]); } } if (dictionary.Count == 0 || dictionary.Count > 100000 || (contagemEsperada >= 0 && dictionary.Count != contagemEsperada)) { return false; } mapa = dictionary; return true; } } internal static class Mapa { private const int MaxMapaCache = 4194304; private const int MaxComprimidoCache = 245760; private const int MaxOverridesCache = 32768; internal static Dictionary<string, Resultado> Derivado; internal static bool Pronto; private static readonly Biome[] TierBiomes = (Biome[])(object)new Biome[8] { (Biome)1, (Biome)8, (Biome)2, (Biome)4, (Biome)16, (Biome)512, (Biome)32, (Biome)64 }; private static SpawnSystem _sistema; private static string _assinaturaAtual; private static List<string> _marcosAnteriores; private static readonly List<string> Tempos = new List<string>(); private static readonly Dictionary<int, int> TierDoTema = new Dictionary<int, int>(); private static string[] _ignorar; private static readonly List<Fonte> Pisos = new List<Fonte>(); internal static int Desativados; private static Dictionary<string, string> _como; private static string _mecanismo; private static int TierDoBioma(Biome mask) { //IL_0004: 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) for (int i = 0; i < TierBiomes.Length; i++) { if ((mask & TierBiomes[i]) != 0) { return i; } } return 0; } private static string Nome(GameObject go) { if (!((Object)(object)go == (Object)null)) { return PrefabNames.Get(go); } return null; } internal static void RefazerSePreciso() { if (!Pronto && !((Object)(object)_sistema == (Object)null)) { Construir(_sistema); } } internal static void Esquecer() { Derivado = null; Pronto = false; _sistema = null; _assinaturaAtual = null; _ignorar = null; } internal static void Construir(SpawnSystem sistema) { _sistema = sistema; UsarBaseOficial(); _assinaturaAtual = "official-baseline-1.0.11-" + 837; RecipeGatePlugin.Log.LogInfo((object)("official policy ready: " + Derivado.Count + " items.")); Rede.PublicarMapaAtualizado(); } internal static bool UsarBaseOficial() { Derivado = BancoOficial.CriarMapa(); Pronto = Derivado != null && Derivado.Count == 837; return Pronto; } private static void Despejar(List<Receita> receitas, List<Ferramenta> ferramentas) { if (RecipeGatePlugin.DumpSpawn == null || !RecipeGatePlugin.DumpSpawn.Value) { return; } try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# RecipeGate - recipes as the formula detected them"); stringBuilder.AppendLine("# format: product | station level N | ingredient + ingredient"); stringBuilder.AppendLine(); List<string> list = new List<string>(); for (int i = 0; i < receitas.Count; i++) { Receita receita = receitas[i]; if (receita != null && !string.IsNullOrEmpty(receita.Produto)) { string text = (string.IsNullOrEmpty(receita.Estacao) ? "-" : receita.Estacao); if (receita.NivelEstacao > 1) { text = text + " level " + receita.NivelEstacao; } list.Add(" " + receita.Produto + " | " + text + " | " + string.Join(" + ", receita.Ingredientes.ToArray())); } } list.Sort(StringComparer.OrdinalIgnoreCase); for (int j = 0; j < list.Count; j++) { stringBuilder.AppendLine(list[j]); } File.WriteAllText(RecipeGatePlugin.CaminhoDeRelatorio("recipes.txt"), stringBuilder.ToString()); stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# RecipeGate - tools: level and damage dealt"); stringBuilder.AppendLine(); list.Clear(); for (int k = 0; k < ferramentas.Count; k++) { Ferramenta ferramenta = ferramentas[k]; if (ferramenta != null) { list.Add(" " + ferramenta.Prefab.PadRight(26) + " level " + ferramenta.Nivel + (ferramenta.Corta ? " chops" : "") + (ferramenta.Escava ? " mines" : "") + ((!ferramenta.Corta && !ferramenta.Escava) ? " (not usable as a tool)" : "")); } } list.Sort(StringComparer.OrdinalIgnoreCase); for (int l = 0; l < list.Count; l++) { stringBuilder.AppendLine(list[l]); } File.WriteAllText(RecipeGatePlugin.CaminhoDeRelatorio("tools.txt"), stringBuilder.ToString()); } catch (Exception ex) { RecipeGatePlugin.Log.LogWarning((object)("dump: " + ex.Message)); } } private static string CaminhoDoCache() { return Path.Combine(RecipeGatePlugin.DiretorioDoCache(), "map-v2.cache"); } private static string CaminhoDoCacheDoServidor(string chaveServidor) { if (string.IsNullOrEmpty(chaveServidor) || chaveServidor.Length > 64) { return null; } foreach (char c in chaveServidor) { if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) { return null; } } return Path.Combine(RecipeGatePlugin.DiretorioDoCache(), "server-" + chaveServidor + "-v1.cache"); } private static string Assinatura(SpawnSystem sistema) { //IL_059a: Unknown result type (might be due to invalid IL or missing references) //IL_05a4: Expected I4, but got Unknown //IL_0699: Unknown result type (might be due to invalid IL or missing references) //IL_06a3: Expected I4, but got Unknown ulong h = 14695981039346656037uL; List<string> list = new List<string>(); h = Mistura(h, VersaoDoJogo()); h = Mistura(h, "1.0.5"); try { h = Mistura(h, typeof(Mapa).Module.ModuleVersionId.ToString()); } catch { } List<string> list2 = new List<string>(); foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { list2.Add(pluginInfo.Key + "@" + ((pluginInfo.Value != null && pluginInfo.Value.Metadata != null) ? pluginInfo.Value.Metadata.Version.ToString() : "?")); } list2.Sort(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < list2.Count; i++) { h = Mistura(h, list2[i]); } list.Add("mods:" + h.ToString("x16")); ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance != (Object)null && instance.m_items != null) { h = Mistura(h, "items" + instance.m_items.Count); for (int j = 0; j < instance.m_items.Count; j++) { if ((Object)(object)instance.m_items[j] != (Object)null) { h = Mistura(h, ((Object)instance.m_items[j]).name); } } } list.Add("items:" + h.ToString("x16")); ZNetScene instance2 = ZNetScene.instance; if ((Object)(object)instance2 != (Object)null && instance2.m_prefabs != null) { h = Mistura(h, "prefabs" + instance2.m_prefabs.Count); for (int k = 0; k < instance2.m_prefabs.Count; k++) { if ((Object)(object)instance2.m_prefabs[k] != (Object)null) { h = Mistura(h, ((Object)instance2.m_prefabs[k]).name); } } } list.Add("prefabs:" + h.ToString("x16")); if ((Object)(object)instance != (Object)null && instance.m_recipes != null) { h = Mistura(h, "recipes" + instance.m_recipes.Count); for (int l = 0; l < instance.m_recipes.Count; l++) { Recipe val = instance.m_recipes[l]; if ((Object)(object)val == (Object)null || (Object)(object)val.m_item == (Object)null) { continue; } h = Mistura(h, ((Object)val.m_item).name + "|" + val.m_enabled + "|" + val.m_minStationLevel + "|" + val.m_requireOnlyOneIngredient + "|" + (((Object)(object)val.m_craftingStation == (Object)null) ? "" : ((Object)val.m_craftingStation).name)); if (val.m_resources == null) { continue; } for (int m = 0; m < val.m_resources.Length; m++) { Requirement val2 = val.m_resources[m]; if (val2 != null && (Object)(object)val2.m_resItem != (Object)null) { h = Mistura(h, ((Object)val2.m_resItem).name); } } } } list.Add("recipes:" + h.ToString("x16")); if ((Object)(object)instance != (Object)null && instance.m_items != null) { for (int n = 0; n < instance.m_items.Count; n++) { GameObject val3 = instance.m_items[n]; if (!((Object)(object)val3 == (Object)null)) { ItemDrop component = val3.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null) && component.m_itemData != null && component.m_itemData.m_shared != null && component.m_itemData.m_shared.m_toolTier > 0) { h = Mistura(h, "tool:" + ((Object)val3).name + ":" + component.m_itemData.m_shared.m_toolTier); } } } } list.Add("tools:" + h.ToString("x16")); ZoneSystem instance3 = ZoneSystem.instance; if ((Object)(object)instance3 != (Object)null && instance3.m_locations != null) { h = Mistura(h, "locations" + instance3.m_locations.Count); for (int num = 0; num < instance3.m_locations.Count; num++) { ZoneLocation val4 = instance3.m_locations[num]; if (val4 != null) { h = Mistura(h, val4.m_prefabName + "|" + val4.m_quantity + "|" + (int)val4.m_biome + "|" + val4.m_enable); } } } list.Add("locations:" + h.ToString("x16")); if ((Object)(object)sistema != (Object)null && sistema.m_spawnLists != null) { for (int num2 = 0; num2 < sistema.m_spawnLists.Count; num2++) { SpawnSystemList val5 = sistema.m_spawnLists[num2]; if ((Object)(object)val5 == (Object)null || val5.m_spawners == null) { continue; } for (int num3 = 0; num3 < val5.m_spawners.Count; num3++) { SpawnData val6 = val5.m_spawners[num3]; if (val6 != null && !((Object)(object)val6.m_prefab == (Object)null)) { h = Mistura(h, ((Object)val6.m_prefab).name + "|" + (int)val6.m_biome + "|" + val6.m_enabled + "|" + val6.m_requiredGlobalKey); } } } } list.Add("spawns:" + h.ToString("x16")); string[] array = ListaDeIgnorados(); for (int num4 = 0; num4 < array.Length; num4++) { h = Mistura(h, "ign:" + array[num4]); } list.Add("ignored:" + h.ToString("x16")); h = MisturaConfiguracoes(h); list.Add("configs:" + h.ToString("x16")); ConferirMarcos(list); return h.ToString("x16"); } private static void ConferirMarcos(List<string> marcos) { List<string> marcosAnteriores = _marcosAnteriores; _marcosAnteriores = marcos; if (marcosAnteriores == null) { return; } List<string> list = new List<string>(); for (int i = 0; i < marcos.Count && i < marcosAnteriores.Count; i++) { if (!(marcos[i] == marcosAnteriores[i])) { string item = marcos[i].Substring(0, marcos[i].IndexOf(':')); list.Add(item); } } if (list.Count != 0) { RecipeGatePlugin.Detalhe("signature changed starting at '" + list[0] + "' (propagated: " + string.Join(", ", list.ToArray()) + ")."); } } private static ulong MisturaConfiguracoes(ulong h) { try { string[] files = Directory.GetFiles(Paths.ConfigPath, "*", SearchOption.AllDirectories); Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase); for (int i = 0; i < files.Length; i++) { string extension = Path.GetExtension(files[i]); if (extension.Equals(".cfg", StringComparison.OrdinalIgnoreCase) || extension.Equals(".yml", StringComparison.OrdinalIgnoreCase) || extension.Equals(".yaml", StringComparison.OrdinalIgnoreCase)) { FileInfo fileInfo = new FileInfo(files[i]); string text = files[i].Substring(Paths.ConfigPath.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); h = Mistura(h, "cfg:" + text.Replace(Path.DirectorySeparatorChar, '/')); h = Mistura(h, fileInfo.Length.ToString()); } } } catch (Exception ex) { RecipeGatePlugin.Log.LogWarning((object)("could not check config timestamps; the cache may remain conservative (" + ex.Message + ").")); } return h; } private static string VersaoDoJogo() { try { Type type = AccessTools.TypeByName("Version"); if (type == null) { return "?"; } MethodInfo methodInfo = AccessTools.Method(type, "GetVersionString", (Type[])null, (Type[])null); if (methodInfo == null) { return "?"; } object obj = methodInfo.Invoke(null, null); return (obj == null) ? "?" : obj.ToString(); } catch { return "?"; } } private static ulong Mistura(ulong h, string texto) { if (texto == null) { texto = ""; } for (int i = 0; i < texto.Length; i++) { h ^= texto[i]; h *= 1099511628211L; } return h; } internal static string EmTexto() { if (Derivado == null) { return ""; } StringBuilder stringBuilder = new StringBuilder(Derivado.Count * 48); foreach (KeyValuePair<string, Resultado> item in Derivado) { stringBuilder.Append(item.Key).Append('\t').Append(item.Value.Tier) .Append('\t') .Append(item.Value.Origem ?? "") .Append('\t') .Append(item.Value.Onde ?? "") .Append('\n'); } return stringBuilder.ToString(); } internal static bool DeTexto(string texto) { return DeTexto(texto, -1); } internal static bool DeTexto(string texto, int contagemEsperada) { if (!MapaWireNucleo.TentarLer(texto, contagemEsperada, out var mapa)) { return false; } Derivado = mapa; Pronto = true; return true; } private static bool LerDoCache(string assinatura) { string text = CaminhoDoCache(); if (LerArquivoDoCache(text, assinatura)) { return true; } string caminho = text + ".bak"; if (LerArquivoDoCache(caminho, assinatura)) { RecipeGatePlugin.Detalhe("invalid primary cache; recovery copy accepted."); return true; } return false; } private static bool LerArquivoDoCache(string caminho, string assinatura) { try { if (!LerArquivoBruto(caminho, assinatura, 4194304, out var contagem, out var bruto)) { return false; } if (!DeTexto(Encoding.UTF8.GetString(bruto), contagem) || Derivado == null || Derivado.Count != contagem) { Derivado = null; Pronto = false; return false; } _ignorar = ListaDeIgnorados(); return true; } catch (Exception ex) { RecipeGatePlugin.Detalhe("cache ignored: " + ex.Message); return false; } } private static bool LerArquivoBruto(string caminho, string assinatura, int maxBruto, out int contagem, out byte[] bruto) { contagem = 0; bruto = null; if (string.IsNullOrEmpty(caminho)) { return false; } FileInfo fileInfo = new FileInfo(caminho); if (!fileInfo.Exists || fileInfo.Length <= 0 || fileInfo.Length > 262144) { return false; } return CacheNucleo.TentarLer(File.ReadAllBytes(caminho), "1.0.11", assinatura, maxBruto, 245760, out contagem, out bruto); } internal static bool CarregarUltimoMapaDoServidor(string chaveServidor, out bool ligado, out string overrides) { ligado = true; overrides = ""; string text = CaminhoDoCacheDoServidor(chaveServidor); if (text == null) { return false; } string assinatura = "server:" + chaveServidor; string[] array = new string[2] { text, text + ".bak" }; for (int i = 0; i < array.Length; i++) { try { if (LerArquivoBruto(array[i], assinatura, 4228096, out var contagem, out var bruto) && EstadoCacheNucleo.TentarLer(bruto, 32768, out var ligado2, out var overrides2, out var mapa) && DeTexto(mapa, contagem) && Derivado != null && Derivado.Count == contagem) { ligado = ligado2; overrides = overrides2; _ignorar = ListaDeIgnorados(); return true; } } catch (Exception ex) { RecipeGatePlugin.Detalhe("previous server state ignored: " + ex.Message); } } Derivado = null; Pronto = false; return false; } internal static void GravarMapaDoServidor(string chaveServidor, bool ligado, string overrides) { string text = CaminhoDoCacheDoServidor(chaveServidor); if (text != null && Derivado != null && Derivado.Count != 0) { byte[] bruto = EstadoCacheNucleo.Montar(ligado, overrides, EmTexto()); GravarArquivoCache(text, "server:" + chaveServidor, Derivado.Count, bruto, 4228096); } } private static void GravarCache(string assinatura) { if (Derivado != null && Derivado.Count != 0) { GravarArquivoCache(CaminhoDoCache(), assinatura, Derivado.Count, Encoding.UTF8.GetBytes(EmTexto()), 4194304); } } private static void GravarArquivoCache(string caminho, string assinatura, int contagem, byte[] bruto, int maxBruto) { string text = null; try { if (contagem <= 0 || bruto == null || bruto.Length <= 0) { return; } Directory.CreateDirectory(Path.GetDirectoryName(caminho)); byte[] array = CacheNucleo.Montar("1.0.11", assinatura, contagem, bruto, maxBruto, 245760); text = caminho + ".tmp-" + Process.GetCurrentProcess().Id + "-" + Guid.NewGuid().ToString("N"); using (FileStream fileStream = new FileStream(text, FileMode.CreateNew, FileAccess.Write, FileShare.None)) { fileStream.Write(array, 0, array.Length); fileStream.Flush(flushToDisk: true); } if (File.Exists(caminho)) { try { File.Replace(text, caminho, caminho + ".bak", ignoreMetadataErrors: true); text = null; return; } catch (PlatformNotSupportedException) { File.Copy(caminho, caminho + ".bak", overwrite: true); File.Copy(text, caminho, overwrite: true); return; } catch (IOException) { File.Copy(caminho, caminho + ".bak", overwrite: true); File.Copy(text, caminho, overwrite: true); return; } } File.Move(text, caminho); text = null; } catch (Exception ex3) { RecipeGatePlugin.Log.LogWarning((object)("cache not written: " + ex3.Message)); } finally { if (!string.IsNullOrEmpty(text) && File.Exists(text)) { try { File.Delete(text); } catch { } } } } private static void Tenta(string oQue, Action acao) { float realtimeSinceStartup = Time.realtimeSinceStartup; try { acao(); } catch (Exception ex) { RecipeGatePlugin.Log.LogWarning((object)(oQue + ": " + ex.Message)); } Tempos.Add(oQue + " " + ((Time.realtimeSinceStartup - realtimeSinceStartup) * 1000f).ToString("0") + "ms"); } private static void DoChao(List<Fonte> fontes) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null || instance.m_vegetation == null) { return; } for (int i = 0; i < instance.m_vegetation.Count; i++) { ZoneVegetation val = instance.m_vegetation[i]; if (val == null || !val.m_enable || (Object)(object)val.m_prefab == (Object)null) { continue; } int num = TierDoBioma(val.m_biome); if (num >= 0) { List<string> list = new List<string>(); List<string> list2 = new List<string>(); Varrer(val.m_prefab, list, list2, null, 0); int tipo; int ferramenta = NivelDeFerramenta(val.m_prefab, 0, out tipo); string onde = Nome(val.m_prefab); for (int j = 0; j < list.Count; j++) { Fonte fonte = new Fonte(list[j], num, ferramenta, "ground", onde, fraca: false); fonte.TipoFerramenta = tipo; fontes.Add(fonte); } for (int k = 0; k < list2.Count; k++) { Fonte fonte2 = new Fonte(list2[k], num, ferramenta, "ground", onde, fraca: true); fonte2.TipoFerramenta = tipo; fontes.Add(fonte2); } } } } private static void DasCriaturas(List<Fonte> fontes, SpawnSystem sys) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sys == (Object)null || sys.m_spawnLists == null) { return; } for (int i = 0; i < sys.m_spawnLists.Count; i++) { SpawnSystemList val = sys.m_spawnLists[i]; if ((Object)(object)val == (Object)null || val.m_spawners == null) { continue; } for (int j = 0; j < val.m_spawners.Count; j++) { SpawnData val2 = val.m_spawners[j]; if (val2 == null || (Object)(object)val2.m_prefab == (Object)null || !val2.m_enabled || val2.m_devDisabled) { continue; } int num = TierDoBioma(val2.m_biome); if (num >= 0) { int num2 = MapaNucleo.TierDaChave(val2.m_requiredGlobalKey); if (num2 > num) { num = num2; } List<string> list = new List<string>(); List<string> list2 = new List<string>(); Varrer(val2.m_prefab, list, list2, null, 0); string onde = Nome(val2.m_prefab); for (int k = 0; k < list.Count; k++) { fontes.Add(new Fonte(list[k], num, 0, "creature", onde, fraca: false)); } for (int l = 0; l < list2.Count; l++) { fontes.Add(new Fonte(list2[l], num, 0, "creature", onde, fraca: true)); } } } } } private static void DosBosses(List<Fonte> fontes) { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || instance.m_prefabs == null) { return; } int num = 0; for (int i = 0; i < instance.m_prefabs.Count; i++) { GameObject val = instance.m_prefabs[i]; if ((Object)(object)val == (Object)null) { continue; } Character component = val.GetComponent<Character>(); if ((Object)(object)component == (Object)null || !component.IsBoss()) { continue; } string defeatSetGlobalKey = component.m_defeatSetGlobalKey; if (string.IsNullOrEmpty(defeatSetGlobalKey)) { continue; } int num2 = MapaNucleo.TierDaChave(defeatSetGlobalKey); if (num2 <= 0) { continue; } CharacterDrop component2 = val.GetComponent<CharacterDrop>(); if ((Object)(object)component2 == (Object)null || component2.m_drops == null) { continue; } num++; string onde = Nome(val) + " (" + defeatSetGlobalKey + ")"; for (int j = 0; j < component2.m_drops.Count; j++) { Drop val2 = component2.m_drops[j]; if (val2 != null && !((Object)(object)val2.m_prefab == (Object)null)) { fontes.Add(new Fonte(Nome(val2.m_prefab), num2, 0, "boss", onde, fraca: false, piso: true)); } } } if (num > 0) { RecipeGatePlugin.Detalhe(num + " bosses read from defeat keys."); } } private static void DosLocais(List<Fonte> fontes) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected I4, but got Unknown ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null || instance.m_locations == null) { return; } for (int i = 0; i < instance.m_locations.Count; i++) { ZoneLocation val = instance.m_locations[i]; if (val == null || !val.m_enable || val.m_quantity <= 0 || Ignorada(val.m_prefabName)) { continue; } int num = TierDoBioma(val.m_biome); if (num < 0) { continue; } List<string> list = new List<string>(); List<string> list2 = new List<string>(); bool flag = false; try { if (!val.m_prefab.IsLoaded) { val.m_prefab.Load(); flag = true; } GameObject asset = val.m_prefab.Asset; if ((Object)(object)asset != (Object)null) { Varrer(asset, list, list2, null, 0); Location component = asset.GetComponent<Location>(); if ((Object)(object)component != (Object)null && (Object)(object)component.m_interiorPrefab != (Object)null) { Varrer(component.m_interiorPrefab, list, list2, null, 0); } DungeonGenerator[] componentsInChildren = asset.GetComponentsInChildren<DungeonGenerator>(true); for (int j = 0; j < componentsInChildren.Length; j++) { int num2 = (int)componentsInChildren[j].m_themes; for (int k = 0; k < 32; k++) { int num3 = 1 << k; if ((num2 & num3) != 0 && (!TierDoTema.TryGetValue(num3, out var value) || value > num)) { TierDoTema[num3] = num; } } } } } catch (Exception ex) { RecipeGatePlugin.Log.LogDebug((object)(val.m_prefabName + ": " + ex.Message)); } finally { if (flag) { try { val.m_prefab.Release(); } catch { } } } for (int l = 0; l < list.Count; l++) { fontes.Add(new Fonte(list[l], num, 0, "location", val.m_prefabName, fraca: false)); } for (int m = 0; m < list2.Count; m++) { fontes.Add(new Fonte(list2[m], num, 0, "location", val.m_prefabName, fraca: true)); } } } private static void DasSalas(List<Fonte> fontes) { //IL_0145: 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_00a5: Expected I4, but got Unknown //IL_00d0: Unknown result type (might be due to invalid IL or missing references) DungeonDB instance = DungeonDB.instance; if ((Object)(object)instance == (Object)null || instance.m_roomLists == null || TierDoTema.Count == 0) { return; } int num = 0; for (int i = 0; i < instance.m_roomLists.Count; i++) { GameObject val = instance.m_roomLists[i]; if ((Object)(object)val == (Object)null) { continue; } RoomList component = val.GetComponent<RoomList>(); if ((Object)(object)component == (Object)null || component.m_rooms == null) { continue; } for (int j = 0; j < component.m_rooms.Count; j++) { RoomData val2 = component.m_rooms[j]; if (val2 == null || !val2.m_enabled || !TierDoTema.TryGetValue((int)val2.m_theme, out var value)) { continue; } List<string> list = new List<string>(); List<string> list2 = new List<string>(); bool flag = false; try { if (!val2.m_prefab.IsLoaded) { val2.m_prefab.Load(); flag = true; } GameObject asset = val2.m_prefab.Asset; if ((Object)(object)asset == (Object)null) { continue; } Varrer(asset, list, list2, null, 0); num++; goto IL_013e; } catch (Exception ex) { RecipeGatePlugin.Log.LogDebug((object)("room: " + ex.Message)); goto IL_013e; } finally { if (flag) { try { val2.m_prefab.Release(); } catch { } } } IL_013e: string onde = "room " + val2.m_theme; for (int k = 0; k < list.Count; k++) { fontes.Add(new Fonte(list[k], value, 0, "room", onde, fraca: false)); } for (int l = 0; l < list2.Count; l++) { fontes.Add(new Fonte(list2[l], value, 0, "room", onde, fraca: true)); } } } RecipeGatePlugin.Detalhe(num + " dungeon rooms read across " + TierDoTema.Count + " themes."); } internal static string[] ListaDeIgnorados() { List<string> list = new List<string>(); string[] array = (RecipeGatePlugin.IgnorarLocais.Value ?? "").Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } return list.ToArray(); } internal static bool ListaMudou() { if (!Pronto || _ignorar == null) { return false; } string[] array = ListaDeIgnorados(); if (array.Length != _ignorar.Length) { return true; } for (int i = 0; i < array.Length; i++) { if (!string.Equals(array[i], _ignorar[i], StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static bool Ignorada(string nome) { if (string.IsNullOrEmpty(nome)) { return false; } if (_ignorar == null) { _ignorar = ListaDeIgnorados(); } for (int i = 0; i < _ignorar.Length; i++) { if (nome.StartsWith(_ignorar[i], StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static void PisoDeChave(string item, int tier, string onde) { Pisos.Add(new Fonte(item, tier, 0, "shop", onde, fraca: false, piso: true)); } private static bool EstaAtivo(Component c, GameObject raiz) { if ((Object)(object)c == (Object)null) { return false; } Transform val = c.transform; while ((Object)(object)val != (Object)null) { if (!((Component)val).gameObject.activeSelf) { return false; } if ((Object)(object)raiz != (Object)null && (Object)(object)((Component)val).gameObject == (Object)(object)raiz) { break; } val = val.parent; } return true; } private static void Varrer(GameObject raiz, List<string> natural, List<string> bau, HashSet<int> vistos, int nivel) { //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)raiz == (Object)null || nivel > 3) { return; } if (vistos == null) { vistos = new HashSet<int>(); } if (!vistos.Add(((Object)raiz).GetInstanceID())) { return; } Pickable[] componentsInChildren = raiz.GetComponentsInChildren<Pickable>(true); for (int i = 0; i < componentsInChildren.Length; i++) { if (!EstaAtivo((Component)(object)componentsInChildren[i], raiz)) { Desativados++; continue; } _mecanismo = "Pickable"; Junta(natural, componentsInChildren[i].m_itemPrefab); DaTabela(natural, componentsInChildren[i].m_extraDrops); } PickableItem[] componentsInChildren2 = raiz.GetComponentsInChildren<PickableItem>(true); for (int j = 0; j < componentsInChildren2.Length; j++) { if (!EstaAtivo((Component)(object)componentsInChildren2[j], raiz)) { Desativados++; continue; } _mecanismo = "PickableItem"; if ((Object)(object)componentsInChildren2[j].m_itemPrefab != (Object)null) { Junta(natural, ((Component)componentsInChildren2[j].m_itemPrefab).gameObject); } if (componentsInChildren2[j].m_randomItemPrefabs == null) { continue; } for (int k = 0; k < componentsInChildren2[j].m_randomItemPrefabs.Length; k++) { RandomItem val = componentsInChildren2[j].m_randomItemPrefabs[k]; if ((Object)(object)val.m_itemPrefab != (Object)null) { Junta(natural, ((Component)val.m_itemPrefab).gameObject); } } } _mecanismo = "MineRock5 (mineable)"; MineRock5[] componentsInChildren3 = raiz.GetComponentsInChildren<MineRock5>(true); for (int l = 0; l < componentsInChildren3.Length; l++) { DaTabela(natural, componentsInChildren3[l].m_dropItems); } _mecanismo = "MineRock (mineable)"; MineRock[] componentsInChildren4 = raiz.GetComponentsInChildren<MineRock>(true); for (int m = 0; m < componentsInChildren4.Length; m++) { DaTabela(natural, componentsInChildren4[m].m_dropItems); } _mecanismo = "TreeBase (tree)"; TreeBase[] componentsInChildren5 = raiz.GetComponentsInChildren<TreeBase>(true); for (int n = 0; n < componentsInChildren5.Length; n++) { DaTabela(natural, componentsInChildren5[n].m_dropWhenDestroyed); string mecanismo = _mecanismo; _mecanismo = "chain: tree becomes log " + Nome(componentsInChildren5[n].m_logPrefab); Varrer(componentsInChildren5[n].m_logPrefab, natural, bau, vistos, nivel + 1); Varrer(componentsInChildren5[n].m_stubPrefab, natural, bau, vistos, nivel + 1); _mecanismo = mecanismo; } _mecanismo = "TreeLog (log)"; TreeLog[] componentsInChildren6 = raiz.GetComponentsInChildren<TreeLog>(true); for (int num = 0; num < componentsInChildren6.Length; num++) { DaTabela(natural, componentsInChildren6[num].m_dropWhenDestroyed); string mecanismo2 = _mecanismo; _mecanismo = "chain: log breaks into " + Nome(componentsInChildren6[num].m_subLogPrefab); Varrer(componentsInChildren6[num].m_subLogPrefab, natural, bau, vistos, nivel + 1); _mecanismo = mecanismo2; } _mecanismo = "DropOnDestroyed"; DropOnDestroyed[] componentsInChildren7 = raiz.GetComponentsInChildren<DropOnDestroyed>(true); for (int num2 = 0; num2 < componentsInChildren7.Length; num2++) { DaTabela(natural, componentsInChildren7[num2].m_dropWhenDestroyed); } _mecanismo = "CharacterDrop (drops on death)"; CharacterDrop[] componentsInChildren8 = raiz.GetComponentsInChildren<CharacterDrop>(true); for (int num3 = 0; num3 < componentsInChildren8.Length; num3++) { if (componentsInChildren8[num3].m_drops == null) { continue; } for (int num4 = 0; num4 < componentsInChildren8[num3].m_drops.Count; num4++) { Drop val2 = componentsInChildren8[num3].m_drops[num4]; if (val2 != null) { Junta(natural, val2.m_prefab); } } } _mecanismo = "Container (chest)"; Container[] componentsInChildren9 = raiz.GetComponentsInChildren<Container>(true); for (int num5 = 0; num5 < componentsInChildren9.Length; num5++) { DaTabela(bau, componentsInChildren9[num5].m_defaultItems); } _mecanismo = "CreatureSpawner"; CreatureSpawner[] componentsInChildren10 = raiz.GetComponentsInChildren<CreatureSpawner>(true); for (int num6 = 0; num6 < componentsInChildren10.Length; num6++) { Varrer(componentsInChildren10[num6].m_creaturePrefab, natural, bau, vistos, nivel + 1); } _mecanismo = "SpawnArea (nest)"; SpawnArea[] componentsInChildren11 = raiz.GetComponentsInChildren<SpawnArea>(true); for (int num7 = 0; num7 < componentsInChildren11.Length; num7++) { if (componentsInChildren11[num7].m_prefabs == null) { continue; } for (int num8 = 0; num8 < componentsInChildren11[num7].m_prefabs.Count; num8++) { SpawnData val3 = componentsInChildren11[num7].m_prefabs[num8]; if (val3 != null) { Varrer(val3.m_prefab, natural, bau, vistos, nivel + 1); } } } _mecanismo = "WispSpawner"; WispSpawner[] componentsInChildren12 = raiz.GetComponentsInChildren<WispSpawner>(true); for (int num9 = 0; num9 < componentsInChildren12.Length; num9++) { Varrer(componentsInChildren12[num9].m_wispPrefab, natural, bau, vistos, nivel + 1); } _mecanismo = "TriggerSpawner"; TriggerSpawner[] componentsInChildren13 = raiz.GetComponentsInChildren<TriggerSpawner>(true); for (int num10 = 0; num10 < componentsInChildren13.Length; num10++) { if (componentsInChildren13[num10].m_creaturePrefabs != null) { for (int num11 = 0; num11 < componentsInChildren13[num10].m_creaturePrefabs.Length; num11++) { Varrer(componentsInChildren13[num10].m_creaturePrefabs[num11], natural, bau, vistos, nivel + 1); } } } _mecanismo = "Trader (shop)"; Trader[] componentsInChildren14 = raiz.GetComponentsInChildren<Trader>(true); for (int num12 = 0; num12 < componentsInChildren14.Length; num12++) { if (componentsInChildren14[num12].m_items == null) { continue; } for (int num13 = 0; num13 < componentsInChildren14[num12].m_items.Count; num13++) { TradeItem val4 = componentsInChildren14[num12].m_items[num13]; if (val4 == null || (Object)(object)val4.m_prefab == (Object)null) { continue; } string text = Nome(((Component)val4.m_prefab).gameObject); if (!string.IsNullOrEmpty(text)) { int num14 = MapaNucleo.TierDaChave(val4.m_requiredGlobalKey); if (num14 > 0) { PisoDeChave(text, num14, "shop: " + Nome(raiz)); } else { Junta(natural, ((Component)val4.m_prefab).gameObject); } } } } _mecanismo = "Beehive"; Beehive[] componentsInChildren15 = raiz.GetComponentsInChildren<Beehive>(true); for (int num15 = 0; num15 < componentsInChildren15.Length; num15++) { if ((Object)(object)componentsInChildren15[num15].m_honeyItem != (Object)null) { Junta(natural, ((Component)componentsInChildren15[num15].m_honeyItem).gameObject); } } _mecanismo = "SapCollector"; SapCollector[] componentsInChildren16 = raiz.GetComponentsInChildren<SapCollector>(true); for (int num16 = 0; num16 < componentsInChildren16.Length; num16++) { if ((Object)(object)componentsInChildren16[num16].m_spawnItem != (Object)null) { Junta(natural, ((Component)componentsInChildren16[num16].m_spawnItem).gameObject); } } Destructible[] componentsInChildren17 = raiz.GetComponentsInChildren<Destructible>(true); for (int num17 = 0; num17 < componentsInChildren17.Length; num17++) { string mecanismo3 = _mecanismo; _mecanismo = "chain: destroyed object becomes " + Nome(componentsInChildren17[num17].m_spawnWhenDestroyed); Varrer(componentsInChildren17[num17].m_spawnWhenDestroyed, natural, bau, vistos, nivel + 1); _mecanismo = mecanismo3; } } private static int NivelDeFerramenta(GameObject go, int nivel) { int tipo; return NivelDeFerramenta(go, nivel, out tipo); } private static int NivelDeFerramenta(GameObject go, int nivel, out int tipo) { if ((Object)(object)go == (Object)null || nivel > 3) { tipo = 0; return 0; } int maior = 0; int tipoMaior = 0; bool flag = false; bool flag2 = false; Action<int, int> action = delegate(int exigido, int deQueTipo) { if (exigido > maior) { maior = exigido; tipoMaior = deQueTipo; } }; TreeBase[] componentsInChildren = go.GetComponentsInChildren<TreeBase>(true); if (componentsInChildren.Length > 0) { flag = true; } for (int num = 0; num < componentsInChildren.Length; num++) { action(componentsInChildren[num].m_minToolTier, 1); action(NivelDeFerramenta(componentsInChildren[num].m_logPrefab, nivel + 1, out var tipo2), tipo2); action(NivelDeFerramenta(componentsInChildren[num].m_stubPrefab, nivel + 1, out tipo2), tipo2); } TreeLog[] componentsInChildren2 = go.GetComponentsInChildren<TreeLog>(true); if (componentsInChildren2.Length > 0) { flag = true; } for (int num2 = 0; num2 < componentsInChildren2.Length; num2++) { action(componentsInChildren2[num2].m_minToolTier, 1); action(NivelDeFerramenta(componentsInChildren2[num2].m_subLogPrefab, nivel + 1, out var tipo3), tipo3); } MineRock5[] componentsInChildren3 = go.GetComponentsInChildren<MineRock5>(true); if (componentsInChildren3.Length > 0) { flag2 = true; } for (int num3 = 0; num3 < componentsInChildren3.Length; num3++) { action(componentsInChildren3[num3].m_minToolTier, 2); } MineRock[] componentsInChildren4 = go.GetComponentsInChildren<MineRock>(true); if (componentsInChildren4.Length > 0) { flag2 = true; } for (int num4 = 0; num4 < componentsInChildren4.Length; num4++) { action(componentsInChildren4[num4].m_minToolTier, 2); } Destructible[] componentsInChildren5 = go.GetComponentsInChildren<Destructible>(true); for (int num5 = 0; num5 < componentsInChildren5.Length; num5++) { action(componentsInChildren5[num5].m_minToolTier, 2); action(NivelDeFerramenta(componentsInChildren5[num5].m_spawnWhenDestroyed, nivel + 1, out var tipo4), tipo4); } if (maior == 0 && tipoMaior == 0) { if (flag2) { tipoMaior = 2; } else if (flag) { tipoMaior = 1; } } tipo = tipoMaior; return maior; } private static void DaTabela(List<string> saida, DropTable t) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (t != null && t.m_drops != null) { for (int i = 0; i < t.m_drops.Count; i++) { Junta(saida, t.m_drops[i].m_item); } } } private static void Junta(List<string> saida, GameObject item) { string text = Nome(item); if (!string.IsNullOrEmpty(text)) { if (_como != null && !_como.ContainsKey(text)) { _como[text] = _mecanismo; } if (!saida.Contains(text)) { saida.Add(text); } } } private static void DosPeixes(List<Fonte> fontes) { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || instance.m_prefabs == null) { return; } for (int i = 0; i < instance.m_prefabs.Count; i++) { GameObject val = instance.m_prefabs[i]; if ((Object)(object)val == (Object)null) { continue; } Fish component = val.GetComponent<Fish>(); if (!((Object)(object)component == (Object)null)) { string onde = "fish: " + Nome(val); if ((Object)(object)val.GetComponent<ItemDrop>() != (Object)null) { fontes.Add(new Fonte(Nome(val), 0, 0, "ocean", onde, fraca: false)); } if ((Object)(object)component.m_pickupItem != (Object)null) { fontes.Add(new Fonte(Nome(component.m_pickupItem), 0, 0, "ocean", onde, fraca: false)); } } } } private static void DasReceitas(List<Receita> receitas, List<Ferramenta> ferramentas, List<Extensao> extensoes) { DaBancada(receitas); DasFerramentas(ferramentas); ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || instance.m_prefabs == null) { return; } for (int i = 0; i < instance.m_prefabs.Count; i++) { GameObject val = instance.m_prefabs[i]; if (!((Object)(object)val == (Object)null)) { DoQueProduzSozinho(receitas, val); DaCriacao(receitas, val); DasConversoes(receitas, val); DoPlantio(receitas, val); DaConstrucao(receitas, extensoes, val); } } } private static void DaBancada(List<Receita> receitas) { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || instance.m_recipes == null) { return; } for (int i = 0; i < instance.m_recipes.Count; i++) { Recipe val = instance.m_recipes[i]; if ((Object)(object)val == (Object)null || !val.m_enabled || (Object)(object)val.m_item == (Object)null || val.m_resources == null) { continue; } Receita receita = new Receita(); receita.Produto = Nome(((Component)val.m_item).gameObject); receita.Estacao = (((Object)(object)val.m_craftingStation == (Object)null) ? null : Nome(((Component)val.m_craftingStation).gameObject)); receita.NivelEstacao = ((val.m_minStationLevel < 1) ? 1 : val.m_minStationLevel); receita.QualquerUm = val.m_requireOnlyOneIngredient; for (int j = 0; j < val.m_resources.Length; j++) { Requirement val2 = val.m_resources[j]; if (val2 != null && (Object)(object)val2.m_resItem != (Object)null) { receita.Ingredientes.Add(Nome(((Component)val2.m_resItem).gameObject)); } } if (receita.Ingredientes.Count > 0) { receitas.Add(receita); } } } private static void DasFerramentas(List<Ferramenta> ferramentas) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || instance.m_items == null) { return; } for (int i = 0; i < instance.m_items.Count; i++) { GameObject val = instance.m_items[i]; if (!((Object)(object)val == (Object)null)) { ItemDrop component = val.GetComponent<ItemDrop>(); if (!((Object)(object)component == (Object)null) && component.m_itemData != null && component.m_itemData.m_shared != null && component.m_itemData.m_shared.m_toolTier > 0) { DamageTypes damages = component.m_itemData.m_shared.m_damages; ferramentas.Add(new Ferramenta(Nome(val), component.m_itemData.m_shared.m_toolTier, damages.m_chop > 0f, damages.m_pickaxe > 0f)); } } } } private static void DoQueProduzSozinho(List<Receita> receitas, GameObject go) { string text = Nome(go); SapCollector component = go.GetComponent<SapCollector>(); if ((Object)(object)component != (Object)null && (Object)(object)component.m_spawnItem != (Object)null) { receitas.Add(new Receita(Nome(((Component)component.m_spawnItem).gameObject), null, text)); } Beehive component2 = go.GetComponent<Beehive>(); if ((Object)(object)component2 != (Object)null && (Object)(object)component2.m_honeyItem != (Object)null) { receitas.Add(new Receita(Nome(((Component)component2.m_honeyItem).gameObject), null, text)); } WispSpawner component3 = go.GetComponent<WispSpawner>(); if ((Object)(object)component3 != (Object)null && (Object)(object)component3.m_wispPrefab != (Object)null) { RendeComoReceita(receitas, component3.m_wispPrefab, text); } CreatureSpawner component4 = go.GetComponent<CreatureSpawner>(); if ((Object)(object)component4 != (Object)null && (Object)(object)component4.m_creaturePrefab != (Object)null && (Object)(object)go.GetComponent<Piece>() != (Object)null) { RendeComoReceita(receitas, component4.m_creaturePrefab, text); } } private static void DaCriacao(List<Receita> receitas, GameObject go) { EggGrow component = go.GetComponent<EggGrow>(); if ((Object)(object)component != (Object)null && (Object)(object)component.m_grownPrefab != (Object)null) { receitas.Add(new Receita(Nome(component.m_grownPrefab), null, Nome(go))); DropsComoReceita(receitas, component.m_grownPrefab); } Growup component2 = go.GetComponent<Growup>(); if ((Object)(object)component2 != (Object)null && (Object)(object)component2.m_grownPrefab != (Object)null) { receitas.Add(new Receita(Nome(component2.m_grownPrefab), null, Nome(go))); DropsComoReceita(receitas, component2.m_grownPrefab); } } private static void DasConversoes(List<Receita> receitas, GameObject go) { string estacao = Nome(go); Smelter component = go.GetComponent<Smelter>(); if ((Object)(object)component != (Object)null && component.m_conversion != null) { for (int i = 0; i < component.m_conversion.Count; i++) { ItemConversion val = component.m_conversion[i]; if (val != null && !((Object)(object)val.m_from == (Object)null) && !((Object)(object)val.m_to == (Object)null)) { receitas.Add(new Receita(Nome(((Component)val.m_to).gameObject), estacao, Nome(((Component)val.m_from).gameObject))); } } } CookingStation component2 = go.GetComponent<CookingStation>(); if ((Object)(object)component2 != (Object)null && component2.m_conversion != null) { for (int j = 0; j < component2.m_conversion.Count; j++) { ItemConversion val2 = component2.m_conversion[j]; if (val2 != null && !((Object)(object)val2.m_from == (Object)null) && !((Object)(object)val2.m_to == (Object)null)) { receitas.Add(new Receita(Nome(((Component)val2.m_to).gameObject), estacao, Nome(((Component)val2.m_from).gameObject))); } } } Fermenter component3 = go.GetComponent<Fermenter>(); if (!((Object)(object)component3 != (Object)null) || component3.m_conversion == null) { return; } for (int k = 0; k < component3.m_conversion.Count; k++) { ItemConversion val3 = component3.m_conversion[k]; if (val3 != null && !((Object)(object)val3.m_from == (Object)null) && !((Object)(object)val3.m_to == (Object)null)) { receitas.Add(new Receita(Nome(((Component)val3.m_to).gameObject), estacao, Nome(((Component)val3.m_from).gameObject))); } } } private static void DoPlantio(List<Receita> receitas, GameObject go) { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) Plant component = go.GetComponent<Plant>(); if ((Object)(object)component == (Object)null || component.m_grownPrefabs == null) { return; } Piece component2 = go.GetComponent<Piece>(); if ((Object)(object)component2 == (Object)null || component2.m_resources == null) { return; } List<string> list = new List<string>(); for (int i = 0; i < component2.m_resources.Length; i++) { Requirement val = component2.m_resources[i]; if (val != null && (Object)(object)val.m_resItem != (Object)null) { list.Add(Nome(((Component)val.m_resItem).gameObject)); } } if (list.Count == 0) { return; } for (int j = 0; j < component.m_grownPrefabs.Length; j++) { GameObject val2 = component.m_grownPrefabs[j]; if (!((Object)(object)val2 == (Object)null)) { List<string> list2 = new List<string>(); List<string> bau = new List<string>(); Varrer(val2, list2, bau, null, 0); for (int k = 0; k < list2.Count; k++) { Receita receita = new Receita(); receita.Produto = list2[k]; receita.Ingredientes = new List<string>(list); receita.Piso = TierDoBioma(component.m_biome); receitas.Add(receita); } } } } private static void DaConstrucao(List<Receita> receitas, List<Extensao> extensoes, GameObject go) { //IL_009a: Unknown result type (might be due to invalid IL or missing references) string text = Nome(go); StationExtension component = go.GetComponent<StationExtension>(); if ((Object)(object)component != (Object)null && (Object)(object)component.m_craftingStation != (Object)null) { extensoes.Add(new Extensao(Nome(((Component)component.m_craftingStation).gameObject), text)); } Piece component2 = go.GetComponent<Piece>(); if ((Object)(object)component2 == (Object)null || component2.m_resources == null || component2.m_resources.Length == 0) { return; } Receita receita = new Receita(); receita.Produto = text; receita.Estacao = (((Object)(object)component2.m_craftingStation == (Object)null) ? null : Nome(((Component)component2.m_craftingStation).gameObject)); receita.Piso = TierDoBioma(component2.m_onlyInBiome); for (int i = 0; i < component2.m_resources.Length; i++) { Requirement val = component2.m_resources[i]; if (val != null && (Object)(object)val.m_resItem != (Object)null) { receita.Ingredientes.Add(Nome(((Component)val.m_resItem).gameObject)); } } if (receita.Ingredientes.Count > 0) { receitas.Add(receita); } } private static void RendeComoReceita(List<Receita> receitas, GameObject rende, string fonte) { if ((Object)(object)rende == (Object)null || string.IsNullOrEmpty(fonte)) { return; } List<string> list = new List<string>(); List<string> bau = new List<string>(); Varrer(rende, list, bau, null, 0); for (int i = 0; i < list.Count; i++) { if (!string.Equals(list[i], fonte, StringComparison.OrdinalIgnoreCase)) { receitas.Add(new Receita(list[i], null, fonte)); } } } private static void DropsComoReceita(List<Receita> receitas, GameObject criatura) { if ((Object)(object)criatura == (Object)null) { return; } CharacterDrop component = criatura.GetComponent<CharacterDrop>(); if ((Object)(object)component == (Object)null || component.m_drops == null) { return; } string text = Nome(criatura); if (string.IsNullOrEmpty(text)) { return; } for (int i = 0; i < component.m_drops.Count; i++) { Drop val = component.m_drops[i]; if (val != null && !((Object)(object)val.m_prefab == (Object)null)) { string text2 = Nome(val.m_prefab); if (!string.IsNullOrEmpty(text2)) { receitas.Add(new Receita(text2, null, text)); } } } } private static void Explicar(List<Fonte> fontes, List<Receita> receitas) { string value = RecipeGatePlugin.Explicar.Value; if (string.IsNullOrEmpty(value)) { return; } string[] array = value.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0) { continue; } RecipeGatePlugin.Log.LogInfo((object)("--- " + text + " ---")); if (Derivado != null && Derivado.TryGetValue(text, out var value2)) { RecipeGatePlugin.Log.LogInfo((object)(" WON tier " + value2.Tier + " " + value2.Origem + ": " + value2.Onde + (value2.Fraca ? " [WEAK]" : " [strong]"))); } for (int j = 0; j < fontes.Count; j++) { Fonte fonte = fontes[j]; if (fonte != null && string.Equals(fonte.Prefab, text, StringComparison.OrdinalIgnoreCase)) { RecipeGatePlugin.Log.LogInfo((object)(" source tier " + fonte.Tier + " " + fonte.Origem + ": " + fonte.Onde + (fonte.Fraca ? " (chest)" : "") + (fonte.Piso ? " (floor)" : "") + ((fonte.Ferramenta > 0) ? (" tool " + fonte.Ferramenta) : ""))); } } QuemProduz(text); for (int k = 0; k < receitas.Count; k++) { Receita receita = receitas[k]; if (receita != null) { bool flag = string.Equals(receita.Produto, text, StringComparison.OrdinalIgnoreCase); bool flag2 = receita.Ingredientes.Contains(text); if (flag || flag2) { RecipeGatePlugin.Log.LogInfo((object)(" " + (flag ? "comes from" : "goes into") + " " + receita.Produto + " = " + string.Join(" + ", receita.Ingredientes.ToArray()) + (string.IsNullOrEmpty(receita.Estacao) ? "" : (" @" + receita.Estacao)) + ((receita.NivelEstacao > 1) ? (" lvl" + receita.NivelEstacao) : "") + (receita.QualquerUm ? " (any one is enough)" : "") + ((receita.Piso > 0) ? (" (only in " + MapaNucleo.NomeDoTier(receita.Piso) + ")") : ""))); } } } } } private static void QuemProduz(string alvo) { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || instance.m_prefabs == null) { return; } int num = 0; for (int i = 0; i < instance.m_prefabs.Count; i++) { GameObject val = instance.m_prefabs[i]; if ((Object)(object)val == (Object)null) { continue; } List<string> list = new List<string>(); List<string> list2 = new List<string>(); _como = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); _mecanismo = "?"; try { Varrer(val, list, list2, null, 0); } catch { _como = null; continue; } bool flag = list.Contains(alvo); bool flag2 = list2.Contains(alvo); if (!_como.TryGetValue(alvo, out var value)) { value = "?"; } _como = null; if (flag || flag2) { num++; if (num <= 20) { RecipeGatePlugin.Log.LogInfo((object)(" produces " + Nome(val) + " through " + value + ((flag2 && !flag) ? " (inside a chest)" : ""))); } } } if (num == 0) { RecipeGatePlugin.Log.LogInfo((object)" NO prefab in the game produces this."); } else if (num > 20) { RecipeGatePlugin.Log.LogInfo((object)(" ... and " + (num - 20) + " prefabs.")); } } internal static void Escrever() { try { if (Derivado == null) { return; } List<string> list = new List<string>(Derivado.Keys); list.Sort(StringComparer.OrdinalIgnoreCase); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# RecipeGate - map derived from game data"); stringBuilder.AppendLine("# " + DateTime.Now.ToString("yyyy-MM-dd HH:mm") + " | " + Derivado.Count + " materials"); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# tier = LOWEST among acquisition methods, each evaluated as"); stringBuilder.AppendLine("# MAX(required biome, tool, or station)"); stringBuilder.AppendLine("# a chest counts only when there is no other source"); stringBuilder.AppendLine(); for (int i = 0; i < MapaNucleo.Biomas.Length; i++) { List<string> list2 = new List<string>(); for (int j = 0; j < list.Count; j++) { if (Derivado[list[j]].Tier == i) { list2.Add(list[j]); } } if (list2.Count != 0) { string text = MapaNucleo.ChaveDoTier(i); stringBuilder.AppendLine("## " + MapaNucleo.NomeDoTier(i) + " (" + ((i == 0) ? "nokey" : ("requires " + text)) + ") " + list2.Count + " materials"); stringBuilder.AppendLine(); for (int k = 0; k < list2.Count; k++) { Resultado resultado = Derivado[list2[k]]; stringBuilder.AppendLine(" " + list2[k] + " | " + resultado.Origem + ": " + resultado.Onde); } stringBuilder.AppendLine(); } } stringBuilder.AppendLine(MapaNucleo.Conferir(Derivado, RecipeGatePlugin.TabelaDoWap(), RecipeGatePlugin.ChaveDoMaterial)); File.WriteAllText(RecipeGatePlugin.CaminhoDeRelatorio("map.txt"), stringBuilder.ToString()); RecipeGatePlugin.Detalhe("map report written to the reports folder."); } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("failed to write the report: " + ex.Message)); } } } public class Fonte { public string Prefab; public int Tier; public int Ferramenta; public int TipoFerramenta; public string Origem; public string Onde; public bool Fraca; public bool Piso; public Fonte() { } public Fonte(string prefab, int tier, int ferramenta, string origem, string onde, bool fraca) { Prefab = prefab; Tier = tier; Ferramenta = ferramenta; Origem = origem; Onde = onde; Fraca = fraca; } public Fonte(string prefab, int tier, int ferramenta, string origem, string onde, bool fraca, bool piso) : this(prefab, tier, ferramenta, origem, onde, fraca) { Piso = piso; } } public class Receita { public string Produto; public List<string> Ingredientes = new List<string>(); public string Estacao; public bool QualquerUm; public int Piso; public int NivelEstacao; public Receita() { } public Receita(string produto, string estacao, params string[] ing) { Produto = produto; Estacao = estacao; NivelEstacao = 1; Ingredientes = new List<string>(ing); } } public class Extensao { public string Estacao; public string Prefab; public Extensao() { } public Extensao(string estacao, string prefab) { Estacao = estacao; Prefab = prefab; } } public static class Tipo { public const int Qualquer = 0; public const int Corte = 1; public const int Escavacao = 2; } public class Ferramenta { public string Prefab; public int Nivel; public bool Corta; public bool Escava; public Ferramenta() { } public Ferramenta(string prefab, int nivel) { Prefab = prefab; Nivel = nivel; Corta = true; Escava = true; } public Ferramenta(string prefab, int nivel, bool corta, bool escava) { Prefab = prefab; Nivel = nivel; Corta = corta; Escava = escava; } } public class Resultado { public int Tier; public string Origem; public string Onde; public bool Fraca; public Resultado(int t, string o, string onde) { Tier = t; Origem = o; Onde = onde; } public Resultado(int t, string o, string onde, bool fraca) : this(t, o, onde) { Fraca = fraca; } } public static class MapaNucleo { public static readonly string[] Biomas = new string[8] { "Meadows", "BlackForest", "Swamp", "Mountain", "Plains", "Mistlands", "AshLands", "DeepNorth" }; public static readonly string[] ChavePorTier = new string[8] { "nokey", "defeated_eikthyr", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking", "defeated_queen", "defeated_fader" }; private static Dictionary<string, Resultado> _piso; public static string NomeDoTier(int t) { if (t < 0 || t >= Biomas.Length) { return "?"; } return Biomas[t]; } public static string ChaveDoTier(int t) { if (t < 0 || t >= ChavePorTier.Length) { return null; } return ChavePorTier[t]; } public static int TierDaChave(string chave) { if (string.IsNullOrEmpty(chave)) { return 0; } for (int i = 0; i < ChavePorTier.Length; i++) { if (string.Equals(ChavePorTier[i], chave, StringComparison.OrdinalIgnoreCase)) { return i; } } return 0; } public static Dictionary<string, Resultado> Resolver(List<Fonte> fontes, List<Receita> receitas, List<Ferramenta> ferramentas, int maxVoltas) { return Resolver(fontes, receitas, ferramentas, null, maxVoltas); } public static Dictionary<string, Resultado> Resolver(List<Fonte> fontes, List<Receita> receitas, List<Ferramenta> ferramentas, List<Extensao> extensoes, int maxVoltas) { if (extensoes == null) { extensoes = new List<Extensao>(); } _piso = new Dictionary<string, Resultado>(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < fontes.Count; i++) { Fonte fonte = fontes[i]; if (fonte != null && fonte.Piso && !string.IsNullOrEmpty(fonte.Prefab) && (!_piso.TryGetValue(fonte.Prefab, out var value) || value.Tier < fonte.Tier)) { _piso[fonte.Prefab] = new Resultado(fonte.Tier, fonte.Origem, fonte.Onde); } } Dictionary<string, Resultado> dictionary = new Dictionary<string, Resultado>(StringComparer.OrdinalIgnoreCase); if (fontes == null) { fontes = new List<Fonte>(); } if (receitas == null) { receitas = new List<Receita>(); } if (ferramentas == null) { ferramentas = new List<Ferramenta>(); } HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); for (int j = 0; j < receitas.Count; j++) { if (receitas[j] != null && !string.IsNullOrEmpty(receitas[j].Produto)) { hashSet.Add(receitas[j].Produto); } } for (int k = 0; k < maxVoltas; k++) { Dictionary<string, Resultado> dictionary2 = new Dictionary<string, Resultado>(StringComparer.OrdinalIgnoreCase); for (int l = 0; l < fontes.Count; l++) { Fonte fonte2 = fontes[l]; if (fonte2 != null && !string.IsNullOrEmpty(fonte2.Prefab) && fonte2.Tier >= 0 && (!fonte2.Fraca || !hashSet.Contains(fonte2.Prefab))) { int num = CustoFerramenta(fonte2.Ferramenta, fonte2.TipoFerramenta, ferramentas, dictionary); if (num >= 0) { int t = Math.Max(fonte2.Tier, num); Melhor(dictionary2, fonte2.Prefab, t, fonte2.Fraca ? "chest" : fonte2.Origem, fonte2.Onde, fonte2.Fraca); } } } for (int m = 0; m < 10; m++) { bool flag = false; for (int n = 0; n < receitas.Count; n++) { Receita receita = receitas[n]; if (receita == null || string.IsNullOrEmpty(receita.Produto) || SeAlimentaDeSi(receita)) { continue; } int num2 = 0; bool flag2 = true; if (receita.QualquerUm) { num2 = -1; for (int num3 = 0; num3 < receita.Ingredientes.Count; num3++) { int num4 = TierDe(receita.Ingredientes[num3], dictionary2, dictionary); if (num4 >= 0 && (num2 < 0 || num4 < num2)) { num2 = num4; } } if (num2 < 0) { flag2 = false; } } else { for (int num5 = 0; num5 < receita.Ingredientes.Count; num5++) { int num6 = TierDe(receita.Ingredientes[num5], dictionary2, dictionary); if (num6 < 0) { flag2 = false; break; } if (num6 > num2) { num2 = num6; } } } if (!flag2) { continue; } if (receita.Piso > num2) { num2 = receita.Piso; } if (!string.IsNullOrEmpty(receita.Estacao)) { int num7 = TierDe(receita.Estacao, dictionary2, dictionary); if (num7 < 0) { continue; } if (num7 > num2) { num2 = num7; } int num8 = CustoDoNivel(receita.Estacao, receita.NivelEstacao, extensoes, dictionary2, dictionary); if (num8 > num2) { num2 = num8; } } bool flag3 = EhFraca(receita.Estacao, dictionary2, dictionary); for (int num9 = 0; num9 < receita.Ingredientes.Count; num9++) { if (flag3) { break; } if (EhFraca(receita.Ingredientes[num9], dictionary2, dictionary)) { flag3 = true; } } if (Melhor(dictionary2, receita.Produto, num2, "recipe", Descrever(receita), flag3)) { flag = true; } } if (!flag) { break; } } for (int num10 = 0; num10 < 10; num10++) { bool flag4 = false; for (int num11 = 0; num11 < receitas.Count; num11++) { Receita receita2 = receitas[num11]; if (receita2 == null || string.IsNullOrEmpty(receita2.Produto) || SeAlimentaDeSi(receita2) || dictionary2.ContainsKey(receita2.Produto)) { continue; } int num12 = 0; bool flag5 = false; for (int num13 = 0; num13 < receita2.Ingredientes.Count; num13++) { int num14 = TierDe(receita2.Ingredientes[num13], dictionary2, dictionary); if (num14 < 0) { continue; } if (receita2.QualquerUm) { if (!flag5 || num14 < num12) { num12 = num14; } } else if (num14 > num12) { num12 = num14; } flag5 = true; } if (!string.IsNullOrEmpty(receita2.Estacao)) { int num15 = TierDe(receita2.Estacao, dictionary2, dictionary); if (num15 >= 0) { flag5 = true; if (num15 > num12) { num12 = num15; } int num16 = CustoDoNivel(receita2.Estacao, receita2.NivelEstacao, extensoes, dictionary2, dictionary); if (num16 > num12) { num12 = num16; } } } if (!flag5) { continue; } if (receita2.Piso > num12) { num12 = receita2.Piso; } bool flag6 = EhFraca(receita2.Estacao, dictionary2, dictionary); for (int num17 = 0; num17 < receita2.Ingredientes.Count; num17++) { if (flag6) { break; } if (EhFraca(receita2.Ingredientes[num17], dictionary2, dictionary)) { flag6 = true; } } if (Melhor(dictionary2, receita2.Produto, num12, "recipe", Descrever(receita2) + " [partial]", flag6)) { flag4 = true; } } if (!flag4) { break; } } for (int num18 = 0; num18 < fontes.Count; num18++) { Fonte fonte3 = fontes[num18]; if (fonte3 != null && fonte3.Fraca && !string.IsNullOrEmpty(fonte3.Prefab) && fonte3.Tier >= 0 && !dictionary2.ContainsKey(fonte3.Prefab)) { int num19 = CustoFerramenta(fonte3.Ferramenta, fonte3.TipoFerramenta, ferramentas, dictionary); if (num19 >= 0) { int t2 = Math.Max(fonte3.Tier, num19); Melhor(dictionary2, fonte3.Prefab, t2, "chest", fonte3.Onde, fraca: true); } } } for (int num20 = 0; num20 < fontes.Count; num20++) { Fonte fonte4 = fontes[num20]; if (fonte4 != null && fonte4.Piso && !string.IsNullOrEmpty(fonte4.Prefab) && (!dictionary2.TryGetValue(fonte4.Prefab, out var value2) || value2.Tier < fonte4.Tier)) { dictionary2[fonte4.Prefab] = new Resultado(fonte4.Tier, "boss", fonte4.Onde); } } if (Igual(dictionary2, dictionary)) { dictionary = dictionary2; break; } dictionary = dictionary2; } return dictionary; } private static int CustoDoNivel(string estacao, int nivel, List<Extensao> extensoes, Dictionary<string, Resultado> a, Dictionary<string, Resultado> b) { if (nivel <= 1 || extensoes.Count == 0) { return 0; } List<int> list = new List<int>(); for (int i = 0; i < extensoes.Count; i++) { Extensao extensao = extensoes[i]; if (extensao != null && string.Equals(extensao.Estacao, estacao, StringComparison.OrdinalIgnoreCase)) { int num = TierDe(extensao.Prefab, a, b); if (num >= 0) { list.Add(num); } } } if (list.Count == 0) { return 0; } list.Sort(); int num2 = nivel - 1; if (num2 > list.Count) { num2 = list.Count; } return list[num2 - 1]; } private static bool SeAlimentaDeSi(Receita r) { for (int i = 0; i < r.Ingredientes.Count; i++) { if (string.Equals(r.Ingredientes[i], r.Produto, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private static string Descrever(Receita r) { string text = string.Join(" + ", r.Ingredientes.ToArray()); if (!string.IsNullOrEmpty(r.Estacao)) { text = text + " @" + r.Estacao; if (r.NivelEstacao > 1) { text = text + " lvl" + r.NivelEstacao; } } if (r.Piso > 0) { text = text + " only in " + NomeDoTier(r.Piso); } return text; } private static bool EhFraca(string nome, Dictionary<string, Resultado> a, Dictionary<string, Resultado> b) { if (string.IsNullOrEmpty(nome)) { return false; } if (a != null && a.TryGetValue(nome, out var value)) { return value.Fraca; } if (b != null && b.TryGetValue(nome, out value)) { return value.Fraca; } return false; } private static int TierDe(string nome, Dictionary<string, Resultado> a, Dictionary<string, Resultado> b) { if (a != null && a.TryGetValue(nome, out var value)) { return value.Tier; } if (b != null && b.TryGetValue(nome, out value)) { return value.Tier; } return -1; } private static bool Melhor(Dictionary<string, Resultado> mapa, string prefab, int t, string origem, string onde) { return Melhor(mapa, prefab, t, origem, onde, fraca: false); } private static bool Melhor(Dictionary<string, Resultado> mapa, string prefab, int t, string origem, string onde, bool fraca) { if (_piso != null && _piso.TryGetValue(prefab, out var value) && value.Tier > t) { t = value.Tier; origem = value.Origem; onde = value.Onde; } if (mapa.TryGetValue(prefab, out var value2) && value2.Tier <= t) { if (value2.Fraca && !fraca && value2.Tier == t) { mapa[prefab] = new Resultado(t, origem, onde, fraca: false); return true; } return false; } mapa[prefab] = new Resultado(t, origem, onde, fraca); return true; } private static int CustoFerramenta(int nivel, int tipo, List<Ferramenta> ferramentas, Dictionary<string, Resultado> tier) { if (ferramentas == null) { return 0; } if (nivel <= 0 && tipo == 0) { return 0; } int num = int.MaxValue; for (int i = 0; i < ferramentas.Count; i++) { Ferramenta ferramenta = ferramentas[i]; if (ferramenta != null && ferramenta.Nivel >= nivel && (tipo != 1 || ferramenta.Corta) && (tipo != 2 || ferramenta.Escava) && tier != null && tier.TryGetValue(ferramenta.Prefab, out var value) && !value.Fraca && value.Tier < num) { num = value.Tier; } } if (num != int.MaxValue) { return num; } return -1; } private static bool Igual(Dictionary<string, Resultado> a, Dictionary<string, Resultado> b) { if (a.Count != b.Count) { return false; } foreach (KeyValuePair<string, Resultado> item in a) { if (!b.TryGetValue(item.Key, out var value)) { return false; } if (value.Tier != item.Value.Tier) { return false; } } return true; } public static string Conferir(Dictionary<string, Resultado> derivado, Dictionary<string, string> wap) { return Conferir(derivado, wap, null); } public static string Conferir(Dictionary<string, Resultado> derivado, Dictionary<string, string> wap, Func<string, string> efetiva) { StringBuilder stringBuilder = new StringBuilder(); if (derivado == null || wap == null) { return ""; } List<string> list = new List<string>(); List<string> list2 = new List<string>(); List<string> list3 = new List<string>(); foreach (KeyValuePair<string, string> item in wap) { if (!derivado.TryGetValue(item.Key, out var value)) { list3.Add(item.Key); continue; } string text = ChaveDoTier(value.Tier); bool flag = false; if (efetiva != null) { string text2 = efetiva(item.Key); if (text2 != text) { text = text2; flag = true; } } if (text == item.Value) { list.Add(item.Key); continue; } list2.Add(item.Key + ": derived=" + (text ?? "nokey") + " wap=" + item.Value + " (" + (flag ? "by hand" : (value.Origem + ": " + value.Onde)) + ")"); } stringBuilder.AppendLine("WAP cross-check: " + list.Count + " identical, " + list2.Count + " different, " + list3.Count + " without a derived source"); for (int i = 0; i < list2.Count; i++) { stringBuilder.AppendLine(" " + list2[i]); } if (list3.Count > 0) { stringBuilder.AppendLine(" no source: " + string.Join(", ", list3.ToArray())); } return stringBuilder.ToString(); } } public static class Nucleo { public const char Separador = ','; public static List<string> LerPendentes(string bruto) { List<string> list = new List<string>(); if (string.IsNullOrEmpty(bruto)) { return list; } string[] array = bruto.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0 && !list.Contains(text)) { list.Add(text); } } return list; } public static string GravarPendentes(List<string> lista) { if (lista == null || lista.Count == 0) { return null; } return string.Join(','.ToString(), lista.ToArray()); } public static bool Adicionar(List<string> lista, string prefab) { if (lista == null || string.IsNullOrEmpty(prefab)) { return false; } if (lista.Contains(prefab)) { return false; } lista.Add(prefab); return true; } public static bool DeveSegurar(string prefab, Func<string, string> chaveDe, Func<string, bool> temChave, out string chave) { chave = null; if (string.IsNullOrEmpty(prefab) || chaveDe == null || temChave == null) { return false; } chave = chaveDe(prefab); if (string.IsNullOrEmpty(chave)) { return false; } return !temChave(chave); } public static void Separar(List<string> pendentes, Func<string, string> chaveDe, Func<string, bool> temChave, out List<string> liberar, out List<string> restantes) { liberar = new List<string>(); restantes = new List<string>(); if (pendentes == null) { return; } for (int i = 0; i < pendentes.Count; i++) { string text = pendentes[i]; if (DeveSegurar(text, chaveDe, temChave, out var _)) { restantes.Add(text); } else { liberar.Add(text); } } } public static List<string> EmChavesGlobais(string bruto, bool par) { List<string> list = new List<string>(); List<string> list2 = LerPendentes(bruto); for (int i = 0; i < list2.Count; i++) { string text = list2[i].Trim(); if (text.Length == 0) { continue; } if (par) { int num = text.IndexOf('='); if (num <= 0 || num == text.Length - 1) { continue; } string text2 = text.Substring(0, num).Trim(); string text3 = text.Substring(num + 1).Trim(); if (text2.Length == 0 || text3.Length == 0) { continue; } text = text2 + "-" + text3; } text = text.ToLowerInvariant(); if (text.IndexOf(' ') < 0 && !list.Contains(text)) { list.Add(text); } } return list; } public static string EmParDeIgual(string chave) { if (string.IsNullOrEmpty(chave)) { return chave; } int num = chave.LastIndexOf('-'); if (num <= 0 || num == chave.Length - 1) { return chave; } return chave.Substring(0, num) + "=" + chave.Substring(num + 1); } public static bool ReceitaPossivel(List<string> ingredientes, bool bastaUm, Func<string, bool> conhece) { if (ingredientes == null || ingredientes.Count == 0 || conhece == null) { return false; } bool result = false; for (int i = 0; i < ingredientes.Count; i++) { string text = ingredientes[i]; if (string.IsNullOrEmpty(text)) { continue; } bool flag = conhece(text); if (bastaUm) { if (flag) { result = true; } } else if (!flag) { return false; } } if (!bastaUm) { return true; } return result; } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("raaotium.recipegate", "RecipeGate", "1.0.11")] public class RecipeGatePlugin : BaseUnityPlugin { public const string GUID = "raaotium.recipegate"; public const string NAME = "RecipeGate"; public const string VERSION = "1.0.11"; internal const string WapGuid = "com.orianaventure.mod.WorldAdvancementProgression"; private const string WapKeyManager = "VentureValheim.Progression.KeyManager"; internal const string PendingKey = "recipegate_pending"; internal const string EnforceKey = "recipegate_on"; internal const string OvrPrefix = "recipegate_ovr-"; internal const string LocPrefix = "recipegate_loc-"; internal static RecipeGatePlugin Instancia; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> Verbose; internal static ConfigEntry<string> Overrides; internal static ConfigEntry<int> UnlockedTier; internal static ConfigEntry<int> ConfirmationTimeout; private static int _manualTier = -1; private static readonly RecipeRefreshQueue _recipeRefresh = new RecipeRefreshQueue(); internal static ConfigEntry<bool> DumpSpawn = null; internal static ConfigEntry<string> Explicar = null; internal static ConfigEntry<bool> GerarRelatorio = null; internal static ConfigEntry<string> IgnorarLocais = null; private static bool _wapChecked; private static object _keyManager; private static FieldInfo _bossItems; private static FieldInfo _materials; private static FieldInfo _foods; private Harmony _harmony; private FileSystemWatcher _watcher; private bool _travaPendente; private float _proximaTentativa; private float _proximaReafirmacao; private static volatile bool _recarregar; private static long _recarregarDepoisUtc; private static string _manuaisBruto; private static Dictionary<string, string> _manuais; private static string _manuaisCanonico = ""; private static string _ultimoErroManual; private static int _frameDasChaves = -1; private static readonly Dictionary<string, bool> _chavesDoFrame = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase); private static bool _estavaLigado = true; private static bool _mapaEstavaPronto; private static SpawnSystem _spawnGuardado; private static float _limiteDeEspera; private static bool _socorroFeito; private static StringBuilder _rastro; internal static string DiretorioDoCache() { return Path.Combine(Paths.BepInExRootPath, "cache", "raaotium.recipegate"); } internal static string CaminhoDeRelatorio(string nome) { string text = Path.Combine(Paths.ConfigPath, "raaotium.recipegate", "reports"); Directory.CreateDirectory(text); return Path.Combine(text, nome); } private static void PrepararArquivosGerados() { try { string path = DiretorioDoCache(); Directory.CreateDirectory(path); string path2 = Path.Combine(Paths.ConfigPath, "recipegate_cache.txt"); if (File.Exists(path2)) { File.Delete(path2); } string[] files = Directory.GetFiles(path, "map-v2.cache.tmp-*"); for (int i = 0; i < files.Length; i++) { File.Delete(files[i]); } string[] array = new string[5] { "spawns", "receitas", "ferramentas", "mapa", "simulacao" }; string[] array2 = new string[5] { "spawns", "recipes", "tools", "map", "simulation" }; for (int j = 0; j < array.Length; j++) { string text = Path.Combine(Paths.ConfigPath, "recipegate_" + array[j] + ".txt"); if (File.Exists(text)) { string text2 = CaminhoDeRelatorio(array2[j] + ".txt"); if (File.Exists(text2)) { File.Delete(text); } else { File.Move(text, text2); } } } } catch (Exception ex) { Log.LogDebug((object)("generated file organization: " + ex.Message)); } } internal static List<string> ChavesDoServidor(string prefixo) { List<string> list = new List<string>(); ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null) { return list; } List<string> globalKeys; try { globalKeys = instance.GetGlobalKeys(); } catch { return list; } if (globalKeys == null) { return list; } for (int i = 0; i < globalKeys.Count; i++) { string text = globalKeys[i]; if (!string.IsNullOrEmpty(text) && text.StartsWith(prefixo, StringComparison.OrdinalIgnoreCase)) { string text2 = text.Substring(prefixo.Length).Trim(); if (text2.Length > 0) { list.Add(text2); } } } list.Sort(StringComparer.OrdinalIgnoreCase); return list; } internal static bool Forcado() { if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { return Rede.EstadoServidorDisponivel; } ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance != (Object)null) { return instance.GetGlobalKey("recipegate_on"); } return false; } private void Awake() { //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Expected O, but got Unknown Instancia = this; Log = ((BaseUnityPlugin)this).Logger; EnglishConfiguration.Migrate(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger); Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Disable this to restore the game's normal recipes. In multiplayer, this option is server-authoritative and reaches clients through RecipeGate's secure channel."); Verbose = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Detailed logging", false, "Records additional diagnostic information."); Overrides = ((BaseUnityPlugin)this).Config.Bind<string>("Server", "Overrides", "", "Exceptional corrections separated by commas: Prefab=key. Accepts nokey, defeated_eikthyr, defeated_gdking, defeated_bonemass, defeated_dragon, defeated_goblinking, defeated_queen, defeated_fader, blocked, and default. In multiplayer, only the authenticated server value is applied."); UnlockedTier = ((BaseUnityPlugin)this).Config.Bind<int>("Server", "Unlocked tier", 0, "Manual fallback: unlock all RecipeGate tiers up to this value without requiring boss keys. 0 = normal progression; 1 = Eikthyr; 2 = The Elder; 3 = Bonemass; 4 = Moder; 5 = Yagluth; 6 = The Queen; 7 = Fader. Only the server value applies in multiplayer. Explicit item overrides take priority. Does not add world keys or bypass normal material discovery. Values outside 0-7 are rejected."); ConfirmationTimeout = ((BaseUnityPlugin)this).Config.Bind<int>("Server", "Confirmation timeout", 60, new ConfigDescription("Seconds a client has to confirm the server policy after joining before the server disconnects it. Raise it if players on slow PCs are kicked with a version error while the world is still loading. Only the server value is used; changes apply to the next players who join.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(20, 600), new object[0])); PrepararArquivosGerados(); Manuais(); try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; _watcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath)); _watcher.Changed += delegate { AgendarRecarga(); }; _watcher.Created += delegate { AgendarRecarga(); }; _watcher.IncludeSubdirectories = false; _watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite; _watcher.EnableRaisingEvents = true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("automatic cfg reload unavailable: " + ex.Message)); } Rede.Registrar(); _harmony = new Harmony("raaotium.recipegate"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)("RecipeGate 1.0.11 loaded — official policy with " + 837 + " items.")); } private static void AgendarRecarga() { Interlocked.Exchange(ref _recarregarDepoisUtc, DateTime.UtcNow.AddMilliseconds(750.0).Ticks); _recarregar = true; } private void OnDestroy() { if (_watcher != null) { _watcher.Dispose(); _watcher = null; } Rede.Esquecer(); if (_harmony != null) { _harmony.UnpatchSelf(); } } internal static void QueueRecipeRefresh() { _chavesDoFrame.Clea