Skip to content

Commit

Permalink
Merge pull request #16 from BUTR/dev
Browse files Browse the repository at this point in the history
v1.0.3
  • Loading branch information
Aragas authored Mar 17, 2023
2 parents 66a3b23 + 9307bd9 commit 8119234
Show file tree
Hide file tree
Showing 22 changed files with 159 additions and 134 deletions.
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,23 @@

The Bannerlord Software Extender (BLSE) is a tool for Bannerlord mods that expands modding capabilities and adds additional functionality to the game.

Once installed, no additional steps are needed to launch Bannerlord with BLSE's added functionality.
You can start the game using **Bannerlord.BLSE.Launcher.exe** for the Vanilla Launcher or **Bannerlord.BLSE.LauncherEx.exe** for the Extended Launcher (BUTRLoader).
Mod Developers can use **Bannerlord.BLSE.Standalone.exe** to use the CLI to launch the game.
Once installed, no additional steps are needed to launch Bannerlord with BLSE's added functionality.
You can start the game using **Bannerlord.BLSE.Launcher.exe** for the Vanilla Launcher or **Bannerlord.BLSE.LauncherEx.exe** for the Extended Launcher (BUTRLoader).
Mod Developers can use **Bannerlord.BLSE.Standalone.exe** to use the CLI to launch the game.

