using System;
using System.Collections.Generic;
using System.Diagnostics;
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 UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("StonewardsRoomChestTracker")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("StonewardsRoomChestTracker")]
[assembly: AssemblyTitle("StonewardsRoomChestTracker")]
[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;
}
}
}
namespace StonewardsRoomChestTracker
{
[BepInPlugin("com.ellenashley.stonewards.roomchesttracker", "Stonewards Room & Chest Tracker", "0.1.0")]
public sealed class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "com.ellenashley.stonewards.roomchesttracker";
public const string PluginName = "Stonewards Room & Chest Tracker";
public const string PluginVersion = "0.1.0";
internal static ManualLogSource Log;
private ConfigEntry<KeyboardShortcut> toggleKey;
private ConfigEntry<bool> startEnabled;
private ConfigEntry<float> updateInterval;
private ConfigEntry<float> panelWidth;
private ConfigEntry<float> panelHeight;
private ConfigEntry<float> positionX;
private ConfigEntry<float> positionY;
private ConfigEntry<float> scale;
private ConfigEntry<float> alpha;
private ConfigEntry<bool> showFoundTotals;
private readonly HashSet<string> discoveredRoomIndices = new HashSet<string>(StringComparer.Ordinal);
private string runKey;
private string activeSceneName;
private int maxRooms = -1;
private bool trackerEnabled = true;
private float nextRefresh;
private Canvas canvas;
private RectTransform panel;
private Text titleText;
private Text roomsText;
private Text chestsText;
private Text detailText;
private Harmony harmony;
private static readonly BindingFlags AllInstance = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
private static readonly BindingFlags AllStatic = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
internal static Plugin Instance { get; private set; }
private void Awake()
{
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
//IL_01bd: Expected O, but got Unknown
Instance = this;
toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("UI", "ToggleKey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Show/hide the tracker.");
startEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "StartEnabled", true, "Show the tracker automatically when a cave map loads.");
updateInterval = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "UpdateInterval", 0.25f, "How often the counts are refreshed.");
panelWidth = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "PanelWidth", 330f, "Tracker panel width in pixels.");
panelHeight = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "PanelHeight", 145f, "Tracker panel height in pixels.");
positionX = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "PositionX", 25f, "Distance from the right edge of the screen.");
positionY = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "PositionY", 25f, "Distance from the top edge of the screen.");
scale = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "Scale", 1f, "Overall UI scale.");
alpha = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "BackgroundAlpha", 0.82f, "Background opacity.");
showFoundTotals = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowFoundTotals", true, "Show rooms found / total beneath the remaining count.");
Log = ((BaseUnityPlugin)this).Logger;
trackerEnabled = startEnabled.Value;
BuildUi();
SceneManager.activeSceneChanged += OnActiveSceneChanged;
harmony = new Harmony("com.ellenashley.stonewards.roomchesttracker");
harmony.PatchAll();
((BaseUnityPlugin)this).Logger.LogInfo((object)"Stonewards Room & Chest Tracker v0.1.0 loaded.");
}
private void OnDestroy()
{
SceneManager.activeSceneChanged -= OnActiveSceneChanged;
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
Instance = null;
}
private void Update()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
KeyboardShortcut value = toggleKey.Value;
if (((KeyboardShortcut)(ref value)).IsDown())
{
trackerEnabled = !trackerEnabled;
}
UpdateUiVisibility();
if (trackerEnabled && IsCaveMap() && Time.unscaledTime >= nextRefresh)
{
nextRefresh = Time.unscaledTime + Mathf.Max(0.05f, updateInterval.Value);
RefreshState();
}
}
private void OnActiveSceneChanged(Scene previous, Scene next)
{
activeSceneName = ((Scene)(ref next)).name;
ResetRunState();
trackerEnabled = startEnabled.Value;
UpdateUiVisibility();
}
internal void RecordPatternChange()
{
if (IsCaveMap())
{
object diggingManager = GetDiggingManager();
if (diggingManager != null)
{
RecordCurrentPattern(diggingManager);
}
}
}
private void RefreshState()
{
try
{
object diggingManager = GetDiggingManager();
if (diggingManager == null)
{
ShowCounts("Waiting for cave...", "", "");
return;
}
UpdateRunKey(diggingManager);
UpdateMaxRooms(diggingManager);
RecordCurrentPattern(diggingManager);
int num = CountUnopenedChests();
int num2 = ((maxRooms < 0) ? (-1) : Mathf.Max(0, maxRooms - discoveredRoomIndices.Count));
string roomLine = ((num2 < 0) ? "Rooms left: ?" : $"Rooms left: {num2}");
string chestLine = $"Chests left: {num}";
string detail = ((showFoundTotals.Value && maxRooms >= 0) ? $"Rooms found: {discoveredRoomIndices.Count} / {maxRooms}" : "Unique generated rooms visited this run");
ShowCounts(roomLine, chestLine, detail);
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"Tracker refresh failed: {arg}");
ShowCounts("Rooms left: ?", "Chests left: ?", "See BepInEx log for details.");
}
}
private void UpdateRunKey(object manager)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
string name = ((Scene)(ref activeScene)).name;
object memberValue = GetMemberValue(manager, manager.GetType(), "worldSeed");
string b = name + "|" + ((memberValue == null) ? "?" : Convert.ToString(memberValue));
if (runKey == null)
{
runKey = b;
}
else if (!string.Equals(runKey, b, StringComparison.Ordinal))
{
runKey = b;
ResetRoomDiscoveryOnly();
((BaseUnityPlugin)this).Logger.LogInfo((object)("New Stonewards run detected: " + runKey));
}
}
private void UpdateMaxRooms(object manager)
{
object obj = GetMemberValue(manager, manager.GetType(), "caveLevelGenerator");
if (obj == null)
{
PropertyInfo property = manager.GetType().GetProperty("CaveLevelGenerator", AllInstance);
if (property != null)
{
obj = property.GetValue(manager, null);
}
}
if (obj == null)
{
return;
}
object memberValue = GetMemberValue(obj, obj.GetType(), "caveLevelGenerationSO");
if (memberValue != null)
{
object memberValue2 = GetMemberValue(memberValue, memberValue.GetType(), "MaxRooms");
if (memberValue2 == null)
{
memberValue2 = GetMemberValue(memberValue, memberValue.GetType(), "maxRooms");
}
if (memberValue2 != null && int.TryParse(Convert.ToString(memberValue2), out var result))
{
maxRooms = result;
}
}
}
private void RecordCurrentPattern(object manager)
{
object memberValue = GetMemberValue(manager, manager.GetType(), "syncDiggingPatternIndex");
if (memberValue != null)
{
string text = Convert.ToString(memberValue);
if (!string.IsNullOrEmpty(text))
{
discoveredRoomIndices.Add(text);
}
}
}
private int CountUnopenedChests()
{
return 0 + CountUnopenedByType("Chest") + CountUnopenedByType("TreasureChest");
}
private int CountUnopenedByType(string typeName)
{
Type type = FindGameType(typeName);
if (type == null || !typeof(Component).IsAssignableFrom(type))
{
return 0;
}
Object[] array = Object.FindObjectsOfType(type);
int num = 0;
Object[] array2 = array;
foreach (Object obj in array2)
{
Component val = (Component)(object)((obj is Component) ? obj : null);
if (!((Object)(object)val == (Object)null) && !((Object)(object)val.gameObject == (Object)null) && val.gameObject.activeInHierarchy)
{
object memberValue = GetMemberValue(val, ((object)val).GetType(), "isOpened");
if (memberValue is bool && !(bool)memberValue)
{
num++;
}
}
}
return num;
}
private static object GetMemberValue(object target, Type type, string name)
{
if (target == null)
{
return null;
}
FieldInfo field = type.GetField(name, AllInstance | AllStatic);
if (field != null)
{
return field.GetValue(target);
}
PropertyInfo property = type.GetProperty(name, AllInstance | AllStatic);
if (property != null && property.GetIndexParameters().Length == 0)
{
try
{
return property.GetValue(target, null);
}
catch
{
return null;
}
}
return null;
}
private static Type FindGameType(string typeName)
{
Type type = Type.GetType(typeName + ", Assembly-CSharp");
if (type != null)
{
return type;
}
return typeof(Plugin).Assembly.GetType(typeName) ?? AppDomain.CurrentDomain.GetAssemblies()[0].GetType(typeName);
}
private static object GetDiggingManager()
{
Type type = FindGameType("DiggingManager");
if (type == null)
{
return null;
}
FieldInfo field = type.GetField("Instance", AllStatic);
if (field == null)
{
return null;
}
return field.GetValue(null);
}
private void ResetRunState()
{
runKey = null;
maxRooms = -1;
discoveredRoomIndices.Clear();
}
private void ResetRoomDiscoveryOnly()
{
discoveredRoomIndices.Clear();
}
private bool IsCaveMap()
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Scene activeScene = SceneManager.GetActiveScene();
string name = ((Scene)(ref activeScene)).name;
if (!string.IsNullOrEmpty(name))
{
return name.StartsWith("MAP_", StringComparison.OrdinalIgnoreCase);
}
return false;
}
private void BuildUi()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Expected O, but got Unknown
//IL_004a: 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)
//IL_006c: Expected O, but got Unknown
//IL_00af: 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)
//IL_00e3: 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)
GameObject val = new GameObject("StonewardsRoomChestTrackerCanvas");
canvas = val.AddComponent<Canvas>();
canvas.renderMode = (RenderMode)0;
canvas.sortingOrder = 5000;
CanvasScaler obj = val.AddComponent<CanvasScaler>();
obj.uiScaleMode = (ScaleMode)1;
obj.referenceResolution = new Vector2(1920f, 1080f);
val.AddComponent<GraphicRaycaster>();
Object.DontDestroyOnLoad((Object)(object)val);
GameObject val2 = new GameObject("TrackerPanel");
val2.transform.SetParent(((Component)canvas).transform, false);
panel = val2.AddComponent<RectTransform>();
((Graphic)val2.AddComponent<Image>()).color = new Color(0.02f, 0.03f, 0.05f, alpha.Value);
panel.anchorMin = new Vector2(1f, 1f);
panel.anchorMax = new Vector2(1f, 1f);
panel.pivot = new Vector2(1f, 1f);
MakeText(val2.transform, "Title", "WORLD STATUS", 22, (FontStyle)1, out titleText);
MakeText(val2.transform, "Rooms", "Rooms left: ?", 30, (FontStyle)1, out roomsText);
MakeText(val2.transform, "Chests", "Chests left: ?", 30, (FontStyle)1, out chestsText);
MakeText(val2.transform, "Detail", "", 17, (FontStyle)0, out detailText);
ApplyUiLayout();
}
private void MakeText(Transform parent, string name, string value, int fontSize, FontStyle style, out Text text)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
//IL_0045: 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_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name);
val.transform.SetParent(parent, false);
text = val.AddComponent<Text>();
text.text = value;
text.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
text.fontSize = fontSize;
text.fontStyle = style;
((Graphic)text).color = Color.white;
text.alignment = (TextAnchor)3;
text.horizontalOverflow = (HorizontalWrapMode)1;
text.verticalOverflow = (VerticalWrapMode)1;
RectTransform component = val.GetComponent<RectTransform>();
component.anchorMin = new Vector2(0f, 1f);
component.anchorMax = new Vector2(1f, 1f);
component.pivot = new Vector2(0.5f, 1f);
}
private void ApplyUiLayout()
{
//IL_002b: 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_0063: 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)
if (!((Object)(object)panel == (Object)null))
{
panel.sizeDelta = new Vector2(panelWidth.Value, panelHeight.Value);
panel.anchoredPosition = new Vector2(0f - positionX.Value, 0f - positionY.Value);
((Transform)panel).localScale = Vector3.one * Mathf.Max(0.25f, scale.Value);
LayoutText(titleText, 8f, -8f, 20f, 34f);
LayoutText(roomsText, 8f, -43f, 20f, 40f);
LayoutText(chestsText, 8f, -82f, 20f, 40f);
LayoutText(detailText, 8f, -122f, 20f, 24f);
}
}
private static void LayoutText(Text text, float x, float y, float width, float height)
{
//IL_001b: 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_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)text == (Object)null))
{
RectTransform rectTransform = ((Graphic)text).rectTransform;
rectTransform.anchorMin = new Vector2(0f, 1f);
rectTransform.anchorMax = new Vector2(1f, 1f);
rectTransform.offsetMin = new Vector2(x, y - height);
rectTransform.offsetMax = new Vector2(0f - x, y);
}
}
private void ShowCounts(string roomLine, string chestLine, string detail)
{
if ((Object)(object)roomsText != (Object)null)
{
roomsText.text = roomLine;
}
if ((Object)(object)chestsText != (Object)null)
{
chestsText.text = chestLine;
}
if ((Object)(object)detailText != (Object)null)
{
detailText.text = detail;
}
}
private void UpdateUiVisibility()
{
bool active = trackerEnabled && IsCaveMap();
if ((Object)(object)canvas != (Object)null)
{
((Component)canvas).gameObject.SetActive(active);
}
}
}
[HarmonyPatch(typeof(DiggingManager), "OnPatternChange")]
internal static class DiggingManagerOnPatternChangePatch
{
private static void Postfix()
{
try
{
Plugin.Instance?.RecordPatternChange();
}
catch (Exception ex)
{
ManualLogSource log = Plugin.Log;
if (log != null)
{
log.LogDebug((object)("OnPatternChange capture failed: " + ex.Message));
}
}
}
}
}