Decompiled source of GK2 Codex v0.18.0
GK2Codex.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using GK2.Framework; using HarmonyLib; using LazyBearTechnology; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Pathfinding; using Rewired; using TMPro; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.ResourceManagement.AsyncOperations; using UnityEngine.SceneManagement; using UnityEngine.TextCore; using UnityEngine.TextCore.LowLevel; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace GK2Codex { internal sealed class AlchemyMix { public string MixId; public readonly List<string> Ingredients = new List<string>(); public readonly List<HashSet<string>> Options = new List<HashSet<string>>(); } internal sealed class AlchemyFormulaInfo { public string Id; public string Name; public string IconId; public int RunesRed; public int RunesGreen; public int RunesBlue; public readonly List<string> Stations = new List<string>(); public readonly List<AlchemyMix> Mixes = new List<AlchemyMix>(); public bool Known; } internal static class Alchemy { private static Dictionary<string, List<AlchemyMixSourceDef>> _bySource; private static readonly Dictionary<string, string> _ingNames = new Dictionary<string, string>(); private static Dictionary<string, List<AlchemyMixSourceDef>> BySource() { if (_bySource != null) { return _bySource; } Dictionary<string, List<AlchemyMixSourceDef>> dictionary = new Dictionary<string, List<AlchemyMixSourceDef>>(); GameBalance me = GameBalance.Me; if ((Object)(object)me != (Object)null && me.alchemyMixSourceDefs != null) { foreach (AlchemyMixSourceDef alchemyMixSourceDef in me.alchemyMixSourceDefs) { if (alchemyMixSourceDef != null && !string.IsNullOrEmpty(alchemyMixSourceDef.formulaId)) { if (!dictionary.TryGetValue(alchemyMixSourceDef.formulaId, out var value)) { value = (dictionary[alchemyMixSourceDef.formulaId] = new List<AlchemyMixSourceDef>()); } value.Add(alchemyMixSourceDef); } } } return _bySource = dictionary; } public static void ResetCaches() { _bySource = null; } public static List<AlchemyFormulaInfo> Collect(bool showAll) { _ingNames.Clear(); List<AlchemyFormulaInfo> list = new List<AlchemyFormulaInfo>(); try { GameBalance me = GameBalance.Me; if ((Object)(object)me == (Object)null || me.alchemyFormulaDefs == null) { return list; } HashSet<string> known = KnownMixes(); Dictionary<string, List<AlchemyMixSourceDef>> bySource = BySource(); foreach (AlchemyFormulaDef alchemyFormulaDef in me.alchemyFormulaDefs) { AlchemyFormulaInfo alchemyFormulaInfo = Build(alchemyFormulaDef, bySource, known, showAll); if (alchemyFormulaInfo != null) { list.Add(alchemyFormulaInfo); } } } catch (Exception ex) { Plugin.Log.LogError((object)("Alchemy: could not read the formulas: " + ex)); } return (from f in list where f != null orderby f.Name ?? "" select f).ToList(); } public static AlchemyFormulaInfo For(string itemId, bool showAll) { if (string.IsNullOrEmpty(itemId)) { return null; } _ingNames.Clear(); try { GameBalance me = GameBalance.Me; if ((Object)(object)me == (Object)null || me.alchemyFormulaDefs == null) { return null; } int num = itemId.IndexOf(':'); string text = ((num > 0) ? itemId.Substring(0, num) : itemId); foreach (AlchemyFormulaDef alchemyFormulaDef in me.alchemyFormulaDefs) { if (alchemyFormulaDef != null && ((BalanceBaseObject)alchemyFormulaDef).id == text) { return Build(alchemyFormulaDef, BySource(), KnownMixes(), showAll); } } } catch (Exception ex) { Plugin.LogThrottled("Alchemy: could not read the formula of " + itemId + ": " + ex.Message); } return null; } private static AlchemyFormulaInfo Build(AlchemyFormulaDef f, Dictionary<string, List<AlchemyMixSourceDef>> bySource, HashSet<string> known, bool showAll) { if (f == null || string.IsNullOrEmpty(((BalanceBaseObject)f).id)) { return null; } bool flag = FormulaKnown(f); if (!showAll && !flag) { return null; } string text = GameApi.ItemName(((BalanceBaseObject)f).id, isGroup: false); if (string.IsNullOrEmpty(text) || text == ((BalanceBaseObject)f).id) { return null; } AlchemyFormulaInfo alchemyFormulaInfo = new AlchemyFormulaInfo { Id = ((BalanceBaseObject)f).id, Name = text, IconId = GameApi.ItemIcon(((BalanceBaseObject)f).id, isGroup: false), RunesRed = f.runesRed, RunesGreen = f.runesGreen, RunesBlue = f.runesBlue, Known = flag }; if (f.craftsIn != null) { foreach (string item in f.craftsIn.Where(GameApi.HasWgoName).Distinct()) { alchemyFormulaInfo.Stations.Add(item); } } Dictionary<string, AlchemyMix> dictionary = new Dictionary<string, AlchemyMix>(); if (bySource.TryGetValue(((BalanceBaseObject)f).id, out var value)) { foreach (AlchemyMixSourceDef item2 in value) { if (item2 == null || string.IsNullOrEmpty(item2.mixId) || (!showAll && !known.Contains(item2.mixId))) { continue; } List<KeyValuePair<string, string>> list = (from i in new string[3] { item2.ingredient1, item2.ingredient2, item2.ingredient3 } where !string.IsNullOrEmpty(i) select new KeyValuePair<string, string>(IngName(i), i)).OrderBy<KeyValuePair<string, string>, string>((KeyValuePair<string, string> kv) => kv.Key, StringComparer.Ordinal).ToList(); if (list.Count == 0) { continue; } string key = string.Join("|", list.Select((KeyValuePair<string, string> kv) => kv.Key).ToArray()); if (!dictionary.TryGetValue(key, out var value2)) { value2 = new AlchemyMix { MixId = item2.mixId }; foreach (KeyValuePair<string, string> item3 in list) { value2.Ingredients.Add(item3.Value); value2.Options.Add(new HashSet<string> { item3.Value }); } dictionary[key] = value2; alchemyFormulaInfo.Mixes.Add(value2); } else { for (int num = 0; num < list.Count && num < value2.Options.Count; num++) { value2.Options[num].Add(list[num].Value); } } } } return alchemyFormulaInfo; } private static string IngName(string id) { if (_ingNames.TryGetValue(id, out var value)) { return value; } bool isGroup = GameApi.ItemDef(id) == null; value = GameApi.ItemName(id, isGroup) ?? id; _ingNames[id] = value; return value; } public static bool FormulaKnown(AlchemyFormulaDef f) { if (f == null) { return false; } try { KnowledgeSystem knowledgeSystem = MainGame.Instance.GameSave.knowledgeSystem; if (knowledgeSystem == null) { return false; } return knowledgeSystem.IsAlchemyFormulaKnown(f); } catch (Exception ex) { Plugin.LogThrottled("Alchemy: knowledge check failed, hiding the formula: " + ex.Message); return false; } } private static HashSet<string> KnownMixes() { HashSet<string> hashSet = new HashSet<string>(); try { KnowledgeSystem knowledgeSystem = MainGame.Instance.GameSave.knowledgeSystem; if (knowledgeSystem == null) { return hashSet; } List<string> value = Traverse.Create((object)knowledgeSystem).Field("knownMixCrafts").GetValue<List<string>>(); if (value != null) { foreach (string item in value) { if (!string.IsNullOrEmpty(item)) { hashSet.Add(item); } } } } catch (Exception ex) { Plugin.LogThrottled("Alchemy: known mixes unreadable: " + ex.Message); } return hashSet; } } public static class Alerts { private sealed class Entry { public string Key; public string Text; public string Icon; public SGuid Target; public float Since; } private sealed class FuelZone { public string Id; public readonly List<WgoData> Sheds = new List<WgoData>(); public readonly HashSet<string> Wants = new HashSet<string>(); } internal sealed class View { public string Text; public string Icon; public SGuid Target; } private static class Tx { private static readonly Dictionary<string, string[]> Table = new Dictionary<string, string[]> { { "Missing", new string[11] { "{0}: {1} {2}/{3}", "{0}: {1} {2}/{3}", "{0}: {1} {2}/{3}", "{0} : {1} {2}/{3}", "{0}: {1} {2}/{3}", "{0}: {1} {2}/{3}", "{0}: {1} {2}/{3}", "{0}: {1} {2}/{3}", "{0}:{1} {2}/{3}", "{0}:{1} {2}/{3}", "{0}: {1} {2}/{3}" } }, { "Elsewhere", new string[11] { "(+{0} misplaced)", "(+{0} не там)", "(+{0} falsch gelagert)", "(+{0} mal rangé)", "(+{0} mal guardado)", "(+{0} no lugar errado)", "(+{0} w złym miejscu)", "(+{0} yanlış yerde)", "(+{0} 別の場所)", "(另有 {0} 放错)", "(+{0} 다른 곳)" } }, { "PowerNoZombies", new string[11] { "no zombies on the carousels", "на каруселях нет зомби", "keine Zombies auf den Karussells", "aucun zombie sur les carrousels", "ningún zombi en los carruseles", "nenhum zumbi nos carrosséis", "na karuzelach nie ma zombie", "atlıkarıncalarda zombi yok", "回転木馬にゾンビがいない", "转盘上没有僵尸", "좀비 컨베이어 벨트 위에 좀비가 없음" } }, { "PowerBroken", new string[11] { "the carousels are broken", "карусели сломаны", "die Karussells sind kaputt", "les carrousels sont cassés", "los carruseles están rotos", "os carrosséis estão quebrados", "karuzele są zepsute", "atlıkarıncalar kırık", "回転木馬が壊れている", "转盘已损坏", "좀비 컨베이어 벨트가 고장남" } }, { "PowerNoCarousel", new string[11] { "no carousel built", "каруселей нет", "kein Karussell gebaut", "aucun carrousel construit", "no hay carruseles construidos", "nenhum carrossel construído", "nie zbudowano karuzeli", "atlıkarınca yapılmadı", "回転木馬が建てられていない", "没有建造转盘", "좀비 컨베이어 벨트가 없음" } }, { "PowerMore", new string[11] { "{0} more zombies needed on the carousels", "нужно ещё зомби на каруселях: {0}", "es fehlen noch {0} Zombies auf den Karussells", "il faut encore {0} zombies sur les carrousels", "faltan {0} zombis en los carruseles", "faltam {0} zumbis nos carrosséis", "brakuje {0} zombie na karuzelach", "atlıkarıncalarda {0} zombi daha gerekli", "回転木馬にあと{0}体のゾンビが必要", "转盘上还需要 {0} 只僵尸", "좀비 컨베이어 벨트에 좀비 {0}마리 더 필요" } }, { "NoSupplier", new string[11] { "{0}: no zombie supplier", "{0}: нет завхоза", "{0}: kein Zombie-Versorger", "{0} : aucun fournisseur zombie", "{0}: sin suministrador zombi", "{0}: sem fornecedor zumbi", "{0}: brak dostawcy zombie", "{0}: zombi tedarikçi yok", "{0}:補給係がいない", "{0}:没有补给员", "{0}: 공급자 없음" } }, { "NoFuel", new string[11] { "Out of fuel in {0}", "Закончилось топливо в зоне {0}", "Kein Brennmaterial in {0}", "Plus de combustible : {0}", "Sin combustible en {0}", "Sem combustível em {0}", "Brak paliwa: {0}", "{0}: yakıt bitti", "{0}:燃料切れ", "{0}:燃料耗尽", "{0}: 연료 부족" } }, { "OutOf", new string[11] { "Out of {0} in {1}", "Закончилось: {0} (зона {1})", "{0} aufgebraucht in {1}", "Plus de {0} : {1}", "Sin {0} en {1}", "Sem {0} em {1}", "Brak: {0} ({1})", "{1}: {0} bitti", "{1}:{0}切れ", "{1}:{0}耗尽", "{1}: {0} 부족" } }, { "Waits", new string[11] { "{0}: finished work waits — {1}", "{0}: готовое ждёт — {1}", "{0}: fertige Arbeit wartet — {1}", "{0} : travail fini en attente — {1}", "{0}: trabajo terminado en espera — {1}", "{0}: trabalho pronto esperando — {1}", "{0}: gotowa praca czeka — {1}", "{0}: biten iş bekliyor — {1}", "{0}:完成品が待機中 — {1}", "{0}:成品在等待 — {1}", "{0}: 완성품 대기 중 — {1}" } }, { "More", new string[11] { "+{0} more", "ещё {0}", "+{0} weitere", "+{0} de plus", "+{0} más", "+{0} a mais", "+{0} więcej", "+{0} tane daha", "他 {0} 件", "还有 {0} 条", "{0}개 더" } }, { "NoOutput", new string[11] { "{0}: no belt leads out", "{0}: нет выходной ленты", "{0}: kein Band führt hinaus", "{0} : aucun convoyeur en sortie", "{0}: ninguna cinta de salida", "{0}: nenhuma esteira de saída", "{0}: brak taśmy wyjściowej", "{0}: çıkış bandı yok", "{0}:出力ベルトがない", "{0}:没有输出传送带", "{0}: 출력 벨트 없음" } }, { "QueueEnded", new string[11] { "{0}: queue ended", "{0}: очередь закончилась", "{0}: Warteschlange leer", "{0} : file terminée", "{0}: cola terminada", "{0}: fila terminou", "{0}: kolejka się skończyła", "{0}: sıra bitti", "{0}:キューが終了", "{0}:队列已完成", "{0}: 대기열 끝남" } }, { "SupplyFull", new string[11] { "Factory Supply Storage full ({0}/{1})", "Склад для припасов фабрики полон ({0}/{1})", "Vorratslager der Fabrik voll ({0}/{1})", "Stockage de fournitures plein ({0}/{1})", "Almacenamiento de suministros lleno ({0}/{1})", "Depósito de suprimentos cheio ({0}/{1})", "Skład na zasoby pełny ({0}/{1})", "Fabrika tedarik deposu dolu ({0}/{1})", "工場の物資保管庫が満杯({0}/{1})", "工厂补给仓库已满({0}/{1})", "공장 보급품 저장고 가득 참 ({0}/{1})" } }, { "NoPower", new string[11] { "Factory stopped: needs {0} power, has {1}", "Фабрика стоит: нужно {0} энергии, есть {1}", "Fabrik steht: braucht {0} Energie, hat {1}", "Usine à l'arrêt : il faut {0} d'énergie, il y en a {1}", "Fábrica parada: necesita {0} de energía, tiene {1}", "Fábrica parada: precisa de {0} de energia, tem {1}", "Fabryka stoi: potrzeba {0} energii, jest {1}", "Fabrika durdu: {0} güç gerekli, {1} var", "工場停止:動力 {0} が必要、現在 {1}", "工厂停转:需要 {0} 动力,现有 {1}", "공장 정지: 동력 {0} 필요, 현재 {1}" } } }; private static int Index => L10n.Index; public static string F(string key, params string[] args) { if (!ExtLoc.TryGet("A" + key, out var text)) { if (!Table.TryGetValue(key, out var value)) { return key; } int index = Index; text = ((index < value.Length && !string.IsNullOrEmpty(value[index])) ? value[index] : value[0]); } try { return string.Format(text, args); } catch { return text; } } } private static readonly Dictionary<string, Entry> Live = new Dictionary<string, Entry>(); private static readonly Dictionary<string, Entry> External = new Dictionary<string, Entry>(); private static readonly HashSet<string> Dismissed = new HashSet<string>(); private const float ShowAfter = 10f; private const int MaxRows = 6; private static float _scanAt; private static Dictionary<string, FuelZone> _fuelZones = new Dictionary<string, FuelZone>(); private static float _fuelWalkAt = -100f; private static List<WgoData> _autoStations = new List<WgoData>(); private static readonly Dictionary<string, float> ReadySince = new Dictionary<string, float>(); private const float NoSupplierAfter = 120f; private static readonly Dictionary<string, float> QueueSince = new Dictionary<string, float>(); private static float _scannedAt = -100f; private static float _diagAt; private static RectTransform _root; private static string _drawn; private static RectTransform _layer; private const float Width = 200f; private static GameObject _pinList; private static float _pinLookAt; private static Vector2 _lastBeside = new Vector2(-1f, -1f); private static bool _builtUp; private static string _drawnLook; public static bool Enabled { get { if (Plugin.AlertsOn != null) { return Plugin.AlertsOn.Value; } return false; } } private static bool Up { get { if (Plugin.RibbonGrow != null) { return Plugin.RibbonGrow.Value == "Up"; } return false; } } private static ConfigEntry<string> Pos { get { if (!Up) { return Plugin.RibbonPosition; } return Plugin.RibbonPositionUp; } } public static void Raise(string key, string text, string iconId, string targetGuid) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(text)) { return; } SGuid target = null; try { if (!string.IsNullOrEmpty(targetGuid)) { target = new SGuid(new Guid(targetGuid)); } } catch { } if (External.TryGetValue(key, out var value)) { value.Text = text; value.Icon = iconId; value.Target = target; return; } External[key] = new Entry { Key = key, Text = text, Icon = iconId, Target = target, Since = Time.unscaledTime - 10f }; } public static void Resolve(string key) { if (key != null) { External.Remove(key); } } private static void WalkFuel() { //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Invalid comparison between Unknown and I4 if (Time.unscaledTime - _fuelWalkAt < 30f) { return; } _fuelWalkAt = Time.unscaledTime; Dictionary<string, FuelZone> dictionary = new Dictionary<string, FuelZone>(); List<WgoData> list = new List<WgoData>(); foreach (GameSceneData gameSceneData in MainGame.Instance.GameSave.worldData.gameSceneDataList) { if (gameSceneData == null || gameSceneData.wgoDataList == null) { continue; } foreach (WgoData wgoData in gameSceneData.wgoDataList) { if (wgoData == null || string.IsNullOrEmpty(((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id) || ((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id.StartsWith("test", StringComparison.Ordinal)) { continue; } WGODef val = null; try { val = ((ObjectLinkedToDefinition<WGODef>)(object)wgoData).Definition; } catch { } if (val == null) { continue; } if (val.isAutoCrafter && (int)val.interactionType == 2) { list.Add(wgoData); } bool isFuelContainer = val.isFuelContainer; if (!isFuelContainer && string.IsNullOrEmpty(val.fuelItemId) && string.IsNullOrEmpty(val.fuelItemId2)) { continue; } string text = null; try { text = Storage.ZoneIdOf(wgoData.WorldZoneData); } catch { } if (string.IsNullOrEmpty(text)) { continue; } if (!dictionary.TryGetValue(text, out var value)) { string key = text; FuelZone obj3 = new FuelZone { Id = text }; value = obj3; dictionary[key] = obj3; } if (isFuelContainer) { value.Sheds.Add(wgoData); continue; } if (!string.IsNullOrEmpty(val.fuelItemId)) { value.Wants.Add(val.fuelItemId); } if (!string.IsNullOrEmpty(val.fuelItemId2)) { value.Wants.Add(val.fuelItemId2); } } } _fuelZones = dictionary; _autoStations = list; } private static void ScanFuel(Dictionary<string, Entry> found) { WalkFuel(); foreach (FuelZone value in _fuelZones.Values) { if (value.Sheds.Count == 0) { continue; } foreach (string want in value.Wants) { ItemDef val = GameApi.ItemDef(want); if (val == null) { continue; } int num = 0; WgoData val2 = null; foreach (WgoData shed in value.Sheds) { try { if (((ObjectLinkedToDefinition<WGODef>)(object)shed).Definition != null && ((ItemFilter)((ObjectLinkedToDefinition<WGODef>)(object)shed).Definition.inventoryWhiteList).Contains(val)) { if (val2 == null) { val2 = shed; } Item val3 = ((shed.Inventory != null) ? shed.Inventory.Data : null); if (val3 != null) { num += val3.GetTotalCountInInventory(want, (Item)null, false); } } } catch { } } if (val2 != null && num <= 0) { string text = GameApi.L("wz_" + value.Id); if (string.IsNullOrEmpty(text)) { text = value.Id; } string text2 = ((want == "fire") ? Tx.F("NoFuel", text) : Tx.F("OutOf", GameApi.ItemName(want, isGroup: false), text)); string key = "codex:fuel:" + value.Id + ":" + want; found[key] = new Entry { Key = key, Text = text2, Icon = GameApi.ItemIcon(want, isGroup: false), Target = val2.UniqueId }; } } } } private static void ScanSuppliers(Dictionary<string, Entry> found) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Invalid comparison between Unknown and I4 WalkFuel(); bool hasWhy = ZppBridge.HasWhy; float unscaledTime = Time.unscaledTime; HashSet<string> ready = new HashSet<string>(); HashSet<string> hashSet = null; foreach (WgoData autoStation in _autoStations) { string text; try { CraftComponent val = ((autoStation != null) ? autoStation.CraftComponent : null); if (val == null || (int)val.Status != 7 || autoStation.Worker is ZombieWgoData) { continue; } text = autoStation.UniqueId.Guid.ToString("N"); goto IL_0093; } catch { } continue; IL_0093: ready.Add(text); if (!ReadySince.TryGetValue(text, out var value)) { value = (ReadySince[text] = unscaledTime); } if (Operators.Is(autoStation)) { if (!(unscaledTime - value < 120f) && Operators.InZone(autoStation).Count <= 0 && !ChoresBridge.Serves(((object)autoStation.UniqueId).ToString())) { bool flag = Operators.ByGardener(autoStation); if (InAssistantScene(autoStation, flag)) { string key = "codex:supplier:" + text; found[key] = new Entry { Key = key, Text = Tx.F("Waits", GameApi.WgoName(((ObjectLinkedToDefinition<WGODef>)(object)autoStation).id), L10n.T(flag ? "ZwNoGardenerGame" : "ZwNoSupplierGame")), Icon = GameApi.WgoIcon(((ObjectLinkedToDefinition<WGODef>)(object)autoStation).id), Target = autoStation.UniqueId }; } } } else { if (!hasWhy) { continue; } string[] array = ZppBridge.Why(text); if (array == null) { continue; } switch (array[0]) { case "no_supplier": { if (unscaledTime - value < 120f) { continue; } if (hashSet == null) { hashSet = SupplierScenes((ZombieType)2); } string text2 = null; try { text2 = autoStation.WorldId; } catch { } if (text2 == null || !hashSet.Contains(text2)) { continue; } break; } case "chests_full": case "skill": case "too_hard": case "stock_limits": case "no_chests": case "held": break; default: continue; } string text3 = ZppBridge.WhyText(array); if (!string.IsNullOrEmpty(text3)) { string key2 = "codex:supplier:" + text; found[key2] = new Entry { Key = key2, Text = Tx.F("Waits", GameApi.WgoName(((ObjectLinkedToDefinition<WGODef>)(object)autoStation).id), text3), Icon = GameApi.WgoIcon(((ObjectLinkedToDefinition<WGODef>)(object)autoStation).id), Target = autoStation.UniqueId }; } } } foreach (string item in ReadySince.Keys.Where((string k) => !ready.Contains(k)).ToList()) { ReadySince.Remove(item); } } private static void ScanQueues(Dictionary<string, Entry> found) { WalkFuel(); float unscaledTime = Time.unscaledTime; HashSet<string> waiting = new HashSet<string>(); foreach (WgoData w in _autoStations) { CraftDef craft = Operators.WaitingToStart(w); if (craft == null) { continue; } List<ZombieWgoData> list = Operators.InZone(w); if (list.Any((ZombieWgoData z) => Operators.Able(z, w, (CraftDefBase)(object)craft)) || ChoresBridge.Serves(((object)w.UniqueId).ToString())) { continue; } string text = w.UniqueId.Guid.ToString("N"); waiting.Add(text); if (!QueueSince.TryGetValue(text, out var value)) { value = (QueueSince[text] = unscaledTime); } bool flag = Operators.ByGardener(w); string text2 = GameApi.WgoName(((ObjectLinkedToDefinition<WGODef>)(object)w).id); string text3; if (list.Count > 0) { text3 = string.Format(L10n.T("QLowSkill"), text2, ZombieState.CraftName(craft), Zombies.TalentName(((ObjectLinkedToDefinition<WGODef>)(object)w).Definition.talent), ((CraftDefBase)craft).talentLock, Operators.BestMastery(list, w, craft)); } else { if (unscaledTime - value < 120f || !InAssistantScene(w, flag)) { continue; } text3 = string.Format(L10n.T(flag ? "QNoGardener" : "QNoSupplier"), text2); } string key = "codex:opqueue:" + text; found[key] = new Entry { Key = key, Text = text3, Icon = GameApi.WgoIcon(((ObjectLinkedToDefinition<WGODef>)(object)w).id), Target = w.UniqueId }; } foreach (string item in QueueSince.Keys.Where((string k) => !waiting.Contains(k)).ToList()) { QueueSince.Remove(item); } } private static bool InAssistantScene(WgoData w, bool gardener) { string text = null; try { text = w.WorldId; } catch { } if (text != null) { return SupplierScenes((ZombieType)(gardener ? 6 : 2)).Contains(text); } return false; } private static HashSet<string> SupplierScenes(ZombieType kind) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) HashSet<string> hashSet = new HashSet<string>(); try { ZombieSystemData zombieSystemData = MainGame.ZombieSystemData; Dictionary<Guid, ZombieWgoData>.ValueCollection valueCollection = ((zombieSystemData == null) ? null : zombieSystemData.Cache?.Values); if (valueCollection == null) { return hashSet; } foreach (ZombieWgoData item in valueCollection) { if (item != null && item.ZombieType == kind && ((WgoData)item).WorldZoneData != null) { string text = null; try { text = ((WgoData)item).WorldId; } catch { } if (text != null) { hashSet.Add(text); } } } } catch { } return hashSet; } private static void ScanPower(Dictionary<string, Entry> found) { WorldZoneData val = Factory.PowerZone(); if (val != null && PowerShort(val, out var have, out var need, out var seated, out var working, out var broken, out var target, out var demand) && demand) { string text = GameApi.WgoIcon("zombie_carousel"); if (text == null || (Object)(object)GameApi.Sprite(text) == (Object)null) { text = GameApi.ItemIcon("body_zombie", isGroup: false); } found["codex:power"] = new Entry { Key = "codex:power", Text = Tx.F("NoPower", need.ToString(), have.ToString()) + " — " + PowerWhy(need, have, seated, working, broken), Icon = text, Target = ((target != null) ? target.UniqueId : null) }; } } private static bool PowerShort(WorldZoneData zone, out int have, out int need, out int seated, out int working, out int broken, out WgoData target, out bool demand) { seated = (working = (broken = 0)); target = null; demand = false; have = (need = 0); try { if (MainGame.Instance.conveyorSystem.IsPaused) { return false; } } catch { } if (!Factory.LivePower(zone, out have, out need) || need <= have) { return false; } WgoData val = null; WgoData val2 = null; foreach (SGuid wgoData2 in zone.wgoDataList) { WgoData wgoData = MainGame.WorldData.GetWgoData(wgoData2); if (wgoData == null) { continue; } if (((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id == "zombie_carousel" || ((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id == "zombie_source_1") { working++; if (val == null) { val = wgoData; } try { WgoPartData mainWgoPartData = wgoData.MainWgoPartData; if (mainWgoPartData != null) { seated += mainWgoPartData.GetDockPoints((Availability)1, (Filter)1).Count; } } catch { } } else if (((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id == "zombie_carousel_broken") { broken++; if (val2 == null) { val2 = wgoData; } } } target = val ?? val2; foreach (Factory.Machine item in Factory.Machines(zone)) { if (item.Queued || item.InQueue) { demand = true; break; } } return true; } private static string PowerWhy(int need, int have, int seated, int working, int broken) { if (working == 0) { return Tx.F((broken > 0) ? "PowerBroken" : "PowerNoCarousel"); } if (seated == 0) { return Tx.F("PowerNoZombies"); } int num = Math.Max(1, Factory.CarouselPower()); return Tx.F("PowerMore", Math.Max(1, (int)Math.Ceiling((double)(need - have) / (double)num)).ToString()); } private static void ScanMachines(Dictionary<string, Entry> found) { WorldZoneData val = Factory.PowerZone(); if (val == null) { return; } foreach (Factory.Machine item in Factory.Machines(val)) { string text = GameApi.WgoName(((ObjectLinkedToDefinition<WGODef>)(object)item.W).id); string icon = GameApi.WgoIcon(((ObjectLinkedToDefinition<WGODef>)(object)item.W).id); string text2 = ((item.W.UniqueId != (SGuid)null) ? item.W.UniqueId.Guid.ToString("N") : ((ObjectLinkedToDefinition<WGODef>)(object)item.W).id); if (item.NoOutput) { string key = "codex:nooutput:" + text2; found[key] = new Entry { Key = key, Text = Tx.F("NoOutput", text), Icon = icon, Target = item.W.UniqueId }; } else if (item.HasZombie && !item.Queued) { string key2 = "codex:queue:" + text2; found[key2] = new Entry { Key = key2, Text = Tx.F("QueueEnded", text), Icon = icon, Target = item.W.UniqueId }; } } } private static void ScanSupply(Dictionary<string, Entry> found) { if (Factory.SupplyStorage(out var used, out var size) && used >= size) { WgoData val = null; try { WorldZoneData worldZoneDataById = MainGame.WorldData.GetWorldZoneDataById("conveyor_storage"); val = ((worldZoneDataById != null) ? worldZoneDataById.MultiInventoryWgoDatas.FirstOrDefault() : null); } catch { } found["codex:supply"] = new Entry { Key = "codex:supply", Text = Tx.F("SupplyFull", used.ToString(), size.ToString()), Icon = GameApi.ItemIcon("box_empty", isGroup: false), Target = ((val != null) ? val.UniqueId : null) }; } } private static void Scan() { //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Invalid comparison between Unknown and I4 //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Invalid comparison between Unknown and I4 _scannedAt = Time.unscaledTime; Dictionary<string, Entry> found = new Dictionary<string, Entry>(); try { ScanFuel(found); } catch (Exception ex) { Plugin.LogThrottled("Alerts fuel: " + ex.Message); } try { ScanPower(found); } catch (Exception ex2) { Plugin.LogThrottled("Alerts power: " + ex2.Message); } try { ScanSupply(found); } catch (Exception ex3) { Plugin.LogThrottled("Alerts supply: " + ex3.Message); } try { ScanMachines(found); } catch (Exception ex4) { Plugin.LogThrottled("Alerts machines: " + ex4.Message); } try { ScanSuppliers(found); } catch (Exception ex5) { Plugin.LogThrottled("Alerts suppliers: " + ex5.Message); } try { ScanQueues(found); } catch (Exception ex6) { Plugin.LogThrottled("Alerts queues: " + ex6.Message); } ZombieSystemData zombieSystemData = MainGame.ZombieSystemData; IEnumerable<ZombieWgoData> enumerable = ((zombieSystemData == null) ? null : zombieSystemData.Cache?.Values); if (enumerable == null) { enumerable = (IEnumerable<ZombieWgoData>)(object)new ZombieWgoData[0]; } Dictionary<string, int> dictionary = new Dictionary<string, int>(); Dictionary<string, WorldZoneData> dictionary2 = new Dictionary<string, WorldZoneData>(); foreach (ZombieWgoData item in enumerable) { WorldZoneData val = ((item != null) ? ((WgoData)item).WorldZoneData : null); if (val != null) { if ((int)item.ZombieType == 2) { dictionary[((ObjectLinkedToDefinition<WorldZoneDef>)(object)val).id] = (dictionary.TryGetValue(((ObjectLinkedToDefinition<WorldZoneDef>)(object)val).id, out var value) ? value : 0) + 1; } if ((int)item.ZombieType == 1) { dictionary2[((ObjectLinkedToDefinition<WorldZoneDef>)(object)val).id] = val; } } } foreach (WgoData autoStation in _autoStations) { try { if (Operators.Is(autoStation) && autoStation.WorldZoneData != null) { dictionary2[((ObjectLinkedToDefinition<WorldZoneDef>)(object)autoStation.WorldZoneData).id] = autoStation.WorldZoneData; } } catch { } } foreach (WorldZoneData value5 in dictionary2.Values) { List<OrderBase> value2 = Traverse.Create((object)value5).Field("orders").GetValue<List<OrderBase>>(); if (value2 == null) { continue; } dictionary.TryGetValue(((ObjectLinkedToDefinition<WorldZoneDef>)(object)value5).id, out var value3); foreach (OrderBase item2 in value2) { DeliveryOrder val2 = (DeliveryOrder)(object)((item2 is DeliveryOrder) ? item2 : null); if (val2 == null || ((OrderBase)val2).Item == null || ((OrderBase)val2).Item.IsEmpty || !item2.ExecutorUniqueId.IsEmpty) { continue; } ZombieWgoData zombie = zombieSystemData.GetZombie(((OrderBase)val2).TargetWgoUniqueId); WgoData val3 = ((zombie != null) ? zombie.AttachedWgoData : ((OrderBase)val2).TargetWgoData); int num; int num2; if (zombie == null) { num = (Operators.Is(val3) ? 1 : 0); if (num != 0) { num2 = Operators.InZone(val3).Count; goto IL_030e; } } else { num = 0; } num2 = value3; goto IL_030e; IL_030e: int num3 = num2; if (num != 0 && num3 == 0) { continue; } int num4 = 0; int num5 = 0; foreach (WgoData multiInventoryWgoData in value5.MultiInventoryWgoDatas) { object obj2; if (multiInventoryWgoData == null) { obj2 = null; } else { Inventory inventory = multiInventoryWgoData.Inventory; obj2 = ((inventory != null) ? inventory.Data : null); } if (obj2 == null || ((ObjectLinkedToDefinition<WGODef>)(object)multiInventoryWgoData).Definition == null) { continue; } try { if (((ObjectLinkedToDefinition<WGODef>)(object)multiInventoryWgoData).Definition.hasRefToOtherWgoInventory) { continue; } } catch { } int totalCountInInventory = multiInventoryWgoData.Inventory.Data.GetTotalCountInInventory(((ObjectLinkedToDefinition<ItemDef>)(object)((OrderBase)val2).Item).id, (Item)null, false); if (((ItemFilter)((ObjectLinkedToDefinition<WGODef>)(object)multiInventoryWgoData).Definition.inventoryWhiteList).Contains(((ObjectLinkedToDefinition<ItemDef>)(object)((OrderBase)val2).Item).Definition) && !((ItemFilter)((ObjectLinkedToDefinition<WGODef>)(object)multiInventoryWgoData).Definition.inventoryBlackList).Contains(((ObjectLinkedToDefinition<ItemDef>)(object)((OrderBase)val2).Item).Definition)) { num4 += totalCountInInventory; } else { num5 += totalCountInInventory; } } if (num3 <= 0 || num4 < ((OrderBase)val2).Item.Count) { string text = GameApi.L("wz_" + ((ObjectLinkedToDefinition<WorldZoneDef>)(object)value5).id) ?? ((ObjectLinkedToDefinition<WorldZoneDef>)(object)value5).id; string text2 = GameApi.ItemName(((ObjectLinkedToDefinition<ItemDef>)(object)((OrderBase)val2).Item).id, isGroup: false); string text3 = ((val3 != null) ? GameApi.WgoName(((ObjectLinkedToDefinition<WGODef>)(object)val3).id) : text); string text4 = ((num3 == 0) ? Tx.F("NoSupplier", text3) : (Tx.F("Missing", text3, text2, num4.ToString(), ((OrderBase)val2).Item.Count.ToString()) + ((num5 > 0) ? (" " + Tx.F("Elsewhere", num5.ToString())) : ""))); string key = "codex:delivery:" + ((object)((OrderBase)val2).TargetWgoUniqueId)?.ToString() + ":" + ((ObjectLinkedToDefinition<ItemDef>)(object)((OrderBase)val2).Item).id; found[key] = new Entry { Key = key, Text = text4, Icon = GameApi.ItemIcon(((ObjectLinkedToDefinition<ItemDef>)(object)((OrderBase)val2).Item).id, isGroup: false), Target = ((val3 != null) ? val3.UniqueId : null) }; } } } foreach (string item3 in Live.Keys.Where((string k) => k.StartsWith("codex:", StringComparison.Ordinal) && !found.ContainsKey(k)).ToList()) { Live.Remove(item3); } foreach (KeyValuePair<string, Entry> item4 in found) { if (Live.TryGetValue(item4.Key, out var value4)) { value4.Text = item4.Value.Text; value4.Icon = item4.Value.Icon; value4.Target = item4.Value.Target; } else { item4.Value.Since = Time.unscaledTime; Live[item4.Key] = item4.Value; } } } internal static void DiagTick() { if (!Diag.On || Time.unscaledTime < _diagAt) { return; } _diagAt = Time.unscaledTime + 2f; try { DiagPower(); } catch (Exception ex) { Plugin.LogThrottled("Diag power: " + ex.Message); } try { DiagRibbon(); } catch { } } private static void DiagPower() { WorldZoneData val = Factory.PowerZone(); if (val == null) { return; } bool flag = false; try { flag = MainGame.Instance.conveyorSystem.IsPaused; } catch { } if (!Factory.LivePower(val, out var have, out var need)) { Diag.Changed("power-alert", "none", "factory power: no factory yet (or nothing built)"); return; } int num = 0; int num2 = 0; foreach (SGuid wgoData2 in val.wgoDataList) { WgoData wgoData = MainGame.WorldData.GetWgoData(wgoData2); if (wgoData != null) { if (((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id == "zombie_carousel") { num++; } else if (((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id == "zombie_carousel_broken") { num2++; } } } Diag.Changed("power-quality", have.ToString(), "factory power: the game reports " + have + " from the power sources (carousels and the starting source; " + num + " carousels working, " + num2 + " broken); belts, splitters and supply stations use " + need); int have2; int need2; int seated; int working; int broken; WgoData target; bool demand; bool flag2 = PowerShort(val, out have2, out need2, out seated, out working, out broken, out target, out demand); bool flag3 = flag2 && demand; Diag.Changed("power-alert", flag3 + "|" + flag2 + "|" + flag + "|" + need + "|" + have + "|" + num2 + "|" + seated, "factory power alert " + (flag3 ? ("FIRES (" + PowerWhy(need, have, seated, working, broken) + ")") : "is clear") + ": used " + need + ", available " + have + ", zombies sitting on carousels " + seated + ", factory paused " + flag + ", broken carousels " + num2 + ((flag2 && !demand) ? ", but nothing is queued at any machine (an empty factory is not a problem)" : "") + (Enabled ? "" : " (the ribbon itself is off, the Now page still shows it)")); } private static void DiagRibbon() { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) if (Enabled && !((Object)(object)_root == (Object)null) && ((Component)_root).gameObject.activeInHierarchy) { Vector3[] array = (Vector3[])(object)new Vector3[4]; _root.GetWorldCorners(array); Rect r = Rect.MinMaxRect(array[0].x, array[0].y, array[2].x, array[2].y); if (!(((Rect)(ref r)).height < 2f)) { Diag.Changed("ribbon-rect", Mathf.Round(((Rect)(ref r)).x) + "," + Mathf.Round(((Rect)(ref r)).y) + "," + Mathf.Round(((Rect)(ref r)).width) + "," + Mathf.Round(((Rect)(ref r)).height), "ribbon on screen: rect " + Diag.R(r) + " (px), screen " + Screen.width + "x" + Screen.height + ", " + Live.Count + " problems live"); } } } internal static void Tick(RectTransform layer, bool codexOpen) { if (!Enabled || (Object)(object)layer == (Object)null) { Hide(); return; } try { if (Time.unscaledTime >= _scanAt) { _scanAt = Time.unscaledTime + 2f; Scan(); FollowPinList(); } List<Entry> list = Current(); Dismissed.RemoveWhere((string k) => !Live.ContainsKey(k) && !External.ContainsKey(k)); bool flag = codexOpen || GameWindowOpen() || StoryBusy(); if (list.Count == 0 || flag) { Hide(); return; } Ensure(layer); string text = string.Join("\n", list.Select((Entry e) => e.Key + "|" + e.Text).ToArray()) + "|" + GameApi.Lang() + "|" + (Up ? "up" : "down") + "|" + FontLook.Key; if (text != _drawn) { bool num = _drawnLook != FontLook.Key; _drawn = text; _drawnLook = FontLook.Key; Draw(list); if (num) { ApplyPosition(); } } if (!((Component)_root).gameObject.activeSelf) { ((Component)_root).gameObject.SetActive(true); } ((Transform)_root).SetAsFirstSibling(); } catch (Exception ex) { Plugin.LogThrottled("Alerts: " + ex.Message); Hide(); } } private static List<Entry> Current() { float now = Time.unscaledTime; return (from e in Live.Values.Concat(External.Values) where now - e.Since >= 10f && !Dismissed.Contains(e.Key) orderby e.Since select e).ToList(); } private static bool GameWindowOpen() { try { return LazyWindowsStackController.HasAnyModalWindowOpened; } catch { return false; } } private static bool StoryBusy() { try { PlayerController playerController = MainGame.PlayerController; if ((Object)(object)playerController == (Object)null) { return false; } return !playerController.IsControlEnabledByType((TakenControlType)3) || !playerController.IsControlEnabledByType((TakenControlType)11) || !playerController.IsControlEnabledByType((TakenControlType)5) || !playerController.IsControlEnabledByType((TakenControlType)12); } catch { return false; } } private static void Hide() { if ((Object)(object)_root != (Object)null && ((Component)_root).gameObject.activeSelf) { ((Component)_root).gameObject.SetActive(false); } } private unsafe static void ApplyPosition() { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_root == (Object)null || (Object)(object)_layer == (Object)null) { return; } float num = 0.01f; float num2 = (Up ? 0.05f : 0.66f); try { string[] array = (Pos?.Value ?? "").Split(','); if (array.Length == 2) { num = float.Parse(array[0].Trim(), CultureInfo.InvariantCulture); num2 = float.Parse(array[1].Trim(), CultureInfo.InvariantCulture); } } catch { } Rect rect = _layer.rect; Vector2 size = ((Rect)(ref rect)).size; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(Mathf.Clamp01(num) * size.x, Mathf.Clamp01(num2) * size.y); Vector2 at = Vector2.zero; bool flag = !Up && AtDefault() && BesidePinList(out at); if (flag) { val = at; } val = FontLook.Px(val, FontLook.CanvasScale); _root.anchoredPosition = val; if (Diag.On) { Diag.Changed("ribbon-pos", val.x.ToString("0") + "," + val.y.ToString("0") + "|" + flag, "ribbon position: default \"" + ((Pos != null) ? ((string)((ConfigEntryBase)Pos).DefaultValue) : "?") + "\", setting \"" + ((Pos != null) ? Pos.Value : "?") + "\" (" + (AtDefault() ? "not moved" : "dragged") + "), " + (flag ? "placed right of Almanac's pin list" : "at the setting") + ": anchored at " + ((object)(*(Vector2*)(&val))/*cast due to .constrained prefix*/).ToString() + " in a layer of " + ((object)(*(Vector2*)(&size))/*cast due to .constrained prefix*/).ToString() + " (UI units)"); } } private static bool AtDefault() { ConfigEntry<string> pos = Pos; if (pos != null) { return pos.Value == (string)((ConfigEntryBase)pos).DefaultValue; } return false; } private static bool BesidePinList(out Vector2 at) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) at = Vector2.zero; try { if ((Object)(object)_pinList == (Object)null && Time.unscaledTime >= _pinLookAt) { _pinLookAt = Time.unscaledTime + 5f; _pinList = GameObject.Find("AlmanacPinList"); } if ((Object)(object)_pinList == (Object)null || !_pinList.activeInHierarchy) { return false; } Transform transform = _pinList.transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); Canvas componentInParent = _pinList.GetComponentInParent<Canvas>(); if ((Object)(object)val == (Object)null || (Object)(object)componentInParent == (Object)null) { return false; } componentInParent = componentInParent.rootCanvas; Camera obj = (((int)componentInParent.renderMode == 0) ? null : componentInParent.worldCamera); Vector3[] array = (Vector3[])(object)new Vector3[4]; val.GetWorldCorners(array); Vector2 val2 = RectTransformUtility.WorldToScreenPoint(obj, array[2]); Vector2 val3 = default(Vector2); if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(_layer, val2, (Camera)null, ref val3)) { return false; } Vector2 val4 = val3; Rect rect = _layer.rect; val3 = val4 - ((Rect)(ref rect)).min; at = new Vector2(val3.x + 6f, val3.y); return true; } catch { return false; } } private static void FollowPinList() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root == (Object)null) && AtDefault()) { Vector2 at; Vector2 val = (Vector2)(BesidePinList(out at) ? at : new Vector2(-1f, -1f)); Vector2 val2 = val - _lastBeside; if (!(((Vector2)(ref val2)).sqrMagnitude < 1f)) { _lastBeside = val; ApplyPosition(); } } } internal static void SavePosition() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root == (Object)null) && !((Object)(object)_layer == (Object)null) && Pos != null) { Rect rect = _layer.rect; Vector2 size = ((Rect)(ref rect)).size; if (!(size.x < 1f) && !(size.y < 1f)) { Vector2 anchoredPosition = _root.anchoredPosition; anchoredPosition.x = Mathf.Clamp(anchoredPosition.x, 0f, size.x - 40f); anchoredPosition.y = (Up ? Mathf.Clamp(anchoredPosition.y, 0f, size.y - 40f) : Mathf.Clamp(anchoredPosition.y, 40f, size.y)); _root.anchoredPosition = anchoredPosition; Pos.Value = (anchoredPosition.x / size.x).ToString("0.###", CultureInfo.InvariantCulture) + "," + (anchoredPosition.y / size.y).ToString("0.###", CultureInfo.InvariantCulture); } } } private static void Ensure(RectTransform layer) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_root != (Object)null) || !((Object)(object)((Transform)_root).parent == (Object)(object)layer) || _builtUp != Up) { if ((Object)(object)_root != (Object)null) { Object.Destroy((Object)(object)((Component)_root).gameObject); } _layer = layer; _builtUp = Up; _root = UiKit.Rect("CodexAlerts", (Transform)(object)layer); RectTransform root = _root; Vector2 anchorMin = (_root.anchorMax = Vector2.zero); root.anchorMin = anchorMin; _root.pivot = (Up ? new Vector2(0f, 0f) : new Vector2(0f, 1f)); _root.sizeDelta = new Vector2(200f, 0f); VerticalLayoutGroup obj = ((Component)_root).gameObject.AddComponent<VerticalLayoutGroup>(); ((LayoutGroup)obj).childAlignment = (TextAnchor)(Up ? 6 : 0); ((HorizontalOrVerticalLayoutGroup)obj).spacing = 2f; ((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = true; ((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false; ((Component)_root).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2; ApplyPosition(); _drawn = null; } } private static void Draw(List<Entry> shown) { UiKit.Clear((Transform)(object)_root); List<Entry> list = shown.Take(6).ToList(); if (Up) { if (shown.Count > 6) { MoreRow(shown.Count - 6); } for (int num = list.Count - 1; num >= 0; num--) { Row(list[num]); } Grip(); return; } Grip(); foreach (Entry item in list) { Row(item); } if (shown.Count > 6) { MoreRow(shown.Count - 6); } } private static void MoreRow(int n) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) UiKit.Size((Component)(object)UiKit.Text(UiKit.Rect("More", (Transform)(object)_root), Tx.F("More", n.ToString()), "small_font", UiKit.TextDim, (TextAlignmentOptions)4100, 13f), -1f, 14f); } private static void Grip() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) RectTransform val = UiKit.Rect("Grip", (Transform)(object)_root); UiKit.Size((Component)(object)UiKit.Img(val, "craft_window-header_1-value_cell", raycast: true, (Color?)new Color(1f, 1f, 1f, 0.55f)), -1f, 7f); UiKit.Text(UiKit.Stretch(UiKit.Rect("Dots", (Transform)(object)val)), "· · ·", "small_font", UiKit.TextDim, (TextAlignmentOptions)514, 9f); ((Component)val).gameObject.AddComponent<RibbonDrag>(); } private static void Row(Entry e) { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown RectTransform val = UiKit.Rect("Alert", (Transform)(object)_root); Image target = UiKit.Img(val, "craft_window-header_1-value_cell", raycast: true); HorizontalLayoutGroup obj = UiKit.HRow(val, 4f, 5, 3); ((LayoutGroup)obj).padding.top = 2; ((LayoutGroup)obj).padding.bottom = 2; ((LayoutGroup)obj).childAlignment = (TextAnchor)3; UiKit.Size((Component)(object)UiKit.Text(UiKit.Rect("Mark", (Transform)(object)val), "!", "small_font_bold", UiKit.CountLow, (TextAlignmentOptions)514, 14f), 6f, 14f); if (!string.IsNullOrEmpty(e.Icon)) { UiKit.Size((Component)(object)UiKit.Icon(UiKit.Rect("Icon", (Transform)(object)val), e.Icon), 14f, 14f); } TextMeshProUGUI obj2 = UiKit.Text(UiKit.Rect("Text", (Transform)(object)val), L10n.Cap(e.Text), "small_font", UiKit.TextName, (TextAlignmentOptions)4097, 12f); ((TMP_Text)obj2).textWrappingMode = (TextWrappingModes)1; ((TMP_Text)obj2).overflowMode = (TextOverflowModes)1; ((TMP_Text)obj2).maxVisibleLines = 2; UiKit.Size((Component)(object)obj2, -1f, -1f, 1f); string key = e.Key; UiKit.SmallButton((Transform)(object)val, "×", (UnityAction)delegate { Dismissed.Add(key); _drawn = null; }); SGuid target2 = e.Target; UiKit.Button(val, (UnityAction)delegate { try { WgoData val2 = ((target2 != (SGuid)null) ? MainGame.WorldData.GetWgoData(target2) : null); if (val2 != null) { Locate.Toggle(val2); } } catch (Exception ex) { Plugin.LogThrottled("Alerts click: " + ex.Message); } }, (Graphic)(object)target); } internal static List<View> Snapshot() { try { if (Time.unscaledTime - _scannedAt >= 2f) { _scanAt = Time.unscaledTime + 2f; Scan(); } } catch (Exception ex) { Plugin.LogThrottled("Alerts snapshot: " + ex.Message); } return (from e in Live.Values.Concat(External.Values) orderby e.Since select new View { Text = e.Text, Icon = e.Icon, Target = e.Target }).ToList(); } internal static void Mark(SGuid target) { try { WgoData val = ((target != (SGuid)null) ? MainGame.WorldData.GetWgoData(target) : null); if (val != null) { Locate.Toggle(val); } } catch (Exception ex) { Plugin.LogThrottled("Alerts click: " + ex.Message); } } internal static void Reset() { Live.Clear(); External.Clear(); Dismissed.Clear(); _drawn = null; ReadySince.Clear(); _autoStations = new List<WgoData>(); _fuelWalkAt = -100f; } } internal sealed class RibbonDrag : MonoBehaviour, IDragHandler, IEventSystemHandler, IEndDragHandler { public void OnDrag(PointerEventData e) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) Transform parent = ((Component)this).transform.parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); RectTransform val2 = (RectTransform)(((Object)(object)val != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null)) { float num = ((((Transform)val2).lossyScale.x > 0.0001f) ? ((Transform)val2).lossyScale.x : 1f); val.anchoredPosition += e.delta / num; } } public void OnEndDrag(PointerEventData e) { Alerts.SavePosition(); } } internal static class AutoWalk { private const float Timeout = 90f; private const float Speed = 2.5f; private const float StandOff = 1.1f; private static bool _active; private static float _since; private static string _scene; private static WgoData _marked; private static string _name; public static bool Enabled { get { if ((Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.WalkToChests != null) { return Plugin.Instance.WalkToChests.Value; } return false; } } public static bool Walking => _active; private static string SceneOf(WgoData w) { try { return w.WorldId; } catch { return null; } } private static float Dist2(WgoData w, Vector3 from) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) try { Vector3 position = w.Position; float num = position.x - from.x; float num2 = position.z - from.z; return num * num + num2 * num2; } catch { return float.MaxValue; } } public static ChestInfo Nearest(string itemId, bool showAll) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) List<ChestInfo> list = Storage.With(itemId, showAll).Concat(Storage.OutputsWith(itemId, showAll)).ToList(); if (list.Count == 0) { return null; } string scene = null; Vector3 me = Vector3.zero; try { scene = MainGame.PlayerData.currentGameSceneId; me = MainGame.PlayerData.position.Value; } catch { } return (from c in list orderby (!Reachable(c.Raw)) ? ((SceneOf(c.Raw) == scene) ? 1 : 2) : 0, Dist2(c.Raw, me) select c).First(); } public static bool Reachable(WgoData chest) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) try { if (chest == null || SceneOf(chest) != MainGame.PlayerData.currentGameSceneId) { return false; } TeleportPointGraph instance = TeleportPointGraph.Instance; if (instance == null) { return true; } Vector3 val = (((Object)(object)MainGame.PlayerController != (Object)null) ? ((Component)MainGame.PlayerController).transform.position : MainGame.PlayerData.position.Value); WgoData val2 = default(WgoData); return !instance.TryResolveDoor(val, chest.BubblePos, chest, ref val2); } catch { return false; } } public static bool Go(ChestInfo c, bool walk) { if (c == null || c.Raw == null) { return false; } _name = c.Name; if (!Locate.IsMarked(c.Raw)) { Locate.Toggle(c.Raw); _marked = c.Raw; } if (walk && Enabled && Reachable(c.Raw)) { return Start(c.Raw); } return false; } private unsafe static bool Start(WgoData chest) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Invalid comparison between Unknown and I4 //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Invalid comparison between Unknown and I4 //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) try { MainGame instance = MainGame.Instance; if ((Object)(object)instance == (Object)null || (int)instance.gameState != 1 || (Object)(object)MainGame.PlayerController == (Object)null) { return false; } if (LazyWindowsStackController.HasAnyModalWindowOpened) { return false; } MovementComponent movementComponent = MainGame.PlayerController.MovementComponent; if (movementComponent == null) { return false; } if (_active) { Cancel("a new walk"); } string currentGameSceneId = MainGame.PlayerData.currentGameSceneId; Vector3 value = MainGame.PlayerData.position.Value; Vector3 position = chest.Position; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(value.x - position.x, 0f, value.z - position.z); Vector3 val2 = ((((Vector3)(ref val)).sqrMagnitude > 0.01f) ? (position + ((Vector3)(ref val)).normalized * 1.1f) : position); val2.y = value.y; WorldZoneData currentWorldZoneData = MainGame.PlayerData.CurrentWorldZoneData; WorldZoneData val3 = null; try { val3 = chest.WorldZoneData; } catch { } int num; ? val4; if (currentWorldZoneData != null && val3 != null) { num = ((((ObjectLinkedToDefinition<WorldZoneDef>)(object)currentWorldZoneData).id == ((ObjectLinkedToDefinition<WorldZoneDef>)(object)val3).id) ? 1 : 0); if (num != 0) { val4 = NavigationGraphMaskUtils.ToGraphMask((IEnumerable<Graph>)currentWorldZoneData.MovementGraphs, currentWorldZoneData.navigationGraph); goto IL_0143; } } else { num = 0; } val4 = default(GraphMask); goto IL_0143; IL_0143: GraphMask val5 = (GraphMask)val4; string text; StartPathResult val6; if (num != 0 && val5 != default(GraphMask)) { text = "zone graph " + ((ObjectLinkedToDefinition<WorldZoneDef>)(object)currentWorldZoneData).id; val6 = movementComponent.StartPath(val2, val5, currentGameSceneId, 2.5f, "", (Action)delegate { Arrived("path ended: " + Completion()); }, (DestinationType)0); } else { text = "roads " + ((currentWorldZoneData != null) ? ((ObjectLinkedToDefinition<WorldZoneDef>)(object)currentWorldZoneData).id : "-") + " -> " + ((val3 != null) ? ((ObjectLinkedToDefinition<WorldZoneDef>)(object)val3).id : "-"); val6 = movementComponent.StartPath(val2, currentGameSceneId, currentGameSceneId, (MovementType)3, 2.5f, "", (Action)delegate { Arrived("path ended: " + Completion()); }, (Seeker)null, (DestinationType)0); } if ((int)val6 == 2) { Plugin.Log.LogInfo((object)("Walk: the game refused the path (" + ((object)(*(StartPathResult*)(&val6))/*cast due to .constrained prefix*/).ToString() + ", " + text + ")")); return false; } _active = (int)val6 == 0; _since = Time.unscaledTime; _scene = currentGameSceneId; Plugin.Log.LogInfo((object)("Walk to " + _name + ": " + ((object)(*(StartPathResult*)(&val6))/*cast due to .constrained prefix*/).ToString() + " (" + text + ")")); return _active; } catch (Exception ex) { _active = false; Plugin.LogThrottled("Walk start: " + ex.Message); return false; } } private static string Completion() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) try { return ((object)MainGame.PlayerController.MovementComponent.Completion/*cast due to .constrained prefix*/).ToString(); } catch { return "?"; } } private static void Arrived(string why) { if (_active) { _active = false; Plugin.Log.LogInfo((object)("Walk to " + _name + " ended: " + why)); Diag.Log("Locate: walk to " + _name + " ended: " + why); Unmark(); } } private static void Unmark() { try { if (_marked != null && Locate.IsMarked(_marked)) { Locate.Toggle(_marked); } } catch { } _marked = null; } public static void Cancel(string why) { if (_active) { Diag.Log("Locate: walk to " + _name + " cancelled: " + why); _active = false; Release(); Plugin.Log.LogInfo((object)("Walk to " + _name + " stopped: " + why)); } } private static void Release() { try { MovementComponent val = (((Object)(object)MainGame.PlayerController != (Object)null) ? MainGame.PlayerController.MovementComponent : null); if (val != null) { val.ForceStop(); } } catch (Exception ex) { Plugin.LogThrottled("Walk stop: " + ex.Message); } } private static bool Pressed() { try { if (Input.GetKey((KeyCode)119) || Input.GetKey((KeyCode)97) || Input.GetKey((KeyCode)115) || Input.GetKey((KeyCode)100) || Input.GetKey((KeyCode)273) || Input.GetKey((KeyCode)274) || Input.GetKey((KeyCode)276) || Input.GetKey((KeyCode)275)) { return true; } } catch { } try { if (Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.3f || Mathf.Abs(Input.GetAxisRaw("Vertical")) > 0.3f) { return true; } } catch { } return false; } public unsafe static void Tick() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Invalid comparison between Unknown and I4 //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Invalid comparison between Unknown and I4 if (!_active) { return; } try { MainGame instance = MainGame.Instance; if ((Object)(object)instance == (Object)null || (int)instance.gameState != 1) { Cancel("not in the game"); Unmark(); return; } MovementComponent val = (((Object)(object)MainGame.PlayerController != (Object)null) ? MainGame.PlayerController.MovementComponent : null); if (val == null) { Cancel("no movement component"); Unmark(); } else if (MainGame.PlayerData.currentGameSceneId != _scene) { Cancel("the player changed place"); Unmark(); } else if (LazyWindowsStackController.HasAnyModalWindowOpened) { Cancel("a window opened"); } else if (Time.unscaledTime - _since > 90f) { Cancel("timeout"); } else if (Time.unscaledTime - _since > 0.4f && Pressed()) { Cancel("the player took over"); } else { if (!(Time.unscaledTime - _since > 1f) || val.IsMoving) { return; } CompletionState completion = val.Completion; if ((int)completion != 0 || !(Time.unscaledTime - _since < 8f)) { string text = "not moving any more (" + ((object)(*(CompletionState*)(&completion))/*cast due to .constrained prefix*/).ToString() + ")"; if ((int)completion != 1) { Plugin.Log.LogInfo((object)("Walk to " + _name + ": " + text + ", releasing the Keeper")); Release(); } Arrived(text); } } } catch (Exception ex) { _active = false; Plugin.LogThrottled("Walk tick: " + ex.Message); } } public static void Reset() { _active = false; _marked = null; } } internal sealed class CodexWindow { private enum BShow { All, Built, NotBuilt } private enum CShow { All, Items, Empty, Full } private enum CKind { All, Chests, Stockpiles } private sealed class ZSlot { public ZombieInfo Z; public int M; public bool Planned; } private sealed class ZPlan { public readonly Dictionary<string, List<ZSlot>> Slots = new Dictionary<string, List<ZSlot>>(); public readonly Dictionary<string, int> Missing = new Dictionary<string, int>(); public readonly Dictionary<string, ZSlot> Best = new Dictionary<string, ZSlot>(); public int Fit; public int Total; } private enum GCol { Num, Total, Why, Top, Bot, Skulls, Gain } private enum GFilter { All, Raise, Capped, Red, Empty } private enum ICol { Name, Red, Green, Blue, Have, Where } private sealed class IngRow { public Entry E; public string Name; public Vector3Int V; public readonly List<string> Ids = new List<string>(); public int Have; public int Bag; public ChestInfo Chest; public int InChest; } private enum IShow { All, NotStudied, Studied, Have, Craft, Sold, Bought } private enum IType { All, Food, Alchemy, Build, Body, Tools, Seeds, Fish, Quest } private enum RCol { Status, Name, Have, Science, Red, Green, Blue } private enum AShow { All, Known, Unknown, CanMix } private sealed class RRow { public Entry E; public StudyInfo S; public bool Done; public int Have; } private sealed class NowItem { public float H; public Action<Transform> Draw; } private enum PadZone { None, List, Stop } private sealed class PadFocus { public RectTransform Rt; public Action Act; public List<PadCell> Cells; } private sealed class PadCell { public RectTransform Rt; public string Tip; } private sealed class StationRow { public PlacedStation S; public List<PlacedStation> All; public List<ZombieInfo> Workers = new List<ZombieInfo>(); public int Empty; public List<ZombieInfo> Fit; public List<ZombieInfo> Free; public List<ZombieInfo> Busy; public ZombieInfo Named; public int Rank; } internal enum ZSub { Overview, Plan, Zombies, Morgue, Raising, Stations, Squads, Trees } internal enum ZCardSub { Overview, Body, Perks, Work } private sealed class ZAct { public string IconId; public string Icon; public string T1; public string T2; public string More; public Color C1 = UiKit.TextName; public Action Go; public ZombieInfo BuyFor; public TalentLevelUpDef Buy; } private enum ZCol { Status, Locate, Name, Type, Zone, Station, Tool, Power, T0, T1, T2, T3, T4, Nodes, Tech, Perks, Rename } private enum ZFilter { All, Problems, Waiting, Idle, Free, Level, Misplaced } private BShow _bShow; private string _bZone; private Dictionary<string, Dictionary<string, int>> _standing; private Dictionary<string, HashSet<string>> _builderZones; private float _placesAt = -100f; internal const string ChestsId = "__chests"; private readonly List<Entry> _chests = new List<Entry>(); private Entry _chestTable; private CShow _cShow; private CKind _cKind; private string _cZone; private int _cSort; private bool _cDesc; private float CwLoc = 22f; private float CwName = 170f; private float CwZone = 130f; private float CwFill = 64f; private GameObject _tableBtn; private GameObject _hover; private Component _tableBtnFor; private string _tableBtnKey; private WgoData _hoverTarget; private float _hoverBuiltAt; private string _hoverSig; private Component _tableClose; private TMP_Text _tableHeading; private Canvas _tableCanvas; private string _tableKey; private float _tableKeyAt; private RectTransform _tableTip; internal const string CorpsePrefix = "__corpse:"; private readonly Dictionary<string, Entry> _corpseEntries = new Dictionary<string, Entry>(); private bool _corpseZombieAim = true; private List<CorpseEval> _evals; private float _evalsAt = -100f; private bool _evalsAim = true; private bool _corpseFoldOpen; internal const string FactoryNowId = "__fnow"; private Entry _factNow; private const int SpeedLineH = 17; private const int SpeedLineInset = 31; internal const string FactoryPlanId = "f:plan"; private static readonly Color Amber = new Color(0.95f, 0.72f, 0.25f, 1f); private readonly List<Entry> _fact = new List<Entry>(); private Entry _factPlan; private List<ZombieInfo> _fZombies = new List<ZombieInfo>(); private float _fZombiesAt = -100f; private static readonly Dictionary<string, int> _fSel = new Dictionary<string, int>(); private static readonly Dictionary<string, string> _fPick = new Dictionary<string, string>(); private static int _fR = 1; private static int _fDays = 1; private static int _fCells; private static bool _fPerk = true; private static readonly int[] DaySteps = new int[11] { 1, 2, 3, 5, 7, 10, 14, 20, 30, 50, 100 }; private static string _fPlanSlot; private static string _fPlanSaved; internal const string GyOverviewId = "__gy_overview"; internal const string GyGravesId = "__gy_graves"; internal const string GyMapId = "__gy_map"; internal const string GyChurchId = "__gy_church"; internal const string GyCatalogueId = "__gy_catalogue"; private Entry _gyOverview; private Entry _gyGraves; private Entry _gyMap; private Entry _gyChurch; private Entry _gyCatalogue; private GCol _gSort = GCol.Gain; private bool _gDesc = true; private GFilter _gFilter; private static readonly Color Brass = new Color(0.64f, 0.47f, 0.19f, 1f); private static readonly Color Slate = new Color(0.42f, 0.44f, 0.49f, 1f); private static readonly Color Rust = new Color(0.55f, 0.23f, 0.18f, 1f); private static readonly Color Good = new Color(0.55f, 0.85f, 0.4f, 1f); private static readonly Color Bad = new Color(0.9f, 0.55f, 0.5f, 1f); private readonly Dictionary<GCol, float> _gw = new Dictionary<GCol, float>(); private const float GU = 1.22f; private const int GBand = 0; private const string MGrass = "#34402c"; private const string MPath = "#46445a"; private const string MArea = "#45522f"; private const string MCurb = "#9c8a5c"; private const string MPlan = "#2e3e52"; private const string MStone = "#4e4658"; private const string MRoof = "#3b3546"; private const string MBg = "#1c2018"; private GyGrid _gmGrid; private GyPlanner _gmPlan; private GraveyardInfo _gmFor; private string _gmSlot; private static readonly bool[] GmLayer = new bool[6] { true, true, true, true, false, true }; private static bool _gmAll; private string _gmPicked; private RectTransform _gmRoot; private RectTransform _gmPlate; private RectTransform _gmViewport; private RectTransform _gmGhost; private RectTransform _gmAnchor; private RectTransform _gmToast; private RectTransform _gmPlanContent; private RectTransform _gmPopup; private ScrollRect _gmMapScroll; private ScrollRect _gmPlanScroll; private TextMeshProUGUI _gmInfo; private TextMeshProUGUI _gmToastText; private float _gmS; private float _gmCell; private float _gmPad; private float _gmToastUntil; private const float GmChipF = 15f; private const float GmChipH = 22f; private const float GmPopW = 236f; private int _gmZMin; private int _gmRows; private int _gmHX = int.MinValue; private int _gmHZ; private bool _gmTipShown; private static readonly HashSet<string> _gmMissing = new HashSet<string>(); private static int _gmSprites; private static int _gmGlyphs; private static int _gmLooks; private static readonly Dictionary<string, string> KindCol = new Dictionary<string, string> { { "grave", "#8f8f9c" }, { "bench", "#b98a55" }, { "monument", "#c9c2b0" }, { "flowerbed", "#c86a8a" }, { "lantern", "#f0c050" }, { "columbarium", "#9fb0c8" } }; private static bool _gmCounted; private TextMeshProUGUI _gmProbe; private static readonly HashSet<string> _gmNoLook = new HashSet<string>(); private GyPlace _gmMoveP; private int _gmMoveSi = -1; private int _gmRmbFrame = -1; internal const string IngredientsId = "__ingredients"; private ICol _ingSort = ICol.Have; private bool _ingDesc = true; private bool _ingHave; private Entry _ingEntry; private readonly Dictionary<ICol, float> _iw = new Dictionary<ICol, float>(); private static readonly Color RuneRed = new Color(0.93f, 0.38f, 0.3f, 1f); private static readonly Color RuneBlue = new Color(0.42f, 0.63f, 0.93f, 1f); private int _iRune; internal const string ResearchId = "__research"; private static readonly Color Green = new Color(0.55f, 0.85f, 0.4f, 1f); private IShow _iShow; private IType _iType; private RCol _rSort; private bool _rDesc; private AShow _aShow; private int _aRune; private string _aStation; private Entry _researchEntry; private int _barStops; private Dictionary<string, int> _owned; private float _ownedAt = -100f; private static readonly Dictionary<IType, string[]> TypeGroups = new Dictionary<IType, string[]> { { IType.Food, new string[1] { "food_bag" } }, { IType.Alchemy, new string[3] { "alch_bag", "pot_bag", "battle_potion" } }, { IType.Build, new string[1] { "buil_bag" } }, { IType.Body, new string[7] { "bodypart", "gr_skin", "gr_bones", "gr_skulls", "gr_heart", "gr_brain", "gr_guts" } }, { IType.Tools, new string[4] { "tool", "weapon", "melee", "range" } }, { IType.Seeds, new string[4] { "seed", "seedable", "fertilizer", "vineyard_seed" } }, { IType.Fish, new string[1] { "fishes" } }, { IType.Quest, new string[1] { "quest_bag" } } }; private readonly Dictionary<RCol, float> _rw = new Dictionary<RCol, float>(); private const int HowMixRows = 6; private string _findNote; private string _findNoteItem; private readonly Dictionary<string, string> _ingText = new Dictionary<string, string>(); private int _mixLimit = 100; private bool _mixAll; private int _mixPool; private string _mixFor; private const int MixPage = 100; private readonly Entry _nowEntry = new Entry { Kind = EntryKind.Now, Id = "__now", Name = "", SortKey = "\0n" }; private const float NowRowH = 36f; private const float NowCardOver = 36f; private const float NowGap = 6f; private static MethodInfo _twBubble; private static float _twLookAt = -100f; private PadZone _fz; private int _fIdx; private Entry _fEntry; private RectTransform _fRt; private int _cardGen; private int _seenGen = -1; private bool _padFollowed; private readonly List<KeyValuePair<RectTransform, Entry>> _padList = new List<KeyValuePair<RectTransform, Entry>>(); private RectTransform _padMore; private static readonly Vector3[] PadCorners = (Vector3[])(object)new Vector3[4]; private int _padFirstRowSeen = -1; private readonly List<Entry> _quests = new List<Entry>(); private List<QuestInfo> _qInfos = new List<QuestInfo>(); private List<PersonInfo> _qPeople = new List<PersonInfo>(); private int _qView; private bool _qShowUnknown; private readonly HashSet<string> _qFlipped = new HashSet<string>(); private Dictionary<string, WgoData> _npcWgo; private const float TabGap = 4f; private const float TabH = 26f; private const float TabsTop = -60f; private const float TabsBottom = -116f; private const float ContentTop = -124f; private RectTransform _tabsBox; private RectTransform _tabsContent; private GridLayoutGroup _tabsGrid; private float _gridWidth = -1f; private int _gridShown = -1; internal const string VOverviewId = "__v_overview"; internal const string VSellId = "__v_sell"; private Entry _vOverview; private Entry _vSell; private readonly float Scale; private readonly float W; private readonly float H; private const float ListW = 300f; private const int MaxListRows = 150; private const float Pad = 26f; private readonly RectTransform _root; private RectTransform _listContent; private RectTransform _cardContent; private RectTransform _tabsRow; private ScrollRect _cardScroll; private ScrollRect _listScroll; private TextMeshProUGUI _searchText; private TextMeshProUGUI _title; private TextMeshProUGUI _status; private TextMeshProUGUI _keys; private TMP_InputField _search; private readonly List<Image> _tabImgs = new List<Image>(); private readonly List<RectTransform> _tabRects = new List<RectTransform>(); private Button _backBtn; private Button _showAllBtn; private TextMeshProUGUI _showAllLabel; private CodexIndex _index; private int _tab; private string _query = ""; private Entry _current; private readonly List<Entry> _history = new List<Entry>(); private const int MaxHistory = 15; private bool _listDirty = true; private bool _rawOpen; private readonly List<PadFocus> _padCard = new List<PadFocus>(); private bool _padInCard; private int _padCardIdx; private RectTransform _padFrame; private RectTransform _padListRow; private RectTransform _showAllRt; private RectTransform _searchRt; private string _drawnLang; private const int TabCount = 10; private static readonly int[] TabOrder = new int[10] { 9, 0, 6, 2, 7, 5, 3, 1, 4, 8 }; private bool _everOpened; private static readonly string[] FaqTabs = new string[10] { "items", "buildings", "zombies", "alchemy", "graveyard", "vendors", "chests", "quests", "factory", "now" }; private string _indexKey; private float _indexAt; private readonly Queue<int> _pendingTabs = new Queue<int>(); private bool _redrawAfterPending; private const float IndexMaxAge = 300f; private string _tabSig; private string _keysText; private string _keysStatus; private bool _keysPad; private bool _keysMap; private readonly List<Entry> _zombies = new List<Entry>(); internal const string RaisingId = "__raising"; internal const string TalentPrefix = "__talent:"; private readonly List<Entry> _alchemy = new List<Entry>(); private readonly List<Entry> _zones = new List<Entry>(); private readonly List<Entry> _vendors = new List<Entry>(); internal const string GraveyardId = "__graveyard"; private GraveyardInfo _gy; private bool _scrollToCurrent; private int _listLimit = 150; private RectTransform _scrollAfterDraw; private string _padHintSig; private string _goalPickFor; private List<EmptyStation> _emptyCache; private HashSet<string> _goalPath; internal const float InsW = 434f; internal const float InsH = 252f; private const float SlotW = 148f; private const float SlotH = 66f; private const float SlotStep = 70f; private const float SlotTop = 2f; private const float PocketsY = 216f; private const float BodyTop = 24f; private const float BodyH = 161f; private const float BodyX = 217f; private ZombieInfo _renaming; private TMP_InputField _renameField; private string _renameText; private const int StationsPerPage = 10; private int _stPage; private const float StGap = 4f; private const float StPad = 4f; private const float StIconW = 22f; private float _stNameW; private float _stZoneW; private float _stNeedW; private float _stFitW; private float _stWorkW; private float _stDoW; internal const string MorgueId = "__morgue"; internal const string StationsId = "__stations"; internal const string SquadsId = "__squads"; private const float ZListW = 176f; private Entry _morgueEntry; private Entry _stationsEntry; private Entry _squadsEntry; private ZSub _zSubLast; private ZCardSub _zCardSub = (ZCardSub)Mathf.Clamp(((Object)(object)Plugin.Instance != (Object)null && Plugin.Instance.ZombieCardTab != null) ? Plugin.Instance.ZombieCardTab.Value : 0, 0, 3); private List<UpgradeIdea> _zIdeas = new List<UpgradeIdea>(); private int _corpseCount = -1; private float _corpseCountAt; private const float UpgradeRowH = 34f; private RectTransform _listArea; private RectTransform _cardArea; private RectTransform _zbar; private RectTransform _host; private RectTransform _tip; private TextMeshProUGUI _tipText; private float _zbarH; private bool _cardDirty; private bool _lastWide; private bool _lastBar; private Entry _tableEntry; private Entry _overviewEntry; internal const string TableId = "__table"; internal const string OverviewId = "__overview"; private ZCol _zSort; private bool _zDesc; private string _zZone; private ZFilter _zFilter; private string _zThrTalent; private string _zThrLabel; private int _zThrLock; private CraftDef _zThrCraft; private string _zCardTalent; private int _padCell = -1; private int _padFirstRow = -1; private string _zCardFor; private readonly Dictionary<ZCol, float> _cw = new Dictionary<ZCol, float>(); private List<SquadInfo> _squads; private int _padKeep = -1; private GameObject _zwBtn; private GameObject _zwTip; private Component _zwFor; private Component _zwClose; private Canvas _zwCanvas; private string _zwZombie; private float _zwReadAt = -100f; internal const string PlanId = "__plan"; private Entry _planEntry; private string _planSel; private PKind? _planKind; private string _planTalent; private bool _planFreeOnly; private bool _planFightersLast; private readonly Dictionary<string, int> _planAlt = new Dictionary<string, int>(); private readonly Dictionary<string, string> _planNotYet = new Dictionary<string, string>(); private readonly Dictionary<RectTransform, string> _planStops = new Dictionary<RectTransform, string>(); private const float PFBody = 16f; private const float PFTitle = 19f; private const float PFSmall = 14f; private const float PFTiny = 13f; private const float PFHead = 17f; private static readonly Color PTitle = Hex("#fff1cc"); private static readonly Color PWhy = Hex("#c8c0ac"); private static readonly Color PDim2 = Hex("#8a8990"); private static readonly Color PGold = Hex("#f2c94c"); private static readonly Color PGreen = Hex("#c8f4a0"); private PlanInput _planIn; private RectTransform _planRight; private int _planRightPad; private readonly Dictionary<string, Action<bool>> _planMarks = new Dictionary<string, Action<bool>>(); private PlanResult _planRes; private List<PlanStep> _planShown; private List<PlanStep> _planOrdered; private Func<PlanStep, string> _planNum; private List<KeyValuePair<string, string>> _planHidden; private List<ZombieInfo> _planPins; internal double PlanBarMs; private Entry DefaultChestEntry => _chestTable; private bool HasChests => _chests.Any((Entry e) => e.Chest != null); private float CwItems => Mathf.Max(80f, CardWidth - 8f - CwLoc - CwName - CwZone - CwFill - 20f); private bool HasFactory => Factory.Crafts.Count > 0; private static string FactoryPlansFile => Path.Combine(Path.Combine(Paths.ConfigPath, "GK2Codex"), "factory_plans.txt"); private Entry DefaultGyEntry => _gyOverview ?? _gyChurch ?? _gyCatalogue; private float TableWidth { get { if (!Wide) { return W - 52f - 300f - 10f - 22f; } return CardWidth - 8f; } } private float GK => 1f / Scale; private bool GyMapShown { get { if (IsOpen && _tab == 4 && _query.Length == 0 && _gyMap != null && _current == _gyMap && (Object)(object)_gmPlate != (Object)null) { return ((Component)_gmPlate).gameObject.activeInHierarchy; } return false; } } private bool GmPopupOpen { get { if ((Object)(object)_gmPopup != (Object)null) { return ((Component)_gmPopup).gameObject.activeInHierarchy; } return false; } } private bool GmOwnsKeys { get { if (GyMapShown) { if (!GmPopupOpen) { return GmMoving; } return true; } return false; } } private GyGrid G => _gmGrid; private bool GmMoving { get { if (_gmMoveP != null) { return _gmMoveSi >= 0; } return false; } } private bool GmOnZone { get { if (_gmHX != int.MinValue && _gmHZ >= 0) { return _gmHZ < G.D; } return false; } } private Entry IngredientsEntry { get { if (_ingEntry == null) { _ingEntry = new Entry { Kind = EntryKind.Alchemy, Id = "__ingredients", Name = L10n.T("AViewIngredients"), IconId = GameApi.ItemIcon("science", isGroup: false), SortKey = "\0i" }; } return _ingEntry; } } private bool NarrowBar { get { if (((_tab == 0 || _tab == 1 || _tab == 2) && _query.Length == 0) || _tab == 3 || _tab == 7 || _tab == 8) { return !Wide; } return false; } } private static bool ShowingAll { get { if (!Plugin.IsDemo) { return Plugin.Instance.ShowAll.Value; } return false; } } private Entry ResearchEntry { get { if (_researchEntry == null) { _researchEntry = new Entry { Kind = EntryKind.Item, Id = "__research", Name = L10n.T("RResearch"), IconId = GameApi.ItemIcon("science", isGroup: false), SortKey = "\0r" }; } return _researchEntry; } } private bool ListShown { get { if (!Wide && (Object)(object)_listArea != (Object)null) { return ((Component)_listArea).gameObject.activeInHierarchy; } return false; } } private PadFocus FocusStop { get { if (_fz != PadZone.Stop || _fIdx < 0 || _fIdx >= _padCard.Count) { return null; } return _padCard[_fIdx]; } } private bool HasQuests => _qInfos.Count > 0; private Entry DefaultVendorEntry => _vOverview; public bool IsOpen { get { if ((Object)(object)_root != (Object)null) { return ((Component)_root).gameObject.activeSelf; } return false; } } public bool SearchFocused { get { if (IsOpen) { if (!((Object)(object)_search != (Object)null) || !_search.isFocused) { return RenameFocused; } return true; } return false; } } private static GameKey ShowAllKey { get { GamePad.Chord padShowAll = Plugin.Instance.PadShowAll; if (padShowAll != null && !padShowAll.IsNone) { return padShowAll.Main; } return GameKey.None; } } private static string GoalFilter { get { try { string value = Plugin.Instance.ZombieGoalFilter.Value; return Zombies.TalentIds.Contains(value) ? value : null; } catch { return null; } } set { try { Plugin.Instance.ZombieGoalFilter.Value = value ?? ""; } catch { } } } private bool RenameFocused { get { if ((Object)(object)_renameField != (Object)null) { return _renameField.isFocused; } return false; } } private float ListWidth { get { if (_tab != 2) { return 300f; } return 176f; } } private float ZCardW { get { if (!Wide) { return W - 52f - ListWidth - 10f - 14f; } return CardWidth; } } private bool Wide { get { if (((_tab != 4 && _tab != 5 && _tab != 9) || _query.Length != 0) && (_tab != 2 || _query.Length != 0 || (!IsTable(_current) && !IsPlan(_current))) && _tab != 6 && (_tab != 0 || _query.Length != 0 || !IsResearch(_current))) { if (_tab == 3) { return IsIngredients(_current); } return false; } return true; } } private RectTransform Host { get { if (!((Object)(object)_host != (Object)null)) { return _cardContent; } return _host; } } private IEnumerable<ZombieInfo> RealZombies => from e in _zombies where e.Zombie != null select e.Zombie; private float CardWidth => W - 52f - 14f; private void ReadPlaces() { if (_standing != null && Time.unscaledTime - _placesAt < 2f) { return; } _standing = new Dictionary<string, Dictionary<string, int>>(); _builderZones = new Dictionary<string, HashSet<string>>(); try { foreach (GameSceneData gameSceneData in MainGame.Instance.GameSave.worldData.gameSceneDataList) { if (gameSceneData == null || gameSceneData.wgoDataList == null) { continue; } foreach (WgoData wgoData in gameSceneData.wgoDataList) { if (wgoData == null || string.IsNullOrEmpty(((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id)) { continue; } try { if (wgoData.isTempObject) { continue; } } catch { } string text = null; try { text = Storage.ZoneIdOf(wgoData.WorldZoneData); } catch { } text = text ?? ""; if (!_standing.TryGetValue(((ObjectLinkedT