using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppSystem;
using Il2CppSystem.Collections;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Nivalis;
using Nivalis.Navigation;
using Nivalis.UI;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Hvizeu")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Shows only pinned journal quests on the gameplay HUD, compass and map.")]
[assembly: AssemblyFileVersion("1.1.14.0")]
[assembly: AssemblyInformationalVersion("1.1.14")]
[assembly: AssemblyProduct("NivalisTrackedQuestsHUD")]
[assembly: AssemblyTitle("NivalisTrackedQuestsHUD")]
[assembly: AssemblyVersion("1.1.14.0")]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[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]
[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]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NativeIntegerAttribute : Attribute
{
public readonly bool[] TransformFlags;
public NativeIntegerAttribute()
{
TransformFlags = new bool[1] { true };
}
public NativeIntegerAttribute(bool[] P_0)
{
TransformFlags = P_0;
}
}
}
namespace NivalisTrackedQuestsHUD
{
[HarmonyPatch(typeof(NavigationUI), "LateUpdate")]
internal static class CompassFilter
{
internal readonly struct Scope
{
internal readonly NavigationManager Manager;
internal readonly List<CompassMarkerData> Original;
internal readonly List<CompassMarkerData> Projection;
internal Scope(NavigationManager manager, List<CompassMarkerData> original, List<CompassMarkerData> projection)
{
Manager = manager;
Original = original;
Projection = projection;
}
}
private static List<CompassMarkerData>? buffer;
private static readonly List<CompassMarkerData> visibleMarkers = new List<CompassMarkerData>();
private static Scope? active;
private static Scope? unresolved;
private static bool failed;
private static bool reported;
private static readonly Dictionary<nint, bool> questVisibility = new Dictionary<IntPtr, bool>();
private const int QuestCacheLimit = 512;
[HarmonyPrefix]
internal static void Prefix(NavigationUI __instance, out Scope? __state)
{
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: Invalid comparison between Unknown and I4
//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
//IL_01ee: Expected O, but got Unknown
__state = null;
if (failed || active.HasValue || unresolved.HasValue)
{
return;
}
try
{
if (ApplicationState.IsQuitting || !Plugin.TrackedCompassOnly.Value || !Singleton<NavigationManager>.InstanceExist() || !Singleton<QuestManager>.InstanceExist())
{
return;
}
NavigationManager instance = Singleton<NavigationManager>.Instance;
QuestManager instance2 = Singleton<QuestManager>.Instance;
if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null)
{
return;
}
List<CompassMarkerData> markers = instance._markers;
if (markers == null)
{
return;
}
int count = markers.Count;
for (int i = 0; i < count; i++)
{
CompassMarkerData val = markers[i];
if (val == null)
{
continue;
}
Quest quest = val.Quest;
if ((Object)(object)quest == (Object)null)
{
if ((int)val.Type != 1)
{
visibleMarkers.Add(val);
}
continue;
}
IntPtr pointer = ((Il2CppObjectBase)quest).Pointer;
if (!questVisibility.TryGetValue(pointer, out var value))
{
RuntimeQuest quest2 = instance2.GetQuest(quest);
value = quest2 != null && quest2.IsActive && quest2.Pinned;
if (questVisibility.Count < 512)
{
questVisibility.Add(pointer, value);
}
}
if (value)
{
visibleMarkers.Add(val);
}
}
if (visibleMarkers.Count == count)
{
return;
}
if (buffer == null)
{
buffer = new List<CompassMarkerData>();
}
foreach (CompassMarkerData visibleMarker in visibleMarkers)
{
buffer.Add(visibleMarker);
}
__state = new Scope(instance, markers, buffer);
active = __state;
instance._markers = buffer;
if (!reported)
{
reported = true;
ManualLogSource modLog = Plugin.ModLog;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(68, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Compass filter active: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(markers.Count);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" registered markers, ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(buffer.Count);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" displayed; panel flag=");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>(((UIPanel)__instance).IsVisible);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
}
modLog.LogInfo(val2);
}
}
catch (Exception error)
{
Fault("Compass filtering failed; native rendering remains available and filtering is disabled until restart.", error);
if (__state.HasValue)
{
Scope? _state = __state;
__state = null;
Finalizer(_state);
}
else
{
buffer = null;
}
}
finally
{
questVisibility.Clear();
visibleMarkers.Clear();
}
}
[HarmonyFinalizer]
internal static void Finalizer(Scope? __state)
{
if (!__state.HasValue)
{
return;
}
Scope valueOrDefault = __state.GetValueOrDefault();
active = null;
unresolved = valueOrDefault;
for (int i = 0; i < 4; i++)
{
try
{
if ((Object)(object)valueOrDefault.Manager != (Object)null)
{
List<CompassMarkerData> markers = valueOrDefault.Manager._markers;
if (markers != null && ((Il2CppObjectBase)markers).Pointer == ((Il2CppObjectBase)valueOrDefault.Projection).Pointer)
{
valueOrDefault.Manager._markers = valueOrDefault.Original;
}
}
}
catch (Exception error)
{
Fault("Compass registry restoration failed; filtering is disabled until restart.", error);
if (i == 3)
{
Report("Compass registry restoration stopped after four attempts. The unresolved registry references are retained; restart the game before relying on tracked-only compass markers. Last error:", error);
break;
}
continue;
}
unresolved = null;
try
{
valueOrDefault.Projection.Clear();
break;
}
catch (Exception error2)
{
buffer = null;
Fault("Compass projection cleanup failed; filtering is disabled until restart.", error2);
break;
}
}
}
private static void Fault(string message, Exception error)
{
bool num = !failed;
failed = true;
if (num)
{
Report(message, error);
}
}
private static void Report(string message, Exception error)
{
try
{
Plugin.ModLog.LogError((object)(message + " " + error));
}
catch
{
}
}
}
[HarmonyPatch(typeof(ActiveJournalEntriesUi), "Refresh")]
internal static class HudRefreshPatch
{
private sealed class HiddenState
{
internal readonly List<GameObject> Rows = new List<GameObject>();
internal float? Alpha;
}
private static (int pinned, int hidden, int business)? lastCounts;
private static readonly Dictionary<int, HiddenState> hiddenStates = new Dictionary<int, HiddenState>();
internal static void RefreshVisible()
{
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Expected O, but got Unknown
if (ApplicationState.IsQuitting)
{
return;
}
try
{
foreach (ActiveJournalEntriesUi item in Object.FindObjectsOfType<ActiveJournalEntriesUi>(true))
{
if ((Object)(object)item != (Object)null)
{
item.Refresh();
}
}
}
catch (Exception ex)
{
ManualLogSource modLog = Plugin.ModLog;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(48, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Could not refresh business reminder visibility: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<Exception>(ex);
}
modLog.LogError(val);
}
}
[HarmonyPrefix]
internal static bool Prefix(ActiveJournalEntriesUi __instance, bool __runOriginal = true)
{
if (!__runOriginal)
{
return false;
}
if (CanSkipRefresh(__instance))
{
if (__instance.entriesGroup.alpha != 0f)
{
int instanceID = ((Object)__instance).GetInstanceID();
if (!hiddenStates.TryGetValue(instanceID, out HiddenState value))
{
value = new HiddenState();
}
HideEmptyGroup(__instance, value);
}
return false;
}
RestoreHiddenState(__instance);
return true;
}
private static bool CanSkipRefresh(ActiveJournalEntriesUi ui)
{
if (ApplicationState.IsQuitting || !((UIPanel)ui).IsVisible || !Plugin.HideBusinessReminders.Value || (Object)(object)ui.questList == (Object)null || (Object)(object)ui.venueQuestList == (Object)null || (Object)(object)ui.entriesGroup == (Object)null || !Singleton<QuestManager>.InstanceExist())
{
return false;
}
QuestManager instance = Singleton<QuestManager>.Instance;
if ((Object)(object)instance == (Object)null)
{
return false;
}
IEnumerable<RuntimeQuest> activeQuestsWithActiveObjectives = instance.ActiveQuestsWithActiveObjectives;
if (activeQuestsWithActiveObjectives == null)
{
return false;
}
IEnumerator<RuntimeQuest> enumerator = activeQuestsWithActiveObjectives.GetEnumerator();
try
{
IEnumerator val = ((Il2CppObjectBase)enumerator).Cast<IEnumerator>();
while (val.MoveNext())
{
RuntimeQuest current = enumerator.Current;
if (current != null && current.Pinned)
{
return false;
}
}
return true;
}
finally
{
((Il2CppObjectBase)enumerator).Cast<IDisposable>().Dispose();
}
}
private static void RestoreHiddenState(ActiveJournalEntriesUi __instance)
{
if (!hiddenStates.Remove(((Object)__instance).GetInstanceID(), out HiddenState value))
{
return;
}
foreach (GameObject row in value.Rows)
{
if ((Object)(object)row != (Object)null)
{
row.SetActive(true);
}
}
float? alpha = value.Alpha;
if (alpha.HasValue)
{
float valueOrDefault = alpha.GetValueOrDefault();
if ((Object)(object)__instance.entriesGroup != (Object)null && __instance.entriesGroup.alpha == 0f)
{
__instance.entriesGroup.alpha = valueOrDefault;
}
}
}
internal static void Forget(ActiveJournalEntriesUi ui)
{
hiddenStates.Remove(((Object)ui).GetInstanceID());
}
private static void HideEmptyGroup(ActiveJournalEntriesUi ui, HiddenState state)
{
if (ui.entriesGroup.alpha != 0f)
{
state.Alpha = ui.entriesGroup.alpha;
ui.entriesGroup.alpha = 0f;
}
if (state.Rows.Count > 0 || state.Alpha.HasValue)
{
hiddenStates[((Object)ui).GetInstanceID()] = state;
}
}
[HarmonyPostfix]
[HarmonyPriority(0)]
internal static void Postfix(ActiveJournalEntriesUi __instance, bool __runOriginal)
{
//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
//IL_01f3: Expected O, but got Unknown
if (ApplicationState.IsQuitting || !((UIPanel)__instance).IsVisible || (Object)(object)__instance.entriesGroup == (Object)null)
{
return;
}
if (!__runOriginal)
{
if (__instance.entriesGroup.alpha != 0f && CanSkipRefresh(__instance))
{
if (!hiddenStates.TryGetValue(((Object)__instance).GetInstanceID(), out HiddenState value))
{
value = new HiddenState();
}
HideEmptyGroup(__instance, value);
}
return;
}
int num = 0;
int num2 = 0;
ItemListUI questList = __instance.questList;
int i = 0;
for (int displayedCount = questList.DisplayedCount; i < displayedCount; i++)
{
ActiveJournalEntryItem obj = ((Il2CppObjectBase)questList.GetItem(i)).Cast<ActiveJournalEntryItem>();
bool pinned = obj._quest.Pinned;
GameObject gameObject = obj.GameObject;
if (gameObject.activeSelf != pinned)
{
gameObject.SetActive(pinned);
}
if (pinned)
{
num++;
}
else
{
num2++;
}
}
int num3 = 0;
HiddenState hiddenState = new HiddenState();
ItemListUI venueQuestList = __instance.venueQuestList;
int j = 0;
for (int displayedCount2 = venueQuestList.DisplayedCount; j < displayedCount2; j++)
{
GameObject gameObject2 = venueQuestList.GetItem(j).GameObject;
if (Plugin.HideBusinessReminders.Value && gameObject2.activeSelf)
{
hiddenState.Rows.Add(gameObject2);
gameObject2.SetActive(false);
}
if (gameObject2.activeSelf)
{
num3++;
}
}
if (num + num3 == 0)
{
HideEmptyGroup(__instance, hiddenState);
}
else if (hiddenState.Rows.Count > 0)
{
hiddenStates[((Object)__instance).GetInstanceID()] = hiddenState;
}
LayoutRebuilder.ForceRebuildLayoutImmediate(__instance.entryParent);
(int, int, int) tuple = (num, num2, num3);
(int, int, int) tuple2 = tuple;
(int, int, int)? tuple3 = lastCounts;
if (tuple3.HasValue)
{
(int, int, int) valueOrDefault = tuple3.GetValueOrDefault();
if (tuple2.Item1 == valueOrDefault.Item1 && tuple2.Item2 == valueOrDefault.Item2 && tuple2.Item3 == valueOrDefault.Item3)
{
return;
}
}
lastCounts = tuple;
ManualLogSource modLog = Plugin.ModLog;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(88, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("HUD filtered: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" pinned quest(s), ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num2);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" untracked row(s) hidden, ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num3);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" business reminder(s) visible.");
}
modLog.LogInfo(val);
}
}
[HarmonyPatch(typeof(ActiveJournalEntriesUi), "ShowAnimated")]
internal static class HudShowPatch
{
private static void Postfix(ActiveJournalEntriesUi __instance)
{
if (!ApplicationState.IsQuitting && ((UIPanel)__instance).IsVisible)
{
__instance.Refresh();
}
}
}
[HarmonyPatch(typeof(ActiveJournalEntriesUi), "OnDestroy")]
internal static class HudDestroyPatch
{
private static void Prefix(ActiveJournalEntriesUi __instance)
{
HudRefreshPatch.Forget(__instance);
}
}
internal static class MapFilter
{
internal sealed class Scope
{
internal readonly Scope? Previous;
internal readonly List<List<RuntimeQuest>> Projections = new List<List<RuntimeQuest>>();
internal Scope(Scope? previous)
{
Previous = previous;
}
}
[HarmonyPatch(typeof(QuestManager), "get_ActiveQuestsWithActiveObjectives")]
internal static class VisibleQuests
{
internal static void Postfix(ref IEnumerable<RuntimeQuest> __result)
{
if (active == null || failed || __result == null)
{
return;
}
try
{
List<RuntimeQuest> val = new List<RuntimeQuest>();
active.Projections.Add(val);
IEnumerator<RuntimeQuest> enumerator = __result.GetEnumerator();
try
{
IEnumerator val2 = ((Il2CppObjectBase)enumerator).Cast<IEnumerator>();
while (val2.MoveNext())
{
RuntimeQuest current = enumerator.Current;
if (current != null && current.Pinned)
{
val.Add(current);
}
}
}
finally
{
((Il2CppObjectBase)enumerator).Cast<IDisposable>().Dispose();
}
__result = ((Il2CppObjectBase)val).Cast<IEnumerable<RuntimeQuest>>();
}
catch (Exception ex)
{
failed = true;
Plugin.ModLog.LogError((object)("Tracked map filtering disabled after an error; native map contents remain available: " + ex));
}
}
}
private static Scope? active;
private static bool failed;
internal static void Begin(out Scope? state)
{
state = null;
if (!failed && Plugin.TrackedMapOnly.Value)
{
active = (state = new Scope(active));
}
}
internal static Exception? End(Exception? error, Scope? state)
{
if (state == null)
{
return error;
}
active = state.Previous;
try
{
foreach (List<RuntimeQuest> projection in state.Projections)
{
projection.Clear();
}
}
catch (Exception ex)
{
failed = true;
Plugin.ModLog.LogError((object)("Tracked map projection cleanup failed; filtering is disabled: " + ex));
}
finally
{
state.Projections.Clear();
}
return error;
}
}
[HarmonyPatch(typeof(MapTile), "OnShow")]
internal static class MapTileFilter
{
private static void Prefix(out MapFilter.Scope? __state)
{
MapFilter.Begin(out __state);
}
private static Exception? Finalizer(Exception? __exception, MapFilter.Scope? __state)
{
return MapFilter.End(__exception, __state);
}
}
[HarmonyPatch(typeof(MapTileDetailsDisplay), "Show")]
internal static class MapDetailsFilter
{
private static void Prefix(out MapFilter.Scope? __state)
{
MapFilter.Begin(out __state);
}
private static Exception? Finalizer(Exception? __exception, MapFilter.Scope? __state)
{
return MapFilter.End(__exception, __state);
}
}
[BepInPlugin("hvizeu.nivalis.trackedquestshud", "Nivalis Tracked Quests HUD", "1.1.14")]
[BepInProcess("Nivalis Nights.exe")]
public sealed class Plugin : BasePlugin
{
internal static ManualLogSource ModLog;
internal static ConfigEntry<bool> HideBusinessReminders;
internal static ConfigEntry<bool> TrackedCompassOnly;
internal static ConfigEntry<bool> TrackedMapOnly;
public override void Load()
{
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Expected O, but got Unknown
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Expected O, but got Unknown
ModLog = ((BasePlugin)this).Log;
HideBusinessReminders = ((BasePlugin)this).Config.Bind<bool>("HUD", "HideBusinessReminders", true, "Hide automatic venue setup/restocking reminders, which have no journal pin toggle. Applies after saving.");
TrackedCompassOnly = ((BasePlugin)this).Config.Bind<bool>("Compass", "TrackedQuestsOnly", true, "Show only pinned quest markers on the compass. Ordinary shops, travel and location markers remain visible.");
TrackedMapOnly = ((BasePlugin)this).Config.Bind<bool>("Map", "TrackedQuestsOnly", true, "Show only tracked quests on the map and in the selected area's quest list. Shops, boats, homes and travel markers stay visible. Reopen the map after changing this.");
Harmony val = new Harmony("hvizeu.nivalis.trackedquestshud");
try
{
val.PatchAll(typeof(Plugin).Assembly);
}
catch
{
val.UnpatchSelf();
throw;
}
HideBusinessReminders.SettingChanged += delegate
{
HudRefreshPatch.RefreshVisible();
};
ManualLogSource log = ((BasePlugin)this).Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(136, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Tracked Quests HUD 1.1.14 loaded (Steam build 25738165 bindings). Hide business reminders: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>(HideBusinessReminders.Value);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("; tracked-only compass: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>(TrackedCompassOnly.Value);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("; tracked-only map: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<bool>(TrackedMapOnly.Value);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(".");
}
log.LogInfo(val2);
}
}
}