using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon;
using Pigeon.Movement;
using Pigeon.UI;
using Sparroh.UI;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("BacklogImprovements")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BacklogImprovements")]
[assembly: AssemblyTitle("BacklogImprovements")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
public static class BacklogUI
{
private sealed class WindowState
{
public DirectiveWindow Window;
public GameObject Root;
public UIButton EditButton;
public UIButton ClearButton;
public UIButton PageButton;
public UIButton SingleButton;
public UIButton CancelButton;
public bool RerollSelecting;
public readonly List<GameObject> RerollOverlays = new List<GameObject>();
}
private static readonly FieldInfo DirectivesField = AccessTools.Field(typeof(DirectiveWindow), "directives");
private static readonly FieldInfo IsAnimatingField = AccessTools.Field(typeof(DirectiveWindow), "isAnimatingPage");
private static readonly FieldInfo DirectiveField = AccessTools.Field(typeof(DirectiveButton), "directive");
private static readonly Dictionary<int, WindowState> States = new Dictionary<int, WindowState>();
private const float BarLeftAnchor = 0.12f;
private const float CompactFontSize = 13f;
private const float MainButtonMinWidth = 120f;
private const float ButtonHeight = 32f;
private const float BarWidth = 720f;
private const float BarHeight = 40f;
private const float BarBottomPad = 18f;
private const float ButtonGap = 4f;
private const float LabelPad = 8f;
private const float TextWidthPad = 24f;
public static bool IsPathEditing => PathLogic.IsEditing;
public static bool IsRerollSelecting
{
get
{
foreach (KeyValuePair<int, WindowState> state in States)
{
if (state.Value.RerollSelecting)
{
return true;
}
}
return false;
}
}
public static bool IsAnySelectionMode
{
get
{
if (!IsPathEditing)
{
return IsRerollSelecting;
}
return true;
}
}
public static void OnWindowOpened(DirectiveWindow window)
{
if ((Object)(object)window == (Object)null)
{
return;
}
FreePages.ApplyFreeNextPage(window);
bool flag = BacklogImprovementsPlugin.EnablePreselect?.Value ?? true;
bool flag2 = BacklogImprovementsPlugin.EnableReroll?.Value ?? true;
if (!flag && !flag2)
{
return;
}
int instanceID = ((Object)window).GetInstanceID();
if (States.TryGetValue(instanceID, out var value) && (Object)(object)value.Root != (Object)null)
{
value.Window = window;
ExitPathEdit(value, activateNext: false, refreshWindow: false);
ExitRerollSelection(value);
RefreshAll(value);
if (flag)
{
PathVisualizer.Refresh(window);
}
return;
}
WindowState windowState = BuildUi(window, flag, flag2);
if (windowState != null)
{
States[instanceID] = windowState;
RefreshAll(windowState);
if (flag)
{
PathVisualizer.Refresh(window);
}
}
}
public static void OnWindowClosed(DirectiveWindow window)
{
if ((Object)(object)window == (Object)null)
{
return;
}
int instanceID = ((Object)window).GetInstanceID();
if (States.TryGetValue(instanceID, out var value))
{
if (PathLogic.IsEditing)
{
PathLogic.SetEditing(editing: false);
}
PathVisualizer.Clear(window);
DestroyState(value);
States.Remove(instanceID);
}
}
public static void OnDirectivesRefreshed(DirectiveWindow window)
{
if ((Object)(object)window == (Object)null)
{
return;
}
FreePages.ApplyFreeNextPage(window);
if (!States.TryGetValue(((Object)window).GetInstanceID(), out var value))
{
return;
}
value.Window = window;
RefreshAll(value);
ConfigEntry<bool> enablePreselect = BacklogImprovementsPlugin.EnablePreselect;
if (enablePreselect == null || enablePreselect.Value)
{
PathVisualizer.Refresh(window);
if (!PathLogic.IsEditing)
{
PathLogic.TryAutoClaim(window);
}
}
if (value.RerollSelecting)
{
RebuildRerollOverlays(value);
}
}
public static void CleanupAll()
{
PathLogic.SetEditing(editing: false);
foreach (KeyValuePair<int, WindowState> state in States)
{
DestroyState(state.Value);
}
States.Clear();
PathVisualizer.CleanupAll();
}
public static bool TryHandleDirectiveClick(DirectiveButton button)
{
if ((Object)(object)button == (Object)null)
{
return false;
}
if (PathLogic.IsEditing)
{
return TryHandlePathClick(button);
}
if (IsRerollSelecting)
{
return TryHandleRerollClick(button);
}
return false;
}
private static bool TryHandlePathClick(DirectiveButton button)
{
WindowState windowState = FindStateForButton(button);
if (windowState == null)
{
return false;
}
if (IsAnimating(windowState.Window))
{
return true;
}
object? obj = DirectiveField?.GetValue(button);
DirectiveInstance val = (DirectiveInstance)((obj is DirectiveInstance) ? obj : null);
int num = PathLogic.IndexOf(val);
if (num < 0)
{
return true;
}
if (val != null && val.IsComplete && val.HasClaimedRewards)
{
UIDialog.Alert("Cannot Select", "That directive is already finished.", (Action)null, "OK");
return true;
}
PathStore.ToggleSelection(PathStore.CurrentPage, num);
RefreshAll(windowState);
PathVisualizer.Refresh(windowState.Window);
DirectiveWindow window = windowState.Window;
if (window != null)
{
window.SetupDirectives(false);
}
return true;
}
private static bool TryHandleRerollClick(DirectiveButton button)
{
WindowState state = FindStateForButton(button);
if (state == null || !state.RerollSelecting)
{
return false;
}
if (IsAnimating(state.Window))
{
return true;
}
object? obj = DirectiveField?.GetValue(button);
DirectiveInstance val = (DirectiveInstance)((obj is DirectiveInstance) ? obj : null);
int index = RerollLogic.IndexOf(val);
if (index < 0 || !RerollLogic.IsEligible(val))
{
UIDialog.Alert("Cannot Reroll", "Only not-started directives can be rerolled.", (Action)null, "OK");
return true;
}
int singleRerollCost = RerollLogic.GetSingleRerollCost();
string text = val.GetTitle();
if (string.IsNullOrEmpty(text))
{
text = "this directive";
}
UIDialog.Confirm("Reroll Directive", $"Reroll {text} for {singleRerollCost} gats?", (Action)delegate
{
if (RerollLogic.TryRerollSingle(index, out var error))
{
ExitRerollSelection(state);
DirectiveWindow window = state.Window;
if (window != null)
{
window.SetupDirectives(true);
}
RefreshAll(state);
PlayRerollSound();
}
else
{
UIDialog.Alert("Reroll Failed", error ?? "Unknown error.", (Action)null, "OK");
}
}, (Action)null, $"Pay {singleRerollCost}", "Cancel");
return true;
}
private static WindowState FindStateForButton(DirectiveButton button)
{
DirectiveWindow componentInParent = ((Component)button).GetComponentInParent<DirectiveWindow>();
if ((Object)(object)componentInParent != (Object)null && States.TryGetValue(((Object)componentInParent).GetInstanceID(), out var value))
{
return value;
}
using (Dictionary<int, WindowState>.Enumerator enumerator = States.GetEnumerator())
{
if (enumerator.MoveNext())
{
return enumerator.Current.Value;
}
}
return null;
}
private static WindowState BuildUi(DirectiveWindow window, bool preselect, bool reroll)
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: 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_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Expected O, but got Unknown
try
{
Transform transform = ((Component)window).transform;
RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
if ((Object)(object)val == (Object)null)
{
return null;
}
UITheme.Initialize();
RectTransform val2 = UIFactory.CreateRect("BacklogImprovementsBar", (Transform)(object)val);
val2.anchorMin = new Vector2(0.12f, 0f);
val2.anchorMax = new Vector2(0.12f, 0f);
val2.pivot = new Vector2(0f, 0f);
val2.sizeDelta = new Vector2(720f, 40f);
val2.anchoredPosition = new Vector2(0f, 18f);
((Transform)val2).SetAsLastSibling();
UIFactory.AddHorizontalLayout(((Component)val2).gameObject, 4f, new RectOffset(0, 0, 0, 0), (TextAnchor)3, false, false, true, true);
WindowState state = new WindowState
{
Window = window,
Root = ((Component)val2).gameObject
};
if (preselect)
{
state.EditButton = UIButton.Create((Transform)(object)val2, "Edit Path", (Action)delegate
{
OnEditClicked(state);
}, (UIButtonStyle)1, (string)null, (float?)32f);
ApplyCompactLabel(state.EditButton);
FitButtonWidth(state.EditButton, 120f);
state.ClearButton = UIButton.Create((Transform)(object)val2, "Clear", (Action)delegate
{
OnClearClicked(state);
}, (UIButtonStyle)2, (string)null, (float?)32f);
ApplyCompactLabel(state.ClearButton);
FitButtonWidth(state.ClearButton, 80f);
}
if (reroll)
{
state.PageButton = UIButton.Create((Transform)(object)val2, "Reroll Page", (Action)delegate
{
OnRerollPageClicked(state);
}, (UIButtonStyle)1, (string)null, (float?)32f);
ApplyCompactLabel(state.PageButton);
FitButtonWidth(state.PageButton, 120f);
state.SingleButton = UIButton.Create((Transform)(object)val2, "Reroll One", (Action)delegate
{
OnRerollOneClicked(state);
}, (UIButtonStyle)0, (string)null, (float?)32f);
ApplyCompactLabel(state.SingleButton);
FitButtonWidth(state.SingleButton, 120f);
state.CancelButton = UIButton.Create((Transform)(object)val2, "Cancel", (Action)delegate
{
ExitRerollSelection(state);
}, (UIButtonStyle)2, (string)null, (float?)32f);
ApplyCompactLabel(state.CancelButton);
state.CancelButton.SetWidth(90f);
state.CancelButton.SetActive(false);
}
return state;
}
catch (Exception arg)
{
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogError((object)$"Failed to build backlog UI: {arg}");
}
return null;
}
}
private static void OnEditClicked(WindowState state)
{
if (!((Object)(object)state?.Window == (Object)null) && !IsAnimating(state.Window))
{
if (PathLogic.IsEditing)
{
ExitPathEdit(state, activateNext: true, refreshWindow: true);
return;
}
ExitRerollSelection(state);
EnterPathEdit(state);
}
}
private static void OnClearClicked(WindowState state)
{
if ((Object)(object)state?.Window == (Object)null || IsAnimating(state.Window))
{
return;
}
int page = PathStore.CurrentPage;
if (!PathStore.HasPath(page))
{
UIDialog.Alert("Nothing to Clear", "No preselected path on this page.", (Action)null, "OK");
return;
}
UIDialog.Confirm("Clear Path", "Remove the preselected path for this backlog page?", (Action)delegate
{
PathStore.ClearPage(page);
RefreshAll(state);
PathVisualizer.Refresh(state.Window);
DirectiveWindow window = state.Window;
if (window != null)
{
window.SetupDirectives(false);
}
}, (Action)null, "Clear", "Cancel");
}
private static void EnterPathEdit(WindowState state)
{
PathLogic.SetEditing(editing: true);
RefreshAll(state);
DirectiveWindow window = state.Window;
if (window != null)
{
window.SetupDirectives(false);
}
PathVisualizer.Refresh(state.Window);
}
private static void ExitPathEdit(WindowState state, bool activateNext, bool refreshWindow)
{
if (!PathLogic.IsEditing)
{
return;
}
PathLogic.SetEditing(editing: false);
PathStore.Save();
RefreshAll(state);
if (refreshWindow)
{
DirectiveWindow window = state.Window;
if (window != null)
{
window.SetupDirectives(false);
}
}
PathVisualizer.Refresh(state.Window);
if (activateNext && !PathLogic.HasBlockingDirective())
{
PathLogic.TryActivateNext(state.Window);
}
}
private static void OnRerollPageClicked(WindowState state)
{
if ((Object)(object)state?.Window == (Object)null || IsAnimating(state.Window))
{
return;
}
ExitRerollSelection(state);
ExitPathEdit(state, activateNext: false, refreshWindow: true);
int num = RerollLogic.CountEligible();
if (num <= 0)
{
UIDialog.Alert("Nothing to Reroll", "There are no not-started directives on this page.", (Action)null, "OK");
return;
}
int cost = RerollLogic.GetPageRerollCost();
if (!RerollLogic.CanAfford(cost))
{
UIDialog.Alert("Not Enough Gats", $"Need {cost} gats to reroll {num} directive(s).", (Action)null, "OK");
return;
}
UIDialog.Confirm("Reroll Page", $"Reroll {num} not-started directive(s) for {cost} gats?\nActive and completed directives are kept.", (Action)delegate
{
if (RerollLogic.TryRerollPage(out var rerolledCount, out var error))
{
DirectiveWindow window = state.Window;
if (window != null)
{
window.SetupDirectives(true);
}
RefreshAll(state);
PlayRerollSound();
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogInfo((object)$"Rerolled {rerolledCount} backlog directive(s) for {cost} gats.");
}
}
else
{
UIDialog.Alert("Reroll Failed", error ?? "Unknown error.", (Action)null, "OK");
}
}, (Action)null, $"Pay {cost}", "Cancel");
}
private static void OnRerollOneClicked(WindowState state)
{
if ((Object)(object)state?.Window == (Object)null || IsAnimating(state.Window))
{
return;
}
if (state.RerollSelecting)
{
ExitRerollSelection(state);
return;
}
if (RerollLogic.CountEligible() <= 0)
{
UIDialog.Alert("Nothing to Reroll", "There are no not-started directives on this page.", (Action)null, "OK");
return;
}
int singleRerollCost = RerollLogic.GetSingleRerollCost();
if (!RerollLogic.CanAfford(singleRerollCost))
{
UIDialog.Alert("Not Enough Gats", $"Need {singleRerollCost} gats to reroll one directive.", (Action)null, "OK");
return;
}
ExitPathEdit(state, activateNext: false, refreshWindow: true);
EnterRerollSelection(state);
}
private static void EnterRerollSelection(WindowState state)
{
state.RerollSelecting = true;
if (state.CancelButton != null)
{
state.CancelButton.SetActive(true);
}
if (state.SingleButton != null)
{
state.SingleButton.SetText("Click a directive…");
FitButtonWidth(state.SingleButton, 120f);
}
if (state.PageButton != null)
{
state.PageButton.SetInteractable(false);
}
if (state.EditButton != null)
{
state.EditButton.SetInteractable(false);
}
if (state.ClearButton != null)
{
state.ClearButton.SetInteractable(false);
}
RebuildRerollOverlays(state);
}
private static void ExitRerollSelection(WindowState state)
{
if (state != null && state.RerollSelecting)
{
state.RerollSelecting = false;
ClearRerollOverlays(state);
if (state.CancelButton != null)
{
state.CancelButton.SetActive(false);
}
if (state.PageButton != null)
{
state.PageButton.SetInteractable(true);
}
if (state.EditButton != null)
{
state.EditButton.SetInteractable(true);
}
RefreshAll(state);
}
}
private static void RebuildRerollOverlays(WindowState state)
{
ClearRerollOverlays(state);
if ((Object)(object)state?.Window == (Object)null || !state.RerollSelecting || !(DirectivesField?.GetValue(state.Window) is DirectiveButton[] array))
{
return;
}
foreach (DirectiveButton val in array)
{
if (!((Object)(object)val == (Object)null) && RerollLogic.IsEligible((DirectiveInstance)/*isinst with value type is only supported in some contexts*/))
{
Transform transform = ((Component)val).transform;
GameObject val2 = CreateEligibleOverlay((RectTransform)(object)((transform is RectTransform) ? transform : null));
if ((Object)(object)val2 != (Object)null)
{
state.RerollOverlays.Add(val2);
}
}
}
}
private static GameObject CreateEligibleOverlay(RectTransform target)
{
//IL_0011: 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)
if ((Object)(object)target == (Object)null)
{
return null;
}
Image obj = UIFactory.CreateImage("RerollEligibleOverlay", (Transform)(object)target, UIColors.WithAlpha(UIColors.ButtonPrimary, 0.35f), false);
UIFactory.ApplyWhiteSprite(obj);
UIHelpers.SetFillParent(((Graphic)obj).rectTransform, UITheme.S(2f));
((Transform)((Graphic)obj).rectTransform).SetAsLastSibling();
return ((Component)obj).gameObject;
}
private static void ClearRerollOverlays(WindowState state)
{
if (state != null)
{
for (int i = 0; i < state.RerollOverlays.Count; i++)
{
UIHelpers.DestroySafe((Object)(object)state.RerollOverlays[i]);
}
state.RerollOverlays.Clear();
}
}
private static void RefreshAll(WindowState state)
{
if (state != null)
{
RefreshPathLabels(state);
RefreshRerollLabels(state);
}
}
private static void RefreshPathLabels(WindowState state)
{
if (state.EditButton != null || state.ClearButton != null)
{
int count = PathStore.GetPath(PathStore.CurrentPage).Count;
bool isEditing = PathLogic.IsEditing;
if (state.EditButton != null)
{
state.EditButton.SetText(isEditing ? "Done" : "Edit Path");
state.EditButton.SetStyle((UIButtonStyle)((!isEditing) ? 1 : 3));
FitButtonWidth(state.EditButton, 120f);
state.EditButton.SetInteractable(!state.RerollSelecting);
}
if (state.ClearButton != null)
{
state.ClearButton.SetInteractable((count > 0 || isEditing) && !state.RerollSelecting);
}
}
}
private static void RefreshRerollLabels(WindowState state)
{
if ((state.PageButton != null || state.SingleButton != null) && !state.RerollSelecting)
{
int num = RerollLogic.CountEligible();
int num2 = num * RerollLogic.CostPerDirective;
int costPerDirective = RerollLogic.CostPerDirective;
bool isEditing = PathLogic.IsEditing;
if (state.PageButton != null)
{
state.PageButton.SetText((num > 0) ? $"Reroll Page ({num2})" : "Reroll Page");
FitButtonWidth(state.PageButton, 120f);
state.PageButton.SetInteractable(!isEditing && num > 0 && RerollLogic.CanAfford(num2));
}
if (state.SingleButton != null)
{
state.SingleButton.SetText((num > 0) ? $"Reroll One ({costPerDirective})" : "Reroll One");
FitButtonWidth(state.SingleButton, 120f);
state.SingleButton.SetInteractable(!isEditing && num > 0 && RerollLogic.CanAfford(costPerDirective));
}
}
}
private static void ApplyCompactLabel(UIButton button)
{
if (!((Object)(object)((button != null) ? button.Label : null) == (Object)null))
{
TextMeshProUGUI label = button.Label;
((TMP_Text)label).enableAutoSizing = false;
((TMP_Text)label).fontSize = 13f;
((TMP_Text)label).fontSizeMin = 13f;
((TMP_Text)label).fontSizeMax = 13f;
((TMP_Text)label).enableWordWrapping = false;
((TMP_Text)label).overflowMode = (TextOverflowModes)0;
UIHelpers.SetFillParent(((TMP_Text)label).rectTransform, 8f);
}
}
private static void FitButtonWidth(UIButton button, float minWidth)
{
if (button == null)
{
return;
}
ApplyCompactLabel(button);
float num = minWidth;
if ((Object)(object)button.Label != (Object)null)
{
((TMP_Text)button.Label).ForceMeshUpdate(false, false);
float num2 = ((TMP_Text)button.Label).preferredWidth + 24f;
if (num2 > num)
{
num = num2;
}
}
button.SetWidth(num);
}
private static bool IsAnimating(DirectiveWindow window)
{
if ((Object)(object)window == (Object)null || IsAnimatingField == null)
{
return false;
}
try
{
return (bool)IsAnimatingField.GetValue(window);
}
catch
{
return false;
}
}
private static void DestroyState(WindowState state)
{
if (state != null)
{
ClearRerollOverlays(state);
UIHelpers.DestroySafe((Object)(object)state.Root);
state.Root = null;
state.EditButton = null;
state.ClearButton = null;
state.PageButton = null;
state.SingleButton = null;
state.CancelButton = null;
state.RerollSelecting = false;
}
}
private static void PlayRerollSound()
{
try
{
if ((Object)(object)PlayerLook.Instance != (Object)null)
{
AkUnitySoundEngine.PostEvent("UI_Directive_Page_Complete2", ((Component)PlayerLook.Instance).gameObject);
}
}
catch
{
}
}
public static void PlayPathSound()
{
try
{
if ((Object)(object)PlayerLook.Instance != (Object)null)
{
AkUnitySoundEngine.PostEvent("UI_Directive_Connect", ((Component)PlayerLook.Instance).gameObject);
}
}
catch
{
}
}
}
public static class FreePages
{
public static void ApplyFreeNextPage(DirectiveWindow window)
{
if ((Object)(object)window == (Object)null)
{
return;
}
ConfigEntry<bool> enableFreePages = BacklogImprovementsPlugin.EnableFreePages;
if (enableFreePages != null && !enableFreePages.Value)
{
return;
}
try
{
object? value = AccessTools.Field(typeof(DirectiveWindow), "nextPageButton").GetValue(window);
HoverInfoHold val = (HoverInfoHold)((value is HoverInfoHold) ? value : null);
if (!((Object)(object)val == (Object)null))
{
AccessTools.Field(typeof(HoverInfoHold), "cost").SetValue(val, Array.Empty<ResourceCost>());
}
}
catch (Exception ex)
{
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("Free next page failed: " + ex.Message));
}
}
}
}
[HarmonyPatch(typeof(DirectiveWindow))]
internal static class DirectiveWindowPatches
{
[HarmonyPostfix]
[HarmonyPatch("OnOpen")]
private static void OnOpenPostfix(DirectiveWindow __instance)
{
BacklogUI.OnWindowOpened(__instance);
}
[HarmonyPostfix]
[HarmonyPatch("SetupDirectives")]
private static void SetupDirectivesPostfix(DirectiveWindow __instance)
{
BacklogUI.OnDirectivesRefreshed(__instance);
}
[HarmonyPostfix]
[HarmonyPatch("OnDisable")]
private static void OnDisablePostfix(DirectiveWindow __instance)
{
BacklogUI.OnWindowClosed(__instance);
}
}
[HarmonyPatch(typeof(DirectiveWindow), "Update")]
internal static class DirectiveWindowUpdatePatch
{
private static void Postfix(DirectiveWindow __instance)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: 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_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Expected O, but got Unknown
//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)
if (BacklogUI.IsAnySelectionMode)
{
try
{
if (PlayerInput.Controls != null)
{
MenuActions menu = PlayerInput.Controls.Menu;
if (((MenuActions)(ref menu)).Click.WasPressedThisFrame() && !((Object)(object)EventSystem.current == (Object)null))
{
Vector2 position = ((Mouse.current == null) ? Vector2.op_Implicit(Input.mousePosition) : ((InputControl<Vector2>)(object)((Pointer)Mouse.current).position).ReadValue());
PointerEventData val = new PointerEventData(EventSystem.current)
{
position = position
};
List<RaycastResult> list = new List<RaycastResult>();
EventSystem.current.RaycastAll(val, list);
for (int i = 0; i < list.Count; i++)
{
RaycastResult val2 = list[i];
DirectiveButton componentInParent = ((RaycastResult)(ref val2)).gameObject.GetComponentInParent<DirectiveButton>();
if ((Object)(object)componentInParent != (Object)null)
{
BacklogUI.TryHandleDirectiveClick(componentInParent);
break;
}
}
}
}
return;
}
catch
{
return;
}
}
ConfigEntry<bool> enablePreselect = BacklogImprovementsPlugin.EnablePreselect;
if (enablePreselect == null || enablePreselect.Value)
{
PathLogic.TryAutoClaim(__instance);
}
}
}
[HarmonyPatch(typeof(DirectiveButton))]
internal static class DirectiveButtonPatches
{
private static readonly FieldInfo DirectiveField = AccessTools.Field(typeof(DirectiveButton), "directive");
private static readonly MethodInfo SetupAvailableMethod = AccessTools.Method(typeof(DirectiveButton), "SetupAvailable", (Type[])null, (Type[])null);
[HarmonyPrefix]
[HarmonyPatch("HasUnlockAction")]
private static bool HasUnlockActionPrefix(DirectiveButton __instance, out UnlockActionParams data, ref bool __result)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
data = default(UnlockActionParams);
if (!BacklogUI.IsAnySelectionMode)
{
return true;
}
__result = false;
return false;
}
[HarmonyPrefix]
[HarmonyPatch("GetPrimaryBinding")]
private static bool GetPrimaryBindingPrefix(DirectiveButton __instance, out InputAction binding, out string label, ref bool __result)
{
//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)
if (!BacklogUI.IsAnySelectionMode)
{
binding = null;
label = null;
return true;
}
MenuActions menu = PlayerInput.Controls.Menu;
binding = ((MenuActions)(ref menu)).Click;
label = (BacklogUI.IsRerollSelecting ? "reroll" : "select");
__result = true;
return false;
}
[HarmonyPostfix]
[HarmonyPatch("Setup")]
private static void SetupPostfix(DirectiveButton __instance, DirectiveInstance directive)
{
if (!PathLogic.IsEditing || directive == null)
{
return;
}
try
{
if (!directive.IsComplete || !directive.HasClaimedRewards)
{
SetupAvailableMethod?.Invoke(__instance, null);
}
}
catch (Exception ex)
{
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogWarning((object)("SetupAvailable force failed: " + ex.Message));
}
}
}
}
[HarmonyPatch(typeof(DirectiveInstance), "CanBeActivated")]
internal static class CanBeActivatedPatch
{
private static bool Prefix(DirectiveInstance __instance, ref bool __result)
{
try
{
ConfigEntry<bool> enablePreselect = BacklogImprovementsPlugin.EnablePreselect;
if (enablePreselect != null && !enablePreselect.Value)
{
return true;
}
if (PathLogic.IsEditing)
{
__result = false;
return false;
}
if (!PathLogic.ShouldAllowActivation(__instance, out var forceTrue) && forceTrue)
{
__result = true;
return false;
}
return true;
}
catch (Exception ex)
{
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogError((object)("CanBeActivated patch: " + ex.Message));
}
return true;
}
}
}
[HarmonyPatch(typeof(PlayerData), "GetCurrrentDirectiveTier")]
internal static class DirectiveTierPatch
{
private static void Postfix(ref int __result)
{
if (PathLogic.IsEditing)
{
__result = 99;
}
}
}
[HarmonyPatch(typeof(DirectiveInstance), "ClaimRewards")]
internal static class DirectiveInstanceClaimPatch
{
private static void Postfix(DirectiveInstance __instance)
{
try
{
ConfigEntry<bool> enablePreselect = BacklogImprovementsPlugin.EnablePreselect;
if ((enablePreselect == null || enablePreselect.Value) && !PathLogic.IsEditing)
{
DirectiveWindow window = Object.FindObjectOfType<DirectiveWindow>();
PathLogic.OnDirectiveClaimed(__instance, window);
}
}
catch (Exception ex)
{
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogError((object)("DirectiveInstance.ClaimRewards postfix: " + ex.Message));
}
}
}
}
public static class PathLogic
{
private static readonly FieldInfo IsActiveField = AccessTools.Field(typeof(DirectiveInstance), "isActive");
private static readonly FieldInfo HasClaimedField = AccessTools.Field(typeof(DirectiveInstance), "hasClaimedRewards");
private static readonly FieldInfo PropertiesField = AccessTools.Field(typeof(DirectiveInstance), "properties");
private static bool _autoClaimBusy;
private static bool _activateBusy;
public static bool IsEditing { get; private set; }
public static void SetEditing(bool editing)
{
IsEditing = editing;
}
public static int IndexOf(DirectiveInstance directive)
{
PlayerData instance = PlayerData.Instance;
if (instance?.defaultDirectives == null || directive == null)
{
return -1;
}
return Array.IndexOf(instance.defaultDirectives, directive);
}
public static bool IsOnCurrentPath(int index)
{
return PathStore.Contains(PathStore.CurrentPage, index);
}
public static bool IsOnCurrentPath(DirectiveInstance directive)
{
int num = IndexOf(directive);
if (num >= 0)
{
return IsOnCurrentPath(num);
}
return false;
}
public static int GetNextPathIndex()
{
PlayerData instance = PlayerData.Instance;
if (instance?.defaultDirectives == null)
{
return -1;
}
List<int> path = PathStore.GetPath(PathStore.CurrentPage);
for (int i = 0; i < path.Count; i++)
{
int num = path[i];
if (num >= 0 && num < instance.defaultDirectives.Length)
{
DirectiveInstance val = instance.defaultDirectives[num];
if (val != null && (!val.IsComplete || !val.HasClaimedRewards))
{
return num;
}
}
}
return -1;
}
public static bool TryActivateNext(DirectiveWindow window = null)
{
if (_activateBusy || IsEditing)
{
return false;
}
ConfigEntry<bool> enablePreselect = BacklogImprovementsPlugin.EnablePreselect;
if (enablePreselect != null && !enablePreselect.Value)
{
return false;
}
PlayerData instance = PlayerData.Instance;
if (instance?.defaultDirectives == null)
{
return false;
}
if (HasBlockingDirective(instance))
{
return false;
}
int nextPathIndex = GetNextPathIndex();
if (nextPathIndex < 0)
{
return false;
}
DirectiveInstance val = instance.defaultDirectives[nextPathIndex];
if (val == null || !val.CanBeActivated())
{
return false;
}
_activateBusy = true;
try
{
val.Activate();
if (val.IsDefault())
{
instance.currentDefaultDirective = nextPathIndex;
}
if (window != null)
{
window.SetupDirectives(true);
}
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogInfo((object)$"Activated path node {nextPathIndex} (tier {val.Tier}).");
}
return true;
}
catch (Exception ex)
{
ManualLogSource log2 = BacklogImprovementsPlugin.Log;
if (log2 != null)
{
log2.LogError((object)$"Failed to activate path node {nextPathIndex}: {ex.Message}");
}
return false;
}
finally
{
_activateBusy = false;
}
}
public static bool HasBlockingDirective(PlayerData data = null)
{
data = data ?? PlayerData.Instance;
if (data?.defaultDirectives == null)
{
return false;
}
for (int i = 0; i < data.defaultDirectives.Length; i++)
{
DirectiveInstance val = data.defaultDirectives[i];
if (val != null)
{
if (val.IsActive)
{
return true;
}
if (val.IsComplete && !val.HasClaimedRewards)
{
return true;
}
}
}
return false;
}
public static bool TryAutoClaim(DirectiveWindow window = null)
{
if (IsEditing || _autoClaimBusy)
{
return false;
}
ConfigEntry<bool> enablePreselect = BacklogImprovementsPlugin.EnablePreselect;
if (enablePreselect != null && !enablePreselect.Value)
{
return false;
}
PlayerData instance = PlayerData.Instance;
if (instance?.defaultDirectives == null)
{
return false;
}
int currentDefaultDirective = instance.currentDefaultDirective;
if (currentDefaultDirective < 0 || currentDefaultDirective >= instance.defaultDirectives.Length)
{
return false;
}
if (!IsOnCurrentPath(currentDefaultDirective))
{
return false;
}
DirectiveInstance val = instance.defaultDirectives[currentDefaultDirective];
if (val == null || !val.CanClaimRewards())
{
return false;
}
_autoClaimBusy = true;
try
{
val.ClaimRewards();
if (window != null)
{
window.SetupDirectives(true);
}
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogInfo((object)$"Auto-claimed path node {currentDefaultDirective}.");
}
return true;
}
catch (Exception ex)
{
ManualLogSource log2 = BacklogImprovementsPlugin.Log;
if (log2 != null)
{
log2.LogError((object)("Auto-claim failed: " + ex.Message));
}
return false;
}
finally
{
_autoClaimBusy = false;
}
}
public static void OnDirectiveClaimed(DirectiveInstance claimed, DirectiveWindow window = null)
{
if (!IsEditing && claimed != null)
{
ConfigEntry<bool> enablePreselect = BacklogImprovementsPlugin.EnablePreselect;
if ((enablePreselect == null || enablePreselect.Value) && IsOnCurrentPath(claimed))
{
TryActivateNext(window);
}
}
}
public static bool ShouldAllowActivation(DirectiveInstance directive, out bool forceTrue)
{
forceTrue = false;
if (directive == null)
{
return true;
}
if (IsEditing)
{
forceTrue = false;
return false;
}
int num = IndexOf(directive);
if (num < 0 || !IsOnCurrentPath(num))
{
return true;
}
int nextPathIndex = GetNextPathIndex();
if (num != nextPathIndex)
{
return true;
}
if (directive.IsActive || directive.IsComplete)
{
return true;
}
PlayerData instance = PlayerData.Instance;
if (instance == null)
{
return true;
}
for (int i = 0; i < instance.defaultDirectives.Length; i++)
{
DirectiveInstance val = instance.defaultDirectives[i];
if (val != null && val != directive && (val.IsActive || (val.IsComplete && !val.HasClaimedRewards)))
{
return true;
}
}
forceTrue = true;
return false;
}
public static bool TryForceCompleteCurrent()
{
PlayerData instance = PlayerData.Instance;
if (instance?.defaultDirectives == null)
{
return false;
}
int num = instance.currentDefaultDirective;
if (num < 0 || num >= instance.defaultDirectives.Length)
{
num = -1;
for (int i = 0; i < instance.defaultDirectives.Length; i++)
{
if (instance.defaultDirectives[i] != null && instance.defaultDirectives[i].IsActive)
{
num = i;
break;
}
}
}
if (num < 0)
{
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogWarning((object)"Force-complete: no active directive.");
}
return false;
}
DirectiveInstance val = instance.defaultDirectives[num];
if (val == null)
{
return false;
}
try
{
if (val.IsActive)
{
val.CompleteAllProperties();
}
else
{
ForceCompleteProperties(val);
}
if (!val.IsComplete)
{
ForceCompleteProperties(val);
}
ManualLogSource log2 = BacklogImprovementsPlugin.Log;
if (log2 != null)
{
log2.LogInfo((object)$"Force-completed directive index {num}.");
}
DirectiveWindow val2 = Object.FindObjectOfType<DirectiveWindow>();
if (val2 != null)
{
val2.SetupDirectives(true);
}
if (IsOnCurrentPath(num) && val.CanClaimRewards())
{
val.ClaimRewards();
if (val2 != null)
{
val2.SetupDirectives(true);
}
}
return true;
}
catch (Exception ex)
{
ManualLogSource log3 = BacklogImprovementsPlugin.Log;
if (log3 != null)
{
log3.LogError((object)("Force-complete failed: " + ex.Message));
}
return false;
}
}
private static void ForceCompleteProperties(DirectiveInstance directive)
{
if (directive == null || PropertiesField == null || !(PropertiesField.GetValue(directive) is IList list))
{
return;
}
for (int i = 0; i < list.Count; i++)
{
object? obj = list[i];
DirectivePropertyInstance val = (DirectivePropertyInstance)((obj is DirectivePropertyInstance) ? obj : null);
if (val != null)
{
val.Current = val.Target;
}
}
if (directive.IsActive)
{
directive.Deactivate();
}
}
}
public static class PathStore
{
private static readonly Dictionary<int, List<int>> PagePaths = new Dictionary<int, List<int>>();
private static string FilePath => Path.Combine(Paths.ConfigPath, "sparroh.backlogimprovements.txt");
private static string LegacyFilePath => Path.Combine(Paths.ConfigPath, "sparroh.preselectbacklog.txt");
public static IReadOnlyDictionary<int, List<int>> All => PagePaths;
public static int CurrentPage
{
get
{
try
{
return PlayerData.Instance?.currentDirectivePage ?? 0;
}
catch
{
return 0;
}
}
}
public static void Load()
{
PagePaths.Clear();
try
{
string text = FilePath;
if (!File.Exists(text) && File.Exists(LegacyFilePath))
{
text = LegacyFilePath;
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogInfo((object)"Migrating preselected paths from legacy PreselectBacklog config.");
}
}
if (!File.Exists(text))
{
return;
}
string[] array = File.ReadAllLines(text);
foreach (string text2 in array)
{
if (string.IsNullOrWhiteSpace(text2))
{
continue;
}
string[] array2 = text2.Split(new char[1] { ',' });
if (array2.Length == 2 && int.TryParse(array2[0].Trim(), out var result) && int.TryParse(array2[1].Trim(), out var result2))
{
if (!PagePaths.TryGetValue(result, out var value))
{
value = new List<int>();
PagePaths[result] = value;
}
if (!value.Contains(result2))
{
value.Add(result2);
}
}
}
foreach (KeyValuePair<int, List<int>> item in PagePaths.ToList())
{
PagePaths[item.Key] = SortByTier(item.Value);
}
if (text == LegacyFilePath && PagePaths.Count > 0)
{
Save();
}
}
catch (Exception ex)
{
ManualLogSource log2 = BacklogImprovementsPlugin.Log;
if (log2 != null)
{
log2.LogError((object)("Failed to load preselected paths: " + ex.Message));
}
}
}
public static void Save()
{
try
{
Directory.CreateDirectory(Paths.ConfigPath);
List<string> list = new List<string>();
foreach (KeyValuePair<int, List<int>> item in PagePaths.OrderBy((KeyValuePair<int, List<int>> k) => k.Key))
{
foreach (int item2 in item.Value)
{
list.Add($"{item.Key},{item2}");
}
}
File.WriteAllLines(FilePath, list);
}
catch (Exception ex)
{
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogError((object)("Failed to save preselected paths: " + ex.Message));
}
}
}
public static List<int> GetPath(int page)
{
if (!PagePaths.TryGetValue(page, out var value))
{
value = new List<int>();
PagePaths[page] = value;
}
return value;
}
public static List<int> GetPathCopy(int page)
{
return new List<int>(GetPath(page));
}
public static bool HasPath(int page)
{
if (PagePaths.TryGetValue(page, out var value))
{
return value.Count > 0;
}
return false;
}
public static bool Contains(int page, int index)
{
if (PagePaths.TryGetValue(page, out var value))
{
return value.Contains(index);
}
return false;
}
public static void SetPath(int page, List<int> indices)
{
PagePaths[page] = SortByTier(indices ?? new List<int>());
Save();
}
public static void ClearPage(int page)
{
if (PagePaths.ContainsKey(page))
{
PagePaths[page] = new List<int>();
Save();
}
}
public static void ToggleSelection(int page, int index)
{
List<int> path = GetPath(page);
if (path.Contains(index))
{
path.Remove(index);
Save();
return;
}
PlayerData data = PlayerData.Instance;
if (data?.defaultDirectives == null || index < 0 || index >= data.defaultDirectives.Length)
{
return;
}
DirectiveInstance val = data.defaultDirectives[index];
if (val == null)
{
return;
}
int selectedTier = val.Tier;
path.RemoveAll(delegate(int i)
{
if (i < 0 || i >= data.defaultDirectives.Length)
{
return true;
}
DirectiveInstance val2 = data.defaultDirectives[i];
return val2 == null || val2.Tier == selectedTier;
});
path.Add(index);
PagePaths[page] = SortByTier(path);
Save();
}
public static List<int> SortByTier(List<int> indices)
{
PlayerData data = PlayerData.Instance;
if (data?.defaultDirectives == null || indices == null)
{
return indices ?? new List<int>();
}
return (from i in indices.Where((int i) => i >= 0 && i < data.defaultDirectives.Length && data.defaultDirectives[i] != null).Distinct()
orderby data.defaultDirectives[i].Tier, i
select i).ToList();
}
}
public static class PathVisualizer
{
private sealed class VisualState
{
public DirectiveWindow Window;
public Transform LineParent;
public readonly List<GameObject> Lines = new List<GameObject>();
public readonly List<GameObject> Badges = new List<GameObject>();
public readonly List<GameObject> Overlays = new List<GameObject>();
}
private static readonly FieldInfo DirectivesField = AccessTools.Field(typeof(DirectiveWindow), "directives");
private static readonly FieldInfo LinesField = AccessTools.Field(typeof(DirectiveWindow), "lines");
private static readonly FieldInfo OutlineField = AccessTools.Field(typeof(DirectiveButton), "outline");
private static readonly Dictionary<int, VisualState> States = new Dictionary<int, VisualState>();
private const float LineWidth = 4f;
private const float BadgeSize = 22f;
public static void Refresh(DirectiveWindow window)
{
if ((Object)(object)window == (Object)null)
{
return;
}
ConfigEntry<bool> enablePreselect = BacklogImprovementsPlugin.EnablePreselect;
if (enablePreselect != null && !enablePreselect.Value)
{
Clear(window);
return;
}
int instanceID = ((Object)window).GetInstanceID();
if (!States.TryGetValue(instanceID, out var value))
{
value = new VisualState
{
Window = window
};
States[instanceID] = value;
}
else
{
value.Window = window;
}
EnsureLineParent(value);
ClearVisuals(value);
if (!(DirectivesField?.GetValue(window) is DirectiveButton[] array))
{
return;
}
List<int> path = PathStore.GetPath(PathStore.CurrentPage);
if (path == null || path.Count == 0)
{
return;
}
List<int> list = PathStore.SortByTier(new List<int>(path));
for (int i = 0; i < list.Count; i++)
{
int num = list[i];
if (num >= 0 && num < array.Length && !((Object)(object)array[num] == (Object)null))
{
CreateBadge(value, array[num], i + 1);
CreateOverlay(value, array[num]);
ApplyOutline(array[num], selected: true);
}
}
for (int j = 0; j < list.Count - 1; j++)
{
int num2 = list[j];
int num3 = list[j + 1];
if (num2 >= 0 && num3 >= 0 && num2 < array.Length && num3 < array.Length && !((Object)(object)array[num2] == (Object)null) && !((Object)(object)array[num3] == (Object)null))
{
CreateLine(value, array[num2], array[num3]);
}
}
}
public static void Clear(DirectiveWindow window)
{
if (!((Object)(object)window == (Object)null))
{
int instanceID = ((Object)window).GetInstanceID();
if (States.TryGetValue(instanceID, out var value))
{
ClearVisuals(value);
UIHelpers.DestroySafe((Object)(object)(((Object)(object)value.LineParent != (Object)null && ((Object)value.LineParent).name == "PreselectPathLines") ? ((Component)value.LineParent).gameObject : null));
States.Remove(instanceID);
}
}
}
public static void CleanupAll()
{
foreach (KeyValuePair<int, VisualState> state in States)
{
ClearVisuals(state.Value);
}
States.Clear();
}
private static void EnsureLineParent(VisualState state)
{
if ((Object)(object)state.LineParent != (Object)null)
{
return;
}
try
{
if (LinesField?.GetValue(state.Window) is IList { Count: >0 } list)
{
object? obj = list[0];
Component val = (Component)((obj is Component) ? obj : null);
if ((Object)(object)val != (Object)null)
{
state.LineParent = val.transform.parent;
return;
}
}
}
catch
{
}
Transform transform = ((Component)state.Window).transform;
RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
RectTransform val3 = UIFactory.CreateRect("PreselectPathLines", (Transform)(object)val2);
UIHelpers.SetFillParent(val3, 0f);
((Transform)val3).SetAsFirstSibling();
Image component = ((Component)val3).gameObject.GetComponent<Image>();
if ((Object)(object)component != (Object)null)
{
Object.Destroy((Object)(object)component);
}
Graphic component2 = ((Component)val3).gameObject.GetComponent<Graphic>();
if ((Object)(object)component2 != (Object)null)
{
component2.raycastTarget = false;
}
state.LineParent = (Transform)(object)val3;
}
private static void CreateLine(VisualState state, DirectiveButton from, DirectiveButton to)
{
//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_0060: 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_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_0073: 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_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: 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_0099: 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_00af: 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_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00b9: 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_00e2: 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_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0145: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_0158: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: 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_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)state.LineParent == (Object)null)
{
return;
}
Transform transform = ((Component)from).transform;
RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
Transform transform2 = ((Component)to).transform;
RectTransform val2 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null);
Transform lineParent = state.LineParent;
RectTransform val3 = (RectTransform)(object)((lineParent is RectTransform) ? lineParent : null);
if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null) && !((Object)(object)val3 == (Object)null))
{
Vector2 val4 = Vector2.op_Implicit(((Transform)val3).InverseTransformPoint(((Transform)val).position));
Vector2 val5 = Vector2.op_Implicit(((Transform)val3).InverseTransformPoint(((Transform)val2).position)) - val4;
float magnitude = ((Vector2)(ref val5)).magnitude;
if (!(magnitude < 1f))
{
Vector2 val6 = val5 / magnitude;
Rect rect = val.rect;
float num = ((Rect)(ref rect)).height * 0.5f;
Vector2 anchoredPosition = val4 + val6 * num;
float num2 = Mathf.Max(0f, magnitude - num * 2f);
Image val7 = UIFactory.CreateImage("PreselectPathLine", state.LineParent, UIColors.WithAlpha(UIColors.Macaroon, 0.95f), false);
UIFactory.ApplyWhiteSprite(val7);
RectTransform rectTransform = ((Graphic)val7).rectTransform;
Vector2 val8 = default(Vector2);
((Vector2)(ref val8))..ctor(0.5f, 0.5f);
rectTransform.anchorMax = val8;
rectTransform.anchorMin = val8;
rectTransform.pivot = new Vector2(0.5f, 0f);
rectTransform.sizeDelta = new Vector2(4f, num2);
rectTransform.anchoredPosition = anchoredPosition;
((Transform)rectTransform).localRotation = Quaternion.FromToRotation(Vector2.op_Implicit(Vector2.up), Vector2.op_Implicit(val6));
((Transform)rectTransform).localScale = Vector3.one;
((Transform)rectTransform).SetAsFirstSibling();
state.Lines.Add(((Component)val7).gameObject);
}
}
}
private static void CreateBadge(VisualState state, DirectiveButton button, int order)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
Transform transform = ((Component)button).transform;
RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
if (!((Object)(object)val == (Object)null))
{
Image val2 = UIFactory.CreateImage("PreselectBadge", (Transform)(object)val, UIColors.Macaroon, false);
UIFactory.ApplyWhiteSprite(val2);
RectTransform rectTransform = ((Graphic)val2).rectTransform;
Vector2 val3 = default(Vector2);
((Vector2)(ref val3))..ctor(1f, 1f);
rectTransform.anchorMax = val3;
rectTransform.anchorMin = val3;
rectTransform.pivot = new Vector2(1f, 1f);
rectTransform.sizeDelta = new Vector2(22f, 22f);
rectTransform.anchoredPosition = new Vector2(-2f, -2f);
((Transform)rectTransform).SetAsLastSibling();
TextMeshProUGUI obj = UIFactory.CreateTmp("Num", (Transform)(object)rectTransform, order.ToString(), 14f, (Color?)UIColors.PanelBg, (TextAlignmentOptions)514, false);
UIHelpers.SetFillParent(((TMP_Text)obj).rectTransform, 1f);
((Graphic)obj).raycastTarget = false;
((TMP_Text)obj).fontStyle = (FontStyles)1;
state.Badges.Add(((Component)val2).gameObject);
}
}
private static void CreateOverlay(VisualState state, DirectiveButton button)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
Transform transform = ((Component)button).transform;
RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
if (!((Object)(object)val == (Object)null))
{
Image val2 = UIFactory.CreateImage("PreselectOverlay", (Transform)(object)val, UIColors.WithAlpha(UIColors.Macaroon, PathLogic.IsEditing ? 0.3f : 0.18f), false);
UIFactory.ApplyWhiteSprite(val2);
UIHelpers.SetFillParent(((Graphic)val2).rectTransform, 2f);
((Transform)((Graphic)val2).rectTransform).SetAsLastSibling();
state.Overlays.Add(((Component)val2).gameObject);
}
}
private static void ApplyOutline(DirectiveButton button, bool selected)
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
try
{
object? obj = OutlineField?.GetValue(button);
PolygonOutline val = (PolygonOutline)((obj is PolygonOutline) ? obj : null);
if (!((Object)(object)val == (Object)null) && selected)
{
((Component)val).gameObject.SetActive(true);
((Graphic)val).color = UIColors.Macaroon;
((OutlineGraphic)val).SetValue(PathLogic.IsEditing ? 10f : 7f);
}
}
catch
{
}
}
private static void ClearVisuals(VisualState state)
{
if (state != null)
{
for (int i = 0; i < state.Lines.Count; i++)
{
UIHelpers.DestroySafe((Object)(object)state.Lines[i]);
}
state.Lines.Clear();
for (int j = 0; j < state.Badges.Count; j++)
{
UIHelpers.DestroySafe((Object)(object)state.Badges[j]);
}
state.Badges.Clear();
for (int k = 0; k < state.Overlays.Count; k++)
{
UIHelpers.DestroySafe((Object)(object)state.Overlays[k]);
}
state.Overlays.Clear();
}
}
}
[BepInPlugin("sparroh.backlogimprovements", "BacklogImprovements", "2.1.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class BacklogImprovementsPlugin : BaseUnityPlugin
{
public const string PluginGUID = "sparroh.backlogimprovements";
public const string PluginName = "BacklogImprovements";
public const string PluginVersion = "2.1.0";
public const string LegacyPreselectGuid = "sparroh.preselectbacklog";
internal static ManualLogSource Log;
public static BacklogImprovementsPlugin Instance;
public static ConfigEntry<bool> EnablePreselect;
public static ConfigEntry<bool> EnableReroll;
public static ConfigEntry<bool> EnableFreePages;
public static ConfigEntry<int> CostPerDirective;
private const bool sparrohmode = false;
private Harmony _harmony;
private InputAction _forceCompleteAction;
private void Awake()
{
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Instance = this;
EnablePreselect = ((BaseUnityPlugin)this).Config.Bind<bool>("Features", "EnablePreselect", true, "Enable path preselect, auto-claim, and auto-activate.");
EnableReroll = ((BaseUnityPlugin)this).Config.Bind<bool>("Features", "EnableReroll", true, "Enable reroll page / reroll one controls.");
EnableFreePages = ((BaseUnityPlugin)this).Config.Bind<bool>("Features", "EnableFreePages", true, "Remove the resource cost for generating the next backlog page.");
CostPerDirective = ((BaseUnityPlugin)this).Config.Bind<int>("Reroll", "CostPerDirective", 50, "Gats cost to reroll a single backlog directive. Page reroll costs this amount times the number of eligible directives.");
PathStore.Load();
try
{
_harmony = new Harmony("sparroh.backlogimprovements");
_harmony.PatchAll();
Log.LogInfo((object)"BacklogImprovements v2.1.0 loaded.");
}
catch (Exception arg)
{
Log.LogError((object)string.Format("Failed to initialize {0}: {1}", "BacklogImprovements", arg));
}
SetupForceCompleteAction();
}
private void SetupForceCompleteAction()
{
try
{
InputAction forceCompleteAction = _forceCompleteAction;
if (forceCompleteAction != null)
{
forceCompleteAction.Dispose();
}
_forceCompleteAction = null;
}
catch (Exception ex)
{
ManualLogSource log = Log;
if (log != null)
{
log.LogWarning((object)("Could not bind force-complete key: " + ex.Message));
}
}
}
private void OnDestroy()
{
try
{
InputAction forceCompleteAction = _forceCompleteAction;
if (forceCompleteAction != null)
{
forceCompleteAction.Disable();
}
InputAction forceCompleteAction2 = _forceCompleteAction;
if (forceCompleteAction2 != null)
{
forceCompleteAction2.Dispose();
}
_forceCompleteAction = null;
BacklogUI.CleanupAll();
PathStore.Save();
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
catch (Exception ex)
{
ManualLogSource log = Log;
if (log != null)
{
log.LogError((object)("Cleanup failed: " + ex.Message));
}
}
}
}
public static class RerollLogic
{
public static int CostPerDirective => Mathf.Max(0, BacklogImprovementsPlugin.CostPerDirective?.Value ?? 50);
public static bool IsEligible(DirectiveInstance directive)
{
if (directive == null)
{
return false;
}
if (!directive.IsActive)
{
return !directive.IsComplete;
}
return false;
}
public static int CountEligible()
{
PlayerData instance = PlayerData.Instance;
if (instance?.defaultDirectives == null)
{
return 0;
}
int num = 0;
for (int i = 0; i < instance.defaultDirectives.Length; i++)
{
if (IsEligible(instance.defaultDirectives[i]))
{
num++;
}
}
return num;
}
public static int GetPageRerollCost()
{
return CountEligible() * CostPerDirective;
}
public static int GetSingleRerollCost()
{
return CostPerDirective;
}
public static bool CanAfford(int cost)
{
if (cost <= 0)
{
return true;
}
PlayerData instance = PlayerData.Instance;
Global instance2 = Global.Instance;
PlayerResource val = ((instance2 != null) ? instance2.ScripResource : null);
if (instance == null || (Object)(object)val == (Object)null)
{
return false;
}
return instance.CanAffordCost(val, cost);
}
public static bool TryCharge(int cost)
{
if (cost <= 0)
{
return true;
}
PlayerData instance = PlayerData.Instance;
Global instance2 = Global.Instance;
PlayerResource val = ((instance2 != null) ? instance2.ScripResource : null);
if (instance == null || (Object)(object)val == (Object)null)
{
return false;
}
return instance.TryRemoveResource(val, cost);
}
public static bool TryRerollSingle(int index, out string error)
{
error = null;
PlayerData instance = PlayerData.Instance;
if (instance?.defaultDirectives == null)
{
error = "Player data not ready.";
return false;
}
if (index < 0 || index >= instance.defaultDirectives.Length)
{
error = "Invalid directive.";
return false;
}
if (!IsEligible(instance.defaultDirectives[index]))
{
error = "That directive cannot be rerolled (active or already complete).";
return false;
}
int singleRerollCost = GetSingleRerollCost();
if (!CanAfford(singleRerollCost))
{
error = $"Not enough gats (need {singleRerollCost}).";
return false;
}
if (!TryCharge(singleRerollCost))
{
error = $"Not enough gats (need {singleRerollCost}).";
return false;
}
ReplaceAt(instance, index);
return true;
}
public static bool TryRerollPage(out int rerolledCount, out string error)
{
rerolledCount = 0;
error = null;
PlayerData instance = PlayerData.Instance;
if (instance?.defaultDirectives == null)
{
error = "Player data not ready.";
return false;
}
List<int> list = new List<int>();
for (int i = 0; i < instance.defaultDirectives.Length; i++)
{
if (IsEligible(instance.defaultDirectives[i]))
{
list.Add(i);
}
}
if (list.Count == 0)
{
error = "No eligible directives to reroll.";
return false;
}
int num = list.Count * CostPerDirective;
if (!CanAfford(num))
{
error = $"Not enough gats (need {num}).";
return false;
}
if (!TryCharge(num))
{
error = $"Not enough gats (need {num}).";
return false;
}
for (int j = 0; j < list.Count; j++)
{
ReplaceAt(instance, list[j]);
}
rerolledCount = list.Count;
return true;
}
private static void ReplaceAt(PlayerData data, int index)
{
int tierFromDirectiveIndex = data.GetTierFromDirectiveIndex(index);
try
{
DirectiveInstance obj = data.defaultDirectives[index];
if (obj != null)
{
obj.Destroy();
}
}
catch (Exception ex)
{
ManualLogSource log = BacklogImprovementsPlugin.Log;
if (log != null)
{
log.LogWarning((object)$"Destroy directive {index}: {ex.Message}");
}
}
data.defaultDirectives[index] = data.CreateDirective(tierFromDirectiveIndex);
}
public static int IndexOf(DirectiveInstance directive)
{
PlayerData instance = PlayerData.Instance;
if (instance?.defaultDirectives == null || directive == null)
{
return -1;
}
return Array.IndexOf(instance.defaultDirectives, directive);
}
}
namespace BacklogImprovements
{
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "BacklogImprovements";
public const string PLUGIN_NAME = "BacklogImprovements";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}