Decompiled source of BorderlessWindowed v1.1.1

BorderlessWindowed.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using Valheim.SettingsGui;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("BorderlessWindowed")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Riintouge")]
[assembly: AssemblyProduct("BorderlessWindowed")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("0da70214-2c9c-40a9-9b69-43f07bf97314")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.1.0")]
[module: UnverifiableCode]
namespace BorderlessWindowed;

[BepInPlugin("com.riintouge.borderlesswindowed", "Borderless Windowed", "1.1.1")]
[BepInProcess("valheim.exe")]
public class BorderlessWindowed : BaseUnityPlugin
{
	[HarmonyPatch(typeof(GraphicsModeManager))]
	private class GraphicsModeManagerPatch
	{
		[HarmonyPatch("ApplyMode")]
		[HarmonyPostfix]
		private static void ApplyModePostfix(bool __result, GraphicsQualityMode mode)
		{
			if (__result)
			{
				((MonoBehaviour)Instance).StartCoroutine(Instance.CoUpdateBorder());
			}
		}
	}

	public static BorderlessWindowed Instance;

	public static ConfigEntry<bool> LoadOnStart;

	public static ConfigEntry<bool> ShowBorder;

	private readonly Harmony Harmony = new Harmony("com.riintouge.borderlesswindowed");

	private readonly BorderHelper BorderHelper = new BorderHelper();

	private void Awake()
	{
		if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
		{
			LoadOnStart = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Core", "LoadOnStart", true, "Whether this plugin loads on game start.");
			ShowBorder = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "ShowBorder", true, "Whether the border should be shown on the game window.");
			if (LoadOnStart.Value)
			{
				Instance = this;
				Harmony.PatchAll();
				((BaseUnityPlugin)this).Config.SettingChanged += Config_SettingChanged;
			}
		}
	}

	private void Config_SettingChanged(object sender, SettingChangedEventArgs e)
	{
		if (e.ChangedSetting == ShowBorder)
		{
			((MonoBehaviour)Instance).StartCoroutine(Instance.CoUpdateBorder());
		}
	}

	internal IEnumerator CoUpdateBorder()
	{
		return BorderHelper.UpdateBorder(ShowBorder.Value);
	}
}
internal class BorderHelper
{
	private const uint GameWindowBorderFlags = 13565952u;

	private static object UpdateBorderLock = new object();

	private NativeMethods.WindowRect? outerBorderThickness;

	private NativeMethods.WindowRect? innerWindowedBorderThickness;

	private NativeMethods.WindowRect? innerMaximizedBorderThickness;

	public IEnumerator UpdateBorder(bool enable)
	{
		if (Monitor.TryEnter(UpdateBorderLock))
		{
			try
			{
				yield return UpdateBorderCore(enable);
			}
			finally
			{
				Monitor.Exit(UpdateBorderLock);
			}
		}
	}

