Decompiled source of Runeheim Online Modpack v1.0.13

plugins/RUNEHEIM MODS-RuneheimLoadingScreen/RuneheimLoadingScreen.dll

Decompiled 3 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using UnityEngine.UI;

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

[BepInPlugin("runeheim.online.loadingscreen", "Runeheim Loading Screen", "0.7.3")]
public sealed class RuneheimLoadingScreenPlugin : BaseUnityPlugin
{
	private sealed class ReferenceEqualityComparer : IEqualityComparer<object>
	{
		public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer();

		public new bool Equals(object x, object y)
		{
			return object.ReferenceEquals(x, y);
		}

		public int GetHashCode(object obj)
		{
			return RuntimeHelpers.GetHashCode(obj);
		}
	}

	public const string PluginGuid = "runeheim.online.loadingscreen";

	public const string PluginName = "Runeheim Loading Screen";

	public const string PluginVersion = "0.7.3";

	private const string RuneheimIp = "185.216.147.166";

	private const string RuneheimPort = "5914";

	private const string RuneheimName = "Runeheim Online";

	private const string LoadingImageFile = "RuneheimLoading.png";

	private const string LoadingLogoFile = "RuneheimLogo.png";

	private static ManualLogSource _log;

	private static bool _destinationKnown;

	private static bool _destinationIsRuneheim;

	private static bool _runeheimLoadActive;

	private static Texture2D _loadingTexture;

	private static Sprite _loadingSprite;

	private static Texture2D _logoTexture;

	private static Sprite _logoSprite;

	private static Image _swappedLogoImage;

	private static Sprite _originalLogoSprite;