Credits to [Pickysaurus](https://www.nexusmods.com/users/31179975) for the BLSE and BUTR Logos!
Credits to [Pickysaurus](https://www.nexusmods.com/users/31179975) for the BLSE and BUTR Logos!


## Features
* **Unblocking Files**
* **Launcher** and **LauncherEx** will automatically unblock files on launch.
Can be opted-out via passing **/nounblock** in command-line args.
* Standalone will not automatically unblock files on launch.
Can opted-in by passing **/unblock** in command-line args.
* **Continue Save File** - Allows to specify the save file to load when launching the game.
Can be used by passing **/continuesave _mysavegame_** in command-line args.
* **Assembly Resolver** - Changes the game's assembly loading priority.
If an assembly is available in one of the loaded modules, it will be loaded from there instead, even if the assembly is available in the main **/bin** folder.
* **Interceptor** - BLSE checks if the is a class with a custom attribute named ***BLSEInterceptorAttribute***. If it's found it checks if there are the following signatures:
* **static void OnInitializeSubModulesPrefix()** - will execute just before the game starts to initialize the SubModules. This gives us the ability to add SubModules declared in other programming languages like [Python](https://github.com/BUTR/Bannerlord.Python) and [Lua](https://github.com/BUTR/Bannerlord.Lua)
* **static void OnLoadSubModulesPostfix()** - will execute just after all SubModules were initialized
* **Continue Save File** - Allows to specify the save file to load when launching the game. Use */continuesave **mysavegame** *(save file should be specified without the extension)
* **Assembly Resolver** - Changes the assembly loading priority. Is an assembly is available in one of the loaded modules, it will be loaded from there instead.
4 changes: 4 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
---------------------------------------------------------------------------------------------------
Version: 1.0.3
Game Versions: v1.0.0,v1.0.1,v1.0.2,v1.0.3,v1.1.0,v1.1.1
* Always try to unblock .dll files on startup
---------------------------------------------------------------------------------------------------
Version: 1.0.2
Game Versions: v1.0.0,v1.0.1,v1.0.2,v1.0.3,v1.1.0,v1.1.1
* Should fix MessageBox dialog not being shown
Expand Down
1 change: 1 addition & 0 deletions src/Bannerlord.BLSE.Shared/Bannerlord.BLSE.Shared.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<PackageReference Include="Bannerlord.BUTR.Shared" Version="$(BUTRSharedVersion)" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
<PackageReference Include="Bannerlord.ModuleManager.Source" PrivateAssets="all" Version="$(BUTRModuleManagerVersion)" />
<PackageReference Include="Harmony.Extensions" Version="$(HarmonyExtensionsVersion)" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.188-beta" PrivateAssets="all" />
<PackageReference Include="IsExternalInit" Version="1.0.3" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers; buildtransitive" />
</ItemGroup>

Expand Down
11 changes: 6 additions & 5 deletions src/Bannerlord.BLSE.Shared/ModuleInitializer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Bannerlord.BLSE.Shared;
using Bannerlord.BLSE.Shared.Utils;
using Bannerlord.BUTR.Shared.Helpers;
using Bannerlord.ModuleManager;

Expand All @@ -15,8 +16,8 @@

using TaleWorlds.Core;

using MessageBoxButtons = Bannerlord.BLSE.Shared.MessageBoxButtons;
using MessageBoxIcon = Bannerlord.BLSE.Shared.MessageBoxIcon;
using MessageBoxButtons = Bannerlord.BLSE.Shared.Utils.MessageBoxButtons;
using MessageBoxIcon = Bannerlord.BLSE.Shared.Utils.MessageBoxIcon;

internal static class ModuleInitializer
{
Expand Down Expand Up @@ -120,7 +121,7 @@ internal static void Action()
Environment.Exit(1);
return null;
}

var harmonyBinFolder = Path.Combine(harmonyModuleFolder, "bin", configName);
var harmonyBinSteamFolder = Path.Combine(harmonySteamModuleFolder, "bin", configName);
if (!Directory.Exists(harmonyBinFolder) && !Directory.Exists(harmonyBinSteamFolder))
Expand All @@ -138,10 +139,10 @@ internal static void Action()
Environment.Exit(1);
return null;
}

return File.Exists(assemblyFile) ? assemblyFile : File.Exists(assemblySteamFile) ? assemblySteamFile : string.Empty;
}

private static Assembly? ResolveHarmonyAssembly(AssemblyName assemblyName)
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
Expand Down
4 changes: 4 additions & 0 deletions src/Bannerlord.BLSE.Shared/NativeMethods.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MessageBox
DeleteFile
GetConsoleWindow
ShowWindow
5 changes: 3 additions & 2 deletions src/Bannerlord.BLSE.Shared/NoExceptions/ProgramEx.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Bannerlord.LauncherEx;
using Bannerlord.BUTR.Shared.Helpers;
using Bannerlord.LauncherEx;

using HarmonyLib;
using HarmonyLib.BUTR.Extensions;
Expand All @@ -21,7 +22,7 @@ private record LauncherExContext(GraphicsForm GraphicsForm, StandaloneUIDomain S
public static LauncherExContext Create()
{
var resourceDepot = new ResourceDepot();
resourceDepot.AddLocation(BasePath.Name, "Modules/Native/LauncherGUI/");
resourceDepot.AddLocation(BasePath.Name, $"{ModuleInfoHelper.ModulesFolder}/Native/LauncherGUI/");
resourceDepot.CollectResources();
resourceDepot.StartWatchingChangesInDepot();

Expand Down
29 changes: 13 additions & 16 deletions src/Bannerlord.BLSE.Shared/Program.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,40 @@
using System;
using Bannerlord.BLSE.Shared.Utils;

using System;
using System.Linq;
using System.Runtime.InteropServices;

using Windows.Win32;
using Windows.Win32.UI.WindowsAndMessaging;

namespace Bannerlord.BLSE.Shared;

public static class Program
{
/*
[DllImport("kernel32.dll")]
private static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
private const int SW_HIDE = 0;
private const int SW_SHOW = 5;
*/

public static void Main(string[] args)
{
/*
var handle = GetConsoleWindow();
ShowWindow(handle, SW_HIDE);
*/
//PInvoke.ShowWindow(PInvoke.GetConsoleWindow(), SHOW_WINDOW_CMD.SW_HIDE);

switch (args[0])
{
case "launcher":
{
// Users can opt-out of unblocking for I guess performance reasons?
if (!args.Contains("/nounblock")) Unblocker.Unblock();
Launcher.Launch(args.Skip(1).ToArray());
break;
}
case "launcherex":
{
// Users can opt-out of unblocking for I guess performance reasons?
if (!args.Contains("/nounblock")) Unblocker.Unblock();
LauncherEx.Launch(args.Skip(1).ToArray());
break;
}
case "standalone":
{
// Since standalone is for external tools, they might unlock the files themselves
if (args.Contains("/unblock")) Unblocker.Unblock();
Standalone.Launch(args.Skip(1).ToArray());
break;
}
Expand Down
5 changes: 5 additions & 0 deletions src/Bannerlord.BLSE.Shared/Standalone.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Bannerlord.BLSE.Features.ContinueSaveFile;
using Bannerlord.BLSE.Features.Interceptor;
using Bannerlord.BLSE.Features.Xbox;
using Bannerlord.BLSE.Shared.Utils;
using Bannerlord.BUTR.Shared.Helpers;
using Bannerlord.ModuleManager;

Expand All @@ -17,6 +18,10 @@
using TaleWorlds.MountAndBlade.Launcher.Library;
using TaleWorlds.SaveSystem;

using MessageBoxButtons = Bannerlord.BLSE.Shared.Utils.MessageBoxButtons;
using MessageBoxDefaultButton = Bannerlord.BLSE.Shared.Utils.MessageBoxDefaultButton;
using MessageBoxIcon = Bannerlord.BLSE.Shared.Utils.MessageBoxIcon;

namespace Bannerlord.BLSE.Shared;

public static class Standalone
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
using System;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;

namespace Bannerlord.BLSE.Shared;
namespace Bannerlord.BLSE.Shared.Utils;

public static class MessageBoxDialog
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);

public static MessageBoxResult Show(string text) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, "\0", (uint)MessageBoxButtons.Ok);
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, "\0", (MESSAGEBOX_STYLE) MessageBoxButtons.Ok);

public static MessageBoxResult Show(string text, string caption) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, caption, (uint)MessageBoxButtons.Ok);
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, caption, (MESSAGEBOX_STYLE) MessageBoxButtons.Ok);

public static MessageBoxResult Show(string text, string caption, MessageBoxButtons buttons) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, caption, (uint)buttons);
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, caption, (MESSAGEBOX_STYLE) buttons);

