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 BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Utils; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyTitle("RecipeGate")] [assembly: AssemblyProduct("RecipeGate")] [assembly: AssemblyFileVersion("2.3.0.0")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("2.3.0.0")] namespace RecipeGate; 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("dados de cache invalidos"); } byte[] array = RedeNucleo.Comprimir(bruto); if (array.Length == 0 || array.Length > maxComprimido) { throw new InvalidDataException("cache comprimido excede o limite"); } 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("arquivo de cache excede o limite"); } 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("cabecalho de cache invalido"); } 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("cabecalho de cache invalido"); } 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; } } internal static class DumpSpawns { private class Bicho { public string Prefab; public List Biomas = new List(); public List Chaves = new List(); public List Drops = new List(); 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 dictionary = new Dictionary(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 prefabName = Utils.GetPrefabName(val2.m_prefab); if (!dictionary.TryGetValue(prefabName, out var value)) { value = new Bicho(); value.Prefab = prefabName; value.Drops = Drops(val2.m_prefab); dictionary[prefabName] = value; } string text = ((!val2.m_enabled) ? " [desativado]" : "") + (val2.m_devDisabled ? " [devDisabled]" : ""); for (int k = 0; k < TierBiomes.Length; k++) { if ((val2.m_biome & TierBiomes[k]) == 0) { continue; } string item = Nomes[k] + text; 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 list = new List(); 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(Utils.GetPrefabName(((Component)val2.m_resItem).gameObject)); } } if (list.Count <= 0) { return "-"; } return string.Join(" + ", list.ToArray()); } return "-"; } private static void DaTabela(List 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 saida, GameObject item) { if (!((Object)(object)item == (Object)null)) { string prefabName = Utils.GetPrefabName(item); if (!string.IsNullOrEmpty(prefabName) && !saida.Contains(prefabName)) { saida.Add(prefabName); } } } private static List Drops(GameObject prefab) { List list = new List(); CharacterDrop component = prefab.GetComponent(); 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 prefabName = Utils.GetPrefabName(val.m_prefab); if (!list.Contains(prefabName)) { list.Add(prefabName); } } } return list; } private static void Salvar(Dictionary bichos, int entradas) { try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# RecipeGate - lista de spawn lida do jogo"); stringBuilder.AppendLine("# gerado em " + DateTime.Now.ToString("yyyy-MM-dd HH:mm")); stringBuilder.AppendLine("# fonte: SpawnSystem.m_spawnLists (a mesma que o UpdateSpawning percorre)"); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# " + bichos.Count + " criaturas em " + entradas + " entradas de spawn"); stringBuilder.AppendLine(); List list = new List(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("## criaturas em mais de um tier (a regra do menor pode enganar aqui)"); 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(" biomas: " + string.Join(", ", bicho.Biomas.ToArray())); if (bicho.Chaves.Count > 0) { stringBuilder.AppendLine(" exige chave: " + string.Join(", ", bicho.Chaves.ToArray())); } if (bicho.Drops.Count > 0) { stringBuilder.AppendLine(" larga: " + string.Join(", ", bicho.Drops.ToArray())); } } } if (num == 0) { stringBuilder.AppendLine(" (nenhuma)"); } stringBuilder.AppendLine(); stringBuilder.AppendLine("## todas as criaturas"); 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(" biomas: " + string.Join(", ", bicho2.Biomas.ToArray())); if (bicho2.Chaves.Count > 0) { stringBuilder.AppendLine(" exige chave: " + string.Join(", ", bicho2.Chaves.ToArray())); } if (bicho2.Drops.Count > 0) { stringBuilder.AppendLine(" larga: " + string.Join(", ", bicho2.Drops.ToArray())); } } string text2 = RecipeGatePlugin.CaminhoDeRelatorio("spawns.txt"); File.WriteAllText(text2, stringBuilder.ToString()); RecipeGatePlugin.Log.LogInfo((object)("dump de spawn escrito em " + text2 + " (" + bichos.Count + " criaturas, " + num + " atravessando tier).")); } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("nao consegui escrever o dump: " + ex.Message)); } } } [HarmonyPatch(typeof(SpawnSystem), "Awake")] internal static class SpawnSystemAwakeDumpPatch { private static void Postfix(SpawnSystem __instance) { try { if (RecipeGatePlugin.DumpSpawn.Value) { DumpSpawns.Escrever(__instance); } } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("falha no dump de spawn: " + 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 mapa) { mapa = null; if (string.IsNullOrEmpty(texto) || texto.Length > 4194304) { return false; } Dictionary dictionary = new Dictionary(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; internal static Dictionary 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 _marcosAnteriores; private static readonly List Tempos = new List(); private static readonly Dictionary TierDoTema = new Dictionary(); private static string[] _ignorar; private static readonly List Pisos = new List(); internal static int Desativados; private static Dictionary _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 Utils.GetPrefabName(go); } return null; } internal static void RefazerSePreciso() { if (!((Object)(object)_sistema == (Object)null) && (ListaMudou() || !string.Equals(_assinaturaAtual, Assinatura(_sistema), StringComparison.Ordinal))) { RecipeGatePlugin.Detalhe("os dados ou configs mudaram; invalidando o cache e refazendo o mapa."); Construir(_sistema); } } internal static void Esquecer() { Derivado = null; Pronto = false; _sistema = null; _assinaturaAtual = null; _ignorar = null; } internal static void Construir(SpawnSystem sistema) { _sistema = sistema; float realtimeSinceStartup = Time.realtimeSinceStartup; string assinatura = (_assinaturaAtual = Assinatura(sistema)); if (LerDoCache(assinatura)) { Pronto = Derivado != null && Derivado.Count > 0; RecipeGatePlugin.Log.LogInfo((object)("mapa pronto: " + Derivado.Count + " materiais (cache).")); RecipeGatePlugin.Detalhe("mapa lido do cache em " + ((Time.realtimeSinceStartup - realtimeSinceStartup) * 1000f).ToString("0") + "ms; nada mudou nos dados do jogo."); Rede.PublicarMapaAtualizado(); return; } List fontes = new List(); List receitas = new List(); List ferramentas = new List(); List extensoes = new List(); Pisos.Clear(); Tempos.Clear(); Desativados = 0; _ignorar = null; Tenta("vegetacao", delegate { DoChao(fontes); }); Tenta("criaturas", delegate { DasCriaturas(fontes, sistema); }); Tenta("localizacoes", delegate { DosLocais(fontes); }); Tenta("bosses", delegate { DosBosses(fontes); }); Tenta("salas", delegate { DasSalas(fontes); }); Tenta("peixes", delegate { DosPeixes(fontes); }); Tenta("receitas", delegate { DasReceitas(receitas, ferramentas, extensoes); }); fontes.AddRange(Pisos); float realtimeSinceStartup2 = Time.realtimeSinceStartup; Derivado = MapaNucleo.Resolver(fontes, receitas, ferramentas, extensoes, 20); Tempos.Add("resolver " + ((Time.realtimeSinceStartup - realtimeSinceStartup2) * 1000f).ToString("0") + "ms"); Pronto = Derivado != null && Derivado.Count > 0; RecipeGatePlugin.Log.LogInfo((object)("mapa pronto: " + Derivado.Count + " materiais em " + (Time.realtimeSinceStartup - realtimeSinceStartup).ToString("0.0") + "s.")); RecipeGatePlugin.Detalhe("mapa derivado de " + fontes.Count + " fontes, " + receitas.Count + " receitas e " + extensoes.Count + " melhorias de estacao (" + Desativados + " colheitas ignoradas por filho desativado)."); RecipeGatePlugin.Detalhe("tempo por etapa: " + string.Join(", ", Tempos.ToArray())); Explicar(fontes, receitas); string text = MapaNucleo.Conferir(Derivado, RecipeGatePlugin.TabelaDoWap(), RecipeGatePlugin.ChaveDoMaterial); if (!string.IsNullOrEmpty(text)) { RecipeGatePlugin.Detalhe(text); } GravarCache(assinatura); Despejar(receitas, ferramentas); if (RecipeGatePlugin.GerarRelatorio.Value) { Escrever(); } Rede.PublicarMapaAtualizado(); } private static void Despejar(List receitas, List ferramentas) { if (!RecipeGatePlugin.DumpSpawn.Value) { return; } try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# RecipeGate - receitas, como a formula as viu"); stringBuilder.AppendLine("# formato: produto | estacao nivel N | ingrediente + ingrediente"); stringBuilder.AppendLine(); List list = new List(); 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 + " nivel " + 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("receitas.txt"), stringBuilder.ToString()); stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# RecipeGate - ferramentas: nivel e que dano fazem"); 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) + " nivel " + ferramenta.Nivel + (ferramenta.Corta ? " corta" : "") + (ferramenta.Escava ? " escava" : "") + ((!ferramenta.Corta && !ferramenta.Escava) ? " (nao serve de ferramenta)" : "")); } } list.Sort(StringComparer.OrdinalIgnoreCase); for (int l = 0; l < list.Count; l++) { stringBuilder.AppendLine(list[l]); } File.WriteAllText(RecipeGatePlugin.CaminhoDeRelatorio("ferramentas.txt"), stringBuilder.ToString()); } catch (Exception ex) { RecipeGatePlugin.Log.LogWarning((object)("despejo: " + ex.Message)); } } private static string CaminhoDoCache() { return Path.Combine(RecipeGatePlugin.DiretorioDoCache(), "map-v2.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 list = new List(); h = Mistura(h, VersaoDoJogo()); h = Mistura(h, "2.3.0"); try { h = Mistura(h, typeof(Mapa).Module.ModuleVersionId.ToString()); } catch { } List list2 = new List(); foreach (KeyValuePair 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, "itens" + 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("itens:" + 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, "receitas" + 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("receitas:" + 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(); 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("ferramentas:" + h.ToString("x16")); ZoneSystem instance3 = ZoneSystem.instance; if ((Object)(object)instance3 != (Object)null && instance3.m_locations != null) { h = Mistura(h, "locais" + 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("locais:" + 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("ignorados:" + h.ToString("x16")); h = MisturaConfiguracoes(h); list.Add("configs:" + h.ToString("x16")); ConferirMarcos(list); return h.ToString("x16"); } private static void ConferirMarcos(List marcos) { List marcosAnteriores = _marcosAnteriores; _marcosAnteriores = marcos; if (marcosAnteriores == null) { return; } List list = new List(); 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("assinatura mudou a partir de '" + list[0] + "' (arrastou: " + string.Join(", ", list.ToArray()) + ")."); } } private static ulong MisturaConfiguracoes(ulong h) { try { string[] files = Directory.GetFiles(Paths.ConfigPath, "*", SearchOption.AllDirectories); Array.Sort(files, (IComparer?)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)("nao consegui conferir a data das configs; o cache pode ficar conservador (" + 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 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("cache principal invalido; copia de recuperacao aceita."); return true; } return false; } private static bool LerArquivoDoCache(string caminho, string assinatura) { try { FileInfo fileInfo = new FileInfo(caminho); if (!fileInfo.Exists || fileInfo.Length <= 0 || fileInfo.Length > 262144) { return false; } if (!CacheNucleo.TentarLer(File.ReadAllBytes(caminho), "2.3.0", assinatura, 4194304, 245760, out var quantas, out var bruto)) { return false; } if (!DeTexto(Encoding.UTF8.GetString(bruto), quantas) || Derivado == null || Derivado.Count != quantas) { Derivado = null; Pronto = false; return false; } _ignorar = ListaDeIgnorados(); return true; } catch (Exception ex) { RecipeGatePlugin.Detalhe("cache ignorado: " + ex.Message); return false; } } private static void GravarCache(string assinatura) { string text = null; try { if (Derivado == null || Derivado.Count == 0) { return; } string text2 = CaminhoDoCache(); Directory.CreateDirectory(Path.GetDirectoryName(text2)); byte[] bytes = Encoding.UTF8.GetBytes(EmTexto()); byte[] array = CacheNucleo.Montar("2.3.0", assinatura, Derivado.Count, bytes, 4194304, 245760); text = text2 + ".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(text2)) { try { File.Replace(text, text2, text2 + ".bak", ignoreMetadataErrors: true); text = null; return; } catch (PlatformNotSupportedException) { File.Copy(text2, text2 + ".bak", overwrite: true); File.Copy(text, text2, overwrite: true); return; } catch (IOException) { File.Copy(text2, text2 + ".bak", overwrite: true); File.Copy(text, text2, overwrite: true); return; } } File.Move(text, text2); text = null; } catch (Exception ex3) { RecipeGatePlugin.Log.LogWarning((object)("cache nao gravado: " + 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 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 list = new List(); List list2 = new List(); 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, "chao", 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, "chao", onde, fraca: true); fonte2.TipoFerramenta = tipo; fontes.Add(fonte2); } } } } private static void DasCriaturas(List 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 list = new List(); List list2 = new List(); 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, "bicho", onde, fraca: false)); } for (int l = 0; l < list2.Count; l++) { fontes.Add(new Fonte(list2[l], num, 0, "bicho", onde, fraca: true)); } } } } } private static void DosBosses(List 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(); 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(); 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 lidos pela chave de derrota."); } } private static void DosLocais(List 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 list = new List(); List list2 = new List(); 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(); 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(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, "local", val.m_prefabName, fraca: false)); } for (int m = 0; m < list2.Count; m++) { fontes.Add(new Fonte(list2[m], num, 0, "local", val.m_prefabName, fraca: true)); } } } private static void DasSalas(List 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(); 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 list = new List(); List list2 = new List(); 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)("sala: " + ex.Message)); goto IL_013e; } finally { if (flag) { try { val2.m_prefab.Release(); } catch { } } } IL_013e: string onde = "sala " + val2.m_theme; for (int k = 0; k < list.Count; k++) { fontes.Add(new Fonte(list[k], value, 0, "sala", onde, fraca: false)); } for (int l = 0; l < list2.Count; l++) { fontes.Add(new Fonte(list2[l], value, 0, "sala", onde, fraca: true)); } } } RecipeGatePlugin.Detalhe(num + " salas de masmorra lidas, em " + TierDoTema.Count + " temas."); } internal static string[] ListaDeIgnorados() { List list = new List(); 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, "loja", 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 natural, List bau, HashSet 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(); } if (!vistos.Add(((Object)raiz).GetInstanceID())) { return; } Pickable[] componentsInChildren = raiz.GetComponentsInChildren(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(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 (mineravel)"; MineRock5[] componentsInChildren3 = raiz.GetComponentsInChildren(true); for (int l = 0; l < componentsInChildren3.Length; l++) { DaTabela(natural, componentsInChildren3[l].m_dropItems); } _mecanismo = "MineRock (mineravel)"; MineRock[] componentsInChildren4 = raiz.GetComponentsInChildren(true); for (int m = 0; m < componentsInChildren4.Length; m++) { DaTabela(natural, componentsInChildren4[m].m_dropItems); } _mecanismo = "TreeBase (arvore)"; TreeBase[] componentsInChildren5 = raiz.GetComponentsInChildren(true); for (int n = 0; n < componentsInChildren5.Length; n++) { DaTabela(natural, componentsInChildren5[n].m_dropWhenDestroyed); string mecanismo = _mecanismo; _mecanismo = "cadeia: arvore vira tronco " + 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 (tronco)"; TreeLog[] componentsInChildren6 = raiz.GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren6.Length; num++) { DaTabela(natural, componentsInChildren6[num].m_dropWhenDestroyed); string mecanismo2 = _mecanismo; _mecanismo = "cadeia: tronco parte em " + Nome(componentsInChildren6[num].m_subLogPrefab); Varrer(componentsInChildren6[num].m_subLogPrefab, natural, bau, vistos, nivel + 1); _mecanismo = mecanismo2; } _mecanismo = "DropOnDestroyed"; DropOnDestroyed[] componentsInChildren7 = raiz.GetComponentsInChildren(true); for (int num2 = 0; num2 < componentsInChildren7.Length; num2++) { DaTabela(natural, componentsInChildren7[num2].m_dropWhenDestroyed); } _mecanismo = "CharacterDrop (larga ao morrer)"; CharacterDrop[] componentsInChildren8 = raiz.GetComponentsInChildren(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 (bau)"; Container[] componentsInChildren9 = raiz.GetComponentsInChildren(true); for (int num5 = 0; num5 < componentsInChildren9.Length; num5++) { DaTabela(bau, componentsInChildren9[num5].m_defaultItems); } _mecanismo = "CreatureSpawner"; CreatureSpawner[] componentsInChildren10 = raiz.GetComponentsInChildren(true); for (int num6 = 0; num6 < componentsInChildren10.Length; num6++) { Varrer(componentsInChildren10[num6].m_creaturePrefab, natural, bau, vistos, nivel + 1); } _mecanismo = "SpawnArea (ninho)"; SpawnArea[] componentsInChildren11 = raiz.GetComponentsInChildren(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(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(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 (loja)"; Trader[] componentsInChildren14 = raiz.GetComponentsInChildren(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, "loja: " + Nome(raiz)); } else { Junta(natural, ((Component)val4.m_prefab).gameObject); } } } } _mecanismo = "Beehive"; Beehive[] componentsInChildren15 = raiz.GetComponentsInChildren(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(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(true); for (int num17 = 0; num17 < componentsInChildren17.Length; num17++) { string mecanismo3 = _mecanismo; _mecanismo = "cadeia: destruido vira " + 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 action = delegate(int exigido, int deQueTipo) { if (exigido > maior) { maior = exigido; tipoMaior = deQueTipo; } }; TreeBase[] componentsInChildren = go.GetComponentsInChildren(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(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(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(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(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 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 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 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(); if (!((Object)(object)component == (Object)null)) { string onde = "peixe: " + Nome(val); if ((Object)(object)val.GetComponent() != (Object)null) { fontes.Add(new Fonte(Nome(val), 0, 0, "mar", onde, fraca: false)); } if ((Object)(object)component.m_pickupItem != (Object)null) { fontes.Add(new Fonte(Nome(component.m_pickupItem), 0, 0, "mar", onde, fraca: false)); } } } } private static void DasReceitas(List receitas, List ferramentas, List 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 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 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(); 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 receitas, GameObject go) { string text = Nome(go); SapCollector component = go.GetComponent(); 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(); 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(); if ((Object)(object)component3 != (Object)null && (Object)(object)component3.m_wispPrefab != (Object)null) { RendeComoReceita(receitas, component3.m_wispPrefab, text); } CreatureSpawner component4 = go.GetComponent(); if ((Object)(object)component4 != (Object)null && (Object)(object)component4.m_creaturePrefab != (Object)null && (Object)(object)go.GetComponent() != (Object)null) { RendeComoReceita(receitas, component4.m_creaturePrefab, text); } } private static void DaCriacao(List receitas, GameObject go) { EggGrow component = go.GetComponent(); 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(); 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 receitas, GameObject go) { string estacao = Nome(go); Smelter component = go.GetComponent(); 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(); 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(); 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 receitas, GameObject go) { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) Plant component = go.GetComponent(); if ((Object)(object)component == (Object)null || component.m_grownPrefabs == null) { return; } Piece component2 = go.GetComponent(); if ((Object)(object)component2 == (Object)null || component2.m_resources == null) { return; } List list = new List(); 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 list2 = new List(); List bau = new List(); 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(list); receita.Piso = TierDoBioma(component.m_biome); receitas.Add(receita); } } } } private static void DaConstrucao(List receitas, List 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(); 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(); 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 receitas, GameObject rende, string fonte) { if ((Object)(object)rende == (Object)null || string.IsNullOrEmpty(fonte)) { return; } List list = new List(); List bau = new List(); 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 receitas, GameObject criatura) { if ((Object)(object)criatura == (Object)null) { return; } CharacterDrop component = criatura.GetComponent(); 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 fontes, List 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)(" VENCEU tier " + value2.Tier + " " + value2.Origem + ": " + value2.Onde + (value2.Fraca ? " [FRACO]" : " [forte]"))); } 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)(" fonte tier " + fonte.Tier + " " + fonte.Origem + ": " + fonte.Onde + (fonte.Fraca ? " (bau)" : "") + (fonte.Piso ? " (piso)" : "") + ((fonte.Ferramenta > 0) ? (" ferramenta " + 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 ? "sai de" : "entra em") + " " + receita.Produto + " = " + string.Join(" + ", receita.Ingredientes.ToArray()) + (string.IsNullOrEmpty(receita.Estacao) ? "" : (" @" + receita.Estacao)) + ((receita.NivelEstacao > 1) ? (" nv" + receita.NivelEstacao) : "") + (receita.QualquerUm ? " (basta um)" : "") + ((receita.Piso > 0) ? (" (so em " + 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 list = new List(); List list2 = new List(); _como = new Dictionary(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)(" produz " + Nome(val) + " por " + value + ((flag2 && !flag) ? " (dentro de bau)" : ""))); } } } if (num == 0) { RecipeGatePlugin.Log.LogInfo((object)" NINGUEM produz isto em prefab nenhum do jogo."); } else if (num > 20) { RecipeGatePlugin.Log.LogInfo((object)(" ... e mais " + (num - 20) + " prefabs.")); } } internal static void Escrever() { try { if (Derivado == null) { return; } List list = new List(Derivado.Keys); list.Sort(StringComparer.OrdinalIgnoreCase); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# RecipeGate - mapa derivado dos dados do jogo"); stringBuilder.AppendLine("# " + DateTime.Now.ToString("yyyy-MM-dd HH:mm") + " | " + Derivado.Count + " materiais"); stringBuilder.AppendLine("#"); stringBuilder.AppendLine("# tier = MENOR entre as formas de obter, cada uma valendo"); stringBuilder.AppendLine("# MAX(bioma, ferramenta ou estacao exigida)"); stringBuilder.AppendLine("# bau conta so quando nao ha nenhuma outra origem"); stringBuilder.AppendLine(); for (int i = 0; i < MapaNucleo.Biomas.Length; i++) { List list2 = new List(); 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) + " (" + ((text == null) ? "livre" : ("exige " + text)) + ") " + list2.Count + " materiais"); 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("mapa.txt"), stringBuilder.ToString()); RecipeGatePlugin.Detalhe("relatorio do mapa escrito na pasta de relatorios."); } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("falha ao escrever o relatorio: " + 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 Ingredientes = new List(); 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(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] { null, "defeated_eikthyr", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking", "defeated_queen", "defeated_fader" }; private static Dictionary _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 = 1; i < ChavePorTier.Length; i++) { if (string.Equals(ChavePorTier[i], chave, StringComparison.OrdinalIgnoreCase)) { return i; } } return 0; } public static Dictionary Resolver(List fontes, List receitas, List ferramentas, int maxVoltas) { return Resolver(fontes, receitas, ferramentas, null, maxVoltas); } public static Dictionary Resolver(List fontes, List receitas, List ferramentas, List extensoes, int maxVoltas) { if (extensoes == null) { extensoes = new List(); } _piso = new Dictionary(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 dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); if (fontes == null) { fontes = new List(); } if (receitas == null) { receitas = new List(); } if (ferramentas == null) { ferramentas = new List(); } HashSet hashSet = new HashSet(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 dictionary2 = new Dictionary(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 ? "bau" : 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, "receita", 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, "receita", Descrever(receita2) + " [parcial]", 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, "bau", 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 extensoes, Dictionary a, Dictionary b) { if (nivel <= 1 || extensoes.Count == 0) { return 0; } List list = new List(); 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 + " nv" + r.NivelEstacao; } } if (r.Piso > 0) { text = text + " so em " + NomeDoTier(r.Piso); } return text; } private static bool EhFraca(string nome, Dictionary a, Dictionary 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 a, Dictionary 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 mapa, string prefab, int t, string origem, string onde) { return Melhor(mapa, prefab, t, origem, onde, fraca: false); } private static bool Melhor(Dictionary 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 ferramentas, Dictionary 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 a, Dictionary b) { if (a.Count != b.Count) { return false; } foreach (KeyValuePair 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 derivado, Dictionary wap) { return Conferir(derivado, wap, null); } public static string Conferir(Dictionary derivado, Dictionary wap, Func efetiva) { StringBuilder stringBuilder = new StringBuilder(); if (derivado == null || wap == null) { return ""; } List list = new List(); List list2 = new List(); List list3 = new List(); foreach (KeyValuePair 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 + ": derivado=" + (text ?? "livre") + " wap=" + item.Value + " (" + (flag ? "na mao" : (value.Origem + ": " + value.Onde)) + ")"); } stringBuilder.AppendLine("conferencia com o WAP: " + list.Count + " iguais, " + list2.Count + " diferentes, " + list3.Count + " sem origem derivada"); for (int i = 0; i < list2.Count; i++) { stringBuilder.AppendLine(" " + list2[i]); } if (list3.Count > 0) { stringBuilder.AppendLine(" sem origem: " + string.Join(", ", list3.ToArray())); } return stringBuilder.ToString(); } } public static class Nucleo { public const char Separador = ','; public static List LerPendentes(string bruto) { List list = new List(); 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 lista) { if (lista == null || lista.Count == 0) { return null; } return string.Join(','.ToString(), lista.ToArray()); } public static bool Adicionar(List 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 chaveDe, Func 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 pendentes, Func chaveDe, Func temChave, out List liberar, out List restantes) { liberar = new List(); restantes = new List(); 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 EmChavesGlobais(string bruto, bool par) { List list = new List(); List 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 ingredientes, bool bastaUm, Func 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; } } [BepInPlugin("raaotium.recipegate", "RecipeGate", "2.3.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class RecipeGatePlugin : BaseUnityPlugin { public const string GUID = "raaotium.recipegate"; public const string NAME = "RecipeGate"; public const string VERSION = "2.3.0"; internal const string WapGuid = "com.orianaventure.mod.WorldAdvancementProgression"; internal const string JotunnGuid = "com.jotunn.jotunn"; 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 Enabled; internal static ConfigEntry Verbose; internal static ConfigEntry Overrides; internal static ConfigEntry DumpSpawn; internal static ConfigEntry Explicar; internal static ConfigEntry GerarRelatorio; internal static ConfigEntry IgnorarLocais; 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 string _manuaisBruto; private static Dictionary _manuais; private static int _frameDasChaves = -1; private static readonly Dictionary _chavesDoFrame = new Dictionary(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" }; 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(array[j] + ".txt"); if (File.Exists(text2)) { File.Delete(text); } else { File.Move(text, text2); } } } } catch (Exception ex) { Log.LogDebug((object)("organizacao dos arquivos gerados: " + ex.Message)); } } internal static List ChavesDoServidor(string prefixo) { List list = new List(); ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null) { return list; } List 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.Recebido; } ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance != (Object)null) { return instance.GetGlobalKey("recipegate_on"); } return false; } private void Awake() { //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Expected O, but got Unknown Instancia = this; Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind("Geral", "Ativo", true, "Desligue para as receitas voltarem ao normal do jogo. Em multiplayer esta opcao e autoritativa no servidor e chega aos clientes pelo canal seguro do RecipeGate."); Verbose = ((BaseUnityPlugin)this).Config.Bind("Geral", "Log detalhado", false, "Registra no log cada decisao da trava e cada recalculo do mapa."); Overrides = ((BaseUnityPlugin)this).Config.Bind("Mapa", "Materiais na mao", "DvergrKeyFragment=defeated_goblinking", "Prefab=chave, separado por virgula. Ganha de tudo. Serve para material que nenhuma tabela conhece. Em multiplayer vale exclusivamente a configuracao autenticada do servidor."); IgnorarLocais = ((BaseUnityPlugin)this).Config.Bind("Mapa", "Ignorar localizacoes", "Dev", "Prefixos de nome de localizacao a ignorar ao montar o mapa, separados por virgula. Em multiplayer somente o servidor monta o mapa."); GerarRelatorio = ((BaseUnityPlugin)this).Config.Bind("Mapa", "Gerar relatorio", false, "Escreve BepInEx/config/raaotium.recipegate/reports/mapa.txt com o mapa derivado inteiro e a conferencia contra a tabela do WAP."); DumpSpawn = ((BaseUnityPlugin)this).Config.Bind("Diagnostico", "Gerar dump de spawn", false, "Escreve arquivos de leitura em BepInEx/config/raaotium.recipegate/reports. Nao muda nada. Ligue, entre uma vez, desligue."); Explicar = ((BaseUnityPlugin)this).Config.Bind("Diagnostico", "Explicar materiais", "", "Lista separada por virgula. Para cada material citado, o log mostra TODAS as fontes e receitas que falam dele, nao so a origem vencedora. Serve pra entender por que um item caiu no tier em que caiu. Ex: ChickenEgg,Chicken"); PrepararArquivosGerados(); try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; _watcher = new FileSystemWatcher(Path.GetDirectoryName(configFilePath), Path.GetFileName(configFilePath)); _watcher.Changed += delegate { _recarregar = true; }; _watcher.IncludeSubdirectories = false; _watcher.NotifyFilter = NotifyFilters.LastWrite; _watcher.EnableRaisingEvents = true; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("sem recarga automatica do cfg: " + ex.Message)); } Rede.Registrar(); _harmony = new Harmony("raaotium.recipegate"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"RecipeGate 2.3.0 carregado — sync direto e falha fechada."); } private void OnDestroy() { if (_watcher != null) { _watcher.Dispose(); _watcher = null; } Rede.Esquecer(); if (_harmony != null) { _harmony.UnpatchSelf(); } } private void Update() { Rede.Atualizar(); if (_travaPendente && Time.realtimeSinceStartup >= _proximaTentativa) { _proximaTentativa = Time.realtimeSinceStartup + 5f; if (PublicarTrava()) { _travaPendente = false; } } if (Mapa.Pronto != _mapaEstavaPronto) { _mapaEstavaPronto = Mapa.Pronto; if (Ligado() && (Object)(object)Player.m_localPlayer != (Object)null) { Trava.AtualizarReceitas(Player.m_localPlayer); } } if (_recarregar) { _recarregar = false; try { ((BaseUnityPlugin)this).Config.Reload(); Mapa.RefazerSePreciso(); Detalhe("cfg relido em tempo real."); _proximaReafirmacao = 0f; } catch (Exception ex) { Log.LogWarning((object)("falha ao reler o cfg: " + ex.Message)); } } SocorroSeOMapaNaoVeio(); bool flag = Ligado(); if (flag != _estavaLigado) { _estavaLigado = flag; Log.LogWarning((object)("RecipeGate " + (flag ? "LIGADO" : "DESLIGADO") + " em tempo real.")); } if (IsServer() && Time.realtimeSinceStartup >= _proximaReafirmacao) { _proximaReafirmacao = Time.realtimeSinceStartup + 30f; PublicarTrava(); } } internal void PedirTrava() { _travaPendente = true; _proximaTentativa = 0f; } private static bool WapPronto() { if (_wapChecked) { return _keyManager != null; } _wapChecked = true; try { Type type = AccessTools.TypeByName("VentureValheim.Progression.KeyManager"); if (type == null) { Detalhe("World Advancement Progression nao encontrado; sem conferencia, mas o mapa derivado basta."); return false; } PropertyInfo propertyInfo = AccessTools.Property(type, "Instance"); _keyManager = ((propertyInfo != null) ? propertyInfo.GetValue(null, null) : null); _bossItems = AccessTools.Field(type, "BossItemKeysList"); _materials = AccessTools.Field(type, "MaterialKeysList"); _foods = AccessTools.Field(type, "FoodKeysList"); if (_keyManager == null || _materials == null) { Log.LogWarning((object)"o WAP esta aqui mas com formato diferente do esperado; RecipeGate fica sem a conferencia, mas o mapa derivado basta."); _keyManager = null; return false; } Detalhe("WAP encontrado; as tabelas dele entram so como conferencia do mapa derivado."); return true; } catch (Exception ex) { Log.LogError((object)("falha ao encaixar no WAP (" + ex.Message + "); RecipeGate inerte.")); _keyManager = null; return false; } } private static Dictionary Tabela(FieldInfo campo) { if (campo == null || _keyManager == null) { return null; } return campo.GetValue(_keyManager) as Dictionary; } private static Dictionary Manuais() { string text = (((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) ? Rede.OverridesServidor : Overrides.Value); text = text ?? ""; if (_manuais != null && text == _manuaisBruto) { return _manuais; } _manuaisBruto = text; _manuais = new Dictionary(StringComparer.OrdinalIgnoreCase); List list = Nucleo.LerPendentes(text); for (int i = 0; i < list.Count; i++) { string text2 = list[i]; int num = text2.IndexOf('='); if (num <= 0) { Log.LogWarning((object)("ignorando '" + text2 + "': use 'Prefab=chave'")); continue; } string text3 = text2.Substring(0, num).Trim(); string text4 = text2.Substring(num + 1).Trim(); if (text3.Length > 0 && text4.Length > 0) { _manuais[text3] = text4; } } if (_manuais.Count > 0) { Detalhe(_manuais.Count + " material(is) mapeados na mao."); } return _manuais; } internal static Dictionary TabelaDoWap() { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); if (!WapPronto()) { return dictionary; } FieldInfo[] array = new FieldInfo[3] { _bossItems, _materials, _foods }; for (int i = 0; i < array.Length; i++) { Dictionary dictionary2 = Tabela(array[i]); if (dictionary2 == null) { continue; } foreach (KeyValuePair item in dictionary2) { dictionary[item.Key] = item.Value; } } return dictionary; } internal static string ChaveDoMaterial(string prefab) { if (string.IsNullOrEmpty(prefab)) { return null; } if (Manuais().TryGetValue(prefab, out var value)) { return value; } if (!Mapa.Pronto || Mapa.Derivado == null) { return null; } if (!Mapa.Derivado.TryGetValue(prefab, out var value2)) { return null; } return MapaNucleo.ChaveDoTier(value2.Tier); } internal static bool TemChave(string chave) { if (string.IsNullOrEmpty(chave)) { return true; } int frameCount = Time.frameCount; if (frameCount != _frameDasChaves) { _chavesDoFrame.Clear(); _frameDasChaves = frameCount; } if (_chavesDoFrame.TryGetValue(chave, out var value)) { return value; } try { ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null) { return false; } bool globalKey = instance.GetGlobalKey(chave); _chavesDoFrame[chave] = globalKey; return globalKey; } catch (Exception ex) { Log.LogWarning((object)("nao consegui ler a chave '" + chave + "' (" + ex.Message + "); segurando por precaucao.")); return false; } } internal static bool Ligado() { ZNet instance = ZNet.instance; if ((Object)(object)instance == (Object)null) { return Enabled.Value; } if (instance.IsServer()) { return Enabled.Value; } if (!Rede.Recebido) { return true; } return Rede.ServidorLigado; } internal static void MigrarEspera(Player player) { if ((Object)(object)player == (Object)null || player.m_customData == null || !player.m_customData.TryGetValue("recipegate_pending", out var value)) { return; } List list = Nucleo.LerPendentes(value); player.m_customData.Remove("recipegate_pending"); ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || list.Count == 0) { return; } int num = 0; for (int i = 0; i < list.Count; i++) { try { GameObject itemPrefab = instance.GetItemPrefab(list[i]); ItemDrop val = (((Object)(object)itemPrefab == (Object)null) ? null : itemPrefab.GetComponent()); if (!((Object)(object)val == (Object)null)) { player.AddKnownItem(val.m_itemData); num++; } } catch { } } Log.LogWarning((object)("migracao da geracao 1: " + num + " material(is) da lista de espera voltaram a ser conhecidos. Quem tranca agora e a receita.")); } internal static void GuardarSpawnSystem(SpawnSystem s) { _spawnGuardado = s; _limiteDeEspera = Time.realtimeSinceStartup + 30f; } internal static bool EsperandoPacote() { return (Object)(object)_spawnGuardado != (Object)null; } internal static void EsquecerMundo() { Mapa.Esquecer(); Rede.EsquecerEstadoDoMundo(); _spawnGuardado = null; _socorroFeito = false; _limiteDeEspera = 0f; _estavaLigado = true; _mapaEstavaPronto = false; } private static void SocorroSeOMapaNaoVeio() { if (!Mapa.Pronto && !((Object)(object)_spawnGuardado == (Object)null) && !_socorroFeito && !(Time.realtimeSinceStartup < _limiteDeEspera)) { Log.LogError((object)"o mapa autenticado do servidor nao chegou em 30s; mantendo todas as receitas travadas. Nao vou derivar localmente nem confiar no cfg do cliente."); _socorroFeito = true; } } internal static bool EsperandoMapa() { if (Ligado()) { return !Mapa.Pronto; } return false; } internal static void Diagnostico(Terminal saida) { Action action = delegate(string t) { if ((Object)(object)saida != (Object)null) { saida.AddString(t); } Log.LogInfo((object)t); }; action("=== RecipeGate 2.3.0 ==="); if (!Mapa.Pronto || Mapa.Derivado == null) { action("mapa: AINDA NAO. " + (Rede.Recebido ? "" : "esperando o pacote do servidor. ") + "Tudo esta sendo segurado."); return; } string text = (Rede.Recebido ? "recebido pelo canal direto do servidor" : (IsServer() ? "derivado aqui (servidor)" : "indisponivel")); action("mapa: " + Mapa.Derivado.Count + " materiais, " + text); action("ligado: " + (Ligado() ? "sim" : "NAO") + (Forcado() ? " (estado autenticado do servidor; cfg local ignorado)" : " (cfg local)")); List list = new List(); for (int num = 1; num < MapaNucleo.ChavePorTier.Length; num++) { if (TemChave(MapaNucleo.ChavePorTier[num])) { list.Add(MapaNucleo.ChavePorTier[num]); } } action("bosses derrotados: " + ((list.Count == 0) ? "nenhum" : string.Join(", ", list.ToArray()))); int[] array = new int[MapaNucleo.ChavePorTier.Length]; string[] array2 = new string[MapaNucleo.ChavePorTier.Length]; int num2 = 0; foreach (KeyValuePair item in Mapa.Derivado) { if (!Nucleo.DeveSegurar(item.Key, ChaveDoMaterial, TemChave, out var _)) { continue; } num2++; int tier = item.Value.Tier; if (tier >= 0 && tier < array.Length) { array[tier]++; if (array2[tier] == null) { array2[tier] = item.Key; } } } action("seguraria agora: " + num2 + " de " + Mapa.Derivado.Count); for (int num3 = 1; num3 < array.Length; num3++) { if (array[num3] != 0) { action(" " + MapaNucleo.NomeDoTier(num3).PadRight(12) + array[num3].ToString().PadLeft(5) + " (ex: " + array2[num3] + ", pede " + MapaNucleo.ChaveDoTier(num3) + ")"); } } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { action("sem personagem local; nada mais a mostrar."); return; } ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || instance.m_recipes == null) { return; } int num4 = 0; List list2 = new List(); for (int num5 = 0; num5 < instance.m_recipes.Count; num5++) { Recipe val = instance.m_recipes[num5]; if (!((Object)(object)val == (Object)null) && val.m_enabled && !((Object)(object)val.m_item == (Object)null) && Trava.TrancadaReceita(val)) { num4++; if (list2.Count < 8) { list2.Add(Utils.GetPrefabName(((Component)val.m_item).gameObject)); } } } action("receitas trancadas agora: " + num4 + " de " + instance.m_recipes.Count + " " + Alguns(list2, 8)); action("nada disso esta gravado no personagem: caiu a chave, a receita reaparece."); } private static void RelatarForaDoMapa(ObjectDB db, List itens, Action diz) { List list = new List(); for (int i = 0; i < itens.Count; i++) { if (!Mapa.Derivado.ContainsKey(itens[i])) { list.Add(itens[i]); } } diz("=== simulacao da progressao (" + itens.Count + " itens do jogo) ==="); diz(" sem origem derivada, passam livres: " + list.Count + " " + Alguns(list, 12)); List list2 = new List(); if (db.m_recipes != null) { for (int j = 0; j < db.m_recipes.Count; j++) { Recipe val = db.m_recipes[j]; if ((Object)(object)val == (Object)null || !val.m_enabled || val.m_resources == null) { continue; } for (int k = 0; k < val.m_resources.Length; k++) { Requirement val2 = val.m_resources[k]; if (val2 != null && !((Object)(object)val2.m_resItem == (Object)null)) { string prefabName = Utils.GetPrefabName(((Component)val2.m_resItem).gameObject); if (!Mapa.Derivado.ContainsKey(prefabName) && !list2.Contains(prefabName)) { list2.Add(prefabName); } } } } } diz(" destes, usados como INGREDIENTE (os que poderiam abrir receita): " + list2.Count + " " + Alguns(list2, 12)); } private static List TodosOsItens(ObjectDB db) { List list = new List(); HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); for (int i = 0; i < db.m_items.Count; i++) { GameObject val = db.m_items[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.GetComponent() == (Object)null)) { string prefabName = Utils.GetPrefabName(val); if (!string.IsNullOrEmpty(prefabName) && hashSet.Add(prefabName)) { list.Add(prefabName); } } } return list; } private static string Alguns(List lista, int quantos) { if (lista.Count == 0) { return ""; } List range = lista.GetRange(0, Math.Min(quantos, lista.Count)); string text = string.Join(", ", range.ToArray()); if (lista.Count > range.Count) { text = text + ", +" + (lista.Count - range.Count); } return text; } private static void Narra(string t) { if (_rastro != null) { _rastro.AppendLine(t); } } internal static void Simular(Terminal saida) { Action action = delegate(string t) { if ((Object)(object)saida != (Object)null) { saida.AddString(t); } Log.LogInfo((object)t); Narra(t); }; if (!Mapa.Pronto || Mapa.Derivado == null) { action("mapa ainda nao esta pronto; espere carregar."); return; } ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || instance.m_recipes == null) { action("ObjectDB indisponivel."); return; } _rastro = new StringBuilder(); Narra("################################################################"); Narra("# RecipeGate 2.3.0 — a progressao inteira, receita por receita"); Narra("#"); Narra("# trancada = o tier dela pede uma chave que o mundo ainda nao tem"); Narra("################################################################"); Narra(""); List list = new List(); Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); for (int num = 0; num < instance.m_recipes.Count; num++) { Recipe val = instance.m_recipes[num]; if (!((Object)(object)val == (Object)null) && val.m_enabled && !((Object)(object)val.m_item == (Object)null)) { string prefabName = Utils.GetPrefabName(((Component)val.m_item).gameObject); if (!string.IsNullOrEmpty(prefabName) && !dictionary.ContainsKey(prefabName)) { list.Add(prefabName); dictionary[prefabName] = ChaveDoMaterial(prefabName); } } } list.Sort(StringComparer.OrdinalIgnoreCase); action("=== " + list.Count + " receitas do jogo, contra as chaves de mundo ==="); HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); List list2 = new List(); int num2 = 0; for (int num3 = 0; num3 < MapaNucleo.ChavePorTier.Length; num3++) { if (num3 > 0) { hashSet.Add(MapaNucleo.ChavePorTier[num3]); } List list3 = new List(); for (int num4 = 0; num4 < list.Count; num4++) { string text = list[num4]; if (!list2.Contains(text)) { string text2 = dictionary[text]; if (string.IsNullOrEmpty(text2) || hashSet.Contains(text2)) { list3.Add(text); } } } for (int num5 = 0; num5 < list3.Count; num5++) { list2.Add(list3[num5]); Narra(" abriu " + list3[num5].PadRight(34) + ((num3 == 0) ? "(livre desde o inicio)" : ("(" + MapaNucleo.ChavePorTier[num3] + ")"))); } string text3 = ((num3 == 0) ? ("sem boss nenhum (" + MapaNucleo.NomeDoTier(0) + ")") : (MapaNucleo.ChavePorTier[num3].PadRight(22) + "(" + MapaNucleo.NomeDoTier(num3) + ")")); action("--- " + text3); action(" abriram agora: " + list3.Count + " " + Alguns(list3, 6)); action(" total aberto: " + list2.Count + " de " + list.Count); int num6 = 0; for (int num7 = 0; num7 < list2.Count; num7++) { string text4 = dictionary[list2[num7]]; if (!string.IsNullOrEmpty(text4) && !hashSet.Contains(text4)) { num6++; Narra(" ADIANTADA " + list2[num7] + " precisa de " + text4); } } if (num6 > 0) { action(" ATENCAO: " + num6 + " receita(s) abertas antes da chave delas"); num2 += num6; } } action(""); List list4 = new List(); for (int num8 = 0; num8 < list.Count; num8++) { if (!list2.Contains(list[num8])) { list4.Add(list[num8]); } } if (list4.Count > 0) { action(" ATENCAO " + list4.Count + " receita(s) NUNCA abrem: " + Alguns(list4, 10)); num2 += list4.Count; } else { action(" ok toda receita abre em algum degrau: nenhuma fica presa para sempre"); } RelatarForaDoMapa(instance, TodosOsItens(instance), action); action((num2 == 0) ? " ok nenhuma receita fora de ordem" : (" " + num2 + " PROBLEMA(S)")); try { string path = CaminhoDeRelatorio("simulacao.txt"); File.WriteAllText(path, _rastro.ToString()); action("rastro completo na pasta de relatorios do RecipeGate"); } catch (Exception ex) { action("nao consegui gravar o rastro: " + ex.Message); } _rastro = null; } internal static bool IsServer() { ZNet instance = ZNet.instance; if ((Object)(object)instance != (Object)null) { return instance.IsServer(); } return false; } internal static void Detalhe(string texto) { if (Verbose != null && Verbose.Value && Log != null) { Log.LogInfo((object)texto); } } internal static bool PublicarTrava() { if (!IsServer()) { return true; } ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null) { return false; } bool globalKey = instance.GetGlobalKey("recipegate_on"); try { if (Enabled.Value && !globalKey) { instance.SetGlobalKey("recipegate_on"); Detalhe("trava publicada: recipegate_on — o .cfg dos clientes deixa de valer."); } else if (!Enabled.Value && globalKey) { instance.RemoveGlobalKey("recipegate_on"); Detalhe("trava removida: recipegate_on."); } Espelhar(instance, "recipegate_ovr-", new List()); Espelhar(instance, "recipegate_loc-", new List()); Rede.Atualizar(); return true; } catch (Exception ex) { Log.LogDebug((object)("trava adiada (" + ex.Message + ")")); return false; } } private static void Espelhar(ZoneSystem zones, string prefixo, List querido) { List list = ChavesDoServidor(prefixo); for (int i = 0; i < list.Count; i++) { if (!querido.Contains(list[i])) { zones.RemoveGlobalKey(prefixo + list[i]); Detalhe("config retirada do mundo: " + prefixo + list[i]); } } for (int j = 0; j < querido.Count; j++) { if (!list.Contains(querido[j])) { zones.SetGlobalKey(prefixo + querido[j]); Detalhe("config carimbada no mundo: " + prefixo + querido[j]); } } } } [HarmonyPatch(typeof(ZNet), "Shutdown")] internal static class SaidaPatch { private static void Postfix() { try { RecipeGatePlugin.EsquecerMundo(); } catch (Exception ex) { RecipeGatePlugin.Log.LogDebug((object)("saida: " + ex.Message)); } } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] internal static class ComandoPatch { private static bool _feito; private static void Postfix() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if (_feito) { return; } _feito = true; new ConsoleCommand("recipegate", "on / off / teste / simular — liga, desliga, mostra o estado, ou roda a progressao inteira do zero ate o ultimo boss.", (ConsoleEvent)delegate(ConsoleEventArgs args) { string text = ((args.Length >= 2) ? args[1].ToLowerInvariant() : ""); if (!(text == "teste") && !(text == "simular") && !RecipeGatePlugin.IsServer()) { args.Context.AddString("so o servidor pode mudar isto."); } else { if (args.Length >= 2) { string text2 = args[1].ToLowerInvariant(); if (text2 == "on" || text2 == "off") { RecipeGatePlugin.Enabled.Value = text2 == "on"; RecipeGatePlugin.Instancia.PedirTrava(); args.Context.AddString("RecipeGate: " + text2); return; } } if (args.Length >= 2 && args[1].ToLowerInvariant() == "teste") { RecipeGatePlugin.Diagnostico(args.Context); } else if (args.Length >= 2 && args[1].ToLowerInvariant() == "simular") { RecipeGatePlugin.Simular(args.Context); } else { args.Context.AddString("RecipeGate esta " + (RecipeGatePlugin.Enabled.Value ? "ligado" : "desligado") + ". Use: recipegate on | recipegate off"); } } }, false, false, true, false, false, (ConsoleOptionsFetcher)null, false, false, false); } } [HarmonyPatch(typeof(ZoneSystem), "GlobalKeyAdd")] internal static class GlobalKeyAddPatch { private static void Postfix() { try { if (RecipeGatePlugin.Ligado()) { Mapa.RefazerSePreciso(); Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { Trava.AtualizarReceitas(localPlayer); } } } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("falha ao reagir a chave nova: " + ex)); } } } [HarmonyPatch(typeof(SpawnSystem), "Awake")] internal static class SpawnSystemAwakeMapaPatch { private static void Postfix(SpawnSystem __instance) { try { if (!Mapa.Pronto && !RecipeGatePlugin.EsperandoPacote()) { RecipeGatePlugin.EsquecerMundo(); if (RecipeGatePlugin.IsServer() || !RecipeGatePlugin.Ligado()) { Mapa.Construir(__instance); return; } RecipeGatePlugin.GuardarSpawnSystem(__instance); RecipeGatePlugin.Detalhe("cliente: esperando o mapa do servidor (nao vou calcular nada aqui)."); } } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("falha ao montar o mapa: " + ex)); } } } [HarmonyPatch(typeof(ZoneSystem), "Start")] internal static class ZoneSystemStartPatch { private static void Postfix() { try { if ((Object)(object)RecipeGatePlugin.Instancia != (Object)null) { RecipeGatePlugin.Instancia.PedirTrava(); } } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("falha ao agendar a trava: " + ex)); } } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal static class PlayerOnSpawnedPatch { private static void Postfix(Player __instance) { try { RecipeGatePlugin.MigrarEspera(__instance); if (RecipeGatePlugin.Ligado()) { Trava.AtualizarReceitas(__instance); } } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("falha no spawn: " + ex)); } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] internal static class RegistrarPeerSeguroPatch { [HarmonyPriority(800)] private static void Prefix(ZNetPeer peer) { Rede.RegistrarPeer(peer); } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] internal static class ExigirPeerValidadoPatch { [HarmonyPriority(800)] private static bool Prefix(ZRpc rpc) { return Rede.PermitirPeerInfo(rpc); } } public static class RedeNucleo { public static byte[] Comprimir(byte[] dados) { using MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress, leaveOpen: true)) { deflateStream.Write(dados, 0, dados.Length); } return memoryStream.ToArray(); } public static byte[] Descomprimir(byte[] comprimido, int tamanhoEsperado, int tamanhoMaximo) { if (comprimido == null || comprimido.Length == 0 || tamanhoEsperado <= 0 || tamanhoEsperado > tamanhoMaximo) { throw new InvalidDataException("limites de descompressao invalidos"); } using MemoryStream stream = new MemoryStream(comprimido, writable: false); using DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress); using MemoryStream memoryStream = new MemoryStream(tamanhoEsperado); byte[] array = new byte[8192]; int num; while ((num = deflateStream.Read(array, 0, array.Length)) > 0) { if (memoryStream.Length + num > tamanhoEsperado || memoryStream.Length + num > tamanhoMaximo) { throw new InvalidDataException("mapa descomprimido excedeu o limite declarado"); } memoryStream.Write(array, 0, num); } if (memoryStream.Length != tamanhoEsperado) { throw new InvalidDataException("tamanho descomprimido nao confere"); } return memoryStream.ToArray(); } public static byte[] Hash(byte[] dados) { using SHA256 sHA = SHA256.Create(); return sHA.ComputeHash(dados); } public static bool Iguais(byte[] a, byte[] b) { if (a == null || b == null || a.Length != b.Length) { return false; } int num = 0; for (int i = 0; i < a.Length; i++) { num |= a[i] ^ b[i]; } return num == 0; } public static string Hex(byte[] dados) { StringBuilder stringBuilder = new StringBuilder(dados.Length * 2); for (int i = 0; i < dados.Length; i++) { stringBuilder.Append(dados[i].ToString("x2")); } return stringBuilder.ToString(); } } internal static class Rede { internal const string CanalVersao = "raaotium.recipegate.version.1"; internal const string CanalMapa = "raaotium.recipegate.map.1"; private const int Protocolo = 1; private const int MaxPacote = 245760; private const int MaxMapa = 4194304; private const int MaxOverrides = 32768; private static readonly HashSet VersoesOk = new HashSet(); private static readonly Dictionary Enviado = new Dictionary(); private static ZRpc _conexaoServidorEsperada; private static ZRpc _conexaoServidorAutenticada; private static ZPackage _pacoteAtual; private static string _assinaturaAtual; private static bool _registrado; internal static bool Recebido; internal static bool ServidorLigado; internal static string OverridesServidor = ""; internal static void Registrar() { if (!_registrado) { _registrado = true; RecipeGatePlugin.Detalhe("sync seguro pronto: RPC direto por conexao, versao exata, mapa comprimido e validado."); } } internal static void RegistrarPeer(ZNetPeer peer) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown if (peer == null || peer.m_rpc == null) { return; } try { if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { _conexaoServidorEsperada = peer.m_rpc; _conexaoServidorAutenticada = null; } peer.m_rpc.Register("raaotium.recipegate.version.1", (Action)ReceberVersao); peer.m_rpc.Register("raaotium.recipegate.map.1", (Action)ReceberMapa); ZPackage val = new ZPackage(); val.Write("2.3.0"); peer.m_rpc.Invoke("raaotium.recipegate.version.1", new object[1] { val }); } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("nao consegui registrar o peer no sync seguro: " + ex.Message)); } } private static void ReceberVersao(ZRpc rpc, ZPackage pacote) { try { if (pacote == null || pacote.Size() <= 0 || pacote.Size() > 128) { Rejeitar(rpc, "pacote de versao invalido"); return; } string text = pacote.ReadString(); if (!string.Equals(text, "2.3.0", StringComparison.Ordinal)) { Rejeitar(rpc, "versao remota " + text + ", exigida 2.3.0"); return; } if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsServer()) { if (_conexaoServidorEsperada == null || !object.ReferenceEquals(_conexaoServidorEsperada, rpc)) { Invalidar("versao recebida fora da conexao direta esperada do servidor"); return; } _conexaoServidorAutenticada = rpc; } VersoesOk.Add(rpc); RecipeGatePlugin.Detalhe("peer RecipeGate validado na versao " + text + "."); } catch (Exception ex) { Rejeitar(rpc, "versao ilegivel: " + ex.Message); } } internal static bool PermitirPeerInfo(ZRpc rpc) { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || VersoesOk.Contains(rpc)) { return true; } Rejeitar(rpc, "cliente nao concluiu a verificacao do RecipeGate"); return false; } private static void Rejeitar(ZRpc rpc, string motivo) { RecipeGatePlugin.Log.LogWarning((object)("peer rejeitado: " + motivo + ".")); VersoesOk.Remove(rpc); Enviado.Remove(rpc); try { if (rpc != null) { rpc.Invoke("Error", new object[1] { (object)(ConnectionStatus)3 }); } } catch { } try { if (!((Object)(object)ZNet.instance != (Object)null) || rpc == null) { return; } List peers = ZNet.instance.GetPeers(); for (int i = 0; i < peers.Count; i++) { if (peers[i] != null && peers[i].m_rpc == rpc) { ZNet.instance.Disconnect(peers[i]); break; } } } catch { } } internal static void Atualizar() { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Expected O, but got Unknown LimparPeers(); if (!RecipeGatePlugin.IsServer() || !Mapa.Pronto || Mapa.Derivado == null || (Object)(object)ZNet.instance == (Object)null || !PrepararPacote()) { return; } List peers = ZNet.instance.GetPeers(); for (int i = 0; i < peers.Count; i++) { ZNetPeer val = peers[i]; if (val != null && val.m_rpc != null && val.IsReady() && VersoesOk.Contains(val.m_rpc) && (!Enviado.TryGetValue(val.m_rpc, out var value) || !(value == _assinaturaAtual))) { try { val.m_rpc.Invoke("raaotium.recipegate.map.1", new object[1] { (object)new ZPackage(_pacoteAtual.GetArray()) }); Enviado[val.m_rpc] = _assinaturaAtual; RecipeGatePlugin.Detalhe("mapa autenticado enviado a um cliente: " + Mapa.Derivado.Count + " materiais."); } catch (Exception ex) { RecipeGatePlugin.Log.LogWarning((object)("falha ao enviar mapa por RPC direto: " + ex.Message)); } } } } internal static void PublicarMapaAtualizado() { _pacoteAtual = null; _assinaturaAtual = null; Enviado.Clear(); Atualizar(); } private static bool PrepararPacote() { //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown try { string s = Mapa.EmTexto(); string text = RecipeGatePlugin.Overrides.Value ?? ""; if (text.Length > 32768) { RecipeGatePlugin.Log.LogError((object)("Materiais na mao excede o limite seguro de " + 32768 + " caracteres; mapa nao sera enviado.")); return false; } byte[] bytes = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetBytes(s); if (bytes.Length == 0 || bytes.Length > 4194304) { RecipeGatePlugin.Log.LogError((object)("mapa fora do limite seguro: " + bytes.Length + " bytes.")); return false; } byte[] array = RedeNucleo.Hash(bytes); string text2 = RedeNucleo.Hex(array) + "|" + RecipeGatePlugin.Enabled.Value + "|" + text; if (_pacoteAtual != null && _assinaturaAtual == text2) { return true; } byte[] array2 = RedeNucleo.Comprimir(bytes); ZPackage val = new ZPackage(); val.Write(1); val.Write("2.3.0"); val.Write(RecipeGatePlugin.Enabled.Value); val.Write(text); val.Write(Mapa.Derivado.Count); val.Write(bytes.Length); val.Write(array); val.Write(array2); if (val.Size() > 245760) { RecipeGatePlugin.Log.LogError((object)("mapa comprimido excede o limite seguro do transporte: " + val.Size() + " bytes.")); return false; } _pacoteAtual = val; _assinaturaAtual = text2; return true; } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("falha ao preparar o mapa seguro: " + ex.Message)); return false; } } private static void ReceberMapa(ZRpc rpc, ZPackage pacote) { if ((Object)(object)ZNet.instance == (Object)null) { return; } if (ZNet.instance.IsServer()) { Rejeitar(rpc, "cliente tentou publicar um mapa"); return; } if (_conexaoServidorAutenticada == null || !object.ReferenceEquals(_conexaoServidorAutenticada, rpc) || !VersoesOk.Contains(rpc)) { Invalidar("mapa recebido fora da conexao autenticada do servidor"); return; } try { if (pacote == null || pacote.Size() <= 0 || pacote.Size() > 245760) { throw new InvalidDataException("tamanho de pacote invalido"); } int num = pacote.ReadInt(); string text = pacote.ReadString(); bool servidorLigado = pacote.ReadBool(); string text2 = pacote.ReadString(); int num2 = pacote.ReadInt(); int num3 = pacote.ReadInt(); int num4 = pacote.ReadInt(); if (num4 != 32) { throw new InvalidDataException("tamanho do hash invalido"); } byte[] array = pacote.ReadByteArray(num4); int num5 = pacote.ReadInt(); if (num5 <= 0 || num5 > 245760) { throw new InvalidDataException("tamanho comprimido invalido"); } byte[] array2 = pacote.ReadByteArray(num5); if (num != 1 || text != "2.3.0" || text2 == null || text2.Length > 32768 || num2 <= 0 || num2 > 100000 || num3 <= 0 || num3 > 4194304 || array == null || array.Length != 32 || array2 == null || array2.Length != num5) { throw new InvalidDataException("cabecalho fora dos limites"); } byte[] array3 = RedeNucleo.Descomprimir(array2, num3, 4194304); if (!RedeNucleo.Iguais(array, RedeNucleo.Hash(array3))) { throw new InvalidDataException("SHA-256 do mapa nao confere"); } string texto = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true).GetString(array3); if (!Mapa.DeTexto(texto, num2)) { throw new InvalidDataException("conteudo do mapa rejeitado"); } ServidorLigado = servidorLigado; OverridesServidor = text2; Recebido = true; RecipeGatePlugin.Log.LogInfo((object)("mapa autenticado recebido do servidor: " + Mapa.Derivado.Count + " materiais, SHA-256 conferido.")); if ((Object)(object)Player.m_localPlayer != (Object)null) { Trava.AtualizarReceitas(Player.m_localPlayer); } } catch (Exception ex) { Invalidar("pacote de mapa rejeitado: " + ex.Message); } } private static void Invalidar(string motivo) { Recebido = false; ServidorLigado = true; OverridesServidor = ""; Mapa.Esquecer(); RecipeGatePlugin.Log.LogError((object)(motivo + "; falha fechada: receitas continuam travadas.")); } internal static void EsquecerEstadoDoMundo() { Recebido = false; ServidorLigado = true; OverridesServidor = ""; } internal static void Esquecer() { EsquecerEstadoDoMundo(); VersoesOk.Clear(); Enviado.Clear(); _pacoteAtual = null; _assinaturaAtual = null; _conexaoServidorEsperada = null; _conexaoServidorAutenticada = null; } private static void LimparPeers() { List list = new List(); foreach (ZRpc item in VersoesOk) { if (item == null || !item.IsConnected()) { list.Add(item); } } for (int i = 0; i < list.Count; i++) { VersoesOk.Remove(list[i]); Enviado.Remove(list[i]); } } } internal static class Trava { private static MethodInfo _atualiza; internal static bool Trancado(string prefab) { if (string.IsNullOrEmpty(prefab)) { return false; } if (!RecipeGatePlugin.Ligado()) { return false; } if (RecipeGatePlugin.EsperandoMapa()) { return true; } string chave; return Nucleo.DeveSegurar(prefab, RecipeGatePlugin.ChaveDoMaterial, RecipeGatePlugin.TemChave, out chave); } internal static bool TrancadaReceita(Recipe receita) { if ((Object)(object)receita == (Object)null || (Object)(object)receita.m_item == (Object)null) { return false; } return Trancado(Utils.GetPrefabName(((Component)receita.m_item).gameObject)); } internal static bool TrancadaPeca(Piece peca) { if ((Object)(object)peca == (Object)null) { return false; } return Trancado(Utils.GetPrefabName(((Component)peca).gameObject)); } internal static void AtualizarReceitas(Player player) { if ((Object)(object)player == (Object)null) { return; } try { if (_atualiza == null) { _atualiza = AccessTools.Method(typeof(Player), "UpdateKnownRecipesList", (Type[])null, (Type[])null); if (_atualiza == null) { return; } } _atualiza.Invoke(player, null); } catch (Exception ex) { RecipeGatePlugin.Log.LogWarning((object)("nao consegui refazer a lista de receitas: " + ex.Message)); } } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) })] internal static class HaveRequirementsReceitaPatch { private static bool Prefix(Recipe recipe, ref bool __result) { try { if (!Trava.TrancadaReceita(recipe)) { return true; } __result = false; return false; } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("falha ao avaliar a receita (" + ex.Message + "); falha fechada.")); __result = false; return false; } } [HarmonyPriority(0)] [HarmonyAfter(new string[] { "Azumatt.AzuCraftyBoxes" })] private static void Postfix(Recipe recipe, ref bool __result) { try { if (__result && Trava.TrancadaReceita(recipe)) { __result = false; } } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("falha ao reafirmar a trava da receita; falha fechada: " + ex.Message)); if (RecipeGatePlugin.Ligado()) { __result = false; } } } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] internal static class HaveRequirementsPecaPatch { private static bool Prefix(Piece piece, ref bool __result) { try { if (!Trava.TrancadaPeca(piece)) { return true; } __result = false; return false; } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("falha ao avaliar a peca (" + ex.Message + "); falha fechada.")); __result = false; return false; } } [HarmonyPriority(0)] [HarmonyAfter(new string[] { "Azumatt.AzuCraftyBoxes" })] private static void Postfix(Piece piece, ref bool __result) { try { if (__result && Trava.TrancadaPeca(piece)) { __result = false; } } catch (Exception ex) { RecipeGatePlugin.Log.LogError((object)("falha ao reafirmar a trava da peca; falha fechada: " + ex.Message)); if (RecipeGatePlugin.Ligado()) { __result = false; } } } } [HarmonyPatch(typeof(Player), "GetAvailableRecipes")] internal static class ListaDaBancadaPatch { [HarmonyPriority(0)] private static void Postfix(ref List available) { try { if (available == null || available.Count == 0) { return; } for (int num = available.Count - 1; num >= 0; num--) { if (Trava.TrancadaReceita(available[num])) { available.RemoveAt(num); } } } catch (Exception ex) { RecipeGatePlugin.Log.LogWarning((object)("falha ao filtrar a bancada: " + ex.Message)); } } } [HarmonyPatch(typeof(PieceTable), "UpdateAvailable")] internal static class ListaDoMarteloPatch { [HarmonyPriority(0)] private static void Postfix(PieceTable __instance) { try { List> value = Traverse.Create((object)__instance).Field("m_availablePieces").GetValue>>(); if (value == null) { return; } for (int i = 0; i < value.Count; i++) { List list = value[i]; if (list == null) { continue; } for (int num = list.Count - 1; num >= 0; num--) { if (Trava.TrancadaPeca(list[num])) { list.RemoveAt(num); } } } } catch (Exception ex) { RecipeGatePlugin.Log.LogWarning((object)("falha ao filtrar o martelo: " + ex.Message)); } } }