using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using AdventureGuide.Config; using AdventureGuide.Data; using AdventureGuide.Diagnostics; using AdventureGuide.Navigation; using AdventureGuide.Patches; using AdventureGuide.Rendering; using AdventureGuide.State; using AdventureGuide.UI; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using ImGuiNET; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using TMPro; using UnityEngine; using UnityEngine.AI; using UnityEngine.EventSystems; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AdventureGuide")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+bfa55558cb8c2118ef5fe2ac2ac03fdad8bac222")] [assembly: AssemblyProduct("AdventureGuide")] [assembly: AssemblyTitle("AdventureGuide")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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; } } } public sealed class SpawnPointBridge { public enum SpawnState { Alive, Dead, Mined, NightLocked, QuestGated, DirectlyPlacedDead, NotFound } public readonly struct SpawnInfo { public readonly SpawnState State; public readonly SpawnPoint? LiveSpawnPoint; public readonly NPC? LiveNPC; public readonly MiningNode? LiveMiningNode; public readonly float RespawnSeconds; public SpawnInfo(SpawnState state, SpawnPoint? liveSP = null, NPC? liveNPC = null, MiningNode? miningNode = null, float respawnSeconds = 0f) { State = state; LiveSpawnPoint = liveSP; LiveNPC = liveNPC; LiveMiningNode = miningNode; RespawnSeconds = respawnSeconds; } } private readonly struct PosKey : IEquatable { private readonly int _x; private readonly int _y; private readonly int _z; public PosKey(float x, float y, float z) { _x = Mathf.RoundToInt(x * 100f); _y = Mathf.RoundToInt(y * 100f); _z = Mathf.RoundToInt(z * 100f); } public bool Equals(PosKey other) { return _x == other._x && _y == other._y && _z == other._z; } public override bool Equals(object? obj) { return obj is PosKey other && Equals(other); } public override int GetHashCode() { return (_x * 397) ^ (_y * 17) ^ _z; } } private readonly Dictionary _index = new Dictionary(); private readonly Dictionary> _npcByName = new Dictionary>(); private const float MaxDriftSqr = 4f; public void Rebuild() { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) _index.Clear(); _npcByName.Clear(); if (SpawnPointManager.SpawnPointsInScene != null) { foreach (SpawnPoint item in SpawnPointManager.SpawnPointsInScene) { if (!((Object)(object)item == (Object)null)) { Vector3 position = ((Component)item).transform.position; PosKey key = new PosKey(position.x, position.y, position.z); _index.TryAdd(key, item); } } } NPC[] array = Object.FindObjectsOfType(); foreach (NPC val in array) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.NPCName)) { string key2 = val.NPCName.ToLowerInvariant(); if (!_npcByName.TryGetValue(key2, out List value)) { value = new List(); _npcByName[key2] = value; } value.Add(val); } } } public SpawnInfo GetState(float x, float y, float z, string expectedNPCName) { PosKey key = new PosKey(x, y, z); if (_index.TryGetValue(key, out SpawnPoint value)) { return ClassifySpawnPoint(value, expectedNPCName); } NPC val = FindDirectlyPlacedNPC(x, y, z, expectedNPCName); if ((Object)(object)val != (Object)null) { MiningNode component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { if (IsMiningNodeMined(component)) { float miningNodeRespawnSeconds = GetMiningNodeRespawnSeconds(component); return new SpawnInfo(SpawnState.Mined, null, val, component, miningNodeRespawnSeconds); } return new SpawnInfo(SpawnState.Alive, null, val, component); } return new SpawnInfo(SpawnState.Alive, null, val); } return new SpawnInfo(SpawnState.DirectlyPlacedDead); } public static bool IsExpectedNPCAlive(SpawnPoint sp, string expectedName) { return sp.MyNPCAlive && (Object)(object)sp.SpawnedNPC != (Object)null && string.Equals(sp.SpawnedNPC.NPCName, expectedName, StringComparison.OrdinalIgnoreCase); } private static SpawnInfo ClassifySpawnPoint(SpawnPoint sp, string expectedNPCName) { if (!sp.canSpawn) { return new SpawnInfo(SpawnState.QuestGated, sp); } if (sp.NightSpawn && !IsNightHours()) { if (IsExpectedNPCAlive(sp, expectedNPCName)) { return new SpawnInfo(SpawnState.Alive, sp, sp.SpawnedNPC); } return new SpawnInfo(SpawnState.NightLocked, sp); } if (IsExpectedNPCAlive(sp, expectedNPCName)) { return new SpawnInfo(SpawnState.Alive, sp, sp.SpawnedNPC); } if (sp.MyNPCAlive && (Object)(object)sp.SpawnedNPC != (Object)null) { return new SpawnInfo(SpawnState.NotFound, sp); } float num = 60f * GetSpawnTimeMod(); float respawnSeconds = ((num > 0f) ? (sp.actualSpawnDelay / num) : 0f); return new SpawnInfo(SpawnState.Dead, sp, null, null, respawnSeconds); } private static bool IsNightHours() { int hour = GameData.Time.GetHour(); return hour > 22 || hour < 4; } private NPC? FindDirectlyPlacedNPC(float x, float y, float z, string expectedName) { //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) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) if (!_npcByName.TryGetValue(expectedName.ToLowerInvariant(), out List value)) { return null; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(x, y, z); foreach (NPC item in value) { if (!((Object)(object)item == (Object)null)) { Vector3 val2 = ((Component)item).transform.position - val; if (((Vector3)(ref val2)).sqrMagnitude <= 4f) { return item; } } } return null; } private static float GetSpawnTimeMod() { GameManager gM = GameData.GM; return ((Object)(object)gM != (Object)null) ? gM.SpawnTimeMod : 1f; } public static bool IsMiningNodeMined(MiningNode node) { return MiningNodeTracker.IsMined(node); } public static float GetMiningNodeRespawnSeconds(MiningNode node) { return MiningNodeTracker.GetRemainingSeconds(node).GetValueOrDefault(); } } namespace AdventureGuide { [BepInPlugin("wow-much.adventure-guide", "Adventure Guide", "2026.327.2")] public sealed class Plugin : BaseUnityPlugin { private Harmony? _harmony; private GuideConfig? _config; private GuideData? _data; private QuestStateTracker? _state; private EntityRegistry? _entities; private NavigationController? _nav; private ArrowRenderer? _arrow; private GroundPathRenderer? _groundPath; private WorldMarkerSystem? _markers; private SpawnTimerTracker? _timers; private MiningNodeTracker? _miningTracker; private LootScanner? _lootScanner; private ImGuiRenderer? _imgui; private GuideWindow? _window; private TrackerState? _trackerState; private TrackerWindow? _tracker; private bool _wasTextInputActive; private bool _gameUIVisible = true; private bool _inGameplay; private bool _discoveryDone; private bool _wasEditUIMode; internal static ManualLogSource Log { get; private set; } static Plugin() { Log = null; AppDomain.CurrentDomain.AssemblyResolve += delegate(object _, ResolveEventArgs args) { if (new AssemblyName(args.Name).Name == "System.Numerics.Vectors") { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (assembly.GetName().Name == "System.Numerics") { return assembly; } } } return null; }; } private void Awake() { //IL_0510: Unknown result type (might be due to invalid IL or missing references) //IL_051a: Expected O, but got Unknown //IL_052c: Unknown result type (might be due to invalid IL or missing references) //IL_0531: Unknown result type (might be due to invalid IL or missing references) //IL_057c: Unknown result type (might be due to invalid IL or missing references) //IL_0581: Unknown result type (might be due to invalid IL or missing references) //IL_0590: Unknown result type (might be due to invalid IL or missing references) //IL_0595: Unknown result type (might be due to invalid IL or missing references) //IL_064c: Unknown result type (might be due to invalid IL or missing references) //IL_0661: Unknown result type (might be due to invalid IL or missing references) //IL_0676: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; _config = new GuideConfig(((BaseUnityPlugin)this).Config); _data = GuideData.Load(Log); _state = new QuestStateTracker(_data); _trackerState = new TrackerState(); _trackerState.LoadFromConfig(_config); float num = ((_config.UiScale.Value >= 0f) ? _config.UiScale.Value : 1f); _config.ResolvedUiScale = num; string iniPath = Path.Combine(Paths.ConfigPath, "wow-much.adventure-guide.imgui.ini"); _imgui = new ImGuiRenderer(Log) { UiScale = num, IniPath = iniPath }; if (!_imgui.Init()) { Log.LogError((object)"ImGui.NET init failed — mod cannot render UI"); return; } _config.UiScale.SettingChanged += OnUiScaleChanged; _config.ResetWindowLayout.SettingChanged += OnResetWindowLayout; _entities = new EntityRegistry(); _timers = new SpawnTimerTracker(); _miningTracker = new MiningNodeTracker(); SpawnPointBridge bridge = new SpawnPointBridge(); _lootScanner = new LootScanner(); _nav = new NavigationController(_data, _entities, _state, _timers, _miningTracker, _lootScanner); _arrow = new ArrowRenderer(_nav); _arrow.Enabled = _config.ShowArrow.Value; _config.ShowArrow.SettingChanged += OnShowArrowChanged; _groundPath = new GroundPathRenderer(_nav); _groundPath.Enabled = _config.ShowGroundPath.Value; _config.ShowGroundPath.SettingChanged += OnShowGroundPathChanged; _markers = new WorldMarkerSystem(_data, _state, bridge, _lootScanner, _config); _markers.Enabled = _config.ShowWorldMarkers.Value; _config.ShowWorldMarkers.SettingChanged += OnShowWorldMarkersChanged; _config.TrackerEnabled.SettingChanged += OnTrackerEnabledChanged; _config.ReplaceQuestLog.SettingChanged += OnReplaceQuestLogChanged; NavigationHistory history = new NavigationHistory(_config.HistoryMaxSize.Value); _config.HistoryMaxSize.SettingChanged += delegate { history.MaxSize = _config.HistoryMaxSize.Value; }; _window = new GuideWindow(_data, _state, _nav, history, _trackerState, _config); _state.SetHistory(history); _window.Filter.LoadFrom(_config); _tracker = new TrackerWindow(_data, _state, _nav, _trackerState, _window, _config); _imgui.OnLayout = delegate { _window.Draw(); _tracker.Draw(); _arrow.Draw(); _config.LayoutResetRequested = false; }; DebugAPI.Data = _data; DebugAPI.State = _state; DebugAPI.Filter = _window.Filter; DebugAPI.Nav = _nav; DebugAPI.Entities = _entities; DebugAPI.GroundPath = _groundPath; QuestAssignPatch.Tracker = _state; QuestAssignPatch.Nav = _nav; QuestAssignPatch.Loot = _lootScanner; QuestAssignPatch.TrackerPins = _trackerState; QuestFinishPatch.Tracker = _state; QuestFinishPatch.Nav = _nav; QuestFinishPatch.Loot = _lootScanner; QuestFinishPatch.TrackerPins = _trackerState; InventoryPatch.Tracker = _state; InventoryPatch.Nav = _nav; InventoryPatch.Loot = _lootScanner; SpawnPatch.Registry = _entities; SpawnPatch.Timers = _timers; SpawnPatch.Markers = _markers; SpawnPatch.Loot = _lootScanner; DeathPatch.Registry = _entities; DeathPatch.Timers = _timers; DeathPatch.Markers = _markers; DeathPatch.Loot = _lootScanner; QuestMarkerPatch.SuppressGameMarkers = _config.ShowWorldMarkers.Value; PointerOverUIPatch.Renderer = _imgui; QuestLogPatch.ReplaceQuestLog = _config.ReplaceQuestLog; SceneManager.sceneLoaded += OnSceneLoaded; _harmony = new Harmony("wow-much.adventure-guide"); _harmony.PatchAll(); QuestStateTracker? state = _state; Scene activeScene = SceneManager.GetActiveScene(); state.OnSceneChanged(((Scene)(ref activeScene)).name); _entities.SyncFromLiveNPCs(); _miningTracker.Rescan(); _lootScanner.OnSceneLoaded(); _trackerState.OnCharacterLoaded(); NavigationController? nav = _nav; GuideConfig? config = _config; activeScene = SceneManager.GetActiveScene(); nav.LoadPerCharacter(config, ((Scene)(ref activeScene)).name); activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; _inGameplay = name != "Menu" && name != "LoadScene"; int num2 = 0; foreach (QuestEntry item in _data.All) { if (item.HasSteps) { num2++; } } Log.LogInfo((object)("Adventure Guide v2026.327.2\n" + $" Quests: {_data.Count} in guide, {num2} with step data\n" + $" Controls: {_config.ToggleKey.Value} = guide, {_config.TrackerToggleKey.Value} = tracker, {_config.GroundPathToggleKey.Value} = ground path\n" + " Config: BepInEx/config/wow-much.adventure-guide.cfg\n Tip: Install BepInEx ConfigurationManager for in-game settings (F1)")); } private void TryMergeUnknownQuests() { if (!_discoveryDone && _data != null) { int num = _data.MergeUnknownQuests(); if (num >= 0) { _discoveryDone = true; } } } private void Update() { //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) bool isVisible = GameUIVisibility.IsVisible; if (isVisible != _gameUIVisible) { _gameUIVisible = isVisible; SyncVisibility(); if (!isVisible) { _imgui?.ClearCaptureState(); if (_wasTextInputActive) { GameData.PlayerTyping = false; _wasTextInputActive = false; } } } bool editUIMode = GameData.EditUIMode; if (_wasEditUIMode && !editUIMode) { GameWindowOverlap.InvalidateRects(); } _wasEditUIMode = editUIMode; if (_gameUIVisible) { bool flag = _imgui?.WantTextInput ?? false; if (flag && !_wasTextInputActive) { GameData.PlayerTyping = true; } else if (!flag && _wasTextInputActive) { GameData.PlayerTyping = false; } _wasTextInputActive = flag; } if (!_discoveryDone) { TryMergeUnknownQuests(); } string currentScene = _state?.CurrentZone ?? ""; _lootScanner?.Update(_data, _state); _nav?.Update(currentScene); _groundPath?.Update(currentScene); _markers?.Update(currentScene); if (_config != null && _window != null && _inGameplay && !GameData.PlayerTyping) { if (Input.GetKeyDown(_config.ToggleKey.Value)) { _window.Toggle(); } if (_config.ReplaceQuestLog.Value && Input.GetKeyDown(InputManager.Journal)) { _window.Toggle(); } if (_config.TrackerEnabled.Value && Input.GetKeyDown(_config.TrackerToggleKey.Value)) { _tracker?.Toggle(); } if (Input.GetKeyDown(_config.GroundPathToggleKey.Value)) { _config.ShowGroundPath.Value = !_config.ShowGroundPath.Value; } } } private void OnGUI() { if (_gameUIVisible) { _imgui?.OnGUI(); } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (_config.UiScale.Value < 0f && ((Scene)(ref scene)).name != "Menu" && ((Scene)(ref scene)).name != "LoadScene") { float value = DetectUiScale(); _config.UiScale.Value = value; } CameraCache.Invalidate(); GameWindowOverlap.Reset(); _inGameplay = ((Scene)(ref scene)).name != "Menu" && ((Scene)(ref scene)).name != "LoadScene"; if (!_inGameplay) { _window?.Hide(); _tracker?.Hide(); _nav?.Clear(); } _markers?.OnSceneLoaded(); _entities?.Clear(); _timers?.Clear(); _miningTracker?.Rescan(); _lootScanner?.OnSceneLoaded(); _state?.OnSceneChanged(((Scene)(ref scene)).name); _trackerState?.OnCharacterLoaded(); _trackerState?.PruneCompleted(_state); _nav?.LoadPerCharacter(_config, ((Scene)(ref scene)).name); _nav?.OnGameStateChanged(((Scene)(ref scene)).name); } private void OnShowArrowChanged(object sender, EventArgs e) { SyncVisibility(); } private void OnShowGroundPathChanged(object sender, EventArgs e) { SyncVisibility(); } private void OnUiScaleChanged(object sender, EventArgs e) { float num = _config.UiScale.Value; if (num < 0f) { num = DetectUiScale(); } _config.ResolvedUiScale = num; _config.LayoutResetRequested = true; _imgui?.SetScale(num); } private void OnResetWindowLayout(object sender, EventArgs e) { if (_config.ResetWindowLayout.Value) { _imgui?.ClearWindowState(); _config.LayoutResetRequested = true; _config.ResetWindowLayout.Value = false; } } private void OnShowWorldMarkersChanged(object sender, EventArgs e) { SyncVisibility(); QuestMarkerPatch.SuppressGameMarkers = _config.ShowWorldMarkers.Value; } private void OnTrackerEnabledChanged(object sender, EventArgs e) { _trackerState.Enabled = _config.TrackerEnabled.Value; } private void OnReplaceQuestLogChanged(object sender, EventArgs e) { if (_config.ReplaceQuestLog.Value) { QuestLog questLog = GameData.QuestLog; if ((Object)(object)questLog != (Object)null && (Object)(object)questLog.QuestWindow != (Object)null && questLog.QuestWindow.activeSelf) { questLog.QuestWindow.SetActive(false); _window?.Show(); } } } private void SyncVisibility() { bool gameUIVisible = _gameUIVisible; _arrow.Enabled = gameUIVisible && _config.ShowArrow.Value; _groundPath.Enabled = gameUIVisible && _config.ShowGroundPath.Value; _markers.Enabled = gameUIVisible && _config.ShowWorldMarkers.Value; } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; if (_config != null) { _config.ShowArrow.SettingChanged -= OnShowArrowChanged; _config.ShowGroundPath.SettingChanged -= OnShowGroundPathChanged; _config.ShowWorldMarkers.SettingChanged -= OnShowWorldMarkersChanged; _config.TrackerEnabled.SettingChanged -= OnTrackerEnabledChanged; _config.ReplaceQuestLog.SettingChanged -= OnReplaceQuestLogChanged; _config.UiScale.SettingChanged -= OnUiScaleChanged; _config.ResetWindowLayout.SettingChanged -= OnResetWindowLayout; QuestMarkerPatch.SuppressGameMarkers = false; } Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _tracker?.Dispose(); _trackerState?.SaveToConfig(); _nav?.SavePerCharacter(); _imgui?.Dispose(); _arrow?.Dispose(); _groundPath?.Destroy(); _markers?.Destroy(); _timers?.Clear(); _entities?.Clear(); _miningTracker?.Clear(); MarkerFonts.Destroy(); DebugAPI.Data = null; DebugAPI.State = null; DebugAPI.Filter = null; DebugAPI.Nav = null; DebugAPI.Entities = null; DebugAPI.GroundPath = null; } private static float DetectUiScale() { return Mathf.Clamp((float)Screen.height / 1080f, 0.5f, 4f); } } internal static class PluginInfo { public const string GUID = "wow-much.adventure-guide"; public const string Name = "Adventure Guide"; public const string Version = "2026.327.2"; } } namespace AdventureGuide.UI { public enum QuestFilterMode { Active, Available, Completed, All } public enum QuestSortMode { Alphabetical, ByZone, ByLevel } public class FilterState { private GuideConfig? _config; private QuestFilterMode _filterMode = QuestFilterMode.Active; private string _searchText = string.Empty; private string? _zoneFilter; private QuestSortMode _sortMode = QuestSortMode.Alphabetical; public int Version { get; private set; } public QuestFilterMode FilterMode { get { return _filterMode; } set { if (_filterMode != value) { _filterMode = value; Version++; GuideConfig? config = _config; if (config != null) { ((ConfigEntryBase)config.FilterMode).SetSerializedValue(value.ToString()); } } } } public string SearchText { get { return _searchText; } set { if (_searchText != value) { _searchText = value; Version++; } } } public string? ZoneFilter { get { return _zoneFilter; } set { if (_zoneFilter != value) { _zoneFilter = value; Version++; GuideConfig? config = _config; if (config != null) { ((ConfigEntryBase)config.ZoneFilter).SetSerializedValue(value ?? ""); } } } } public QuestSortMode SortMode { get { return _sortMode; } set { if (_sortMode != value) { _sortMode = value; Version++; GuideConfig? config = _config; if (config != null) { ((ConfigEntryBase)config.SortMode).SetSerializedValue(value.ToString()); } } } } public void LoadFrom(GuideConfig config) { _config = config; _filterMode = config.FilterMode.Value; _sortMode = config.SortMode.Value; string value = config.ZoneFilter.Value; _zoneFilter = (string.IsNullOrEmpty(value) ? null : value); Version++; } } public sealed class GuideWindow { private readonly GuideData _data; private readonly QuestStateTracker _state; private readonly FilterState _filter = new FilterState(); private readonly QuestListPanel _listPanel; private readonly QuestDetailPanel _detailPanel; private readonly NavigationHistory _history; private readonly GuideConfig _config; private bool _visible; public bool Visible => _visible; public FilterState Filter => _filter; public GuideWindow(GuideData data, QuestStateTracker state, NavigationController nav, NavigationHistory history, TrackerState tracker, GuideConfig config) { _data = data; _state = state; _history = history; _config = config; _listPanel = new QuestListPanel(data, state, _filter, tracker); _detailPanel = new QuestDetailPanel(data, state, nav, tracker, config); } public void Toggle() { _visible = !_visible; } public void Show() { _visible = true; } public void Hide() { _visible = false; } public void Draw() { //IL_0024: 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_0036: 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_007c: Unknown result type (might be due to invalid IL or missing references) if (_visible) { ImGuiCond val = (ImGuiCond)(_config.LayoutResetRequested ? 1 : 4); float resolvedUiScale = _config.ResolvedUiScale; ImGuiIOPtr iO = ImGui.GetIO(); Vector2 displaySize = ((ImGuiIOPtr)(ref iO)).DisplaySize; ImGui.SetNextWindowSize(new Vector2(780f * resolvedUiScale, 530f * resolvedUiScale), val); ImGui.SetNextWindowPos(new Vector2(displaySize.X * 0.5f, displaySize.Y * 0.5f), val, new Vector2(0.5f, 0.5f)); Theme.PushWindowStyle(); if (ImGui.Begin("Adventure Guide", ref _visible, (ImGuiWindowFlags)32)) { DrawTabBar(); } Theme.ClampWindowPosition(); ImGui.End(); Theme.PopWindowStyle(); } } private void DrawTabBar() { if (!ImGui.BeginTabBar("##GuideTabs")) { return; } if (ImGui.BeginTabItem("Quests")) { DrawQuestsTab(); ImGui.EndTabItem(); } if (ImGui.TabItemButton("<")) { NavigationHistory.PageRef? pageRef = _history.Back(); if (pageRef.HasValue && pageRef.Value.Type == NavigationHistory.PageType.Quest) { _state.SelectedQuestDBName = pageRef.Value.Key; } } if (ImGui.TabItemButton(">")) { NavigationHistory.PageRef? pageRef2 = _history.Forward(); if (pageRef2.HasValue && pageRef2.Value.Type == NavigationHistory.PageType.Quest) { _state.SelectedQuestDBName = pageRef2.Value.Key; } } ImGui.EndTabBar(); } private void DrawQuestsTab() { float num = ImGui.GetContentRegionAvail().X * 0.32f; ImGui.BeginChild("##LeftPanel", new Vector2(num, 0f), true); _listPanel.Draw(num); ImGui.EndChild(); ImGui.SameLine(); ImGui.BeginChild("##RightPanel", Vector2.Zero, true); _detailPanel.Draw(); ImGui.EndChild(); } } public sealed class QuestDetailPanel { private enum StepState { Completed, Current, Future } private readonly GuideData _data; private readonly QuestStateTracker _state; private readonly NavigationController _nav; private readonly TrackerState _tracker; private readonly GuideConfig _config; private const int MaxSubQuestDepth = 5; private bool IsNavigationEnabled => _config.ShowArrow.Value || _config.ShowGroundPath.Value; public QuestDetailPanel(GuideData data, QuestStateTracker state, NavigationController nav, TrackerState tracker, GuideConfig config) { _data = data; _state = state; _nav = nav; _tracker = tracker; _config = config; } public void Draw() { if (_state.SelectedQuestDBName == null) { ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); ImGui.TextWrapped("Select a quest from the list."); ImGui.PopStyleColor(); return; } QuestEntry byDBName = _data.GetByDBName(_state.SelectedQuestDBName); if (byDBName == null) { ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); ImGui.TextWrapped("Quest not found in guide data."); ImGui.PopStyleColor(); } else { DrawHeader(byDBName); DrawObjectives(byDBName); DrawRewards(byDBName); DrawPrerequisites(byDBName); } } private void DrawHeader(QuestEntry quest) { if (_tracker.Enabled && !_state.IsCompleted(quest.DBName)) { bool flag = _tracker.IsTracked(quest.DBName); if (flag) { ImGui.PushStyleColor((ImGuiCol)21, Theme.Accent); } if (ImGui.SmallButton(flag ? "[Untrack]" : "[Track]")) { if (flag) { _tracker.Untrack(quest.DBName); } else { _tracker.Track(quest.DBName); } } if (flag) { ImGui.PopStyleColor(); } ImGui.SameLine(); } ImGui.PushStyleColor((ImGuiCol)0, Theme.Header); ImGui.TextWrapped(quest.DisplayName); ImGui.PopStyleColor(); DrawLevelZoneLine(quest); if (quest.Acquisition != null) { foreach (AcquisitionSource item in quest.Acquisition) { ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); string method = item.Method; if (1 == 0) { } string text; switch (method) { case "dialog": if (item.SourceName == null) { goto default; } text = "Given by: " + item.SourceName; break; case "item_read": if (item.SourceName == null) { goto default; } text = "Read: " + item.SourceName; break; case "zone_entry": if (item.SourceName == null) { goto default; } text = "Enter: " + item.SourceName; break; case "quest_chain": if (item.SourceName == null) { goto default; } text = "Chain from: " + item.SourceName; break; default: text = ((item.SourceName != null) ? ("From: " + item.SourceName) : null); break; } if (1 == 0) { } string text2 = text; if (text2 != null) { if (item.ZoneName != null && item.Method == "dialog") { text2 = text2 + " (" + item.ZoneName + ")"; } ImGui.Text(text2); } ImGui.PopStyleColor(); } } if (quest.Completion != null) { foreach (CompletionSource item2 in quest.Completion) { if (item2.SourceName == null && item2.ZoneName == null) { continue; } ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); string method2 = item2.Method; if (1 == 0) { } string text; switch (method2) { case "item_turnin": case "dialog": if (item2.SourceName == null) { goto default; } text = "Turn in to: " + item2.SourceName; break; case "zone": if (item2.SourceName == null) { goto default; } text = "Complete at: " + item2.SourceName; break; default: text = ((item2.SourceName == null) ? null : ("Complete: " + item2.SourceName)); break; } if (1 == 0) { } string text3 = text; if (text3 == null) { ImGui.PopStyleColor(); continue; } bool flag2 = item2.ZoneName != null; bool flag3 = flag2; if (flag3) { text = item2.Method; bool flag4 = ((text == "item_turnin" || text == "dialog") ? true : false); flag3 = flag4; } if (flag3) { text3 = text3 + " (" + item2.ZoneName + ")"; } ImGui.Text(text3); ImGui.PopStyleColor(); } } if (quest.Description != null) { ImGui.Spacing(); ImGui.TextWrapped(quest.Description); } ImGui.Spacing(); ImGui.Separator(); ImGui.Spacing(); } private static void DrawLevelZoneLine(QuestEntry quest) { int? num = quest.LevelEstimate?.Recommended; string zoneContext = quest.ZoneContext; bool flag = quest.Flags?.Repeatable ?? false; if (!num.HasValue && zoneContext == null && !flag) { return; } ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); string text = ""; if (num.HasValue) { text = $"Lv {num}"; } if (zoneContext != null) { if (text.Length > 0) { text += " · "; } text += zoneContext; } if (flag) { if (text.Length > 0) { text += " · "; } text += "Repeatable"; } ImGui.Text(text); if (ImGui.IsItemHovered()) { List steps = quest.Steps; if (steps != null && steps.Count > 0) { ImGui.BeginTooltip(); ImGui.Text("Quest level: hardest step"); ImGui.Separator(); int? num2 = quest.LevelEstimate?.Recommended; foreach (QuestStep step in quest.Steps) { int? num3 = step.LevelEstimate?.Recommended; string text2 = (num3.HasValue ? $"Lv {num3,2}" : " "); bool flag2 = num2.HasValue && num3 == num2; string text3 = (flag2 ? " <" : ""); uint num4 = (flag2 ? Theme.TextPrimary : Theme.TextSecondary); ImGui.PushStyleColor((ImGuiCol)0, num4); ImGui.Text($" {step.Order}. {step.Description} {text2}{text3}"); ImGui.PopStyleColor(); } ImGui.EndTooltip(); } } ImGui.PopStyleColor(); } private void DrawObjectives(QuestEntry quest) { if (!quest.HasSteps) { ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); ImGui.TextWrapped("No guide data available for this quest."); ImGui.PopStyleColor(); } else if (ImGui.CollapsingHeader("Objectives", (ImGuiTreeNodeFlags)32)) { HashSet visited = new HashSet { quest.StableKey }; ImGui.Indent(16f); DrawSteps(quest, visited); ImGui.Unindent(16f); } } private void DrawSteps(QuestEntry quest, HashSet visited) { if (quest.Steps == null || quest.Steps.Count == 0) { return; } ImGui.PushID(quest.DBName); int currentStepIndex = StepProgress.GetCurrentStepIndex(quest, _state, _data); string text = null; for (int i = 0; i < quest.Steps.Count; i++) { QuestStep questStep = quest.Steps[i]; if (questStep.OrGroup != null && questStep.OrGroup == text) { ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); ImGui.Text(" -- OR --"); ImGui.PopStyleColor(); } StepState state = ((i >= currentStepIndex) ? ((i == currentStepIndex) ? StepState.Current : StepState.Future) : StepState.Completed); DrawStep(questStep, state, quest, visited); text = questStep.OrGroup; } ImGui.PopID(); } private void DrawStep(QuestStep step, StepState state, QuestEntry quest, HashSet visited) { if (1 == 0) { } uint num = state switch { StepState.Completed => Theme.QuestCompleted, StepState.Current => Theme.QuestActive, _ => Theme.TextPrimary, }; if (1 == 0) { } uint num2 = num; string text = $"{step.Order}. {step.Description}"; if (step.Action == "collect" && step.TargetKey != null && step.Quantity.HasValue) { int num3 = _state.CountItem(step.TargetKey); text += $" ({num3}/{step.Quantity})"; if (num3 >= step.Quantity.Value) { num2 = Theme.QuestCompleted; } } if (step.Action == "complete_quest" && step.TargetKey != null) { QuestEntry byStableKey = _data.GetByStableKey(step.TargetKey); if (byStableKey != null && _state.IsCompleted(byStableKey.DBName)) { num2 = Theme.QuestCompleted; } } int? num4 = step.LevelEstimate?.Recommended; string action; if (num4.HasValue) { int valueOrDefault = num4.GetValueOrDefault(); if (true) { action = step.Action; if (!(action == "collect") && !(action == "read")) { List factors = step.LevelEstimate.Factors; if (factors != null && factors.Count > 0) { text = text + " · " + step.LevelEstimate.Factors[0].Name; } } text += $" · Lv {valueOrDefault}"; goto IL_026d; } } action = step.Action; if (!(action == "collect") && !(action == "read")) { List factors = step.LevelEstimate?.Factors; if (factors != null && factors.Count > 0) { text = text + " · " + step.LevelEstimate.Factors[0].Name; } } goto IL_026d; IL_026d: DrawNavButton(step, quest); ImGui.PushStyleColor((ImGuiCol)0, num2); ImGui.Text(text); ImGui.PopStyleColor(); DrawStepSources(step, quest, visited); DrawSubQuestSteps(step, visited); if (_nav.IsNavigating(quest.DBName, step.Order)) { List<(ZoneLineEntry, float, bool, bool)> alternativeZoneLines = _nav.GetAlternativeZoneLines(_state.CurrentZone); if (alternativeZoneLines.Count > 1) { DrawZoneLineAlternatives(alternativeZoneLines, step); } } } private void DrawNavButton(QuestStep step, QuestEntry quest) { if (!IsNavigationEnabled || step.TargetKey == null) { return; } bool flag; if (!(step.TargetType == "item")) { flag = ((step.TargetType == "character") ? (step.TargetKey != null && _data.CharacterSpawns.ContainsKey(step.TargetKey)) : (step.TargetType == "zone" && (step.ZoneName != null || step.TargetKey != null))); } else { RequiredItemInfo requiredItemInfo = FindRequiredItem(quest, step); flag = requiredItemInfo != null && (requiredItemInfo.Sources?.Exists((ItemSource s) => HasNavigableSource(s))).GetValueOrDefault(); } bool flag2 = _nav.IsNavigating(quest.DBName, step.Order); if (!flag) { ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); ImGui.PushStyleVar((ImGuiStyleVar)0, 0.4f); ImGui.SmallButton($"[NAV]##{step.Order}"); ImGui.PopStyleVar(); ImGui.PopStyleColor(); if (ImGui.IsItemHovered((ImGuiHoveredFlags)512)) { ImGui.BeginTooltip(); ImGui.Text("No known source"); ImGui.EndTooltip(); } ImGui.SameLine(); return; } if (flag2) { ImGui.PushStyleColor((ImGuiCol)21, Theme.QuestActive); } if (ImGui.SmallButton($"[NAV]##{step.Order}")) { if (flag2) { _nav.Clear(); } else { _nav.NavigateTo(step, quest, _state.CurrentZone); } } if (flag2) { ImGui.PopStyleColor(); } if (ImGui.IsItemHovered()) { ImGui.BeginTooltip(); if (flag2) { ImGui.Text("Click to stop navigating"); } else { ImGui.Text("Navigate to " + (step.TargetName ?? step.Description)); } ImGui.EndTooltip(); } ImGui.SameLine(); } private void DrawStepSources(QuestStep step, QuestEntry quest, HashSet visited) { string action = step.Action; if ((!(action == "collect") && !(action == "read")) || step.TargetName == null) { DrawTips(step); return; } RequiredItemInfo requiredItemInfo = FindRequiredItem(quest, step); if (requiredItemInfo?.Sources == null || requiredItemInfo.Sources.Count == 0) { DrawTips(step); return; } ImGui.Indent(16f); ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); int num = Math.Min(requiredItemInfo.Sources.Count, 4); for (int i = 0; i < num; i++) { DrawSource(requiredItemInfo.Sources[i], quest, step, visited); } if (requiredItemInfo.Sources.Count > 4) { int num2 = requiredItemInfo.Sources.Count - 4; int valueOrDefault = requiredItemInfo.Sources[4].Level.GetValueOrDefault(); List? sources = requiredItemInfo.Sources; int valueOrDefault2 = sources[sources.Count - 1].Level.GetValueOrDefault(valueOrDefault); string arg = ((valueOrDefault == valueOrDefault2) ? $"Lv {valueOrDefault}" : $"Lv {valueOrDefault}-{valueOrDefault2}"); if (ImGui.TreeNode($"{num2} more sources ({arg})##{step.Order}")) { for (int j = 4; j < requiredItemInfo.Sources.Count; j++) { DrawSource(requiredItemInfo.Sources[j], quest, step, visited); } ImGui.TreePop(); } } ImGui.PopStyleColor(); ImGui.Unindent(16f); DrawTips(step); } private void DrawZoneLineAlternatives(List<(ZoneLineEntry line, float distance, bool isSelected, bool isAccessible)> alternatives, QuestStep step) { ImGui.Indent(16f); ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); string arg = $"{alternatives.Count} zone connections"; if (ImGui.TreeNode($"{arg}##zl_{step.Order}")) { for (int i = 0; i < alternatives.Count; i++) { (ZoneLineEntry line, float distance, bool isSelected, bool isAccessible) tuple = alternatives[i]; var (zoneLineEntry, num, flag, _) = tuple; if (!tuple.isAccessible) { ImGui.PushStyleVar((ImGuiStyleVar)0, 0.3f); ImGui.Text($"To {zoneLineEntry.DestinationDisplay} ({num:F0}m)"); ImGui.PopStyleVar(); if (zoneLineEntry.RequiredQuestGroups == null) { continue; } using List>.Enumerator enumerator = zoneLineEntry.RequiredQuestGroups.GetEnumerator(); if (!enumerator.MoveNext()) { continue; } List current = enumerator.Current; foreach (string item in current) { if (_state.IsCompleted(item)) { continue; } QuestEntry byDBName = _data.GetByDBName(item); if (byDBName != null) { ImGui.Indent(16f); if (ImGui.Selectable($"Requires: \"{byDBName.DisplayName}\"##rq_{step.Order}_{i}_{item}")) { _state.SelectQuest(byDBName.DBName); } ImGui.Unindent(16f); } } } else { string arg2 = $"To {zoneLineEntry.DestinationDisplay} ({num:F0}m)"; if (flag) { ImGui.PushStyleColor((ImGuiCol)0, Theme.QuestActive); } if (ImGui.Selectable($"{arg2}##zl_{step.Order}_{i}")) { _nav.PinZoneLine(zoneLineEntry); } if (flag) { ImGui.PopStyleColor(); } if (ImGui.IsItemHovered()) { ImGui.BeginTooltip(); ImGui.Text("Route via " + zoneLineEntry.DestinationDisplay); ImGui.EndTooltip(); } } } ImGui.TreePop(); } ImGui.PopStyleColor(); ImGui.Unindent(16f); } private void DrawSource(ItemSource src, QuestEntry quest, QuestStep step, HashSet visited, int depth = 0) { string type = src.Type; if (1 == 0) { } string text; int? nodeCount; switch (type) { case "drop": text = "Drops from: " + src.Name; break; case "vendor": text = "Sold by: " + src.Name; break; case "dialog_give": text = "Given by: " + src.Name; break; case "fishing": text = "Fishing"; break; case "mining": text = "Mining"; break; case "pickup": text = "Found in world"; break; case "crafting": text = "Crafted from: " + src.Name; break; case "quest_reward": text = "Quest reward: " + src.Name; break; case "ingredient": { string? name = src.Name; nodeCount = src.NodeCount; object obj; if (nodeCount.HasValue) { int valueOrDefault = nodeCount.GetValueOrDefault(); obj = $" x{valueOrDefault}"; } else { obj = ""; } text = "Ingredient: " + name + (string?)obj; break; } case "item_use": text = "Use: " + src.Name; break; default: text = src.Name ?? src.Type; break; } if (1 == 0) { } string text2 = text; string text3 = text2; if (src.Zone != null) { text3 = text3 + " · " + src.Zone; } nodeCount = src.Level; if (nodeCount.HasValue) { int valueOrDefault2 = nodeCount.GetValueOrDefault(); if (true) { text3 += $" · Lv {valueOrDefault2}"; } } if (src.Type == "quest_reward" && src.QuestKey != null) { QuestEntry byStableKey = _data.GetByStableKey(src.QuestKey); List list = byStableKey?.Steps; if (list != null && list.Count > 0 && visited.Count <= 5 && !visited.Contains(byStableKey.StableKey)) { DrawQuestRewardTree(src, byStableKey, text3, step, visited); return; } } List children = src.Children; if (children != null && children.Count > 0 && depth < 3) { if (!ImGui.TreeNode($"{text3}##src_{step.Order}_{depth}_{src.Type}_{src.Name}")) { return; } if (src.Type == "quest_reward" && src.QuestKey != null) { QuestEntry byStableKey2 = _data.GetByStableKey(src.QuestKey); if (byStableKey2 != null) { ImGui.PushStyleColor((ImGuiCol)0, Theme.QuestActive); if (ImGui.Selectable($"Open quest: {byStableKey2.DisplayName}##goto_{step.Order}_{src.QuestKey}")) { _state.SelectQuest(byStableKey2.DBName); } ImGui.PopStyleColor(); } } foreach (ItemSource child in src.Children) { DrawSource(child, quest, step, visited, depth + 1); } ImGui.TreePop(); return; } string text4 = src.MakeSourceId(); if (text4 != null) { bool flag = _nav.IsSourceActive(text4); if (flag) { uint num = (_nav.IsManualSourceOverride ? Theme.NavManualOverride : Theme.QuestActive); ImGui.PushStyleColor((ImGuiCol)0, num); } if (ImGui.Selectable($"{text3}##src_{step.Order}_{text4}")) { _nav.ToggleSource(text4, _state.CurrentZone); } if (flag) { ImGui.PopStyleColor(); } if (ImGui.IsItemHovered()) { ImGui.BeginTooltip(); string text5 = (flag ? "Remove from" : "Add to"); if (src.SourceKey != null) { ImGui.Text(text5 + " navigation: " + src.Name); } else { ImGui.Text(text5 + " navigation: " + (src.Zone ?? src.Scene)); } ImGui.EndTooltip(); } } else { ImGui.PushStyleColor((ImGuiCol)0, Theme.SourceDimmed); ImGui.Text(text3); ImGui.PopStyleColor(); } } private void DrawSubQuestSteps(QuestStep step, HashSet visited) { if (step.Action != "complete_quest" || step.TargetKey == null) { return; } QuestEntry byStableKey = _data.GetByStableKey(step.TargetKey); if (byStableKey?.Steps != null && byStableKey.Steps.Count != 0 && visited.Count <= 5 && !visited.Contains(byStableKey.StableKey)) { ImGui.Indent(16f); ImGui.PushStyleColor((ImGuiCol)0, Theme.QuestActive); if (ImGui.Selectable($"Open quest: {byStableKey.DisplayName}##cq_{step.Order}_{step.TargetKey}")) { _state.SelectQuest(byStableKey.DBName); } ImGui.PopStyleColor(); visited.Add(byStableKey.StableKey); DrawSteps(byStableKey, visited); visited.Remove(byStableKey.StableKey); ImGui.Unindent(16f); } } private void DrawQuestRewardTree(ItemSource src, QuestEntry subQuest, string label, QuestStep parentStep, HashSet visited) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) bool flag = _state.IsCompleted(subQuest.DBName); ImGuiTreeNodeFlags val = (ImGuiTreeNodeFlags)((!flag) ? 32 : 0); if (flag) { ImGui.PushStyleColor((ImGuiCol)0, Theme.QuestCompleted); } bool flag2 = ImGui.TreeNodeEx($"{label}##sqt_{parentStep.Order}_{src.QuestKey}", val); if (flag) { ImGui.PopStyleColor(); } if (flag2) { ImGui.PushStyleColor((ImGuiCol)0, Theme.QuestActive); if (ImGui.Selectable($"Open quest: {subQuest.DisplayName}##goto_{parentStep.Order}_{src.QuestKey}")) { _state.SelectQuest(subQuest.DBName); } ImGui.PopStyleColor(); visited.Add(subQuest.StableKey); DrawSteps(subQuest, visited); visited.Remove(subQuest.StableKey); ImGui.TreePop(); } } private void DrawTips(QuestStep step) { if (step.Tips == null || step.Tips.Count == 0) { return; } ImGui.Indent(16f); if (ImGui.TreeNode($"Tips##{step.Order}")) { ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); foreach (string tip in step.Tips) { ImGui.TextWrapped(tip); } ImGui.PopStyleColor(); ImGui.TreePop(); } ImGui.Unindent(16f); } private void DrawRewards(QuestEntry quest) { RewardInfo rewards = quest.Rewards; if (rewards == null || !HasAnyRewards(rewards) || !ImGui.CollapsingHeader("Rewards", (ImGuiTreeNodeFlags)32)) { return; } ImGui.Indent(16f); if (rewards.XP > 0) { ImGui.Text($"{rewards.XP} XP"); } if (rewards.Gold > 0) { ImGui.Text($"{rewards.Gold} Gold"); } if (rewards.ItemName != null) { ImGui.Text(rewards.ItemName); } if (rewards.VendorUnlock != null) { ImGui.Text("Unlocks " + rewards.VendorUnlock.ItemName + " at " + rewards.VendorUnlock.VendorName); } if (rewards.UnlockedZoneLines != null) { foreach (UnlockedZoneLine unlockedZoneLine in rewards.UnlockedZoneLines) { string text = "Opens path from " + unlockedZoneLine.FromZone + " to " + unlockedZoneLine.ToZone; List coRequirements = unlockedZoneLine.CoRequirements; if (coRequirements != null && coRequirements.Count > 0) { text = text + " (also requires " + string.Join(", ", unlockedZoneLine.CoRequirements) + ")"; } ImGui.Text(text); } } if (rewards.UnlockedCharacters != null) { foreach (UnlockedCharacter unlockedCharacter in rewards.UnlockedCharacters) { string text2 = ((unlockedCharacter.Zone != null) ? ("Enables " + unlockedCharacter.Name + " in " + unlockedCharacter.Zone) : ("Enables " + unlockedCharacter.Name)); ImGui.Text(text2); } } if (rewards.NextQuestName != null) { ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); ImGui.Text("Next: " + rewards.NextQuestName); ImGui.PopStyleColor(); } if (rewards.FactionEffects != null) { foreach (FactionEffect factionEffect in rewards.FactionEffects) { string arg = ((factionEffect.Amount >= 0) ? "+" : ""); ImGui.Text($"{factionEffect.FactionName}: {arg}{factionEffect.Amount}"); } } if (rewards.AlsoCompletes != null && rewards.AlsoCompletes.Count > 0) { ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); ImGui.Text("Also completes: " + string.Join(", ", rewards.AlsoCompletes)); ImGui.PopStyleColor(); } ImGui.Unindent(16f); } private static bool HasAnyRewards(RewardInfo r) { int result; if (r.XP <= 0 && r.Gold <= 0 && r.ItemName == null && r.VendorUnlock == null) { List unlockedZoneLines = r.UnlockedZoneLines; if (unlockedZoneLines == null || unlockedZoneLines.Count <= 0) { List unlockedCharacters = r.UnlockedCharacters; if ((unlockedCharacters == null || unlockedCharacters.Count <= 0) && r.NextQuestName == null) { List factionEffects = r.FactionEffects; if (factionEffects == null || factionEffects.Count <= 0) { List alsoCompletes = r.AlsoCompletes; result = ((alsoCompletes != null && alsoCompletes.Count > 0) ? 1 : 0); goto IL_007c; } } } } result = 1; goto IL_007c; IL_007c: return (byte)result != 0; } private void DrawPrerequisites(QuestEntry quest) { //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) if (quest.Prerequisites == null || quest.Prerequisites.Count == 0) { return; } HashSet hashSet = CollectStepTreeQuestKeys(quest); List list = new List(); foreach (Prerequisite prerequisite in quest.Prerequisites) { if (!hashSet.Contains(prerequisite.QuestKey)) { list.Add(prerequisite); } } if (list.Count == 0) { return; } bool flag = false; foreach (Prerequisite item in list) { if (!IsPrerequisiteCompleted(item)) { flag = true; break; } } ImGuiTreeNodeFlags val = (ImGuiTreeNodeFlags)(flag ? 32 : 0); if (!ImGui.CollapsingHeader("Prerequisites", val)) { return; } ImGui.Indent(16f); foreach (Prerequisite item2 in list) { uint num = (IsPrerequisiteCompleted(item2) ? Theme.QuestCompleted : Theme.TextPrimary); string text = ((item2.Item != null) ? (item2.QuestName + " (" + item2.Item + ")") : item2.QuestName); ImGui.PushStyleColor((ImGuiCol)0, num); if (ImGui.Selectable(text + "##prereq_" + item2.QuestKey)) { QuestEntry byStableKey = _data.GetByStableKey(item2.QuestKey); if (byStableKey != null) { _state.SelectQuest(byStableKey.DBName); } } ImGui.PopStyleColor(); } ImGui.Unindent(16f); } private static HashSet CollectStepTreeQuestKeys(QuestEntry quest) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); if (quest.Steps != null) { foreach (QuestStep step in quest.Steps) { if (step.Action == "complete_quest" && step.TargetKey != null) { hashSet.Add(step.TargetKey); } } } if (quest.RequiredItems != null) { foreach (RequiredItemInfo requiredItem in quest.RequiredItems) { if (requiredItem.Sources != null) { CollectQuestRewardKeys(requiredItem.Sources, hashSet); } } } return hashSet; } private static void CollectQuestRewardKeys(List sources, HashSet keys) { foreach (ItemSource source in sources) { if (source.Type == "quest_reward" && source.QuestKey != null) { keys.Add(source.QuestKey); } if (source.Children != null) { CollectQuestRewardKeys(source.Children, keys); } } } private bool IsPrerequisiteCompleted(Prerequisite prereq) { QuestEntry byStableKey = _data.GetByStableKey(prereq.QuestKey); return byStableKey != null && _state.IsCompleted(byStableKey.DBName); } private static RequiredItemInfo? FindRequiredItem(QuestEntry quest, QuestStep step) { QuestStep step2 = step; return quest.RequiredItems?.Find((RequiredItemInfo ri) => string.Equals(ri.ItemName, step2.TargetName, StringComparison.OrdinalIgnoreCase)); } private bool HasNavigableSource(ItemSource s) { if (s.Scene != null) { return true; } if (s.SourceKey != null && _data.CharacterSpawns.ContainsKey(s.SourceKey)) { return true; } return s.Children?.Exists((ItemSource c) => HasNavigableSource(c)) ?? false; } } public sealed class QuestListPanel { private readonly GuideData _data; private readonly QuestStateTracker _state; private readonly FilterState _filter; private readonly TrackerState _tracker; private string _searchBuf = string.Empty; private readonly List _sorted = new List(); private int _lastFilterVersion = -1; private int _lastStateVersion = -1; private static readonly string[] FilterNames = new string[4] { "Active", "Available", "Completed", "All" }; private int _filterIndex; private const string CurrentZoneSentinel = "\u001current"; private readonly string[] _zoneNames; private int _zoneIndex; public QuestListPanel(GuideData data, QuestStateTracker state, FilterState filter, TrackerState tracker) { _data = data; _state = state; _filter = filter; _tracker = tracker; SortedSet sortedSet = new SortedSet(StringComparer.OrdinalIgnoreCase); foreach (QuestEntry item in data.All) { if (item.ZoneContext != null) { sortedSet.Add(item.ZoneContext); } } _zoneNames = new string[sortedSet.Count + 2]; _zoneNames[0] = "All Zones"; _zoneNames[1] = "Current Zone"; int num = 2; foreach (string item2 in sortedSet) { _zoneNames[num++] = item2; } } public void Draw(float width) { DrawFilterRow(width); DrawZoneFilter(); DrawSearchBar(); ImGui.Separator(); ImGui.BeginChild("##QuestScroll"); if (DrawQuestList() == 0) { ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); if (_data.Count == 0) { ImGui.TextWrapped("No quest data loaded."); } else if (!string.IsNullOrEmpty(_filter.SearchText)) { ImGui.TextWrapped("No quests match your search."); } else { ImGui.TextWrapped("No quests in this category."); } ImGui.PopStyleColor(); } ImGui.EndChild(); } private void DrawFilterRow(float width) { _filterIndex = (int)_filter.FilterMode; ImGui.SetNextItemWidth(width * 0.55f); if (ImGui.Combo("##Filter", ref _filterIndex, FilterNames, FilterNames.Length)) { _filter.FilterMode = (QuestFilterMode)_filterIndex; } ImGui.SameLine(); DrawSortButton("Az", QuestSortMode.Alphabetical, "Sort alphabetically"); ImGui.SameLine(0f, 2f); DrawSortButton("Lv", QuestSortMode.ByLevel, "Sort by level"); ImGui.SameLine(0f, 2f); DrawSortButton("Zn", QuestSortMode.ByZone, "Sort by zone"); ImGui.Spacing(); } private void DrawSortButton(string label, QuestSortMode mode, string tooltip) { bool flag = _filter.SortMode == mode; if (flag) { ImGui.PushStyleColor((ImGuiCol)21, Theme.Accent); } if (ImGui.SmallButton(label + "##sort")) { _filter.SortMode = mode; } if (flag) { ImGui.PopStyleColor(); } if (ImGui.IsItemHovered()) { ImGui.BeginTooltip(); ImGui.TextUnformatted(tooltip); ImGui.EndTooltip(); } } private void DrawZoneFilter() { _zoneIndex = 0; if (_filter.ZoneFilter != null) { if (_filter.ZoneFilter == "\u001current") { _zoneIndex = 1; } else { for (int i = 2; i < _zoneNames.Length; i++) { if (string.Equals(_zoneNames[i], _filter.ZoneFilter, StringComparison.OrdinalIgnoreCase)) { _zoneIndex = i; break; } } } } ImGui.SetNextItemWidth(-1f); if (ImGui.Combo("##Zone", ref _zoneIndex, _zoneNames, _zoneNames.Length)) { FilterState filter = _filter; int zoneIndex = _zoneIndex; if (1 == 0) { } string zoneFilter = zoneIndex switch { 0 => null, 1 => "\u001current", _ => _zoneNames[_zoneIndex], }; if (1 == 0) { } filter.ZoneFilter = zoneFilter; } ImGui.Spacing(); } private void DrawSearchBar() { if (_searchBuf != _filter.SearchText) { _searchBuf = _filter.SearchText; } ImGui.SetNextItemWidth(-1f); if (ImGui.InputTextWithHint("##QuestSearch", "Search quests...", ref _searchBuf, 256u)) { _filter.SearchText = _searchBuf; } ImGui.Spacing(); } private int DrawQuestList() { bool flag = _filter.Version != _lastFilterVersion; bool flag2 = _state.Version != _lastStateVersion; if (flag || flag2) { _lastFilterVersion = _filter.Version; _lastStateVersion = _state.Version; _sorted.Clear(); IReadOnlyList all = _data.All; for (int i = 0; i < all.Count; i++) { QuestEntry questEntry = all[i]; if (PassesFilter(questEntry) && PassesSearch(questEntry)) { _sorted.Add(questEntry); } } _sorted.Sort(CompareQuests); } foreach (QuestEntry item in _sorted) { DrawQuestEntry(item); } return _sorted.Count; } private int CompareQuests(QuestEntry a, QuestEntry b) { QuestSortMode sortMode = _filter.SortMode; if (1 == 0) { } int result = sortMode switch { QuestSortMode.ByLevel => CompareLevels(a, b), QuestSortMode.ByZone => CompareZones(a, b), _ => string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase), }; if (1 == 0) { } return result; } private static int CompareLevels(QuestEntry a, QuestEntry b) { int? num = a.LevelEstimate?.Recommended; int? num2 = b.LevelEstimate?.Recommended; if (!num.HasValue && !num2.HasValue) { return string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase); } if (!num.HasValue) { return 1; } if (!num2.HasValue) { return -1; } int num3 = num.Value.CompareTo(num2.Value); return (num3 != 0) ? num3 : string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase); } private static int CompareZones(QuestEntry a, QuestEntry b) { if (a.ZoneContext == null && b.ZoneContext == null) { return string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase); } if (a.ZoneContext == null) { return 1; } if (b.ZoneContext == null) { return -1; } int num = string.Compare(a.ZoneContext, b.ZoneContext, StringComparison.OrdinalIgnoreCase); return (num != 0) ? num : string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase); } private bool PassesFilter(QuestEntry quest) { QuestFilterMode filterMode = _filter.FilterMode; if (1 == 0) { } bool flag = filterMode switch { QuestFilterMode.Active => _state.IsActive(quest.DBName), QuestFilterMode.Available => !_state.IsActive(quest.DBName) && !_state.IsCompleted(quest.DBName), QuestFilterMode.Completed => _state.IsCompleted(quest.DBName), QuestFilterMode.All => true, _ => true, }; if (1 == 0) { } if (!flag) { return false; } if (_filter.ZoneFilter != null) { string text = ((_filter.ZoneFilter == "\u001current") ? _data.GetZoneDisplayName(_state.CurrentZone) : _filter.ZoneFilter); if (text == null) { return true; } return string.Equals(quest.ZoneContext, text, StringComparison.OrdinalIgnoreCase); } return true; } private bool PassesSearch(QuestEntry quest) { if (string.IsNullOrEmpty(_filter.SearchText)) { return true; } string searchText = _filter.SearchText; if (quest.DisplayName.Contains(searchText, StringComparison.OrdinalIgnoreCase)) { return true; } if (quest.ZoneContext != null && quest.ZoneContext.Contains(searchText, StringComparison.OrdinalIgnoreCase)) { return true; } if (quest.Acquisition != null) { foreach (AcquisitionSource item in quest.Acquisition) { if (item.SourceName != null && item.SourceName.Contains(searchText, StringComparison.OrdinalIgnoreCase)) { return true; } } } if (quest.RequiredItems != null) { foreach (RequiredItemInfo requiredItem in quest.RequiredItems) { if (requiredItem.ItemName.Contains(searchText, StringComparison.OrdinalIgnoreCase)) { return true; } } } if (quest.Steps != null) { foreach (QuestStep step in quest.Steps) { if (step.TargetName != null && step.TargetName.Contains(searchText, StringComparison.OrdinalIgnoreCase)) { return true; } } } return false; } private void DrawQuestEntry(QuestEntry quest) { bool flag = quest.DBName == _state.SelectedQuestDBName; uint questColor = GetQuestColor(quest); if (flag) { ImGui.PushStyleColor((ImGuiCol)21, Theme.Accent); } string text = ((_tracker.Enabled && _tracker.IsTracked(quest.DBName)) ? "·" : " "); QuestFlags flags = quest.Flags; string text2 = ((flags != null && flags.Repeatable) ? " [R]" : ""); int? num = quest.LevelEstimate?.Recommended; string text3; if (num.HasValue) { int valueOrDefault = num.GetValueOrDefault(); text3 = $"{text}{valueOrDefault,2} {quest.DisplayName}{text2}"; } else { text3 = text + " " + quest.DisplayName + text2; } string text4 = text3; ImGui.PushStyleColor((ImGuiCol)0, questColor); if (ImGui.Selectable(text4 + "##" + quest.DBName, flag)) { _state.SelectQuest(quest.DBName); } if (ImGui.IsItemHovered()) { ImGui.BeginTooltip(); if (quest.ZoneContext != null) { ImGui.Text(quest.ZoneContext); } string text5 = (_state.IsCompleted(quest.DBName) ? "Completed" : (_state.IsImplicitlyActive(quest.DBName) ? "Completable here" : (_state.IsActive(quest.DBName) ? "Active" : "Available"))); ImGui.Text(text5); num = quest.LevelEstimate?.Recommended; if (num.HasValue) { int valueOrDefault2 = num.GetValueOrDefault(); if (true) { ImGui.Text($"Level {valueOrDefault2}"); } } ImGui.EndTooltip(); } ImGui.PopStyleColor((!flag) ? 1 : 2); } private uint GetQuestColor(QuestEntry quest) { return Theme.GetQuestColor(_state, quest.DBName); } } public readonly struct StepDistance { public readonly bool InCurrentZone; public readonly float Meters; public readonly string? Label; public bool HasDistance => Meters < float.MaxValue; public bool HasLabel => Label != null; public StepDistance(bool inCurrentZone, float meters, string? label = null) { InCurrentZone = inCurrentZone; Meters = meters; Label = label; } } public static class Theme { public static readonly uint Background = Rgba(0.1f, 0.1f, 0.12f, 0.95f); public static readonly uint Surface = Rgba(0.15f, 0.15f, 0.18f, 1f); public static readonly uint TextPrimary = Rgba(1f, 1f, 1f, 1f); public static readonly uint TextSecondary = Rgba(0.6f, 0.6f, 0.6f, 1f); public static readonly uint Accent = Rgba(0.2f, 0.35f, 0.55f, 1f); public static readonly uint Success = Rgba(0.4f, 0.8f, 0.4f, 1f); public static readonly uint Warning = Rgba(1f, 0.5f, 0.3f, 1f); public static readonly uint Error = Rgba(1f, 0.3f, 0.3f, 1f); public static readonly uint QuestActive = Rgba(1f, 0.9f, 0.3f, 1f); public static readonly uint QuestImplicit = Rgba(0.55f, 0.8f, 0.75f, 1f); public static readonly uint QuestCompleted = Rgba(0.4f, 0.7f, 0.4f, 1f); public static readonly uint QuestAvailable = Rgba(0.5f, 0.7f, 0.9f, 1f); public static readonly uint NavManualOverride = Rgba(0.45f, 0.85f, 0.9f, 1f); public static readonly uint SourceDimmed = Rgba(0.5f, 0.5f, 0.5f, 1f); public static readonly uint Header = Rgba(0.9f, 0.85f, 0.6f, 1f); public static readonly uint LevelSafe = Rgba(0.4f, 0.8f, 0.4f, 1f); public static readonly uint LevelCaution = Rgba(1f, 0.9f, 0.3f, 1f); public static readonly uint LevelDanger = Rgba(1f, 0.3f, 0.3f, 1f); public static readonly uint TrackerFlashGreen = Rgba(0.2f, 0.8f, 0.2f, 0.3f); public static readonly uint TrackerFlashYellow = Rgba(0.8f, 0.7f, 0.1f, 0.2f); public const float WindowPadding = 8f; public const float ItemSpacing = 4f; public const float SectionGap = 8f; public const float IndentWidth = 16f; public const float LeftPanelRatio = 0.32f; public static void PushWindowStyle() { ImGui.PushStyleColor((ImGuiCol)2, Background); ImGui.PushStyleColor((ImGuiCol)3, Surface); } public static void PopWindowStyle() { ImGui.PopStyleColor(2); } public static uint Rgba(float r, float g, float b, float a) { byte b2 = (byte)(r * 255f + 0.5f); byte b3 = (byte)(g * 255f + 0.5f); byte b4 = (byte)(b * 255f + 0.5f); byte b5 = (byte)(a * 255f + 0.5f); return (uint)(b2 | (b3 << 8) | (b4 << 16) | (b5 << 24)); } public static void ClampWindowPosition() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) Vector2 windowPos = ImGui.GetWindowPos(); Vector2 windowSize = ImGui.GetWindowSize(); ImGuiIOPtr iO = ImGui.GetIO(); Vector2 displaySize = ((ImGuiIOPtr)(ref iO)).DisplaySize; float num = windowPos.X; float num2 = windowPos.Y; if (num + windowSize.X < 40f) { num = 40f - windowSize.X; } if (num > displaySize.X - 40f) { num = displaySize.X - 40f; } if (num2 > displaySize.Y - 40f) { num2 = displaySize.Y - 40f; } if (num2 < 0f) { num2 = 0f; } if (num != windowPos.X || num2 != windowPos.Y) { ImGui.SetWindowPos(new Vector2(num, num2)); } } public static uint GetQuestColor(QuestStateTracker state, string dbName) { if (state.IsImplicitlyActive(dbName)) { return QuestImplicit; } if (state.IsActive(dbName)) { return QuestActive; } if (state.IsCompleted(dbName)) { return QuestCompleted; } return QuestAvailable; } } internal static class TrackerSorter { private readonly struct SourceDistance { public readonly float Meters; public readonly string? Label; public static SourceDistance None => new SourceDistance(float.MaxValue); public SourceDistance(float meters, string? label = null) { Meters = meters; Label = label; } public static SourceDistance Best(SourceDistance a, SourceDistance b) { if (a.Label != null && b.Label == null) { return a; } if (b.Label != null && a.Label == null) { return b; } return (a.Meters <= b.Meters) ? a : b; } } public static void ComputeDistances(IReadOnlyList quests, GuideData data, QuestStateTracker state, NavigationController nav, Vector3 playerPos, Dictionary output) { //IL_0145: Unknown result type (might be due to invalid IL or missing references) output.Clear(); string currentZone = state.CurrentZone; for (int i = 0; i < quests.Count; i++) { string text = quests[i]; QuestEntry byDBName = data.GetByDBName(text); if (byDBName == null) { output[text] = new StepDistance(inCurrentZone: false, float.MaxValue); } else if (nav.Target != null && string.Equals(nav.Target.QuestDBName, text, StringComparison.OrdinalIgnoreCase)) { bool flag = !nav.Target.IsCrossZone(currentZone); if (flag && nav.Target.TargetKind == NavigationTarget.Kind.Zone) { string label = ((nav.Target.SourceId != null && nav.Target.SourceId.StartsWith("fishing:", StringComparison.Ordinal)) ? "Fishing" : null); output[text] = new StepDistance(inCurrentZone: true, float.MaxValue, label); } else { float meters = (flag ? nav.Distance : float.MaxValue); output[text] = new StepDistance(flag, meters); } } else if (!IsCurrentStepInZone(byDBName, state, data, currentZone)) { output[text] = new StepDistance(inCurrentZone: false, float.MaxValue); } else { SourceDistance sourceDistance = ComputeStepDistance(byDBName, state, data, currentZone, playerPos); output[text] = new StepDistance(inCurrentZone: true, sourceDistance.Meters, sourceDistance.Label); } } } public static void Sort(List quests, TrackerSortMode mode, GuideData data, IReadOnlyDictionary? distances) { switch (mode) { case TrackerSortMode.Proximity: if (distances == null) { break; } SortByProximity(quests, data, distances); return; case TrackerSortMode.Level: SortByLevel(quests, data); return; } SortAlphabetical(quests, data); } private static void SortByProximity(List quests, GuideData data, IReadOnlyDictionary distances) { IReadOnlyDictionary distances2 = distances; GuideData data2 = data; quests.Sort(delegate(string a, string b) { StepDistance value; StepDistance stepDistance = (distances2.TryGetValue(a, out value) ? value : new StepDistance(inCurrentZone: false, float.MaxValue)); StepDistance value2; StepDistance stepDistance2 = (distances2.TryGetValue(b, out value2) ? value2 : new StepDistance(inCurrentZone: false, float.MaxValue)); if (stepDistance.InCurrentZone != stepDistance2.InCurrentZone) { return (!stepDistance.InCurrentZone) ? 1 : (-1); } if (stepDistance.InCurrentZone) { float num = (stepDistance.HasDistance ? stepDistance.Meters : 0f); float value3 = (stepDistance2.HasDistance ? stepDistance2.Meters : 0f); int num2 = num.CompareTo(value3); if (num2 != 0) { return num2; } } QuestEntry byDBName = data2.GetByDBName(a); QuestEntry byDBName2 = data2.GetByDBName(b); return string.Compare(byDBName?.DisplayName, byDBName2?.DisplayName, StringComparison.OrdinalIgnoreCase); }); } private static void SortByLevel(List quests, GuideData data) { GuideData data2 = data; quests.Sort(delegate(string a, string b) { QuestEntry byDBName = data2.GetByDBName(a); QuestEntry byDBName2 = data2.GetByDBName(b); int valueOrDefault = (byDBName?.LevelEstimate?.Recommended).GetValueOrDefault(int.MaxValue); int valueOrDefault2 = (byDBName2?.LevelEstimate?.Recommended).GetValueOrDefault(int.MaxValue); int num = valueOrDefault.CompareTo(valueOrDefault2); return (num != 0) ? num : string.Compare(byDBName?.DisplayName, byDBName2?.DisplayName, StringComparison.OrdinalIgnoreCase); }); } private static void SortAlphabetical(List quests, GuideData data) { GuideData data2 = data; quests.Sort(delegate(string a, string b) { QuestEntry byDBName = data2.GetByDBName(a); QuestEntry byDBName2 = data2.GetByDBName(b); return string.Compare(byDBName?.DisplayName ?? a, byDBName2?.DisplayName ?? b, StringComparison.OrdinalIgnoreCase); }); } public static string? GetStepZoneName(QuestEntry quest, QuestStateTracker state, GuideData data) { QuestStep currentStep = GetCurrentStep(quest, state, data); if (currentStep == null) { return null; } var (questStep, questEntry) = StepProgress.ResolveActiveStep(currentStep, quest, state, data); if (questStep == null) { return null; } string text = StepSceneResolver.ResolveScene(questEntry ?? quest, questStep, data); return (text != null) ? data.GetZoneDisplayName(text) : null; } private static bool IsCurrentStepInZone(QuestEntry quest, QuestStateTracker state, GuideData data, string currentScene) { QuestStep currentStep = GetCurrentStep(quest, state, data); if (currentStep == null) { return false; } var (questStep, questEntry) = StepProgress.ResolveActiveStep(currentStep, quest, state, data); if (questStep == null) { return false; } return StepSceneResolver.HasSourceInScene(questEntry ?? quest, questStep, data, currentScene); } private static SourceDistance ComputeStepDistance(QuestEntry quest, QuestStateTracker state, GuideData data, string currentScene, Vector3 playerPos) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) QuestStep currentStep = GetCurrentStep(quest, state, data); if (currentStep == null) { return SourceDistance.None; } var (step, questEntry) = StepProgress.ResolveActiveStep(currentStep, quest, state, data); if (step == null) { return SourceDistance.None; } QuestEntry questEntry2 = questEntry ?? quest; string targetKey = step.TargetKey; if (targetKey != null && step.TargetType == "character" && data.CharacterSpawns.ContainsKey(targetKey)) { return NearestSpawnDistance(data, targetKey, currentScene, playerPos); } if (step.TargetType == "item" && questEntry2.RequiredItems != null) { RequiredItemInfo requiredItemInfo = questEntry2.RequiredItems.Find((RequiredItemInfo ri) => string.Equals(ri.ItemName, step.TargetName, StringComparison.OrdinalIgnoreCase)); if (requiredItemInfo?.Sources != null) { return NearestSourceDistance(requiredItemInfo.Sources, data, currentScene, playerPos); } } return SourceDistance.None; } private static SourceDistance NearestSourceDistance(List sources, GuideData data, string currentScene, Vector3 playerPos) { //IL_0059: 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_00a3: Unknown result type (might be due to invalid IL or missing references) SourceDistance sourceDistance = SourceDistance.None; foreach (ItemSource source in sources) { if (source.Type == "quest_reward") { List children = source.Children; if (children != null && children.Count > 0) { sourceDistance = SourceDistance.Best(sourceDistance, NearestSourceDistance(source.Children, data, currentScene, playerPos)); continue; } } if (source.SourceKey != null) { sourceDistance = SourceDistance.Best(sourceDistance, NearestSpawnDistance(data, source.SourceKey, currentScene, playerPos)); } if (source.Children != null) { sourceDistance = SourceDistance.Best(sourceDistance, NearestSourceDistance(source.Children, data, currentScene, playerPos)); } } return sourceDistance; } private static SourceDistance NearestSpawnDistance(GuideData data, string key, string currentScene, Vector3 playerPos) { //IL_00ac: 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) if (key.StartsWith("fishing:", StringComparison.Ordinal)) { string a = key.Substring("fishing:".Length); return string.Equals(a, currentScene, StringComparison.OrdinalIgnoreCase) ? new SourceDistance(float.MaxValue, "Fishing") : SourceDistance.None; } if (!data.CharacterSpawns.TryGetValue(key, out List value) || value.Count == 0) { return SourceDistance.None; } float num = float.MaxValue; foreach (SpawnPoint item in value) { if (string.Equals(item.Scene, currentScene, StringComparison.OrdinalIgnoreCase)) { float num2 = Vector3.Distance(playerPos, new Vector3(item.X, item.Y, item.Z)); if (num2 < num) { num = num2; } } } return new SourceDistance(num); } private static QuestStep? GetCurrentStep(QuestEntry quest, QuestStateTracker state, GuideData data) { if (quest.Steps == null || quest.Steps.Count == 0) { return null; } int currentStepIndex = StepProgress.GetCurrentStepIndex(quest, state, data); return (currentStepIndex < quest.Steps.Count) ? quest.Steps[currentStepIndex] : null; } } public enum TrackerSortMode { Proximity, Level, Alphabetical } public sealed class TrackerWindow { private struct EntryAnimation { public float AddedAt; public float CompletedAt; public float StepAdvancedAt; } private const float DefaultWidth = 340f; private const float DefaultHeight = 260f; private const float FadeInDuration = 0.3f; private const float FadeOutDuration = 0.3f; private const float CompletionFlashDuration = 1.5f; private const float CompletionLingerDuration = 2f; private const float StepAdvanceDuration = 0.8f; private const float CompactTintRounding = 8f; private const float CompactPadTop = 10f; private const float CompactPadBottom = 6f; private const float CompactPadLeft = 8f; private const float CompactPadRight = 6f; private const int DrawFlagsRoundCornersAll = 240; private readonly GuideData _data; private readonly QuestStateTracker _state; private readonly NavigationController _nav; private readonly TrackerState _tracker; private readonly GuideWindow _guide; private readonly GuideConfig _config; private bool _visible = true; private readonly Dictionary _animations = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _fadingOut = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _completionTimers = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly List _sorted = new List(); private readonly Dictionary _distances = new Dictionary(StringComparer.OrdinalIgnoreCase); private int _lastStateVersion = -1; private float _lastProximitySort; private TrackerSortMode _lastSortMode; private readonly Dictionary _cachedStepIndex = new Dictionary(StringComparer.OrdinalIgnoreCase); private bool _compact = true; private Vector2 _contentMin; private Vector2 _contentMax; public bool Visible => _visible; public void Toggle() { _visible = !_visible; } public void Show() { _visible = true; } public void Hide() { _visible = false; } public TrackerWindow(GuideData data, QuestStateTracker state, NavigationController nav, TrackerState tracker, GuideWindow guide, GuideConfig config) { _data = data; _state = state; _nav = nav; _tracker = tracker; _guide = guide; _config = config; _tracker.Tracked += OnQuestTracked; _tracker.Untracked += OnQuestUntracked; _tracker.QuestCompleted += OnQuestCompleted; _tracker.StepAdvanced += OnQuestStepAdvanced; } public void Dispose() { _tracker.Tracked -= OnQuestTracked; _tracker.Untracked -= OnQuestUntracked; _tracker.QuestCompleted -= OnQuestCompleted; _tracker.StepAdvanced -= OnQuestStepAdvanced; } private void OnQuestTracked(string dbName) { _animations[dbName] = new EntryAnimation { AddedAt = Time.realtimeSinceStartup }; _fadingOut.Remove(dbName); _visible = true; } private void OnQuestUntracked(string dbName) { _fadingOut[dbName] = Time.realtimeSinceStartup; _completionTimers.Remove(dbName); } private void OnQuestCompleted(string dbName) { EntryAnimation orDefaultAnim = GetOrDefaultAnim(dbName); orDefaultAnim.CompletedAt = Time.realtimeSinceStartup; _animations[dbName] = orDefaultAnim; _completionTimers[dbName] = Time.realtimeSinceStartup; } private void OnQuestStepAdvanced(string dbName) { EntryAnimation orDefaultAnim = GetOrDefaultAnim(dbName); orDefaultAnim.StepAdvancedAt = Time.realtimeSinceStartup; _animations[dbName] = orDefaultAnim; } public void Draw() { //IL_00cb: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) if (!_visible || !_tracker.Enabled || (_contentMax.Y > _contentMin.Y && GameWindowOverlap.ShouldSuppressTracker(_contentMin.X, _contentMin.Y, _contentMax.X, _contentMax.Y))) { return; } PruneAnimations(); DetectStepAdvances(); RebuildSortedListIfNeeded(); if (_sorted.Count == 0 && _fadingOut.Count == 0) { return; } ImGuiCond val = (ImGuiCond)(_config.LayoutResetRequested ? 1 : 4); float resolvedUiScale = _config.ResolvedUiScale; ImGuiIOPtr iO = ImGui.GetIO(); Vector2 displaySize = ((ImGuiIOPtr)(ref iO)).DisplaySize; ImGui.SetNextWindowSize(new Vector2(340f * resolvedUiScale, 260f * resolvedUiScale), val); ImGui.SetNextWindowPos(new Vector2(40f, displaySize.Y * 0.5f), val, new Vector2(0f, 0.5f)); int num = 0; int num2 = 0; Theme.PushWindowStyle(); if (_compact) { ImGui.PushStyleColor((ImGuiCol)2, 0u); ImGui.PushStyleColor((ImGuiCol)3, 0u); ImGui.PushStyleColor((ImGuiCol)5, 0u); ImGui.PushStyleColor((ImGuiCol)10, 0u); ImGui.PushStyleColor((ImGuiCol)11, 0u); ImGui.PushStyleColor((ImGuiCol)12, 0u); ImGui.PushStyleColor((ImGuiCol)21, 0u); ImGui.PushStyleColor((ImGuiCol)7, 0u); num = 8; } if (_compact && _contentMax.Y > _contentMin.Y) { uint col = Theme.Rgba(0f, 0f, 0f, _config.TrackerBackgroundOpacity.Value); IntPtr self = CimguiNative.igGetBackgroundDrawList_Nil(); CimguiNative.ImDrawList_AddRectFilled(self, new CimguiNative.Vec2(_contentMin.X, _contentMin.Y), new CimguiNative.Vec2(_contentMax.X, _contentMax.Y), col, 8f, 240); } ImGuiWindowFlags val2 = (ImGuiWindowFlags)798752; if (_compact) { val2 = (ImGuiWindowFlags)(val2 | 0xA); } if ((!_compact) ? ImGui.Begin("Quest Tracker###Tracker", ref _visible, val2) : ImGui.Begin("###Tracker", val2)) { if (_compact) { ImGui.PushStyleVar((ImGuiStyleVar)0, 0f); } DrawHeaderBar(); if (_compact) { ImGui.PopStyleVar(); } DrawQuestList(); bool flag = ImGui.IsWindowHovered((ImGuiHoveredFlags)3); bool flag2 = ImGui.IsWindowFocused((ImGuiFocusedFlags)3) && ImGui.IsMouseDown((ImGuiMouseButton)0); _compact = !flag && !flag2; if (_compact && ImGui.IsWindowFocused((ImGuiFocusedFlags)3)) { ImGui.SetWindowFocus((string)null); } } Theme.ClampWindowPosition(); ImGui.End(); if (num > 0) { ImGui.PopStyleColor(num); } if (num2 > 0) { ImGui.PopStyleVar(num2); } Theme.PopWindowStyle(); } private void DrawHeaderBar() { DrawSortButton("Px", TrackerSortMode.Proximity, "Sort by proximity"); ImGui.SameLine(0f, 2f); DrawSortButton("Lv", TrackerSortMode.Level, "Sort by level"); ImGui.SameLine(0f, 2f); DrawSortButton("Az", TrackerSortMode.Alphabetical, "Sort alphabetically"); ImGui.Separator(); } private void DrawSortButton(string label, TrackerSortMode mode, string tooltip) { bool flag = _tracker.SortMode == mode; if (flag) { ImGui.PushStyleColor((ImGuiCol)21, Theme.Accent); } if (ImGui.SmallButton(label + "##tsort")) { _tracker.SortMode = mode; _lastSortMode = mode; RebuildSortedList(); } if (flag) { ImGui.PopStyleColor(); } if (ImGui.IsItemHovered()) { ImGui.BeginTooltip(); ImGui.TextUnformatted(tooltip); ImGui.EndTooltip(); } } private void DrawQuestList() { //IL_008b: 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) ImGui.BeginChild("##TrackerScroll", Vector2.Zero, false); Vector2 cursorScreenPos = ImGui.GetCursorScreenPos(); for (int i = 0; i < _sorted.Count; i++) { string dbName = _sorted[i]; QuestEntry byDBName = _data.GetByDBName(dbName); if (byDBName != null) { DrawQuestEntry(byDBName, dbName, i); } } Vector2 cursorScreenPos2 = ImGui.GetCursorScreenPos(); Vector2 windowPos = ImGui.GetWindowPos(); float windowWidth = ImGui.GetWindowWidth(); float windowHeight = ImGui.GetWindowHeight(); ImGuiStylePtr style = ImGui.GetStyle(); float y = ((ImGuiStylePtr)(ref style)).ItemSpacing.Y; float num = windowPos.Y + windowHeight; float y2 = ((cursorScreenPos2.Y <= num) ? (cursorScreenPos2.Y - y + 6f) : (num + 6f)); _contentMin = new Vector2(windowPos.X - 8f, windowPos.Y - 10f); _contentMax = new Vector2(windowPos.X + windowWidth + 6f, y2); ImGui.EndChild(); } private void DrawQuestEntry(QuestEntry quest, string dbName, int index) { EntryAnimation orDefaultAnim = GetOrDefaultAnim(dbName); float realtimeSinceStartup = Time.realtimeSinceStartup; float value; bool flag = _fadingOut.TryGetValue(dbName, out value); if (!flag && !_tracker.IsTracked(dbName)) { return; } float num = 1f; if (flag) { float num2 = realtimeSinceStartup - value; num = Mathf.Clamp01(1f - num2 / 0.3f); if (num <= 0f) { return; } } else if (orDefaultAnim.AddedAt > 0f) { float num3 = realtimeSinceStartup - orDefaultAnim.AddedAt; if (num3 < 0.3f) { num = num3 / 0.3f; } } ImGui.PushID(index); if (num < 1f) { ImGui.PushStyleVar((ImGuiStyleVar)0, num); } bool flag2 = false; if (orDefaultAnim.CompletedAt > 0f && realtimeSinceStartup - orDefaultAnim.CompletedAt < 1.5f) { ImGui.PushStyleColor((ImGuiCol)0, Theme.Success); flag2 = true; } else if (orDefaultAnim.StepAdvancedAt > 0f && realtimeSinceStartup - orDefaultAnim.StepAdvancedAt < 0.8f) { ImGui.PushStyleColor((ImGuiCol)0, Theme.QuestActive); flag2 = true; } if (_config.ShowArrow.Value || _config.ShowGroundPath.Value) { DrawNavButton(quest); ImGui.SameLine(); } DrawQuestNameAndLevel(quest); DrawCurrentStep(quest); if (ImGui.BeginPopupContextItem("##ctx" + quest.DBName)) { if (ImGui.Selectable("Untrack")) { _tracker.Untrack(quest.DBName); } if (ImGui.Selectable("Open in Guide")) { _state.SelectQuest(quest.DBName); _guide.Show(); } ImGui.EndPopup(); } DrawPrerequisites(quest); ImGui.Spacing(); if (flag2) { ImGui.PopStyleColor(); } if (num < 1f) { ImGui.PopStyleVar(); } ImGui.PopID(); } private void DrawNavButton(QuestEntry quest) { (QuestStep? rawStep, QuestStep? displayStep, QuestEntry displayQuest) currentStep = GetCurrentStep(quest); QuestStep item = currentStep.rawStep; QuestStep item2 = currentStep.displayStep; QuestEntry item3 = currentStep.displayQuest; bool flag = item2?.TargetKey != null; bool flag2 = item != null && _nav.IsNavigating(quest.DBName, item.Order); if (!flag) { ImGui.PushStyleVar((ImGuiStyleVar)0, 0.3f); ImGui.SmallButton("[NAV]"); ImGui.PopStyleVar(); if (ImGui.IsItemHovered((ImGuiHoveredFlags)512)) { ImGui.BeginTooltip(); ImGui.TextUnformatted("No navigable target"); ImGui.EndTooltip(); } return; } if (flag2) { ImGui.PushStyleColor((ImGuiCol)21, Theme.QuestActive); } if (ImGui.SmallButton("[NAV]")) { if (flag2) { _nav.Clear(); } else { _nav.NavigateTo(item, quest, _state.CurrentZone); } } if (flag2) { ImGui.PopStyleColor(); } if (ImGui.IsItemHovered()) { ImGui.BeginTooltip(); ImGui.TextUnformatted(flag2 ? "Stop navigating" : "Navigate to current step"); ImGui.EndTooltip(); } } private void DrawQuestNameAndLevel(QuestEntry quest) { int? num = quest.LevelEstimate?.Recommended; string text; if (num.HasValue) { int valueOrDefault = num.GetValueOrDefault(); text = $"{valueOrDefault,2} {quest.DisplayName}"; } else { text = " " + quest.DisplayName; } string text2 = text; if (_distances.TryGetValue(quest.DBName, out var value)) { if (value.HasDistance) { text2 += $" ({value.Meters:0}m)"; } else if (value.HasLabel) { text2 = text2 + " (" + value.Label + ")"; } } ImGui.PushStyleColor((ImGuiCol)0, Theme.GetQuestColor(_state, quest.DBName)); if (ImGui.Selectable(text2 + "##name" + quest.DBName)) { _state.SelectQuest(quest.DBName); _guide.Show(); } ImGui.PopStyleColor(); } private void DrawCurrentStep(QuestEntry quest) { (QuestStep? rawStep, QuestStep? displayStep, QuestEntry displayQuest) currentStep = GetCurrentStep(quest); QuestStep item = currentStep.displayStep; QuestEntry item2 = currentStep.displayQuest; ImGui.Indent(16f); ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); if (item == null) { ImGui.TextWrapped(quest.HasSteps ? "Completed" : "No guide data available."); ImGui.PopStyleColor(); ImGui.Unindent(16f); return; } string text = FormatStepText(item2, item); if (_distances.TryGetValue(quest.DBName, out var value) && !value.InCurrentZone && item.Action != "travel") { string stepZoneName = TrackerSorter.GetStepZoneName(quest, _state, _data); if (stepZoneName != null) { text = "Travel to " + stepZoneName + "."; } } ImGui.TextWrapped(text); ImGui.PopStyleColor(); ImGui.Unindent(16f); } private string FormatStepText(QuestEntry quest, QuestStep step) { if (step.Quantity.HasValue && step.TargetKey != null) { int num = _state.CountItem(step.TargetKey); int value = step.Quantity.Value; return $"{step.Description} ({num}/{value})"; } return step.Description; } private void DrawPrerequisites(QuestEntry quest) { if (quest.Prerequisites == null || quest.Prerequisites.Count == 0) { return; } foreach (Prerequisite prerequisite in quest.Prerequisites) { if (prerequisite.Item != null || _state.IsCompleted(prerequisite.QuestKey)) { continue; } ImGui.Indent(16f); ImGui.PushStyleColor((ImGuiCol)0, Theme.TextSecondary); ImGui.PushStyleVar((ImGuiStyleVar)0, 0.6f); if (ImGui.Selectable("Requires: " + prerequisite.QuestName + "##prereq" + prerequisite.QuestKey)) { _state.SelectQuest(prerequisite.QuestKey); _guide.Show(); } ImGui.PopStyleVar(); ImGui.PopStyleColor(); ImGui.Unindent(16f); break; } } private void PruneAnimations() { float realtimeSinceStartup = Time.realtimeSinceStartup; List list = new List(); string key; float value; foreach (KeyValuePair completionTimer in _completionTimers) { completionTimer.Deconstruct(out key, out value); string item = key; float num = value; if (realtimeSinceStartup - num > 2f) { list.Add(item); } } foreach (string item3 in list) { _completionTimers.Remove(item3); _tracker.Untrack(item3); } List list2 = new List(); foreach (KeyValuePair item4 in _fadingOut) { item4.Deconstruct(out key, out value); string item2 = key; float num2 = value; if (realtimeSinceStartup - num2 > 0.3f) { list2.Add(item2); } } foreach (string item5 in list2) { _fadingOut.Remove(item5); _animations.Remove(item5); _cachedStepIndex.Remove(item5); } } private void RebuildSortedListIfNeeded() { bool isDirty = _tracker.IsDirty; bool flag = _state.Version != _lastStateVersion; bool flag2 = _tracker.SortMode != _lastSortMode; bool flag3 = Time.realtimeSinceStartup - _lastProximitySort > 2f; if (isDirty || flag || flag2 || flag3) { if (flag) { _lastStateVersion = _state.Version; } RebuildSortedList(); } } private void RebuildSortedList() { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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) _sorted.Clear(); _sorted.AddRange(_tracker.TrackedQuests); foreach (string key in _fadingOut.Keys) { if (!_sorted.Contains(key)) { _sorted.Add(key); } } _lastSortMode = _tracker.SortMode; _lastProximitySort = Time.realtimeSinceStartup; if ((Object)(object)GameData.PlayerControl != (Object)null) { Vector3 position = ((Component)GameData.PlayerControl).transform.position; TrackerSorter.ComputeDistances(_sorted, _data, _state, _nav, position, _distances); } else { _distances.Clear(); } TrackerSorter.Sort(_sorted, _tracker.SortMode, _data, (_distances.Count > 0) ? _distances : null); } private void DetectStepAdvances() { foreach (string trackedQuest in _tracker.TrackedQuests) { QuestEntry byDBName = _data.GetByDBName(trackedQuest); if (byDBName?.Steps != null) { int currentStepIndex = StepProgress.GetCurrentStepIndex(byDBName, _state, _data); if (_cachedStepIndex.TryGetValue(trackedQuest, out var value) && currentStepIndex > value) { _tracker.OnStepAdvanced(trackedQuest); } _cachedStepIndex[trackedQuest] = currentStepIndex; } } } private (QuestStep? rawStep, QuestStep? displayStep, QuestEntry displayQuest) GetCurrentStep(QuestEntry quest) { if (quest.Steps == null || quest.Steps.Count == 0) { return (null, null, quest); } int currentStepIndex = StepProgress.GetCurrentStepIndex(quest, _state, _data); QuestStep questStep = ((currentStepIndex < quest.Steps.Count) ? quest.Steps[currentStepIndex] : null); if (questStep == null) { return (null, null, quest); } var (item, questEntry) = StepProgress.ResolveActiveStep(questStep, quest, _state, _data); return (questStep, item, questEntry ?? quest); } private EntryAnimation GetOrDefaultAnim(string dbName) { EntryAnimation value; return _animations.TryGetValue(dbName, out value) ? value : default(EntryAnimation); } } } namespace AdventureGuide.State { internal static class GameUIVisibility { private static Canvas? _hudCanvas; private static bool _searched; public static bool IsVisible { get { if ((Object)(object)_hudCanvas == (Object)null) { if (_searched) { return true; } _searched = true; TypeText val = Object.FindObjectOfType(); if ((Object)(object)val != (Object)null) { _hudCanvas = ((Component)val).GetComponent(); } } return (Object)(object)_hudCanvas == (Object)null || ((Behaviour)_hudCanvas).enabled; } } } internal static class GameWindowOverlap { private struct WindowRect { public float Left; public float Top; public float Right; public float Bottom; public bool Overlaps(float otherLeft, float otherTop, float otherRight, float otherBottom) { return Left < otherRight && Right > otherLeft && Top < otherBottom && Bottom > otherTop; } } private static List? _uiWindows; private static bool _searched; private static WindowRect[]? _rects; private static bool[]? _wasActive; private static readonly HashSet _suppressors = new HashSet(); public static bool ShouldSuppressTracker(float trackerLeft, float trackerTop, float trackerRight, float trackerBottom) { List uIWindows = GetUIWindows(); if (uIWindows == null || uIWindows.Count == 0) { return false; } EnsureCaches(uIWindows.Count); for (int i = 0; i < uIWindows.Count; i++) { GameObject val = uIWindows[i]; bool flag = (Object)(object)val != (Object)null && val.activeSelf; if (flag && !_wasActive[i]) { EnsureRect(i, val); if (_rects[i].Overlaps(trackerLeft, trackerTop, trackerRight, trackerBottom)) { _suppressors.Add(i); } } else if (!flag && _wasActive[i]) { _suppressors.Remove(i); } _wasActive[i] = flag; } return _suppressors.Count > 0; } public static void InvalidateRects() { _rects = null; } public static void Reset() { _uiWindows = null; _searched = false; _rects = null; _wasActive = null; _suppressors.Clear(); } private static List? GetUIWindows() { if (_uiWindows != null) { return _uiWindows; } if (_searched) { return null; } _searched = true; CameraController val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return null; } HashSet hashSet = new HashSet(); List list = new List(); foreach (GameObject uIWindow in val.UIWindows) { if ((Object)(object)uIWindow != (Object)null && hashSet.Add(uIWindow)) { list.Add(uIWindow); } } if ((Object)(object)GameData.Misc != (Object)null) { foreach (GameObject uIWindow2 in GameData.Misc.UIWindows) { if ((Object)(object)uIWindow2 != (Object)null && hashSet.Add(uIWindow2)) { list.Add(uIWindow2); } } } _uiWindows = list; return _uiWindows; } private static void EnsureCaches(int count) { if (_wasActive == null || _wasActive.Length != count) { _wasActive = new bool[count]; for (int i = 0; i < count; i++) { GameObject val = _uiWindows[i]; _wasActive[i] = (Object)(object)val != (Object)null && val.activeSelf; } _suppressors.Clear(); } if (_rects == null || _rects.Length != count) { _rects = new WindowRect[count]; } } private static void EnsureRect(int i, GameObject go) { //IL_0089: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if (_rects[i].Right > 0f) { return; } RectTransform component = go.GetComponent(); if ((Object)(object)component == (Object)null) { _rects[i] = default(WindowRect); return; } Vector3[] array = (Vector3[])(object)new Vector3[4]; component.GetWorldCorners(array); float num = Screen.height; float num2 = float.MaxValue; float num3 = float.MinValue; float num4 = float.MaxValue; float num5 = float.MinValue; for (int j = 0; j < 4; j++) { Vector2 val = RectTransformUtility.WorldToScreenPoint((Camera)null, array[j]); float num6 = num - val.y; if (val.x < num2) { num2 = val.x; } if (val.x > num3) { num3 = val.x; } if (num6 < num4) { num4 = num6; } if (num6 > num5) { num5 = num6; } } _rects[i] = new WindowRect { Left = num2, Top = num4, Right = num3, Bottom = num5 }; } } public sealed class NavigationHistory { public enum PageType { Quest } public readonly struct PageRef { public readonly PageType Type; public readonly string Key; public PageRef(PageType type, string key) { Type = type; Key = key; } } private readonly List _pages = new List(); private int _cursor = -1; private int _maxSize; public bool CanGoBack => _cursor > 0; public bool CanGoForward => _cursor < _pages.Count - 1; public int MaxSize { get { return _maxSize; } set { _maxSize = Math.Max(1, value); } } public NavigationHistory(int maxSize = 100) { _maxSize = maxSize; } public void Navigate(PageRef page) { if (_cursor >= 0 && _cursor < _pages.Count) { PageRef pageRef = _pages[_cursor]; if (pageRef.Type == page.Type && pageRef.Key == page.Key) { return; } } if (_cursor < _pages.Count - 1) { _pages.RemoveRange(_cursor + 1, _pages.Count - _cursor - 1); } _pages.Add(page); _cursor = _pages.Count - 1; while (_pages.Count > _maxSize) { _pages.RemoveAt(0); _cursor--; } } public PageRef? Back() { if (!CanGoBack) { return null; } _cursor--; return _pages[_cursor]; } public PageRef? Forward() { if (!CanGoForward) { return null; } _cursor++; return _pages[_cursor]; } public void Clear() { _pages.Clear(); _cursor = -1; } } public sealed class QuestStateTracker { private readonly struct ImplicitQuest { public readonly string DBName; public readonly string? ActivationScene; public ImplicitQuest(string dbName, string? activationScene) { DBName = dbName; ActivationScene = activationScene; } } private readonly HashSet _activeQuests = new HashSet(StringComparer.OrdinalIgnoreCase); private readonly HashSet _completedQuests = new HashSet(StringComparer.OrdinalIgnoreCase); private readonly List _implicitQuests; private readonly HashSet _implicitlyActiveQuests = new HashSet(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _inventoryCache = new Dictionary(StringComparer.OrdinalIgnoreCase); private bool _dirty = true; private NavigationHistory? _history; public int Version { get; private set; } public string CurrentZone { get; set; } = ""; public string? SelectedQuestDBName { get; set; } public IReadOnlyCollection ActiveQuests => _activeQuests; public IReadOnlyCollection CompletedQuests => _completedQuests; public QuestStateTracker(GuideData data) { _implicitQuests = new List(); foreach (QuestEntry item in data.All) { if (item.IsImplicit && item.Steps != null && item.Steps.Count != 0) { QuestStep step = item.Steps[item.Steps.Count - 1]; string activationScene = StepSceneResolver.ResolveScene(item, step, data); _implicitQuests.Add(new ImplicitQuest(item.DBName, activationScene)); } } } public void SetHistory(NavigationHistory history) { _history = history; } public void SelectQuest(string dbName) { if (!(dbName == SelectedQuestDBName)) { _history?.Navigate(new NavigationHistory.PageRef(NavigationHistory.PageType.Quest, dbName)); SelectedQuestDBName = dbName; } } public bool IsActive(string dbName) { return _activeQuests.Contains(dbName); } public bool IsActionable(string dbName) { if (_activeQuests.Contains(dbName)) { return true; } EnsureCacheCurrent(); return _implicitlyActiveQuests.Contains(dbName); } public bool IsImplicitlyActive(string dbName) { if (_activeQuests.Contains(dbName)) { return false; } EnsureCacheCurrent(); return _implicitlyActiveQuests.Contains(dbName); } public bool IsCompleted(string dbName) { return _completedQuests.Contains(dbName); } public void SyncFromGameData() { _activeQuests.Clear(); _completedQuests.Clear(); if (GameData.HasQuest != null) { foreach (string item in GameData.HasQuest) { _activeQuests.Add(item); } } if (GameData.CompletedQuests != null) { foreach (string completedQuest in GameData.CompletedQuests) { _completedQuests.Add(completedQuest); } } _dirty = true; Version++; } public void OnQuestAssigned(string dbName) { _activeQuests.Add(dbName); _dirty = true; Version++; } public void OnQuestCompleted(string dbName) { _activeQuests.Remove(dbName); _completedQuests.Add(dbName); _dirty = true; Version++; } public void OnInventoryChanged() { _dirty = true; Version++; } public void OnSceneChanged(string sceneName) { CurrentZone = sceneName; SyncFromGameData(); } public int CountItem(string itemStableKey) { EnsureCacheCurrent(); int value; return _inventoryCache.TryGetValue(itemStableKey, out value) ? value : 0; } private void EnsureCacheCurrent() { if (_dirty) { RebuildInventoryCache(); RebuildImplicitQuests(); } } private void RebuildInventoryCache() { _inventoryCache.Clear(); _dirty = false; if (GameData.PlayerInv?.StoredSlots == null) { return; } foreach (ItemIcon storedSlot in GameData.PlayerInv.StoredSlots) { if ((Object)(object)storedSlot?.MyItem != (Object)null) { string key = "item:" + ((Object)storedSlot.MyItem).name.Trim().ToLowerInvariant(); _inventoryCache[key] = ((!_inventoryCache.TryGetValue(key, out var value)) ? 1 : (value + 1)); } } } private void RebuildImplicitQuests() { _implicitlyActiveQuests.Clear(); foreach (ImplicitQuest implicitQuest in _implicitQuests) { if (!_activeQuests.Contains(implicitQuest.DBName) && !_completedQuests.Contains(implicitQuest.DBName) && implicitQuest.ActivationScene != null && string.Equals(implicitQuest.ActivationScene, CurrentZone, StringComparison.OrdinalIgnoreCase)) { _implicitlyActiveQuests.Add(implicitQuest.DBName); } } } } public static class StepProgress { public static int GetCurrentStepIndex(QuestEntry quest, QuestStateTracker state, GuideData data) { if (quest.Steps == null || quest.Steps.Count == 0) { return 0; } if (state.IsCompleted(quest.DBName)) { return quest.Steps.Count; } int num = ((state.IsActionable(quest.DBName) && IsAcquisitionStep(quest, quest.Steps[0])) ? 1 : 0); for (int i = num; i < quest.Steps.Count; i++) { QuestStep questStep = quest.Steps[i]; if (questStep.Action == "collect" && questStep.TargetKey != null && questStep.Quantity.HasValue) { int num2 = state.CountItem(questStep.TargetKey); if (num2 < questStep.Quantity.Value) { return i; } continue; } if (questStep.Action == "complete_quest" && questStep.TargetKey != null) { QuestEntry byStableKey = data.GetByStableKey(questStep.TargetKey); if (byStableKey == null || !state.IsCompleted(byStableKey.DBName)) { return i; } continue; } return i; } return quest.Steps.Count - 1; } public static bool IsAcquisitionStep(QuestEntry quest, QuestStep step) { if (quest.Acquisition == null || quest.Acquisition.Count == 0) { return false; } foreach (AcquisitionSource item in quest.Acquisition) { if (step.Action == "talk" && item.Method == "dialog" && string.Equals(step.TargetName, item.SourceName, StringComparison.OrdinalIgnoreCase)) { return true; } if (step.Action == "read" && item.Method == "item_read" && string.Equals(step.TargetName, item.SourceName, StringComparison.OrdinalIgnoreCase)) { return true; } if (step.Action == "travel" && item.Method == "zone_entry") { return true; } } return false; } public static (QuestStep? Step, QuestEntry? Quest) ResolveActiveStep(QuestStep step, QuestEntry quest, QuestStateTracker state, GuideData data, int maxDepth = 8) { QuestStep questStep = step; QuestEntry questEntry = quest; for (int i = 0; i < maxDepth; i++) { if (questStep.Action == "complete_quest" && questStep.TargetKey != null) { QuestEntry byStableKey = data.GetByStableKey(questStep.TargetKey); if (byStableKey?.Steps == null || byStableKey.Steps.Count == 0) { return (questStep, questEntry); } if (state.IsCompleted(byStableKey.DBName)) { return (questStep, questEntry); } int currentStepIndex = GetCurrentStepIndex(byStableKey, state, data); if (currentStepIndex >= byStableKey.Steps.Count) { return (questStep, questEntry); } questStep = byStableKey.Steps[currentStepIndex]; questEntry = byStableKey; continue; } if (questStep.Action == "collect" && questStep.TargetName != null) { QuestEntry questEntry2 = FindQuestRewardPrereq(questEntry, questStep, state, data); if (questEntry2 != null) { int currentStepIndex2 = GetCurrentStepIndex(questEntry2, state, data); if (currentStepIndex2 < questEntry2.Steps.Count) { questStep = questEntry2.Steps[currentStepIndex2]; questEntry = questEntry2; continue; } } } return (questStep, questEntry); } return (questStep, questEntry); } private static QuestEntry? FindQuestRewardPrereq(QuestEntry quest, QuestStep step, QuestStateTracker state, GuideData data) { QuestStep step2 = step; if (quest.RequiredItems == null) { return null; } RequiredItemInfo requiredItemInfo = quest.RequiredItems.Find((RequiredItemInfo ri) => string.Equals(ri.ItemName, step2.TargetName, StringComparison.OrdinalIgnoreCase)); if (requiredItemInfo?.Sources == null) { return null; } foreach (ItemSource source in requiredItemInfo.Sources) { if (!(source.Type != "quest_reward") && source.QuestKey != null) { QuestEntry byStableKey = data.GetByStableKey(source.QuestKey); if (byStableKey?.Steps != null && byStableKey.Steps.Count != 0 && !state.IsCompleted(byStableKey.DBName)) { return byStableKey; } } } return null; } } public sealed class TrackerState { private readonly HashSet _tracked = new HashSet(StringComparer.OrdinalIgnoreCase); private readonly List _orderedList = new List(); private GuideConfig? _config; private ConfigEntry? _trackedEntry; private int _boundSlotIndex = -1; private bool _dirty; public bool Enabled { get; set; } = true; public bool AutoTrackEnabled { get; set; } = true; public TrackerSortMode SortMode { get; set; } = TrackerSortMode.Proximity; public bool IsDirty { get { bool dirty = _dirty; _dirty = false; return dirty; } } public IReadOnlyList TrackedQuests => _orderedList; public event Action? Tracked; public event Action? Untracked; public event Action? QuestCompleted; public event Action? StepAdvanced; public bool IsTracked(string dbName) { return _tracked.Contains(dbName); } public void Track(string dbName) { if (_tracked.Add(dbName)) { _orderedList.Add(dbName); _dirty = true; this.Tracked?.Invoke(dbName); } } public void Untrack(string dbName) { if (_tracked.Remove(dbName)) { _orderedList.Remove(dbName); _dirty = true; this.Untracked?.Invoke(dbName); } } public void OnQuestCompleted(string dbName) { if (_tracked.Contains(dbName)) { this.QuestCompleted?.Invoke(dbName); } } public void OnStepAdvanced(string dbName) { if (_tracked.Contains(dbName)) { this.StepAdvanced?.Invoke(dbName); } } public void PruneCompleted(QuestStateTracker state) { for (int num = _orderedList.Count - 1; num >= 0; num--) { string text = _orderedList[num]; if (state.IsCompleted(text)) { _tracked.Remove(text); _orderedList.RemoveAt(num); _dirty = true; } } } public void LoadFromConfig(GuideConfig config) { _config = config; Enabled = config.TrackerEnabled.Value; AutoTrackEnabled = config.TrackerAutoTrack.Value; if (Enum.TryParse(config.TrackerSortMode.Value, out var result)) { SortMode = result; } } public void OnCharacterLoaded() { if (_config == null) { return; } SaveGameData currentCharacterSlot = GameData.CurrentCharacterSlot; if (currentCharacterSlot == null || currentCharacterSlot.index == _boundSlotIndex) { return; } if (_trackedEntry != null) { _trackedEntry.Value = string.Join(";", _orderedList); } _boundSlotIndex = currentCharacterSlot.index; _trackedEntry = _config.BindPerCharacter(currentCharacterSlot.index, "TrackedQuests", ""); _tracked.Clear(); _orderedList.Clear(); string value = _trackedEntry.Value; if (!string.IsNullOrEmpty(value)) { string[] array = value.Split(';'); foreach (string text in array) { string text2 = text.Trim(); if (text2.Length > 0 && _tracked.Add(text2)) { _orderedList.Add(text2); } } } _dirty = true; } public void SaveToConfig() { if (_config != null) { _config.TrackerEnabled.Value = Enabled; _config.TrackerAutoTrack.Value = AutoTrackEnabled; _config.TrackerSortMode.Value = SortMode.ToString(); if (_trackedEntry != null) { _trackedEntry.Value = string.Join(";", _orderedList); } } } } } namespace AdventureGuide.Rendering { public static class CimguiNative { public struct Vec2 { public float X; public float Y; public Vec2(float x, float y) { X = x; Y = y; } } public struct Vec4 { public float X; public float Y; public float Z; public float W; public Vec4(float x, float y, float z, float w) { X = x; Y = y; Z = z; W = w; } } private static byte[] _utf8Buf = new byte[256]; [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr igGetForegroundDrawList_Nil(); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr igGetBackgroundDrawList_Nil(); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr igGetWindowDrawList(); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] public static extern void ImDrawList_AddLine(IntPtr self, Vec2 p1, Vec2 p2, uint col, float thickness); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] public static extern void ImDrawList_AddTriangleFilled(IntPtr self, Vec2 p1, Vec2 p2, Vec2 p3, uint col); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] public static extern void ImDrawList_AddTriangle(IntPtr self, Vec2 p1, Vec2 p2, Vec2 p3, uint col, float thickness); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] public static extern void ImDrawList_AddCircleFilled(IntPtr self, Vec2 center, float radius, uint col, int numSegments); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] public static extern void ImDrawList_AddCircle(IntPtr self, Vec2 center, float radius, uint col, int numSegments, float thickness); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] public static extern void ImDrawList_AddRectFilled(IntPtr self, Vec2 pMin, Vec2 pMax, uint col, float rounding, int flags); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] public unsafe static extern void ImDrawList_AddText_Vec2(IntPtr self, Vec2 pos, uint col, byte* textBegin, byte* textEnd); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] public static extern void ImDrawList_AddQuadFilled(IntPtr self, Vec2 p1, Vec2 p2, Vec2 p3, Vec2 p4, uint col); [DllImport("cimgui", CallingConvention = CallingConvention.Cdecl)] private unsafe static extern void igCalcTextSize(Vec2* pOut, byte* text, byte* textEnd, byte wrapWidth, float maxWidth); private static int WriteUtf8(string text) { int byteCount = Encoding.UTF8.GetByteCount(text); if (byteCount > _utf8Buf.Length) { _utf8Buf = new byte[byteCount * 2]; } return Encoding.UTF8.GetBytes(text, 0, text.Length, _utf8Buf, 0); } public unsafe static Vec2 CalcTextSize(string text) { if (string.IsNullOrEmpty(text)) { return new Vec2(0f, 0f); } int num = WriteUtf8(text); Vec2 result = default(Vec2); fixed (byte* ptr = _utf8Buf) { igCalcTextSize(&result, ptr, ptr + num, 0, -1f); } return result; } public unsafe static void AddText(IntPtr drawList, float x, float y, uint color, string text) { if (!(drawList == IntPtr.Zero) && !string.IsNullOrEmpty(text)) { int num = WriteUtf8(text); fixed (byte* ptr = _utf8Buf) { ImDrawList_AddText_Vec2(drawList, new Vec2(x, y), color, ptr, ptr + num); } } } } public sealed class ImGuiRenderer : IDisposable { private readonly ManualLogSource _log; private IntPtr _nativeLib; private IntPtr _context; private Texture2D? _fontTexture; private Material? _material; private CommandBuffer? _commandBuffer; private GCHandle _iniPathHandle; private readonly Dictionary _textures = new Dictionary(); private readonly List _meshPool = new List(); private readonly List _verts = new List(); private readonly List _uvs = new List(); private readonly List _colors = new List(); private readonly List _indices = new List(); private readonly MaterialPropertyBlock _mpb = new MaterialPropertyBlock(); private const float BaseFontSize = 16f; private float _uiScale = 1f; private float _pendingScale = -1f; private byte[]? _unscaledStyleBackup; public Action? OnLayout { get; set; } public bool WantCaptureMouse { get; private set; } public bool WantTextInput { get; private set; } public string? IniPath { get; set; } public float UiScale { set { _uiScale = value; } } public float CurrentScale => _uiScale; [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr LoadLibrary(string lpFileName); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool FreeLibrary(IntPtr hModule); internal void ClearCaptureState() { WantCaptureMouse = false; WantTextInput = false; } public ImGuiRenderer(ManualLogSource log) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected O, but got Unknown _log = log; } public unsafe bool Init() { //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown try { Assembly executingAssembly = Assembly.GetExecutingAssembly(); using Stream stream = executingAssembly.GetManifestResourceStream("AdventureGuide.cimgui.dll"); if (stream == null) { _log.LogError((object)"cimgui.dll not found in embedded resources"); return false; } byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); string text = Path.Combine(Paths.CachePath, "imgui_native"); Directory.CreateDirectory(text); string text2 = Path.Combine(text, "cimgui.dll"); if (!File.Exists(text2)) { File.WriteAllBytes(text2, array); } _nativeLib = LoadLibrary(text2); if (_nativeLib == IntPtr.Zero) { _log.LogError((object)$"Failed to LoadLibrary: {text2} (error {Marshal.GetLastWin32Error()})"); return false; } _context = ImGui.CreateContext(); ImGuiIOPtr iO = ImGui.GetIO(); ref ImGuiBackendFlags backendFlags = ref ((ImGuiIOPtr)(ref iO)).BackendFlags; backendFlags = (ImGuiBackendFlags)((uint)backendFlags | 8u); if (IniPath != null) { byte[] bytes = Encoding.UTF8.GetBytes(IniPath + "\0"); _iniPathHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned); ((ImGuiIO)((ImGuiIOPtr)(ref iO)).NativePtr).IniFilename = (byte*)(void*)_iniPathHandle.AddrOfPinnedObject(); } ImGui.StyleColorsDark(); BuildFontAtlas(); SaveStyleBackup(); ImGuiStylePtr style = ImGui.GetStyle(); ((ImGuiStylePtr)(ref style)).ScaleAllSizes(_uiScale); CreateMaterial(); _commandBuffer = new CommandBuffer { name = "AdventureGuide_ImGui" }; _log.LogInfo((object)"ImGui.NET initialized successfully"); return true; } catch (Exception arg) { _log.LogError((object)$"ImGui init failed: {arg}"); return false; } } public void OnGUI() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) Event current = Event.current; if (current == null || (int)current.type != 7) { return; } try { if (_pendingScale >= 0f) { ApplyScale(_pendingScale); _pendingScale = -1f; } ImGuiIOPtr iO = ImGui.GetIO(); ((ImGuiIOPtr)(ref iO)).DisplaySize = new Vector2(Screen.width, Screen.height); ((ImGuiIOPtr)(ref iO)).DeltaTime = ((Time.deltaTime > 0f) ? Time.deltaTime : (1f / 60f)); UpdateInput(iO); ImGui.NewFrame(); OnLayout?.Invoke(); ImGui.EndFrame(); WantCaptureMouse = ((ImGuiIOPtr)(ref iO)).WantCaptureMouse; WantTextInput = ((ImGuiIOPtr)(ref iO)).WantTextInput; ImGui.Render(); RenderDrawData(); } catch (Exception arg) { _log.LogError((object)$"ImGui render error: {arg}"); } } public IntPtr RegisterTexture(Texture tex) { IntPtr nativeTexturePtr = tex.GetNativeTexturePtr(); _textures[nativeTexturePtr] = tex; return nativeTexturePtr; } public void UnregisterTexture(IntPtr id) { _textures.Remove(id); } public void Dispose() { if (_iniPathHandle.IsAllocated) { _iniPathHandle.Free(); } if (_context != IntPtr.Zero) { ImGui.DestroyContext(_context); _context = IntPtr.Zero; } foreach (Mesh item in _meshPool) { Object.Destroy((Object)(object)item); } _meshPool.Clear(); if ((Object)(object)_fontTexture != (Object)null) { Object.Destroy((Object)(object)_fontTexture); } if ((Object)(object)_material != (Object)null) { Object.Destroy((Object)(object)_material); } CommandBuffer? commandBuffer = _commandBuffer; if (commandBuffer != null) { commandBuffer.Dispose(); } if (_nativeLib != IntPtr.Zero) { FreeLibrary(_nativeLib); _nativeLib = IntPtr.Zero; } } public void SetScale(float scale) { _pendingScale = scale; } public void ClearWindowState() { ImGui.LoadIniSettingsFromMemory(""); } private unsafe void BuildFontAtlas() { //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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) ImGuiIOPtr iO = ImGui.GetIO(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); using Stream stream = executingAssembly.GetManifestResourceStream("AdventureGuide.Roboto-Regular.ttf"); ImFontAtlasPtr fonts; if (stream != null) { byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); IntPtr intPtr = ImGui.MemAlloc((uint)array.Length); Marshal.Copy(array, 0, intPtr, array.Length); ImFontGlyphRangesBuilderPtr val = default(ImFontGlyphRangesBuilderPtr); ((ImFontGlyphRangesBuilderPtr)(ref val))..ctor(ImGuiNative.ImFontGlyphRangesBuilder_ImFontGlyphRangesBuilder()); fonts = ((ImGuiIOPtr)(ref iO)).Fonts; ((ImFontGlyphRangesBuilderPtr)(ref val)).AddRanges(((ImFontAtlasPtr)(ref fonts)).GetGlyphRangesDefault()); ((ImFontGlyphRangesBuilderPtr)(ref val)).AddChar((ushort)10003); ((ImFontGlyphRangesBuilderPtr)(ref val)).AddChar((ushort)9675); ImVector val2 = default(ImVector); ((ImFontGlyphRangesBuilderPtr)(ref val)).BuildRanges(ref val2); ImFontConfig* ptr = ImGuiNative.ImFontConfig_ImFontConfig(); ((ImFontConfig)ptr).OversampleH = 2; ((ImFontConfig)ptr).OversampleV = 1; fonts = ((ImGuiIOPtr)(ref iO)).Fonts; ((ImFontAtlasPtr)(ref fonts)).AddFontFromMemoryTTF(intPtr, array.Length, 16f * _uiScale, ImFontConfigPtr.op_Implicit(ptr), val2.Data); ((ImFontGlyphRangesBuilderPtr)(ref val)).Destroy(); } else { _log.LogWarning((object)"Roboto-Regular.ttf not found in resources, using default font"); fonts = ((ImGuiIOPtr)(ref iO)).Fonts; ((ImFontAtlasPtr)(ref fonts)).AddFontDefault(); } fonts = ((ImGuiIOPtr)(ref iO)).Fonts; ((ImFontAtlasPtr)(ref fonts)).Build(); fonts = ((ImGuiIOPtr)(ref iO)).Fonts; byte* ptr2 = default(byte*); int num = default(int); int num2 = default(int); int num3 = default(int); ((ImFontAtlasPtr)(ref fonts)).GetTexDataAsRGBA32(ref ptr2, ref num, ref num2, ref num3); _fontTexture = new Texture2D(num, num2, (TextureFormat)4, false); byte[] array2 = new byte[num * num2 * 4]; Marshal.Copy((IntPtr)ptr2, array2, 0, array2.Length); _fontTexture.LoadRawTextureData(array2); _fontTexture.Apply(); fonts = ((ImGuiIOPtr)(ref iO)).Fonts; ((ImFontAtlasPtr)(ref fonts)).SetTexID(((Texture)_fontTexture).GetNativeTexturePtr()); } private void ApplyScale(float newScale) { //IL_002d: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) _uiScale = newScale; if ((Object)(object)_fontTexture != (Object)null) { Object.Destroy((Object)(object)_fontTexture); _fontTexture = null; } ImGuiIOPtr iO = ImGui.GetIO(); ImFontAtlasPtr fonts = ((ImGuiIOPtr)(ref iO)).Fonts; ((ImFontAtlasPtr)(ref fonts)).Clear(); BuildFontAtlas(); RestoreStyleBackup(); ImGuiStylePtr style = ImGui.GetStyle(); ((ImGuiStylePtr)(ref style)).ScaleAllSizes(_uiScale); if ((Object)(object)_material != (Object)null) { _material.mainTexture = (Texture)(object)_fontTexture; } _log.LogInfo((object)$"UI scale changed to {_uiScale:F2}"); } private unsafe void SaveStyleBackup() { //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) int num = Unsafe.SizeOf(); _unscaledStyleBackup = new byte[num]; fixed (byte* destination = _unscaledStyleBackup) { ImGuiStylePtr style = ImGui.GetStyle(); Buffer.MemoryCopy(((ImGuiStylePtr)(ref style)).NativePtr, destination, num, num); } } private unsafe void RestoreStyleBackup() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (_unscaledStyleBackup != null) { fixed (byte* source = _unscaledStyleBackup) { ImGuiStylePtr style = ImGui.GetStyle(); Buffer.MemoryCopy(source, ((ImGuiStylePtr)(ref style)).NativePtr, _unscaledStyleBackup.Length, _unscaledStyleBackup.Length); } } } private void CreateMaterial() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown Shader val = Shader.Find("UI/Default"); _material = new Material(val) { hideFlags = (HideFlags)61 }; _material.SetInt("_SrcBlend", 5); _material.SetInt("_DstBlend", 10); _material.SetInt("_ZWrite", 0); _material.SetInt("_Cull", 0); _material.mainTexture = (Texture)(object)_fontTexture; } private void UpdateInput(ImGuiIOPtr io) { //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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0140: 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_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) Vector3 mousePosition = Input.mousePosition; ((ImGuiIOPtr)(ref io)).AddMousePosEvent(mousePosition.x, (float)Screen.height - mousePosition.y); ((ImGuiIOPtr)(ref io)).AddMouseButtonEvent(0, Input.GetMouseButton(0)); ((ImGuiIOPtr)(ref io)).AddMouseButtonEvent(1, Input.GetMouseButton(1)); ((ImGuiIOPtr)(ref io)).AddMouseButtonEvent(2, Input.GetMouseButton(2)); Vector2 mouseScrollDelta = Input.mouseScrollDelta; if (mouseScrollDelta.y != 0f || mouseScrollDelta.x != 0f) { ((ImGuiIOPtr)(ref io)).AddMouseWheelEvent(mouseScrollDelta.x, mouseScrollDelta.y); } ((ImGuiIOPtr)(ref io)).AddKeyEvent((ImGuiKey)4096, Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305)); ((ImGuiIOPtr)(ref io)).AddKeyEvent((ImGuiKey)8192, Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303)); ((ImGuiIOPtr)(ref io)).AddKeyEvent((ImGuiKey)16384, Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307)); AddKeyMapping(io, (ImGuiKey)512, (KeyCode)9); AddKeyMapping(io, (ImGuiKey)513, (KeyCode)276); AddKeyMapping(io, (ImGuiKey)514, (KeyCode)275); AddKeyMapping(io, (ImGuiKey)515, (KeyCode)273); AddKeyMapping(io, (ImGuiKey)516, (KeyCode)274); AddKeyMapping(io, (ImGuiKey)517, (KeyCode)280); AddKeyMapping(io, (ImGuiKey)518, (KeyCode)281); AddKeyMapping(io, (ImGuiKey)519, (KeyCode)278); AddKeyMapping(io, (ImGuiKey)520, (KeyCode)279); AddKeyMapping(io, (ImGuiKey)521, (KeyCode)277); AddKeyMapping(io, (ImGuiKey)522, (KeyCode)127); AddKeyMapping(io, (ImGuiKey)523, (KeyCode)8); AddKeyMapping(io, (ImGuiKey)524, (KeyCode)32); AddKeyMapping(io, (ImGuiKey)525, (KeyCode)13); AddKeyMapping(io, (ImGuiKey)526, (KeyCode)27); AddKeyMapping(io, (ImGuiKey)615, (KeyCode)271); AddKeyMapping(io, (ImGuiKey)546, (KeyCode)97); AddKeyMapping(io, (ImGuiKey)548, (KeyCode)99); AddKeyMapping(io, (ImGuiKey)567, (KeyCode)118); AddKeyMapping(io, (ImGuiKey)569, (KeyCode)120); string inputString = Input.inputString; foreach (char c in inputString) { if (c >= ' ' && c != '\u007f') { ((ImGuiIOPtr)(ref io)).AddInputCharacter((uint)c); } } } private static void AddKeyMapping(ImGuiIOPtr io, ImGuiKey imguiKey, KeyCode unityKey) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) ((ImGuiIOPtr)(ref io)).AddKeyEvent(imguiKey, Input.GetKey(unityKey)); } private void RenderDrawData() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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_007b: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: 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) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) if (_commandBuffer == null || (Object)(object)_material == (Object)null) { return; } ImDrawDataPtr drawData = ImGui.GetDrawData(); if (((ImDrawDataPtr)(ref drawData)).CmdListsCount == 0) { return; } float num = Screen.width; float num2 = Screen.height; Matrix4x4 projectionMatrix = Matrix4x4.Ortho(0f, num, num2, 0f, -1f, 1f); _commandBuffer.Clear(); _commandBuffer.SetProjectionMatrix(projectionMatrix); _commandBuffer.SetViewMatrix(Matrix4x4.identity); float x = ((ImDrawDataPtr)(ref drawData)).DisplayPos.X; float y = ((ImDrawDataPtr)(ref drawData)).DisplayPos.Y; while (_meshPool.Count < ((ImDrawDataPtr)(ref drawData)).CmdListsCount) { Mesh val = new Mesh { indexFormat = (IndexFormat)1 }; val.MarkDynamic(); _meshPool.Add(val); } for (int i = 0; i < ((ImDrawDataPtr)(ref drawData)).CmdListsCount; i++) { ImDrawListPtr val2 = ((ImDrawDataPtr)(ref drawData)).CmdListsRange[i]; ImPtrVector vtxBuffer = ((ImDrawListPtr)(ref val2)).VtxBuffer; ImVector idxBuffer = ((ImDrawListPtr)(ref val2)).IdxBuffer; ImPtrVector cmdBuffer = ((ImDrawListPtr)(ref val2)).CmdBuffer; _verts.Clear(); _uvs.Clear(); _colors.Clear(); for (int j = 0; j < vtxBuffer.Size; j++) { ImDrawVertPtr val3 = vtxBuffer[j]; _verts.Add(new Vector3(((ImDrawVertPtr)(ref val3)).pos.X - x, ((ImDrawVertPtr)(ref val3)).pos.Y - y, 0f)); _uvs.Add(new Vector2(((ImDrawVertPtr)(ref val3)).uv.X, ((ImDrawVertPtr)(ref val3)).uv.Y)); uint col = ((ImDrawVertPtr)(ref val3)).col; _colors.Add(new Color32((byte)(col & 0xFFu), (byte)((col >> 8) & 0xFFu), (byte)((col >> 16) & 0xFFu), (byte)((col >> 24) & 0xFFu))); } Mesh val4 = _meshPool[i]; val4.Clear(); val4.SetVertices(_verts); val4.SetUVs(0, _uvs); val4.SetColors(_colors); val4.subMeshCount = cmdBuffer.Size; for (int k = 0; k < cmdBuffer.Size; k++) { ImDrawCmdPtr val5 = cmdBuffer[k]; _indices.Clear(); for (int l = 0; l < (int)((ImDrawCmdPtr)(ref val5)).ElemCount; l++) { _indices.Add((int)(idxBuffer[(int)((ImDrawCmdPtr)(ref val5)).IdxOffset + l] + ((ImDrawCmdPtr)(ref val5)).VtxOffset)); } val4.SetTriangles(_indices, k); } val4.UploadMeshData(false); for (int m = 0; m < cmdBuffer.Size; m++) { ImDrawCmdPtr val6 = cmdBuffer[m]; if (((ImDrawCmdPtr)(ref val6)).ElemCount != 0) { float num3 = ((ImDrawCmdPtr)(ref val6)).ClipRect.X - x; float num4 = ((ImDrawCmdPtr)(ref val6)).ClipRect.Y - y; float num5 = ((ImDrawCmdPtr)(ref val6)).ClipRect.Z - ((ImDrawCmdPtr)(ref val6)).ClipRect.X; float num6 = ((ImDrawCmdPtr)(ref val6)).ClipRect.W - ((ImDrawCmdPtr)(ref val6)).ClipRect.Y; _commandBuffer.EnableScissorRect(new Rect(num3, num2 - num4 - num6, num5, num6)); _mpb.Clear(); if (_textures.TryGetValue(((ImDrawCmdPtr)(ref val6)).TextureId, out Texture value)) { _mpb.SetTexture("_MainTex", value); _mpb.SetVector("_MainTex_ST", new Vector4(1f, -1f, 0f, 1f)); } else { _mpb.SetTexture("_MainTex", (Texture)(object)_fontTexture); _mpb.SetVector("_MainTex_ST", new Vector4(1f, 1f, 0f, 0f)); } _commandBuffer.DrawMesh(val4, Matrix4x4.identity, _material, m, 0, _mpb); } } _commandBuffer.DisableScissorRect(); } Graphics.ExecuteCommandBuffer(_commandBuffer); } } } namespace AdventureGuide.Patches { [HarmonyPatch(typeof(Character), "DoDeath")] internal static class DeathPatch { internal static EntityRegistry? Registry; internal static SpawnTimerTracker? Timers; internal static WorldMarkerSystem? Markers; internal static LootScanner? Loot; [HarmonyPostfix] private static void Postfix(Character __instance) { NPC component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null)) { Registry?.Unregister(component); Timers?.OnNPCDeath(component); Markers?.MarkSpawnDirty(); Loot?.MarkDirty(); } } } [HarmonyPatch(typeof(Inventory), "UpdatePlayerInventory")] internal static class InventoryPatch { internal static QuestStateTracker? Tracker; internal static NavigationController? Nav; internal static LootScanner? Loot; [HarmonyPostfix] private static void Postfix() { Tracker?.OnInventoryChanged(); Nav?.OnGameStateChanged(Tracker?.CurrentZone ?? ""); Loot?.MarkDirty(); } } [HarmonyPatch(typeof(EventSystem), "IsPointerOverGameObject", new Type[] { })] internal static class PointerOverUIPatch { internal static ImGuiRenderer? Renderer; private static void Postfix(ref bool __result) { if (!__result) { ImGuiRenderer renderer = Renderer; if (renderer != null && renderer.WantCaptureMouse) { __result = true; } } } } [HarmonyPatch(typeof(GameData), "AssignQuest")] internal static class QuestAssignPatch { internal static QuestStateTracker? Tracker; internal static NavigationController? Nav; internal static LootScanner? Loot; internal static TrackerState? TrackerPins; [HarmonyPostfix] private static void Postfix(string _questName) { Tracker?.OnQuestAssigned(_questName); Nav?.OnGameStateChanged(Tracker?.CurrentZone ?? ""); Loot?.MarkDirty(); TrackerState trackerPins = TrackerPins; if (trackerPins != null && trackerPins.Enabled && trackerPins.AutoTrackEnabled) { TrackerPins.Track(_questName); } } } [HarmonyPatch(typeof(GameData), "FinishQuest")] internal static class QuestFinishPatch { internal static QuestStateTracker? Tracker; internal static NavigationController? Nav; internal static LootScanner? Loot; internal static TrackerState? TrackerPins; [HarmonyPostfix] private static void Postfix(string _questName) { Tracker?.OnQuestCompleted(_questName); Nav?.OnGameStateChanged(Tracker?.CurrentZone ?? ""); Loot?.MarkDirty(); TrackerPins?.OnQuestCompleted(_questName); } } [HarmonyPatch(typeof(QuestLog), "Update")] internal static class QuestLogPatch { internal static ConfigEntry? ReplaceQuestLog; [HarmonyPrefix] private static bool Prefix() { return !(ReplaceQuestLog?.Value ?? false); } } [HarmonyPatch(typeof(NPC), "SpawnQuestMarker")] internal static class QuestMarkerPatch { internal static bool SuppressGameMarkers; [HarmonyPrefix] private static bool Prefix() { return !SuppressGameMarkers; } } [HarmonyPatch(typeof(SpawnPoint), "SpawnNPC")] internal static class SpawnPatch { internal static EntityRegistry? Registry; internal static SpawnTimerTracker? Timers; internal static WorldMarkerSystem? Markers; internal static LootScanner? Loot; [HarmonyPostfix] private static void Postfix(SpawnPoint __instance) { if ((Object)(object)__instance.SpawnedNPC != (Object)null) { Registry?.Register(__instance.SpawnedNPC, __instance); } Timers?.OnNPCSpawn(__instance); Markers?.MarkSpawnDirty(); Loot?.MarkDirty(); } } } namespace AdventureGuide.Navigation { public sealed class ArrowRenderer { private const float ArrowSize = 20f; private const float EdgeMargin = 40f; private const float MarkerSize = 8f; private const float ArrivalDistance = 15f; private const float OutlineThickness = 1.5f; private static readonly uint ColorArrow = Theme.Rgba(1f, 0.85f, 0.3f, 0.9f); private static readonly uint ColorOutline = Theme.Rgba(0.1f, 0.1f, 0.1f, 0.8f); private static readonly uint ColorText = Theme.Rgba(1f, 0.95f, 0.6f, 0.95f); private readonly NavigationController _nav; private bool _enabled = true; private string[] _cachedLines = Array.Empty(); private CimguiNative.Vec2[] _cachedLineSizes = Array.Empty(); private float _cachedTotalHeight; private int _cachedDistInt = -1; private string? _cachedTargetName; public bool Enabled { get { return _enabled; } set { _enabled = value; } } public ArrowRenderer(NavigationController nav) { _nav = nav; } public void Draw() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_0276: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) if (!_enabled || _nav.Target == null || _nav.Distance < 15f) { return; } IntPtr intPtr = CimguiNative.igGetBackgroundDrawList_Nil(); if (intPtr == IntPtr.Zero) { return; } Camera val = CameraCache.Get(); if ((Object)(object)val == (Object)null) { return; } NavigationTarget navigationTarget = _nav.ZoneLineWaypoint ?? _nav.Target; Vector3 val2 = val.WorldToScreenPoint(navigationTarget.Position + Vector3.up * 0.5f); bool flag = val2.z < 0f; float num = Screen.width; float num2 = Screen.height; if (flag) { val2.x = num - val2.x; val2.y = num2 - val2.y; } float num3 = num2 - val2.y; bool flag2 = !flag && val2.x > 40f && val2.x < num - 40f && num3 > 40f && num3 < num2 - 40f; int num4 = Mathf.RoundToInt(_nav.Distance); if (num4 != _cachedDistInt || navigationTarget.DisplayName != _cachedTargetName) { _cachedDistInt = num4; _cachedTargetName = navigationTarget.DisplayName; string[] array = navigationTarget.DisplayName.Split('\n'); array[0] = $"{array[0]} ({num4}m)"; _cachedLines = array; _cachedLineSizes = new CimguiNative.Vec2[array.Length]; _cachedTotalHeight = 0f; for (int i = 0; i < array.Length; i++) { _cachedLineSizes[i] = CimguiNative.CalcTextSize(array[i]); _cachedTotalHeight += _cachedLineSizes[i].Y; } } if (flag2) { DrawDiamond(intPtr, val2.x, num3, 8f); DrawCenteredLines(intPtr, val2.x, num3 + 8f + 4f, num); return; } float num5 = num * 0.5f; float num6 = num2 * 0.5f; float num7 = val2.x - num5; float num8 = num3 - num6; float num9 = Mathf.Sqrt(num7 * num7 + num8 * num8); if (num9 < 0.01f) { num7 = 0f; num8 = -1f; num9 = 1f; } num7 /= num9; num8 /= num9; float num10 = 60f; float num11 = num * 0.5f - num10; float num12 = num2 * 0.5f - num10; float num13 = ((num7 != 0f) ? Mathf.Abs(num11 / num7) : float.MaxValue); float num14 = ((num8 != 0f) ? Mathf.Abs(num12 / num8) : float.MaxValue); float num15 = Mathf.Min(num13, num14); float num16 = num5 + num7 * num15; float num17 = num6 + num8 * num15; DrawArrow(intPtr, num16, num17, num7, num8); DrawCenteredLines(intPtr, num16, num17 + 20f + 4f, num); } public void Dispose() { } private void DrawCenteredLines(IntPtr dl, float anchorX, float y, float screenWidth) { for (int i = 0; i < _cachedLines.Length; i++) { float num = anchorX - _cachedLineSizes[i].X * 0.5f; if (num < 40f) { num = 40f; } if (num + _cachedLineSizes[i].X > screenWidth - 40f) { num = screenWidth - 40f - _cachedLineSizes[i].X; } CimguiNative.AddText(dl, num, y, ColorText, _cachedLines[i]); y += _cachedLineSizes[i].Y; } } private static void DrawArrow(IntPtr dl, float x, float y, float dirX, float dirY) { float num = Mathf.Atan2(dirY, dirX); float num2 = Mathf.Cos(num); float num3 = Mathf.Sin(num); float x2 = x + num2 * 20f; float y2 = y + num3 * 20f; float num4 = (0f - num3) * 20f * 0.5f; float num5 = num2 * 20f * 0.5f; float num6 = x - num2 * 20f * 0.3f; float num7 = y - num3 * 20f * 0.3f; CimguiNative.Vec2 p = new CimguiNative.Vec2(x2, y2); CimguiNative.Vec2 p2 = new CimguiNative.Vec2(num6 + num4, num7 + num5); CimguiNative.Vec2 p3 = new CimguiNative.Vec2(num6 - num4, num7 - num5); CimguiNative.ImDrawList_AddTriangleFilled(dl, p, p2, p3, ColorArrow); CimguiNative.ImDrawList_AddTriangle(dl, p, p2, p3, ColorOutline, 1.5f); } private static void DrawDiamond(IntPtr dl, float x, float y, float size) { CimguiNative.Vec2 vec = new CimguiNative.Vec2(x, y - size); CimguiNative.Vec2 vec2 = new CimguiNative.Vec2(x + size, y); CimguiNative.Vec2 vec3 = new CimguiNative.Vec2(x, y + size); CimguiNative.Vec2 vec4 = new CimguiNative.Vec2(x - size, y); CimguiNative.ImDrawList_AddQuadFilled(dl, vec, vec2, vec3, vec4, ColorArrow); CimguiNative.ImDrawList_AddLine(dl, vec, vec2, ColorOutline, 1.5f); CimguiNative.ImDrawList_AddLine(dl, vec2, vec3, ColorOutline, 1.5f); CimguiNative.ImDrawList_AddLine(dl, vec3, vec4, ColorOutline, 1.5f); CimguiNative.ImDrawList_AddLine(dl, vec4, vec, ColorOutline, 1.5f); } } public static class CameraCache { private static Camera? _camera; private static Transform? _lastCamPos; public static Camera? Get() { Transform gameCamPos = GameData.GameCamPos; if ((Object)(object)gameCamPos == (Object)null) { _camera = null; _lastCamPos = null; return null; } if ((Object)(object)_lastCamPos != (Object)(object)gameCamPos || (Object)(object)_camera == (Object)null) { _camera = ((Component)gameCamPos).GetComponent(); _lastCamPos = gameCamPos; } return _camera; } public static void Invalidate() { _camera = null; _lastCamPos = null; } } public sealed class EntityRegistry { private readonly struct Entry { public readonly NPC Npc; public readonly Character Character; public readonly string StableKey; public Entry(NPC npc, Character character, string stableKey) { Npc = npc; Character = character; StableKey = stableKey; } } private readonly Dictionary> _byKey = new Dictionary>(StringComparer.OrdinalIgnoreCase); public void Register(NPC npc, SpawnPoint? spawnPoint = null) { if ((Object)(object)npc == (Object)null) { return; } Character component = ((Component)npc).GetComponent(); if ((Object)(object)component == (Object)null) { return; } string text = DeriveStableKey(npc, spawnPoint); if (text != null) { if (!_byKey.TryGetValue(text, out List value)) { value = new List(2); _byKey[text] = value; } value.Add(new Entry(npc, component, text)); } } public void Unregister(NPC npc) { if ((Object)(object)npc == (Object)null) { return; } foreach (KeyValuePair> item in _byKey) { List value = item.Value; for (int num = value.Count - 1; num >= 0; num--) { if ((Object)(object)value[num].Npc == (Object)(object)npc) { value.RemoveAt(num); break; } } } } public void Clear() { _byKey.Clear(); } public void SyncFromLiveNPCs() { Clear(); if (NPCTable.LiveNPCs == null) { return; } SpawnPoint[] array = Object.FindObjectsOfType(); Dictionary dictionary = new Dictionary(); SpawnPoint[] array2 = array; foreach (SpawnPoint val in array2) { if ((Object)(object)val.SpawnedNPC != (Object)null) { dictionary[val.SpawnedNPC] = val; } } foreach (NPC liveNPC in NPCTable.LiveNPCs) { dictionary.TryGetValue(liveNPC, out var value); Register(liveNPC, value); } } public NPC? FindClosest(string? stableKey, Vector3 position) { //IL_0094: 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) if (stableKey == null) { return null; } if (!_byKey.TryGetValue(stableKey, out List value)) { string text = StripVariantSuffix(stableKey); if (text == null || !_byKey.TryGetValue(text, out value)) { return null; } } NPC result = null; float num = float.MaxValue; for (int num2 = value.Count - 1; num2 >= 0; num2--) { Entry entry = value[num2]; if (!IsAlive(in entry)) { value.RemoveAt(num2); } else { float num3 = Vector3.Distance(position, ((Component)entry.Npc).transform.position); if (num3 < num) { num = num3; result = entry.Npc; } } } if (value.Count == 0) { _byKey.Remove(stableKey); } return result; } public int CountAlive(string? stableKey) { if (stableKey == null) { return 0; } if (!_byKey.TryGetValue(stableKey, out List value)) { string text = StripVariantSuffix(stableKey); if (text == null || !_byKey.TryGetValue(text, out value)) { return 0; } } int num = 0; for (int num2 = value.Count - 1; num2 >= 0; num2--) { Entry entry = value[num2]; if (!IsAlive(in entry)) { value.RemoveAt(num2); } else { num++; } } if (value.Count == 0) { _byKey.Remove(stableKey); } return num; } internal static string? DeriveStableKey(NPC npc, SpawnPoint? spawnPoint = null) { if ((Object)(object)spawnPoint != (Object)null) { string text = FindPrefabName(spawnPoint.CommonSpawns, npc.NPCName) ?? FindPrefabName(spawnPoint.RareSpawns, npc.NPCName); if (text != null) { return "character:" + text.Trim().ToLowerInvariant(); } } string name = ((Object)((Component)npc).gameObject).name; if (string.IsNullOrEmpty(name)) { return null; } return "character:" + name.Trim().ToLowerInvariant(); } private static string? FindPrefabName(List? spawns, string npcName) { if (spawns == null) { return null; } foreach (GameObject spawn in spawns) { if (!((Object)(object)spawn == (Object)null)) { NPC component = spawn.GetComponent(); if ((Object)(object)component != (Object)null && string.Equals(component.NPCName, npcName, StringComparison.OrdinalIgnoreCase)) { return ((Object)spawn).name; } } } return null; } private static string? StripVariantSuffix(string key) { int num = key.LastIndexOf(':'); if (num <= 0) { return null; } ReadOnlySpan readOnlySpan = key.AsSpan(num + 1); if (readOnlySpan.Length == 0) { return null; } ReadOnlySpan readOnlySpan2 = readOnlySpan; for (int i = 0; i < readOnlySpan2.Length; i++) { char c = readOnlySpan2[i]; if (c < '0' || c > '9') { return null; } } string text = key.Substring(0, num); return (text.IndexOf(':') >= 0) ? text : null; } private static bool IsAlive(in Entry entry) { return (Object)(object)entry.Npc != (Object)null && (Object)(object)((Component)entry.Npc).gameObject != (Object)null && (Object)(object)entry.Character != (Object)null && entry.Character.Alive; } } public sealed class GroundPathRenderer { private sealed class PathSegment { private readonly LineRenderer _core; private readonly LineRenderer _glow; private readonly Material _coreMat; private Vector3 _anchor; internal PathSegment(GameObject parent, string name, Texture2D dashTex) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0059: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Expected O, but got Unknown //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name + "_Glow"); val.transform.SetParent(parent.transform); _glow = val.AddComponent(); ConfigureLineRenderer(_glow, 0.5f); Material val2 = new Material(Shader.Find("Sprites/Default")); val2.color = GlowColor; ((Renderer)_glow).material = val2; _glow.startColor = GlowColor; _glow.endColor = GlowColor; GameObject val3 = new GameObject(name + "_Core"); val3.transform.SetParent(parent.transform); _core = val3.AddComponent(); ConfigureLineRenderer(_core, 0.2f); _coreMat = new Material(Shader.Find("Sprites/Default")); _coreMat.mainTexture = (Texture)(object)dashTex; _coreMat.color = Color.white; ((Renderer)_core).material = _coreMat; _core.textureMode = (LineTextureMode)1; _core.startColor = CoreColor; _core.endColor = CoreColor; } internal void SetEndpoints(Vector3 p0, Vector3 p1) { //IL_001d: 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_002e: 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_0035: 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) _core.positionCount = 2; _glow.positionCount = 2; SetAt(0, p0); SetAt(1, p1); _anchor = p0; SetTiling(Vector3.Distance(p0, p1)); } internal void SetFromCorners(Vector3[] src, int start, int count, float yOffset) { //IL_0023: 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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) _core.positionCount = count; _glow.positionCount = count; float num = 0f; Vector3 val = default(Vector3); for (int i = 0; i < count; i++) { Vector3 val2 = src[start + i]; val2.y += yOffset; SetAt(i, val2); if (i == 0) { _anchor = val2; } else { num += Vector3.Distance(val, val2); } val = val2; } SetTiling(num); } internal void UpdateLastPosition(Vector3 pos) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) int num = _core.positionCount - 1; if (num >= 1) { SetAt(num, pos); float num2 = 0f; Vector3 val = _anchor; for (int i = 1; i <= num; i++) { Vector3 position = _core.GetPosition(i); num2 += Vector3.Distance(val, position); val = position; } SetTiling(num2); } } internal void Clear() { _core.positionCount = 0; _glow.positionCount = 0; } internal void SetVisible(bool visible) { bool enabled = visible && _core.positionCount >= 2; ((Renderer)_core).enabled = enabled; ((Renderer)_glow).enabled = enabled; } private void SetAt(int i, Vector3 pos) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) _core.SetPosition(i, pos); _glow.SetPosition(i, new Vector3(pos.x, pos.y - 0.01f, pos.z)); } private void SetTiling(float len) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) _coreMat.mainTextureScale = new Vector2(len * 1.5f, 1f); } } private const float RecalcDistance = 5f; private const float PlayerNavSampleRadius = 5f; private const float TargetNavSampleRadius = 15f; private const float ArrivalDistance = 15f; private const float CoreWidth = 0.2f; private const float GlowWidth = 0.5f; private const float TileScale = 1.5f; private static readonly Color CoreColor = new Color(1f, 0.85f, 0.3f, 0.8f); private static readonly Color GlowColor = new Color(1f, 0.75f, 0.2f, 0.15f); private readonly NavigationController _nav; private readonly NavMeshPath _path = new NavMeshPath(); private Vector3[] _corners = (Vector3[])(object)new Vector3[64]; private int _cornerCount; private bool _enabled; private Vector3 _lastCalcPlayerPos; private Vector3 _lastCalcTargetPos; private bool _pathValid; private GameObject? _lineObj; private PathSegment? _stub; private PathSegment? _mid; private PathSegment? _tail; public bool Enabled { get { return _enabled; } set { _enabled = value; SetAllVisible(value && _pathValid); } } public GroundPathRenderer(NavigationController nav) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown _nav = nav; } public void Update(string currentScene) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_010d: Unknown result type (might be due to invalid IL or missing references) if (!_enabled || _nav.Target == null) { _pathValid = false; SetAllVisible(visible: false); return; } if ((Object)(object)GameData.PlayerControl == (Object)null) { SetAllVisible(visible: false); return; } Vector3 position = ((Component)GameData.PlayerControl).transform.position; NavigationTarget navigationTarget = _nav.ZoneLineWaypoint ?? _nav.Target; if (navigationTarget.IsCrossZone(currentScene)) { _pathValid = false; SetAllVisible(visible: false); return; } if (_nav.Distance < 15f) { _pathValid = false; SetAllVisible(visible: false); return; } bool flag = RecalculateIfNeeded(position, navigationTarget.Position); if (!_pathValid || _cornerCount < 2) { SetAllVisible(visible: false); return; } if (flag) { ApplyToSegments(); } UpdateEndpoints(position, navigationTarget.Position); SetAllVisible(visible: true); } public void Destroy() { if ((Object)(object)_lineObj != (Object)null) { Object.Destroy((Object)(object)_lineObj); _lineObj = null; _stub = null; _mid = null; _tail = null; } } private bool RecalculateIfNeeded(Vector3 playerPos, Vector3 targetPos) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Invalid comparison between Unknown and I4 bool flag = Vector3.Distance(_lastCalcTargetPos, targetPos) > 0.5f; bool flag2 = Vector3.Distance(_lastCalcPlayerPos, playerPos) > 5f; if (_pathValid && !flag && !flag2) { return false; } NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(playerPos, ref val, 5f, -1)) { return false; } _lastCalcPlayerPos = playerPos; _lastCalcTargetPos = targetPos; Vector3 val2 = targetPos; NavMeshHit val3 = default(NavMeshHit); if (NavMesh.SamplePosition(targetPos, ref val3, 15f, -1)) { val2 = ((NavMeshHit)(ref val3)).position; } _path.ClearCorners(); if (!NavMesh.CalculatePath(((NavMeshHit)(ref val)).position, val2, -1, _path) || (int)_path.status == 2) { _pathValid = false; return true; } _pathValid = true; _cornerCount = _path.GetCornersNonAlloc(_corners); if (_cornerCount >= _corners.Length) { _corners = (Vector3[])(object)new Vector3[_cornerCount * 2]; _cornerCount = _path.GetCornersNonAlloc(_corners); } return true; } private void ApplyToSegments() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) EnsureSegments(); if (_cornerCount == 2) { _stub.SetEndpoints(Vector3.zero, Vector3.zero); _mid.Clear(); _tail.Clear(); return; } int num = 1; int num2 = _cornerCount - 2; Vector3 val = _corners[num]; val.y += 0.5f; _stub.SetEndpoints(val, val); Vector3 val2 = _corners[num2]; val2.y += 0.5f; _tail.SetEndpoints(val2, val2); if (num < num2) { _mid.SetFromCorners(_corners, num, num2 - num + 1, 0.5f); } else { _mid.Clear(); } } private void UpdateEndpoints(Vector3 playerPos, Vector3 targetPos) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) if (_stub != null && _cornerCount >= 2) { Vector3 val = playerPos + Vector3.up * 0.5f; Vector3 val2 = targetPos + Vector3.up * 0.5f; if (_cornerCount == 2) { _stub.SetEndpoints(val2, val); return; } _stub.UpdateLastPosition(val); _tail.UpdateLastPosition(val2); } } private void EnsureSegments() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown if (_stub == null) { _lineObj = new GameObject("AdventureGuide_GroundPath"); Object.DontDestroyOnLoad((Object)(object)_lineObj); ((Object)_lineObj).hideFlags = (HideFlags)61; Texture2D dashTex = CreateDashTexture(); _stub = new PathSegment(_lineObj, "Stub", dashTex); _mid = new PathSegment(_lineObj, "Mid", dashTex); _tail = new PathSegment(_lineObj, "Tail", dashTex); } } private void SetAllVisible(bool visible) { _stub?.SetVisible(visible); _mid?.SetVisible(visible); _tail?.SetVisible(visible); } private static void ConfigureLineRenderer(LineRenderer lr, float width) { lr.useWorldSpace = true; lr.startWidth = width; lr.endWidth = width; lr.numCornerVertices = 4; lr.numCapVertices = 2; ((Renderer)lr).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)lr).receiveShadows = false; ((Renderer)lr).allowOcclusionWhenDynamic = false; } private static Texture2D CreateDashTexture() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(128, 4, (TextureFormat)4, false); ((Texture)val).wrapMode = (TextureWrapMode)0; ((Texture)val).filterMode = (FilterMode)1; Color[] array = (Color[])(object)new Color[512]; Color val2 = default(Color); for (int i = 0; i < 128; i++) { float num = (float)i / 128f; float num2 = ((num < 0.1f) ? (num / 0.1f) : ((num < 0.45000002f) ? 1f : ((!(num < 0.55f)) ? 0f : ((0.55f - num) / 0.1f)))); ((Color)(ref val2))..ctor(1f, 1f, 1f, num2); for (int j = 0; j < 4; j++) { array[j * 128 + i] = val2; } } val.SetPixels(array); val.Apply(false, true); return val; } } public sealed class LootScanner { public readonly struct LootContainer { public readonly Vector3 Position; public readonly int InstanceId; public readonly Component Source; public readonly string DisplayName; public readonly HashSet MatchingItems; public LootContainer(Vector3 position, int instanceId, Component source, string displayName, HashSet matchingItems) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) Position = position; InstanceId = instanceId; Source = source; DisplayName = displayName; MatchingItems = matchingItems; } } private readonly HashSet _neededItems = new HashSet(StringComparer.OrdinalIgnoreCase); private readonly List _containers = new List(); private bool _dirty = true; private readonly List _rotChests = new List(); public IReadOnlyList Containers => _containers; public bool HasContainers => _containers.Count > 0; public void MarkDirty() { _dirty = true; } public void Update(GuideData data, QuestStateTracker state) { if (PruneDestroyed()) { _dirty = true; } if (_dirty) { _dirty = false; Rebuild(data, state); } } public void OnSceneLoaded() { _rotChests.Clear(); _rotChests.AddRange(Object.FindObjectsOfType()); _dirty = true; } public LootContainer? FindClosestWithAnyItem(HashSet items, Vector3 playerPos) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if (items.Count == 0) { return null; } LootContainer? result = null; float num = float.MaxValue; foreach (LootContainer container in _containers) { bool flag = false; foreach (string matchingItem in container.MatchingItems) { if (items.Contains(matchingItem)) { flag = true; break; } } if (flag) { float num2 = Vector3.Distance(playerPos, container.Position); if (num2 < num) { num = num2; result = container; } } } return result; } private void Rebuild(GuideData data, QuestStateTracker state) { //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) _neededItems.Clear(); _containers.Clear(); foreach (QuestEntry item in data.All) { if (!state.IsActionable(item.DBName) || item.RequiredItems == null) { continue; } foreach (RequiredItemInfo requiredItem in item.RequiredItems) { if (state.CountItem(requiredItem.ItemStableKey) < requiredItem.Quantity) { _neededItems.Add(requiredItem.ItemName); } } } if (_neededItems.Count == 0) { return; } foreach (CorpseData allCorpseDatum in CorpseDataManager.AllCorpseData) { if ((Object)(object)allCorpseDatum.MyNPC == (Object)null) { continue; } LootTable component = ((Component)allCorpseDatum.MyNPC).GetComponent(); if (!((Object)(object)component == (Object)null)) { HashSet hashSet = FindMatchingItems(component); if (hashSet.Count > 0) { _containers.Add(new LootContainer(((Component)allCorpseDatum.MyNPC).transform.position, ((Object)allCorpseDatum.MyNPC).GetInstanceID(), (Component)(object)allCorpseDatum.MyNPC, allCorpseDatum.MyNPC.NPCName, hashSet)); } } } foreach (RotChest rotChest in _rotChests) { if ((Object)(object)rotChest == (Object)null) { continue; } LootTable component2 = ((Component)rotChest).GetComponent(); if (!((Object)(object)component2 == (Object)null)) { HashSet hashSet2 = FindMatchingItems(component2); if (hashSet2.Count > 0) { _containers.Add(new LootContainer(((Component)rotChest).transform.position, ((Object)rotChest).GetInstanceID(), (Component)(object)rotChest, "Loot Chest", hashSet2)); } } } } private HashSet FindMatchingItems(LootTable loot) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (Item actualDrop in loot.ActualDrops) { if ((Object)(object)actualDrop != (Object)null && !string.IsNullOrEmpty(actualDrop.ItemName) && _neededItems.Contains(actualDrop.ItemName)) { hashSet.Add(actualDrop.ItemName); } } return hashSet; } private bool PruneDestroyed() { bool result = false; for (int num = _containers.Count - 1; num >= 0; num--) { if ((Object)(object)_containers[num].Source == (Object)null) { _containers.RemoveAt(num); result = true; } } for (int num2 = _rotChests.Count - 1; num2 >= 0; num2--) { if ((Object)(object)_rotChests[num2] == (Object)null) { _rotChests.RemoveAt(num2); } } return result; } } internal static class MarkerFonts { internal const char CircleQuestion = '\uf059'; internal const char Star = '\uf005'; internal const char CircleDot = '\uf192'; internal const char Clock = '\uf017'; internal const char Moon = '\uf186'; private static readonly char[] RequiredGlyphs = new char[5] { '\uf059', '\uf005', '\uf192', '\uf017', '\uf186' }; private static readonly Color OutlineColor = new Color(0.04f, 0.03f, 0.02f, 0.85f); private const float OutlineWidth = 0.18f; private static TMP_FontAsset? _iconFont; private static TMP_FontAsset? _subTextFont; private static bool _initialized; public static TMP_FontAsset? IconFont { get { EnsureInitialized(); return _iconFont; } } public static TMP_FontAsset? SubTextFont { get { EnsureInitialized(); return _subTextFont; } } public static bool IsReady { get { EnsureInitialized(); return _initialized; } } public static void Destroy() { if ((Object)(object)_iconFont != (Object)null) { Object.Destroy((Object)(object)_iconFont); } if ((Object)(object)_subTextFont != (Object)null) { Object.Destroy((Object)(object)_subTextFont); } _iconFont = null; _subTextFont = null; _initialized = false; } private static void EnsureInitialized() { if (_initialized) { return; } Shader val = Shader.Find("TextMeshPro/Distance Field"); if ((Object)(object)val == (Object)null) { return; } _iconFont = CreateIconFont(val); _subTextFont = CreateSubTextFont(val); if ((Object)(object)_iconFont == (Object)null || (Object)(object)_subTextFont == (Object)null) { if ((Object)(object)_iconFont != (Object)null) { Object.Destroy((Object)(object)_iconFont); } if ((Object)(object)_subTextFont != (Object)null) { Object.Destroy((Object)(object)_subTextFont); } _iconFont = null; _subTextFont = null; } else { _initialized = true; } } private static TMP_FontAsset? CreateIconFont(Shader sdfShader) { Font val = GameData.Misc?.FontAwesome; if ((Object)(object)val == (Object)null) { return null; } TMP_FontAsset val2 = TMP_FontAsset.CreateFontAsset(val); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogError((object)"MarkerFonts: Failed to create TMP_FontAsset from Font Awesome"); return null; } ((Object)val2).name = "MarkerIcons-FA"; ConfigureMaterial(((TMP_Asset)val2).material, sdfShader); string text = new string(RequiredGlyphs); string text2 = default(string); if (!val2.TryAddCharacters(text, ref text2, true)) { Object.Destroy((Object)(object)val2); return null; } char[] requiredGlyphs = RequiredGlyphs; foreach (char c in requiredGlyphs) { if (!val2.HasCharacter(c, false, false)) { Object.Destroy((Object)(object)val2); return null; } } Plugin.Log.LogInfo((object)"MarkerFonts: Icon font created (Font Awesome SDF)"); return val2; } private static TMP_FontAsset? CreateSubTextFont(Shader sdfShader) { Font val = FindFont("Roboto-Regular"); if ((Object)(object)val == (Object)null) { return null; } TMP_FontAsset val2 = TMP_FontAsset.CreateFontAsset(val); if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogError((object)"MarkerFonts: Failed to create TMP_FontAsset from Roboto"); return null; } ((Object)val2).name = "MarkerSubText-Roboto"; ConfigureMaterial(((TMP_Asset)val2).material, sdfShader); Plugin.Log.LogInfo((object)"MarkerFonts: Sub-text font created (Roboto SDF)"); return val2; } private static void ConfigureMaterial(Material material, Shader sdfShader) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) material.shader = sdfShader; material.SetColor("_OutlineColor", OutlineColor); material.SetFloat("_OutlineWidth", 0.18f); material.EnableKeyword("OUTLINE_ON"); } private static Font? FindFont(string name) { //IL_001e: 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_003c: Expected O, but got Unknown Object[] array = Resources.FindObjectsOfTypeAll(typeof(Font)); Object[] array2 = array; foreach (Object val in array2) { if (((Object)(Font)val).name == name) { return (Font)val; } } return null; } } public enum MarkerType { TurnInReady, TurnInRepeatReady, Objective, QuestGiver, QuestGiverRepeat, TurnInPending, DeadSpawn, NightSpawn, ZoneReentry } public sealed class MarkerPool { private const int InitialCapacity = 32; private readonly GameObject _root; private readonly List _pool; private int _activeCount; public int ActiveCount => _activeCount; public MarkerPool() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown _root = new GameObject("AdventureGuide_WorldMarkers"); Object.DontDestroyOnLoad((Object)(object)_root); ((Object)_root).hideFlags = (HideFlags)61; _pool = new List(32); _activeCount = 0; for (int i = 0; i < 32; i++) { CreateInstance(); } } public MarkerInstance Get(int index) { while (index >= _pool.Count) { CreateInstance(); } return _pool[index]; } public void SetActiveCount(int count) { for (int i = count; i < _activeCount; i++) { _pool[i].SetActive(active: false); } _activeCount = count; } public void DeactivateAll() { for (int i = 0; i < _activeCount; i++) { _pool[i].SetActive(active: false); } _activeCount = 0; } public void Destroy() { Object.Destroy((Object)(object)_root); _pool.Clear(); _activeCount = 0; } private void CreateInstance() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_003e: 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_005b: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject($"Marker_{_pool.Count}"); val.transform.SetParent(_root.transform); val.transform.localScale = Vector3.one; val.AddComponent(); GameObject val2 = new GameObject("Icon"); val2.transform.SetParent(val.transform); val2.transform.localPosition = Vector3.zero; TextMeshPro val3 = val2.AddComponent(); ((TMP_Text)val3).alignment = (TextAlignmentOptions)514; ((TMP_Text)val3).enableWordWrapping = false; ((TMP_Text)val3).overflowMode = (TextOverflowModes)0; ((TMP_Text)val3).richText = false; val2.transform.localScale = new Vector3(-1f, 1f, 1f); GameObject val4 = new GameObject("SubText"); val4.transform.SetParent(val.transform); TextMeshPro val5 = val4.AddComponent(); ((TMP_Text)val5).alignment = (TextAlignmentOptions)258; ((TMP_Text)val5).enableWordWrapping = true; ((TMP_Text)val5).overflowMode = (TextOverflowModes)3; ((TMP_Text)val5).richText = false; ((Graphic)val5).color = MarkerInstance.SubTextColor; val4.transform.localScale = new Vector3(-1f, 1f, 1f); RectTransform rectTransform = ((TMP_Text)val3).rectTransform; rectTransform.sizeDelta = new Vector2(4f, 4f); RectTransform rectTransform2 = ((TMP_Text)val5).rectTransform; rectTransform2.sizeDelta = new Vector2(8f, 3f); val.SetActive(false); _pool.Add(new MarkerInstance(val, val3, val5)); } } public sealed class MarkerInstance { private const float SizeTier1 = 8f; private const float SizeTier2 = 7f; private const float SizeObjective = 6.5f; private const float SizeTier3 = 6f; private const float SizeInfo = 5.5f; private static readonly Color Gold = new Color(1f, 0.85f, 0.3f, 1f); private static readonly Color Blue = new Color(0.4f, 0.65f, 1f, 1f); private static readonly Color Orange = new Color(1f, 0.6f, 0.25f, 1f); private static readonly Color Grey = new Color(0.5f, 0.5f, 0.5f, 1f); private static readonly Color MutedRed = new Color(0.65f, 0.35f, 0.35f, 1f); private static readonly Color PaleBlue = new Color(0.55f, 0.6f, 0.8f, 1f); internal static readonly Color SubTextColor = new Color(0.92f, 0.92f, 0.92f, 1f); private const float IconFadeStart = 100f; private const float IconFadeEnd = 150f; private const float SubFadeStart = 60f; private const float SubFadeEnd = 80f; private static readonly (char glyph, Color color, float size)[] TypeVisuals = new(char, Color, float)[9] { ('\uf059', Gold, 8f), ('\uf059', Blue, 8f), ('\uf192', Orange, 6.5f), ('\uf005', Gold, 7f), ('\uf005', Blue, 7f), ('\uf059', Grey, 6f), ('\uf017', MutedRed, 5.5f), ('\uf186', PaleBlue, 5.5f), ('\uf017', Grey, 5.5f) }; public readonly GameObject Root; private readonly TextMeshPro _icon; private readonly TextMeshPro _subText; private Color _baseIconColor; public MarkerInstance(GameObject root, TextMeshPro icon, TextMeshPro subText) { Root = root; _icon = icon; _subText = subText; } public void Configure(MarkerType type, string? subText, float markerScale, float iconSize, float subTextSize, float iconYOffset, float subTextYOffset) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: 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_00c5: 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) var (c, val, _) = TypeVisuals[(int)type]; Root.transform.localScale = Vector3.one * markerScale; if ((Object)(object)MarkerFonts.IconFont != (Object)null) { ((TMP_Text)_icon).font = MarkerFonts.IconFont; } if ((Object)(object)MarkerFonts.SubTextFont != (Object)null) { ((TMP_Text)_subText).font = MarkerFonts.SubTextFont; } ((TMP_Text)_icon).text = c.ToString(); ((TMP_Text)_icon).fontSize = iconSize; ((Graphic)_icon).color = val; _baseIconColor = val; _icon.transform.localPosition = new Vector3(0f, iconYOffset, 0f); ((TMP_Text)_subText).fontSize = subTextSize; _subText.transform.localPosition = new Vector3(0f, subTextYOffset, 0f); if (!string.IsNullOrEmpty(subText)) { ((TMP_Text)_subText).text = subText; ((Component)_subText).gameObject.SetActive(true); } else { ((TMP_Text)_subText).text = ""; ((Component)_subText).gameObject.SetActive(false); } } public void UpdateSubText(string? subText) { if (!string.IsNullOrEmpty(subText)) { ((TMP_Text)_subText).text = subText; ((Component)_subText).gameObject.SetActive(true); } else { ((TMP_Text)_subText).text = ""; ((Component)_subText).gameObject.SetActive(false); } } public void SetPosition(Vector3 position) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) Root.transform.position = position; } public void SetAlpha(float distance) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: 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) float a = ComputeFade(distance, 100f, 150f); float a2 = ComputeFade(distance, 60f, 80f); Color baseIconColor = _baseIconColor; baseIconColor.a = a; ((Graphic)_icon).color = baseIconColor; if (((Component)_subText).gameObject.activeSelf) { Color subTextColor = SubTextColor; subTextColor.a = a2; ((Graphic)_subText).color = subTextColor; } } public void SetActive(bool active) { Root.SetActive(active); } private static float ComputeFade(float distance, float fadeStart, float fadeEnd) { if (distance > fadeEnd) { return 0f; } if (distance > fadeStart) { return 1f - (distance - fadeStart) / (fadeEnd - fadeStart); } return 1f; } } public sealed class MiningNodeTracker { private static readonly FieldInfo? RespawnField = typeof(MiningNode).GetField("Respawn", BindingFlags.Instance | BindingFlags.NonPublic); private const float TickRate = 60f; private MiningNode[] _nodes = Array.Empty(); public MiningNode[] Nodes => _nodes; public void Rescan() { _nodes = Object.FindObjectsOfType(); } public void Clear() { _nodes = Array.Empty(); } public static bool IsMined(MiningNode node) { return (Object)(object)node.MyRender != (Object)null && !((Renderer)node.MyRender).enabled; } public static float? GetRemainingSeconds(MiningNode node) { if (RespawnField == null) { return null; } if (!IsMined(node)) { return null; } float num = (float)RespawnField.GetValue(node); if (num <= 0f) { return null; } return num / 60f; } public (MiningNode node, float seconds)? FindShortestRespawn() { MiningNode val = null; float num = float.MaxValue; MiningNode[] nodes = _nodes; foreach (MiningNode val2 in nodes) { if (!((Object)(object)val2 == (Object)null)) { float? remainingSeconds = GetRemainingSeconds(val2); if (remainingSeconds.HasValue && remainingSeconds.Value < num) { val = val2; num = remainingSeconds.Value; } } } return ((Object)(object)val != (Object)null) ? new(MiningNode, float)?((val, num)) : null; } public MiningNode? FindClosestAlive(Vector3 playerPos) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) MiningNode result = null; float num = float.MaxValue; MiningNode[] nodes = _nodes; foreach (MiningNode val in nodes) { if (!((Object)(object)val == (Object)null) && !IsMined(val)) { Vector3 val2 = ((Component)val).transform.position - playerPos; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num) { result = val; num = sqrMagnitude; } } } return result; } } public sealed class NavigationController { private readonly GuideData _data; private readonly EntityRegistry _entities; private readonly QuestStateTracker _state; private readonly SpawnTimerTracker _timers; private readonly MiningNodeTracker _miningTracker; private readonly LootScanner _lootScanner; private readonly ZoneGraph _zoneGraph; private ZoneLineEntry? _cachedZoneLine; private ZoneLineEntry? _pinnedZoneLine; private Vector3 _lastCrossZoneCalcPos; private const float CrossZoneRecalcDistance = 10f; private const string MiningNodesKeyPrefix = "mining-nodes:"; private const string FishingKeyPrefix = "fishing:"; private List _allItemSources = new List(); private readonly HashSet _activeSourceKeys = new HashSet(StringComparer.OrdinalIgnoreCase); private bool _manualOverride; private string? _currentSourceKey; private string? _originQuestDBName; private int _originStepOrder; private ConfigEntry? _navQuestEntry; private ConfigEntry? _navStepEntry; private int _boundSlotIndex = -1; private float _sourceRescanTimer; private const float SourceRescanInterval = 0.25f; private readonly NavMeshPath _scratchPath = new NavMeshPath(); public NavigationTarget? Target { get; private set; } public float Distance { get; private set; } public Vector3 Direction { get; private set; } public NavigationTarget? ZoneLineWaypoint { get; private set; } public bool IsManualSourceOverride => _manualOverride; public NavigationController(GuideData data, EntityRegistry entities, QuestStateTracker state, SpawnTimerTracker timers, MiningNodeTracker miningTracker, LootScanner lootScanner) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown _data = data; _entities = entities; _state = state; _timers = timers; _miningTracker = miningTracker; _lootScanner = lootScanner; _zoneGraph = new ZoneGraph(data, state); } public bool NavigateTo(QuestStep step, QuestEntry quest, string currentScene) { _originQuestDBName = quest.DBName; _originStepOrder = step.Order; SavePerCharacter(); return ResolveAndNavigate(step, quest, currentScene); } private bool ResolveAndNavigate(QuestStep step, QuestEntry quest, string currentScene) { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) var (questStep, questEntry) = StepProgress.ResolveActiveStep(step, quest, _state, _data); if (questStep != null && questEntry != null && questStep != step) { step = questStep; quest = questEntry; } if (step.Action == "complete_quest") { return false; } ResetTargetState(); if (step.TargetKey == null) { return false; } if (step.TargetType == "character") { Vector3? playerPosition = GetPlayerPosition(); if (playerPosition.HasValue) { NPC val = _entities.FindClosest(step.TargetKey, playerPosition.Value); if ((Object)(object)val != (Object)null) { Target = MakeTarget(NavigationTarget.Kind.Character, ((Component)val).transform.position, WithCharacterUnlockText(step.TargetName ?? step.Description, step.TargetKey), currentScene, quest.DBName, step.Order, step.TargetKey); return true; } } } string targetType = step.TargetType; if (1 == 0) { } bool result = targetType switch { "character" => ResolveCharacterTarget(step, quest, currentScene), "zone" => ResolveZoneTarget(step, quest, currentScene), "item" => ResolveItemTarget(step, quest, currentScene), _ => false, }; if (1 == 0) { } return result; } public void PinZoneLine(ZoneLineEntry zoneLine) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) _pinnedZoneLine = zoneLine; _cachedZoneLine = null; _lastCrossZoneCalcPos = Vector3.zero; } public void Clear() { ResetTargetState(); _originQuestDBName = null; _originStepOrder = 0; SavePerCharacter(); } public void LoadPerCharacter(GuideConfig config, string currentScene) { SaveGameData currentCharacterSlot = GameData.CurrentCharacterSlot; if (currentCharacterSlot == null || currentCharacterSlot.index == _boundSlotIndex) { return; } SavePerCharacter(); _boundSlotIndex = currentCharacterSlot.index; _navQuestEntry = config.BindPerCharacter(currentCharacterSlot.index, "NavQuest", ""); _navStepEntry = config.BindPerCharacter(currentCharacterSlot.index, "NavStep", 0); string value = _navQuestEntry.Value; int value2 = _navStepEntry.Value; if (string.IsNullOrEmpty(value) || value2 <= 0) { return; } QuestEntry byDBName = _data.GetByDBName(value); if (byDBName?.Steps == null || _state.IsCompleted(byDBName.DBName)) { return; } QuestStep questStep = null; foreach (QuestStep step in byDBName.Steps) { if (step.Order == value2) { questStep = step; break; } } if (questStep != null) { NavigateTo(questStep, byDBName, currentScene); } } public void SavePerCharacter() { if (_navQuestEntry != null) { _navQuestEntry.Value = _originQuestDBName ?? ""; _navStepEntry.Value = _originStepOrder; } } private void ResetTargetState() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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) Target = null; ZoneLineWaypoint = null; _cachedZoneLine = null; _pinnedZoneLine = null; _lastCrossZoneCalcPos = Vector3.zero; _activeSourceKeys.Clear(); _allItemSources.Clear(); _manualOverride = false; _currentSourceKey = null; _sourceRescanTimer = 0f; Distance = 0f; Direction = Vector3.zero; } public void ToggleSource(string sourceKey, string currentScene) { if (Target == null) { return; } _manualOverride = true; if (!_activeSourceKeys.Remove(sourceKey)) { _activeSourceKeys.Add(sourceKey); } if (_activeSourceKeys.Count == 0) { _manualOverride = false; ComputeAutoSourceSet(currentScene); } QuestEntry byDBName = _data.GetByDBName(Target.QuestDBName); if (byDBName?.Steps != null) { QuestStep questStep = byDBName.Steps.Find((QuestStep s) => s.Order == Target.StepOrder); if (questStep != null) { Target = null; ZoneLineWaypoint = null; _cachedZoneLine = null; _currentSourceKey = null; ResolveClosestActiveSource(byDBName, questStep, currentScene); } } } public bool IsSourceActive(string sourceKey) { return _activeSourceKeys.Contains(sourceKey); } public bool NavigateToZone(string scene, string displayName, string sourceId, string questDBName, int stepOrder, string currentScene) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) Clear(); if (string.Equals(scene, currentScene, StringComparison.OrdinalIgnoreCase)) { Target = MakeTarget(NavigationTarget.Kind.Zone, Vector3.zero, displayName, scene, questDBName, stepOrder, sourceId); return true; } string text = FindZoneKeyBySceneName(scene); if (text == null) { return false; } Vector3 playerPos = (Vector3)(((??)GetPlayerPosition()) ?? Vector3.zero); ZoneLineEntry zoneLineEntry = FindClosestZoneLine(text, currentScene, playerPos); if (zoneLineEntry != null) { Target = MakeTarget(NavigationTarget.Kind.ZoneLine, new Vector3(zoneLineEntry.X, zoneLineEntry.Y, zoneLineEntry.Z), "To: " + zoneLineEntry.DestinationDisplay, currentScene, questDBName, stepOrder, sourceId); } else { Target = MakeTarget(NavigationTarget.Kind.Zone, Vector3.zero, displayName, scene, questDBName, stepOrder, sourceId); } return true; } public void OnGameStateChanged(string currentScene) { _zoneGraph.Rebuild(); if (Target == null) { return; } QuestEntry byDBName = _data.GetByDBName(Target.QuestDBName); if (byDBName?.Steps == null) { Clear(); return; } if (_state.IsCompleted(byDBName.DBName)) { Clear(); return; } int currentStepIndex = StepProgress.GetCurrentStepIndex(byDBName, _state, _data); int num = -1; for (int i = 0; i < byDBName.Steps.Count; i++) { if (byDBName.Steps[i].Order == Target.StepOrder) { num = i; break; } } if (num < 0 || num >= currentStepIndex) { if (!_manualOverride && _allItemSources.Count > 0) { ComputeAutoSourceSet(currentScene); } return; } for (int j = currentStepIndex; j < byDBName.Steps.Count; j++) { QuestStep questStep = byDBName.Steps[j]; if (questStep.TargetKey != null) { ResolveAndNavigate(questStep, byDBName, currentScene); return; } } Clear(); } public void Update(string currentScene) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0230: 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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) if (Target == null) { return; } Vector3? playerPosition = GetPlayerPosition(); if (!playerPosition.HasValue) { return; } if (Target.IsCrossZone(currentScene)) { UpdateCrossZoneRouting(currentScene, playerPosition.Value); return; } ZoneLineWaypoint = null; if (Target.TargetKind == NavigationTarget.Kind.Zone) { Distance = 0f; Direction = Vector3.zero; return; } if (Target.TargetKind == NavigationTarget.Kind.Character) { HashSet hashSet = BuildNeededItems(Target.QuestDBName); LootScanner.LootContainer? lootContainer = ((hashSet.Count > 0) ? _lootScanner.FindClosestWithAnyItem(hashSet, playerPosition.Value) : null); if (lootContainer.HasValue) { Target.Position = lootContainer.Value.Position; } else if (_activeSourceKeys.Count > 0) { _sourceRescanTimer += Time.deltaTime; if (_sourceRescanTimer >= 0.25f) { _sourceRescanTimer = 0f; UpdateClosestActiveSource(currentScene, playerPosition.Value); } TrackCurrentSourcePosition(playerPosition.Value); } else if (IsMiningNodesKey(Target.SourceId)) { UpdateMiningTarget(playerPosition.Value); } else { NPC val = _entities.FindClosest(Target.SourceId, playerPosition.Value); if ((Object)(object)val != (Object)null) { Target.Position = ((Component)val).transform.position; } else { Vector3? val2 = FindShortestRespawnPosition(Target.SourceId); if (val2.HasValue) { Target.Position = val2.Value; } } } } UpdateDistanceAndDirection(Target.Position, playerPosition.Value); } public bool IsNavigating(string questDBName, int stepOrder) { return Target != null && (IsMatch(Target.QuestDBName, Target.StepOrder, questDBName, stepOrder) || IsMatch(Target.OriginQuestDBName, Target.OriginStepOrder, questDBName, stepOrder)); } private static bool IsMatch(string aQuest, int aStep, string bQuest, int bStep) { return string.Equals(aQuest, bQuest, StringComparison.OrdinalIgnoreCase) && aStep == bStep; } public List<(ZoneLineEntry line, float distance, bool isActive, bool isAccessible)> GetAlternativeZoneLines(string currentScene) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: 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) List<(ZoneLineEntry, float, bool, bool)> list = new List<(ZoneLineEntry, float, bool, bool)>(); if (Target == null || !Target.IsCrossZone(currentScene)) { return list; } Vector3 val = (Vector3)(((??)GetPlayerPosition()) ?? Vector3.zero); string text = FindZoneKeyBySceneName(Target.Scene); if (text == null) { return list; } Vector3 val2 = default(Vector3); foreach (ZoneLineEntry zoneLine in _data.ZoneLines) { if (string.Equals(zoneLine.Scene, currentScene, StringComparison.OrdinalIgnoreCase) && string.Equals(zoneLine.DestinationZoneKey, text, StringComparison.OrdinalIgnoreCase)) { ((Vector3)(ref val2))..ctor(zoneLine.X, zoneLine.Y, zoneLine.Z); float item = Vector3.Distance(val, val2); ZoneLineEntry zoneLineEntry = _pinnedZoneLine ?? _cachedZoneLine; bool item2 = zoneLineEntry != null && zoneLine.X == zoneLineEntry.X && zoneLine.Y == zoneLineEntry.Y && zoneLine.Z == zoneLineEntry.Z; bool item3 = IsZoneLineAccessible(zoneLine); list.Add((zoneLine, item, item2, item3)); } } list.Sort(delegate((ZoneLineEntry line, float distance, bool isActive, bool isAccessible) a, (ZoneLineEntry line, float distance, bool isActive, bool isAccessible) b) { int num = b.isAccessible.CompareTo(a.isAccessible); return (num != 0) ? num : a.distance.CompareTo(b.distance); }); return list; } private static bool IsMiningNodesKey(string? key) { return key?.StartsWith("mining-nodes:", StringComparison.Ordinal) ?? false; } private static bool IsFishingKey(string? key) { return key?.StartsWith("fishing:", StringComparison.Ordinal) ?? false; } private static string FishingKeyScene(string key) { return key.Substring("fishing:".Length); } private void UpdateClosestActiveSource(string currentScene, Vector3 playerPos) { //IL_00a1: 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) //IL_00bf: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) NPC val = null; string text = null; float num = float.MaxValue; foreach (string activeSourceKey in _activeSourceKeys) { if (IsFishingKey(activeSourceKey)) { continue; } Vector3 val3; if (IsMiningNodesKey(activeSourceKey)) { MiningNode val2 = _miningTracker.FindClosestAlive(playerPos); if ((Object)(object)val2 != (Object)null) { val3 = ((Component)val2).transform.position - playerPos; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; text = activeSourceKey; val = null; } } continue; } NPC val4 = _entities.FindClosest(activeSourceKey, playerPos); if ((Object)(object)val4 != (Object)null) { val3 = ((Component)val4).transform.position - playerPos; float sqrMagnitude2 = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude2 < num) { num = sqrMagnitude2; text = activeSourceKey; val = val4; } } } if (text == null || !(text != _currentSourceKey)) { return; } _currentSourceKey = text; string text2 = null; foreach (ItemSource allItemSource in _allItemSources) { if (string.Equals(allItemSource.SourceKey, text, StringComparison.OrdinalIgnoreCase)) { text2 = allItemSource.Name; break; } } Target.SourceId = text; Target.DisplayName = WithCharacterUnlockText(text2 ?? text, text); } private void TrackCurrentSourcePosition(Vector3 playerPos) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_009e: Unknown result type (might be due to invalid IL or missing references) if (_currentSourceKey == null || IsFishingKey(_currentSourceKey)) { return; } if (IsMiningNodesKey(_currentSourceKey)) { UpdateMiningTarget(playerPos); return; } NPC val = _entities.FindClosest(_currentSourceKey, playerPos); if ((Object)(object)val != (Object)null) { Target.Position = ((Component)val).transform.position; return; } Vector3? val2 = FindShortestRespawnPosition(_currentSourceKey); if (val2.HasValue) { Target.Position = val2.Value; } } private void UpdateMiningTarget(Vector3 playerPos) { //IL_0007: 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_0061: Unknown result type (might be due to invalid IL or missing references) MiningNode val = _miningTracker.FindClosestAlive(playerPos); if ((Object)(object)val != (Object)null) { Target.Position = ((Component)val).transform.position; return; } (MiningNode, float)? tuple = _miningTracker.FindShortestRespawn(); if (tuple.HasValue) { Target.Position = ((Component)tuple.Value.Item1).transform.position; } } private Vector3? FindShortestRespawnPosition(string? stableKey) { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) if (stableKey == null) { return null; } SpawnPoint val = null; float num = float.MaxValue; foreach (KeyValuePair item in _timers.Tracked) { TrackedSpawn value = item.Value; if (!((Object)(object)value.Point == (Object)null) && string.Equals(value.StableKey, stableKey, StringComparison.OrdinalIgnoreCase)) { float? remainingSeconds = _timers.GetRemainingSeconds(value.Point); if (remainingSeconds.HasValue && remainingSeconds.Value < num) { val = value.Point; num = remainingSeconds.Value; } } } return (val != null) ? new Vector3?(((Component)val).transform.position) : null; } private bool ResolveCharacterTarget(QuestStep step, QuestEntry quest, string currentScene) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (!_data.CharacterSpawns.TryGetValue(step.TargetKey, out List value) || value.Count == 0) { return false; } SpawnPoint spawnPoint = PickBestSpawn(value, currentScene); Target = MakeTarget(NavigationTarget.Kind.Character, new Vector3(spawnPoint.X, spawnPoint.Y, spawnPoint.Z), WithCharacterUnlockText(step.TargetName ?? step.Description, step.TargetKey), spawnPoint.Scene, quest.DBName, step.Order, step.TargetKey); return true; } private bool ResolveZoneTarget(QuestStep step, QuestEntry quest, string currentScene) { //IL_0101: 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) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) string destZoneKey = step.TargetKey; if (destZoneKey != null && !_data.ZoneLookup.Values.Any((ZoneInfo z) => string.Equals(z.StableKey, destZoneKey, StringComparison.OrdinalIgnoreCase))) { destZoneKey = FindZoneKeyByDisplayName(step.TargetName); } if (destZoneKey == null) { return false; } string text = null; foreach (KeyValuePair item in _data.ZoneLookup) { if (string.Equals(item.Value.StableKey, destZoneKey, StringComparison.OrdinalIgnoreCase)) { text = item.Key; break; } } if (text == null) { return false; } Vector3 playerPos = (Vector3)(((??)GetPlayerPosition()) ?? Vector3.zero); ZoneLineEntry zoneLineEntry = FindClosestZoneLine(destZoneKey, currentScene, playerPos); if (zoneLineEntry != null) { Target = MakeTarget(NavigationTarget.Kind.ZoneLine, new Vector3(zoneLineEntry.X, zoneLineEntry.Y, zoneLineEntry.Z), "To: " + zoneLineEntry.DestinationDisplay, currentScene, quest.DBName, step.Order); } else { Target = MakeTarget(NavigationTarget.Kind.Zone, Vector3.zero, step.TargetName ?? text, text, quest.DBName, step.Order); } return true; } private bool ResolveItemTarget(QuestStep step, QuestEntry quest, string currentScene) { QuestStep step2 = step; RequiredItemInfo requiredItemInfo = quest.RequiredItems?.Find((RequiredItemInfo ri) => string.Equals(ri.ItemName, step2.TargetName, StringComparison.OrdinalIgnoreCase)); if (requiredItemInfo?.Sources == null || requiredItemInfo.Sources.Count == 0) { return false; } _allItemSources.Clear(); CollectLeafSources(requiredItemInfo.Sources, _allItemSources); if (_allItemSources.Count == 0) { return ResolveItemZoneFallback(requiredItemInfo.Sources, quest, step2, currentScene); } _manualOverride = false; ComputeAutoSourceSet(currentScene); return ResolveClosestActiveSource(quest, step2, currentScene); } private void CollectLeafSources(List sources, List result) { foreach (ItemSource source in sources) { if (source.Type == "quest_reward") { List children = source.Children; if (children != null && children.Count > 0) { CollectLeafSources(source.Children, result); continue; } } List value; if (source.SourceKey == null) { if (source.Children != null) { CollectLeafSources(source.Children, result); } } else if (IsFishingKey(source.SourceKey)) { result.Add(source); } else if (_data.CharacterSpawns.TryGetValue(source.SourceKey, out value) && value.Count > 0) { result.Add(source); } else if (source.Children != null) { CollectLeafSources(source.Children, result); } } } private void ComputeAutoSourceSet(string currentScene) { string currentScene2 = currentScene; _activeSourceKeys.Clear(); foreach (ItemSource allItemSource in _allItemSources) { if (allItemSource.SourceKey == null) { continue; } List value; if (IsFishingKey(allItemSource.SourceKey)) { if (string.Equals(FishingKeyScene(allItemSource.SourceKey), currentScene2, StringComparison.OrdinalIgnoreCase)) { _activeSourceKeys.Add(allItemSource.SourceKey); } } else if (_data.CharacterSpawns.TryGetValue(allItemSource.SourceKey, out value) && value.Exists((SpawnPoint s) => string.Equals(s.Scene, currentScene2, StringComparison.OrdinalIgnoreCase))) { _activeSourceKeys.Add(allItemSource.SourceKey); } } if (_activeSourceKeys.Count == 0 && _allItemSources.Count > 0) { ItemSource itemSource = _allItemSources[0]; if (itemSource.SourceKey != null) { _activeSourceKeys.Add(itemSource.SourceKey); } } } private bool ResolveClosestActiveSource(QuestEntry quest, QuestStep step, string currentScene) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (Vector3)(((??)GetPlayerPosition()) ?? Vector3.zero); SpawnPoint spawnPoint = null; string text = null; string text2 = null; float num = float.MaxValue; foreach (string activeSourceKey in _activeSourceKeys) { if (IsFishingKey(activeSourceKey)) { string a = FishingKeyScene(activeSourceKey); if (string.Equals(a, currentScene, StringComparison.OrdinalIgnoreCase)) { _currentSourceKey = activeSourceKey; Target = MakeTarget(NavigationTarget.Kind.Zone, Vector3.zero, "Fishing", currentScene, quest.DBName, step.Order, activeSourceKey); return true; } } else { if (!_data.CharacterSpawns.TryGetValue(activeSourceKey, out List value)) { continue; } string text3 = null; foreach (ItemSource allItemSource in _allItemSources) { if (string.Equals(allItemSource.SourceKey, activeSourceKey, StringComparison.OrdinalIgnoreCase)) { text3 = allItemSource.Name; break; } } foreach (SpawnPoint item in value) { if (string.Equals(item.Scene, currentScene, StringComparison.OrdinalIgnoreCase)) { float num2 = Vector3.Distance(val, new Vector3(item.X, item.Y, item.Z)); if (num2 < num) { num = num2; spawnPoint = item; text = activeSourceKey; text2 = text3; } } } } } if (spawnPoint == null) { foreach (string activeSourceKey2 in _activeSourceKeys) { if (IsFishingKey(activeSourceKey2)) { string text4 = FishingKeyScene(activeSourceKey2); string text5 = FindZoneKeyBySceneName(text4); if (text5 != null) { return NavigateToZone(text4, "Fishing", activeSourceKey2, quest.DBName, step.Order, currentScene); } } else { if (!_data.CharacterSpawns.TryGetValue(activeSourceKey2, out List value2) || value2.Count == 0) { continue; } spawnPoint = value2[0]; text = activeSourceKey2; foreach (ItemSource allItemSource2 in _allItemSources) { if (string.Equals(allItemSource2.SourceKey, activeSourceKey2, StringComparison.OrdinalIgnoreCase)) { text2 = allItemSource2.Name; break; } } break; } } } if (spawnPoint == null) { return false; } _currentSourceKey = text; string displayName = text2 ?? text ?? step.TargetName ?? step.Description; Target = MakeTarget(NavigationTarget.Kind.Character, new Vector3(spawnPoint.X, spawnPoint.Y, spawnPoint.Z), WithCharacterUnlockText(displayName, text), spawnPoint.Scene, quest.DBName, step.Order, text); return true; } private bool ResolveItemZoneFallback(List sources, QuestEntry quest, QuestStep step, string currentScene) { ItemSource itemSource = FindFirstSourceWithScene(sources); string text = itemSource?.Scene; string text2 = ((text != null) ? FindZoneKeyBySceneName(text) : FindZoneKeyByDisplayName(sources[0].Zone)); if (text2 == null) { return false; } string text3 = null; foreach (KeyValuePair item in _data.ZoneLookup) { if (string.Equals(item.Value.StableKey, text2, StringComparison.OrdinalIgnoreCase)) { text3 = item.Key; break; } } if (text3 == null) { return false; } string displayName = itemSource?.Zone ?? text3; string sourceId = itemSource?.MakeSourceId(); return NavigateToZone(text3, displayName, sourceId, quest.DBName, step.Order, currentScene); } private void UpdateCrossZoneRouting(string currentScene, Vector3 playerPos) { //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) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) if (_cachedZoneLine == null || Vector3.Distance(_lastCrossZoneCalcPos, playerPos) > 10f) { _lastCrossZoneCalcPos = playerPos; ZoneLineEntry zoneLineEntry = null; bool flag = false; if (_pinnedZoneLine != null && string.Equals(_pinnedZoneLine.Scene, currentScene, StringComparison.OrdinalIgnoreCase)) { zoneLineEntry = _pinnedZoneLine; } else { _pinnedZoneLine = null; ZoneGraph.Route route = _zoneGraph.FindRoute(currentScene, Target.Scene); string text = route?.NextHopZoneKey; if (text != null) { zoneLineEntry = (route.IsLocked ? FindClosestZoneLineAny(text, currentScene, playerPos) : FindClosestZoneLine(text, currentScene, playerPos)); flag = route.IsLocked; } } if (zoneLineEntry != _cachedZoneLine) { _cachedZoneLine = zoneLineEntry; if (zoneLineEntry != null) { string displayName = (flag ? ("To: " + zoneLineEntry.DestinationDisplay + "\nRequires: Complete \"" + GetZoneLineLockReason(zoneLineEntry) + "\"") : ("To: " + zoneLineEntry.DestinationDisplay)); ZoneLineWaypoint = MakeTarget(NavigationTarget.Kind.ZoneLine, new Vector3(zoneLineEntry.X, zoneLineEntry.Y, zoneLineEntry.Z), displayName, currentScene, Target.QuestDBName, Target.StepOrder); } else { ZoneLineWaypoint = null; } } } if (ZoneLineWaypoint != null) { UpdateDistanceAndDirection(ZoneLineWaypoint.Position, playerPos); } else { UpdateDistanceAndDirection(Target.Position, playerPos); } } private SpawnPoint PickBestSpawn(List spawns, string currentScene) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Invalid comparison between Unknown and I4 //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Invalid comparison between Unknown and I4 Vector3? playerPosition = GetPlayerPosition(); SpawnPoint spawnPoint = null; float num = float.MaxValue; SpawnPoint spawnPoint2 = null; float num2 = float.MaxValue; SpawnPoint spawnPoint3 = null; float num3 = float.MaxValue; Vector3 val = default(Vector3); foreach (SpawnPoint spawn in spawns) { if (!string.Equals(spawn.Scene, currentScene, StringComparison.OrdinalIgnoreCase)) { continue; } if (!playerPosition.HasValue) { if (spawnPoint == null) { spawnPoint = spawn; } continue; } ((Vector3)(ref val))..ctor(spawn.X, spawn.Y, spawn.Z); float num4 = Vector3.Distance(playerPosition.Value, val); NavMeshPathStatus reachability = GetReachability(playerPosition.Value, val); if ((int)reachability == 0) { if (num4 < num) { num = num4; spawnPoint = spawn; } } else if ((int)reachability == 1) { if (num4 < num2) { num2 = num4; spawnPoint2 = spawn; } } else if (num4 < num3) { num3 = num4; spawnPoint3 = spawn; } } return spawnPoint ?? spawnPoint2 ?? spawnPoint3 ?? spawns[0]; } private bool IsZoneLineAccessible(ZoneLineEntry zl) { if (zl.IsEnabled && (zl.RequiredQuestGroups == null || zl.RequiredQuestGroups.Count == 0)) { return true; } if (zl.RequiredQuestGroups == null || zl.RequiredQuestGroups.Count == 0) { return zl.IsEnabled; } foreach (List requiredQuestGroup in zl.RequiredQuestGroups) { if (requiredQuestGroup.TrueForAll((string q) => _state.IsCompleted(q))) { return true; } } return false; } private string? GetZoneLineLockReason(ZoneLineEntry zl) { if (zl.RequiredQuestGroups == null || zl.RequiredQuestGroups.Count == 0) { return null; } List list = null; foreach (List requiredQuestGroup in zl.RequiredQuestGroups) { List list2 = requiredQuestGroup.FindAll((string q) => !_state.IsCompleted(q)); if (list2.Count == 0) { return null; } if (list == null || list2.Count < list.Count) { list = list2; } } if (list == null) { return null; } List list3 = new List(); foreach (string item in list) { list3.Add(_data.GetByDBName(item)?.DisplayName ?? item); } return string.Join(" and ", list3); } private ZoneLineEntry? FindClosestZoneLine(string destinationZoneKey, string currentScene, Vector3 playerPos) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00bf: Invalid comparison between Unknown and I4 //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Invalid comparison between Unknown and I4 ZoneLineEntry zoneLineEntry = null; float num = float.MaxValue; ZoneLineEntry zoneLineEntry2 = null; float num2 = float.MaxValue; ZoneLineEntry zoneLineEntry3 = null; float num3 = float.MaxValue; Vector3 val = default(Vector3); foreach (ZoneLineEntry zoneLine in _data.ZoneLines) { if (!string.Equals(zoneLine.Scene, currentScene, StringComparison.OrdinalIgnoreCase) || !string.Equals(zoneLine.DestinationZoneKey, destinationZoneKey, StringComparison.OrdinalIgnoreCase) || !IsZoneLineAccessible(zoneLine)) { continue; } ((Vector3)(ref val))..ctor(zoneLine.X, zoneLine.Y, zoneLine.Z); float num4 = Vector3.Distance(playerPos, val); NavMeshPathStatus reachability = GetReachability(playerPos, val); if ((int)reachability == 0) { if (num4 < num) { num = num4; zoneLineEntry = zoneLine; } } else if ((int)reachability == 1) { if (num4 < num2) { num2 = num4; zoneLineEntry2 = zoneLine; } } else if (num4 < num3) { num3 = num4; zoneLineEntry3 = zoneLine; } } return zoneLineEntry ?? zoneLineEntry2 ?? zoneLineEntry3; } private ZoneLineEntry? FindClosestZoneLineAny(string destinationZoneKey, string currentScene, Vector3 playerPos) { //IL_0055: 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) ZoneLineEntry result = null; float num = float.MaxValue; foreach (ZoneLineEntry zoneLine in _data.ZoneLines) { if (string.Equals(zoneLine.Scene, currentScene, StringComparison.OrdinalIgnoreCase) && string.Equals(zoneLine.DestinationZoneKey, destinationZoneKey, StringComparison.OrdinalIgnoreCase)) { float num2 = Vector3.Distance(playerPos, new Vector3(zoneLine.X, zoneLine.Y, zoneLine.Z)); if (num2 < num) { num = num2; result = zoneLine; } } } return result; } private bool HasZoneLineForDestination(string? zoneKey, string currentScene) { if (zoneKey == null) { return false; } foreach (ZoneLineEntry zoneLine in _data.ZoneLines) { if (string.Equals(zoneLine.Scene, currentScene, StringComparison.OrdinalIgnoreCase) && string.Equals(zoneLine.DestinationZoneKey, zoneKey, StringComparison.OrdinalIgnoreCase) && IsZoneLineAccessible(zoneLine)) { return true; } } return false; } private string? FindZoneKeyBySceneName(string sceneName) { ZoneInfo value; return _data.ZoneLookup.TryGetValue(sceneName, out value) ? value.StableKey : null; } private string? FindZoneKeyByDisplayName(string? displayName) { if (displayName == null) { return null; } foreach (KeyValuePair item in _data.ZoneLookup) { if (string.Equals(item.Value.DisplayName, displayName, StringComparison.OrdinalIgnoreCase)) { return item.Value.StableKey; } } return null; } private static ItemSource? FindFirstSourceWithScene(List sources) { foreach (ItemSource source in sources) { if (source.Scene != null) { return source; } if (source.Children != null) { ItemSource itemSource = FindFirstSourceWithScene(source.Children); if (itemSource != null) { return itemSource; } } } return null; } private NavMeshPathStatus GetReachability(Vector3 from, Vector3 to) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_006a: Unknown result type (might be due to invalid IL or missing references) NavMeshHit val = default(NavMeshHit); if (!NavMesh.SamplePosition(from, ref val, 5f, -1)) { return (NavMeshPathStatus)2; } NavMeshHit val2 = default(NavMeshHit); if (!NavMesh.SamplePosition(to, ref val2, 5f, -1)) { return (NavMeshPathStatus)2; } _scratchPath.ClearCorners(); NavMesh.CalculatePath(((NavMeshHit)(ref val)).position, ((NavMeshHit)(ref val2)).position, -1, _scratchPath); return _scratchPath.status; } private void UpdateDistanceAndDirection(Vector3 targetPos, Vector3 playerPos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) Vector3 val = targetPos - playerPos; Distance = ((Vector3)(ref val)).magnitude; Direction = ((Distance > 0.1f) ? ((Vector3)(ref val)).normalized : Vector3.zero); } private static Vector3? GetPlayerPosition() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) PlayerControl playerControl = GameData.PlayerControl; return ((Object)(object)playerControl != (Object)null) ? new Vector3?(((Component)playerControl).transform.position) : null; } private string WithCharacterUnlockText(string displayName, string? targetKey) { if (targetKey == null) { return displayName; } if (!_data.CharacterQuestUnlocks.TryGetValue(targetKey, out List> value)) { return displayName; } List list = null; foreach (List item in value) { List list2 = item.FindAll((string q) => !_state.IsCompleted(q)); if (list2.Count == 0) { return displayName; } if (list == null || list2.Count < list.Count) { list = list2; } } if (list == null) { return displayName; } List list3 = new List(); foreach (string item2 in list) { list3.Add(_data.GetByDBName(item2)?.DisplayName ?? item2); } return displayName + "\nRequires: Complete \"" + string.Join("\" and \"", list3) + "\""; } private HashSet BuildNeededItems(string questDBName) { HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); QuestEntry byDBName = _data.GetByDBName(questDBName); if (byDBName?.RequiredItems == null) { return hashSet; } foreach (RequiredItemInfo requiredItem in byDBName.RequiredItems) { if (_state.CountItem(requiredItem.ItemStableKey) < requiredItem.Quantity) { hashSet.Add(requiredItem.ItemName); } } return hashSet; } private NavigationTarget MakeTarget(NavigationTarget.Kind kind, Vector3 position, string displayName, string scene, string questDBName, int stepOrder, string? sourceId = null) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return new NavigationTarget(kind, position, displayName, scene, questDBName, stepOrder, sourceId, _originQuestDBName, _originStepOrder); } } internal static class NavigationDisplay { internal const float GroundOffset = 0.5f; } public sealed class NavigationTarget { public enum Kind { Character, ZoneLine, Zone, Position } public Kind TargetKind { get; } public Vector3 Position { get; set; } public string DisplayName { get; set; } public string Scene { get; set; } public string? SourceId { get; set; } public string QuestDBName { get; } public int StepOrder { get; } public string OriginQuestDBName { get; } public int OriginStepOrder { get; } public NavigationTarget(Kind targetKind, Vector3 position, string displayName, string scene, string questDBName, int stepOrder, string? sourceId = null, string? originQuestDBName = null, int? originStepOrder = null) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) TargetKind = targetKind; Position = position; DisplayName = displayName; Scene = scene; QuestDBName = questDBName; StepOrder = stepOrder; SourceId = sourceId; OriginQuestDBName = originQuestDBName ?? questDBName; OriginStepOrder = originStepOrder.GetValueOrDefault(stepOrder); } public bool IsCrossZone(string currentScene) { return !string.Equals(Scene, currentScene, StringComparison.OrdinalIgnoreCase); } } public sealed class SpawnTimerTracker { private static readonly FieldInfo? MySpawnPointField = typeof(NPC).GetField("MySpawnPoint", BindingFlags.Instance | BindingFlags.NonPublic); private readonly Dictionary _tracked = new Dictionary(); public IReadOnlyDictionary Tracked => _tracked; public void OnNPCDeath(NPC npc) { SpawnPoint spawnPoint = GetSpawnPoint(npc); if (!((Object)(object)spawnPoint == (Object)null) && !string.IsNullOrEmpty(spawnPoint.ID)) { string stableKey = EntityRegistry.DeriveStableKey(npc, spawnPoint); _tracked[spawnPoint.ID] = new TrackedSpawn(spawnPoint, npc.NPCName, stableKey); } } public void OnNPCSpawn(SpawnPoint sp) { if ((Object)(object)sp != (Object)null && !string.IsNullOrEmpty(sp.ID)) { _tracked.Remove(sp.ID); } } public void Clear() { _tracked.Clear(); } public float? GetRemainingSeconds(SpawnPoint sp) { if ((Object)(object)sp == (Object)null || string.IsNullOrEmpty(sp.ID)) { return null; } if (!_tracked.ContainsKey(sp.ID)) { return null; } float num = 60f * GetSpawnTimeMod(); if (num <= 0f) { return null; } return sp.actualSpawnDelay / num; } public static bool IsNightLocked(SpawnPoint sp) { if (!sp.NightSpawn) { return false; } int hour = GameData.Time.GetHour(); return hour <= 22 && hour >= 4; } public static string FormatTimer(float seconds) { if (seconds <= 0f) { return "~0:00"; } int num = Mathf.CeilToInt(seconds); int num2 = num / 60; int num3 = num % 60; return $"~{num2}:{num3:D2}"; } private static SpawnPoint? GetSpawnPoint(NPC npc) { if (MySpawnPointField == null) { return null; } object? value = MySpawnPointField.GetValue(npc); return (SpawnPoint?)((value is SpawnPoint) ? value : null); } private static float GetSpawnTimeMod() { GameManager gM = GameData.GM; if ((Object)(object)gM == (Object)null) { return 1f; } return gM.SpawnTimeMod; } } public readonly struct TrackedSpawn { public readonly SpawnPoint Point; public readonly string NPCName; public readonly string? StableKey; public TrackedSpawn(SpawnPoint point, string npcName, string? stableKey) { Point = point; NPCName = npcName; StableKey = stableKey; } } public sealed class WorldMarkerSystem { private const float StaticHeightOffset = 2.5f; private const float LiveHeightAboveCollider = 0.8f; private const float CorpseHeightOffset = 1.5f; private readonly GuideData _data; private readonly QuestStateTracker _state; private readonly SpawnPointBridge _bridge; private readonly MarkerPool _pool; private readonly GuideConfig _config; private readonly LootScanner _lootScanner; private readonly List _markers = new List(); private readonly Dictionary _intentIndex = new Dictionary(StringComparer.OrdinalIgnoreCase); private string _lastScene = ""; private bool _enabled; private bool _configDirty; private bool _spawnDirty; private int _lastHour = -1; private int _lastStateVersion = -1; public bool Enabled { get { return _enabled; } set { if (_enabled != value) { _enabled = value; if (value) { _configDirty = true; } else { _pool.DeactivateAll(); } } } } public WorldMarkerSystem(GuideData data, QuestStateTracker state, SpawnPointBridge bridge, LootScanner lootScanner, GuideConfig config) { _data = data; _state = state; _bridge = bridge; _lootScanner = lootScanner; _config = config; _pool = new MarkerPool(); config.MarkerScale.SettingChanged += OnConfigChanged; config.IconSize.SettingChanged += OnConfigChanged; config.SubTextSize.SettingChanged += OnConfigChanged; config.IconYOffset.SettingChanged += OnConfigChanged; config.SubTextYOffset.SettingChanged += OnConfigChanged; } public void Update(string currentScene) { if (!_enabled || (Object)(object)GameData.PlayerControl == (Object)null || !MarkerFonts.IsReady) { return; } int hour = GameData.Time.hour; bool flag = currentScene != _lastScene; bool flag2 = hour != _lastHour; bool flag3 = _state.Version != _lastStateVersion; bool flag4 = flag || flag2 || flag3 || _configDirty || _spawnDirty; if (flag3) { _lastStateVersion = _state.Version; } _configDirty = false; _spawnDirty = false; _lastHour = hour; if (flag4) { _lastScene = currentScene; if (flag) { _bridge.Rebuild(); } RebuildMarkers(currentScene); } UpdateLiveState(currentScene); } private void OnConfigChanged(object sender, EventArgs e) { _configDirty = true; } public void MarkSpawnDirty() { _spawnDirty = true; } public void OnSceneLoaded() { _pool.DeactivateAll(); } public void Destroy() { _config.MarkerScale.SettingChanged -= OnConfigChanged; _config.IconSize.SettingChanged -= OnConfigChanged; _config.SubTextSize.SettingChanged -= OnConfigChanged; _config.IconYOffset.SettingChanged -= OnConfigChanged; _config.SubTextYOffset.SettingChanged -= OnConfigChanged; _pool.Destroy(); } private void RebuildMarkers(string currentScene) { //IL_017a: Unknown result type (might be due to invalid IL or missing references) _markers.Clear(); _intentIndex.Clear(); foreach (QuestEntry item in _data.All) { bool flag = _state.IsActionable(item.DBName); bool flag2 = _state.IsCompleted(item.DBName); bool flag3 = item.Flags?.Repeatable ?? false; if (!flag && (!flag2 || flag3)) { CollectQuestGiverMarkers(item, currentScene, flag3); } if (flag) { CollectTurnInMarkers(item, currentScene, flag3); CollectObjectiveMarkers(item, currentScene); } } CollectLootContainerMarkers(); _pool.SetActiveCount(_markers.Count); for (int i = 0; i < _markers.Count; i++) { MarkerEntry markerEntry = _markers[i]; MarkerInstance markerInstance = _pool.Get(i); markerInstance.Configure(markerEntry.Type, markerEntry.SubText, _config.MarkerScale.Value, _config.IconSize.Value, _config.SubTextSize.Value, _config.IconYOffset.Value, _config.SubTextYOffset.Value); markerInstance.SetPosition(markerEntry.Position); markerInstance.SetActive(active: true); } } private void CollectQuestGiverMarkers(QuestEntry quest, string scene, bool repeatable) { if (quest.Acquisition == null) { return; } if (quest.Prerequisites != null) { foreach (Prerequisite prerequisite in quest.Prerequisites) { if (prerequisite.Item == null) { QuestEntry byStableKey = _data.GetByStableKey(prerequisite.QuestKey); if (byStableKey == null || !_state.IsCompleted(byStableKey.DBName)) { return; } } } } foreach (AcquisitionSource item in quest.Acquisition) { if (!(item.SourceType != "character") && item.SourceStableKey != null) { MarkerType questType = (repeatable ? MarkerType.QuestGiverRepeat : MarkerType.QuestGiver); string questSubText = ((item.Keyword != null) ? ("Say '" + item.Keyword + "'") : "Talk to"); string displayName = item.SourceName ?? quest.DisplayName; EmitPerSpawnMarkers(item.SourceStableKey, scene, displayName, questType, questSubText); } } } private void CollectTurnInMarkers(QuestEntry quest, string scene, bool repeatable) { if (quest.Completion == null) { return; } bool flag = HasAllRequiredItems(quest); foreach (CompletionSource item in quest.Completion) { if (!(item.SourceType != "character") && item.SourceStableKey != null) { MarkerType questType = ((!flag) ? MarkerType.TurnInPending : (repeatable ? MarkerType.TurnInRepeatReady : MarkerType.TurnInReady)); string questSubText = FormatTurnInText(quest, item); string displayName = item.SourceName ?? quest.DisplayName; EmitPerSpawnMarkers(item.SourceStableKey, scene, displayName, questType, questSubText); } } } private void CollectObjectiveMarkers(QuestEntry quest, string scene) { if (quest.Steps == null) { return; } int currentStepIndex = StepProgress.GetCurrentStepIndex(quest, _state, _data); if (currentStepIndex < quest.Steps.Count) { QuestStep questStep = quest.Steps[currentStepIndex]; (QuestStep? Step, QuestEntry? Quest) tuple = StepProgress.ResolveActiveStep(questStep, quest, _state, _data); QuestStep item = tuple.Step; QuestEntry item2 = tuple.Quest; bool flag = item != questStep && item2 != null; EmitStepTargetMarker(questStep, scene); if (flag) { EmitStepTargetMarker(item, scene); } EmitItemSourceMarkers(quest, scene); if (flag) { EmitItemSourceMarkers(item2, scene); } } } private void EmitStepTargetMarker(QuestStep step, string scene) { if (step.TargetKey != null && step.TargetType == "character") { EmitPerSpawnMarkers(step.TargetKey, scene, step.TargetName ?? step.Description, MarkerType.Objective, FormatStepActionText(step)); } } private void EmitItemSourceMarkers(QuestEntry quest, string scene) { if (quest.RequiredItems == null) { return; } foreach (RequiredItemInfo requiredItem in quest.RequiredItems) { int num = _state.CountItem(requiredItem.ItemStableKey); if (num >= requiredItem.Quantity) { continue; } string questSubText = $"{num}/{requiredItem.Quantity} {requiredItem.ItemName}"; if (requiredItem.Sources == null) { continue; } foreach (ItemSource source in requiredItem.Sources) { if (source.SourceKey != null) { EmitPerSpawnMarkers(source.SourceKey, scene, source.Name ?? requiredItem.ItemName, MarkerType.Objective, questSubText); } } } } private void EmitPerSpawnMarkers(string stableKey, string scene, string displayName, MarkerType questType, string? questSubText) { //IL_0063: 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_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_007c: 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) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) if (!_data.CharacterSpawns.TryGetValue(stableKey, out List value)) { return; } foreach (SpawnPoint item in value) { if (string.Equals(item.Scene, scene, StringComparison.OrdinalIgnoreCase)) { Vector3 val = new Vector3(item.X, item.Y, item.Z) + Vector3.up * 2.5f; string spawnKey = $"{stableKey}@{item.X:F2},{item.Y:F2},{item.Z:F2}"; SpawnPointBridge.SpawnInfo state = _bridge.GetState(item.X, item.Y, item.Z, displayName); Vector3 position = (((Object)(object)state.LiveNPC != (Object)null) ? GetMarkerPosition(state.LiveNPC) : val); switch (state.State) { case SpawnPointBridge.SpawnState.Alive: TryAddMarker(spawnKey, questType, displayName, questSubText, position, stableKey, state.LiveSpawnPoint, state.LiveNPC, state.LiveMiningNode, questType, questSubText); break; case SpawnPointBridge.SpawnState.Dead: case SpawnPointBridge.SpawnState.Mined: { string text = ((state.RespawnSeconds > 0f) ? SpawnTimerTracker.FormatTimer(state.RespawnSeconds) : "Respawning..."); TryAddMarker(spawnKey, MarkerType.DeadSpawn, displayName, displayName + "\n" + text, position, null, state.LiveSpawnPoint, state.LiveNPC, state.LiveMiningNode, questType, questSubText); break; } case SpawnPointBridge.SpawnState.NightLocked: { int hour = GameData.Time.hour; int min = GameData.Time.min; TryAddMarker(spawnKey, MarkerType.NightSpawn, displayName, $"{displayName}\nNight only (23:00-04:00)\nNow: {hour}:{min:D2}", position, null, state.LiveSpawnPoint, state.LiveNPC, state.LiveMiningNode, questType, questSubText); break; } case SpawnPointBridge.SpawnState.DirectlyPlacedDead: TryAddMarker(spawnKey, MarkerType.ZoneReentry, displayName, displayName + "\nRe-enter zone to respawn", position, null); break; } } } } private void CollectLootContainerMarkers() { //IL_0021: 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: 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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) foreach (LootScanner.LootContainer container in _lootScanner.Containers) { Vector3 position = container.Position + Vector3.up * 1.5f; string key = $"loot@{container.InstanceId}"; string subText = FormatLootContainerText(container); _intentIndex[key] = _markers.Count; _markers.Add(new MarkerEntry { Position = position, Type = MarkerType.Objective, DisplayName = container.DisplayName, TargetKey = null, SubText = subText }); } } private string FormatLootContainerText(LootScanner.LootContainer container) { string text = null; int num = 0; foreach (string matchingItem in container.MatchingItems) { num++; if (text != null) { continue; } int num2 = 0; int num3 = 1; foreach (QuestEntry item in _data.All) { if (!_state.IsActionable(item.DBName) || item.RequiredItems == null) { continue; } foreach (RequiredItemInfo requiredItem in item.RequiredItems) { if (string.Equals(requiredItem.ItemName, matchingItem, StringComparison.OrdinalIgnoreCase)) { num2 = _state.CountItem(requiredItem.ItemStableKey); num3 = requiredItem.Quantity; break; } } } text = $"Loot: {num2}/{num3} {matchingItem}"; } if (num > 1) { text += $" (+{num - 1} more)"; } return text ?? container.DisplayName; } private void UpdateLiveState(string currentScene) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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) Camera val = CameraCache.Get(); if ((Object)(object)val == (Object)null) { return; } PlayerControl playerControl = GameData.PlayerControl; Vector3? val2 = ((playerControl != null) ? new Vector3?(((Component)playerControl).transform.position) : null); for (int i = 0; i < _markers.Count; i++) { MarkerEntry m = _markers[i]; MarkerInstance markerInstance = _pool.Get(i); if (m.TargetKey != null) { NPC val3 = m.LiveSpawnPoint?.SpawnedNPC ?? m.TrackedNPC; if ((Object)(object)val3 != (Object)null) { m.Position = GetMarkerPosition(val3); } } if ((Object)(object)m.LiveMiningNode != (Object)null) { UpdateMiningMarkerState(ref m, markerInstance, m.LiveMiningNode); } else if ((Object)(object)m.LiveSpawnPoint != (Object)null) { UpdateSpawnMarkerState(ref m, markerInstance); } markerInstance.SetPosition(m.Position); if (val2.HasValue) { float alpha = Vector3.Distance(val2.Value, m.Position); markerInstance.SetAlpha(alpha); } _markers[i] = m; } } private void UpdateSpawnMarkerState(ref MarkerEntry m, MarkerInstance instance) { //IL_00d1: 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) SpawnPoint liveSpawnPoint = m.LiveSpawnPoint; bool flag = SpawnPointBridge.IsExpectedNPCAlive(liveSpawnPoint, m.DisplayName); if (flag && m.Type != m.QuestType) { m.Type = m.QuestType; m.SubText = m.QuestSubText; m.TargetKey = "live"; instance.Configure(m.Type, m.SubText, _config.MarkerScale.Value, _config.IconSize.Value, _config.SubTextSize.Value, _config.IconYOffset.Value, _config.SubTextYOffset.Value); if ((Object)(object)liveSpawnPoint.SpawnedNPC != (Object)null) { m.Position = GetMarkerPosition(liveSpawnPoint.SpawnedNPC); } } else if (!flag && m.Type == m.QuestType) { m.Type = MarkerType.DeadSpawn; m.TargetKey = null; string text = FormatRespawnTimer(liveSpawnPoint); m.SubText = m.DisplayName + "\n" + text; instance.Configure(m.Type, m.SubText, _config.MarkerScale.Value, _config.IconSize.Value, _config.SubTextSize.Value, _config.IconYOffset.Value, _config.SubTextYOffset.Value); } else if (m.Type == MarkerType.DeadSpawn) { string text2 = FormatRespawnTimer(liveSpawnPoint); m.SubText = m.DisplayName + "\n" + text2; instance.UpdateSubText(m.SubText); } } private void UpdateMiningMarkerState(ref MarkerEntry m, MarkerInstance instance, MiningNode node) { bool flag = SpawnPointBridge.IsMiningNodeMined(node); if (!flag && m.Type != m.QuestType) { m.Type = m.QuestType; m.SubText = m.QuestSubText; m.TargetKey = "live"; instance.Configure(m.Type, m.SubText, _config.MarkerScale.Value, _config.IconSize.Value, _config.SubTextSize.Value, _config.IconYOffset.Value, _config.SubTextYOffset.Value); } else if (flag && m.Type == m.QuestType) { m.Type = MarkerType.DeadSpawn; m.TargetKey = null; float miningNodeRespawnSeconds = SpawnPointBridge.GetMiningNodeRespawnSeconds(node); string text = ((miningNodeRespawnSeconds > 0f) ? SpawnTimerTracker.FormatTimer(miningNodeRespawnSeconds) : "Regenerating..."); m.SubText = m.DisplayName + "\n" + text; instance.Configure(m.Type, m.SubText, _config.MarkerScale.Value, _config.IconSize.Value, _config.SubTextSize.Value, _config.IconYOffset.Value, _config.SubTextYOffset.Value); } else if (flag && m.Type == MarkerType.DeadSpawn) { float miningNodeRespawnSeconds2 = SpawnPointBridge.GetMiningNodeRespawnSeconds(node); string text2 = ((miningNodeRespawnSeconds2 > 0f) ? SpawnTimerTracker.FormatTimer(miningNodeRespawnSeconds2) : "Regenerating..."); m.SubText = m.DisplayName + "\n" + text2; instance.UpdateSubText(m.SubText); } } private static string FormatRespawnTimer(SpawnPoint sp) { float num = (((Object)(object)GameData.GM != (Object)null) ? GameData.GM.SpawnTimeMod : 1f); float num2 = 60f * num; float num3 = ((num2 > 0f) ? (sp.actualSpawnDelay / num2) : 0f); return (num3 > 0f) ? SpawnTimerTracker.FormatTimer(num3) : "Respawning..."; } private static string FormatTurnInText(QuestEntry quest, CompletionSource comp) { if (quest.RequiredItems == null || quest.RequiredItems.Count == 0) { if (comp.Keyword != null) { return "Say '" + comp.Keyword + "'"; } return "Talk to"; } int num = 0; string text = null; foreach (RequiredItemInfo requiredItem in quest.RequiredItems) { if (requiredItem.OrGroup == null) { num++; if (text == null) { text = requiredItem.ItemName; } } } switch (num) { case 0: if (comp.Keyword != null) { return "Say '" + comp.Keyword + "'"; } return "Talk to"; case 1: return "Give " + text; default: return $"Give {num} items"; } } private static string FormatStepActionText(QuestStep step) { string action = step.Action; if (1 == 0) { } string result = action switch { "talk" => (step.Keyword == null) ? "Talk to" : ("Say '" + step.Keyword + "'"), "shout" => (step.Keyword == null) ? "Shout near" : ("Shout '" + step.Keyword + "'"), "kill" => (!(step.Quantity > 1)) ? "Kill" : $"Kill ({step.Quantity})", _ => "Talk to", }; if (1 == 0) { } return result; } private void TryAddMarker(string spawnKey, MarkerType type, string displayName, string? subText, Vector3 position, string? targetKey, SpawnPoint? liveSpawnPoint = null, NPC? trackedNPC = null, MiningNode? liveMiningNode = null, MarkerType questType = MarkerType.TurnInReady, string? questSubText = null) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (_intentIndex.TryGetValue(spawnKey, out var value)) { MarkerEntry markerEntry = _markers[value]; if (type < markerEntry.Type) { _markers[value] = new MarkerEntry { Position = markerEntry.Position, Type = type, DisplayName = displayName, TargetKey = targetKey, SubText = subText, LiveSpawnPoint = liveSpawnPoint, TrackedNPC = trackedNPC, LiveMiningNode = liveMiningNode, QuestType = questType, QuestSubText = questSubText }; } } else { _intentIndex[spawnKey] = _markers.Count; _markers.Add(new MarkerEntry { Position = position, Type = type, DisplayName = displayName, TargetKey = targetKey, SubText = subText, LiveSpawnPoint = liveSpawnPoint, TrackedNPC = trackedNPC, LiveMiningNode = liveMiningNode, QuestType = questType, QuestSubText = questSubText }); } } private static Vector3 GetMarkerPosition(NPC npc) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_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) //IL_005e: Unknown result type (might be due to invalid IL or missing references) CapsuleCollider component = ((Component)npc).GetComponent(); float num = (((Object)(object)component != (Object)null) ? (component.height * Mathf.Max(((Component)npc).transform.localScale.y, 1f) + 0.8f) : 2.5f); return ((Component)npc).transform.position + Vector3.up * num; } private bool HasAllRequiredItems(QuestEntry quest) { if (quest.RequiredItems == null || quest.RequiredItems.Count == 0) { return false; } foreach (RequiredItemInfo requiredItem in quest.RequiredItems) { if (_state.CountItem(requiredItem.ItemStableKey) < requiredItem.Quantity) { return false; } } return true; } } public struct MarkerEntry { public Vector3 Position; public MarkerType Type; public string DisplayName; public string? TargetKey; public string? SubText; public SpawnPoint? LiveSpawnPoint; public NPC? TrackedNPC; public MiningNode? LiveMiningNode; public MarkerType QuestType; public string? QuestSubText; } public sealed class ZoneGraph { public sealed class Route { public string NextHopZoneKey { get; } public bool IsLocked { get; } public IReadOnlyList Path { get; } public Route(string nextHopZoneKey, bool isLocked, IReadOnlyList path) { NextHopZoneKey = nextHopZoneKey; IsLocked = isLocked; Path = path; } } private readonly GuideData _data; private readonly QuestStateTracker _state; private readonly Dictionary> _adj = new Dictionary>(); private readonly Dictionary _zoneKeyToScene = new Dictionary(StringComparer.OrdinalIgnoreCase); public ZoneGraph(GuideData data, QuestStateTracker state) { _data = data; _state = state; foreach (KeyValuePair item in data.ZoneLookup) { _zoneKeyToScene[item.Value.StableKey] = item.Key; } Rebuild(); } public void Rebuild() { _adj.Clear(); foreach (ZoneLineEntry zoneLine in _data.ZoneLines) { if (string.IsNullOrEmpty(zoneLine.DestinationZoneKey) || !_zoneKeyToScene.TryGetValue(zoneLine.DestinationZoneKey, out string value)) { continue; } bool flag = IsZoneLineAccessible(zoneLine); if (!_adj.TryGetValue(zoneLine.Scene, out List<(string, string, bool)> value2)) { value2 = new List<(string, string, bool)>(); _adj[zoneLine.Scene] = value2; } bool flag2 = false; for (int i = 0; i < value2.Count; i++) { if (string.Equals(value2[i].Item1, value, StringComparison.OrdinalIgnoreCase)) { if (flag && !value2[i].Item3) { value2[i] = (value, zoneLine.DestinationZoneKey, true); } flag2 = true; break; } } if (!flag2) { value2.Add((value, zoneLine.DestinationZoneKey, flag)); } } } public Route? FindRoute(string currentScene, string targetScene) { if (string.Equals(currentScene, targetScene, StringComparison.OrdinalIgnoreCase)) { return null; } List list = BFS(currentScene, targetScene, accessibleOnly: true); if (list != null) { string toScene = list[1]; string nextHopZoneKey = FindZoneKeyForEdge(currentScene, toScene, accessibleOnly: true); return new Route(nextHopZoneKey, isLocked: false, list); } List list2 = BFS(currentScene, targetScene, accessibleOnly: false); if (list2 != null) { string toScene2 = list2[1]; string nextHopZoneKey2 = FindZoneKeyForEdge(currentScene, toScene2, accessibleOnly: false); bool isLocked = !HasAccessibleEdge(currentScene, toScene2); return new Route(nextHopZoneKey2, isLocked, list2); } return null; } private List? BFS(string start, string goal, bool accessibleOnly) { Queue<(string, List)> queue = new Queue<(string, List)>(); HashSet hashSet = new HashSet(StringComparer.OrdinalIgnoreCase); queue.Enqueue((start, new List { start })); hashSet.Add(start); while (queue.Count > 0) { var (key, collection) = queue.Dequeue(); if (!_adj.TryGetValue(key, out List<(string, string, bool)> value)) { continue; } foreach (var (text, _, flag) in value) { if ((!accessibleOnly || flag) && !hashSet.Contains(text)) { List list = new List(collection) { text }; if (string.Equals(text, goal, StringComparison.OrdinalIgnoreCase)) { return list; } hashSet.Add(text); queue.Enqueue((text, list)); } } } return null; } private string? FindZoneKeyForEdge(string fromScene, string toScene, bool accessibleOnly) { if (!_adj.TryGetValue(fromScene, out List<(string, string, bool)> value)) { return null; } foreach (var (a, result, flag) in value) { if (string.Equals(a, toScene, StringComparison.OrdinalIgnoreCase) && (!accessibleOnly || flag)) { return result; } } return null; } private bool HasAccessibleEdge(string fromScene, string toScene) { if (!_adj.TryGetValue(fromScene, out List<(string, string, bool)> value)) { return false; } foreach (var item in value) { var (a, _, _) = item; if (item.Item3 && string.Equals(a, toScene, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private bool IsZoneLineAccessible(ZoneLineEntry zl) { if (zl.IsEnabled && (zl.RequiredQuestGroups == null || zl.RequiredQuestGroups.Count == 0)) { return true; } if (zl.RequiredQuestGroups == null || zl.RequiredQuestGroups.Count == 0) { return zl.IsEnabled; } foreach (List requiredQuestGroup in zl.RequiredQuestGroups) { if (requiredQuestGroup.TrueForAll((string q) => _state.IsCompleted(q))) { return true; } } return false; } } } namespace AdventureGuide.Diagnostics { public static class DebugAPI { internal static GuideData? Data { get; set; } internal static QuestStateTracker? State { get; set; } internal static FilterState? Filter { get; set; } internal static NavigationController? Nav { get; set; } internal static EntityRegistry? Entities { get; set; } internal static GroundPathRenderer? GroundPath { get; set; } public static string DumpState() { if (State == null) { return "Not initialized"; } return "Zone: " + State.CurrentZone + "\n" + $"Active quests: {State.ActiveQuests.Count}\n" + $"Completed quests: {State.CompletedQuests.Count}\n" + "Selected: " + (State.SelectedQuestDBName ?? "(none)") + "\n" + $"Filter: {Filter?.FilterMode}\n" + $"Sort: {Filter?.SortMode}\n" + "Search: '" + Filter?.SearchText + "'\nZone filter: " + (Filter?.ZoneFilter ?? "(all)"); } public static string DumpNav() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) if (Nav == null) { return "Not initialized"; } if (Nav.Target == null) { return "No active navigation target"; } NavigationTarget target = Nav.Target; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Target: " + target.DisplayName); stringBuilder.AppendLine($" Kind: {target.TargetKind}"); stringBuilder.AppendLine(" Scene: " + target.Scene); stringBuilder.AppendLine($" Position: {target.Position}"); stringBuilder.AppendLine(" SourceId: " + (target.SourceId ?? "(none)")); stringBuilder.AppendLine($" Quest: {target.QuestDBName} step {target.StepOrder}"); stringBuilder.AppendLine($" Origin: {target.OriginQuestDBName} step {target.OriginStepOrder}"); string currentScene = State?.CurrentZone ?? ""; stringBuilder.AppendLine($" CrossZone: {target.IsCrossZone(currentScene)}"); stringBuilder.AppendLine($" Distance: {Nav.Distance:F1}"); if (Nav.ZoneLineWaypoint != null) { NavigationTarget zoneLineWaypoint = Nav.ZoneLineWaypoint; stringBuilder.AppendLine("ZoneLineWaypoint: " + zoneLineWaypoint.DisplayName); stringBuilder.AppendLine(" Scene: " + zoneLineWaypoint.Scene); stringBuilder.AppendLine($" Position: {zoneLineWaypoint.Position}"); } else { stringBuilder.AppendLine("ZoneLineWaypoint: (none)"); } if (GroundPath != null) { stringBuilder.AppendLine($"GroundPath: enabled={GroundPath.Enabled}"); } stringBuilder.AppendLine($"ManualOverride: {Nav.IsManualSourceOverride}"); return stringBuilder.ToString(); } public static string DumpEntities(string? displayName = null) { if (Entities == null) { return "Not initialized"; } if (displayName != null) { string text = (displayName.StartsWith("character:", StringComparison.OrdinalIgnoreCase) ? displayName : ("character:" + displayName.Trim().ToLowerInvariant())); int num = Entities.CountAlive(text); return $"{text}: {num} alive"; } return "Pass a character name or stable key: DumpEntities(\"NPC Name\")"; } public static string DumpQuest(string name) { if (Data == null) { return "Not initialized"; } QuestEntry questEntry = FindQuest(name); if (questEntry == null) { return "Quest '" + name + "' not found (searched DB name and display name)"; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("DBName: " + questEntry.DBName); stringBuilder.AppendLine("Name: " + questEntry.DisplayName); stringBuilder.AppendLine("Type: " + questEntry.QuestType); stringBuilder.AppendLine("Zone: " + questEntry.ZoneContext); stringBuilder.AppendLine($"Level: {questEntry.LevelEstimate?.Recommended}"); stringBuilder.AppendLine($"Active: {State?.IsActive(questEntry.DBName)}"); stringBuilder.AppendLine($"Completed: {State?.IsCompleted(questEntry.DBName)}"); if (questEntry.Steps != null) { stringBuilder.AppendLine($"Steps ({questEntry.Steps.Count}):"); foreach (QuestStep step in questEntry.Steps) { stringBuilder.AppendLine($" {step.Order}. [{step.Action}] {step.Description} (target_key={step.TargetKey})"); } } if (questEntry.Rewards != null) { stringBuilder.AppendLine($"Rewards: {questEntry.Rewards.XP} XP, {questEntry.Rewards.Gold} Gold, {questEntry.Rewards.ItemName}"); } return stringBuilder.ToString(); } public static string DumpZoneQuests() { if (Data == null || State == null) { return "Not initialized"; } string currentZone = State.CurrentZone; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Quests in zone '" + currentZone + "':"); foreach (QuestEntry item in Data.All) { if (item.ZoneContext != null && item.ZoneContext.Equals(currentZone, StringComparison.OrdinalIgnoreCase)) { string text = (State.IsCompleted(item.DBName) ? "done" : (State.IsActive(item.DBName) ? "active" : "available")); stringBuilder.AppendLine(" [" + text + "] " + item.DisplayName + " (" + item.DBName + ")"); } } return stringBuilder.ToString(); } public static string ResetQuest(string name) { if (Data == null || State == null) { return "Not initialized"; } QuestEntry questEntry = FindQuest(name); if (questEntry == null) { return "Quest '" + name + "' not found"; } bool flag = GameData.HasQuest.Remove(questEntry.DBName); bool flag2 = GameData.CompletedQuests.Remove(questEntry.DBName); State.SyncFromGameData(); Nav?.OnGameStateChanged(State.CurrentZone); string text = (flag ? "active" : (flag2 ? "completed" : "not in quest log")); return "Reset '" + questEntry.DisplayName + "' (was " + text + ")"; } public static string TestRoute(string fromScene, string toScene) { if (Nav == null) { return "Not initialized"; } if (!(typeof(NavigationController).GetField("_zoneGraph", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(Nav) is ZoneGraph zoneGraph)) { return "ZoneGraph not found"; } ZoneGraph.Route route = zoneGraph.FindRoute(fromScene, toScene); if (route == null) { return "No route from " + fromScene + " to " + toScene; } return string.Format("NextHop={0} IsLocked={1} Path={2}", route.NextHopZoneKey, route.IsLocked, string.Join(" -> ", route.Path)); } private static QuestEntry? FindQuest(string name) { if (Data == null) { return null; } QuestEntry byDBName = Data.GetByDBName(name); if (byDBName != null) { return byDBName; } foreach (QuestEntry item in Data.All) { if (string.Equals(item.DisplayName, name, StringComparison.OrdinalIgnoreCase)) { return item; } } return null; } } } namespace AdventureGuide.Data { public sealed class GuideData { private readonly Dictionary _byDBName = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _byStableKey = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly List _all = new List(); private readonly Dictionary _displayToScene = new Dictionary(StringComparer.OrdinalIgnoreCase); public IReadOnlyList All => _all; public int Count => _all.Count; public IReadOnlyDictionary ZoneLookup { get; private set; } = new Dictionary(); public IReadOnlyDictionary> CharacterSpawns { get; private set; } = new Dictionary>(); public IReadOnlyList ZoneLines { get; private set; } = Array.Empty(); public IReadOnlyList ChainGroups { get; private set; } = Array.Empty(); public IReadOnlyDictionary>> CharacterQuestUnlocks { get; private set; } = new Dictionary>>(); public QuestEntry? GetByDBName(string dbName) { QuestEntry value; return _byDBName.TryGetValue(dbName, out value) ? value : null; } public QuestEntry? GetByStableKey(string stableKey) { QuestEntry value; return _byStableKey.TryGetValue(stableKey, out value) ? value : null; } public string? GetZoneDisplayName(string sceneName) { ZoneInfo value; return ZoneLookup.TryGetValue(sceneName, out value) ? value.DisplayName : null; } public string? GetSceneName(string displayName) { string value; return _displayToScene.TryGetValue(displayName, out value) ? value : null; } public static GuideData Load(ManualLogSource log) { GuideData guideData = new GuideData(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); using Stream stream = executingAssembly.GetManifestResourceStream("AdventureGuide.quest-guide.json"); if (stream == null) { log.LogError((object)"Failed to load embedded quest-guide.json"); return guideData; } using StreamReader streamReader = new StreamReader(stream); string text = streamReader.ReadToEnd(); GuideWrapper guideWrapper = JsonConvert.DeserializeObject(text); if (guideWrapper == null) { log.LogError((object)"Failed to deserialize quest-guide.json"); return guideData; } if (guideWrapper.Quests != null) { foreach (QuestEntry quest in guideWrapper.Quests) { guideData._all.Add(quest); guideData._byDBName[quest.DBName] = quest; guideData._byStableKey[quest.StableKey] = quest; } } guideData.ZoneLookup = guideWrapper.ZoneLookup ?? new Dictionary(); foreach (var (value, zoneInfo2) in guideData.ZoneLookup) { guideData._displayToScene[zoneInfo2.DisplayName] = value; } guideData.CharacterSpawns = guideWrapper.CharacterSpawns ?? new Dictionary>(); guideData.ZoneLines = guideWrapper.ZoneLines ?? new List(); guideData.ChainGroups = guideWrapper.ChainGroups ?? new List(); guideData.CharacterQuestUnlocks = guideWrapper.CharacterQuestUnlocks ?? new Dictionary>>(); return guideData; } public int MergeUnknownQuests() { QuestDB questDB = GameData.QuestDB; if ((Object)(object)questDB == (Object)null || questDB.QuestDatabase == null) { return -1; } int num = 0; Quest[] questDatabase = questDB.QuestDatabase; foreach (Quest val in questDatabase) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(val.DBName) && !_byDBName.ContainsKey(val.DBName)) { QuestEntry questEntry = new QuestEntry { DBName = val.DBName, DisplayName = (val.QuestName ?? val.DBName), Description = val.QuestDesc }; _all.Add(questEntry); _byDBName[questEntry.DBName] = questEntry; num++; } } return num; } } internal sealed class GuideWrapper { [JsonProperty("_version")] public int Version { get; set; } [JsonProperty("_zone_lookup")] public Dictionary? ZoneLookup { get; set; } [JsonProperty("_character_spawns")] public Dictionary>? CharacterSpawns { get; set; } [JsonProperty("_zone_lines")] public List? ZoneLines { get; set; } [JsonProperty("_chain_groups")] public List? ChainGroups { get; set; } [JsonProperty("_character_quest_unlocks")] public Dictionary>>? CharacterQuestUnlocks { get; set; } [JsonProperty("quests")] public List? Quests { get; set; } } public sealed class ZoneInfo { [JsonProperty("display_name")] public string DisplayName { get; set; } = ""; [JsonProperty("stable_key")] public string StableKey { get; set; } = ""; [JsonProperty("level_min")] public int? LevelMin { get; set; } [JsonProperty("level_max")] public int? LevelMax { get; set; } [JsonProperty("level_median")] public int? LevelMedian { get; set; } } public sealed class SpawnPoint { [JsonProperty("scene")] public string Scene { get; set; } = ""; [JsonProperty("x")] public float X { get; set; } [JsonProperty("y")] public float Y { get; set; } [JsonProperty("z")] public float Z { get; set; } [JsonProperty("night_spawn")] public bool NightSpawn { get; set; } } public sealed class ZoneLineEntry { [JsonProperty("scene")] public string Scene { get; set; } = ""; [JsonProperty("x")] public float X { get; set; } [JsonProperty("y")] public float Y { get; set; } [JsonProperty("z")] public float Z { get; set; } [JsonProperty("is_enabled")] public bool IsEnabled { get; set; } = true; [JsonProperty("destination_zone_key")] public string DestinationZoneKey { get; set; } = ""; [JsonProperty("destination_display")] public string DestinationDisplay { get; set; } = ""; [JsonProperty("landing_x")] public float? LandingX { get; set; } [JsonProperty("landing_y")] public float? LandingY { get; set; } [JsonProperty("landing_z")] public float? LandingZ { get; set; } [JsonProperty("required_quest_groups")] public List>? RequiredQuestGroups { get; set; } } public sealed class ChainGroupEntry { [JsonProperty("name")] public string Name { get; set; } = ""; [JsonProperty("quests")] public List Quests { get; set; } = new List(); } public sealed class QuestEntry { [JsonProperty("db_name")] public string DBName { get; set; } = ""; [JsonProperty("stable_key")] public string StableKey { get; set; } = ""; [JsonProperty("display_name")] public string DisplayName { get; set; } = ""; [JsonProperty("description")] public string? Description { get; set; } [JsonProperty("quest_type")] public string? QuestType { get; set; } [JsonProperty("zone_context")] public string? ZoneContext { get; set; } [JsonProperty("difficulty")] public string? Difficulty { get; set; } [JsonProperty("estimated_time")] public string? EstimatedTime { get; set; } [JsonProperty("tags")] public List? Tags { get; set; } [JsonProperty("acquisition")] public List? Acquisition { get; set; } [JsonProperty("prerequisites")] public List? Prerequisites { get; set; } [JsonProperty("steps")] public List? Steps { get; set; } [JsonProperty("required_items")] public List? RequiredItems { get; set; } [JsonProperty("completion")] public List? Completion { get; set; } [JsonProperty("rewards")] public RewardInfo? Rewards { get; set; } [JsonProperty("chain")] public List? Chain { get; set; } [JsonProperty("flags")] public QuestFlags? Flags { get; set; } [JsonProperty("level_estimate")] public LevelEstimate? LevelEstimate { get; set; } [JsonProperty("acceptance")] public string? Acceptance { get; set; } [JsonIgnore] public bool IsImplicit => string.Equals(Acceptance, "implicit", StringComparison.OrdinalIgnoreCase); [JsonIgnore] public bool HasSteps { get { List steps = Steps; return steps != null && steps.Count > 0; } } } public sealed class QuestStep { [JsonProperty("order")] public int Order { get; set; } [JsonProperty("action")] public string Action { get; set; } = ""; [JsonProperty("description")] public string Description { get; set; } = ""; [JsonProperty("target_name")] public string? TargetName { get; set; } [JsonProperty("target_type")] public string? TargetType { get; set; } [JsonProperty("target_key")] public string? TargetKey { get; set; } [JsonProperty("quantity")] public int? Quantity { get; set; } [JsonProperty("zone_name")] public string? ZoneName { get; set; } [JsonProperty("keyword")] public string? Keyword { get; set; } [JsonProperty("tips")] public List? Tips { get; set; } [JsonProperty("or_group")] public string? OrGroup { get; set; } [JsonProperty("level_estimate")] public LevelEstimate? LevelEstimate { get; set; } } public sealed class AcquisitionSource { [JsonProperty("method")] public string Method { get; set; } = ""; [JsonProperty("source_name")] public string? SourceName { get; set; } [JsonProperty("source_type")] public string? SourceType { get; set; } [JsonProperty("source_stable_key")] public string? SourceStableKey { get; set; } [JsonProperty("zone_name")] public string? ZoneName { get; set; } [JsonProperty("keyword")] public string? Keyword { get; set; } [JsonProperty("note")] public string? Note { get; set; } } public sealed class CompletionSource { [JsonProperty("method")] public string Method { get; set; } = ""; [JsonProperty("source_name")] public string? SourceName { get; set; } [JsonProperty("source_type")] public string? SourceType { get; set; } [JsonProperty("source_stable_key")] public string? SourceStableKey { get; set; } [JsonProperty("zone_name")] public string? ZoneName { get; set; } [JsonProperty("keyword")] public string? Keyword { get; set; } [JsonProperty("note")] public string? Note { get; set; } } public sealed class ItemSource { [JsonProperty("type")] public string Type { get; set; } = ""; [JsonProperty("name")] public string? Name { get; set; } [JsonProperty("zone")] public string? Zone { get; set; } [JsonProperty("scene")] public string? Scene { get; set; } [JsonProperty("level")] public int? Level { get; set; } [JsonProperty("source_key")] public string? SourceKey { get; set; } [JsonProperty("quest_key")] public string? QuestKey { get; set; } [JsonProperty("node_count")] public int? NodeCount { get; set; } [JsonProperty("spawn_count")] public int? SpawnCount { get; set; } [JsonProperty("recipe_key")] public string? RecipeKey { get; set; } [JsonProperty("children")] public List? Children { get; set; } public string? MakeSourceId() { return SourceKey ?? ((Scene != null) ? (Type + ":" + Scene) : null); } } public sealed class RequiredItemInfo { [JsonProperty("item_name")] public string ItemName { get; set; } = ""; [JsonProperty("item_stable_key")] public string ItemStableKey { get; set; } = ""; [JsonProperty("quantity")] public int Quantity { get; set; } = 1; [JsonProperty("or_group")] public string? OrGroup { get; set; } [JsonProperty("sources")] public List? Sources { get; set; } } public sealed class Prerequisite { [JsonProperty("type")] public string Type { get; set; } = "quest"; [JsonProperty("quest_key")] public string QuestKey { get; set; } = ""; [JsonProperty("quest_name")] public string QuestName { get; set; } = ""; [JsonProperty("item")] public string? Item { get; set; } } public sealed class LevelEstimate { [JsonProperty("recommended")] public int? Recommended { get; set; } [JsonProperty("factors")] public List? Factors { get; set; } } public sealed class LevelFactor { [JsonProperty("source")] public string Source { get; set; } = ""; [JsonProperty("name")] public string? Name { get; set; } [JsonProperty("level")] public int Level { get; set; } } public sealed class RewardInfo { [JsonProperty("xp")] public int XP { get; set; } [JsonProperty("gold")] public int Gold { get; set; } [JsonProperty("item_name")] public string? ItemName { get; set; } [JsonProperty("next_quest_name")] public string? NextQuestName { get; set; } [JsonProperty("next_quest_stable_key")] public string? NextQuestStableKey { get; set; } [JsonProperty("also_completes")] public List? AlsoCompletes { get; set; } [JsonProperty("vendor_unlock")] public VendorUnlockInfo? VendorUnlock { get; set; } [JsonProperty("unlocked_zone_lines")] public List? UnlockedZoneLines { get; set; } [JsonProperty("unlocked_characters")] public List? UnlockedCharacters { get; set; } [JsonProperty("achievements")] public List? Achievements { get; set; } [JsonProperty("faction_effects")] public List? FactionEffects { get; set; } } public sealed class VendorUnlockInfo { [JsonProperty("item_name")] public string ItemName { get; set; } = ""; [JsonProperty("vendor_name")] public string VendorName { get; set; } = ""; } public sealed class UnlockedZoneLine { [JsonProperty("from_zone")] public string FromZone { get; set; } = ""; [JsonProperty("to_zone")] public string ToZone { get; set; } = ""; [JsonProperty("co_requirements")] public List? CoRequirements { get; set; } } public sealed class UnlockedCharacter { [JsonProperty("name")] public string Name { get; set; } = ""; [JsonProperty("zone")] public string? Zone { get; set; } } public sealed class FactionEffect { [JsonProperty("faction_name")] public string FactionName { get; set; } = ""; [JsonProperty("amount")] public int Amount { get; set; } } public sealed class ChainLink { [JsonProperty("quest_name")] public string QuestName { get; set; } = ""; [JsonProperty("quest_stable_key")] public string QuestStableKey { get; set; } = ""; [JsonProperty("relationship")] public string Relationship { get; set; } = ""; } public sealed class QuestFlags { [JsonProperty("repeatable")] public bool Repeatable { get; set; } [JsonProperty("disabled")] public bool Disabled { get; set; } [JsonProperty("disabled_text")] public string? DisabledText { get; set; } [JsonProperty("kill_turn_in_holder")] public bool KillTurnInHolder { get; set; } [JsonProperty("destroy_turn_in_holder")] public bool DestroyTurnInHolder { get; set; } [JsonProperty("once_per_spawn_instance")] public bool OncePerSpawnInstance { get; set; } } public static class StepSceneResolver { public static string? ResolveScene(QuestEntry quest, QuestStep step, GuideData data) { if (step.ZoneName != null) { string sceneName = data.GetSceneName(step.ZoneName); if (sceneName != null) { return sceneName; } } if (step.TargetKey != null && data.CharacterSpawns.TryGetValue(step.TargetKey, out List value) && value.Count > 0) { return value[0].Scene; } string text = FindFirstSourceKey(quest, step); if (text != null) { if (text.StartsWith("fishing:", StringComparison.Ordinal)) { return text.Substring("fishing:".Length); } if (data.CharacterSpawns.TryGetValue(text, out List value2) && value2.Count > 0) { return value2[0].Scene; } } return null; } public static string? FindFirstSourceKey(QuestEntry quest, QuestStep step) { QuestStep step2 = step; if (step2.TargetType != "item" || quest.RequiredItems == null) { return null; } RequiredItemInfo requiredItemInfo = quest.RequiredItems.Find((RequiredItemInfo ri) => string.Equals(ri.ItemName, step2.TargetName, StringComparison.OrdinalIgnoreCase)); if (requiredItemInfo?.Sources == null) { return null; } return FindFirstLeafSourceKey(requiredItemInfo.Sources); } private static string? FindFirstLeafSourceKey(List sources) { foreach (ItemSource source in sources) { if (source.Type == "quest_reward") { List children = source.Children; if (children != null && children.Count > 0) { return FindFirstLeafSourceKey(source.Children); } } if (source.SourceKey != null) { return source.SourceKey; } if (source.Children != null) { string text = FindFirstLeafSourceKey(source.Children); if (text != null) { return text; } } } return null; } public static bool HasSourceInScene(QuestEntry quest, QuestStep step, GuideData data, string scene) { QuestStep step2 = step; if (step2.TargetType != "item" || quest.RequiredItems == null) { string text = ResolveScene(quest, step2, data); return text != null && string.Equals(text, scene, StringComparison.OrdinalIgnoreCase); } RequiredItemInfo requiredItemInfo = quest.RequiredItems.Find((RequiredItemInfo ri) => string.Equals(ri.ItemName, step2.TargetName, StringComparison.OrdinalIgnoreCase)); if (requiredItemInfo?.Sources == null) { return false; } return AnySourceInScene(requiredItemInfo.Sources, data, scene); } private static bool AnySourceInScene(List sources, GuideData data, string scene) { foreach (ItemSource source in sources) { if (source.Type == "quest_reward") { List children = source.Children; if (children != null && children.Count > 0) { if (AnySourceInScene(source.Children, data, scene)) { return true; } continue; } } if (source.SourceKey != null) { List value; if (source.SourceKey.StartsWith("fishing:", StringComparison.Ordinal)) { string a = source.SourceKey.Substring("fishing:".Length); if (string.Equals(a, scene, StringComparison.OrdinalIgnoreCase)) { return true; } } else if (data.CharacterSpawns.TryGetValue(source.SourceKey, out value)) { foreach (SpawnPoint item in value) { if (string.Equals(item.Scene, scene, StringComparison.OrdinalIgnoreCase)) { return true; } } } } if (source.Children != null && AnySourceInScene(source.Children, data, scene)) { return true; } } return false; } } } namespace AdventureGuide.Config { public sealed class GuideConfig { private static readonly object Hidden = new { Browsable = false }; internal float ResolvedUiScale { get; set; } = 1f; internal bool LayoutResetRequested { get; set; } public ConfigEntry ToggleKey { get; } public ConfigEntry ReplaceQuestLog { get; } public ConfigEntry UiScale { get; } public ConfigEntry HistoryMaxSize { get; } public ConfigEntry ResetWindowLayout { get; } public ConfigEntry ShowArrow { get; } public ConfigEntry ShowGroundPath { get; } public ConfigEntry GroundPathToggleKey { get; } public ConfigEntry ShowWorldMarkers { get; } public ConfigEntry MarkerScale { get; } public ConfigEntry IconSize { get; } public ConfigEntry SubTextSize { get; } public ConfigEntry SubTextYOffset { get; } public ConfigEntry IconYOffset { get; } public ConfigEntry TrackerEnabled { get; } public ConfigEntry TrackerToggleKey { get; } public ConfigEntry TrackerAutoTrack { get; } public ConfigEntry TrackerSortMode { get; } public ConfigEntry TrackerBackgroundOpacity { get; } public ConfigEntry FilterMode { get; } public ConfigEntry SortMode { get; } public ConfigEntry ZoneFilter { get; } public ConfigFile File { get; } public GuideConfig(ConfigFile config) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Expected O, but got Unknown //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Expected O, but got Unknown //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Expected O, but got Unknown //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Expected O, but got Unknown //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Expected O, but got Unknown //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Expected O, but got Unknown File = config; ToggleKey = config.Bind("General", "ToggleKey", (KeyCode)108, "Key to toggle the Adventure Guide window"); ReplaceQuestLog = config.Bind("General", "ReplaceQuestLog", false, "If true, pressing J opens Adventure Guide instead of the game's Quest Log"); UiScale = config.Bind("General", "UiScale", -1f, new ConfigDescription("UI scale factor. Affects font size and element spacing. Set to -1 to auto-detect from screen resolution.", (AcceptableValueBase)(object)new AcceptableValueRange(-1f, 4f), Array.Empty())); HistoryMaxSize = config.Bind("General", "HistoryMaxSize", 100, new ConfigDescription("Maximum number of pages in navigation history", (AcceptableValueBase)(object)new AcceptableValueRange(10, 500), Array.Empty())); ResetWindowLayout = config.Bind("General", "ResetWindowLayout", false, "Toggle to reset all window positions and sizes to defaults."); ShowArrow = config.Bind("Navigation", "ShowArrow", true, "Show directional arrow pointing toward navigation target"); ShowGroundPath = config.Bind("Navigation", "ShowGroundPath", false, "Show ground path from player to navigation target (uses NavMesh pathfinding)"); GroundPathToggleKey = config.Bind("Navigation", "GroundPathToggleKey", (KeyCode)112, "Key to toggle the ground path overlay"); ShowWorldMarkers = config.Bind("World Markers", "Enabled", true, "Show floating quest markers above NPCs (!, ?, objective icons). Replaces the game's built-in markers when enabled."); MarkerScale = config.Bind("World Markers", "Scale", 1f, new ConfigDescription("Overall scale of world markers", (AcceptableValueBase)(object)new AcceptableValueRange(0.05f, 2f), Array.Empty())); IconSize = config.Bind("World Markers", "IconSize", 7f, new ConfigDescription("Font size of the marker icon glyph", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 20f), Array.Empty())); SubTextSize = config.Bind("World Markers", "SubTextSize", 3.5f, new ConfigDescription("Font size of the sub-text label", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); SubTextYOffset = config.Bind("World Markers", "SubTextYOffset", -1f, new ConfigDescription("Y offset of sub-text relative to icon (negative = below)", (AcceptableValueBase)(object)new AcceptableValueRange(-5f, 5f), Array.Empty())); IconYOffset = config.Bind("World Markers", "IconYOffset", 1f, new ConfigDescription("Y offset of icon relative to marker root", (AcceptableValueBase)(object)new AcceptableValueRange(-5f, 5f), Array.Empty())); TrackerEnabled = config.Bind("Tracker", "Enabled", true, "Enable the quest tracker overlay. When disabled, auto-tracking and the tracker window are inactive."); TrackerToggleKey = config.Bind("Tracker", "ToggleKey", (KeyCode)107, "Key to toggle the quest tracker overlay"); TrackerAutoTrack = config.Bind("Tracker", "AutoTrack", true, "Automatically track newly accepted quests"); TrackerSortMode = config.Bind("Tracker", "SortMode", "Proximity", "Sort order: Proximity, Level, or Alphabetical"); TrackerBackgroundOpacity = config.Bind("Tracker", "BackgroundOpacity", 0.4f, new ConfigDescription("Opacity of the tracker background when not hovered (0 = fully transparent, 1 = opaque)", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); FilterMode = Bind(config, "_State", "FilterMode", QuestFilterMode.Active); SortMode = Bind(config, "_State", "SortMode", QuestSortMode.ByLevel); ZoneFilter = Bind(config, "_State", "ZoneFilter", ""); } private static ConfigEntry Bind(ConfigFile config, string section, string key, T defaultValue) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown return config.Bind(section, key, defaultValue, new ConfigDescription("Auto-managed by Adventure Guide", (AcceptableValueBase)null, new object[1] { Hidden })); } public ConfigEntry BindPerCharacter(int slotIndex, string key, T defaultValue) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown return File.Bind("_Character", $"{key}_Slot{slotIndex}", defaultValue, new ConfigDescription($"Per-character state for slot {slotIndex} (auto-managed)", (AcceptableValueBase)null, new object[1] { Hidden })); } } }