Decompiled source of RossPortalsPatch v1.0.1

RossPortalsPatch.dll

Decompiled 2 days ago
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.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RossPortalsPatch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("RossPortalsPatch")]
[assembly: AssemblyTitle("RossPortalsPatch")]
[assembly: AssemblyVersion("1.0.1.0")]
[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 RossPortalsPatch
{
	[BepInPlugin("com.dreich.rossportalspatch", "RossPortalsPatch", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class RossPortalsPatchPlugin : BaseUnityPlugin
	{
		public const string Guid = "com.dreich.rossportalspatch";

		public const string Name = "RossPortalsPatch";

		public const string Version = "1.0.1";

		public const string RossPortalsGuid = "com.rossdwest.rossportals";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> ScaleWithGameGui;

		internal static ConfigEntry<float> ExtraPanelScale;

		private Harmony _harmony;

		private bool _headless;

		private void Awake()
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Invalid comparison between Unknown and I4
			Log = ((BaseUnityPlugin)this).Logger;
			_harmony = new Harmony("com.dreich.rossportalspatch");
			ScaleWithGameGui = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "ScaleWithGameGui", true, "Scale the RossPortals panel the same way Valheim scales its own UI (screen resolution x the GUI Scale slider in Settings > Accessibility).");
			ExtraPanelScale = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "ExtraPanelScale", 1f, new ConfigDescription("Extra multiplier on top of the game's GUI scale, for the portal panel only.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 2f), Array.Empty<object>()));
			LinkPersistence.Apply(_harmony);
			_headless = (int)SystemInfo.graphicsDeviceType == 4;
			if (!_headless)
			{
				PanelScaler.Init();
			}
			Log.LogInfo((object)"RossPortalsPatch 1.0.1 loaded");
		}

		private void LateUpdate()
		{
			if (!_headless)
			{
				PanelScaler.Tick();
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class LinkPersistence
	{
		private const string KeyTarget = "RossPortals_TargetId";

		private const string KeyPrevious = "RossPortals_PreviousId";

		private const string LegacyKeyTarget = "XPortal_TargetId";

		private const string LegacyKeyPrevious = "XPortal_PreviousId";

		internal const string KeyUid = "RossPortalsPatch_Uid";

		internal const string KeyTargetUid = "RossPortalsPatch_TargetUid";

		private const string NoTarget = "none";

		private static FieldInfo _recordId;

		public static void Apply(Harmony harmony)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Expected O, but got Unknown
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			Type type = AccessTools.TypeByName("RossPortals.Game.Portals.PortalZdo");
			Type type2 = AccessTools.TypeByName("RossPortals.Game.Portals.PortalRecord");
			MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "RestoreConnections", (Type[])null, (Type[])null));
			MethodInfo methodInfo2 = ((type == null || type2 == null) ? null : AccessTools.Method(type, "Write", new Type[1] { type2 }, (Type[])null));
			_recordId = ((type2 == null) ? null : AccessTools.Field(type2, "Id"));
			if (methodInfo == null || methodInfo2 == null || _recordId == null)
			{
				RossPortalsPatchPlugin.Log.LogError((object)"Could not find RossPortals' PortalZdo.RestoreConnections / Write / PortalRecord.Id. This RossPortals version is not supported; portal links are NOT being fixed.");
				return;
			}
			harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(LinkPersistence), "RestorePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(LinkPersistence), "WritePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			RossPortalsPatchPlugin.Log.LogInfo((object)"Patched RossPortals portal-link persistence (stable portal ids).");
		}

		private static bool RestorePrefix()
		{
			try
			{
				Restore();
				return false;
			}
			catch (Exception ex)
			{
				RossPortalsPatchPlugin.Log.LogError((object)("Portal link restore failed; falling back to RossPortals' own: " + ex));
				return true;
			}
		}

		private static void Restore()
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: 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_005a: 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_0070: 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_0120: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0250: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
			ZDOMan instance = ZDOMan.instance;
			List<ZDO> list = ((instance != null) ? instance.GetPortalList() : null);
			if (list == null || list.Count == 0)
			{
				return;
			}
			Dictionary<ZDOID, ZDOID> dictionary = new Dictionary<ZDOID, ZDOID>();
			foreach (ZDO item in list)
			{
				ZDOID zDOID = item.GetZDOID("RossPortals_PreviousId");
				if (zDOID == ZDOID.None)
				{
					zDOID = item.GetZDOID("XPortal_PreviousId");
				}
				if (zDOID != ZDOID.None)
				{
					dictionary[zDOID] = item.m_uid;
				}
			}
			Dictionary<string, ZDO> dictionary2 = new Dictionary<string, ZDO>();
			Dictionary<ZDOID, string> dictionary3 = new Dictionary<ZDOID, string>();
			int num = 0;
			int num2 = 0;
			foreach (ZDO item2 in list)
			{
				string text = item2.GetString("RossPortalsPatch_Uid", "");
				if (string.IsNullOrEmpty(text) || dictionary2.ContainsKey(text))
				{
					if (!string.IsNullOrEmpty(text))
					{
						num2++;
					}
					text = NewUid();
					Claim(item2);
					item2.Set("RossPortalsPatch_Uid", text);
					num++;
				}
				dictionary2[text] = item2;
				dictionary3[item2.m_uid] = text;
			}
			int num3 = 0;
			int num4 = 0;
			int num5 = 0;
			int num6 = 0;
			int num7 = 0;
			foreach (ZDO item3 in list)
			{
				string text2 = item3.GetString("RossPortalsPatch_TargetUid", "");
				ZDOID val;
				if (text2 == "none")
				{
					val = ZDOID.None;
				}
				else if (!string.IsNullOrEmpty(text2))
				{
					if (dictionary2.TryGetValue(text2, out var value))
					{
						val = value.m_uid;
						num3++;
					}
					else
					{
						val = ZDOID.None;
						num6++;
					}
				}
				else
				{
					ZDOID val2 = LegacyTarget(item3);
					ZDOID value2;
					if (val2 == ZDOID.None)
					{
						val = ZDOID.None;
						item3.Set("RossPortalsPatch_TargetUid", "none");
					}
					else if (dictionary.TryGetValue(val2, out value2))
					{
						val = value2;
						item3.Set("RossPortalsPatch_TargetUid", dictionary3[value2]);
						num4++;
					}
					else
					{
						val = ZDOID.None;
						item3.Set("RossPortalsPatch_TargetUid", "none");
						num5++;
					}
				}
				if (item3.GetConnectionZDOID((ConnectionType)1) != val || item3.GetZDOID("RossPortals_TargetId") != val)
				{
					Claim(item3);
					item3.SetConnection((ConnectionType)1, val);
					item3.Set("RossPortals_TargetId", val);
					num7++;
				}
				RetireLegacyTarget(item3);
			}
			foreach (ZDO item4 in list)
			{
				if (!(item4.GetZDOID("RossPortals_PreviousId") == item4.m_uid))
				{
					Claim(item4);
					item4.Set("RossPortals_PreviousId", item4.m_uid);
				}
			}
			RossPortalsPatchPlugin.Log.LogInfo((object)($"Portal links restored: {list.Count} portal(s); {num3} by stable id, " + $"{num4} migrated from old ids, {num5} unresolvable old link(s) dropped, " + $"{num6} pointing at a missing portal, {num7} connection(s) rewritten, " + string.Format("{0} new stable id(s){1}.", num, (num2 > 0) ? $", {num2} duplicate id(s) replaced" : "")));
		}

		private static ZDOID LegacyTarget(ZDO zdo)
		{
			//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)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			ZDOID zDOID = zdo.GetZDOID("RossPortals_TargetId");
			if (zDOID != ZDOID.None)
			{
				return zDOID;
			}
			if (zdo.GetZDOID("RossPortals_PreviousId") != ZDOID.None)
			{
				return ZDOID.None;
			}
			return zdo.GetZDOID("XPortal_TargetId");
		}

		private static void RetireLegacyTarget(ZDO zdo)
		{
			//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)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (!(zdo.GetZDOID("XPortal_TargetId") == ZDOID.None))
			{
				Claim(zdo);
				zdo.Set("XPortal_TargetId", ZDOID.None);
			}
		}

		private static void WritePostfix(object[] __args)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_0054: 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)
			try
			{
				if (__args == null || __args.Length == 0 || __args[0] == null)
				{
					return;
				}
				ZDOID val = (ZDOID)_recordId.GetValue(__args[0]);
				ZDOMan instance = ZDOMan.instance;
				ZDO val2 = ((instance != null) ? instance.GetZDO(val) : null);
				if (val2 != null)
				{
					EnsureUid(val2);
					ZDOID zDOID = val2.GetZDOID("RossPortals_TargetId");
					if (zDOID == ZDOID.None)
					{
						val2.Set("RossPortalsPatch_TargetUid", "none");
					}
					else
					{
						ZDO zDO = instance.GetZDO(zDOID);
						val2.Set("RossPortalsPatch_TargetUid", (zDO != null) ? EnsureUid(zDO) : string.Empty);
					}
					RetireLegacyTarget(val2);
				}
			}
			catch (Exception ex)
			{
				RossPortalsPatchPlugin.Log.LogError((object)("Failed to record a stable portal link: " + ex));
			}
		}

		private static string EnsureUid(ZDO zdo)
		{
			string text = zdo.GetString("RossPortalsPatch_Uid", "");
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
			text = NewUid();
			Claim(zdo);
			zdo.Set("RossPortalsPatch_Uid", text);
			return text;
		}

		private static string NewUid()
		{
			return Guid.NewGuid().ToString("N");
		}

		private static void Claim(ZDO zdo)
		{
			long sessionID = ZDOMan.GetSessionID();
			if (zdo.GetOwner() != sessionID)
			{
				zdo.SetOwner(sessionID);
			}
		}
	}
	internal static class PanelScaler
	{
		private static PropertyInfo _instance;

		private static FieldInfo _panel;

		private static FieldInfo _largeGuiScale;

		private static FieldInfo _minWidth;

		private static FieldInfo _minHeight;

		private static bool _ready;

		private static GameObject _canvas;

		private static CanvasScaler _scaler;

		private static GameObject _guiFront;

		private static GameObject _hosted;

		public static void Init()
		{
			Type type = AccessTools.TypeByName("RossPortals.Game.UI.PortalConfigPanel");
			_instance = ((type == null) ? null : AccessTools.Property(type, "Instance"));
			_panel = ((type == null) ? null : AccessTools.Field(type, "_panel"));
			_largeGuiScale = AccessTools.Field(typeof(GuiScaler), "m_largeGuiScale");
			_minWidth = AccessTools.Field(typeof(GuiScaler), "m_minWidth");
			_minHeight = AccessTools.Field(typeof(GuiScaler), "m_minHeight");
			_ready = _instance != null && _panel != null;
			if (!_ready)
			{
				RossPortalsPatchPlugin.Log.LogError((object)"Could not find RossPortals' PortalConfigPanel.Instance/_panel; the portal panel will not be scaled.");
			}
			if (_largeGuiScale == null)
			{
				RossPortalsPatchPlugin.Log.LogWarning((object)"GuiScaler.m_largeGuiScale not found; panel scaling will follow resolution only, not the GUI Scale slider.");
			}
		}

		public static void Tick()
		{
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			if (!_ready)
			{
				return;
			}
			object value = _instance.GetValue(null);
			GameObject val = (GameObject)((value == null) ? null : /*isinst with value type is only supported in some contexts*/);
			if ((Object)(object)_canvas != (Object)null && (Object)(object)_guiFront == (Object)null)
			{
				DestroyCanvas();
			}
			if ((Object)(object)_hosted != (Object)null && (Object)(object)_hosted != (Object)(object)val)
			{
				Object.Destroy((Object)(object)_hosted);
				_hosted = null;
			}
			if (!((Object)(object)val == (Object)null) && ((!((Object)(object)_canvas == (Object)null) && !((Object)(object)val.transform.parent != (Object)(object)_canvas.transform)) || Adopt(val)) && val.activeSelf)
			{
				float num = (RossPortalsPatchPlugin.ScaleWithGameGui.Value ? GameGuiScale() : 1f);
				num *= RossPortalsPatchPlugin.ExtraPanelScale.Value;
				num = FitOnScreen((RectTransform)val.transform, num);
				if (!Mathf.Approximately(_scaler.scaleFactor, num))
				{
					_scaler.scaleFactor = num;
				}
			}
		}

		private static bool Adopt(GameObject panel)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Expected O, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			Transform parent = panel.transform.parent;
			if ((Object)(object)parent == (Object)null)
			{
				return false;
			}
			Canvas component = ((Component)parent).GetComponent<Canvas>();
			if ((Object)(object)component == (Object)null || (Object)(object)parent.parent == (Object)null)
			{
				return false;
			}
			if ((Object)(object)_canvas == (Object)null)
			{
				_canvas = new GameObject("RossPortalsPatchGUI", new Type[5]
				{
					typeof(RectTransform),
					typeof(GuiPixelFix),
					typeof(Canvas),
					typeof(CanvasScaler),
					typeof(GraphicRaycaster)
				});
				_canvas.layer = ((Component)parent).gameObject.layer;
				_canvas.transform.SetParent(parent.parent, false);
				RectTransform val = (RectTransform)_canvas.transform;
				val.anchorMin = Vector2.zero;
				val.anchorMax = Vector2.one;
				val.offsetMin = Vector2.zero;
				val.offsetMax = Vector2.zero;
				val.anchoredPosition = Vector2.zero;
				Canvas component2 = _canvas.GetComponent<Canvas>();
				component2.additionalShaderChannels = component.additionalShaderChannels;
				component2.renderMode = (RenderMode)0;
				component2.overrideSorting = true;
				component2.sortingOrder = component.sortingOrder + 1;
				_scaler = _canvas.GetComponent<CanvasScaler>();
				CanvasScaler component3 = ((Component)parent).GetComponent<CanvasScaler>();
				_scaler.referencePixelsPerUnit = (((Object)(object)component3 != (Object)null) ? component3.referencePixelsPerUnit : 50f);
				_scaler.uiScaleMode = (ScaleMode)0;
				_scaler.scaleFactor = 1f;
				_guiFront = ((Component)parent).gameObject;
			}
			panel.transform.SetParent(_canvas.transform, false);
			_hosted = panel;
			return true;
		}

		private static void DestroyCanvas()
		{
			if ((Object)(object)_canvas != (Object)null)
			{
				Object.Destroy((Object)(object)_canvas);
			}
			_canvas = null;
			_scaler = null;
			_guiFront = null;
			_hosted = null;
		}

		private static float GameGuiScale()
		{
			float num = ReadStatic(_minWidth, 1920f);
			float num2 = ReadStatic(_minHeight, 1080f);
			float num3 = ReadStatic(_largeGuiScale, 1f);
			float num4 = Mathf.Min((float)Screen.width / num, (float)Screen.height / num2) * num3;
			if (!(num4 > 0.01f))
			{
				return 1f;
			}
			return num4;
		}

		private static float FitOnScreen(RectTransform rt, float scale)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			Rect rect = rt.rect;
			Vector2 size = ((Rect)(ref rect)).size;
			if (size.x <= 0f || size.y <= 0f)
			{
				return scale;
			}
			float num = Mathf.Min((float)Screen.width * 0.95f / size.x, (float)Screen.height * 0.95f / size.y);
			return Mathf.Min(scale, num);
		}

		private static float ReadStatic(FieldInfo field, float fallback)
		{
			if (field == null)
			{
				return fallback;
			}
			object value = field.GetValue(null);
			if (value is float)
			{
				return (float)value;
			}
			if (value is int num)
			{
				return num;
			}
			return fallback;
		}
	}
}