	private IEnumerator UpdateBorderCore(bool enable)
	{
		bool gameIsStarting = (Object)(object)Console.instance == (Object)null;
		yield return null;
		if (Screen.fullScreen)
		{
			yield break;
		}
		IntPtr hWnd = FindGameWindowHandle();
		if (hWnd == IntPtr.Zero)
		{
			yield break;
		}
		bool flag = GameWindowHasBorder(hWnd);
		if (enable == flag)
		{
			yield break;
		}
		DebugMessage(">>> BEGIN");
		DebugMessage($"SetGameWindowBorder({enable})");
		bool isMaximized = NativeMethods.IsZoomed(hWnd);
		bool isResolutionPreset = Screen.resolutions.Any((Resolution x) => Screen.width == ((Resolution)(ref x)).width && Screen.height == ((Resolution)(ref x)).height);
		int sceneWidth = Screen.width;
		int sceneHeight = Screen.height;
		DebugMessage(string.Format("Scene extents, {0}: {1}x{2} ({3}a preset)", isMaximized ? "maximized" : "windowed", Screen.width, Screen.height, isResolutionPreset ? "" : "not "));
		GetGameWindowRects(hWnd, out var outer, out var innerInitial);
		DebugMessage($"Outer, initial: ({outer.Left},{outer.Top}) to ({outer.Right},{outer.Bottom})");
		DebugMessage($"Inner, initial: ({innerInitial.Left},{innerInitial.Top}) to ({innerInitial.Right},{innerInitial.Bottom})");
		if (!outerBorderThickness.HasValue)
		{
			if (!flag)
			{
				yield break;
			}
			outerBorderThickness = ComputeBorderThickness(outer, sceneWidth, sceneHeight);
		}
		if (!isMaximized && !innerWindowedBorderThickness.HasValue)
		{
			if (!flag)
			{
				yield break;
			}
			innerWindowedBorderThickness = ComputeBorderThickness(innerInitial, sceneWidth, sceneHeight);
		}
		if (isMaximized && !innerMaximizedBorderThickness.HasValue)
		{
			if (!flag)
			{
				yield break;
			}
			innerMaximizedBorderThickness = ComputeBorderThickness(innerInitial, sceneWidth, sceneHeight);
		}
		SetGameWindowBorder(hWnd, enable);
		yield return null;
		int left = innerInitial.Left;
		int top = innerInitial.Top;
		int num = sceneWidth;
		int num2 = sceneHeight;
		if (enable)
		{
			NativeMethods.WindowRect value = outerBorderThickness.Value;
			left -= value.Left;
			top -= value.Top;
			num = sceneWidth + value.Left + value.Right;
			if (isResolutionPreset)
			{
				num2 += value.Top + value.Bottom;
			}
			else if (!isMaximized)
			{
				NativeMethods.WindowRect value2 = innerWindowedBorderThickness.Value;
				num2 += value.Top - value2.Top + (value.Bottom - value2.Bottom);
			}
		}
		else
		{
			NativeMethods.WindowRect windowRect = (isMaximized ? innerMaximizedBorderThickness.Value : innerWindowedBorderThickness.Value);
			left += windowRect.Left;
			top += windowRect.Top;
			if (gameIsStarting)
			{
				left--;
			}
			else if (!isResolutionPreset)
			{
				num2 += windowRect.Top + windowRect.Bottom;
			}
		}
		uint flags = 52u;
		DebugMessage($"SetWindowPos( ... , {left} , {top} , {num} , {num2} , ... );");
		if (num2 == sceneHeight && num != sceneWidth)
		{
			NativeMethods.SetWindowPos(hWnd, IntPtr.Zero, left, top, num, num2 - 1, flags);
		}
		NativeMethods.SetWindowPos(hWnd, IntPtr.Zero, left, top, num, num2, flags);
		yield return null;
		DebugMessage("<<< END\n");
	}

	private NativeMethods.WindowRect ComputeBorderThickness(NativeMethods.WindowRect outer, int width, int height)
	{
		NativeMethods.WindowRect result = default(NativeMethods.WindowRect);
		result.Left = (outer.Right - outer.Left - width) / 2;
		result.Right = result.Left;
		result.Bottom = outer.Bottom - outer.Top - height;
		DebugMessage($"Computed border thickness: LR {result.Left},{result.Right} to TB {result.Top},{result.Bottom}");
		return result;
	}

	private static void DebugMessage(string message)
	{
	}

	private static IntPtr FindGameWindowHandle()
	{
		IntPtr gameWindowHandle = IntPtr.Zero;
		NativeMethods.EnumDesktopWindows(lpfn: delegate(IntPtr hWnd, int lParam)
		{
			StringBuilder stringBuilder = new StringBuilder(255);
			NativeMethods.GetWindowText(hWnd, stringBuilder, stringBuilder.Capacity + 1);
			string text = stringBuilder.ToString();
			if (NativeMethods.IsWindowVisible(hWnd) && text == "Valheim")
			{
				gameWindowHandle = hWnd;
				return false;
			}
			return true;
		}, hDesktop: IntPtr.Zero, lParam: IntPtr.Zero);
		return gameWindowHandle;
	}