public static MessageBoxResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, caption, ((uint)buttons) | ((uint)icon));
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, caption, ((MESSAGEBOX_STYLE) buttons) | ((MESSAGEBOX_STYLE) icon));

public static MessageBoxResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton button) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, caption, ((uint)buttons) | ((uint)icon) | ((uint)button));
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, caption, ((MESSAGEBOX_STYLE) buttons) | ((MESSAGEBOX_STYLE) icon) | ((MESSAGEBOX_STYLE) button));

public static MessageBoxResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton button, MessageBoxModal modal) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, caption, ((uint)buttons) | ((uint)icon) | ((uint)button) | ((uint)modal));
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, caption, ((MESSAGEBOX_STYLE) buttons) | ((MESSAGEBOX_STYLE) icon) | ((MESSAGEBOX_STYLE) button) | ((MESSAGEBOX_STYLE) modal));
}

public enum MessageBoxButtons
Expand Down
14 changes: 14 additions & 0 deletions src/Bannerlord.BLSE.Shared/Utils/NtfsUnblocker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.IO;
using System.Threading.Tasks;

using Windows.Win32;

namespace Bannerlord.BLSE.Shared.Utils
{
internal static class NtfsUnblocker
{
public static void UnblockDirectory(string path, string wildcard = "*") => Parallel.ForEach(Directory.EnumerateFiles(path, wildcard, SearchOption.AllDirectories), UnblockFile);

public static void UnblockFile(string fileName) => PInvoke.DeleteFile($"{fileName}:Zone.Identifier");
}
}
61 changes: 61 additions & 0 deletions src/Bannerlord.BLSE.Shared/Utils/Unblocker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Bannerlord.BUTR.Shared.Helpers;

using HarmonyLib;
using HarmonyLib.BUTR.Extensions;

using System;
using System.IO;
using System.Reflection;
using System.Threading;

namespace Bannerlord.BLSE.Shared.Utils;

public static class Unblocker
{
private static readonly Harmony _harmony = new("Bannerlord.BLSE.Shared.Patches.Unblocker");
private static Thread? _currentUnblockingThread;


public static void Unblock()
{
if (_currentUnblockingThread is not null)
return;

Assembly.Load(new AssemblyName("TaleWorlds.Starter.Library"));

var result = _harmony.TryPatch(
AccessTools2.DeclaredMethod("TaleWorlds.Starter.Library.Program:Main"),
prefix: AccessTools2.Method(typeof(Unblocker), nameof(MainPrefix)));

if (result)
{
_currentUnblockingThread = new Thread(UnblockFiles);
_currentUnblockingThread.Start();
}
}

private static void MainPrefix()
{
// We prevent the game from being started if we didn't finish with unblocking
try
{
_currentUnblockingThread?.Join();
}
catch (Exception) { /* ignore */ }

_harmony.Unpatch(AccessTools2.DeclaredMethod("TaleWorlds.Starter.Library.Program:Main"), AccessTools2.Method(typeof(Unblocker), nameof(MainPrefix)));
}

private static void UnblockFiles()
{
var modulesPath = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "../", "../", ModuleInfoHelper.ModulesFolder));
if (Directory.Exists(modulesPath))
{
try
{
NtfsUnblocker.UnblockDirectory(modulesPath, "*.dll");
}
catch { /* ignore */ }
}
}
}
8 changes: 4 additions & 4 deletions src/Bannerlord.BLSE/Features/Xbox/Patches/ModulePatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ public static bool Enable(Harmony harmony)
AccessTools2.Constructor(typeof(Module)),
prefix: AccessTools2.Method(typeof(ModulePatch), nameof(ShowedLoginScreenPrefix)));
if (!res1) return false;

