Decompiled source of Room And Chest Tracker v1.2.0

BepInEx/plugins/StonewardsRoomChestTracker.dll

Decompiled 15 hours ago
using System;
using System.Collections;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using Mirror;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace StonewardsRoomChestTracker;

[BepInPlugin("com.ellenashley.stonewards.roomchesttracker", "Stonewards Room & Chest Tracker", "0.2.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.2.0";

	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 bool trackerEnabled;

	private float nextRefresh;

	private bool clientHandlerRegistered;

	private bool haveServerState;

	private int syncedRoomsLeft = -1;

	private int syncedRoomsFound = -1;

	private int syncedRoomsTotal = -1;

	private int syncedChestsLeft = -1;

	private Canvas canvas;

	private RectTransform panel;

	private Image background;

	private Text titleText;

	private Text roomsText;

	private Text chestsText;

	private Text detailText;

	private float lastW;

	private float lastH;

	private float lastX;

	private float lastY;

	private float lastScale;

	private float lastAlpha;

	private bool lastShowTotals;

	private static readonly BindingFlags Inst = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

	private static readonly BindingFlags Stat = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;

	internal static Plugin Instance { get; private set; }

	private void Awake()
	{
		//IL_0022: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("UI", "ToggleKey", new KeyboardShortcut((KeyCode)288, (KeyCode[])(object)new KeyCode[0]), "Show/hide the tracker.");
		startEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "StartEnabled", true, "Show the tracker automatically on cave maps.");
		updateInterval = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "UpdateInterval", 0.25f, "State refresh interval in seconds.");
		panelWidth = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "PanelWidth", 220f, "Tracker width in pixels.");
		panelHeight = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "PanelHeight", 82f, "Tracker height in pixels.");
		positionX = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "PositionX", 25f, "Distance from the LEFT edge of the screen.");
		positionY = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "PositionY", 90f, "Distance from the TOP edge of the screen.");
		scale = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "Scale", 0.8f, "Overall tracker scale.");
		alpha = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "BackgroundAlpha", 0.72f, "Tracker background opacity.");
		showFoundTotals = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ShowFoundTotals", false, "Show rooms found / total.");
		trackerEnabled = startEnabled.Value;
		BuildUi();
		SceneManager.activeSceneChanged += OnActiveSceneChanged;
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Stonewards Room & Chest Tracker v0.2.0 loaded.");
	}

	private void OnDestroy()
	{
		SceneManager.activeSceneChanged -= OnActiveSceneChanged;
		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;
		}
		ApplyUiIfChanged();
		UpdateUiVisibility();
		if (trackerEnabled && IsCaveMap())
		{
			RegisterClientHandlerIfNeeded();
			if (Time.unscaledTime >= nextRefresh)
			{
				nextRefresh = Time.unscaledTime + Mathf.Max(0.05f, updateInterval.Value);
				Refresh();
			}
		}
	}

	private void OnActiveSceneChanged(Scene oldScene, Scene newScene)
	{
		trackerEnabled = startEnabled.Value;
		haveServerState = false;
		syncedRoomsLeft = (syncedRoomsFound = (syncedRoomsTotal = (syncedChestsLeft = -1)));
		clientHandlerRegistered = false;
		UpdateUiVisibility();
	}

	private void RegisterClientHandlerIfNeeded()
	{
		if (NetworkClient.active && !clientHandlerRegistered)
		{
			NetworkClient.RegisterHandler<TrackerStateMessage>((Action<TrackerStateMessage>)OnTrackerState, true);
			clientHandlerRegistered = true;
		}
	}

	private void OnTrackerState(TrackerStateMessage msg)
	{
		syncedRoomsLeft = msg.roomsLeft;
		syncedRoomsFound = msg.roomsFound;
		syncedRoomsTotal = msg.roomsTotal;
		syncedChestsLeft = msg.chestsLeft;
		haveServerState = true;
	}

	private void Refresh()
	{
		try
		{
			if (NetworkServer.active)
			{
				int maxRooms = GetMaxRooms();
				int generatedPatternCount = GetGeneratedPatternCount();
				int roomsLeft = ((maxRooms >= 0 && generatedPatternCount >= 0) ? Mathf.Max(0, maxRooms - generatedPatternCount) : (-1));
				int roomsFound = ((maxRooms >= 0 && generatedPatternCount >= 0) ? generatedPatternCount : (-1));
				int chestsLeft = CountUnopenedChests();
				syncedRoomsLeft = roomsLeft;
				syncedRoomsFound = roomsFound;
				syncedRoomsTotal = maxRooms;
				syncedChestsLeft = chestsLeft;
				haveServerState = true;
				NetworkServer.SendToAll<TrackerStateMessage>(new TrackerStateMessage
				{
					roomsLeft = roomsLeft,
					roomsFound = roomsFound,
					roomsTotal = maxRooms,
					chestsLeft = chestsLeft
				}, 0, false);
			}
			if (haveServerState)
			{
				string room = ((syncedRoomsLeft < 0) ? "Rooms left: ?" : ("Rooms left: " + syncedRoomsLeft));
				string chest = ((syncedChestsLeft < 0) ? "Chests left: ?" : ("Chests left: " + syncedChestsLeft));
				string detail = ((showFoundTotals.Value && syncedRoomsTotal >= 0) ? ("Found: " + Mathf.Max(0, syncedRoomsFound) + " / " + syncedRoomsTotal) : "");
				ShowCounts(room, chest, detail);
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Tracker refresh failed: " + ex));
		}
	}

	private int GetMaxRooms()
	{
		object diggingManager = GetDiggingManager();
		if (diggingManager == null)
		{
			return -1;
		}
		object member = GetMember(diggingManager, "caveLevelGenerator");
		if (member == null)
		{
			member = GetMember(diggingManager, "CaveLevelGenerator");
		}
		if (member == null)
		{
			return -1;
		}
		object member2 = GetMember(member, "caveLevelGenerationSO");
		if (member2 == null)
		{
			return -1;
		}
		object value = GetMember(member2, "MaxRooms") ?? GetMember(member2, "maxRooms");
		return TryInt(value);
	}

	private int GetGeneratedPatternCount()
	{
		object diggingManager = GetDiggingManager();
		if (diggingManager == null)
		{
			return -1;
		}
		return GetCollectionCount(GetMember(diggingManager, "generatedPatterns"));
	}

	private int CountUnopenedChests()
	{
		int num = 0;
		num += CountType("Chest");
		return num + CountType("TreasureChest");
	}

	private int CountType(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 val in array2)
		{
			Component val2 = (Component)(object)((val is Component) ? val : null);
			if (!((Object)(object)val2 == (Object)null) && Object.op_Implicit((Object)(object)val2.gameObject) && val2.gameObject.activeInHierarchy)
			{
				object member = GetMember(val2, "NetworkisOpened");
				if (!(member is bool))
				{
					member = GetMember(val2, "isOpened");
				}
				if (member is bool && !(bool)member)
				{
					num++;
				}
			}
		}
		return num;
	}

	private static int GetCollectionCount(object value)
	{
		if (value == null)
		{
			return -1;
		}
		if (value is ICollection collection)
		{
			return collection.Count;
		}
		PropertyInfo property = value.GetType().GetProperty("Count", Inst);
		if (property != null && property.PropertyType == typeof(int))
		{
			try
			{
				return (int)property.GetValue(value, null);
			}
			catch
			{
			}
		}
		if (!(value is IEnumerable enumerable))
		{
			return -1;
		}
		int num = 0;
		foreach (object item in enumerable)
		{
			_ = item;
			num++;
		}
		return num;
	}

	private static int TryInt(object value)
	{
		if (value == null)
		{
			return -1;
		}
		try
		{
			return Convert.ToInt32(value);
		}
		catch
		{
			return -1;
		}
	}

	private static object GetMember(object target, string name)
	{
		if (target == null)
		{
			return null;
		}
		Type type = target.GetType();
		FieldInfo field = type.GetField(name, Inst | Stat);
		if (field != null)
		{
			try
			{
				return field.GetValue(target);
			}
			catch
			{
			}
		}
		PropertyInfo property = type.GetProperty(name, Inst | Stat);
		if (property != null && property.GetIndexParameters().Length == 0)
		{
			try
			{
				return property.GetValue(target, null);
			}
			catch
			{
			}
		}
		return null;
	}

	private static Type FindGameType(string name)
	{
		Type type = Type.GetType(name + ", Assembly-CSharp");
		if (type != null)
		{
			return type;
		}
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			try
			{
				type = assembly.GetType(name);
				if (type != null)
				{
					return type;
				}
			}
			catch
			{
			}
		}
		return null;
	}

	private static object GetDiggingManager()
	{
		Type type = FindGameType("DiggingManager");
		if (type == null)
		{
			return null;
		}
		FieldInfo fieldInfo = type.GetField("Instance", Stat) ?? type.GetField("instance", Stat);
		if (!(fieldInfo == null))
		{
			return fieldInfo.GetValue(null);
		}
		return null;
	}

	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_004c: 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_006e: Expected O, but got Unknown
		GameObject val = new GameObject("StonewardsRoomChestTrackerCanvas");
		canvas = val.AddComponent<Canvas>();
		canvas.renderMode = (RenderMode)0;
		canvas.sortingOrder = 5000;
		CanvasScaler val2 = val.AddComponent<CanvasScaler>();
		val2.uiScaleMode = (ScaleMode)1;
		val2.referenceResolution = new Vector2(1920f, 1080f);
		val.AddComponent<GraphicRaycaster>();
		Object.DontDestroyOnLoad((Object)(object)val);
		GameObject val3 = new GameObject("TrackerPanel");
		val3.transform.SetParent(((Component)canvas).transform, false);
		panel = val3.AddComponent<RectTransform>();
		background = val3.AddComponent<Image>();
		ApplyUiBackground();
		MakeText(val3.transform, "Title", "WORLD STATUS", 15, (FontStyle)1, out titleText);
		MakeText(val3.transform, "Rooms", "Rooms left: ?", 20, (FontStyle)1, out roomsText);
		MakeText(val3.transform, "Chests", "Chests left: ?", 20, (FontStyle)1, out chestsText);
		MakeText(val3.transform, "Detail", "", 12, (FontStyle)0, out detailText);
		ApplyUiLayout();
	}

	private void MakeText(Transform parent, string name, string value, int size, 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_0088: Unknown result type (might be due to invalid IL or missing references)
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		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 = size;
		text.fontStyle = style;
		((Graphic)text).color = Color.white;
		text.alignment = (TextAnchor)3;
		text.horizontalOverflow = (HorizontalWrapMode)1;
		text.verticalOverflow = (VerticalWrapMode)1;
		RectTransform rectTransform = ((Graphic)text).rectTransform;
		rectTransform.anchorMin = new Vector2(0f, 1f);
		rectTransform.anchorMax = new Vector2(1f, 1f);
		rectTransform.pivot = new Vector2(0.5f, 1f);
	}

	private void ApplyUiIfChanged()
	{
		if (!((Object)(object)panel == (Object)null) && (lastW != panelWidth.Value || lastH != panelHeight.Value || lastX != positionX.Value || lastY != positionY.Value || lastScale != scale.Value || lastAlpha != alpha.Value || lastShowTotals != showFoundTotals.Value))
		{
			ApplyUiLayout();
			ApplyUiBackground();
		}
	}

	private void ApplyUiLayout()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0044: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
		panel.anchorMin = new Vector2(0f, 1f);
		panel.anchorMax = new Vector2(0f, 1f);
		panel.pivot = new Vector2(0f, 1f);
		panel.sizeDelta = new Vector2(Mathf.Max(120f, panelWidth.Value), Mathf.Max(60f, panelHeight.Value));
		panel.anchoredPosition = new Vector2(Mathf.Max(0f, positionX.Value), 0f - Mathf.Max(0f, positionY.Value));
		((Transform)panel).localScale = Vector3.one * Mathf.Clamp(scale.Value, 0.25f, 3f);
		LayoutText(titleText, 8f, -6f, 18f);
		LayoutText(roomsText, 8f, -28f, 24f);
		LayoutText(chestsText, 8f, -51f, 24f);
		LayoutText(detailText, 8f, -72f, 16f);
		lastW = panelWidth.Value;
		lastH = panelHeight.Value;
		lastX = positionX.Value;
		lastY = positionY.Value;
		lastScale = scale.Value;
		lastShowTotals = showFoundTotals.Value;
	}

	private static void LayoutText(Text text, float x, float y, float height)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)text == (Object)null))
		{
			RectTransform rectTransform = ((Graphic)text).rectTransform;
			rectTransform.offsetMin = new Vector2(x, y - height);
			rectTransform.offsetMax = new Vector2(0f - x, y);
		}
	}

	private void ApplyUiBackground()
	{
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)background == (Object)null))
		{
			((Graphic)background).color = new Color(0.02f, 0.03f, 0.05f, Mathf.Clamp01(alpha.Value));
			lastAlpha = alpha.Value;
		}
	}

	private void ShowCounts(string room, string chest, string detail)
	{
		roomsText.text = room;
		chestsText.text = chest;
		detailText.text = (showFoundTotals.Value ? detail : "");
	}

	private void UpdateUiVisibility()
	{
		if ((Object)(object)canvas != (Object)null)
		{
			((Component)canvas).gameObject.SetActive(trackerEnabled && IsCaveMap());
		}
	}
}
public struct TrackerStateMessage : NetworkMessage
{
	public int roomsLeft;

	public int roomsFound;

	public int roomsTotal;

	public int chestsLeft;
}