	private static bool GameWindowHasBorder(IntPtr hWnd)
	{
		if (hWnd != IntPtr.Zero)
		{
			return (NativeMethods.GetWindowLong(hWnd, -16) & 0xCF0000) != 0;
		}
		return false;
	}

	private unsafe static void GetGameWindowRects(IntPtr hWnd, out NativeMethods.WindowRect outer, out NativeMethods.WindowRect inner)
	{
		NativeMethods.GetWindowRect(hWnd, out var lpRect);
		outer = lpRect;
		NativeMethods.WindowRect windowRect = default(NativeMethods.WindowRect);
		NativeMethods.DwmGetWindowAttribute(hWnd, 9, &windowRect, sizeof(NativeMethods.WindowRect));
		inner = windowRect;
	}

	private static void SetGameWindowBorder(IntPtr hWnd, bool enable)
	{
		if (!(hWnd == IntPtr.Zero))
		{
			uint windowLong = NativeMethods.GetWindowLong(hWnd, -16);
			bool flag = (windowLong & 0xCF0000) != 0;
			if (enable != flag)
			{
				windowLong = ((!enable) ? (windowLong &= 0xFF30FFFFu) : (windowLong |= 0xCF0000u));
				NativeMethods.SetWindowLong(hWnd, -16, windowLong);
			}
		}
	}
}
public class NativeMethods
{
	public delegate bool EnumDesktopWindowsDelegate(IntPtr hwnd, int lParam);

	public struct WindowRect
	{
		public int Left;

		public int Top;

		public int Right;

		public int Bottom;
	}

	public const int DWMWA_EXTENDED_FRAME_BOUNDS = 9;

	public const int GWL_STYLE = -16;

	public const uint WS_MAXIMIZEBOX = 65536u;

	public const uint WS_MINIMIZEBOX = 131072u;

	public const uint WS_THICKFRAME = 262144u;

	public const uint WS_SYSMENU = 524288u;

	public const uint WS_DLGFRAME = 4194304u;

	public const uint WS_BORDER = 8388608u;

	public const uint SWP_ASYNCWINDOWPOS = 16384u;

	public const uint SWP_DEFERERASE = 8192u;

	public const uint SWP_DRAWFRAME = 32u;

	public const uint SWP_FRAMECHANGED = 32u;

	public const uint SWP_HIDEWINDOW = 128u;

	public const uint SWP_NOACTIVATE = 16u;

	public const uint SWP_NOCOPYBITS = 256u;

	public const uint SWP_NOMOVE = 2u;

	public const uint SWP_NOOWNERZORDER = 512u;

	public const uint SWP_NOREDRAW = 8u;

	public const uint SWP_NOREPOSITION = 512u;

	public const uint SWP_NOSENDCHANGING = 1024u;

	public const uint SWP_NOSIZE = 1u;

	public const uint SWP_NOZORDER = 4u;

	public const uint SWP_SHOWWINDOW = 64u;

	[DllImport("dwmapi.dll")]
	public unsafe static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, void* pvAttribute, int cbAttribute);

	[DllImport("user32.dll", SetLastError = true)]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDesktopWindowsDelegate lpfn, IntPtr lParam);

	[DllImport("user32.dll", SetLastError = true)]
	public static extern uint GetWindowLong(IntPtr hWnd, int nIndex);

	[DllImport("user32.dll")]
	public static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);

	[DllImport("user32.dll")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool IsWindowVisible(IntPtr hWnd);

	[DllImport("user32.dll")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool IsZoomed(IntPtr hWnd);

	[DllImport("user32.dll", SetLastError = true)]
	public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint flags);

	[DllImport("user32.dll")]
	[return: MarshalAs(UnmanagedType.Bool)]
	public static extern bool GetWindowRect(IntPtr hWnd, out WindowRect lpRect);

	[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
	public static extern int GetWindowText(IntPtr hWnd, [Out] StringBuilder lpString, int nMaxCount);
}