Decompiled source of CustomLoadingScreens v0.9.7

CustomLoadingScreens.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.9.7")]
[assembly: AssemblyInformationalVersion("0.9.7+f5b4472023e021319b5052bfbf00f6018987d118")]
[assembly: AssemblyVersion("0.9.7.0")]
namespace CustomLoadingScreens;

[BepInPlugin("cjayride.CustomLoadingScreens", "Custom Loading Screens", "0.9.7")]
public class BepInExPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(FejdStartup), "LoadMainScene")]
	public static class LoadMainScene_Patch
	{
		public static void Prefix(FejdStartup __instance)
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			PickScreensAndTips();
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance.m_loading == (Object)null || (Object)(object)loadingSprite == (Object)null)
			{
				return;
			}
			Transform val = __instance.m_loading.transform.Find("Bkg");
			if ((Object)(object)val == (Object)null)
			{
				((BaseUnityPlugin)context).Logger.LogWarning((object)"FejdStartup.m_loading has no Bkg child.");
				return;
			}
			Image component = ((Component)val).GetComponent<Image>();
			if (!((Object)(object)component == (Object)null))
			{
				ApplyToLoadingImage(Object.Instantiate<Image>(component, __instance.m_loading.transform), loadingSprite, loadingColorMask.Value, preserveAspect: true);
			}
		}
	}

	[HarmonyPriority(800)]
	[HarmonyPatch(typeof(ZNet), "RPC_ClientHandshake")]
	public static class ZNet_RPC_ClientHandshake_Patch
	{
		public static void Prefix(ZNet __instance)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance == (Object)null || __instance.IsServer())
			{
				return;
			}
			if ((Object)(object)loadingSprite == (Object)null)
			{
				PickScreensAndTips();
			}
			Hud instance = Hud.instance;
			if (!((Object)(object)instance == (Object)null) && !((Object)(object)loadingSprite == (Object)null))
			{
				ApplyToLoadingImage(instance.m_loadingImage, loadingSprite, loadingColorMask.Value, preserveAspect: true);
				if (showTipsOnLoadingScreen.Value && loadingTips.Length != 0 && !string.IsNullOrEmpty(loadingTip) && !((Object)(object)instance.m_loadingTip == (Object)null))
				{
					instance.m_loadingTip.text = loadingTip;
					((Graphic)instance.m_loadingTip).color = tipTextColor.Value;
				}
			}
		}
	}

	[HarmonyPatch(typeof(Hud), "UpdateBlackScreen")]
	public static class UpdateBlackScreen_Patch
	{
		public static void Prefix(Hud __instance, bool ___m_haveSetupLoadScreen, ref bool __state)
		{
			__state = !___m_haveSetupLoadScreen;
		}

		public static void Postfix(Hud __instance, Player player, bool ___m_haveSetupLoadScreen, bool __state)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			if ((Object)(object)loadingSprite == (Object)null)
			{
				PickScreensAndTips();
			}
			bool flag = ShouldUsePortalLoadingScreen(player);
			if (flag && !portalLoadingActive)
			{
				OnPortalTeleportStarted();
			}
			portalLoadingActive = flag;
			Sprite val = (differentSpawnScreen.Value ? loadingSprite2 : loadingSprite);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			bool flag2 = __state && ___m_haveSetupLoadScreen;
			bool flag3 = IsHudLoadingVisible(__instance);
			if (flag2 || flag3 || flag)
			{
				if (flag)
				{
					ShowSpawnStyleLoadingPanel(__instance);
				}
				if ((Object)(object)__instance.m_loadingImage != (Object)null && (Object)(object)__instance.m_loadingImage.sprite != (Object)(object)val)
				{
					ApplySpawnLoadingScreen(__instance, val);
				}
				else if (flag2 || flag)
				{
					ApplySpawnLoadingScreen(__instance, val);
				}
			}
		}
	}

	private static BepInExPlugin context;

	public static ConfigEntry<bool> modEnabled;

	public static ConfigEntry<string> loadingText;

	public static ConfigEntry<bool> differentSpawnScreen;

	public static ConfigEntry<bool> differentSpawnTip;

	public static ConfigEntry<bool> showTipsOnLoadingScreen;

	public static ConfigEntry<bool> removeVignette;

	public static ConfigEntry<Color> spawnColorMask;

	public static ConfigEntry<Color> loadingColorMask;

	public static ConfigEntry<Color> loadingTextColor;

	public static ConfigEntry<Color> tipTextColor;

	public static ConfigEntry<string> imagePath;

	public static ConfigEntry<string> tipsPath;

	public static List<string> loadingScreens = new List<string>();

	public static string[] loadingTips = new string[0];

	private static Sprite loadingSprite;

	private static Sprite loadingSprite2;

	private static string loadingTip;

	private static string loadingTip2;

	private static bool vignetteRemovedThisSession;

	private static bool portalLoadingActive;

	private static Sprite lastAppliedSpawnSprite;

	private static MethodInfo loadImageBytes;

	private const int MaxCachedSprites = 4;

	private static readonly Dictionary<string, Sprite> spriteCache = new Dictionary<string, Sprite>(4);

	private static readonly Queue<string> spriteCacheOrder = new Queue<string>(4);

	private void Awake()
	{
		//IL_008a: 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)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e4: Invalid comparison between Unknown and I4
		context = this;
		modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable this mod");
		differentSpawnScreen = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DifferentSpawnScreen", true, "Use a different screen for the spawn part");
		differentSpawnTip = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DifferentSpawnTip", true, "Use a different tip for the spawn part");
		spawnColorMask = ((BaseUnityPlugin)this).Config.Bind<Color>("General", "SpawnColorMask", new Color(0.532f, 0.588f, 0.853f, 1f), "Change the color mask of the spawn screen (set last number to 0 to disable)");
		loadingColorMask = ((BaseUnityPlugin)this).Config.Bind<Color>("General", "LoadingColorMask", Color.white, "Change the color mask of the initial loading screen (set to white to disable)");
		removeVignette = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RemoveMask", true, "Remove dark edges for the spawn part");
		loadingText = ((BaseUnityPlugin)this).Config.Bind<string>("General", "LoadingText", "Loading...", "Custom Loading... text");
		loadingTextColor = ((BaseUnityPlugin)this).Config.Bind<Color>("General", "LoadingTextColor", new Color(1f, 0.641f, 0f, 1f), "Custom Loading... text color");
		tipTextColor = ((BaseUnityPlugin)this).Config.Bind<Color>("General", "TipTextColor", Color.white, "Custom tip text color");
		showTipsOnLoadingScreen = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowTipsOnLoadingScreen", true, "Show a tip on the initial loading overlay");
		imagePath = ((BaseUnityPlugin)this).Config.Bind<string>("General", "PathToImagesFolder", "plugins\\cjayride-CustomLoadingScreens\\CustomLoadingScreens", "Path to image files. Example: config\\CustomLoadingScreens or plugins\\cjayride-CustomLoadingScreens\\CustomLoadingScreens");
		tipsPath = ((BaseUnityPlugin)this).Config.Bind<string>("General", "PathToTipsFolder", "plugins\\cjayride-CustomLoadingScreens\\CustomLoadingScreens", "Path to tips file. Example: config\\CustomLoadingScreens or plugins\\cjayride-CustomLoadingScreens\\CustomLoadingScreens");
		if (!modEnabled.Value || Application.isBatchMode || (int)SystemInfo.graphicsDeviceType == 4)
		{
			return;
		}
		loadImageBytes = FindLoadImageMethod();
		if (loadImageBytes == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"Could not find ImageConversion.LoadImage(Texture2D, byte[]). Screens will not decode.");
		}
		LoadCustomLoadingScreens();
		LoadTips();
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Found " + loadingScreens.Count + " loading images and " + loadingTips.Length + " tips."));
		if (loadingScreens.Count > 0)
		{
			Sprite orLoadSprite = GetOrLoadSprite(loadingScreens[0]);
			if ((Object)(object)orLoadSprite != (Object)null && (Object)(object)orLoadSprite.texture != (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Warmup decode OK: " + ((Texture)orLoadSprite.texture).width + "x" + ((Texture)orLoadSprite.texture).height));
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Warmup decode failed for " + loadingScreens[0]));
			}
		}
		Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
	}

	private static MethodInfo FindLoadImageMethod()
	{
		MethodInfo[] methods = typeof(ImageConversion).GetMethods(BindingFlags.Static | BindingFlags.Public);
		for (int i = 0; i < methods.Length; i++)
		{
			if (!(methods[i].Name != "LoadImage"))
			{
				ParameterInfo[] parameters = methods[i].GetParameters();
				if (parameters.Length == 2 && parameters[0].ParameterType == typeof(Texture2D) && parameters[1].ParameterType == typeof(byte[]))
				{
					return methods[i];
				}
			}
		}
		return null;
	}

	private static string GetPluginDirectory()
	{
		return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
	}

	private static string GetBepInExRoot()
	{
		string pluginDirectory = GetPluginDirectory();
		string directoryName = Path.GetDirectoryName(pluginDirectory);
		if (string.Equals(Path.GetFileName(pluginDirectory), "plugins", StringComparison.OrdinalIgnoreCase))
		{
			return directoryName;
		}
		return Path.GetDirectoryName(directoryName);
	}

	private static bool IsImageFile(string file)
	{
		if (Path.GetFileName(file).Equals("icon.png", StringComparison.OrdinalIgnoreCase))
		{
			return false;
		}
		string extension = Path.GetExtension(file);
		if (!extension.Equals(".png", StringComparison.OrdinalIgnoreCase) && !extension.Equals(".jpg", StringComparison.OrdinalIgnoreCase))
		{
			return extension.Equals(".jpeg", StringComparison.OrdinalIgnoreCase);
		}
		return true;
	}

	private static bool DirectoryHasImages(string path)
	{
		if (string.IsNullOrEmpty(path) || !Directory.Exists(path))
		{
			return false;
		}
		try
		{
			string[] files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
			for (int i = 0; i < files.Length; i++)
			{
				if (IsImageFile(files[i]))
				{
					return true;
				}
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)context).Logger.LogWarning((object)("Could not scan " + path + ": " + ex.Message));
		}
		return false;
	}

	private static string GetContentDirectory(string configuredRelativePath)
	{
		string pluginDirectory = GetPluginDirectory();
		string text = Path.Combine(pluginDirectory, "CustomLoadingScreens");
		string text2 = Path.Combine(GetBepInExRoot(), configuredRelativePath);
		if (DirectoryHasImages(text))
		{
			return text;
		}
		if (DirectoryHasImages(pluginDirectory))
		{
			return pluginDirectory;
		}
		if (DirectoryHasImages(text2))
		{
			return text2;
		}
		Directory.CreateDirectory(text);
		return text;
	}

	private void LoadTips()
	{
		string contentDirectory = GetContentDirectory(tipsPath.Value);
		string path = Path.Combine(contentDirectory, "tips.txt");
		if (!File.Exists(path))
		{
			string text = Path.Combine(GetPluginDirectory(), "tips.txt");
			if (File.Exists(text))
			{
				path = text;
			}
		}
		if (!File.Exists(path))
		{
			File.WriteAllText(Path.Combine(contentDirectory, "tips.txt"), string.Empty);
			loadingTips = new string[0];
			return;
		}
		string[] array = File.ReadAllLines(path);
		int num = 0;
		for (int i = 0; i < array.Length; i++)
		{
			if (!string.IsNullOrWhiteSpace(array[i]))
			{
				num++;
			}
		}
		if (num == 0)
		{
			loadingTips = new string[0];
			return;
		}
		string[] array2 = new string[num];
		int num2 = 0;
		for (int j = 0; j < array.Length; j++)
		{
			if (!string.IsNullOrWhiteSpace(array[j]))
			{
				array2[num2++] = array[j];
			}
		}
		loadingTips = array2;
	}

	private static void LoadCustomLoadingScreens()
	{
		loadingScreens.Clear();
		string contentDirectory = GetContentDirectory(imagePath.Value);
		if (!Directory.Exists(contentDirectory))
		{
			Directory.CreateDirectory(contentDirectory);
			((BaseUnityPlugin)context).Logger.LogWarning((object)("No loading images found. Put png/jpg files in " + contentDirectory));
			return;
		}
		string[] files = Directory.GetFiles(contentDirectory, "*.*", SearchOption.AllDirectories);
		for (int i = 0; i < files.Length; i++)
		{
			if (IsImageFile(files[i]))
			{
				loadingScreens.Add(files[i]);
			}
		}
		if (loadingScreens.Count == 0)
		{
			((BaseUnityPlugin)context).Logger.LogWarning((object)("No png/jpg loading images in " + contentDirectory));
		}
		else
		{
			((BaseUnityPlugin)context).Logger.LogInfo((object)("Using loading images from " + contentDirectory));
		}
	}

	private static Sprite GetRandomLoadingScreen()
	{
		int count = loadingScreens.Count;
		if (count == 0)
		{
			return null;
		}
		return GetOrLoadSprite(loadingScreens[Random.Range(0, count)]);
	}

	private static bool TryLoadImage(Texture2D tex, byte[] imageData)
	{
		if (loadImageBytes == null)
		{
			return false;
		}
		try
		{
			object obj = loadImageBytes.Invoke(null, new object[2] { tex, imageData });
			bool flag = default(bool);
			int num;
			if (obj is bool)
			{
				flag = (bool)obj;
				num = 1;
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)context).Logger.LogWarning((object)("LoadImage failed: " + ex.Message));
			return false;
		}
	}

	private static Sprite GetOrLoadSprite(string path)
	{
		//IL_0066: Unknown result type (might be due to invalid IL or missing references)
		//IL_006c: Expected O, but got Unknown
		//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		if (spriteCache.TryGetValue(path, out var value) && (Object)(object)value != (Object)null && (Object)(object)value.texture != (Object)null)
		{
			return value;
		}
		byte[] imageData;
		try
		{
			imageData = File.ReadAllBytes(path);
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)context).Logger.LogWarning((object)("Failed to read loading screen " + path + ": " + ex.Message));
			return null;
		}
		Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
		((Texture)val).wrapMode = (TextureWrapMode)1;
		((Texture)val).filterMode = (FilterMode)1;
		((Texture)val).anisoLevel = 0;
		if (!TryLoadImage(val, imageData))
		{
			Object.Destroy((Object)(object)val);
			((BaseUnityPlugin)context).Logger.LogWarning((object)("Failed to decode loading screen " + path));
			return null;
		}
		Sprite val2 = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0);
		((Object)val2).name = "CLS_" + Path.GetFileName(path);
		while (spriteCache.Count >= 4 && spriteCacheOrder.Count > 0)
		{
			string key = spriteCacheOrder.Dequeue();
			if (!spriteCache.TryGetValue(key, out var value2))
			{
				continue;
			}
			spriteCache.Remove(key);
			if ((Object)(object)value2 != (Object)null && (Object)(object)value2 != (Object)(object)loadingSprite && (Object)(object)value2 != (Object)(object)loadingSprite2)
			{
				if ((Object)(object)value2.texture != (Object)null)
				{
					Object.Destroy((Object)(object)value2.texture);
				}
				Object.Destroy((Object)(object)value2);
			}
		}
		spriteCache[path] = val2;
		spriteCacheOrder.Enqueue(path);
		return val2;
	}

	private static void PickScreensAndTips()
	{
		vignetteRemovedThisSession = false;
		lastAppliedSpawnSprite = null;
		if (loadingScreens.Count == 0)
		{
			LoadCustomLoadingScreens();
		}
		loadingSprite = GetRandomLoadingScreen();
		loadingSprite2 = (differentSpawnScreen.Value ? GetRandomLoadingScreen() : loadingSprite);
		if ((Object)(object)loadingSprite != (Object)null && (Object)(object)loadingSprite.texture != (Object)null)
		{
			((BaseUnityPlugin)context).Logger.LogInfo((object)("Picked loading sprites " + ((Texture)loadingSprite.texture).width + "x" + ((Texture)loadingSprite.texture).height));
		}
		else
		{
			((BaseUnityPlugin)context).Logger.LogWarning((object)"PickScreensAndTips: no loading sprite (check png/jpg decode).");
		}
		if (loadingTips.Length != 0)
		{
			loadingTip = loadingTips[Random.Range(0, loadingTips.Length)];
			loadingTip2 = (differentSpawnTip.Value ? loadingTips[Random.Range(0, loadingTips.Length)] : loadingTip);
		}
		else
		{
			loadingTip = null;
			loadingTip2 = null;
		}
	}

	private static bool IsHudLoadingVisible(Hud hud)
	{
		if ((Object)(object)hud == (Object)null)
		{
			return false;
		}
		if ((Object)(object)hud.m_loadingScreen != (Object)null && ((Component)hud.m_loadingScreen).gameObject.activeInHierarchy && hud.m_loadingScreen.alpha > 0.05f)
		{
			return true;
		}
		if ((Object)(object)hud.m_loadingImage != (Object)null)
		{
			return ((Behaviour)hud.m_loadingImage).isActiveAndEnabled;
		}
		return false;
	}

	private static void ApplyToLoadingImage(Image image, Sprite sprite, Color color, bool preserveAspect)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)image == (Object)null) && !((Object)(object)sprite == (Object)null))
		{
			image.sprite = sprite;
			((Graphic)image).color = color;
			image.type = (Type)0;
			image.preserveAspect = preserveAspect;
			((Behaviour)image).enabled = true;
			((Component)image).transform.SetAsLastSibling();
		}
	}

	private static bool ShouldUsePortalLoadingScreen(Player player)
	{
		if ((Object)(object)player == (Object)null || ((Character)player).IsDead() || player.IsSleeping() || !((Character)player).IsTeleporting())
		{
			return false;
		}
		Game instance = Game.instance;
		if (!((Object)(object)instance == (Object)null))
		{
			return !instance.IsShuttingDown();
		}
		return true;
	}

	private static void OnPortalTeleportStarted()
	{
		if (differentSpawnScreen.Value)
		{
			loadingSprite2 = GetRandomLoadingScreen();
		}
		if (differentSpawnTip.Value && loadingTips.Length != 0)
		{
			loadingTip2 = loadingTips[Random.Range(0, loadingTips.Length)];
		}
		vignetteRemovedThisSession = false;
	}

	private static void ShowSpawnStyleLoadingPanel(Hud hud)
	{
		if ((Object)(object)hud.m_sleepingProgress != (Object)null)
		{
			hud.m_sleepingProgress.SetActive(false);
		}
		if ((Object)(object)hud.m_teleportingProgress != (Object)null)
		{
			hud.m_teleportingProgress.SetActive(false);
		}
		if ((Object)(object)hud.m_loadingProgress != (Object)null)
		{
			hud.m_loadingProgress.SetActive(true);
		}
	}

	private static void ApplySpawnLoadingScreen(Hud hud, Sprite sprite)
	{
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006e: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)hud == (Object)null) && !((Object)(object)sprite == (Object)null))
		{
			ApplyToLoadingImage(hud.m_loadingImage, sprite, spawnColorMask.Value, preserveAspect: true);
			if ((Object)(object)hud.m_loadingTip != (Object)null && loadingTips.Length != 0)
			{
				hud.m_loadingTip.text = (differentSpawnTip.Value ? loadingTip2 : loadingTip);
				((Graphic)hud.m_loadingTip).color = tipTextColor.Value;
			}
			if (!vignetteRemovedThisSession && removeVignette.Value && (Object)(object)hud.m_loadingProgress != (Object)null)
			{
				Transform transform = hud.m_loadingProgress.transform;
				DisableChild(transform, "TopFade");
				DisableChild(transform, "BottomFade");
				DisableChild(transform, "text_darken");
				vignetteRemovedThisSession = true;
			}
			if ((Object)(object)lastAppliedSpawnSprite != (Object)(object)sprite)
			{
				lastAppliedSpawnSprite = sprite;
				((BaseUnityPlugin)context).Logger.LogInfo((object)"Applied spawn loading screen to Hud.m_loadingImage.");
			}
		}
	}

	private static void DisableChild(Transform parent, string name)
	{
		Transform val = parent.Find(name);
		if ((Object)(object)val != (Object)null)
		{
			((Component)val).gameObject.SetActive(false);
		}
	}
}