	private static bool _logoApplied;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_0017: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		_log = ((BaseUnityPlugin)this).Logger;
		LoadRuneheimAssets();
		_harmony = new Harmony("runeheim.online.loadingscreen");
		PatchFejdMethod("SetServerToJoin", null, "SetServerToJoinPostfix", 0);
		PatchFejdMethod("JoinServer", "JoinServerPrefix", null, 800);
		PatchFejdMethod("OnWorldStart", "OnWorldStartPrefix", null, 800);
		PatchPlayerMethod("OnSpawned", null, "PlayerOnSpawnedPostfix", 0);
		PatchHudUpdateBlackScreen();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Runeheim Loading Screen v0.7.3 loaded.");
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Runeheim background + loading-logo test enabled.");
	}

	private void OnDestroy()
	{
		RestoreLoadingLogo();
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}

	private void LoadRuneheimAssets()
	{
		string location = Assembly.GetExecutingAssembly().Location;
		string directoryName = Path.GetDirectoryName(location);
		if (string.IsNullOrEmpty(directoryName))
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"Could not determine the Runeheim Loading Screen mod folder.");
			return;
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Runeheim asset folder: " + directoryName));
		_loadingSprite = LoadPngAsSprite(Path.Combine(directoryName, "RuneheimLoading.png"), "RuneheimLoadingTexture", "RuneheimLoadingSprite", out _loadingTexture);
		_logoSprite = LoadPngAsSprite(Path.Combine(directoryName, "RuneheimLogo.png"), "RuneheimLogoTexture", "RuneheimLogoSprite", out _logoTexture);
	}

	private Sprite LoadPngAsSprite(string path, string textureName, string spriteName, out Texture2D texture)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Expected O, but got Unknown
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
		texture = null;
		try
		{
			if (!File.Exists(path))
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Runeheim PNG was not found: " + path));
				return null;
			}
			byte[] bytes = File.ReadAllBytes(path);
			texture = new Texture2D(2, 2, (TextureFormat)4, false);
			((Object)texture).name = textureName;
			((Texture)texture).wrapMode = (TextureWrapMode)1;
			if (!LoadImageCompat(texture, bytes))
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not decode Runeheim PNG: " + Path.GetFileName(path)));
				return null;
			}
			Sprite val = Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), new Vector2(0.5f, 0.5f), 100f);
			((Object)val).name = spriteName;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded Runeheim asset: " + Path.GetFileName(path)));
			return val;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not load Runeheim PNG " + Path.GetFileName(path) + ": " + ex));
			return null;
		}
	}

	private static bool LoadImageCompat(Texture2D texture, byte[] bytes)
	{
		try
		{
			Type typeFromHandle = typeof(ImageConversion);
			MethodInfo[] methods = typeFromHandle.GetMethods(BindingFlags.Static | BindingFlags.Public);
			foreach (MethodInfo methodInfo in methods)
			{
				if (string.Equals(methodInfo.Name, "LoadImage", StringComparison.Ordinal))
				{
					ParameterInfo[] parameters = methodInfo.GetParameters();
					if (parameters.Length == 2 && parameters[0].ParameterType == typeof(Texture2D) && parameters[1].ParameterType == typeof(byte[]))
					{
						object obj = methodInfo.Invoke(null, new object[2] { texture, bytes });
						return obj is bool && (bool)obj;
					}
					if (parameters.Length == 3 && parameters[0].ParameterType == typeof(Texture2D) && parameters[1].ParameterType == typeof(byte[]) && parameters[2].ParameterType == typeof(bool))
					{
						object obj2 = methodInfo.Invoke(null, new object[3] { texture, bytes, false });
						return obj2 is bool && (bool)obj2;
					}
				}
			}
			_log.LogError((object)"Could not find a compatible Unity ImageConversion.LoadImage(byte[]) overload.");
			return false;
		}
		catch (TargetInvocationException ex)
		{
			Exception ex2 = ex.InnerException ?? ex;
			_log.LogError((object)("Runeheim PNG decode failed: " + ex2));
			return false;
		}
		catch (Exception ex3)
		{
			_log.LogError((object)("Runeheim PNG decode failed: " + ex3));
			return false;
		}
	}

	private void PatchHudUpdateBlackScreen()
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		//IL_0047: Expected O, but got Unknown
		//IL_0062: Unknown result type (might be due to invalid IL or missing references)
		//IL_0068: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(Hud), "UpdateBlackScreen", (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"Could not find Hud.UpdateBlackScreen().");
			return;
		}
		HarmonyMethod val = new HarmonyMethod(typeof(RuneheimLoadingScreenPlugin), "HudUpdateBlackScreenPrefix", (Type[])null);
		val.priority = 800;
		HarmonyMethod val2 = new HarmonyMethod(typeof(RuneheimLoadingScreenPlugin), "HudUpdateBlackScreenPostfix", (Type[])null);
		val2.priority = 0;
		_harmony.Patch((MethodBase)methodInfo, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private void PatchFejdMethod(string methodName, string prefixName, string postfixName, int priority)
	{
		MethodInfo methodInfo = AccessTools.Method(typeof(FejdStartup), methodName, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not find FejdStartup." + methodName + "()."));
			return;
		}
		HarmonyMethod val = CreateHarmonyMethod(prefixName, priority);
		HarmonyMethod val2 = CreateHarmonyMethod(postfixName, priority);
		_harmony.Patch((MethodBase)methodInfo, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private void PatchPlayerMethod(string methodName, string prefixName, string postfixName, int priority)
	{
		MethodInfo methodInfo = AccessTools.Method(typeof(Player), methodName, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Could not find Player." + methodName + "()."));
			return;
		}
		HarmonyMethod val = CreateHarmonyMethod(prefixName, priority);
		HarmonyMethod val2 = CreateHarmonyMethod(postfixName, priority);
		_harmony.Patch((MethodBase)methodInfo, val, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
	}

	private static HarmonyMethod CreateHarmonyMethod(string methodName, int priority)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		if (string.IsNullOrEmpty(methodName))
		{
			return null;
		}
		HarmonyMethod val = new HarmonyMethod(typeof(RuneheimLoadingScreenPlugin), methodName, (Type[])null);
		val.priority = priority;
		return val;
	}

	public static void SetServerToJoinPostfix(object[] __args)
	{
		RestoreLoadingLogo();
		_destinationKnown = false;
		_destinationIsRuneheim = false;
		_runeheimLoadActive = false;
		try
		{
			List<string> list = new List<string>();
			HashSet<object> visited = new HashSet<object>(ReferenceEqualityComparer.Instance);
			if (__args != null)
			{
				for (int i = 0; i < __args.Length; i++)
				{
					CollectScalarValues(__args[i], list, 0, visited);
				}
			}
			string text = string.Join(" | ", list.ToArray());
			bool flag = text.IndexOf("185.216.147.166", StringComparison.OrdinalIgnoreCase) >= 0;
			bool flag2 = text.IndexOf("5914", StringComparison.OrdinalIgnoreCase) >= 0;
			bool flag3 = text.IndexOf("Runeheim Online", StringComparison.OrdinalIgnoreCase) >= 0;
			_destinationKnown = true;
			_destinationIsRuneheim = flag3 || (flag && flag2);
			if (_destinationIsRuneheim)
			{
				_log.LogInfo((object)"Runeheim destination detected.");
			}
			else
			{
				_log.LogInfo((object)"Non-Runeheim destination detected.");
			}
		}
		catch (Exception ex)
		{
			_destinationKnown = false;
			_destinationIsRuneheim = false;
			_runeheimLoadActive = false;
			_log.LogWarning((object)("Server detection failed; defaulting to vanilla: " + ex.Message));
		}
	}

	public static void JoinServerPrefix()
	{
		RestoreLoadingLogo();
		_runeheimLoadActive = _destinationKnown && _destinationIsRuneheim;
		if (_runeheimLoadActive)
		{
			_log.LogInfo((object)"Runeheim join armed.");
		}
		else
		{
			_log.LogInfo((object)"Non-Runeheim join; loading screen stays vanilla.");
		}
	}

	public static void OnWorldStartPrefix()
	{
		RestoreLoadingLogo();
		_destinationKnown = false;
		_destinationIsRuneheim = false;
		_runeheimLoadActive = false;
		_log.LogInfo((object)"Solo/local world selected; loading screen stays vanilla.");
	}

	public static void PlayerOnSpawnedPostfix()
	{
		if (_runeheimLoadActive)
		{
			_log.LogInfo((object)"Runeheim player spawned; clearing loading-screen state.");
		}
		RestoreLoadingLogo();
		_runeheimLoadActive = false;
	}

	public static void HudUpdateBlackScreenPrefix(bool ___m_haveSetupLoadScreen, ref bool __state)
	{
		__state = !___m_haveSetupLoadScreen;
	}

	public static void HudUpdateBlackScreenPostfix(Hud __instance, bool ___m_haveSetupLoadScreen, bool __state)
	{
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		if (!_runeheimLoadActive || (Object)(object)__instance == (Object)null || !__state || !___m_haveSetupLoadScreen)
		{
			return;
		}
		try
		{
			if ((Object)(object)_loadingSprite != (Object)null)
			{
				Image loadingImage = __instance.m_loadingImage;
				if ((Object)(object)loadingImage == (Object)null)
				{
					_log.LogWarning((object)"Hud.m_loadingImage was null.");
				}
				else
				{
					loadingImage.sprite = _loadingSprite;
					loadingImage.type = (Type)0;
					loadingImage.preserveAspect = true;
					((Graphic)loadingImage).color = Color.white;
					((Component)loadingImage).gameObject.SetActive(true);
					_log.LogInfo((object)"Runeheim custom HUD loading image applied.");
				}
			}
			TryApplyRuneheimLogo(__instance);
		}
		catch (Exception ex)
		{
			_log.LogError((object)("Failed to apply Runeheim loading UI: " + ex));
		}
	}

	private static void TryApplyRuneheimLogo(Hud hud)
	{
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0148: Unknown result type (might be due to invalid IL or missing references)
		//IL_015b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0165: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0195: Unknown result type (might be due to invalid IL or missing references)
		//IL_019f: Unknown result type (might be due to invalid IL or missing references)
		if (_logoApplied || (Object)(object)_logoSprite == (Object)null || (Object)(object)hud == (Object)null)
		{
			return;
		}
		try
		{
			Image[] componentsInChildren = ((Component)hud).GetComponentsInChildren<Image>(true);
			Image val = null;
			int num = 0;
			foreach (Image val2 in componentsInChildren)
			{
				if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)hud.m_loadingImage))
				{
					string objectName = (((Object)(object)((Component)val2).gameObject != (Object)null) ? ((Object)((Component)val2).gameObject).name : string.Empty);
					string spriteName = (((Object)(object)val2.sprite != (Object)null) ? ((Object)val2.sprite).name : string.Empty);
					int num2 = ScoreLogoCandidate(objectName, spriteName);
					if (num2 > num)
					{
						num = num2;
						val = val2;
					}
				}
			}
			if ((Object)(object)val == (Object)null || num < 10)
			{
				_log.LogWarning((object)"Could not confidently identify the Valheim loading logo; leaving it unchanged.");
				LogLikelyImageNames(componentsInChildren);
				return;
			}
			_swappedLogoImage = val;
			_originalLogoSprite = val.sprite;
			val.sprite = _logoSprite;
			val.type = (Type)0;
			val.preserveAspect = true;
			((Graphic)val).color = Color.white;
			((Component)val).gameObject.SetActive(true);
			RectTransform rectTransform = ((Graphic)val).rectTransform;
			if ((Object)(object)rectTransform != (Object)null)
			{
				rectTransform.anchorMin = new Vector2(0.5f, rectTransform.anchorMin.y);
				rectTransform.anchorMax = new Vector2(0.5f, rectTransform.anchorMax.y);
				rectTransform.pivot = new Vector2(0.5f, rectTransform.pivot.y);
				rectTransform.anchoredPosition = new Vector2(0f, rectTransform.anchoredPosition.y);
			}
			_logoApplied = true;
			_log.LogInfo((object)("Runeheim loading logo applied to UI object '" + ((Object)((Component)val).gameObject).name + "'."));
		}
		catch (Exception ex)
		{
			_log.LogWarning((object)("Runeheim logo swap failed safely; Valheim logo left unchanged: " + ex.Message));
		}
	}

	private static int ScoreLogoCandidate(string objectName, string spriteName)
	{
		int num = 0;
		if (!string.IsNullOrEmpty(objectName))
		{
			if (objectName.IndexOf("valheim", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				num += 40;
			}
			if (objectName.IndexOf("logo", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				num += 20;
			}
		}
		if (!string.IsNullOrEmpty(spriteName))
		{
			if (spriteName.IndexOf("valheim", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				num += 40;
			}
			if (spriteName.IndexOf("logo", StringComparison.OrdinalIgnoreCase) >= 0)
			{
				num += 20;
			}
		}
		return num;
	}

	private static void LogLikelyImageNames(Image[] images)
	{
		if (images == null)
		{
			return;
		}
		int num = 0;
		for (int i = 0; i < images.Length; i++)
		{
			if (num >= 20)
			{
				break;
			}
			Image val = images[i];
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)Hud.instance.m_loadingImage))
			{
				string text = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : "<null>");
				string text2 = (((Object)(object)val.sprite != (Object)null) ? ((Object)val.sprite).name : "<none>");
				if (text.IndexOf("logo", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("valheim", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("logo", StringComparison.OrdinalIgnoreCase) >= 0 || text2.IndexOf("valheim", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					_log.LogInfo((object)("Logo candidate: object='" + text + "', sprite='" + text2 + "'."));
					num++;
				}
			}
		}
	}

	private static void RestoreLoadingLogo()
	{
		try
		{
			if ((Object)(object)_swappedLogoImage != (Object)null)
			{
				_swappedLogoImage.sprite = _originalLogoSprite;
			}
		}
		catch
		{
		}
		_swappedLogoImage = null;
		_originalLogoSprite = null;
		_logoApplied = false;
	}

	private static void CollectScalarValues(object value, List<string> output, int depth, HashSet<object> visited)
	{
		if (value == null || depth > 5)
		{
			return;
		}
		Type type = value.GetType();
		if (type == typeof(string) || type.IsPrimitive || type.IsEnum || type == typeof(decimal))
		{
			output.Add(Convert.ToString(value));
			return;
		}
		if (!type.IsValueType)
		{
			if (visited.Contains(value))
			{
				return;
			}
			visited.Add(value);
		}
		if (value is IEnumerable enumerable && !(value is string))
		{
			int num = 0;
			{
				foreach (object item in enumerable)
				{
					CollectScalarValues(item, output, depth + 1, visited);
					num++;
					if (num >= 32)
					{
						break;
					}
				}
				return;
			}
		}
		BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
		FieldInfo[] fields = type.GetFields(bindingAttr);
		for (int i = 0; i < fields.Length; i++)
		{
			try
			{
				CollectScalarValues(fields[i].GetValue(value), output, depth + 1, visited);
			}
			catch
			{
			}
		}
		PropertyInfo[] properties = type.GetProperties(bindingAttr);
		foreach (PropertyInfo propertyInfo in properties)
		{
			if (propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0)
			{
				try
				{
					CollectScalarValues(propertyInfo.GetValue(value, null), output, depth + 1, visited);
				}
				catch
				{
				}
			}
		}
	}
}