var res2 = harmony.TryPatch(
AccessTools2.DeclaredMethod("TaleWorlds.MountAndBlade.Platform.GDK.PlatformGDKSubModule:OnSubModuleLoad"),
prefix: AccessTools2.Method(typeof(ModulePatch), nameof(OnSubModuleLoadPrefix)));
if (!res2) return false;

var res3 = harmony.TryPatch(
AccessTools2.DeclaredMethod("TaleWorlds.MountAndBlade.Platform.GDK.PlatformGDKSubModule:OnApplicationTick"),
prefix: AccessTools2.Method(typeof(ModulePatch), nameof(OnApplicationTickPrefix)));
Expand All @@ -38,14 +38,14 @@ private static void ShowedLoginScreenPrefix(ref bool ___ShowedLoginScreen)
{
___ShowedLoginScreen = true;
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static bool OnSubModuleLoadPrefix()
{
Common.PlatformFileHelper = new PlatformFileHelperPC("Mount and Blade II Bannerlord");
return false;
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static bool OnApplicationTickPrefix()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Bannerlord.LauncherEx/BUTRLauncherManagerHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ public LoadOrder LoadTWLoadOrder()
{
BetaSorting = LauncherSettings.BetaSorting,
FixCommonIssues = LauncherSettings.FixCommonIssues,
UnblockFiles = LauncherSettings.UnblockFiles,
UnblockFiles = true, // TODO: Remove. Always unblock
Language = Manager.GetActiveLanguage(),
};

Expand Down
20 changes: 9 additions & 11 deletions src/Bannerlord.LauncherEx/Helpers/Input/MessageBoxDialog.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
using System;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;

namespace Bannerlord.LauncherEx.Helpers.Input;

public static class MessageBoxDialog
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);

public static MessageBoxResult Show(string text) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, "\0", (uint)MessageBoxButtons.Ok);
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, "\0", (MESSAGEBOX_STYLE) MessageBoxButtons.Ok);

public static MessageBoxResult Show(string text, string caption) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, caption, (uint)MessageBoxButtons.Ok);
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, caption, (MESSAGEBOX_STYLE) MessageBoxButtons.Ok);

public static MessageBoxResult Show(string text, string caption, MessageBoxButtons buttons) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, caption, (uint)buttons);
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, caption, (MESSAGEBOX_STYLE) buttons);

public static MessageBoxResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, caption, ((uint)buttons) | ((uint)icon));
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, caption, ((MESSAGEBOX_STYLE) buttons) | ((MESSAGEBOX_STYLE) icon));

public static MessageBoxResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton button) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, caption, ((uint)buttons) | ((uint)icon) | ((uint)button));
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, caption, ((MESSAGEBOX_STYLE) buttons) | ((MESSAGEBOX_STYLE) icon) | ((MESSAGEBOX_STYLE) button));

public static MessageBoxResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton button, MessageBoxModal modal) =>
(MessageBoxResult) MessageBox(IntPtr.Zero, text, caption, ((uint)buttons) | ((uint)icon) | ((uint)button) | ((uint)modal));
(MessageBoxResult) PInvoke.MessageBox(HWND.Null, text, caption, ((MESSAGEBOX_STYLE) buttons) | ((MESSAGEBOX_STYLE) icon) | ((MESSAGEBOX_STYLE) button) | ((MESSAGEBOX_STYLE) modal));
}

public enum MessageBoxButtons
Expand Down
Loading

0 comments on commit 8119234

Please sign in to comment.