diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index ade1755..9319d53 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -1,29 +1 @@
-FROM mcr.microsoft.com/vscode/devcontainers/base:ubuntu-20.04
-
-RUN apt-get update \
- && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
- wget \
- ca-certificates \
- \
- # .NET dependencies
- libc6 \
- libgcc1 \
- libgssapi-krb5-2 \
- libicu66 \
- libssl1.1 \
- libstdc++6 \
- zlib1g \
- \
- # Mono
- mono-devel \
- # Install Microsoft package feed
- && wget -q https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb \
- && dpkg -i packages-microsoft-prod.deb \
- && rm packages-microsoft-prod.deb \
- \
- # Install .NET 6 & 7
- && apt-get update \
- && apt-get install -y --no-install-recommends \
- dotnet-sdk-6.0 \
- dotnet-sdk-7.0 \
- && rm -rf /var/lib/apt/lists/*
\ No newline at end of file
+FROM ghcr.io/butr/devcontainer:latest
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 5940eaa..9b17a2d 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,11 +1,79 @@
{
- "name": ".NET Core & Mono",
+ "name": ".NET & Mono & Powershell",
"build": {
- "dockerfile": "Dockerfile"
+ "dockerfile": "Dockerfile",
+ "cacheFrom": [
+ "ghcr.io/butr/bannerlord.blse-devcontainer:latest"
+ ]
},
"features": {
+ "ghcr.io/butr/devcontainer/upgrade:1": {
+
+ },
+ "ghcr.io/devcontainers/features/git:1": {
+ "version": "latest",
+ "ppa": "false"
+ },
+ "ghcr.io/butr/devcontainer/mono:1": {
+
+ },
+ "ghcr.io/devcontainers/features/dotnet:2": {
+
+ },
"ghcr.io/devcontainers/features/powershell:1": {
- "version": "latest"
+ "version": "latest"
+ }
+ },
+ "overrideFeatureInstallOrder": [
+ "ghcr.io/butr/devcontainer/upgrade",
+ "ghcr.io/devcontainers/features/git",
+ "ghcr.io/butr/devcontainer/mono",
+ "ghcr.io/devcontainers/features/dotnet",
+ "ghcr.io/devcontainers/features/powershell",
+ ],
+ "containerEnv": {
+ "DOTNET_CLI_TELEMETRY_OPTOUT": "true",
+ "DOTNET_HTTPREPL_TELEMETRY_OPTOUT": "true",
+ "DOTNET_NOLOGO": "true",
+ "DOTNET_SKIP_FIRST_TIME_EXPERIENCE": "true",
+ "DOTNET_USE_POLLING_FILE_WATCHER": "true",
+ "NUGET_XMLDOC_MODE": "skip",
+
+ "BANNERLORD_BUTR_COMPATIBILITY_SCORE_URL": "${localEnv:BANNERLORD_BUTR_COMPATIBILITY_SCORE_URL}"
+ },
+ "mounts": [
+ {
+ "source":"${localEnv:BANNERLORD_GAME_DIR}",
+ "target":"/bannerlord",
+ "type":"bind"
+ }
+ ],
+ "postStartCommand": {
+ "dotnet restore": "dotnet restore src/Bannerlord.BLSE.sln"
+ },
+ "postAttachCommand": "dotnet restore src/Bannerlord.BLSE.sln",
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "editorconfig.editorconfig",
+ "github.vscode-github-actions",
+ "ms-vscode.powershell",
+ "ms-azuretools.vscode-docker",
+ "ms-dotnettools.csdevkit"
+ ],
+ "settings": {
+ "terminal.integrated.defaultProfile.linux": "pwsh",
+ "terminal.integrated.profiles.linux": {
+ "path": {
+ "path": "/usr/local/bin/pwsh"
+ }
+ },
+ "powershell.powerShellAdditionalExePaths": {
+ "pwsh": "/usr/local/bin/pwsh"
+ },
+ "telemetry.telemetryLevel": "off",
+ "dotnetAcquisitionExtension.enableTelemetry": false
+ }
}
}
-}
+}
\ No newline at end of file
diff --git a/.github/workflows/devcontainer.yml b/.github/workflows/devcontainer.yml
new file mode 100644
index 0000000..45d2d33
--- /dev/null
+++ b/.github/workflows/devcontainer.yml
@@ -0,0 +1,33 @@
+name: Dev Container Build and Push Image
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ paths:
+ - '.devcontainer/**/*'
+ - '.github/workflows/devcontainer.yml'
+
+jobs:
+ build-and-push:
+ runs-on: ubuntu-latest
+ steps:
+ -
+ name: Checkout
+ id: checkout
+ uses: actions/checkout@v4
+ -
+ name: Login to GitHub Container Registry
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: BUTR
+ password: ${{ secrets.TOKEN_GPR }}
+ -
+ name: Pre-build dev container image
+ uses: devcontainers/ci@v0.3
+ with:
+ imageName: ghcr.io/butr/bannerlord.blse-devcontainer
+ cacheFrom: ghcr.io/butr/bannerlord.blse-devcontainer
+ push: always
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 0ec3974..ab948a1 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -76,13 +76,13 @@ jobs:
###########################
publish-on-nexusmods:
if: github.ref == 'refs/heads/master'
- needs: ["get-changelog", "build"]
+ needs: [get-changelog, build]
uses: BUTR/workflows/.github/workflows/release-nexusmods.yml@master
with:
nexusmods_game_id: mountandblade2bannerlord
nexusmods_mod_id: 1
mod_filename: 'Bannerlord Software Extender (BLSE)'
- mod_version: ${{ needs.build-changelog.outputs.mod_version }}
+ mod_version: ${{ needs.get-changelog.outputs.mod_version }}
mod_description: ${{ needs.build.outputs.mod_description }}
artifact_name: bannerlord
secrets:
@@ -94,11 +94,11 @@ jobs:
###########################
publish-on-github:
if: github.ref == 'refs/heads/master'
- needs: ["get-changelog", "build"]
+ needs: [get-changelog, build]
uses: BUTR/workflows/.github/workflows/release-github.yml@master
with:
mod_id: Bannerlord.BLSE
- mod_version: ${{ needs.build-changelog.outputs.mod_version }}
+ mod_version: ${{ needs.get-changelog.outputs.mod_version }}
mod_description: ${{ needs.build.outputs.mod_description }}
artifact_name: bannerlord
@@ -107,7 +107,7 @@ jobs:
###########################
publish-on-steam:
if: github.ref == 'refs/heads/master'
- needs: ["get-changelog", "build"]
+ needs: [get-changelog, build]
runs-on: ubuntu-latest
steps:
- name: Download Module artifact
@@ -123,7 +123,7 @@ jobs:
ssfnFileName: ${{ secrets.STEAM_SSFN_FILE_NAME }}
ssfnFileContents: ${{ secrets.STEAM_SSFN_FILE_CONTENTS }}
appId: ${{ secrets.STEAM_APPID }}
- buildDescription: ${{ needs.build-changelog.outputs.mod_version }}
- rootPath: artifact
+ buildDescription: ${{ needs.get-changelog.outputs.mod_version }}
+ rootPath: build
depot1Path: ./artifact
releaseBranch: prerelease
diff --git a/build/common.props b/build/common.props
index 21ac841..c6e97ff 100644
--- a/build/common.props
+++ b/build/common.props
@@ -11,13 +11,13 @@
- 1.4.12
+ 1.5.0
2.2.2
- 3.0.0.137
- 5.0.209
+ 3.0.0.139
+ 5.0.222
3.2.0.77
1.0.1.50
- 1.0.77
+ 1.0.107
full
diff --git a/build/common.targets b/build/common.targets
index 47a6443..411f264 100644
--- a/build/common.targets
+++ b/build/common.targets
@@ -37,9 +37,10 @@ if (Files.Length > 0)
Log.LogMessage(MessageImportance.Normal, $"EmbeddedResource Src: {sourceItemSpec}");
using (var sourceStream = File.OpenRead(sourcePath))
- using (var destinationStream = File.OpenWrite(destinationPath))
+ using (var destinationStream = new FileStream(destinationPath, FileMode.OpenOrCreate, FileAccess.Write))
using (var destinationGZip = new GZipStream(destinationStream, CompressionLevel.Optimal))
{
+ destinationStream.SetLength(0);
sourceStream.CopyTo(destinationGZip);
}
diff --git a/changelog.txt b/changelog.txt
index b7151d0..d06c9e1 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,4 +1,10 @@
---------------------------------------------------------------------------------------------------
+Version: 1.5.0
+Game Versions: v1.0.0,v1.0.1,v1.0.2,v1.0.3,v1.1.0,v1.1.1,v1.1.2,v1.1.3,v1.1.4,v1.1.5,v1.1.6,v1.2.x
+* BETA Release!
+* Switched to new launcher manager backend
+* Added Update Recommendations - based on BUTR Analytics Server (based on ButterLib Crash Reports)
+---------------------------------------------------------------------------------------------------
Version: 1.4.12
Game Versions: v1.0.0,v1.0.1,v1.0.2,v1.0.3,v1.1.0,v1.1.1,v1.1.2,v1.1.3,v1.1.4,v1.1.5,v1.1.6,v1.2.9
* Adapted to v1.2.9. Thanks to jzebedee!
diff --git a/src/Bannerlord.BLSE.Loaders.Launcher/Bannerlord.BLSE.Loaders.Launcher.csproj b/src/Bannerlord.BLSE.Loaders.Launcher/Bannerlord.BLSE.Loaders.Launcher.csproj
index 0ca898b..906c6f4 100644
--- a/src/Bannerlord.BLSE.Loaders.Launcher/Bannerlord.BLSE.Loaders.Launcher.csproj
+++ b/src/Bannerlord.BLSE.Loaders.Launcher/Bannerlord.BLSE.Loaders.Launcher.csproj
@@ -4,7 +4,7 @@
winexe
x64
net472
- 11.0
+ 12.0
enable
../../resources/BLSE_SMALL.ico
true
diff --git a/src/Bannerlord.BLSE.Loaders.LauncherEx/Bannerlord.BLSE.Loaders.LauncherEx.csproj b/src/Bannerlord.BLSE.Loaders.LauncherEx/Bannerlord.BLSE.Loaders.LauncherEx.csproj
index 73e65b2..bd83798 100644
--- a/src/Bannerlord.BLSE.Loaders.LauncherEx/Bannerlord.BLSE.Loaders.LauncherEx.csproj
+++ b/src/Bannerlord.BLSE.Loaders.LauncherEx/Bannerlord.BLSE.Loaders.LauncherEx.csproj
@@ -4,7 +4,7 @@
winexe
x64
net472
- 11.0
+ 12.0
enable
../../resources/BLSE_SMALL.ico
true
diff --git a/src/Bannerlord.BLSE.Loaders.Standalone/Bannerlord.BLSE.Loaders.Standalone.csproj b/src/Bannerlord.BLSE.Loaders.Standalone/Bannerlord.BLSE.Loaders.Standalone.csproj
index 3e43bce..b797fac 100644
--- a/src/Bannerlord.BLSE.Loaders.Standalone/Bannerlord.BLSE.Loaders.Standalone.csproj
+++ b/src/Bannerlord.BLSE.Loaders.Standalone/Bannerlord.BLSE.Loaders.Standalone.csproj
@@ -4,7 +4,7 @@
winexe
x64
net472
- 11.0
+ 12.0
enable
../../resources/BLSE_SMALL.ico
true
diff --git a/src/Bannerlord.BLSE.Shared/Bannerlord.BLSE.Shared.csproj b/src/Bannerlord.BLSE.Shared/Bannerlord.BLSE.Shared.csproj
index b30d038..75ee181 100644
--- a/src/Bannerlord.BLSE.Shared/Bannerlord.BLSE.Shared.csproj
+++ b/src/Bannerlord.BLSE.Shared/Bannerlord.BLSE.Shared.csproj
@@ -2,7 +2,7 @@
netstandard2.0
- 11.0
+ 12.0
enable
x64
library
@@ -18,13 +18,11 @@
false
true
- $(PkgBUTR_ILRepack)\tools\net461\ILRepack.exe
-
-
-
+
+
@@ -79,8 +77,10 @@
$(MSBuildThisFileDirectory)..\Bannerlord.LauncherEx\Bannerlord.LauncherEx.csproj
"$([System.IO.Path]::GetFullPath('$(LauncherExProject)'))"
-
-
+
+
+
+
diff --git a/src/Bannerlord.BLSE/BLSECommands.cs b/src/Bannerlord.BLSE/BLSECommands.cs
index 427b99f..17d704b 100644
--- a/src/Bannerlord.BLSE/BLSECommands.cs
+++ b/src/Bannerlord.BLSE/BLSECommands.cs
@@ -4,14 +4,13 @@
using System.Linq;
using System.Reflection;
-namespace Bannerlord.BLSE
+namespace Bannerlord.BLSE;
+
+public static class BLSECommands
{
- public static class BLSECommands
+ public static string GetVersion(List _)
{
- public static string GetVersion(List _)
- {
- var blseMetadata = AccessTools2.TypeByName("Bannerlord.BLSE.BLSEInterceptorAttribute")?.Assembly.GetCustomAttributes();
- return blseMetadata?.FirstOrDefault(x => x.Key == "BLSEVersion")?.Value ?? "0.0.0.0";
- }
+ var blseMetadata = AccessTools2.TypeByName("Bannerlord.BLSE.BLSEInterceptorAttribute")?.Assembly.GetCustomAttributes();
+ return blseMetadata?.FirstOrDefault(x => x.Key == "BLSEVersion")?.Value ?? "0.0.0.0";
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/BLSEExceptionHandlerAttribute.cs b/src/Bannerlord.BLSE/BLSEExceptionHandlerAttribute.cs
index 1604721..1fcaca3 100644
--- a/src/Bannerlord.BLSE/BLSEExceptionHandlerAttribute.cs
+++ b/src/Bannerlord.BLSE/BLSEExceptionHandlerAttribute.cs
@@ -1,7 +1,6 @@
using System;
-namespace Bannerlord.BLSE
-{
- [AttributeUsage(AttributeTargets.Class)]
- public sealed class BLSEExceptionHandlerAttribute : Attribute { }
-}
\ No newline at end of file
+namespace Bannerlord.BLSE;
+
+[AttributeUsage(AttributeTargets.Class)]
+public sealed class BLSEExceptionHandlerAttribute : Attribute { }
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/BLSEInterceptorAttribute.cs b/src/Bannerlord.BLSE/BLSEInterceptorAttribute.cs
index 7d82759..ae128ed 100644
--- a/src/Bannerlord.BLSE/BLSEInterceptorAttribute.cs
+++ b/src/Bannerlord.BLSE/BLSEInterceptorAttribute.cs
@@ -1,7 +1,6 @@
using System;
-namespace Bannerlord.BLSE
-{
- [AttributeUsage(AttributeTargets.Class)]
- public sealed class BLSEInterceptorAttribute : Attribute { }
-}
\ No newline at end of file
+namespace Bannerlord.BLSE;
+
+[AttributeUsage(AttributeTargets.Class)]
+public sealed class BLSEInterceptorAttribute : Attribute { }
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Bannerlord.BLSE.csproj b/src/Bannerlord.BLSE/Bannerlord.BLSE.csproj
index 196a480..6739a13 100644
--- a/src/Bannerlord.BLSE/Bannerlord.BLSE.csproj
+++ b/src/Bannerlord.BLSE/Bannerlord.BLSE.csproj
@@ -6,7 +6,7 @@
$(Version).$(GITHUB_RUN_NUMBER)
netstandard2.0
- 11.0
+ 12.0
enable
x64
diff --git a/src/Bannerlord.BLSE/FeatureIds.cs b/src/Bannerlord.BLSE/FeatureIds.cs
index 4b583e8..caeeadc 100644
--- a/src/Bannerlord.BLSE/FeatureIds.cs
+++ b/src/Bannerlord.BLSE/FeatureIds.cs
@@ -1,35 +1,34 @@
using System.Collections.Generic;
-namespace Bannerlord.BLSE
+namespace Bannerlord.BLSE;
+
+public static class FeatureIds
{
- public static class FeatureIds
- {
- public static string InterceptorId => "BLSE.LoadingInterceptor";
- public static string AssemblyResolverId => "BLSE.AssemblyResolver";
- private static string InterceptorId2 => "BUTRLoader.BUTRLoadingInterceptor";
- private static string AssemblyResolverId2 => "BUTRLoader.BUTRAssemblyResolver";
- public static string ContinueSaveFileId => "BLSE.ContinueSaveFile";
- public static string CommandsId => "BLSE.Commands";
- public static string XboxId => "BLSE.Xbox";
- public static string ExceptionInterceptorId => "BLSE.ExceptionInterceptor";
+ public static string InterceptorId => "BLSE.LoadingInterceptor";
+ public static string AssemblyResolverId => "BLSE.AssemblyResolver";
+ private static string InterceptorId2 => "BUTRLoader.BUTRLoadingInterceptor";
+ private static string AssemblyResolverId2 => "BUTRLoader.BUTRAssemblyResolver";
+ public static string ContinueSaveFileId => "BLSE.ContinueSaveFile";
+ public static string CommandsId => "BLSE.Commands";
+ public static string XboxId => "BLSE.Xbox";
+ public static string ExceptionInterceptorId => "BLSE.ExceptionInterceptor";
- public static readonly HashSet Features = new()
- {
- InterceptorId,
- InterceptorId2,
- AssemblyResolverId,
- AssemblyResolverId2,
- ContinueSaveFileId,
- CommandsId,
- ExceptionInterceptorId,
- };
- public static readonly HashSet LauncherFeatures = new()
- {
- InterceptorId,
- InterceptorId2,
- AssemblyResolverId,
- AssemblyResolverId2,
- ExceptionInterceptorId,
- };
- }
+ public static readonly HashSet Features = new()
+ {
+ InterceptorId,
+ InterceptorId2,
+ AssemblyResolverId,
+ AssemblyResolverId2,
+ ContinueSaveFileId,
+ CommandsId,
+ ExceptionInterceptorId,
+ };
+ public static readonly HashSet LauncherFeatures = new()
+ {
+ InterceptorId,
+ InterceptorId2,
+ AssemblyResolverId,
+ AssemblyResolverId2,
+ ExceptionInterceptorId,
+ };
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/AssemblyResolver/AssemblyResolverFeature.cs b/src/Bannerlord.BLSE/Features/AssemblyResolver/AssemblyResolverFeature.cs
index bac4795..edcb16a 100644
--- a/src/Bannerlord.BLSE/Features/AssemblyResolver/AssemblyResolverFeature.cs
+++ b/src/Bannerlord.BLSE/Features/AssemblyResolver/AssemblyResolverFeature.cs
@@ -11,68 +11,67 @@
using TaleWorlds.Library;
-namespace Bannerlord.BLSE.Features.AssemblyResolver
+namespace Bannerlord.BLSE.Features.AssemblyResolver;
+
+public static class AssemblyResolverFeature
{
- public static class AssemblyResolverFeature
- {
- private static ResolveEventHandler AssemblyLoaderOnAssemblyResolve =
- AccessTools2.GetDelegate(typeof(AssemblyLoader), "OnAssemblyResolve")!;
+ private static ResolveEventHandler AssemblyLoaderOnAssemblyResolve =
+ AccessTools2.GetDelegate(typeof(AssemblyLoader), "OnAssemblyResolve")!;
- public static string Id = FeatureIds.AssemblyResolverId;
+ public static string Id = FeatureIds.AssemblyResolverId;
- public static void Enable(Harmony harmony)
- {
- AssemblyLoader.Initialize();
- AppDomain.CurrentDomain.AssemblyResolve -= AssemblyLoaderOnAssemblyResolve;
- AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
- }
+ public static void Enable(Harmony harmony)
+ {
+ AssemblyLoader.Initialize();
+ AppDomain.CurrentDomain.AssemblyResolve -= AssemblyLoaderOnAssemblyResolve;
+ AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
+ }
- private static Assembly? OnAssemblyResolve(object? sender, ResolveEventArgs args)
- {
- if (args.Name is null) return null;
+ private static Assembly? OnAssemblyResolve(object? sender, ResolveEventArgs args)
+ {
+ if (args.Name is null) return null;
- var name = new AssemblyName(args.Name);
- if (name.Name is null) return null;
+ var name = new AssemblyName(args.Name);
+ if (name.Name is null) return null;
- foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
+ foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ if (assembly.FullName == name.FullName)
{
- if (assembly.FullName == name.FullName)
- {
- return assembly;
- }
+ return assembly;
}
+ }
- try
- {
- var configName = Path.GetFileName(Directory.GetCurrentDirectory());
-
- var isInGame = GameUtils.GetModulesNames() is not null;
+ try
+ {
+ var configName = Path.GetFileName(Directory.GetCurrentDirectory());
- var assemblies = (isInGame ? ModuleInfoHelper.GetLoadedModules() : ModuleInfoHelper.GetModules()).Select(x =>
- {
- var directory = Path.Combine(x.Path, "bin", configName);
- return Directory.Exists(directory) ? Directory.GetFiles(directory, "*.dll") : Array.Empty();
- }).ToArray();
+ var isInGame = GameUtils.GetModulesNames() is not null;
- var assembly = assemblies.SelectMany(x => x).FirstOrDefault(x => Path.GetFileNameWithoutExtension(x) == name.Name);
+ var assemblies = (isInGame ? ModuleInfoHelper.GetLoadedModules() : ModuleInfoHelper.GetModules()).Select(x =>
+ {
+ var directory = Path.Combine(x.Path, "bin", configName);
+ return Directory.Exists(directory) ? Directory.GetFiles(directory, "*.dll") : Array.Empty();
+ }).ToArray();
- if (assembly is not null)
- {
- return Assembly.LoadFrom(assembly);
- }
+ var assembly = assemblies.SelectMany(x => x).FirstOrDefault(x => Path.GetFileNameWithoutExtension(x) == name.Name);
- assembly = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.dll").FirstOrDefault(x => Path.GetFileNameWithoutExtension(x) == name.Name);
- if (assembly is not null)
- {
- return Assembly.LoadFrom(assembly);
- }
- }
- catch (Exception)
+ if (assembly is not null)
{
- return null;
+ return Assembly.LoadFrom(assembly);
}
+ assembly = Directory.GetFiles(Directory.GetCurrentDirectory(), "*.dll").FirstOrDefault(x => Path.GetFileNameWithoutExtension(x) == name.Name);
+ if (assembly is not null)
+ {
+ return Assembly.LoadFrom(assembly);
+ }
+ }
+ catch (Exception)
+ {
return null;
}
+
+ return null;
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/Commands/CommandsFeature.cs b/src/Bannerlord.BLSE/Features/Commands/CommandsFeature.cs
index 33b6910..68debd4 100644
--- a/src/Bannerlord.BLSE/Features/Commands/CommandsFeature.cs
+++ b/src/Bannerlord.BLSE/Features/Commands/CommandsFeature.cs
@@ -5,20 +5,19 @@
using System;
using System.Collections.Generic;
-namespace Bannerlord.BLSE.Features.Commands
+namespace Bannerlord.BLSE.Features.Commands;
+
+public static class CommandsFeature
{
- public static class CommandsFeature
- {
- public static string Id = FeatureIds.CommandsId;
+ public static string Id = FeatureIds.CommandsId;
- public static readonly Dictionary, string>> Functions = new()
- {
- { "blse.version", BLSECommands.GetVersion }
- };
+ public static readonly Dictionary, string>> Functions = new()
+ {
+ { "blse.version", BLSECommands.GetVersion }
+ };
- public static void Enable(Harmony harmony)
- {
- CommandLineFunctionalityPatch.Enable(harmony);
- }
+ public static void Enable(Harmony harmony)
+ {
+ CommandLineFunctionalityPatch.Enable(harmony);
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/Commands/Patches/CommandLineFunctionalityPatch.cs b/src/Bannerlord.BLSE/Features/Commands/Patches/CommandLineFunctionalityPatch.cs
index 4b50e6d..e27a221 100644
--- a/src/Bannerlord.BLSE/Features/Commands/Patches/CommandLineFunctionalityPatch.cs
+++ b/src/Bannerlord.BLSE/Features/Commands/Patches/CommandLineFunctionalityPatch.cs
@@ -9,55 +9,54 @@
using TaleWorlds.Library;
-namespace Bannerlord.BLSE.Features.Commands.Patches
+namespace Bannerlord.BLSE.Features.Commands.Patches;
+
+internal static class CommandLineFunctionalityPatch
{
- internal static class CommandLineFunctionalityPatch
+ private readonly ref struct CommandLineFunctionHandle
{
- private readonly ref struct CommandLineFunctionHandle
- {
- private delegate object CommandLineFunctionCtorDelegate(Func, string> commandlinefunc);
- private static readonly CommandLineFunctionCtorDelegate? CommandLineFunctionCtor =
- AccessTools2.GetConstructorDelegate("TaleWorlds.Library.CommandLineFunctionality+CommandLineFunction", new[] { typeof(Func, string>) });
+ private delegate object CommandLineFunctionCtorDelegate(Func, string> commandlinefunc);
+ private static readonly CommandLineFunctionCtorDelegate? CommandLineFunctionCtor =
+ AccessTools2.GetConstructorDelegate("TaleWorlds.Library.CommandLineFunctionality+CommandLineFunction", new[] { typeof(Func, string>) });
- public static CommandLineFunctionHandle Create(Func, string> commandlinefunc)
- {
- var commandLineFunction = CommandLineFunctionCtor?.Invoke(commandlinefunc);
- return commandLineFunction is not null ? new(commandLineFunction) : default;
- }
+ public static CommandLineFunctionHandle Create(Func, string> commandlinefunc)
+ {
+ var commandLineFunction = CommandLineFunctionCtor?.Invoke(commandlinefunc);
+ return commandLineFunction is not null ? new(commandLineFunction) : default;
+ }
- public object Object { get; }
+ public object Object { get; }
- private CommandLineFunctionHandle(object obj) => Object = obj;
- }
+ private CommandLineFunctionHandle(object obj) => Object = obj;
+ }
- private static Harmony? _harmony;
+ private static Harmony? _harmony;
- public static bool Enable(Harmony harmony)
- {
- _harmony = harmony;
+ public static bool Enable(Harmony harmony)
+ {
+ _harmony = harmony;
- return harmony.TryPatch(
- AccessTools2.DeclaredMethod(typeof(CommandLineFunctionality), nameof(CommandLineFunctionality.CollectCommandLineFunctions)),
- postfix: AccessTools2.DeclaredMethod(typeof(CommandLineFunctionalityPatch), nameof(CollectCommandLineFunctionsPostfix)));
- }
+ return harmony.TryPatch(
+ AccessTools2.DeclaredMethod(typeof(CommandLineFunctionality), nameof(CommandLineFunctionality.CollectCommandLineFunctions)),
+ postfix: AccessTools2.DeclaredMethod(typeof(CommandLineFunctionalityPatch), nameof(CollectCommandLineFunctionsPostfix)));
+ }
- private static void CollectCommandLineFunctionsPostfix(IDictionary ___AllFunctions, ref List __result)
+ private static void CollectCommandLineFunctionsPostfix(IDictionary ___AllFunctions, ref List __result)
+ {
+ try
{
- try
+ foreach (var (name, function) in CommandsFeature.Functions)
{
- foreach (var (name, function) in CommandsFeature.Functions)
- {
- if (CommandLineFunctionHandle.Create(function) is not { Object: { } cmdFuncObject }) continue;
- ___AllFunctions.Add(name, cmdFuncObject);
- __result.Add(name);
- }
- }
- finally
- {
- _harmony?.Unpatch(
- AccessTools2.DeclaredMethod(typeof(CommandLineFunctionality), nameof(CommandLineFunctionality.CollectCommandLineFunctions)),
- AccessTools2.DeclaredMethod(typeof(CommandLineFunctionalityPatch), nameof(CollectCommandLineFunctionsPostfix)));
+ if (CommandLineFunctionHandle.Create(function) is not { Object: { } cmdFuncObject }) continue;
+ ___AllFunctions.Add(name, cmdFuncObject);
+ __result.Add(name);
}
}
+ finally
+ {
+ _harmony?.Unpatch(
+ AccessTools2.DeclaredMethod(typeof(CommandLineFunctionality), nameof(CommandLineFunctionality.CollectCommandLineFunctions)),
+ AccessTools2.DeclaredMethod(typeof(CommandLineFunctionalityPatch), nameof(CollectCommandLineFunctionsPostfix)));
+ }
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/ContinueSaveFile/ContinueSaveFileFeature.cs b/src/Bannerlord.BLSE/Features/ContinueSaveFile/ContinueSaveFileFeature.cs
index c3ff8f9..2b7daca 100644
--- a/src/Bannerlord.BLSE/Features/ContinueSaveFile/ContinueSaveFileFeature.cs
+++ b/src/Bannerlord.BLSE/Features/ContinueSaveFile/ContinueSaveFileFeature.cs
@@ -6,39 +6,38 @@
using TaleWorlds.MountAndBlade;
-namespace Bannerlord.BLSE.Features.ContinueSaveFile
+namespace Bannerlord.BLSE.Features.ContinueSaveFile;
+
+public static class ContinueSaveFileFeature
{
- public static class ContinueSaveFileFeature
- {
- public static string Id = FeatureIds.ContinueSaveFileId;
+ public static string Id = FeatureIds.ContinueSaveFileId;
- private static string? _currentSaveFile;
- private static Harmony? _harmony;
+ private static string? _currentSaveFile;
+ private static Harmony? _harmony;
- public static void Enable(Harmony harmony)
- {
- _harmony = harmony;
- ModulePatch.OnSaveGameArgParsed += (_, saveFile) => _currentSaveFile = saveFile;
- ModulePatch.Enable(harmony);
+ public static void Enable(Harmony harmony)
+ {
+ _harmony = harmony;
+ ModulePatch.OnSaveGameArgParsed += (_, saveFile) => _currentSaveFile = saveFile;
+ ModulePatch.Enable(harmony);
- AppDomain.CurrentDomain.AssemblyLoad += CurrentDomainOnAssemblyLoad;
- }
+ AppDomain.CurrentDomain.AssemblyLoad += CurrentDomainOnAssemblyLoad;
+ }
- private static void CurrentDomainOnAssemblyLoad(object? sender, AssemblyLoadEventArgs args)
- {
- if (_harmony is null) return;
-
- if (args.LoadedAssembly.GetName().Name == "SandBox")
- {
- SandBoxSubModulePatch.GetSaveGameArg = GetSaveFile;
- SandBoxSubModulePatch.Enable(_harmony);
- InformationManagerPatch.Enable(_harmony);
- }
- }
+ private static void CurrentDomainOnAssemblyLoad(object? sender, AssemblyLoadEventArgs args)
+ {
+ if (_harmony is null) return;
- private static string? GetSaveFile(GameStartupInfo startupInfo)
+ if (args.LoadedAssembly.GetName().Name == "SandBox")
{
- return _currentSaveFile;
+ SandBoxSubModulePatch.GetSaveGameArg = GetSaveFile;
+ SandBoxSubModulePatch.Enable(_harmony);
+ InformationManagerPatch.Enable(_harmony);
}
}
+
+ private static string? GetSaveFile(GameStartupInfo startupInfo)
+ {
+ return _currentSaveFile;
+ }
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/InformationManagerConfirmInquiryHandler.cs b/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/InformationManagerConfirmInquiryHandler.cs
index 110019e..3d7a27f 100644
--- a/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/InformationManagerConfirmInquiryHandler.cs
+++ b/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/InformationManagerConfirmInquiryHandler.cs
@@ -1,10 +1,9 @@
using System;
-namespace Bannerlord.BLSE.Features.ContinueSaveFile.Patches
+namespace Bannerlord.BLSE.Features.ContinueSaveFile.Patches;
+
+internal class InformationManagerConfirmInquiryHandler : IDisposable
{
- internal class InformationManagerConfirmInquiryHandler : IDisposable
- {
- public InformationManagerConfirmInquiryHandler() => InformationManagerPatch.SkipChange = true;
- public void Dispose() => InformationManagerPatch.SkipChange = false;
- }
+ public InformationManagerConfirmInquiryHandler() => InformationManagerPatch.SkipChange = true;
+ public void Dispose() => InformationManagerPatch.SkipChange = false;
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/InformationManagerPatch.cs b/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/InformationManagerPatch.cs
index ee56089..dfb58fb 100644
--- a/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/InformationManagerPatch.cs
+++ b/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/InformationManagerPatch.cs
@@ -3,27 +3,26 @@
using TaleWorlds.Library;
-namespace Bannerlord.BLSE.Features.ContinueSaveFile.Patches
+namespace Bannerlord.BLSE.Features.ContinueSaveFile.Patches;
+
+internal static class InformationManagerPatch
{
- internal static class InformationManagerPatch
- {
- internal static bool SkipChange = false;
+ internal static bool SkipChange = false;
- public static bool Enable(Harmony harmony)
- {
- return harmony.TryPatch(
- original: AccessTools2.Method(typeof(InformationManager), "ShowInquiry"),
- prefix: AccessTools2.Method(typeof(InformationManagerPatch), nameof(Prefix)));
- }
+ public static bool Enable(Harmony harmony)
+ {
+ return harmony.TryPatch(
+ original: AccessTools2.Method(typeof(InformationManager), "ShowInquiry"),
+ prefix: AccessTools2.Method(typeof(InformationManagerPatch), nameof(Prefix)));
+ }
- private static bool Prefix(InquiryData data)
+ private static bool Prefix(InquiryData data)
+ {
+ if (SkipChange)
{
- if (SkipChange)
- {
- data.AffirmativeAction?.Invoke();
- return false;
- }
- return true;
+ data.AffirmativeAction?.Invoke();
+ return false;
}
+ return true;
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/ModulePatch.cs b/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/ModulePatch.cs
index 1f1c997..e7d3dec 100644
--- a/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/ModulePatch.cs
+++ b/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/ModulePatch.cs
@@ -9,38 +9,37 @@
using TaleWorlds.Engine;
using TaleWorlds.MountAndBlade;
-namespace Bannerlord.BLSE.Features.ContinueSaveFile.Patches
+namespace Bannerlord.BLSE.Features.ContinueSaveFile.Patches;
+
+internal static class ModulePatch
{
- internal static class ModulePatch
- {
- public static event Action? OnSaveGameArgParsed;
+ public static event Action? OnSaveGameArgParsed;
- private static Harmony? _harmony;
+ private static Harmony? _harmony;
- public static bool Enable(Harmony harmony)
- {
- _harmony = harmony;
+ public static bool Enable(Harmony harmony)
+ {
+ _harmony = harmony;
- return harmony.TryPatch(
- AccessTools2.DeclaredMethod(typeof(Module), "ProcessApplicationArguments"),
- postfix: AccessTools2.DeclaredMethod(typeof(ModulePatch), nameof(ProcessApplicationArgumentsPostfix)));
- }
+ return harmony.TryPatch(
+ AccessTools2.DeclaredMethod(typeof(Module), "ProcessApplicationArguments"),
+ postfix: AccessTools2.DeclaredMethod(typeof(ModulePatch), nameof(ProcessApplicationArgumentsPostfix)));
+ }
- private static void ProcessApplicationArgumentsPostfix(Module __instance)
+ private static void ProcessApplicationArgumentsPostfix(Module __instance)
+ {
+ var cli = Utilities.GetFullCommandLineString();
+ var array = CommandLineSplitter.SplitCommandLine(cli).ToArray();
+ for (var i = 0; i < array.Length; i++)
{
- var cli = Utilities.GetFullCommandLineString();
- var array = CommandLineSplitter.SplitCommandLine(cli).ToArray();
- for (var i = 0; i < array.Length; i++)
- {
- if (!string.Equals(array[i], "/continuesave", StringComparison.OrdinalIgnoreCase)) continue;
- if (array.Length <= i + 1) continue;
- var saveGame = array[i + 1];
- OnSaveGameArgParsed?.Invoke(__instance.StartupInfo, saveGame);
- }
-
- _harmony?.Unpatch(
- AccessTools2.DeclaredMethod(typeof(Module), "ProcessApplicationArguments"),
- AccessTools2.DeclaredMethod(typeof(ModulePatch), nameof(ProcessApplicationArgumentsPostfix)));
+ if (!string.Equals(array[i], "/continuesave", StringComparison.OrdinalIgnoreCase)) continue;
+ if (array.Length <= i + 1) continue;
+ var saveGame = array[i + 1];
+ OnSaveGameArgParsed?.Invoke(__instance.StartupInfo, saveGame);
}
+
+ _harmony?.Unpatch(
+ AccessTools2.DeclaredMethod(typeof(Module), "ProcessApplicationArguments"),
+ AccessTools2.DeclaredMethod(typeof(ModulePatch), nameof(ProcessApplicationArgumentsPostfix)));
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/SandBoxSubModulePatch.cs b/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/SandBoxSubModulePatch.cs
index 15e2404..94033ce 100644
--- a/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/SandBoxSubModulePatch.cs
+++ b/src/Bannerlord.BLSE/Features/ContinueSaveFile/Patches/SandBoxSubModulePatch.cs
@@ -10,66 +10,65 @@
using TaleWorlds.SaveSystem;
using TaleWorlds.SaveSystem.Load;
-namespace Bannerlord.BLSE.Features.ContinueSaveFile.Patches
+namespace Bannerlord.BLSE.Features.ContinueSaveFile.Patches;
+
+internal static class SandBoxSubModulePatch
{
- internal static class SandBoxSubModulePatch
- {
- private delegate void TryLoadSaveDelegate(SaveGameFileInfo saveInfo, Action onStartGame, Action? onCancel = null);
+ private delegate void TryLoadSaveDelegate(SaveGameFileInfo saveInfo, Action onStartGame, Action? onCancel = null);
- public static Func? GetSaveGameArg;
+ public static Func? GetSaveGameArg;
- private static Harmony? _harmony;
+ private static Harmony? _harmony;
- public static bool Enable(Harmony harmony)
- {
- _harmony = harmony;
+ public static bool Enable(Harmony harmony)
+ {
+ _harmony = harmony;
- return harmony.TryPatch(
- AccessTools2.DeclaredMethod("SandBox.SandBoxSubModule:OnInitialState"),
- prefix: AccessTools2.DeclaredMethod(typeof(SandBoxSubModulePatch), nameof(OnInitialStatePrefix)));
- }
+ return harmony.TryPatch(
+ AccessTools2.DeclaredMethod("SandBox.SandBoxSubModule:OnInitialState"),
+ prefix: AccessTools2.DeclaredMethod(typeof(SandBoxSubModulePatch), nameof(OnInitialStatePrefix)));
+ }
- private static bool OnInitialStatePrefix(MBSubModuleBase __instance)
+ private static bool OnInitialStatePrefix(MBSubModuleBase __instance)
+ {
+ static void FailedToLoad(string message)
{
- static void FailedToLoad(string message)
+ try
{
- try
- {
- InformationManagerWrapper.ShowInquiry("Warning!", message);
- }
- catch (Exception)
- {
- MessageBoxDialog.Show(message, "Warning!");
- }
+ InformationManagerWrapper.ShowInquiry("Warning!", message);
}
-
- if (AccessTools2.GetDelegate("SandBox.SandBoxSaveHelper:TryLoadSave") is not { } tryLoadSave) return true;
- if (GetSaveGameArg?.Invoke(Module.CurrentModule.StartupInfo) is not { } saveFileName) return true;
- if (saveFileName.EndsWith(".sav", StringComparison.OrdinalIgnoreCase)) saveFileName = saveFileName.Remove(saveFileName.Length - 4, 4);
- if (MBSaveLoad.GetSaveFileWithName(saveFileName) is not { } saveFile)
+ catch (Exception)
{
- FailedToLoad($"Failed to load Save!\nFailed to find save '{saveFileName}'!");
- return true;
- }
- if (AccessTools2.TypeByName("SandBox.SandBoxSubModule") is not { } sandBoxSubModuleType)
- {
- FailedToLoad($"Failed to load Save!\nFailed to find 'SandBox' module!");
- return true;
- }
- if (AccessTools2.GetDelegate>(__instance, sandBoxSubModuleType, "StartGame") is not { } startGame)
- {
- FailedToLoad($"Failed to load Save!\nUnexpected 'SandBox' issue! 'StartGame' method not found!");
- return true;
+ MessageBoxDialog.Show(message, "Warning!");
}
+ }
+
+ if (AccessTools2.GetDelegate("SandBox.SandBoxSaveHelper:TryLoadSave") is not { } tryLoadSave) return true;
+ if (GetSaveGameArg?.Invoke(Module.CurrentModule.StartupInfo) is not { } saveFileName) return true;
+ if (saveFileName.EndsWith(".sav", StringComparison.OrdinalIgnoreCase)) saveFileName = saveFileName.Remove(saveFileName.Length - 4, 4);
+ if (MBSaveLoad.GetSaveFileWithName(saveFileName) is not { } saveFile)
+ {
+ FailedToLoad($"Failed to load Save!\nFailed to find save '{saveFileName}'!");
+ return true;
+ }
+ if (AccessTools2.TypeByName("SandBox.SandBoxSubModule") is not { } sandBoxSubModuleType)
+ {
+ FailedToLoad($"Failed to load Save!\nFailed to find 'SandBox' module!");
+ return true;
+ }
+ if (AccessTools2.GetDelegate>(__instance, sandBoxSubModuleType, "StartGame") is not { } startGame)
+ {
+ FailedToLoad($"Failed to load Save!\nUnexpected 'SandBox' issue! 'StartGame' method not found!");
+ return true;
+ }
- using (var _ = new InformationManagerConfirmInquiryHandler())
- tryLoadSave(saveFile, startGame);
+ using (var _ = new InformationManagerConfirmInquiryHandler())
+ tryLoadSave(saveFile, startGame);
- _harmony?.Unpatch(
- AccessTools2.DeclaredMethod("SandBox.SandBoxSubModule:OnInitialState"),
- AccessTools2.DeclaredMethod(typeof(SandBoxSubModulePatch), nameof(OnInitialStatePrefix)));
+ _harmony?.Unpatch(
+ AccessTools2.DeclaredMethod("SandBox.SandBoxSubModule:OnInitialState"),
+ AccessTools2.DeclaredMethod(typeof(SandBoxSubModulePatch), nameof(OnInitialStatePrefix)));
- return false;
- }
+ return false;
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/ExceptionInterceptor/ExceptionInterceptorFeature.cs b/src/Bannerlord.BLSE/Features/ExceptionInterceptor/ExceptionInterceptorFeature.cs
index c8c5266..a1d5f48 100644
--- a/src/Bannerlord.BLSE/Features/ExceptionInterceptor/ExceptionInterceptorFeature.cs
+++ b/src/Bannerlord.BLSE/Features/ExceptionInterceptor/ExceptionInterceptorFeature.cs
@@ -8,71 +8,70 @@
using System.Runtime.ExceptionServices;
using System.Security;
-namespace Bannerlord.BLSE.Features.ExceptionInterceptor
+namespace Bannerlord.BLSE.Features.ExceptionInterceptor;
+
+public static class ExceptionInterceptorFeature
{
- public static class ExceptionInterceptorFeature
- {
- public static string Id = FeatureIds.ExceptionInterceptorId;
+ public static string Id = FeatureIds.ExceptionInterceptorId;
- private delegate void OnExceptionDelegate(Exception exception);
+ private delegate void OnExceptionDelegate(Exception exception);
- private static readonly Harmony ExceptionHandler = new("bannerlord.blse.exceptionhandler");
- private static readonly MethodInfo FinalizerMethod = AccessTools2.Method(typeof(ExceptionInterceptorFeature), nameof(Finalizer))!;
+ private static readonly Harmony ExceptionHandler = new("bannerlord.blse.exceptionhandler");
+ private static readonly MethodInfo FinalizerMethod = AccessTools2.Method(typeof(ExceptionInterceptorFeature), nameof(Finalizer))!;
- public static event Action? OnException;
+ public static event Action? OnException;
- public static void Enable()
- {
- AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
- OnException += HandleException;
- }
+ public static void Enable()
+ {
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
+ OnException += HandleException;
+ }
- public static void EnableAutoGens()
- {
- AppDomain.CurrentDomain.AssemblyLoad += CurrentDomainOnAssemblyLoad;
- FinalizerGlobal.Enable(ExceptionHandler, FinalizerMethod);
- }
+ public static void EnableAutoGens()
+ {
+ AppDomain.CurrentDomain.AssemblyLoad += CurrentDomainOnAssemblyLoad;
+ FinalizerGlobal.Enable(ExceptionHandler, FinalizerMethod);
+ }
- public static void Disable()
- {
- AppDomain.CurrentDomain.UnhandledException -= CurrentDomainOnUnhandledException;
- OnException -= HandleException;
- AppDomain.CurrentDomain.AssemblyLoad -= CurrentDomainOnAssemblyLoad;
- ExceptionHandler.UnpatchAll(ExceptionHandler.Id);
- }
+ public static void Disable()
+ {
+ AppDomain.CurrentDomain.UnhandledException -= CurrentDomainOnUnhandledException;
+ OnException -= HandleException;
+ AppDomain.CurrentDomain.AssemblyLoad -= CurrentDomainOnAssemblyLoad;
+ ExceptionHandler.UnpatchAll(ExceptionHandler.Id);
+ }
- private static void CurrentDomainOnAssemblyLoad(object sender, AssemblyLoadEventArgs args)
- {
- var assembly = args.LoadedAssembly;
- FinalizerGlobal.OnNewAssembly(ExceptionHandler, FinalizerMethod, assembly);
- }
+ private static void CurrentDomainOnAssemblyLoad(object sender, AssemblyLoadEventArgs args)
+ {
+ var assembly = args.LoadedAssembly;
+ FinalizerGlobal.OnNewAssembly(ExceptionHandler, FinalizerMethod, assembly);
+ }
- private static void Finalizer(Exception? __exception)
- {
- if (__exception is not null)
- HandleException(__exception);
- }
+ private static void Finalizer(Exception? __exception)
+ {
+ if (__exception is not null)
+ HandleException(__exception);
+ }
- [HandleProcessCorruptedStateExceptions, SecurityCritical]
- private static void CurrentDomainOnUnhandledException(object? _, UnhandledExceptionEventArgs e)
- {
- if (e.ExceptionObject is Exception exception)
- OnException?.Invoke(exception);
- }
+ [HandleProcessCorruptedStateExceptions, SecurityCritical]
+ private static void CurrentDomainOnUnhandledException(object? _, UnhandledExceptionEventArgs e)
+ {
+ if (e.ExceptionObject is Exception exception)
+ OnException?.Invoke(exception);
+ }
- private static void HandleException(Exception exception)
+ private static void HandleException(Exception exception)
+ {
+ try
{
- try
+ foreach (var type in TypeFinder.GetInterceptorTypes(typeof(BLSEExceptionHandlerAttribute)))
{
- foreach (var type in TypeFinder.GetInterceptorTypes(typeof(BLSEExceptionHandlerAttribute)))
+ if (AccessTools2.GetDelegate(type, "OnException") is { } method)
{
- if (AccessTools2.GetDelegate(type, "OnException") is { } method)
- {
- method(exception);
- }
+ method(exception);
}
}
- catch (Exception) { /* ignore */ }
}
+ catch (Exception) { /* ignore */ }
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/ExceptionInterceptor/FinalizerGlobal.cs b/src/Bannerlord.BLSE/Features/ExceptionInterceptor/FinalizerGlobal.cs
index c1d2bdd..52f6c4d 100644
--- a/src/Bannerlord.BLSE/Features/ExceptionInterceptor/FinalizerGlobal.cs
+++ b/src/Bannerlord.BLSE/Features/ExceptionInterceptor/FinalizerGlobal.cs
@@ -5,52 +5,51 @@
using System.Linq;
using System.Reflection;
-namespace Bannerlord.BLSE.Features.ExceptionInterceptor
+namespace Bannerlord.BLSE.Features.ExceptionInterceptor;
+
+internal static class FinalizerGlobal
{
- internal static class FinalizerGlobal
+ private static readonly HashSet BlacklistedMethodStarts = new()
+ {
+ "GameNetwork_",
+ "ManagedOptions_",
+ "MBEditor_",
+ "MBMultiplayerData_",
+ "CrashInformationCollector_",
+ "NativeParallelDriver_",
+ "NativeObject_",
+ "ManagedObject_",
+ "DotNetObject_",
+ "ManagedExtensions_",
+ };
+ private static readonly HashSet BlacklistedMethods = new()
{
- private static readonly HashSet BlacklistedMethodStarts = new()
- {
- "GameNetwork_",
- "ManagedOptions_",
- "MBEditor_",
- "MBMultiplayerData_",
- "CrashInformationCollector_",
- "NativeParallelDriver_",
- "NativeObject_",
- "ManagedObject_",
- "DotNetObject_",
- "ManagedExtensions_",
- };
- private static readonly HashSet BlacklistedMethods = new()
- {
- "Managed_SetStringArrayValueAtIndex",
- "Managed_SetCurrentStringReturnValueAsUnicode",
- "Managed_SetCurrentStringReturnValue",
- "Managed_PassCustomCallbackMethodPointers",
- "Managed_GetStringArrayValueAtIndex",
- "Managed_GetStringArrayLength",
- };
+ "Managed_SetStringArrayValueAtIndex",
+ "Managed_SetCurrentStringReturnValueAsUnicode",
+ "Managed_SetCurrentStringReturnValue",
+ "Managed_PassCustomCallbackMethodPointers",
+ "Managed_GetStringArrayValueAtIndex",
+ "Managed_GetStringArrayLength",
+ };
- public static void Enable(Harmony harmony, MethodInfo finalizerMethod)
- {
- var callbacksGeneratedTypes = AccessTools2.AllAssemblies().SelectMany(x => x.GetTypes().Where(y => y.Name.EndsWith("CallbacksGenerated")));
- var callbackGeneratedMethods = callbacksGeneratedTypes.SelectMany(AccessTools.GetDeclaredMethods)
- .Where(x => !BlacklistedMethods.Contains(x.Name))
- .Where(x => !BlacklistedMethodStarts.Any(y => x.Name.StartsWith(y)));
- foreach (var method in callbackGeneratedMethods.Where(x => x.GetCustomAttributesData().Any(y => y.AttributeType.Name == "MonoPInvokeCallbackAttribute")))
- harmony.Patch(method, finalizer: new HarmonyMethod(finalizerMethod));
- }
+ public static void Enable(Harmony harmony, MethodInfo finalizerMethod)
+ {
+ var callbacksGeneratedTypes = AccessTools2.AllAssemblies().SelectMany(x => x.GetTypes().Where(y => y.Name.EndsWith("CallbacksGenerated")));
+ var callbackGeneratedMethods = callbacksGeneratedTypes.SelectMany(AccessTools.GetDeclaredMethods)
+ .Where(x => !BlacklistedMethods.Contains(x.Name))
+ .Where(x => !BlacklistedMethodStarts.Any(y => x.Name.StartsWith(y)));
+ foreach (var method in callbackGeneratedMethods.Where(x => x.GetCustomAttributesData().Any(y => y.AttributeType.Name == "MonoPInvokeCallbackAttribute")))
+ harmony.Patch(method, finalizer: new HarmonyMethod(finalizerMethod));
+ }
- public static void OnNewAssembly(Harmony harmony, MethodInfo finalizerMethod, Assembly assembly)
- {
- var callbacksGeneratedTypes = assembly.GetTypes().Where(y => y.Name.EndsWith("CallbacksGenerated"));
- var callbackGeneratedMethods = callbacksGeneratedTypes.SelectMany(AccessTools.GetDeclaredMethods)
- .Where(x => !BlacklistedMethods.Contains(x.Name))
- .Where(x => !BlacklistedMethodStarts.Any(y => x.Name.StartsWith(y)));
- foreach (var method in callbackGeneratedMethods.Where(x => x.GetCustomAttributesData().Any(y => y.AttributeType.Name == "MonoPInvokeCallbackAttribute")))
- harmony.Patch(method, finalizer: new HarmonyMethod(finalizerMethod));
- }
+ public static void OnNewAssembly(Harmony harmony, MethodInfo finalizerMethod, Assembly assembly)
+ {
+ var callbacksGeneratedTypes = assembly.GetTypes().Where(y => y.Name.EndsWith("CallbacksGenerated"));
+ var callbackGeneratedMethods = callbacksGeneratedTypes.SelectMany(AccessTools.GetDeclaredMethods)
+ .Where(x => !BlacklistedMethods.Contains(x.Name))
+ .Where(x => !BlacklistedMethodStarts.Any(y => x.Name.StartsWith(y)));
+ foreach (var method in callbackGeneratedMethods.Where(x => x.GetCustomAttributesData().Any(y => y.AttributeType.Name == "MonoPInvokeCallbackAttribute")))
+ harmony.Patch(method, finalizer: new HarmonyMethod(finalizerMethod));
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/ExceptionInterceptor/FinalizerSimple.cs b/src/Bannerlord.BLSE/Features/ExceptionInterceptor/FinalizerSimple.cs
index 0d7a4af..13bbe77 100644
--- a/src/Bannerlord.BLSE/Features/ExceptionInterceptor/FinalizerSimple.cs
+++ b/src/Bannerlord.BLSE/Features/ExceptionInterceptor/FinalizerSimple.cs
@@ -3,39 +3,38 @@
using System.Reflection;
-namespace Bannerlord.BLSE.Features.ExceptionInterceptor
+namespace Bannerlord.BLSE.Features.ExceptionInterceptor;
+
+// TaleWorlds.DotNet.Managed:ApplicationTick -> Replicated
+// TaleWorlds.Engine.ScriptComponentBehaviour:OnTick -> Called by TaleWorlds.Engine.ManagedScriptHolder:TickComponents
+// TaleWorlds.MountAndBlade.Module:OnApplicationTick -> Replicated
+// TaleWorlds.MountAndBlade.View.Missions.MissionView:OnMissionScreenTick -> Called by TaleWorlds.MountAndBlade.View.Screen.MissionScreen:OnFrameTick
+// TaleWorlds.ScreenSystem.ScreenManager:Tick -> Replicated
+// TaleWorlds.MountAndBlade.Mission:Tick -> Replicated
+// TaleWorlds.MountAndBlade.MissionBehaviour:OnMissionTick -> Called by TaleWorlds.MountAndBlade.Mission:Tick
+// TaleWorlds.MountAndBlade.MBSubModuleBase:OnSubModuleLoad -> Replicated
+internal static class FinalizerSimple
{
- // TaleWorlds.DotNet.Managed:ApplicationTick -> Replicated
- // TaleWorlds.Engine.ScriptComponentBehaviour:OnTick -> Called by TaleWorlds.Engine.ManagedScriptHolder:TickComponents
- // TaleWorlds.MountAndBlade.Module:OnApplicationTick -> Replicated
- // TaleWorlds.MountAndBlade.View.Missions.MissionView:OnMissionScreenTick -> Called by TaleWorlds.MountAndBlade.View.Screen.MissionScreen:OnFrameTick
- // TaleWorlds.ScreenSystem.ScreenManager:Tick -> Replicated
- // TaleWorlds.MountAndBlade.Mission:Tick -> Replicated
- // TaleWorlds.MountAndBlade.MissionBehaviour:OnMissionTick -> Called by TaleWorlds.MountAndBlade.Mission:Tick
- // TaleWorlds.MountAndBlade.MBSubModuleBase:OnSubModuleLoad -> Replicated
- internal static class FinalizerSimple
- {
- private static readonly MethodInfo? ModuleInitializeMethod = AccessTools2.Method("TaleWorlds.MountAndBlade.Module:Initialize");
+ private static readonly MethodInfo? ModuleInitializeMethod = AccessTools2.Method("TaleWorlds.MountAndBlade.Module:Initialize");
- private static readonly MethodInfo? ManagedApplicationTickMethod = AccessTools2.Method("TaleWorlds.DotNet.Managed:ApplicationTick");
+ private static readonly MethodInfo? ManagedApplicationTickMethod = AccessTools2.Method("TaleWorlds.DotNet.Managed:ApplicationTick");
- private static readonly MethodInfo? ScreenManagerPreTickMethod = AccessTools2.Method("TaleWorlds.Engine.EngineScreenManager:PreTick");
- private static readonly MethodInfo? ScreenManagerTickMethod = AccessTools2.Method("TaleWorlds.Engine.EngineScreenManager:Tick");
- private static readonly MethodInfo? ScreenManagerLateTickMethod = AccessTools2.Method("TaleWorlds.Engine.EngineScreenManager:LateTick");
+ private static readonly MethodInfo? ScreenManagerPreTickMethod = AccessTools2.Method("TaleWorlds.Engine.EngineScreenManager:PreTick");
+ private static readonly MethodInfo? ScreenManagerTickMethod = AccessTools2.Method("TaleWorlds.Engine.EngineScreenManager:Tick");
+ private static readonly MethodInfo? ScreenManagerLateTickMethod = AccessTools2.Method("TaleWorlds.Engine.EngineScreenManager:LateTick");
- private static readonly MethodInfo? ManagedScriptHolderTickComponentsMethod = AccessTools2.Method("TaleWorlds.Engine.ManagedScriptHolder:TickComponents");
+ private static readonly MethodInfo? ManagedScriptHolderTickComponentsMethod = AccessTools2.Method("TaleWorlds.Engine.ManagedScriptHolder:TickComponents");
- public static void Enable(Harmony harmony, MethodInfo finalizerMethod)
- {
- harmony.Patch(ModuleInitializeMethod, finalizer: new HarmonyMethod(finalizerMethod));
+ public static void Enable(Harmony harmony, MethodInfo finalizerMethod)
+ {
+ harmony.Patch(ModuleInitializeMethod, finalizer: new HarmonyMethod(finalizerMethod));
- harmony.Patch(ManagedApplicationTickMethod, finalizer: new HarmonyMethod(finalizerMethod));
+ harmony.Patch(ManagedApplicationTickMethod, finalizer: new HarmonyMethod(finalizerMethod));
- harmony.Patch(ScreenManagerPreTickMethod, finalizer: new HarmonyMethod(finalizerMethod));
- harmony.Patch(ScreenManagerTickMethod, finalizer: new HarmonyMethod(finalizerMethod));
- harmony.Patch(ScreenManagerLateTickMethod, finalizer: new HarmonyMethod(finalizerMethod));
+ harmony.Patch(ScreenManagerPreTickMethod, finalizer: new HarmonyMethod(finalizerMethod));
+ harmony.Patch(ScreenManagerTickMethod, finalizer: new HarmonyMethod(finalizerMethod));
+ harmony.Patch(ScreenManagerLateTickMethod, finalizer: new HarmonyMethod(finalizerMethod));
- harmony.Patch(ManagedScriptHolderTickComponentsMethod, finalizer: new HarmonyMethod(finalizerMethod));
- }
+ harmony.Patch(ManagedScriptHolderTickComponentsMethod, finalizer: new HarmonyMethod(finalizerMethod));
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/Interceptor/InterceptorFeature.cs b/src/Bannerlord.BLSE/Features/Interceptor/InterceptorFeature.cs
index 1473a74..445d0dc 100644
--- a/src/Bannerlord.BLSE/Features/Interceptor/InterceptorFeature.cs
+++ b/src/Bannerlord.BLSE/Features/Interceptor/InterceptorFeature.cs
@@ -4,41 +4,40 @@
using HarmonyLib;
using HarmonyLib.BUTR.Extensions;
-namespace Bannerlord.BLSE.Features.Interceptor
+namespace Bannerlord.BLSE.Features.Interceptor;
+
+public static class InterceptorFeature
{
- public static class InterceptorFeature
- {
- public static string Id = FeatureIds.InterceptorId;
+ public static string Id = FeatureIds.InterceptorId;
- private delegate void OnInitializeSubModulesPrefixDelegate();
- private delegate void OnLoadSubModulesPostfixDelegate();
+ private delegate void OnInitializeSubModulesPrefixDelegate();
+ private delegate void OnLoadSubModulesPostfixDelegate();
- public static void Enable(Harmony harmony)
- {
- ModulePatch.OnInitializeSubModulesPrefix += OnInitializeSubModulesPrefix;
- ModulePatch.OnLoadSubModulesPostfix += OnLoadSubModulesPostfix;
- ModulePatch.Enable(harmony);
- }
+ public static void Enable(Harmony harmony)
+ {
+ ModulePatch.OnInitializeSubModulesPrefix += OnInitializeSubModulesPrefix;
+ ModulePatch.OnLoadSubModulesPostfix += OnLoadSubModulesPostfix;
+ ModulePatch.Enable(harmony);
+ }
- private static void OnInitializeSubModulesPrefix()
+ private static void OnInitializeSubModulesPrefix()
+ {
+ foreach (var type in TypeFinder.GetInterceptorTypes(typeof(BLSEInterceptorAttribute)))
{
- foreach (var type in TypeFinder.GetInterceptorTypes(typeof(BLSEInterceptorAttribute)))
+ if (AccessTools2.GetDelegate(type, "OnInitializeSubModulesPrefix", logErrorInTrace: false) is { } method)
{
- if (AccessTools2.GetDelegate(type, "OnInitializeSubModulesPrefix", logErrorInTrace: false) is { } method)
- {
- method();
- }
+ method();
}
}
+ }
- private static void OnLoadSubModulesPostfix()
+ private static void OnLoadSubModulesPostfix()
+ {
+ foreach (var type in TypeFinder.GetInterceptorTypes(typeof(BLSEInterceptorAttribute)))
{
- foreach (var type in TypeFinder.GetInterceptorTypes(typeof(BLSEInterceptorAttribute)))
+ if (AccessTools2.GetDelegate(type, "OnLoadSubModulesPostfix", logErrorInTrace: false) is { } method)
{
- if (AccessTools2.GetDelegate(type, "OnLoadSubModulesPostfix", logErrorInTrace: false) is { } method)
- {
- method();
- }
+ method();
}
}
}
diff --git a/src/Bannerlord.BLSE/Features/Interceptor/Patches/ModulePatch.cs b/src/Bannerlord.BLSE/Features/Interceptor/Patches/ModulePatch.cs
index c4b5e0f..a8a4e93 100644
--- a/src/Bannerlord.BLSE/Features/Interceptor/Patches/ModulePatch.cs
+++ b/src/Bannerlord.BLSE/Features/Interceptor/Patches/ModulePatch.cs
@@ -6,50 +6,49 @@
using Module = TaleWorlds.MountAndBlade.Module;
-namespace Bannerlord.BLSE.Features.Interceptor.Patches
+namespace Bannerlord.BLSE.Features.Interceptor.Patches;
+
+internal static class ModulePatch
{
- internal static class ModulePatch
+ public static event Action? OnInitializeSubModulesPrefix;
+ public static event Action? OnLoadSubModulesPostfix;
+
+ private static Harmony? _harmony;
+
+ public static bool Enable(Harmony harmony)
+ {
+ _harmony = harmony;
+
+ var res1 = harmony.TryPatch(
+ AccessTools2.Method(typeof(Module), "LoadSubModules"),
+ postfix: AccessTools2.Method(typeof(ModulePatch), nameof(LoadSubModulesPostfix)));
+ if (!res1) return false;
+
+ var res2 = harmony.TryPatch(
+ AccessTools2.Method(typeof(Module), "InitializeSubModules"),
+ prefix: AccessTools2.Method(typeof(ModulePatch), nameof(InitializeSubModulesPrefix)));
+ if (!res2) return false;
+
+ return true;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void InitializeSubModulesPrefix()
{
- public static event Action? OnInitializeSubModulesPrefix;
- public static event Action? OnLoadSubModulesPostfix;
-
- private static Harmony? _harmony;
-
- public static bool Enable(Harmony harmony)
- {
- _harmony = harmony;
-
- var res1 = harmony.TryPatch(
- AccessTools2.Method(typeof(Module), "LoadSubModules"),
- postfix: AccessTools2.Method(typeof(ModulePatch), nameof(LoadSubModulesPostfix)));
- if (!res1) return false;
-
- var res2 = harmony.TryPatch(
- AccessTools2.Method(typeof(Module), "InitializeSubModules"),
- prefix: AccessTools2.Method(typeof(ModulePatch), nameof(InitializeSubModulesPrefix)));
- if (!res2) return false;
-
- return true;
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static void InitializeSubModulesPrefix()
- {
- OnInitializeSubModulesPrefix?.Invoke();
-
- _harmony?.Unpatch(
- AccessTools2.Method(typeof(Module), "InitializeSubModules"),
- AccessTools2.Method(typeof(ModulePatch), nameof(InitializeSubModulesPrefix)));
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static void LoadSubModulesPostfix()
- {
- OnLoadSubModulesPostfix?.Invoke();
-
- _harmony?.Unpatch(
- AccessTools2.Method(typeof(Module), "LoadSubModules"),
- AccessTools2.Method(typeof(ModulePatch), nameof(LoadSubModulesPostfix)));
- }
+ OnInitializeSubModulesPrefix?.Invoke();
+
+ _harmony?.Unpatch(
+ AccessTools2.Method(typeof(Module), "InitializeSubModules"),
+ AccessTools2.Method(typeof(ModulePatch), nameof(InitializeSubModulesPrefix)));
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void LoadSubModulesPostfix()
+ {
+ OnLoadSubModulesPostfix?.Invoke();
+
+ _harmony?.Unpatch(
+ AccessTools2.Method(typeof(Module), "LoadSubModules"),
+ AccessTools2.Method(typeof(ModulePatch), nameof(LoadSubModulesPostfix)));
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/Xbox/Patches/ModulePatch.cs b/src/Bannerlord.BLSE/Features/Xbox/Patches/ModulePatch.cs
index 916f79b..c7a5558 100644
--- a/src/Bannerlord.BLSE/Features/Xbox/Patches/ModulePatch.cs
+++ b/src/Bannerlord.BLSE/Features/Xbox/Patches/ModulePatch.cs
@@ -9,50 +9,49 @@
using Module = TaleWorlds.MountAndBlade.Module;
-namespace Bannerlord.BLSE.Features.Xbox.Patches
+namespace Bannerlord.BLSE.Features.Xbox.Patches;
+
+internal static class ModulePatch
{
- internal static class ModulePatch
+ public static bool Enable(Harmony harmony)
+ {
+ var asm = Assembly.LoadFrom("TaleWorlds.MountAndBlade.Platform.GDK.dll");
+ Trace.Assert(asm is not null);
+
+ var res1 = harmony.TryPatch(
+ 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)));
+ if (!res3) return false;
+
+ return true;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ 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()
{
- public static bool Enable(Harmony harmony)
- {
- var asm = Assembly.LoadFrom("TaleWorlds.MountAndBlade.Platform.GDK.dll");
- Trace.Assert(asm is not null);
-
- var res1 = harmony.TryPatch(
- 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)));
- if (!res3) return false;
-
- return true;
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- 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()
- {
- return false;
- }
+ return false;
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Features/Xbox/XboxFeature.cs b/src/Bannerlord.BLSE/Features/Xbox/XboxFeature.cs
index 95e4956..b4041d9 100644
--- a/src/Bannerlord.BLSE/Features/Xbox/XboxFeature.cs
+++ b/src/Bannerlord.BLSE/Features/Xbox/XboxFeature.cs
@@ -4,21 +4,20 @@
using System.IO;
-namespace Bannerlord.BLSE.Features.Xbox
+namespace Bannerlord.BLSE.Features.Xbox;
+
+///
+/// We currently just bypass the sign in screen on launch. Don't think it's very safe, but it works for now.
+///
+public static class XboxFeature
{
- ///
- /// We currently just bypass the sign in screen on launch. Don't think it's very safe, but it works for now.
- ///
- public static class XboxFeature
- {
- public static string Id = FeatureIds.XboxId;
+ public static string Id = FeatureIds.XboxId;
- public static void Enable(Harmony harmony)
- {
- if (Path.GetFileName(Directory.GetCurrentDirectory()) != "Gaming.Desktop.x64_Shipping_Client")
- return;
+ public static void Enable(Harmony harmony)
+ {
+ if (Path.GetFileName(Directory.GetCurrentDirectory()) != "Gaming.Desktop.x64_Shipping_Client")
+ return;
- ModulePatch.Enable(harmony);
- }
+ ModulePatch.Enable(harmony);
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Utils/AssemblyWrapper.cs b/src/Bannerlord.BLSE/Utils/AssemblyWrapper.cs
index 1e35436..30f899f 100644
--- a/src/Bannerlord.BLSE/Utils/AssemblyWrapper.cs
+++ b/src/Bannerlord.BLSE/Utils/AssemblyWrapper.cs
@@ -1,11 +1,10 @@
using System.Reflection;
-namespace Bannerlord.BLSE.Utils
+namespace Bannerlord.BLSE.Utils;
+
+internal class AssemblyWrapper : Assembly
{
- internal class AssemblyWrapper : Assembly
- {
- public override string Location { get; }
+ public override string Location { get; }
- public AssemblyWrapper(string location) => Location = location;
- }
+ public AssemblyWrapper(string location) => Location = location;
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Utils/CommandLineSplitter.cs b/src/Bannerlord.BLSE/Utils/CommandLineSplitter.cs
index 0b3959a..e58bf81 100644
--- a/src/Bannerlord.BLSE/Utils/CommandLineSplitter.cs
+++ b/src/Bannerlord.BLSE/Utils/CommandLineSplitter.cs
@@ -1,111 +1,110 @@
using System.Collections.Generic;
-namespace Bannerlord.BLSE.Utils
+namespace Bannerlord.BLSE.Utils;
+
+internal static class CommandLineSplitter
{
- internal static class CommandLineSplitter
+ private enum Boundary
{
- private enum Boundary
- {
- TokenStart,
- WordEnd,
- QuoteStart,
- QuoteEnd
- }
+ TokenStart,
+ WordEnd,
+ QuoteStart,
+ QuoteEnd
+ }
- public static IEnumerable SplitCommandLine(string commandLine)
- {
- var startTokenIndex = 0;
+ public static IEnumerable SplitCommandLine(string commandLine)
+ {
+ var startTokenIndex = 0;
- var pos = 0;
+ var pos = 0;
- var seeking = Boundary.TokenStart;
- var seekingQuote = Boundary.QuoteStart;
+ var seeking = Boundary.TokenStart;
+ var seekingQuote = Boundary.QuoteStart;
- while (pos < commandLine.Length)
- {
- var c = commandLine[pos];
+ while (pos < commandLine.Length)
+ {
+ var c = commandLine[pos];
- if (char.IsWhiteSpace(c))
+ if (char.IsWhiteSpace(c))
+ {
+ if (seekingQuote == Boundary.QuoteStart)
{
- if (seekingQuote == Boundary.QuoteStart)
+ switch (seeking)
{
- switch (seeking)
- {
- case Boundary.WordEnd:
- yield return CurrentToken();
- startTokenIndex = pos;
- seeking = Boundary.TokenStart;
- break;
-
- case Boundary.TokenStart:
- startTokenIndex = pos;
- break;
- }
+ case Boundary.WordEnd:
+ yield return CurrentToken();
+ startTokenIndex = pos;
+ seeking = Boundary.TokenStart;
+ break;
+
+ case Boundary.TokenStart:
+ startTokenIndex = pos;
+ break;
}
}
- else if (c == '\"')
+ }
+ else if (c == '\"')
+ {
+ if (seeking == Boundary.TokenStart)
{
- if (seeking == Boundary.TokenStart)
+ switch (seekingQuote)
{
- switch (seekingQuote)
- {
- case Boundary.QuoteEnd:
- yield return CurrentToken();
- startTokenIndex = pos;
- seekingQuote = Boundary.QuoteStart;
- break;
-
- case Boundary.QuoteStart:
- startTokenIndex = pos + 1;
- seekingQuote = Boundary.QuoteEnd;
- break;
- }
- }
- else
- {
- switch (seekingQuote)
- {
- case Boundary.QuoteEnd:
- seekingQuote = Boundary.QuoteStart;
- break;
-
- case Boundary.QuoteStart:
- seekingQuote = Boundary.QuoteEnd;
- break;
- }
+ case Boundary.QuoteEnd:
+ yield return CurrentToken();
+ startTokenIndex = pos;
+ seekingQuote = Boundary.QuoteStart;
+ break;
+
+ case Boundary.QuoteStart:
+ startTokenIndex = pos + 1;
+ seekingQuote = Boundary.QuoteEnd;
+ break;
}
}
- else if (seeking == Boundary.TokenStart && seekingQuote == Boundary.QuoteStart)
- {
- seeking = Boundary.WordEnd;
- startTokenIndex = pos;
- }
-
- Advance();
-
- if (IsAtEndOfInput())
+ else
{
- switch (seeking)
+ switch (seekingQuote)
{
- case Boundary.TokenStart:
+ case Boundary.QuoteEnd:
+ seekingQuote = Boundary.QuoteStart;
break;
- default:
- yield return CurrentToken();
+
+ case Boundary.QuoteStart:
+ seekingQuote = Boundary.QuoteEnd;
break;
}
}
}
+ else if (seeking == Boundary.TokenStart && seekingQuote == Boundary.QuoteStart)
+ {
+ seeking = Boundary.WordEnd;
+ startTokenIndex = pos;
+ }
- void Advance() => pos++;
+ Advance();
- string CurrentToken()
+ if (IsAtEndOfInput())
{
- return commandLine.Substring(startTokenIndex, IndexOfEndOfToken()).Replace("\"", "");
+ switch (seeking)
+ {
+ case Boundary.TokenStart:
+ break;
+ default:
+ yield return CurrentToken();
+ break;
+ }
}
+ }
- int IndexOfEndOfToken() => pos - startTokenIndex;
+ void Advance() => pos++;
- bool IsAtEndOfInput() => pos == commandLine.Length;
+ string CurrentToken()
+ {
+ return commandLine.Substring(startTokenIndex, IndexOfEndOfToken()).Replace("\"", "");
}
+
+ int IndexOfEndOfToken() => pos - startTokenIndex;
+
+ bool IsAtEndOfInput() => pos == commandLine.Length;
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.BLSE/Utils/GameUtils.cs b/src/Bannerlord.BLSE/Utils/GameUtils.cs
index 641d273..f5f8723 100644
--- a/src/Bannerlord.BLSE/Utils/GameUtils.cs
+++ b/src/Bannerlord.BLSE/Utils/GameUtils.cs
@@ -3,26 +3,25 @@
using System;
-namespace Bannerlord.BLSE.Utils
+namespace Bannerlord.BLSE.Utils;
+
+internal static class GameUtils
{
- internal static class GameUtils
- {
- private static readonly Lazy EngineApplicationInterfaceType =
- new(() => AccessTools2.TypeByName("TaleWorlds.Engine.EngineApplicationInterface"));
+ private static readonly Lazy EngineApplicationInterfaceType =
+ new(() => AccessTools2.TypeByName("TaleWorlds.Engine.EngineApplicationInterface"));
- private static readonly Lazy?> IUtilField =
- new(() => AccessTools2.StaticFieldRefAccess
-
-
-
-
-
-
+
+
$(ILRepackExcludeAssemblies);$(ProjectDir)$(OutputPath)System.Drawing.dll;
$(ILRepackExcludeAssemblies);$(ProjectDir)$(OutputPath)System.Drawing.Common.dll;
@@ -92,4 +92,14 @@
+
+
+
+ <_Parameter1>BUTRCompatibilityScoreUrl
+ <_Parameter2>$(BUTRCompatibilityScoreUrl)
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Extensions/CollectionsExtensions.cs b/src/Bannerlord.LauncherEx/Extensions/CollectionsExtensions.cs
deleted file mode 100644
index 9e7ff48..0000000
--- a/src/Bannerlord.LauncherEx/Extensions/CollectionsExtensions.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System.Collections.Generic;
-
-// ReSharper disable once CheckNamespace
-namespace Bannerlord.ModuleManager;
-
-internal static class CollectionsExtensions
-{
- public static int IndexOf(this IReadOnlyList self, T elementToFind)
- {
- var i = 0;
- foreach (T element in self)
- {
- if (Equals(element, elementToFind))
- return i;
- i++;
- }
- return -1;
- }
-}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Extensions/LauncherModsVMExtensions.cs b/src/Bannerlord.LauncherEx/Extensions/LauncherModsVMExtensions.cs
deleted file mode 100644
index e2af3b8..0000000
--- a/src/Bannerlord.LauncherEx/Extensions/LauncherModsVMExtensions.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Bannerlord.LauncherEx.Mixins;
-using Bannerlord.LauncherEx.ViewModels;
-
-using TaleWorlds.Library;
-using TaleWorlds.MountAndBlade.Launcher.Library;
-
-namespace Bannerlord.LauncherEx.Extensions
-{
- internal static class LauncherModsVMExtensions
- {
- public static MBBindingList? GetModules(this LauncherModsVM viewModel) =>
- viewModel.GetPropertyValue(nameof(LauncherModsVMMixin.Modules2)) as MBBindingList;
- }
-}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Extensions/OpenGLTextureExtensions.cs b/src/Bannerlord.LauncherEx/Extensions/OpenGLTextureExtensions.cs
index 285d1c0..f595711 100644
--- a/src/Bannerlord.LauncherEx/Extensions/OpenGLTextureExtensions.cs
+++ b/src/Bannerlord.LauncherEx/Extensions/OpenGLTextureExtensions.cs
@@ -12,81 +12,80 @@
using TaleWorlds.TwoDimension.Standalone;
-namespace Bannerlord.LauncherEx.Extensions
+namespace Bannerlord.LauncherEx.Extensions;
+
+internal static class OpenGLTextureExtensions
{
- internal static class OpenGLTextureExtensions
+ private enum PixelFormat : uint
{
- private enum PixelFormat : uint
- {
- ColorIndex = 6400U,
- StencilIndex,
- DepthComponent,
- Red,
- Green,
- Blue,
- Alpha,
- RGB,
- RGBA,
- Luminance,
- LuminanceAlpha,
- BGR = 32992U,
- BGRA
- }
+ ColorIndex = 6400U,
+ StencilIndex,
+ DepthComponent,
+ Red,
+ Green,
+ Blue,
+ Alpha,
+ RGB,
+ RGBA,
+ Luminance,
+ LuminanceAlpha,
+ BGR = 32992U,
+ BGRA
+ }
- private delegate void MakeActiveDelegate(OpenGLTexture texture);
- private static readonly MakeActiveDelegate? _makeActiveDelegate = AccessTools2.GetDelegate(typeof(OpenGLTexture), "MakeActive");
+ private delegate void MakeActiveDelegate(OpenGLTexture texture);
+ private static readonly MakeActiveDelegate? _makeActiveDelegate = AccessTools2.GetDelegate(typeof(OpenGLTexture), "MakeActive");
- [DllImport("Opengl32.dll", EntryPoint = "glTexImage2D")]
- private static extern void TexImage2D(uint target, int level, uint pixelInternalformat, int width, int height, int border, PixelFormat format, uint type, byte[] pixels);
+ [DllImport("Opengl32.dll", EntryPoint = "glTexImage2D")]
+ private static extern void TexImage2D(uint target, int level, uint pixelInternalformat, int width, int height, int border, PixelFormat format, uint type, byte[] pixels);
- [DllImport("Opengl32.dll", EntryPoint = "glTexImage2D")]
- private static extern void TexImage2D2(uint target, int level, uint pixelInternalformat, int width, int height, int border, PixelFormat format, uint type, IntPtr pixels);
+ [DllImport("Opengl32.dll", EntryPoint = "glTexImage2D")]
+ private static extern void TexImage2D2(uint target, int level, uint pixelInternalformat, int width, int height, int border, PixelFormat format, uint type, IntPtr pixels);
- public static void MakeActive(this OpenGLTexture texture) => _makeActiveDelegate?.Invoke(texture);
+ public static void MakeActive(this OpenGLTexture texture) => _makeActiveDelegate?.Invoke(texture);
- public static bool LoadFromStream(this OpenGLTexture texture, string name, Stream stream)
+ public static bool LoadFromStream(this OpenGLTexture texture, string name, Stream stream)
+ {
+ if (_makeActiveDelegate is null)
+ return false;
+
+ // TODO: For some reason, we need now to pass req_comp as 4, not 0 as previously
+ var image = new ImageReader().Read(stream, 4);
+ texture.Initialize(name, image.Width, image.Height);
+ texture.MakeActive();
+ var (error, pixelFormat, pixelInternalformat) = image.Comp switch
+ {
+ 1 => (false, PixelFormat.Red, 0x8229U),
+ 3 => (false, PixelFormat.RGB, 0x8051U),
+ 4 => (false, PixelFormat.RGBA, 0x8058U),
+ _ => (true, (PixelFormat) 0, 0U),
+ };
+ if (!error)
{
- if (_makeActiveDelegate is null)
- return false;
-
- // TODO: For some reason, we need now to pass req_comp as 4, not 0 as previously
- var image = new ImageReader().Read(stream, 4);
- texture.Initialize(name, image.Width, image.Height);
- texture.MakeActive();
- var (error, pixelFormat, pixelInternalformat) = image.Comp switch
- {
- 1 => (false, PixelFormat.Red, 0x8229U),
- 3 => (false, PixelFormat.RGB, 0x8051U),
- 4 => (false, PixelFormat.RGBA, 0x8058U),
- _ => (true, (PixelFormat) 0, 0U),
- };
- if (!error)
- {
- TexImage2D(0x00000DE1, 0, pixelInternalformat, image.Width, image.Height, 0, pixelFormat, 0x00001401, image.Data);
- }
-
- return true;
+ TexImage2D(0x00000DE1, 0, pixelInternalformat, image.Width, image.Height, 0, pixelFormat, 0x00001401, image.Data);
}
- public static bool LoadFromAssetTexture(this OpenGLTexture texture, string name, Texture source)
- {
- if (_makeActiveDelegate is null)
- return false;
+ return true;
+ }
- if (source.TexturePixels is null)
- return false;
+ public static bool LoadFromAssetTexture(this OpenGLTexture texture, string name, Texture source)
+ {
+ if (_makeActiveDelegate is null)
+ return false;
- var textureData = source.TexturePixels.GetData();
- using var bitmap = TextureUtil.DecodeTextureDataToBitmap(textureData.PrimaryRawImage, (int) source.Width, (int) source.Height, source.Format);
- var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+ if (source.TexturePixels is null)
+ return false;
- texture.Initialize(name, (int) source.Width, (int) source.Height);
- texture.MakeActive();
- TexImage2D2(0x00000DE1, 0, 0x8058U, data.Width, data.Height, 0, PixelFormat.BGRA, 0x00001401, data.Scan0);
+ var textureData = source.TexturePixels.GetData();
+ using var bitmap = TextureUtil.DecodeTextureDataToBitmap(textureData.PrimaryRawImage, (int) source.Width, (int) source.Height, source.Format);
+ var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- bitmap.UnlockBits(data);
+ texture.Initialize(name, (int) source.Width, (int) source.Height);
+ texture.MakeActive();
+ TexImage2D2(0x00000DE1, 0, 0x8058U, data.Width, data.Height, 0, PixelFormat.BGRA, 0x00001401, data.Scan0);
- return true;
- }
+ bitmap.UnlockBits(data);
+
+ return true;
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Extensions/PlatformFileHelperPCExtended.cs b/src/Bannerlord.LauncherEx/Extensions/PlatformFileHelperPCExtended.cs
index 42806cd..e2fb7d9 100644
--- a/src/Bannerlord.LauncherEx/Extensions/PlatformFileHelperPCExtended.cs
+++ b/src/Bannerlord.LauncherEx/Extensions/PlatformFileHelperPCExtended.cs
@@ -2,22 +2,21 @@
using TaleWorlds.Library;
-namespace Bannerlord.LauncherEx.Extensions
+namespace Bannerlord.LauncherEx.Extensions;
+
+// TODO: What to with Xbox version?
+internal static class PlatformFileHelperPCExtended
{
- // TODO: What to with Xbox version?
- internal static class PlatformFileHelperPCExtended
- {
- private delegate string GetDirectoryFullPathDelegate(object instance, PlatformDirectoryPath directoryPath);
- private static GetDirectoryFullPathDelegate? GetDirectoryFullPathMethod =
- AccessTools2.GetDelegate("TaleWorlds.Library.PlatformFileHelperPC:GetDirectoryFullPath");
+ private delegate string GetDirectoryFullPathDelegate(object instance, PlatformDirectoryPath directoryPath);
+ private static GetDirectoryFullPathDelegate? GetDirectoryFullPathMethod =
+ AccessTools2.GetDelegate("TaleWorlds.Library.PlatformFileHelperPC:GetDirectoryFullPath");
- private delegate object GetPlatformFileHelperDelegate();
- private static GetPlatformFileHelperDelegate? GetPlatformFileHelper =
- AccessTools2.GetPropertyGetterDelegate("TaleWorlds.Library.Common:PlatformFileHelper");
+ private delegate object GetPlatformFileHelperDelegate();
+ private static GetPlatformFileHelperDelegate? GetPlatformFileHelper =
+ AccessTools2.GetPropertyGetterDelegate("TaleWorlds.Library.Common:PlatformFileHelper");
- public static string? GetDirectoryFullPath(PlatformDirectoryPath directoryPath) =>
- GetPlatformFileHelper is not null && GetDirectoryFullPathMethod is not null && GetPlatformFileHelper() is { } obj
- ? GetDirectoryFullPathMethod(obj, directoryPath)
- : null;
- }
+ public static string? GetDirectoryFullPath(PlatformDirectoryPath directoryPath) =>
+ GetPlatformFileHelper is not null && GetDirectoryFullPathMethod is not null && GetPlatformFileHelper() is { } obj
+ ? GetDirectoryFullPathMethod(obj, directoryPath)
+ : null;
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Extensions/ProcessExtensions.cs b/src/Bannerlord.LauncherEx/Extensions/ProcessExtensions.cs
index e96c81a..ceb18e8 100644
--- a/src/Bannerlord.LauncherEx/Extensions/ProcessExtensions.cs
+++ b/src/Bannerlord.LauncherEx/Extensions/ProcessExtensions.cs
@@ -9,50 +9,49 @@
using Windows.Win32.Foundation;
using Windows.Win32.System.Diagnostics.ToolHelp;
-namespace Bannerlord.LauncherEx.Extensions
+namespace Bannerlord.LauncherEx.Extensions;
+
+internal static class ProcessExtensions
{
- internal static class ProcessExtensions
- {
- public static int ParentProcessId(this Process process) => ParentProcessId(process.Id);
- public static Process? ParentProcess(this Process process) => ParentProcessId(process.Id) is var pId && pId is not -1 ? Process.GetProcessById(pId) : null;
+ public static int ParentProcessId(this Process process) => ParentProcessId(process.Id);
+ public static Process? ParentProcess(this Process process) => ParentProcessId(process.Id) is var pId && pId is not -1 ? Process.GetProcessById(pId) : null;
- private static int ParentProcessId(int id)
+ private static int ParentProcessId(int id)
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ var pe32 = new PROCESSENTRY32
{
- var pe32 = new PROCESSENTRY32
- {
- dwSize = (uint) Marshal.SizeOf(typeof(PROCESSENTRY32))
- };
- using var hSnapshot = new SafeSnapshotHandle(PInvoke.CreateToolhelp32Snapshot(CREATE_TOOLHELP_SNAPSHOT_FLAGS.TH32CS_SNAPPROCESS, (uint) id));
- if (hSnapshot.IsInvalid) return -1;
-
- if (!PInvoke.Process32First(hSnapshot, ref pe32))
- return -1;
-
- do
- {
- if (pe32.th32ProcessID == (uint) id)
- return (int) pe32.th32ParentProcessID;
- } while (PInvoke.Process32Next(hSnapshot, ref pe32));
- }
-
- return -1;
- }
+ dwSize = (uint) Marshal.SizeOf(typeof(PROCESSENTRY32))
+ };
+ using var hSnapshot = new SafeSnapshotHandle(PInvoke.CreateToolhelp32Snapshot(CREATE_TOOLHELP_SNAPSHOT_FLAGS.TH32CS_SNAPPROCESS, (uint) id));
+ if (hSnapshot.IsInvalid) return -1;
- [SuppressUnmanagedCodeSecurity]
- private sealed class SafeSnapshotHandle : SafeHandleMinusOneIsInvalid
- {
- private readonly HANDLE _handle;
+ if (!PInvoke.Process32First(hSnapshot, ref pe32))
+ return -1;
- [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
- internal SafeSnapshotHandle(HANDLE handle) : base(true)
+ do
{
- _handle = handle;
- SetHandle(_handle);
- }
+ if (pe32.th32ProcessID == (uint) id)
+ return (int) pe32.th32ParentProcessID;
+ } while (PInvoke.Process32Next(hSnapshot, ref pe32));
+ }
- protected override bool ReleaseHandle() => PInvoke.CloseHandle(_handle);
+ return -1;
+ }
+
+ [SuppressUnmanagedCodeSecurity]
+ private sealed class SafeSnapshotHandle : SafeHandleMinusOneIsInvalid
+ {
+ private readonly HANDLE _handle;
+
+ [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
+ internal SafeSnapshotHandle(HANDLE handle) : base(true)
+ {
+ _handle = handle;
+ SetHandle(_handle);
}
+
+ protected override bool ReleaseHandle() => PInvoke.CloseHandle(_handle);
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Extensions/ViewModelExtensions.cs b/src/Bannerlord.LauncherEx/Extensions/ViewModelExtensions.cs
index 445dd87..8d02c4f 100644
--- a/src/Bannerlord.LauncherEx/Extensions/ViewModelExtensions.cs
+++ b/src/Bannerlord.LauncherEx/Extensions/ViewModelExtensions.cs
@@ -10,75 +10,74 @@
using TaleWorlds.Library;
-namespace Bannerlord.LauncherEx.Extensions
-{
- internal static class ViewModelExtensions
- {
- private static readonly AccessTools.FieldRef? PropertiesAndMethods =
- AccessTools2.FieldRefAccess("TaleWorlds.Library.ViewModel:_propertiesAndMethods");
-
- private delegate Dictionary GetPropertiesDelegate(object instance);
- private static readonly GetPropertiesDelegate? GetProperties =
- AccessTools2.GetDeclaredPropertyGetterDelegate("TaleWorlds.Library.ViewModel+DataSourceTypeBindingPropertiesCollection:Properties");
+namespace Bannerlord.LauncherEx.Extensions;
- private delegate Dictionary GetMethodsDelegate(object instance);
- private static readonly GetMethodsDelegate? GetMethods =
- AccessTools2.GetDeclaredPropertyGetterDelegate("TaleWorlds.Library.ViewModel+DataSourceTypeBindingPropertiesCollection:Methods");
+internal static class ViewModelExtensions
+{
+ private static readonly AccessTools.FieldRef? PropertiesAndMethods =
+ AccessTools2.FieldRefAccess("TaleWorlds.Library.ViewModel:_propertiesAndMethods");
- private static readonly AccessTools.FieldRef? CachedViewModelProperties =
- AccessTools2.StaticFieldRefAccess("TaleWorlds.Library.ViewModel:_cachedViewModelProperties");
+ private delegate Dictionary GetPropertiesDelegate(object instance);
+ private static readonly GetPropertiesDelegate? GetProperties =
+ AccessTools2.GetDeclaredPropertyGetterDelegate("TaleWorlds.Library.ViewModel+DataSourceTypeBindingPropertiesCollection:Properties");
- public delegate object DataSourceTypeBindingPropertiesCollectionCtorDelegate(Dictionary properties, Dictionary methods);
- public static readonly DataSourceTypeBindingPropertiesCollectionCtorDelegate? DataSourceTypeBindingPropertiesCollectionCtor =
- AccessTools2.GetDeclaredConstructorDelegate(
- "TaleWorlds.Library.ViewModel+DataSourceTypeBindingPropertiesCollection", new[] { typeof(Dictionary), typeof(Dictionary) });
+ private delegate Dictionary GetMethodsDelegate(object instance);
+ private static readonly GetMethodsDelegate? GetMethods =
+ AccessTools2.GetDeclaredPropertyGetterDelegate("TaleWorlds.Library.ViewModel+DataSourceTypeBindingPropertiesCollection:Methods");
- public static void AddProperty(this ViewModel viewModel, string name, PropertyInfo propertyInfo)
- {
- if (!GetOrCreateIndividualStorage(viewModel, out var propDict, out _))
- return;
+ private static readonly AccessTools.FieldRef? CachedViewModelProperties =
+ AccessTools2.StaticFieldRefAccess("TaleWorlds.Library.ViewModel:_cachedViewModelProperties");
- propDict[name] = propertyInfo;
- }
+ public delegate object DataSourceTypeBindingPropertiesCollectionCtorDelegate(Dictionary properties, Dictionary methods);
+ public static readonly DataSourceTypeBindingPropertiesCollectionCtorDelegate? DataSourceTypeBindingPropertiesCollectionCtor =
+ AccessTools2.GetDeclaredConstructorDelegate(
+ "TaleWorlds.Library.ViewModel+DataSourceTypeBindingPropertiesCollection", new[] { typeof(Dictionary), typeof(Dictionary) });
- public static void AddMethod(this ViewModel viewModel, string name, MethodInfo methodInfo)
- {
- if (!GetOrCreateIndividualStorage(viewModel, out _, out var methodDict))
- return;
+ public static void AddProperty(this ViewModel viewModel, string name, PropertyInfo propertyInfo)
+ {
+ if (!GetOrCreateIndividualStorage(viewModel, out var propDict, out _))
+ return;
- methodDict[name] = methodInfo;
- }
+ propDict[name] = propertyInfo;
+ }
- private static bool GetOrCreateIndividualStorage(ViewModel viewModel, [NotNullWhen(true)] out Dictionary? propDict, [NotNullWhen(true)] out Dictionary? methodDict)
- {
- propDict = null;
- methodDict = null;
+ public static void AddMethod(this ViewModel viewModel, string name, MethodInfo methodInfo)
+ {
+ if (!GetOrCreateIndividualStorage(viewModel, out _, out var methodDict))
+ return;
- if (PropertiesAndMethods is null || CachedViewModelProperties is null || DataSourceTypeBindingPropertiesCollectionCtor is null || GetProperties is null || GetMethods is null)
- return false;
+ methodDict[name] = methodInfo;
+ }
- if (PropertiesAndMethods(viewModel) is not { } storage || CachedViewModelProperties() is not { } staticStorageDict)
- return false;
+ private static bool GetOrCreateIndividualStorage(ViewModel viewModel, [NotNullWhen(true)] out Dictionary? propDict, [NotNullWhen(true)] out Dictionary? methodDict)
+ {
+ propDict = null;
+ methodDict = null;
- if ((propDict = GetProperties(storage)) is null || (methodDict = GetMethods(storage)) is null)
- return false;
+ if (PropertiesAndMethods is null || CachedViewModelProperties is null || DataSourceTypeBindingPropertiesCollectionCtor is null || GetProperties is null || GetMethods is null)
+ return false;
- var type = viewModel.GetType();
- if (!staticStorageDict.Contains(type)) // There is not static storage to copy from, fast exit
- return true;
+ if (PropertiesAndMethods(viewModel) is not { } storage || CachedViewModelProperties() is not { } staticStorageDict)
+ return false;
- if (staticStorageDict[type] is not { } staticStorage)
- return false;
+ if ((propDict = GetProperties(storage)) is null || (methodDict = GetMethods(storage)) is null)
+ return false;
- // TW caches the properties, since we modify each VM individually, we need to copy them
- if (ReferenceEquals(storage, staticStorage))
- PropertiesAndMethods(viewModel) = DataSourceTypeBindingPropertiesCollectionCtor(propDict = new(propDict), methodDict = new(methodDict));
+ var type = viewModel.GetType();
+ if (!staticStorageDict.Contains(type)) // There is not static storage to copy from, fast exit
return true;
- }
- public static TViewModelMixin? GetMixin(this TViewModel viewModel)
- where TViewModelMixin : ViewModelMixin
- where TViewModel : ViewModel
- => viewModel.GetPropertyValue(typeof(TViewModelMixin).Name) as TViewModelMixin;
+ if (staticStorageDict[type] is not { } staticStorage)
+ return false;
+
+ // TW caches the properties, since we modify each VM individually, we need to copy them
+ if (ReferenceEquals(storage, staticStorage))
+ PropertiesAndMethods(viewModel) = DataSourceTypeBindingPropertiesCollectionCtor(propDict = new(propDict), methodDict = new(methodDict));
+ return true;
}
+
+ public static TViewModelMixin? GetMixin(this TViewModel viewModel)
+ where TViewModelMixin : ViewModelMixin
+ where TViewModel : ViewModel
+ => viewModel.GetPropertyValue(typeof(TViewModelMixin).Name) as TViewModelMixin;
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Extensions/WidgetExtensions.cs b/src/Bannerlord.LauncherEx/Extensions/WidgetExtensions.cs
index 0baf97c..15a396e 100644
--- a/src/Bannerlord.LauncherEx/Extensions/WidgetExtensions.cs
+++ b/src/Bannerlord.LauncherEx/Extensions/WidgetExtensions.cs
@@ -11,95 +11,94 @@
using TaleWorlds.GauntletUI.BaseTypes;
using TaleWorlds.Library;
-namespace Bannerlord.LauncherEx.Extensions
+namespace Bannerlord.LauncherEx.Extensions;
+
+internal static class WidgetExtensions
{
- internal static class WidgetExtensions
- {
- private delegate void OnPropertyChangedDelegate1(PropertyOwnerObject instance, T value, [CallerMemberName] string? propertyName = null);
- private static readonly ConcurrentDictionary OnPropertyChanged1 =
- new();
+ private delegate void OnPropertyChangedDelegate1(PropertyOwnerObject instance, T value, [CallerMemberName] string? propertyName = null);
+ private static readonly ConcurrentDictionary OnPropertyChanged1 =
+ new();
- private delegate void OnPropertyChangedDelegate2(PropertyOwnerObject instance, bool value, [CallerMemberName] string? propertyName = null);
- private static readonly OnPropertyChangedDelegate2? OnPropertyChanged2 =
- AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(bool), typeof(string) });
+ private delegate void OnPropertyChangedDelegate2(PropertyOwnerObject instance, bool value, [CallerMemberName] string? propertyName = null);
+ private static readonly OnPropertyChangedDelegate2? OnPropertyChanged2 =
+ AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(bool), typeof(string) });
- private delegate void OnPropertyChangedDelegate3(PropertyOwnerObject instance, int value, [CallerMemberName] string? propertyName = null);
- private static readonly OnPropertyChangedDelegate3? OnPropertyChanged3 =
- AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(int), typeof(string) });
+ private delegate void OnPropertyChangedDelegate3(PropertyOwnerObject instance, int value, [CallerMemberName] string? propertyName = null);
+ private static readonly OnPropertyChangedDelegate3? OnPropertyChanged3 =
+ AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(int), typeof(string) });
- private delegate void OnPropertyChangedDelegate4(PropertyOwnerObject instance, float value, [CallerMemberName] string? propertyName = null);
- private static readonly OnPropertyChangedDelegate4? OnPropertyChanged4 =
- AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(float), typeof(string) });
+ private delegate void OnPropertyChangedDelegate4(PropertyOwnerObject instance, float value, [CallerMemberName] string? propertyName = null);
+ private static readonly OnPropertyChangedDelegate4? OnPropertyChanged4 =
+ AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(float), typeof(string) });
- private delegate void OnPropertyChangedDelegate5(PropertyOwnerObject instance, uint value, [CallerMemberName] string? propertyName = null);
- private static readonly OnPropertyChangedDelegate5? OnPropertyChanged5 =
- AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(uint), typeof(string) });
+ private delegate void OnPropertyChangedDelegate5(PropertyOwnerObject instance, uint value, [CallerMemberName] string? propertyName = null);
+ private static readonly OnPropertyChangedDelegate5? OnPropertyChanged5 =
+ AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(uint), typeof(string) });
- private delegate void OnPropertyChangedDelegate6(PropertyOwnerObject instance, Color value, [CallerMemberName] string? propertyName = null);
- private static readonly OnPropertyChangedDelegate6? OnPropertyChanged6 =
- AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(Color), typeof(string) });
+ private delegate void OnPropertyChangedDelegate6(PropertyOwnerObject instance, Color value, [CallerMemberName] string? propertyName = null);
+ private static readonly OnPropertyChangedDelegate6? OnPropertyChanged6 =
+ AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(Color), typeof(string) });
- private delegate void OnPropertyChangedDelegate7(PropertyOwnerObject instance, double value, [CallerMemberName] string? propertyName = null);
- private static readonly OnPropertyChangedDelegate7? OnPropertyChanged7 =
- AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(double), typeof(string) });
+ private delegate void OnPropertyChangedDelegate7(PropertyOwnerObject instance, double value, [CallerMemberName] string? propertyName = null);
+ private static readonly OnPropertyChangedDelegate7? OnPropertyChanged7 =
+ AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(double), typeof(string) });
- private delegate void OnPropertyChangedDelegate8(PropertyOwnerObject instance, Vec2 value, [CallerMemberName] string? propertyName = null);
- private static readonly OnPropertyChangedDelegate8? OnPropertyChanged8 =
- AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(Vec2), typeof(string) });
+ private delegate void OnPropertyChangedDelegate8(PropertyOwnerObject instance, Vec2 value, [CallerMemberName] string? propertyName = null);
+ private static readonly OnPropertyChangedDelegate8? OnPropertyChanged8 =
+ AccessTools2.GetDelegate(typeof(PropertyOwnerObject), "OnPropertyChanged", new[] { typeof(Vec2), typeof(string) });
- private delegate void OnPropertyChangedDelegate(PropertyOwnerObject instance, T value, [CallerMemberName] string? propertyName = null);
- private static readonly OnPropertyChangedDelegate? OnPropertyChangedMethod =
- AccessTools2.GetDelegate>(typeof(PropertyOwnerObject), "OnPropertyChanged");
+ private delegate void OnPropertyChangedDelegate(PropertyOwnerObject instance, T value, [CallerMemberName] string? propertyName = null);
+ private static readonly OnPropertyChangedDelegate? OnPropertyChangedMethod =
+ AccessTools2.GetDelegate>(typeof(PropertyOwnerObject), "OnPropertyChanged");
- private delegate void SetIsPressedDelegate(Widget instance, bool value);
- private static readonly SetIsPressedDelegate? SetIsPressedMethod =
- AccessTools2.GetPropertySetterDelegate(typeof(Widget), "IsPressed");
+ private delegate void SetIsPressedDelegate(Widget instance, bool value);
+ private static readonly SetIsPressedDelegate? SetIsPressedMethod =
+ AccessTools2.GetPropertySetterDelegate(typeof(Widget), "IsPressed");
- public static bool IsPointInsideMeasuredArea(this Widget widget)
- {
- var method = AccessTools2.Method(typeof(Widget), "IsPointInsideMeasuredArea");
- var property = AccessTools2.Property(typeof(EventManager), "MousePosition");
+ public static bool IsPointInsideMeasuredArea(this Widget widget)
+ {
+ var method = AccessTools2.Method(typeof(Widget), "IsPointInsideMeasuredArea");
+ var property = AccessTools2.Property(typeof(EventManager), "MousePosition");
+
+ if (method is null || property is null)
+ return false;
+
+ if (method.Invoke(widget, new[] { property.GetValue(widget.EventManager) }) is not bool result)
+ return false;
- if (method is null || property is null)
- return false;
+ return result;
+ }
- if (method.Invoke(widget, new[] { property.GetValue(widget.EventManager) }) is not bool result)
- return false;
+ public static void SetIsPressed(this Widget widget, bool value) => SetIsPressedMethod?.Invoke(widget, value);
- return result;
+ public static bool SetField(this Widget widget, ref T field, T value, [CallerMemberName] string? propertyName = null)
+ {
+ if (EqualityComparer.Default.Equals(field, value))
+ {
+ return false;
}
+ field = value;
- public static void SetIsPressed(this Widget widget, bool value) => SetIsPressedMethod?.Invoke(widget, value);
+ switch (value)
+ {
+ case bool val when OnPropertyChanged2 is not null: OnPropertyChanged2(widget, val, propertyName); return true;
+ case int val when OnPropertyChanged3 is not null: OnPropertyChanged3(widget, val, propertyName); return true;
+ case float val when OnPropertyChanged4 is not null: OnPropertyChanged4(widget, val, propertyName); return true;
+ case uint val when OnPropertyChanged5 is not null: OnPropertyChanged5(widget, val, propertyName); return true;
+ case Color val when OnPropertyChanged6 is not null: OnPropertyChanged6(widget, val, propertyName); return true;
+ case double val when OnPropertyChanged7 is not null: OnPropertyChanged7(widget, val, propertyName); return true;
+ case Vec2 val when OnPropertyChanged8 is not null: OnPropertyChanged8(widget, val, propertyName); return true;
+ }
- public static bool SetField(this Widget widget, ref T field, T value, [CallerMemberName] string? propertyName = null)
+ static Delegate ValueFactory(Type _)
{
- if (EqualityComparer.Default.Equals(field, value))
- {
- return false;
- }
- field = value;
-
- switch (value)
- {
- case bool val when OnPropertyChanged2 is not null: OnPropertyChanged2(widget, val, propertyName); return true;
- case int val when OnPropertyChanged3 is not null: OnPropertyChanged3(widget, val, propertyName); return true;
- case float val when OnPropertyChanged4 is not null: OnPropertyChanged4(widget, val, propertyName); return true;
- case uint val when OnPropertyChanged5 is not null: OnPropertyChanged5(widget, val, propertyName); return true;
- case Color val when OnPropertyChanged6 is not null: OnPropertyChanged6(widget, val, propertyName); return true;
- case double val when OnPropertyChanged7 is not null: OnPropertyChanged7(widget, val, propertyName); return true;
- case Vec2 val when OnPropertyChanged8 is not null: OnPropertyChanged8(widget, val, propertyName); return true;
- }
-
- static Delegate ValueFactory(Type _)
- {
- var method = AccessTools.GetDeclaredMethods(typeof(PropertyOwnerObject)).FirstOrDefault(x => x.IsGenericMethod && x.Name == "OnPropertyChanged")?.MakeGenericMethod(typeof(T))!;
- return AccessTools2.GetDelegate>(method)!;
- }
-
- if (OnPropertyChanged1.GetOrAdd(typeof(T), ValueFactory) is OnPropertyChangedDelegate1 del)
- del(widget, value, propertyName);
- return true;
+ var method = AccessTools.GetDeclaredMethods(typeof(PropertyOwnerObject)).FirstOrDefault(x => x.IsGenericMethod && x.Name == "OnPropertyChanged")?.MakeGenericMethod(typeof(T))!;
+ return AccessTools2.GetDelegate>(method)!;
}
+
+ if (OnPropertyChanged1.GetOrAdd(typeof(T), ValueFactory) is OnPropertyChangedDelegate1 del)
+ del(widget, value, propertyName);
+ return true;
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/AssemblyWrapper.cs b/src/Bannerlord.LauncherEx/Helpers/AssemblyWrapper.cs
index cb52b1c..7d2b080 100644
--- a/src/Bannerlord.LauncherEx/Helpers/AssemblyWrapper.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/AssemblyWrapper.cs
@@ -1,11 +1,10 @@
using System.Reflection;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+internal class AssemblyWrapper : Assembly
{
- internal class AssemblyWrapper : Assembly
- {
- public override string Location { get; }
+ public override string Location { get; }
- public AssemblyWrapper(string location) => Location = location;
- }
+ public AssemblyWrapper(string location) => Location = location;
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/ConfigReader.cs b/src/Bannerlord.LauncherEx/Helpers/ConfigReader.cs
index 8ba2cdf..8251958 100644
--- a/src/Bannerlord.LauncherEx/Helpers/ConfigReader.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/ConfigReader.cs
@@ -4,60 +4,59 @@
using System.Linq;
using System.Text;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+internal static class ConfigReader
{
- internal static class ConfigReader
- {
- private static readonly string BOMMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
-
- public static readonly string GameConfigPath =
- Path.Combine($@"{Environment.GetFolderPath(Environment.SpecialFolder.Personal)}", "Mount and Blade II Bannerlord", "Configs", "BannerlordConfig.txt");
- public static readonly string EngineConfigPath =
- Path.Combine($@"{Environment.GetFolderPath(Environment.SpecialFolder.Personal)}", "Mount and Blade II Bannerlord", "Configs", "engine_config.txt");
+ private static readonly string BOMMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
+
+ public static readonly string GameConfigPath =
+ Path.Combine($@"{Environment.GetFolderPath(Environment.SpecialFolder.Personal)}", "Mount and Blade II Bannerlord", "Configs", "BannerlordConfig.txt");
+ public static readonly string EngineConfigPath =
+ Path.Combine($@"{Environment.GetFolderPath(Environment.SpecialFolder.Personal)}", "Mount and Blade II Bannerlord", "Configs", "engine_config.txt");
- public static Dictionary GetGameOptions(Func readFileContent)
+ public static Dictionary GetGameOptions(Func readFileContent)
+ {
+ var dict = new Dictionary();
+ if (readFileContent(GameConfigPath) is not { } data) return dict;
+ try
{
- var dict = new Dictionary();
- if (readFileContent(GameConfigPath) is not { } data) return dict;
- try
- {
- var content = Encoding.UTF8.GetString(data);
- if (content.StartsWith(BOMMarkUtf8, StringComparison.Ordinal))
- content = content.Remove(0, BOMMarkUtf8.Length);
+ var content = Encoding.UTF8.GetString(data);
+ if (content.StartsWith(BOMMarkUtf8, StringComparison.Ordinal))
+ content = content.Remove(0, BOMMarkUtf8.Length);
- foreach (var keyValue in content.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries))
- {
- var split = keyValue.Split(new[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
- if (split.Length != 2) continue;
- var key = split[0].Trim();
- var value = split[1].Trim();
- dict[key] = value;
- }
+ foreach (var keyValue in content.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ var split = keyValue.Split(new[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
+ if (split.Length != 2) continue;
+ var key = split[0].Trim();
+ var value = split[1].Trim();
+ dict[key] = value;
}
- catch (Exception) { /* ignore */ }
- return dict;
}
- public static Dictionary GetEngineOptions(Func readFileContent)
+ catch (Exception) { /* ignore */ }
+ return dict;
+ }
+ public static Dictionary GetEngineOptions(Func readFileContent)
+ {
+ var dict = new Dictionary();
+ if (readFileContent(EngineConfigPath) is not { } data) return dict;
+ try
{
- var dict = new Dictionary();
- if (readFileContent(EngineConfigPath) is not { } data) return dict;
- try
- {
- var content = Encoding.UTF8.GetString(data);
- if (content.StartsWith(BOMMarkUtf8, StringComparison.Ordinal))
- content = content.Remove(0, BOMMarkUtf8.Length);
+ var content = Encoding.UTF8.GetString(data);
+ if (content.StartsWith(BOMMarkUtf8, StringComparison.Ordinal))
+ content = content.Remove(0, BOMMarkUtf8.Length);
- foreach (var keyValue in content.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries))
- {
- var split = keyValue.Split(new[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
- if (split.Length != 2) continue;
- var key = split[0].Trim();
- var value = split[1].Trim();
- dict[key] = value;
- }
+ foreach (var keyValue in content.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ var split = keyValue.Split(new[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
+ if (split.Length != 2) continue;
+ var key = split[0].Trim();
+ var value = split[1].Trim();
+ dict[key] = value;
}
- catch (Exception) { /* ignore */ }
- return dict;
}
+ catch (Exception) { /* ignore */ }
+ return dict;
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/HintManager.cs b/src/Bannerlord.LauncherEx/Helpers/HintManager.cs
index 2951414..dea86f2 100644
--- a/src/Bannerlord.LauncherEx/Helpers/HintManager.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/HintManager.cs
@@ -2,13 +2,12 @@
using TaleWorlds.MountAndBlade.Launcher.Library;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+internal static class HintManager
{
- internal static class HintManager
- {
- public static void ShowHint(BUTRTextObject message) => ShowHint(message.ToString());
- public static void ShowHint(string message) => LauncherUI.AddHintInformation(message);
+ public static void ShowHint(BUTRTextObject message) => ShowHint(message.ToString());
+ public static void ShowHint(string message) => LauncherUI.AddHintInformation(message);
- public static void HideHint() => LauncherUI.HideHintInformation();
- }
+ public static void HideHint() => LauncherUI.HideHintInformation();
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/Input/BUTRInputManager.cs b/src/Bannerlord.LauncherEx/Helpers/Input/BUTRInputManager.cs
index ec9bfd7..c244cc1 100644
--- a/src/Bannerlord.LauncherEx/Helpers/Input/BUTRInputManager.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/Input/BUTRInputManager.cs
@@ -6,168 +6,152 @@
using TaleWorlds.InputSystem;
using TaleWorlds.Library;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+// Can't believe I need to add a custom keyboard handler for the launcher
+internal class BUTRInputManager : IInputManager, IDisposable
{
- // Can't believe I need to add a custom keyboard handler for the launcher
- internal class BUTRInputManager : IInputManager, IDisposable
- {
- public readonly IInputManager InputManager;
- public readonly int[] ReleasedChars = new int[10];
+ public readonly IInputManager InputManager;
+ public readonly int[] ReleasedChars = new int[10];
- private KeyboardState _currentState;
- private KeyboardState _previousState;
+ private KeyboardState _currentState;
+ private KeyboardState _previousState;
- public BUTRInputManager(IInputManager inputManager) => InputManager = inputManager;
+ public BUTRInputManager(IInputManager inputManager) => InputManager = inputManager;
- public void Update()
- {
- _currentState.Dispose();
-
- _previousState = _currentState;
- _currentState = Keyboard.GetState();
-
- var previousPressedKeys = _previousState.GetPressedKeys();
- var currentPressedKeys = _currentState.GetPressedKeys();
-
- var i = 0;
- foreach (var str in previousPressedKeys.Except(currentPressedKeys).Select(x => _currentState.AsString(x)))
- {
- if (string.IsNullOrEmpty(str)) continue;
-
- ReleasedChars[i] = str[0];
- i++;
- }
- for (; i < ReleasedChars.Length; i++)
- {
- ReleasedChars[i] = default;
- }
- }
+ public void Update()
+ {
+ _currentState.Dispose();
- public bool IsMouseActive() => InputManager.IsMouseActive();
- public float GetMousePositionX() => InputManager.GetMousePositionX();
- public float GetMousePositionY() => InputManager.GetMousePositionY();
- public float GetMouseScrollValue() => InputManager.GetMouseScrollValue();
- public float GetMouseMoveY() => InputManager.GetMouseMoveY();
- public float GetMouseSensitivity() => InputManager.GetMouseSensitivity();
- public float GetMouseDeltaZ() => InputManager.GetMouseDeltaZ();
+ _previousState = _currentState;
+ _currentState = Keyboard.GetState();
- public void SetClipboardText(string text)
+ var previousPressedKeys = _previousState.GetPressedKeys();
+ var currentPressedKeys = _currentState.GetPressedKeys();
+
+ var i = 0;
+ foreach (var str in previousPressedKeys.Except(currentPressedKeys).Select(x => _currentState.AsString(x)))
{
- var thread = new Thread(() => WindowsClipboard.SetText(text));
- thread.SetApartmentState(ApartmentState.STA);
- thread.Start();
- thread.Join();
- //_inputManagerImplementation.SetClipboardText(text);
+ if (string.IsNullOrEmpty(str)) continue;
+
+ ReleasedChars[i] = str[0];
+ i++;
}
- public string GetClipboardText()
+ for (; i < ReleasedChars.Length; i++)
{
- var text = string.Empty;
- var thread = new Thread(() => text = WindowsClipboard.GetText());
- thread.SetApartmentState(ApartmentState.STA);
- thread.Start();
- thread.Join();
- return text;
- //return _inputManagerImplementation.GetClipboardText();
+ ReleasedChars[i] = default;
}
+ }
- public Vec2 GetKeyState(InputKey key) =>
- IsAction(key, rawKey => new Vec2(_currentState.IsKeyDown(rawKey) ? 1f : 0f, _previousState.IsKeyDown(rawKey) ? 1f : 0f), _key => InputManager.GetKeyState(_key));
- public bool IsKeyPressed(InputKey key) =>
- IsAction(key, rawKey => _currentState.IsKeyDown(rawKey) && _previousState.IsKeyUp(rawKey), _key => InputManager.IsKeyPressed(_key));
- public bool IsKeyDown(InputKey key) =>
- IsAction(key, rawKey => _currentState.IsKeyDown(rawKey) || _previousState.IsKeyDown(rawKey), _key => InputManager.IsKeyDown(_key));
- public bool IsKeyReleased(InputKey key) =>
- IsAction(key, rawKey => _currentState.IsKeyUp(rawKey) && _previousState.IsKeyDown(rawKey), _key => InputManager.IsKeyReleased(_key));
- public bool IsKeyDownImmediate(InputKey key) =>
- IsAction(key, rawKey => _currentState.IsKeyDown(rawKey), _key => InputManager.IsKeyDownImmediate(_key));
-
- public Vec2 GetResolution() => InputManager.GetResolution();
- public Vec2 GetDesktopResolution() => InputManager.GetDesktopResolution();
-
- public void SetCursorPosition(int x, int y) => InputManager.SetCursorPosition(x, y);
- public void SetCursorFriction(float frictionValue) => InputManager.SetCursorFriction(frictionValue);
-
- public void PressKey(InputKey key) => InputManager.PressKey(key);
- public void ClearKeys() => InputManager.ClearKeys();
- public int GetVirtualKeyCode(InputKey key) => InputManager.GetVirtualKeyCode(key);
- public float GetMouseMoveX() => InputManager.GetMouseMoveX();
- public void UpdateKeyData(byte[] keyData) => InputManager.UpdateKeyData(keyData);
-
- public bool IsControllerConnected() => InputManager.IsControllerConnected();
-#if v100 || v101 || v102 || v103 || v110 || v111 || v112 || v113 || v114 || v115
- public InputKey GetControllerClickKey() => InputManager.GetControllerClickKey();
-#endif
+ public bool IsMouseActive() => InputManager.IsMouseActive();
+ public float GetMousePositionX() => InputManager.GetMousePositionX();
+ public float GetMousePositionY() => InputManager.GetMousePositionY();
+ public float GetMouseScrollValue() => InputManager.GetMouseScrollValue();
+ public float GetMouseMoveY() => InputManager.GetMouseMoveY();
+ public float GetMouseSensitivity() => InputManager.GetMouseSensitivity();
+ public float GetMouseDeltaZ() => InputManager.GetMouseDeltaZ();
-#if v110 || v111
- public void SetRumbleEffect(float[] lowFrequencyLevels, float[] lowFrequencyDurations, int numLowFrequencyElements, float[] highFrequencyLevels,
- float[] highFrequencyDurations, int numHighFrequencyElements) =>
- InputManager.SetRumbleEffect(lowFrequencyLevels, lowFrequencyDurations, numLowFrequencyElements, highFrequencyLevels, highFrequencyDurations, numHighFrequencyElements);
- public void SetTriggerFeedback(byte leftTriggerPosition, byte leftTriggerStrength, byte rightTriggerPosition, byte rightTriggerStrength) =>
- InputManager.SetTriggerFeedback(leftTriggerPosition, leftTriggerStrength, rightTriggerPosition, rightTriggerStrength);
- public void SetTriggerWeaponEffect(byte leftStartPosition, byte leftEnd_position, byte leftStrength, byte rightStartPosition, byte rightEndPosition, byte rightStrength) =>
- InputManager.SetTriggerWeaponEffect(leftStartPosition, leftEnd_position, leftStrength, rightStartPosition, rightEndPosition, rightStrength);
- public void SetTriggerVibration(float[] leftTriggerAmplitudes, float[] leftTriggerFrequencies, float[] leftTriggerDurations, int numLeftTriggerElements,
- float[] rightTriggerAmplitudes, float[] rightTriggerFrequencies, float[] rightTriggerDurations, int numRightTriggerElements) =>
- InputManager.SetTriggerVibration(leftTriggerAmplitudes, leftTriggerFrequencies, leftTriggerDurations, numLeftTriggerElements, rightTriggerAmplitudes,
- rightTriggerFrequencies, rightTriggerDurations, numRightTriggerElements);
- public void SetLightbarColor(float red, float green, float blue) => InputManager.SetLightbarColor(red, green, blue);
-#endif
+ public void SetClipboardText(string text)
+ {
+ var thread = new Thread(() => WindowsClipboard.SetText(text));
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
+ thread.Join();
+ //_inputManagerImplementation.SetClipboardText(text);
+ }
+ public string GetClipboardText()
+ {
+ var text = string.Empty;
+ var thread = new Thread(() => text = WindowsClipboard.GetText());
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
+ thread.Join();
+ return text;
+ //return _inputManagerImplementation.GetClipboardText();
+ }
- private static TReturn IsAction(InputKey key, Func action, Func fallback)
- {
- var rawKey = key switch
- {
- InputKey.BackSpace => Keys.Back,
- InputKey.Enter => Keys.Enter,
- _ => Enum.TryParse(key.ToString(), out var keyVal) ? keyVal : Keys.None
- };
- if (key is >= InputKey.ControllerLStickUp and <= InputKey.ControllerRTrigger or InputKey.ControllerLStick or InputKey.ControllerRStick)
- {
- return fallback(key);
- }
- if (key is InputKey.LeftMouseButton or InputKey.RightMouseButton or InputKey.MiddleMouseButton)
- {
- return fallback(key);
- }
- if (rawKey == Keys.None)
- {
- Trace.TraceError($"Wrong key {key}");
- return fallback(key);
- }
-
- return action(rawKey);
- }
+ public Vec2 GetKeyState(InputKey key) =>
+ IsAction(key, rawKey => new Vec2(_currentState.IsKeyDown(rawKey) ? 1f : 0f, _previousState.IsKeyDown(rawKey) ? 1f : 0f), _key => InputManager.GetKeyState(_key));
+ public bool IsKeyPressed(InputKey key) =>
+ IsAction(key, rawKey => _currentState.IsKeyDown(rawKey) && _previousState.IsKeyUp(rawKey), _key => InputManager.IsKeyPressed(_key));
+ public bool IsKeyDown(InputKey key) =>
+ IsAction(key, rawKey => _currentState.IsKeyDown(rawKey) || _previousState.IsKeyDown(rawKey), _key => InputManager.IsKeyDown(_key));
+ public bool IsKeyReleased(InputKey key) =>
+ IsAction(key, rawKey => _currentState.IsKeyUp(rawKey) && _previousState.IsKeyDown(rawKey), _key => InputManager.IsKeyReleased(_key));
+ public bool IsKeyDownImmediate(InputKey key) =>
+ IsAction(key, rawKey => _currentState.IsKeyDown(rawKey), _key => InputManager.IsKeyDownImmediate(_key));
-#if v120
- public TaleWorlds.InputSystem.Input.ControllerTypes GetControllerType() => InputManager.GetControllerType();
+ public Vec2 GetResolution() => InputManager.GetResolution();
+ public Vec2 GetDesktopResolution() => InputManager.GetDesktopResolution();
- public float GetGyroX() => InputManager.GetGyroX();
- public float GetGyroY() => InputManager.GetGyroY();
- public float GetGyroZ() => InputManager.GetGyroZ();
+ public void SetCursorPosition(int x, int y) => InputManager.SetCursorPosition(x, y);
+ public void SetCursorFriction(float frictionValue) => InputManager.SetCursorFriction(frictionValue);
- public InputKey[] GetClickKeys() => InputManager.GetClickKeys();
+ public void PressKey(InputKey key) => InputManager.PressKey(key);
+ public void ClearKeys() => InputManager.ClearKeys();
+ public int GetVirtualKeyCode(InputKey key) => InputManager.GetVirtualKeyCode(key);
+ public float GetMouseMoveX() => InputManager.GetMouseMoveX();
+ public void UpdateKeyData(byte[] keyData) => InputManager.UpdateKeyData(keyData);
- public void SetRumbleEffect(float[] lowFrequencyLevels, float[] lowFrequencyDurations, int numLowFrequencyElements, float[] highFrequencyLevels, float[] highFrequencyDurations, int numHighFrequencyElements) =>
- InputManager.SetRumbleEffect(lowFrequencyLevels, lowFrequencyDurations, numLowFrequencyElements, highFrequencyLevels, highFrequencyDurations, numHighFrequencyElements);
+ public bool IsControllerConnected() => InputManager.IsControllerConnected();
- public void SetTriggerFeedback(byte leftTriggerPosition, byte leftTriggerStrength, byte rightTriggerPosition, byte rightTriggerStrength) =>
- InputManager.SetTriggerFeedback(leftTriggerPosition, leftTriggerStrength, rightTriggerPosition, rightTriggerStrength);
+#if v100 || v110
+ public InputKey GetControllerClickKey() => InputManager.GetControllerClickKey();
+#endif
- public void SetTriggerWeaponEffect(byte leftStartPosition, byte leftEnd_position, byte leftStrength, byte rightStartPosition, byte rightEndPosition, byte rightStrength) =>
- InputManager.SetTriggerWeaponEffect(leftStartPosition, leftEnd_position, leftStrength, rightStartPosition, rightEndPosition, rightStrength);
+#if v110 || v120
+ public void SetRumbleEffect(float[] lowFrequencyLevels, float[] lowFrequencyDurations, int numLowFrequencyElements, float[] highFrequencyLevels, float[] highFrequencyDurations, int numHighFrequencyElements) =>
+ InputManager.SetRumbleEffect(lowFrequencyLevels, lowFrequencyDurations, numLowFrequencyElements, highFrequencyLevels, highFrequencyDurations, numHighFrequencyElements);
+ public void SetTriggerFeedback(byte leftTriggerPosition, byte leftTriggerStrength, byte rightTriggerPosition, byte rightTriggerStrength) =>
+ InputManager.SetTriggerFeedback(leftTriggerPosition, leftTriggerStrength, rightTriggerPosition, rightTriggerStrength);
+ public void SetTriggerWeaponEffect(byte leftStartPosition, byte leftEnd_position, byte leftStrength, byte rightStartPosition, byte rightEndPosition, byte rightStrength) =>
+ InputManager.SetTriggerWeaponEffect(leftStartPosition, leftEnd_position, leftStrength, rightStartPosition, rightEndPosition, rightStrength);
+ public void SetTriggerVibration(float[] leftTriggerAmplitudes, float[] leftTriggerFrequencies, float[] leftTriggerDurations, int numLeftTriggerElements, float[] rightTriggerAmplitudes, float[] rightTriggerFrequencies, float[] rightTriggerDurations, int numRightTriggerElements) =>
+ InputManager.SetTriggerVibration(leftTriggerAmplitudes, leftTriggerFrequencies, leftTriggerDurations, numLeftTriggerElements, rightTriggerAmplitudes, rightTriggerFrequencies, rightTriggerDurations, numRightTriggerElements);
+ public void SetLightbarColor(float red, float green, float blue) => InputManager.SetLightbarColor(red, green, blue);
+#endif
- public void SetTriggerVibration(float[] leftTriggerAmplitudes, float[] leftTriggerFrequencies, float[] leftTriggerDurations, int numLeftTriggerElements, float[] rightTriggerAmplitudes, float[] rightTriggerFrequencies, float[] rightTriggerDurations, int numRightTriggerElements) =>
- InputManager.SetTriggerVibration(leftTriggerAmplitudes, leftTriggerFrequencies, leftTriggerDurations, numLeftTriggerElements, rightTriggerAmplitudes, rightTriggerFrequencies, rightTriggerDurations, numRightTriggerElements);
+#if v120
+ public TaleWorlds.InputSystem.Input.ControllerTypes GetControllerType() => InputManager.GetControllerType();
- public void SetLightbarColor(float red, float green, float blue) => InputManager.SetLightbarColor(red, green, blue);
+ public float GetGyroX() => InputManager.GetGyroX();
+ public float GetGyroY() => InputManager.GetGyroY();
+ public float GetGyroZ() => InputManager.GetGyroZ();
- public bool IsAnyTouchActive() => InputManager.IsAnyTouchActive();
+ public InputKey[] GetClickKeys() => InputManager.GetClickKeys();
+
+ public bool IsAnyTouchActive() => InputManager.IsAnyTouchActive();
#endif
- public void Dispose()
+ private static TReturn IsAction(InputKey key, Func action, Func fallback)
+ {
+ var rawKey = key switch
{
- _currentState.Dispose();
- _previousState.Dispose();
+ InputKey.BackSpace => Keys.Back,
+ InputKey.Enter => Keys.Enter,
+ _ => Enum.TryParse(key.ToString(), out var keyVal) ? keyVal : Keys.None
+ };
+ if (key is >= InputKey.ControllerLStickUp and <= InputKey.ControllerRTrigger or InputKey.ControllerLStick or InputKey.ControllerRStick)
+ {
+ return fallback(key);
}
+ if (key is InputKey.LeftMouseButton or InputKey.RightMouseButton or InputKey.MiddleMouseButton)
+ {
+ return fallback(key);
+ }
+ if (rawKey == Keys.None)
+ {
+ Trace.TraceError($"Wrong key {key}");
+ return fallback(key);
+ }
+
+ return action(rawKey);
+ }
+
+
+ public void Dispose()
+ {
+ _currentState.Dispose();
+ _previousState.Dispose();
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/Input/KeyState.cs b/src/Bannerlord.LauncherEx/Helpers/Input/KeyState.cs
index c33f25f..3645901 100644
--- a/src/Bannerlord.LauncherEx/Helpers/Input/KeyState.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/Input/KeyState.cs
@@ -1,4 +1,3 @@
-namespace Bannerlord.LauncherEx.Helpers
-{
- internal enum KeyState { Up, Down, }
-}
\ No newline at end of file
+namespace Bannerlord.LauncherEx.Helpers;
+
+internal enum KeyState { Up, Down, }
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/Input/Keyboard.cs b/src/Bannerlord.LauncherEx/Helpers/Input/Keyboard.cs
index abe7b14..5247efb 100644
--- a/src/Bannerlord.LauncherEx/Helpers/Input/Keyboard.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/Input/Keyboard.cs
@@ -3,16 +3,15 @@
using Windows.Win32;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+internal static class Keyboard
{
- internal static class Keyboard
+ public static KeyboardState GetState()
{
- public static KeyboardState GetState()
- {
- var keyState = MemoryPool.Shared.Rent(256);
- return !PInvoke.GetKeyboardState(keyState.Memory.Span)
- ? KeyboardState.Empty
- : new KeyboardState(keyState, Console.CapsLock, Console.NumberLock);
- }
+ var keyState = MemoryPool.Shared.Rent(256);
+ return !PInvoke.GetKeyboardState(keyState.Memory.Span)
+ ? KeyboardState.Empty
+ : new KeyboardState(keyState, Console.CapsLock, Console.NumberLock);
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/Input/KeyboardState.cs b/src/Bannerlord.LauncherEx/Helpers/Input/KeyboardState.cs
index 4bef231..29a105d 100644
--- a/src/Bannerlord.LauncherEx/Helpers/Input/KeyboardState.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/Input/KeyboardState.cs
@@ -6,170 +6,169 @@
using Windows.Win32;
using Windows.Win32.Foundation;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+internal readonly struct KeyboardState
{
- internal readonly struct KeyboardState
- {
- public static KeyboardState Empty = new(null);
+ public static KeyboardState Empty = new(null);
- private static readonly byte[] _definedKeyCodes =
- ((Keys[]) Enum.GetValues(typeof(Keys))).Cast().Where(keyCode => keyCode is >= 1 and <= 255).Select(keyCode => (byte) keyCode).ToArray();
+ private static readonly byte[] _definedKeyCodes =
+ ((Keys[]) Enum.GetValues(typeof(Keys))).Cast().Where(keyCode => keyCode is >= 1 and <= 255).Select(keyCode => (byte) keyCode).ToArray();
- private const byte CapsLockModifier = 1;
- private const byte NumLockModifier = 2;
+ private const byte CapsLockModifier = 1;
+ private const byte NumLockModifier = 2;
- private readonly IMemoryOwner? _keyState;
- // Array of 256 bits:
- private readonly uint _keys0, _keys1, _keys2, _keys3, _keys4, _keys5, _keys6, _keys7;
- private readonly byte _modifiers;
+ private readonly IMemoryOwner? _keyState;
+ // Array of 256 bits:
+ private readonly uint _keys0, _keys1, _keys2, _keys3, _keys4, _keys5, _keys6, _keys7;
+ private readonly byte _modifiers;
- public bool CapsLock => (_modifiers & CapsLockModifier) > 0;
- public bool NumLock => (_modifiers & NumLockModifier) > 0;
- public KeyState this[Keys key] => InternalGetKey(key) ? KeyState.Down : KeyState.Up;
+ public bool CapsLock => (_modifiers & CapsLockModifier) > 0;
+ public bool NumLock => (_modifiers & NumLockModifier) > 0;
+ public KeyState this[Keys key] => InternalGetKey(key) ? KeyState.Down : KeyState.Up;
- public KeyboardState(IMemoryOwner? keyState, bool capsLock = false, bool numLock = false) : this()
+ public KeyboardState(IMemoryOwner? keyState, bool capsLock = false, bool numLock = false) : this()
+ {
+ _keyState = keyState;
+ _keys0 = 0;
+ _keys1 = 0;
+ _keys2 = 0;
+ _keys3 = 0;
+ _keys4 = 0;
+ _keys5 = 0;
+ _keys6 = 0;
+ _keys7 = 0;
+ _modifiers = (byte) (0 | (capsLock ? CapsLockModifier : 0) | (numLock ? NumLockModifier : 0));
+
+ if (_keyState is null) return;
+ var keys = new HashSet();
+ var span = _keyState.Memory.Span;
+ for (var i = 0; i < _definedKeyCodes.Length; i++)
{
- _keyState = keyState;
- _keys0 = 0;
- _keys1 = 0;
- _keys2 = 0;
- _keys3 = 0;
- _keys4 = 0;
- _keys5 = 0;
- _keys6 = 0;
- _keys7 = 0;
- _modifiers = (byte) (0 | (capsLock ? CapsLockModifier : 0) | (numLock ? NumLockModifier : 0));
-
- if (_keyState is null) return;
- var keys = new HashSet();
- var span = _keyState.Memory.Span;
- for (var i = 0; i < _definedKeyCodes.Length; i++)
+ if ((span[_definedKeyCodes[i]] & 0x80) == 0) continue;
+ var key = (Keys) _definedKeyCodes[i];
+ if (keys.Contains(key)) continue;
+ keys.Add(key);
+
+ var mask = (uint) 1 << ((int) key & 0x1f);
+ switch ((int) key >> 5)
{
- if ((span[_definedKeyCodes[i]] & 0x80) == 0) continue;
- var key = (Keys) _definedKeyCodes[i];
- if (keys.Contains(key)) continue;
- keys.Add(key);
-
- var mask = (uint) 1 << ((int) key & 0x1f);
- switch ((int) key >> 5)
- {
- case 0: _keys0 |= mask; break;
- case 1: _keys1 |= mask; break;
- case 2: _keys2 |= mask; break;
- case 3: _keys3 |= mask; break;
- case 4: _keys4 |= mask; break;
- case 5: _keys5 |= mask; break;
- case 6: _keys6 |= mask; break;
- case 7: _keys7 |= mask; break;
- }
+ case 0: _keys0 |= mask; break;
+ case 1: _keys1 |= mask; break;
+ case 2: _keys2 |= mask; break;
+ case 3: _keys3 |= mask; break;
+ case 4: _keys4 |= mask; break;
+ case 5: _keys5 |= mask; break;
+ case 6: _keys6 |= mask; break;
+ case 7: _keys7 |= mask; break;
}
}
+ }
- public bool IsKeyDown(Keys key) => InternalGetKey(key);
- public bool IsKeyUp(Keys key) => !InternalGetKey(key);
+ public bool IsKeyDown(Keys key) => InternalGetKey(key);
+ public bool IsKeyUp(Keys key) => !InternalGetKey(key);
- public int GetPressedKeyCount()
- {
- var count = CountBits(_keys0) + CountBits(_keys1) + CountBits(_keys2) + CountBits(_keys3)
- + CountBits(_keys4) + CountBits(_keys5) + CountBits(_keys6) + CountBits(_keys7);
- return (int) count;
- }
- public Keys[] GetPressedKeys()
- {
- var count = GetPressedKeyCount();
- if (count == 0) return Array.Empty();
- var keys = new Keys[count];
-
- var index = 0;
- if (_keys0 != 0) index = AddKeysToArray(_keys0, 0 * 32, keys, index);
- if (_keys1 != 0) index = AddKeysToArray(_keys1, 1 * 32, keys, index);
- if (_keys2 != 0) index = AddKeysToArray(_keys2, 2 * 32, keys, index);
- if (_keys3 != 0) index = AddKeysToArray(_keys3, 3 * 32, keys, index);
- if (_keys4 != 0) index = AddKeysToArray(_keys4, 4 * 32, keys, index);
- if (_keys5 != 0) index = AddKeysToArray(_keys5, 5 * 32, keys, index);
- if (_keys6 != 0) index = AddKeysToArray(_keys6, 6 * 32, keys, index);
- if (_keys7 != 0) index = AddKeysToArray(_keys7, 7 * 32, keys, index);
-
- return keys;
- }
+ public int GetPressedKeyCount()
+ {
+ var count = CountBits(_keys0) + CountBits(_keys1) + CountBits(_keys2) + CountBits(_keys3)
+ + CountBits(_keys4) + CountBits(_keys5) + CountBits(_keys6) + CountBits(_keys7);
+ return (int) count;
+ }
+ public Keys[] GetPressedKeys()
+ {
+ var count = GetPressedKeyCount();
+ if (count == 0) return Array.Empty();
+ var keys = new Keys[count];
+
+ var index = 0;
+ if (_keys0 != 0) index = AddKeysToArray(_keys0, 0 * 32, keys, index);
+ if (_keys1 != 0) index = AddKeysToArray(_keys1, 1 * 32, keys, index);
+ if (_keys2 != 0) index = AddKeysToArray(_keys2, 2 * 32, keys, index);
+ if (_keys3 != 0) index = AddKeysToArray(_keys3, 3 * 32, keys, index);
+ if (_keys4 != 0) index = AddKeysToArray(_keys4, 4 * 32, keys, index);
+ if (_keys5 != 0) index = AddKeysToArray(_keys5, 5 * 32, keys, index);
+ if (_keys6 != 0) index = AddKeysToArray(_keys6, 6 * 32, keys, index);
+ if (_keys7 != 0) index = AddKeysToArray(_keys7, 7 * 32, keys, index);
+
+ return keys;
+ }
- private bool InternalGetKey(Keys key)
+ private bool InternalGetKey(Keys key)
+ {
+ var mask = (uint) 1 << ((int) key & 0x1f);
+ uint element = ((int) key >> 5) switch
{
- var mask = (uint) 1 << ((int) key & 0x1f);
- uint element = ((int) key >> 5) switch
- {
- 0 => _keys0,
- 1 => _keys1,
- 2 => _keys2,
- 3 => _keys3,
- 4 => _keys4,
- 5 => _keys5,
- 6 => _keys6,
- 7 => _keys7,
- _ => 0
- };
- return (element & mask) != 0;
- }
+ 0 => _keys0,
+ 1 => _keys1,
+ 2 => _keys2,
+ 3 => _keys3,
+ 4 => _keys4,
+ 5 => _keys5,
+ 6 => _keys6,
+ 7 => _keys7,
+ _ => 0
+ };
+ return (element & mask) != 0;
+ }
- public override int GetHashCode() => (int) (_keys0 ^ _keys1 ^ _keys2 ^ _keys3 ^ _keys4 ^ _keys5 ^ _keys6 ^ _keys7);
+ public override int GetHashCode() => (int) (_keys0 ^ _keys1 ^ _keys2 ^ _keys3 ^ _keys4 ^ _keys5 ^ _keys6 ^ _keys7);
- public static bool operator ==(KeyboardState a, KeyboardState b) => a._keys0 == b._keys0 &&
- a._keys1 == b._keys1 &&
- a._keys2 == b._keys2 &&
- a._keys3 == b._keys3 &&
- a._keys4 == b._keys4 &&
- a._keys5 == b._keys5 &&
- a._keys6 == b._keys6 &&
- a._keys7 == b._keys7;
+ public static bool operator ==(KeyboardState a, KeyboardState b) => a._keys0 == b._keys0 &&
+ a._keys1 == b._keys1 &&
+ a._keys2 == b._keys2 &&
+ a._keys3 == b._keys3 &&
+ a._keys4 == b._keys4 &&
+ a._keys5 == b._keys5 &&
+ a._keys6 == b._keys6 &&
+ a._keys7 == b._keys7;
- public static bool operator !=(KeyboardState a, KeyboardState b) => !(a == b);
+ public static bool operator !=(KeyboardState a, KeyboardState b) => !(a == b);
- public override bool Equals(object? obj) => obj is KeyboardState state && this == state;
+ public override bool Equals(object? obj) => obj is KeyboardState state && this == state;
- public unsafe string AsString(Keys key)
- {
- if (_keyState is null)
- return string.Empty;
+ public unsafe string AsString(Keys key)
+ {
+ if (_keyState is null)
+ return string.Empty;
- var vkCode = (uint) key;
+ var vkCode = (uint) key;
- var currentHWnd = PInvoke.GetForegroundWindow();
- var currentWindowThreadID = PInvoke.GetWindowThreadProcessId(currentHWnd);
+ var currentHWnd = PInvoke.GetForegroundWindow();
+ var currentWindowThreadID = PInvoke.GetWindowThreadProcessId(currentHWnd);
- var hkl = PInvoke.GetKeyboardLayout(currentWindowThreadID);
- var lScanCode = PInvoke.MapVirtualKeyEx(vkCode, 0, hkl);
+ var hkl = PInvoke.GetKeyboardLayout(currentWindowThreadID);
+ var lScanCode = PInvoke.MapVirtualKeyEx(vkCode, 0, hkl);
- var span = stackalloc char[5];
- var relevantKeyCountInBuffer = PInvoke.ToUnicodeEx(vkCode, lScanCode, _keyState.Memory.Span, new PWSTR(span), 5, 0, hkl);
- return relevantKeyCountInBuffer switch
- {
- -1 or 0 => string.Empty,
- 1 => span[0].ToString(),
- 2 or _ => new string(span, 0, 2),
- };
- }
-
- private static uint CountBits(uint v)
+ var span = stackalloc char[5];
+ var relevantKeyCountInBuffer = PInvoke.ToUnicodeEx(vkCode, lScanCode, _keyState.Memory.Span, new PWSTR(span), 5, 0, hkl);
+ return relevantKeyCountInBuffer switch
{
- // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
- v = v - ((v >> 1) & 0x55555555); // reuse input as temporary
- v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp
- return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
- }
+ -1 or 0 => string.Empty,
+ 1 => span[0].ToString(),
+ 2 or _ => new string(span, 0, 2),
+ };
+ }
- private static int AddKeysToArray(uint keys, int offset, Keys[] pressedKeys, int index)
- {
- for (var i = 0; i < 32; i++)
- {
- if ((keys & (1 << i)) != 0)
- pressedKeys[index++] = (Keys) (offset + i);
- }
- return index;
- }
+ private static uint CountBits(uint v)
+ {
+ // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
+ v = v - ((v >> 1) & 0x55555555); // reuse input as temporary
+ v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp
+ return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
+ }
- public void Dispose()
+ private static int AddKeysToArray(uint keys, int offset, Keys[] pressedKeys, int index)
+ {
+ for (var i = 0; i < 32; i++)
{
- _keyState?.Dispose();
+ if ((keys & (1 << i)) != 0)
+ pressedKeys[index++] = (Keys) (offset + i);
}
+ return index;
+ }
+
+ public void Dispose()
+ {
+ _keyState?.Dispose();
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/Input/Keys.cs b/src/Bannerlord.LauncherEx/Helpers/Input/Keys.cs
index 4260c33..fab8e4b 100644
--- a/src/Bannerlord.LauncherEx/Helpers/Input/Keys.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/Input/Keys.cs
@@ -1,646 +1,645 @@
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+internal enum Keys
{
- internal enum Keys
- {
- ///
- /// Reserved.
- ///
- None = 0,
- ///
- /// BACKSPACE key.
- ///
- Back = 8,
- ///
- /// TAB key.
- ///
- Tab = 9,
- ///
- /// ENTER key.
- ///
- Enter = 13,
- ///
- /// CAPS LOCK key.
- ///
- CapsLock = 20,
- ///
- /// ESC key.
- ///
- Escape = 27,
- ///
- /// SPACEBAR key.
- ///
- Space = 32,
- ///
- /// PAGE UP key.
- ///
- PageUp = 33,
- ///
- /// PAGE DOWN key.
- ///
- PageDown = 34,
- ///
- /// END key.
- ///
- End = 35,
- ///
- /// HOME key.
- ///
- Home = 36,
- ///
- /// LEFT ARROW key.
- ///
- Left = 37,
- ///
- /// UP ARROW key.
- ///
- Up = 38,
- ///
- /// RIGHT ARROW key.
- ///
- Right = 39,
- ///
- /// DOWN ARROW key.
- ///
- Down = 40,
- ///
- /// SELECT key.
- ///
- Select = 41,
- ///
- /// PRINT key.
- ///
- Print = 42,
- ///
- /// EXECUTE key.
- ///
- Execute = 43,
- ///
- /// PRINT SCREEN key.
- ///
- PrintScreen = 44,
- ///
- /// INS key.
- ///
- Insert = 45,
- ///
- /// DEL key.
- ///
- Delete = 46,
- ///
- /// HELP key.
- ///
- Help = 47,
- ///
- /// Used for miscellaneous characters; it can vary by keyboard.
- ///
- D0 = 48,
- ///
- /// Used for miscellaneous characters; it can vary by keyboard.
- ///
- D1 = 49,
- ///
- /// Used for miscellaneous characters; it can vary by keyboard.
- ///
- D2 = 50,
- ///
- /// Used for miscellaneous characters; it can vary by keyboard.
- ///
- D3 = 51,
- ///
- /// Used for miscellaneous characters; it can vary by keyboard.
- ///
- D4 = 52,
- ///
- /// Used for miscellaneous characters; it can vary by keyboard.
- ///
- D5 = 53,
- ///
- /// Used for miscellaneous characters; it can vary by keyboard.
- ///
- D6 = 54,
- ///
- /// Used for miscellaneous characters; it can vary by keyboard.
- ///
- D7 = 55,
- ///
- /// Used for miscellaneous characters; it can vary by keyboard.
- ///
- D8 = 56,
- ///
- /// Used for miscellaneous characters; it can vary by keyboard.
- ///
- D9 = 57,
- ///
- /// A key.
- ///
- A = 65,
- ///
- /// B key.
- ///
- B = 66,
- ///
- /// C key.
- ///
- C = 67,
- ///
- /// D key.
- ///
- D = 68,
- ///
- /// E key.
- ///
- E = 69,
- ///
- /// F key.
- ///
- F = 70,
- ///
- /// G key.
- ///
- G = 71,
- ///
- /// H key.
- ///
- H = 72,
- ///
- /// I key.
- ///
- I = 73,
- ///
- /// J key.
- ///
- J = 74,
- ///
- /// K key.
- ///
- K = 75,
- ///
- /// L key.
- ///
- L = 76,
- ///
- /// M key.
- ///
- M = 77,
- ///
- /// N key.
- ///
- N = 78,
- ///
- /// O key.
- ///
- O = 79,
- ///
- /// P key.
- ///
- P = 80,
- ///
- /// Q key.
- ///
- Q = 81,
- ///
- /// R key.
- ///
- R = 82,
- ///
- /// S key.
- ///
- S = 83,
- ///
- /// T key.
- ///
- T = 84,
- ///
- /// U key.
- ///
- U = 85,
- ///
- /// V key.
- ///
- V = 86,
- ///
- /// W key.
- ///
- W = 87,
- ///
- /// X key.
- ///
- X = 88,
- ///
- /// Y key.
- ///
- Y = 89,
- ///
- /// Z key.
- ///
- Z = 90,
- ///
- /// Left Windows key.
- ///
- LeftWindows = 91,
- ///
- /// Right Windows key.
- ///
- RightWindows = 92,
- ///
- /// Applications key.
- ///
- Apps = 93,
- ///
- /// Computer Sleep key.
- ///
- Sleep = 95,
- ///
- /// Numeric keypad 0 key.
- ///
- NumPad0 = 96,
- ///
- /// Numeric keypad 1 key.
- ///
- NumPad1 = 97,
- ///
- /// Numeric keypad 2 key.
- ///
- NumPad2 = 98,
- ///
- /// Numeric keypad 3 key.
- ///
- NumPad3 = 99,
- ///
- /// Numeric keypad 4 key.
- ///
- NumPad4 = 100,
- ///
- /// Numeric keypad 5 key.
- ///
- NumPad5 = 101,
- ///
- /// Numeric keypad 6 key.
- ///
- NumPad6 = 102,
- ///
- /// Numeric keypad 7 key.
- ///
- NumPad7 = 103,
- ///
- /// Numeric keypad 8 key.
- ///
- NumPad8 = 104,
- ///
- /// Numeric keypad 9 key.
- ///
- NumPad9 = 105,
- ///
- /// Multiply key.
- ///
- Multiply = 106,
- ///
- /// Add key.
- ///
- Add = 107,
- ///
- /// Separator key.
- ///
- Separator = 108,
- ///
- /// Subtract key.
- ///
- Subtract = 109,
- ///
- /// Decimal key.
- ///
- Decimal = 110,
- ///
- /// Divide key.
- ///
- Divide = 111,
- ///
- /// F1 key.
- ///
- F1 = 112,
- ///
- /// F2 key.
- ///
- F2 = 113,
- ///
- /// F3 key.
- ///
- F3 = 114,
- ///
- /// F4 key.
- ///
- F4 = 115,
- ///
- /// F5 key.
- ///
- F5 = 116,
- ///
- /// F6 key.
- ///
- F6 = 117,
- ///
- /// F7 key.
- ///
- F7 = 118,
- ///
- /// F8 key.
- ///
- F8 = 119,
- ///
- /// F9 key.
- ///
- F9 = 120,
- ///
- /// F10 key.
- ///
- F10 = 121,
- ///
- /// F11 key.
- ///
- F11 = 122,
- ///
- /// F12 key.
- ///
- F12 = 123,
- ///
- /// F13 key.
- ///
- F13 = 124,
- ///
- /// F14 key.
- ///
- F14 = 125,
- ///
- /// F15 key.
- ///
- F15 = 126,
- ///
- /// F16 key.
- ///
- F16 = 127,
- ///
- /// F17 key.
- ///
- F17 = 128,
- ///
- /// F18 key.
- ///
- F18 = 129,
- ///
- /// F19 key.
- ///
- F19 = 130,
- ///
- /// F20 key.
- ///
- F20 = 131,
- ///
- /// F21 key.
- ///
- F21 = 132,
- ///
- /// F22 key.
- ///
- F22 = 133,
- ///
- /// F23 key.
- ///
- F23 = 134,
- ///
- /// F24 key.
- ///
- F24 = 135,
- ///
- /// NUM LOCK key.
- ///
- NumLock = 144,
- ///
- /// SCROLL LOCK key.
- ///
- Scroll = 145,
- ///
- /// Left SHIFT key.
- ///
- LeftShift = 160,
- ///
- /// Right SHIFT key.
- ///
- RightShift = 161,
- ///
- /// Left CONTROL key.
- ///
- LeftControl = 162,
- ///
- /// Right CONTROL key.
- ///
- RightControl = 163,
- ///
- /// Left ALT key.
- ///
- LeftAlt = 164,
- ///
- /// Right ALT key.
- ///
- RightAlt = 165,
- ///
- /// Browser Back key.
- ///
- BrowserBack = 166,
- ///
- /// Browser Forward key.
- ///
- BrowserForward = 167,
- ///
- /// Browser Refresh key.
- ///
- BrowserRefresh = 168,
- ///
- /// Browser Stop key.
- ///
- BrowserStop = 169,
- ///
- /// Browser Search key.
- ///
- BrowserSearch = 170,
- ///
- /// Browser Favorites key.
- ///
- BrowserFavorites = 171,
- ///
- /// Browser Start and Home key.
- ///
- BrowserHome = 172,
- ///
- /// Volume Mute key.
- ///
- VolumeMute = 173,
- ///
- /// Volume Down key.
- ///
- VolumeDown = 174,
- ///
- /// Volume Up key.
- ///
- VolumeUp = 175,
- ///
- /// Next Track key.
- ///
- MediaNextTrack = 176,
- ///
- /// Previous Track key.
- ///
- MediaPreviousTrack = 177,
- ///
- /// Stop Media key.
- ///
- MediaStop = 178,
- ///
- /// Play/Pause Media key.
- ///
- MediaPlayPause = 179,
- ///
- /// Start Mail key.
- ///
- LaunchMail = 180,
- ///
- /// Select Media key.
- ///
- SelectMedia = 181,
- ///
- /// Start Application 1 key.
- ///
- LaunchApplication1 = 182,
- ///
- /// Start Application 2 key.
- ///
- LaunchApplication2 = 183,
- ///
- /// The OEM Semicolon key on a US standard keyboard.
- ///
- OemSemicolon = 186,
- ///
- /// For any country/region, the '+' key.
- ///
- OemPlus = 187,
- ///
- /// For any country/region, the ',' key.
- ///
- OemComma = 188,
- ///
- /// For any country/region, the '-' key.
- ///
- OemMinus = 189,
- ///
- /// For any country/region, the '.' key.
- ///
- OemPeriod = 190,
- ///
- /// The OEM question mark key on a US standard keyboard.
- ///
- OemQuestion = 191,
- ///
- /// The OEM tilde key on a US standard keyboard.
- ///
- OemTilde = 192,
- ///
- /// The OEM open bracket key on a US standard keyboard.
- ///
- OemOpenBrackets = 219,
- ///
- /// The OEM pipe key on a US standard keyboard.
- ///
- OemPipe = 220,
- ///
- /// The OEM close bracket key on a US standard keyboard.
- ///
- OemCloseBrackets = 221,
- ///
- /// The OEM singled/double quote key on a US standard keyboard.
- ///
- OemQuotes = 222,
- ///
- /// Used for miscellaneous characters; it can vary by keyboard.
- ///
- Oem8 = 223,
- ///
- /// The OEM angle bracket or backslash key on the RT 102 key keyboard.
- ///
- OemBackslash = 226,
- ///
- /// IME PROCESS key.
- ///
- ProcessKey = 229,
- ///
- /// Attn key.
- ///
- Attn = 246,
- ///
- /// CrSel key.
- ///
- Crsel = 247,
- ///
- /// ExSel key.
- ///
- Exsel = 248,
- ///
- /// Erase EOF key.
- ///
- EraseEof = 249,
- ///
- /// Play key.
- ///
- Play = 250,
- ///
- /// Zoom key.
- ///
- Zoom = 251,
- ///
- /// PA1 key.
- ///
- Pa1 = 253,
- ///
- /// CLEAR key.
- ///
- OemClear = 254,
- ///
- /// Green ChatPad key.
- ///
- ChatPadGreen = 0xCA,
- ///
- /// Orange ChatPad key.
- ///
- ChatPadOrange = 0xCB,
- ///
- /// PAUSE key.
- ///
- Pause = 0x13,
- ///
- /// IME Convert key.
- ///
- ImeConvert = 0x1c,
- ///
- /// IME NoConvert key.
- ///
- ImeNoConvert = 0x1d,
- ///
- /// Kana key on Japanese keyboards.
- ///
- Kana = 0x15,
- ///
- /// Kanji key on Japanese keyboards.
- ///
- Kanji = 0x19,
- ///
- /// OEM Auto key.
- ///
- OemAuto = 0xf3,
- ///
- /// OEM Copy key.
- ///
- OemCopy = 0xf2,
- ///
- /// OEM Enlarge Window key.
- ///
- OemEnlW = 0xf4
- }
+ ///
+ /// Reserved.
+ ///
+ None = 0,
+ ///
+ /// BACKSPACE key.
+ ///
+ Back = 8,
+ ///
+ /// TAB key.
+ ///
+ Tab = 9,
+ ///
+ /// ENTER key.
+ ///
+ Enter = 13,
+ ///
+ /// CAPS LOCK key.
+ ///
+ CapsLock = 20,
+ ///
+ /// ESC key.
+ ///
+ Escape = 27,
+ ///
+ /// SPACEBAR key.
+ ///
+ Space = 32,
+ ///
+ /// PAGE UP key.
+ ///
+ PageUp = 33,
+ ///
+ /// PAGE DOWN key.
+ ///
+ PageDown = 34,
+ ///
+ /// END key.
+ ///
+ End = 35,
+ ///
+ /// HOME key.
+ ///
+ Home = 36,
+ ///
+ /// LEFT ARROW key.
+ ///
+ Left = 37,
+ ///
+ /// UP ARROW key.
+ ///
+ Up = 38,
+ ///
+ /// RIGHT ARROW key.
+ ///
+ Right = 39,
+ ///
+ /// DOWN ARROW key.
+ ///
+ Down = 40,
+ ///
+ /// SELECT key.
+ ///
+ Select = 41,
+ ///
+ /// PRINT key.
+ ///
+ Print = 42,
+ ///
+ /// EXECUTE key.
+ ///
+ Execute = 43,
+ ///
+ /// PRINT SCREEN key.
+ ///
+ PrintScreen = 44,
+ ///
+ /// INS key.
+ ///
+ Insert = 45,
+ ///
+ /// DEL key.
+ ///
+ Delete = 46,
+ ///
+ /// HELP key.
+ ///
+ Help = 47,
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ D0 = 48,
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ D1 = 49,
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ D2 = 50,
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ D3 = 51,
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ D4 = 52,
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ D5 = 53,
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ D6 = 54,
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ D7 = 55,
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ D8 = 56,
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ D9 = 57,
+ ///
+ /// A key.
+ ///
+ A = 65,
+ ///
+ /// B key.
+ ///
+ B = 66,
+ ///
+ /// C key.
+ ///
+ C = 67,
+ ///
+ /// D key.
+ ///
+ D = 68,
+ ///
+ /// E key.
+ ///
+ E = 69,
+ ///
+ /// F key.
+ ///
+ F = 70,
+ ///
+ /// G key.
+ ///
+ G = 71,
+ ///
+ /// H key.
+ ///
+ H = 72,
+ ///
+ /// I key.
+ ///
+ I = 73,
+ ///
+ /// J key.
+ ///
+ J = 74,
+ ///
+ /// K key.
+ ///
+ K = 75,
+ ///
+ /// L key.
+ ///
+ L = 76,
+ ///
+ /// M key.
+ ///
+ M = 77,
+ ///
+ /// N key.
+ ///
+ N = 78,
+ ///
+ /// O key.
+ ///
+ O = 79,
+ ///
+ /// P key.
+ ///
+ P = 80,
+ ///
+ /// Q key.
+ ///
+ Q = 81,
+ ///
+ /// R key.
+ ///
+ R = 82,
+ ///
+ /// S key.
+ ///
+ S = 83,
+ ///
+ /// T key.
+ ///
+ T = 84,
+ ///
+ /// U key.
+ ///
+ U = 85,
+ ///
+ /// V key.
+ ///
+ V = 86,
+ ///
+ /// W key.
+ ///
+ W = 87,
+ ///
+ /// X key.
+ ///
+ X = 88,
+ ///
+ /// Y key.
+ ///
+ Y = 89,
+ ///
+ /// Z key.
+ ///
+ Z = 90,
+ ///
+ /// Left Windows key.
+ ///
+ LeftWindows = 91,
+ ///
+ /// Right Windows key.
+ ///
+ RightWindows = 92,
+ ///
+ /// Applications key.
+ ///
+ Apps = 93,
+ ///
+ /// Computer Sleep key.
+ ///
+ Sleep = 95,
+ ///
+ /// Numeric keypad 0 key.
+ ///
+ NumPad0 = 96,
+ ///
+ /// Numeric keypad 1 key.
+ ///
+ NumPad1 = 97,
+ ///
+ /// Numeric keypad 2 key.
+ ///
+ NumPad2 = 98,
+ ///
+ /// Numeric keypad 3 key.
+ ///
+ NumPad3 = 99,
+ ///
+ /// Numeric keypad 4 key.
+ ///
+ NumPad4 = 100,
+ ///
+ /// Numeric keypad 5 key.
+ ///
+ NumPad5 = 101,
+ ///
+ /// Numeric keypad 6 key.
+ ///
+ NumPad6 = 102,
+ ///
+ /// Numeric keypad 7 key.
+ ///
+ NumPad7 = 103,
+ ///
+ /// Numeric keypad 8 key.
+ ///
+ NumPad8 = 104,
+ ///
+ /// Numeric keypad 9 key.
+ ///
+ NumPad9 = 105,
+ ///
+ /// Multiply key.
+ ///
+ Multiply = 106,
+ ///
+ /// Add key.
+ ///
+ Add = 107,
+ ///
+ /// Separator key.
+ ///
+ Separator = 108,
+ ///
+ /// Subtract key.
+ ///
+ Subtract = 109,
+ ///
+ /// Decimal key.
+ ///
+ Decimal = 110,
+ ///
+ /// Divide key.
+ ///
+ Divide = 111,
+ ///
+ /// F1 key.
+ ///
+ F1 = 112,
+ ///
+ /// F2 key.
+ ///
+ F2 = 113,
+ ///
+ /// F3 key.
+ ///
+ F3 = 114,
+ ///
+ /// F4 key.
+ ///
+ F4 = 115,
+ ///
+ /// F5 key.
+ ///
+ F5 = 116,
+ ///
+ /// F6 key.
+ ///
+ F6 = 117,
+ ///
+ /// F7 key.
+ ///
+ F7 = 118,
+ ///
+ /// F8 key.
+ ///
+ F8 = 119,
+ ///
+ /// F9 key.
+ ///
+ F9 = 120,
+ ///
+ /// F10 key.
+ ///
+ F10 = 121,
+ ///
+ /// F11 key.
+ ///
+ F11 = 122,
+ ///
+ /// F12 key.
+ ///
+ F12 = 123,
+ ///
+ /// F13 key.
+ ///
+ F13 = 124,
+ ///
+ /// F14 key.
+ ///
+ F14 = 125,
+ ///
+ /// F15 key.
+ ///
+ F15 = 126,
+ ///
+ /// F16 key.
+ ///
+ F16 = 127,
+ ///
+ /// F17 key.
+ ///
+ F17 = 128,
+ ///
+ /// F18 key.
+ ///
+ F18 = 129,
+ ///
+ /// F19 key.
+ ///
+ F19 = 130,
+ ///
+ /// F20 key.
+ ///
+ F20 = 131,
+ ///
+ /// F21 key.
+ ///
+ F21 = 132,
+ ///
+ /// F22 key.
+ ///
+ F22 = 133,
+ ///
+ /// F23 key.
+ ///
+ F23 = 134,
+ ///
+ /// F24 key.
+ ///
+ F24 = 135,
+ ///
+ /// NUM LOCK key.
+ ///
+ NumLock = 144,
+ ///
+ /// SCROLL LOCK key.
+ ///
+ Scroll = 145,
+ ///
+ /// Left SHIFT key.
+ ///
+ LeftShift = 160,
+ ///
+ /// Right SHIFT key.
+ ///
+ RightShift = 161,
+ ///
+ /// Left CONTROL key.
+ ///
+ LeftControl = 162,
+ ///
+ /// Right CONTROL key.
+ ///
+ RightControl = 163,
+ ///
+ /// Left ALT key.
+ ///
+ LeftAlt = 164,
+ ///
+ /// Right ALT key.
+ ///
+ RightAlt = 165,
+ ///
+ /// Browser Back key.
+ ///
+ BrowserBack = 166,
+ ///
+ /// Browser Forward key.
+ ///
+ BrowserForward = 167,
+ ///
+ /// Browser Refresh key.
+ ///
+ BrowserRefresh = 168,
+ ///
+ /// Browser Stop key.
+ ///
+ BrowserStop = 169,
+ ///
+ /// Browser Search key.
+ ///
+ BrowserSearch = 170,
+ ///
+ /// Browser Favorites key.
+ ///
+ BrowserFavorites = 171,
+ ///
+ /// Browser Start and Home key.
+ ///
+ BrowserHome = 172,
+ ///
+ /// Volume Mute key.
+ ///
+ VolumeMute = 173,
+ ///
+ /// Volume Down key.
+ ///
+ VolumeDown = 174,
+ ///
+ /// Volume Up key.
+ ///
+ VolumeUp = 175,
+ ///
+ /// Next Track key.
+ ///
+ MediaNextTrack = 176,
+ ///
+ /// Previous Track key.
+ ///
+ MediaPreviousTrack = 177,
+ ///
+ /// Stop Media key.
+ ///
+ MediaStop = 178,
+ ///
+ /// Play/Pause Media key.
+ ///
+ MediaPlayPause = 179,
+ ///
+ /// Start Mail key.
+ ///
+ LaunchMail = 180,
+ ///
+ /// Select Media key.
+ ///
+ SelectMedia = 181,
+ ///
+ /// Start Application 1 key.
+ ///
+ LaunchApplication1 = 182,
+ ///
+ /// Start Application 2 key.
+ ///
+ LaunchApplication2 = 183,
+ ///
+ /// The OEM Semicolon key on a US standard keyboard.
+ ///
+ OemSemicolon = 186,
+ ///
+ /// For any country/region, the '+' key.
+ ///
+ OemPlus = 187,
+ ///
+ /// For any country/region, the ',' key.
+ ///
+ OemComma = 188,
+ ///
+ /// For any country/region, the '-' key.
+ ///
+ OemMinus = 189,
+ ///
+ /// For any country/region, the '.' key.
+ ///
+ OemPeriod = 190,
+ ///
+ /// The OEM question mark key on a US standard keyboard.
+ ///
+ OemQuestion = 191,
+ ///
+ /// The OEM tilde key on a US standard keyboard.
+ ///
+ OemTilde = 192,
+ ///
+ /// The OEM open bracket key on a US standard keyboard.
+ ///
+ OemOpenBrackets = 219,
+ ///
+ /// The OEM pipe key on a US standard keyboard.
+ ///
+ OemPipe = 220,
+ ///
+ /// The OEM close bracket key on a US standard keyboard.
+ ///
+ OemCloseBrackets = 221,
+ ///
+ /// The OEM singled/double quote key on a US standard keyboard.
+ ///
+ OemQuotes = 222,
+ ///
+ /// Used for miscellaneous characters; it can vary by keyboard.
+ ///
+ Oem8 = 223,
+ ///
+ /// The OEM angle bracket or backslash key on the RT 102 key keyboard.
+ ///
+ OemBackslash = 226,
+ ///
+ /// IME PROCESS key.
+ ///
+ ProcessKey = 229,
+ ///
+ /// Attn key.
+ ///
+ Attn = 246,
+ ///
+ /// CrSel key.
+ ///
+ Crsel = 247,
+ ///
+ /// ExSel key.
+ ///
+ Exsel = 248,
+ ///
+ /// Erase EOF key.
+ ///
+ EraseEof = 249,
+ ///
+ /// Play key.
+ ///
+ Play = 250,
+ ///
+ /// Zoom key.
+ ///
+ Zoom = 251,
+ ///
+ /// PA1 key.
+ ///
+ Pa1 = 253,
+ ///
+ /// CLEAR key.
+ ///
+ OemClear = 254,
+ ///
+ /// Green ChatPad key.
+ ///
+ ChatPadGreen = 0xCA,
+ ///
+ /// Orange ChatPad key.
+ ///
+ ChatPadOrange = 0xCB,
+ ///
+ /// PAUSE key.
+ ///
+ Pause = 0x13,
+ ///
+ /// IME Convert key.
+ ///
+ ImeConvert = 0x1c,
+ ///
+ /// IME NoConvert key.
+ ///
+ ImeNoConvert = 0x1d,
+ ///
+ /// Kana key on Japanese keyboards.
+ ///
+ Kana = 0x15,
+ ///
+ /// Kanji key on Japanese keyboards.
+ ///
+ Kanji = 0x19,
+ ///
+ /// OEM Auto key.
+ ///
+ OemAuto = 0xf3,
+ ///
+ /// OEM Copy key.
+ ///
+ OemCopy = 0xf2,
+ ///
+ /// OEM Enlarge Window key.
+ ///
+ OemEnlW = 0xf4
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/Integrations.cs b/src/Bannerlord.LauncherEx/Helpers/Integrations.cs
index 678dc7e..3b37284 100644
--- a/src/Bannerlord.LauncherEx/Helpers/Integrations.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/Integrations.cs
@@ -3,20 +3,19 @@
using System.Diagnostics;
using System.IO;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+public static class Integrations
{
- public static class Integrations
- {
- public static bool IsModOrganizer2 { get; }
- public static string? ModOrganizer2Path { get; }
+ public static bool IsModOrganizer2 { get; }
+ public static string? ModOrganizer2Path { get; }
- static Integrations()
+ static Integrations()
+ {
+ if (Process.GetCurrentProcess().ParentProcess() is { MainModule.FileVersionInfo.OriginalFilename: "ModOrganizer.exe", MainModule.FileName: { } path })
{
- if (Process.GetCurrentProcess().ParentProcess() is { MainModule.FileVersionInfo.OriginalFilename: "ModOrganizer.exe", MainModule.FileName: { } path })
- {
- IsModOrganizer2 = true;
- ModOrganizer2Path = Path.GetDirectoryName(path);
- }
+ IsModOrganizer2 = true;
+ ModOrganizer2Path = Path.GetDirectoryName(path);
}
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/ModuleChecker.cs b/src/Bannerlord.LauncherEx/Helpers/ModuleChecker.cs
index 55b9601..98e8dec 100644
--- a/src/Bannerlord.LauncherEx/Helpers/ModuleChecker.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/ModuleChecker.cs
@@ -1,5 +1,4 @@
using Bannerlord.BUTR.Shared.Helpers;
-using Bannerlord.LauncherManager.Extensions;
using Bannerlord.LauncherManager.Models;
using Bannerlord.ModuleManager;
@@ -7,57 +6,49 @@
using Mono.Cecil.Rocks;
using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
using TaleWorlds.Library;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+// TODO: NativeAOT won't cover that?
+internal static class ModuleChecker
{
- // TODO: NativeAOT won't cover that?
- internal static class ModuleChecker
+ public static bool IsObfuscated(ModuleInfoExtendedWithMetadata moduleInfoExtended)
{
- private static readonly HashSet MainModules = ModuleInfoHelper.GetPhysicalModules().Select(x => x.Id).ToHashSet();
- private static readonly HashSet ExternalModules = ModuleInfoHelper.GetPlatformModules().Select(x => x.Id).ToHashSet();
-
- public static bool IsInstalledInMainAndExternalModuleDirectory(ModuleInfoExtendedWithPath moduleInfoExtended) =>
- MainModules.Contains(moduleInfoExtended.Id) && ExternalModules.Contains(moduleInfoExtended.Id);
+ static bool CanBeLoaded(SubModuleInfoExtended x) =>
+ ModuleInfoHelper.CheckIfSubModuleCanBeLoaded(x, ApplicationPlatform.CurrentPlatform, ApplicationPlatform.CurrentRuntimeLibrary, TaleWorlds.MountAndBlade.DedicatedServerType.None, false);
- public static bool IsObfuscated(ModuleInfoExtendedWithPath moduleInfoExtended)
+ foreach (var subModule in moduleInfoExtended.SubModules.Where(CanBeLoaded))
{
- static bool CanBeLoaded(SubModuleInfoExtended x) =>
- ModuleInfoHelper.CheckIfSubModuleCanBeLoaded(x, ApplicationPlatform.CurrentPlatform, ApplicationPlatform.CurrentRuntimeLibrary, TaleWorlds.MountAndBlade.DedicatedServerType.None, false);
+ var asm = Path.GetFullPath(Path.Combine(moduleInfoExtended.Path, "bin", "Win64_Shipping_Client", subModule.DLLName));
+ if (!File.Exists(asm)) continue;
- foreach (var subModule in moduleInfoExtended.SubModules.Where(CanBeLoaded))
+ try
{
- var asm = Path.GetFullPath(Path.Combine(moduleInfoExtended.Path, "bin", "Win64_Shipping_Client", subModule.DLLName));
- if (!File.Exists(asm)) continue;
+ using var moduleDefinition = ModuleDefinition.ReadModule(asm);
- try
+ var hasObfuscationAttributeUsed = moduleDefinition.GetCustomAttributes().Any(x => x.Constructor.DeclaringType.Name switch
{
- using var moduleDefinition = ModuleDefinition.ReadModule(asm);
-
- var hasObfuscationAttributeUsed = moduleDefinition.GetCustomAttributes().Any(x => x.Constructor.DeclaringType.Name switch
- {
- "ConfusedByAttribute" => true,
- _ => false
- });
- var hasObfuscationAttributeDeclared = moduleDefinition.Types.Any(x => x.Name switch
- {
- "ConfusedByAttribute" => true,
- _ => false
- });
- // Every module should have a module initializer. If it's missing, someone is hiding it
- var hasModuleInitializer = moduleDefinition.GetAllTypes().Any(x => x.Name == "");
-
- return hasObfuscationAttributeUsed || hasObfuscationAttributeDeclared || !hasModuleInitializer;
- }
- // Failing to read the metadata is a direct sign of metadata manipulation
- catch (Exception) { return true; }
- }
+ "ConfusedByAttribute" => true,
+ _ => false
+ });
+ var hasObfuscationAttributeDeclared = moduleDefinition.Types.Any(x => x.Name switch
+ {
+ "ConfusedByAttribute" => true,
+ _ => false
+ });
+ // Every module should have a module initializer. If it's missing, someone is hiding it
+ var hasModuleInitializer = moduleDefinition.GetAllTypes().Any(x => x.Name == "");
- return false;
+ return hasObfuscationAttributeUsed || hasObfuscationAttributeDeclared || !hasModuleInitializer;
+ }
+ // Failing to read the metadata is a direct sign of metadata manipulation
+ catch (Exception) { return true; }
}
+
+ return false;
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/TypeWrapper.cs b/src/Bannerlord.LauncherEx/Helpers/TypeWrapper.cs
index 9e4f8c3..9e9bf1c 100644
--- a/src/Bannerlord.LauncherEx/Helpers/TypeWrapper.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/TypeWrapper.cs
@@ -2,50 +2,49 @@
using System.Globalization;
using System.Reflection;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+internal class TypeWrapper : Type
{
- internal class TypeWrapper : Type
- {
- public override string Name { get; } = default!;
- public override Guid GUID { get; } = default!;
- public override Module Module { get; } = default!;
- public override Assembly Assembly { get; } = default!;
- public override string FullName { get; } = default!;
- public override string Namespace { get; } = default!;
- public override string AssemblyQualifiedName { get; } = default!;
- public override Type BaseType { get; } = default!;
- public override Type UnderlyingSystemType { get; } = default!;
+ public override string Name { get; } = default!;
+ public override Guid GUID { get; } = default!;
+ public override Module Module { get; } = default!;
+ public override Assembly Assembly { get; } = default!;
+ public override string FullName { get; } = default!;
+ public override string Namespace { get; } = default!;
+ public override string AssemblyQualifiedName { get; } = default!;
+ public override Type BaseType { get; } = default!;
+ public override Type UnderlyingSystemType { get; } = default!;
- public TypeWrapper(string location) => Assembly = new AssemblyWrapper(location);
+ public TypeWrapper(string location) => Assembly = new AssemblyWrapper(location);
- public override object[] GetCustomAttributes(bool inherit) => new object[] { };
- public override bool IsDefined(Type attributeType, bool inherit) => false;
- public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => new ConstructorInfo[] { };
- public override Type? GetInterface(string name, bool ignoreCase) => null;
- public override Type[] GetInterfaces() => new Type[] { };
- public override EventInfo? GetEvent(string name, BindingFlags bindingAttr) => null;
- public override EventInfo[] GetEvents(BindingFlags bindingAttr) => new EventInfo[] { };
- public override Type[] GetNestedTypes(BindingFlags bindingAttr) => new Type[] { };
- public override Type? GetNestedType(string name, BindingFlags bindingAttr) => null;
- public override Type? GetElementType() => null;
- protected override bool HasElementTypeImpl() => false;
- protected override PropertyInfo? GetPropertyImpl(string name, BindingFlags bindingAttr, Binder? binder, Type? returnType, Type[]? types, ParameterModifier[]? modifiers) => null;
- public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => new PropertyInfo[] { };
- protected override MethodInfo? GetMethodImpl(string name, BindingFlags bindingAttr, Binder? binder, CallingConventions callConvention, Type[]? types, ParameterModifier[]? modifiers) => null;
- public override MethodInfo[] GetMethods(BindingFlags bindingAttr) => new MethodInfo[] { };
- public override FieldInfo? GetField(string name, BindingFlags bindingAttr) => null;
- public override FieldInfo[] GetFields(BindingFlags bindingAttr) => new FieldInfo[] { };
- public override MemberInfo[] GetMembers(BindingFlags bindingAttr) => new MemberInfo[] { };
- protected override TypeAttributes GetAttributeFlagsImpl() => TypeAttributes.NotPublic;
- protected override bool IsArrayImpl() => false;
- protected override bool IsByRefImpl() => false;
- protected override bool IsPointerImpl() => false;
- protected override bool IsPrimitiveImpl() => false;
- protected override bool IsCOMObjectImpl() => false;
- public override object? InvokeMember(string name, BindingFlags invokeAttr, Binder? binder, object? target, object?[]? args, ParameterModifier[]? modifiers, CultureInfo? culture, string[]? namedParameters) => null;
- protected override ConstructorInfo? GetConstructorImpl(BindingFlags bindingAttr, Binder? binder, CallingConventions callConvention, Type[] types, ParameterModifier[]? modifiers) => null;
+ public override object[] GetCustomAttributes(bool inherit) => new object[] { };
+ public override bool IsDefined(Type attributeType, bool inherit) => false;
+ public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) => new ConstructorInfo[] { };
+ public override Type? GetInterface(string name, bool ignoreCase) => null;
+ public override Type[] GetInterfaces() => new Type[] { };
+ public override EventInfo? GetEvent(string name, BindingFlags bindingAttr) => null;
+ public override EventInfo[] GetEvents(BindingFlags bindingAttr) => new EventInfo[] { };
+ public override Type[] GetNestedTypes(BindingFlags bindingAttr) => new Type[] { };
+ public override Type? GetNestedType(string name, BindingFlags bindingAttr) => null;
+ public override Type? GetElementType() => null;
+ protected override bool HasElementTypeImpl() => false;
+ protected override PropertyInfo? GetPropertyImpl(string name, BindingFlags bindingAttr, Binder? binder, Type? returnType, Type[]? types, ParameterModifier[]? modifiers) => null;
+ public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) => new PropertyInfo[] { };
+ protected override MethodInfo? GetMethodImpl(string name, BindingFlags bindingAttr, Binder? binder, CallingConventions callConvention, Type[]? types, ParameterModifier[]? modifiers) => null;
+ public override MethodInfo[] GetMethods(BindingFlags bindingAttr) => new MethodInfo[] { };
+ public override FieldInfo? GetField(string name, BindingFlags bindingAttr) => null;
+ public override FieldInfo[] GetFields(BindingFlags bindingAttr) => new FieldInfo[] { };
+ public override MemberInfo[] GetMembers(BindingFlags bindingAttr) => new MemberInfo[] { };
+ protected override TypeAttributes GetAttributeFlagsImpl() => TypeAttributes.NotPublic;
+ protected override bool IsArrayImpl() => false;
+ protected override bool IsByRefImpl() => false;
+ protected override bool IsPointerImpl() => false;
+ protected override bool IsPrimitiveImpl() => false;
+ protected override bool IsCOMObjectImpl() => false;
+ public override object? InvokeMember(string name, BindingFlags invokeAttr, Binder? binder, object? target, object?[]? args, ParameterModifier[]? modifiers, CultureInfo? culture, string[]? namedParameters) => null;
+ protected override ConstructorInfo? GetConstructorImpl(BindingFlags bindingAttr, Binder? binder, CallingConventions callConvention, Type[] types, ParameterModifier[]? modifiers) => null;
- public override object[] GetCustomAttributes(Type attributeType, bool inherit) => new object[] { };
- }
+ public override object[] GetCustomAttributes(Type attributeType, bool inherit) => new object[] { };
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/UI/IRef.cs b/src/Bannerlord.LauncherEx/Helpers/UI/IRef.cs
index 6954d03..0f1416b 100644
--- a/src/Bannerlord.LauncherEx/Helpers/UI/IRef.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/UI/IRef.cs
@@ -3,161 +3,160 @@
using System.Reflection;
using System.Runtime.CompilerServices;
-namespace Bannerlord.LauncherEx.Helpers
-{
- ///
- /// https://github.com/Aragas/Bannerlord.MBOptionScreen/blob/dev/src/MCM/Abstractions/Ref/IRef.cs
- ///
- internal interface IRef : INotifyPropertyChanged
- {
- Type Type { get; }
- object? Value { get; set; }
- }
+namespace Bannerlord.LauncherEx.Helpers;
- ///
- /// https://github.com/Aragas/Bannerlord.MBOptionScreen/blob/dev/src/MCM/Abstractions/Ref/PropertyRef.cs
- ///
- internal sealed class PropertyRef : IRef, IEquatable
- {
- ///
- public event PropertyChangedEventHandler? PropertyChanged;
+///
+/// https://github.com/Aragas/Bannerlord.MBOptionScreen/blob/dev/src/MCM/Abstractions/Ref/IRef.cs
+///
+internal interface IRef : INotifyPropertyChanged
+{
+ Type Type { get; }
+ object? Value { get; set; }
+}
+
+///
+/// https://github.com/Aragas/Bannerlord.MBOptionScreen/blob/dev/src/MCM/Abstractions/Ref/PropertyRef.cs
+///
+internal sealed class PropertyRef : IRef, IEquatable
+{
+ ///
+ public event PropertyChangedEventHandler? PropertyChanged;
- public PropertyInfo PropertyInfo { get; }
- public object Instance { get; }
+ public PropertyInfo PropertyInfo { get; }
+ public object Instance { get; }
- ///
- public Type Type => PropertyInfo.PropertyType;
- ///
- public object? Value
+ ///
+ public Type Type => PropertyInfo.PropertyType;
+ ///
+ public object? Value
+ {
+ get => PropertyInfo.GetValue(Instance);
+ set
{
- get => PropertyInfo.GetValue(Instance);
- set
+ if (PropertyInfo.CanWrite)
{
- if (PropertyInfo.CanWrite)
- {
- PropertyInfo.SetValue(Instance, value);
- OnPropertyChanged();
- }
+ PropertyInfo.SetValue(Instance, value);
+ OnPropertyChanged();
}
}
+ }
- public PropertyRef(PropertyInfo propInfo, object instance)
- {
- PropertyInfo = propInfo;
- Instance = instance;
- }
+ public PropertyRef(PropertyInfo propInfo, object instance)
+ {
+ PropertyInfo = propInfo;
+ Instance = instance;
+ }
- private void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ private void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- public bool Equals(PropertyRef? other)
- {
- if (other is null) return false;
- if (ReferenceEquals(this, other)) return true;
- return PropertyInfo.Equals(other.PropertyInfo) && Instance.Equals(other.Instance);
- }
- ///
- public override bool Equals(object? obj)
- {
- if (obj is null) return false;
- if (ReferenceEquals(this, obj)) return true;
- if (obj.GetType() != GetType()) return false;
- return Equals((PropertyRef) obj);
- }
- ///
- public override int GetHashCode() => PropertyInfo.GetHashCode() ^ Instance.GetHashCode();
- public static bool operator ==(PropertyRef? left, PropertyRef? right) => Equals(left, right);
- public static bool operator !=(PropertyRef? left, PropertyRef? right) => !Equals(left, right);
+ public bool Equals(PropertyRef? other)
+ {
+ if (other is null) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return PropertyInfo.Equals(other.PropertyInfo) && Instance.Equals(other.Instance);
}
-
- internal sealed class StorageRef : IRef
+ ///
+ public override bool Equals(object? obj)
{
- public event PropertyChangedEventHandler? PropertyChanged;
+ if (obj is null) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((PropertyRef) obj);
+ }
+ ///
+ public override int GetHashCode() => PropertyInfo.GetHashCode() ^ Instance.GetHashCode();
+ public static bool operator ==(PropertyRef? left, PropertyRef? right) => Equals(left, right);
+ public static bool operator !=(PropertyRef? left, PropertyRef? right) => !Equals(left, right);
+}
+
+internal sealed class StorageRef : IRef
+{
+ public event PropertyChangedEventHandler? PropertyChanged;
- public Type Type { get; }
+ public Type Type { get; }
- private T? _value;
- public object? Value
+ private T? _value;
+ public object? Value
+ {
+ get => _value;
+ set
{
- get => _value;
- set
+ if (value is T val && !Equals(_value, val))
{
- if (value is T val && !Equals(_value, val))
- {
- _value = val;
- OnPropertyChanged();
- }
+ _value = val;
+ OnPropertyChanged();
}
}
-
- public StorageRef(T? value)
- {
- _value = value;
- Type = value?.GetType() ?? typeof(T);
- }
-
- private void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
- internal class ProxyRef : IRef, IEquatable>
+ public StorageRef(T? value)
{
- ///
- public event PropertyChangedEventHandler? PropertyChanged;
+ _value = value;
+ Type = value?.GetType() ?? typeof(T);
+ }
+
+ private void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+}
+
+internal class ProxyRef : IRef, IEquatable>
+{
+ ///
+ public event PropertyChangedEventHandler? PropertyChanged;
- private readonly Func _getter;
- private readonly Action? _setter;
+ private readonly Func _getter;
+ private readonly Action? _setter;
- ///
- public Type Type => typeof(T);
- ///
- public object? Value
+ ///
+ public Type Type => typeof(T);
+ ///
+ public object? Value
+ {
+ get => _getter();
+ set
{
- get => _getter();
- set
+ if (_setter is not null && value is T val)
{
- if (_setter is not null && value is T val)
- {
- _setter(val);
- OnPropertyChanged();
- }
+ _setter(val);
+ OnPropertyChanged();
}
}
+ }
- public ProxyRef(Func getter, Action? setter)
- {
- _getter = getter ?? throw new ArgumentNullException(nameof(getter));
- _setter = setter;
- }
+ public ProxyRef(Func getter, Action? setter)
+ {
+ _getter = getter ?? throw new ArgumentNullException(nameof(getter));
+ _setter = setter;
+ }
- protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- ///
- public bool Equals(ProxyRef? other)
- {
- if (other is null) return false;
- if (ReferenceEquals(this, other)) return true;
- return _getter.Equals(other._getter) && Equals(_setter, other._setter);
- }
- ///
- public override bool Equals(object? obj)
- {
- if (obj is null) return false;
- if (ReferenceEquals(this, obj)) return true;
- if (obj.GetType() != GetType()) return false;
- return Equals((ProxyRef) obj);
- }
- ///
- public override int GetHashCode()
- {
- var hash = 269;
- hash = (hash * 47) + _getter.GetHashCode();
- if (_setter is not null)
- hash = (hash * 47) + _setter.GetHashCode();
- return hash;
- }
- public static bool operator ==(ProxyRef? left, ProxyRef? right) => Equals(left, right);
- public static bool operator !=(ProxyRef? left, ProxyRef? right) => !Equals(left, right);
+ ///
+ public bool Equals(ProxyRef? other)
+ {
+ if (other is null) return false;
+ if (ReferenceEquals(this, other)) return true;
+ return _getter.Equals(other._getter) && Equals(_setter, other._setter);
+ }
+ ///
+ public override bool Equals(object? obj)
+ {
+ if (obj is null) return false;
+ if (ReferenceEquals(this, obj)) return true;
+ if (obj.GetType() != GetType()) return false;
+ return Equals((ProxyRef) obj);
+ }
+ ///
+ public override int GetHashCode()
+ {
+ var hash = 269;
+ hash = (hash * 47) + _getter.GetHashCode();
+ if (_setter is not null)
+ hash = (hash * 47) + _setter.GetHashCode();
+ return hash;
}
+ public static bool operator ==(ProxyRef? left, ProxyRef? right) => Equals(left, right);
+ public static bool operator !=(ProxyRef? left, ProxyRef? right) => !Equals(left, right);
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/UI/MixinManager.cs b/src/Bannerlord.LauncherEx/Helpers/UI/MixinManager.cs
index 5146602..b5ebdc9 100644
--- a/src/Bannerlord.LauncherEx/Helpers/UI/MixinManager.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/UI/MixinManager.cs
@@ -13,165 +13,164 @@
using TaleWorlds.Library;
using TaleWorlds.MountAndBlade.Launcher.Library;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
+internal class BUTRDataSourcePropertyAttribute : Attribute
{
- [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
- internal class BUTRDataSourcePropertyAttribute : Attribute
- {
- public string? OverrideName { get; set; }
- }
- [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
- internal class BUTRDataSourceMethodAttribute : Attribute
- {
- public string? OverrideName { get; set; }
- }
+ public string? OverrideName { get; set; }
+}
+[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
+internal class BUTRDataSourceMethodAttribute : Attribute
+{
+ public string? OverrideName { get; set; }
+}
- internal abstract class BUTRViewModel : ViewModel
+internal abstract class BUTRViewModel : ViewModel
+{
+ protected BUTRViewModel()
{
- protected BUTRViewModel()
+ var properties = GetType().GetProperties(AccessTools.all);
+ foreach (var propertyInfo in properties)
{
- var properties = GetType().GetProperties(AccessTools.all);
- foreach (var propertyInfo in properties)
+ if (propertyInfo.GetCustomAttribute() is { } attribute)
{
- if (propertyInfo.GetCustomAttribute() is { } attribute)
- {
- if (propertyInfo.GetMethod?.IsPrivate == true || propertyInfo.SetMethod?.IsPrivate == true) throw new Exception();
+ if (propertyInfo.GetMethod?.IsPrivate == true || propertyInfo.SetMethod?.IsPrivate == true) throw new Exception();
- this.AddProperty(attribute.OverrideName ?? propertyInfo.Name, propertyInfo);
- }
+ this.AddProperty(attribute.OverrideName ?? propertyInfo.Name, propertyInfo);
}
+ }
- var methods = GetType().GetMethods(AccessTools.all);
- foreach (var methodInfo in methods)
+ var methods = GetType().GetMethods(AccessTools.all);
+ foreach (var methodInfo in methods)
+ {
+ if (methodInfo.GetCustomAttribute() is { } attribute)
{
- if (methodInfo.GetCustomAttribute() is { } attribute)
- {
- if (methodInfo.IsPrivate) throw new Exception();
+ if (methodInfo.IsPrivate) throw new Exception();
- this.AddMethod(attribute.OverrideName ?? methodInfo.Name, methodInfo);
- }
+ this.AddMethod(attribute.OverrideName ?? methodInfo.Name, methodInfo);
}
}
+ }
- protected new bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null)
+ protected new bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null)
+ {
+ if (EqualityComparer.Default.Equals(field, value))
{
- if (EqualityComparer.Default.Equals(field, value))
- {
- return false;
- }
- field = value;
- OnPropertyChanged(propertyName);
- return true;
+ return false;
}
+ field = value;
+ OnPropertyChanged(propertyName);
+ return true;
}
+}
- internal abstract class ViewModelMixin
- where TViewModelMixin : ViewModelMixin
- where TViewModel : ViewModel
- {
- private readonly WeakReference _vm;
+internal abstract class ViewModelMixin
+ where TViewModelMixin : ViewModelMixin
+ where TViewModel : ViewModel
+{
+ private readonly WeakReference _vm;
- protected TViewModel? ViewModel => _vm.TryGetTarget(out var vm) ? vm : null;
+ protected TViewModel? ViewModel => _vm.TryGetTarget(out var vm) ? vm : null;
- public TViewModelMixin Mixin => (TViewModelMixin) this;
+ public TViewModelMixin Mixin => (TViewModelMixin) this;
- protected ViewModelMixin(TViewModel vm)
- {
- _vm = new WeakReference(vm);
+ protected ViewModelMixin(TViewModel vm)
+ {
+ _vm = new WeakReference(vm);
- SetVMProperty(nameof(Mixin), GetType().Name);
- foreach (var propertyInfo in GetType().GetProperties(AccessTools.all))
+ SetVMProperty(nameof(Mixin), GetType().Name);
+ foreach (var propertyInfo in GetType().GetProperties(AccessTools.all))
+ {
+ if (propertyInfo.GetCustomAttribute() is { } attribute)
{
- if (propertyInfo.GetCustomAttribute() is { } attribute)
- {
- if (propertyInfo.GetMethod?.IsPrivate == true || propertyInfo.SetMethod?.IsPrivate == true) throw new Exception();
-
- var wrappedPropertyInfo = new WrappedPropertyInfo(propertyInfo, this);
- vm.AddProperty(attribute.OverrideName ?? propertyInfo.Name, wrappedPropertyInfo);
- wrappedPropertyInfo.PropertyChanged += (_, e) => ViewModel?.OnPropertyChanged(e.PropertyName);
- }
+ if (propertyInfo.GetMethod?.IsPrivate == true || propertyInfo.SetMethod?.IsPrivate == true) throw new Exception();
+
+ var wrappedPropertyInfo = new WrappedPropertyInfo(propertyInfo, this);
+ vm.AddProperty(attribute.OverrideName ?? propertyInfo.Name, wrappedPropertyInfo);
+ wrappedPropertyInfo.PropertyChanged += (_, e) => ViewModel?.OnPropertyChanged(e.PropertyName);
}
- foreach (var methodInfo in GetType().GetMethods(AccessTools.all))
+ }
+ foreach (var methodInfo in GetType().GetMethods(AccessTools.all))
+ {
+ if (methodInfo.GetCustomAttribute() is { } attribute)
{
- if (methodInfo.GetCustomAttribute() is { } attribute)
- {
- if (methodInfo.IsPrivate) throw new Exception();
+ if (methodInfo.IsPrivate) throw new Exception();
- var wrappedMethodInfo = new WrappedMethodInfo(methodInfo, this);
- vm.AddMethod(attribute.OverrideName ?? methodInfo.Name, wrappedMethodInfo);
- }
+ var wrappedMethodInfo = new WrappedMethodInfo(methodInfo, this);
+ vm.AddMethod(attribute.OverrideName ?? methodInfo.Name, wrappedMethodInfo);
}
}
+ }
- protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
- {
- ViewModel?.OnPropertyChanged(propertyName);
- }
+ protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
+ {
+ ViewModel?.OnPropertyChanged(propertyName);
+ }
- protected void OnPropertyChangedWithValue(T value, [CallerMemberName] string? propertyName = null) where T : class
- {
+ protected void OnPropertyChangedWithValue(T value, [CallerMemberName] string? propertyName = null) where T : class
+ {
#if v100 || v101 || v102 || v103
ViewModel?.OnPropertyChangedWithValue((object) value, propertyName);
#elif v110 || v111
ViewModel?.OnPropertyChangedWithValue(value, propertyName);
#endif
- }
-
- protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null)
- {
- if (EqualityComparer.Default.Equals(field, value))
- {
- return false;
- }
- field = value;
- OnPropertyChanged(propertyName);
- return true;
- }
+ }
- protected void SetVMProperty(string property, string? overrideName = null)
+ protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null)
+ {
+ if (EqualityComparer.Default.Equals(field, value))
{
- var propertyInfo = new WrappedPropertyInfo(AccessTools2.Property(GetType(), property)!, this);
- ViewModel?.AddProperty(overrideName ?? property, propertyInfo);
- propertyInfo.PropertyChanged += (_, e) => ViewModel?.OnPropertyChanged(e.PropertyName);
+ return false;
}
+ field = value;
+ OnPropertyChanged(propertyName);
+ return true;
+ }
- protected void SetVMMethod(string method, string? overrideName = null)
- {
- var methodInfo = new WrappedMethodInfo(AccessTools2.Method(GetType(), method)!, this);
- ViewModel?.AddMethod(overrideName ?? method, methodInfo);
- }
+ protected void SetVMProperty(string property, string? overrideName = null)
+ {
+ var propertyInfo = new WrappedPropertyInfo(AccessTools2.Property(GetType(), property)!, this);
+ ViewModel?.AddProperty(overrideName ?? property, propertyInfo);
+ propertyInfo.PropertyChanged += (_, e) => ViewModel?.OnPropertyChanged(e.PropertyName);
}
- internal static class MixinManager
+ protected void SetVMMethod(string method, string? overrideName = null)
{
- public static readonly Dictionary> Mixins = new();
+ var methodInfo = new WrappedMethodInfo(AccessTools2.Method(GetType(), method)!, this);
+ ViewModel?.AddMethod(overrideName ?? method, methodInfo);
+ }
+}
- private static void AddMixin(ViewModel viewModel, object mixin)
- {
- if (Mixins.TryGetValue(viewModel, out var list))
- {
- list.Add(mixin);
- }
- else
- {
- Mixins.Add(viewModel, new List { mixin });
- }
- }
+internal static class MixinManager
+{
+ public static readonly Dictionary> Mixins = new();
- public static LauncherVM AddMixins(LauncherVM launcherVM)
+ private static void AddMixin(ViewModel viewModel, object mixin)
+ {
+ if (Mixins.TryGetValue(viewModel, out var list))
{
- AddMixin(launcherVM.News, new LauncherNewsVMMixin(launcherVM.News));
- AddMixin(launcherVM.ModsData, new LauncherModsVMMixin(launcherVM.ModsData));
- AddMixin(launcherVM.ConfirmStart, new LauncherConfirmStartVMMixin(launcherVM.ConfirmStart));
- AddMixin(launcherVM, new LauncherVMMixin(launcherVM));
- return launcherVM;
+ list.Add(mixin);
}
-
- public static LauncherConfirmStartVM AddMixin(LauncherConfirmStartVM confirmStartVM)
+ else
{
- AddMixin(confirmStartVM, new LauncherConfirmStartVMMixin(confirmStartVM));
- return confirmStartVM;
+ Mixins.Add(viewModel, new List { mixin });
}
}
+
+ public static LauncherVM AddMixins(LauncherVM launcherVM)
+ {
+ AddMixin(launcherVM.News, new LauncherNewsVMMixin(launcherVM.News));
+ AddMixin(launcherVM.ModsData, new LauncherModsVMMixin(launcherVM.ModsData));
+ AddMixin(launcherVM.ConfirmStart, new LauncherConfirmStartVMMixin(launcherVM.ConfirmStart));
+ AddMixin(launcherVM, new LauncherVMMixin(launcherVM));
+ return launcherVM;
+ }
+
+ public static LauncherConfirmStartVM AddMixin(LauncherConfirmStartVM confirmStartVM)
+ {
+ AddMixin(confirmStartVM, new LauncherConfirmStartVMMixin(confirmStartVM));
+ return confirmStartVM;
+ }
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/UI/PrefabExtensionManager.cs b/src/Bannerlord.LauncherEx/Helpers/UI/PrefabExtensionManager.cs
index 6743efe..751cc2d 100644
--- a/src/Bannerlord.LauncherEx/Helpers/UI/PrefabExtensionManager.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/UI/PrefabExtensionManager.cs
@@ -3,227 +3,226 @@
using System.Collections.Generic;
using System.Xml;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+///
+/// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Prefabs/IPrefabPatch.cs
+///
+internal interface IPrefabPatch { }
+
+///
+/// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Prefabs/PrefabExtensionSetAttributePatch.cs
+///
+internal abstract class PrefabExtensionSetAttributePatch : IPrefabPatch
{
- ///
- /// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Prefabs/IPrefabPatch.cs
- ///
- internal interface IPrefabPatch { }
-
- ///
- /// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Prefabs/PrefabExtensionSetAttributePatch.cs
- ///
- internal abstract class PrefabExtensionSetAttributePatch : IPrefabPatch
- {
- public abstract string Attribute { get; }
- public abstract string Value { get; }
- }
- internal abstract class PrefabExtensionSetAttributesPatch : IPrefabPatch
- {
- public abstract List Attributes { get; }
+ public abstract string Attribute { get; }
+ public abstract string Value { get; }
+}
+internal abstract class PrefabExtensionSetAttributesPatch : IPrefabPatch
+{
+ public abstract List Attributes { get; }
- public record struct Attribute(string Name, string Value);
- }
+ public record struct Attribute(string Name, string Value);
+}
- ///
- /// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Prefabs/PrefabExtensionInsertAsSiblingPatch.cs
- ///
- internal abstract class PrefabExtensionInsertAsSiblingPatch : IPrefabPatch
- {
- public enum InsertType { Prepend, Append }
+///
+/// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Prefabs/PrefabExtensionInsertAsSiblingPatch.cs
+///
+internal abstract class PrefabExtensionInsertAsSiblingPatch : IPrefabPatch
+{
+ public enum InsertType { Prepend, Append }
- public virtual InsertType Type => InsertType.Append;
+ public virtual InsertType Type => InsertType.Append;
- public abstract XmlDocument GetPrefabExtension();
- }
+ public abstract XmlDocument GetPrefabExtension();
+}
- ///
- /// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Prefabs/PrefabExtensionReplacePatch.cs
- ///
- internal abstract class PrefabExtensionReplacePatch : IPrefabPatch
- {
- public abstract XmlDocument GetPrefabExtension();
- }
+///
+/// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Prefabs/PrefabExtensionReplacePatch.cs
+///
+internal abstract class PrefabExtensionReplacePatch : IPrefabPatch
+{
+ public abstract XmlDocument GetPrefabExtension();
+}
+
+///
+/// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Prefabs/CustomPatch.cs
+///
+internal abstract class PrefabExtensionCustomPatch : IPrefabPatch where T : XmlNode
+{
+ public abstract void Apply(T obj);
+}
+
+///
+/// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Components/PrefabComponent.cs
+///
+internal static class PrefabExtensionManager
+{
+ private static readonly ConcurrentDictionary>> MoviePatches = new();
- ///
- /// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Prefabs/CustomPatch.cs
- ///
- internal abstract class PrefabExtensionCustomPatch : IPrefabPatch where T : XmlNode
+ public static void RegisterPatch(string movie, Action patcher)
{
- public abstract void Apply(T obj);
+ if (string.IsNullOrEmpty(movie))
+ {
+ return;
+ }
+
+ MoviePatches.GetOrAdd(movie, _ => new List>()).Add(patcher);
}
- ///
- /// https://github.com/BUTR/Bannerlord.UIExtenderEx/blob/dev/src/Bannerlord.UIExtenderEx/Components/PrefabComponent.cs
- ///
- internal static class PrefabExtensionManager
+ public static void RegisterPatch(string movie, string? xpath, Action patcher)
{
- private static readonly ConcurrentDictionary>> MoviePatches = new();
-
- public static void RegisterPatch(string movie, Action patcher)
+ RegisterPatch(movie, document =>
{
- if (string.IsNullOrEmpty(movie))
+ var node = document.SelectSingleNode(xpath ?? string.Empty);
+ if (node is null)
{
return;
}
- MoviePatches.GetOrAdd(movie, _ => new List>()).Add(patcher);
- }
+ patcher(node);
+ });
+ }
- public static void RegisterPatch(string movie, string? xpath, Action patcher)
+ public static void RegisterPatch(string movie, string? xpath, PrefabExtensionCustomPatch patcher)
+ {
+ RegisterPatch(movie, document =>
{
- RegisterPatch(movie, document =>
+ var node = document.SelectSingleNode(xpath ?? string.Empty);
+ if (node is null)
{
- var node = document.SelectSingleNode(xpath ?? string.Empty);
- if (node is null)
- {
- return;
- }
+ return;
+ }
- patcher(node);
- });
- }
+ patcher.Apply(node);
+ });
+ }
- public static void RegisterPatch(string movie, string? xpath, PrefabExtensionCustomPatch patcher)
+ public static void RegisterPatch(string movie, string? xpath, PrefabExtensionSetAttributePatch patch)
+ {
+ RegisterPatch(movie, xpath, node =>
{
- RegisterPatch(movie, document =>
+ var ownerDocument = node as XmlDocument ?? node.OwnerDocument;
+ if (ownerDocument is null)
{
- var node = document.SelectSingleNode(xpath ?? string.Empty);
- if (node is null)
- {
- return;
- }
-
- patcher.Apply(node);
- });
- }
+ return;
+ }
- public static void RegisterPatch(string movie, string? xpath, PrefabExtensionSetAttributePatch patch)
- {
- RegisterPatch(movie, xpath, node =>
+ if (node.NodeType != XmlNodeType.Element)
{
- var ownerDocument = node as XmlDocument ?? node.OwnerDocument;
- if (ownerDocument is null)
- {
- return;
- }
-
- if (node.NodeType != XmlNodeType.Element)
- {
- return;
- }
+ return;
+ }
- if (node.Attributes![patch.Attribute] is null)
- {
- var attribute = ownerDocument.CreateAttribute(patch.Attribute);
- node.Attributes.Append(attribute);
- }
+ if (node.Attributes![patch.Attribute] is null)
+ {
+ var attribute = ownerDocument.CreateAttribute(patch.Attribute);
+ node.Attributes.Append(attribute);
+ }
- node.Attributes![patch.Attribute].Value = patch.Value;
- });
- }
+ node.Attributes![patch.Attribute].Value = patch.Value;
+ });
+ }
- public static void RegisterPatch(string movie, string? xpath, PrefabExtensionSetAttributesPatch patch)
+ public static void RegisterPatch(string movie, string? xpath, PrefabExtensionSetAttributesPatch patch)
+ {
+ RegisterPatch(movie, xpath, node =>
{
- RegisterPatch(movie, xpath, node =>
+ var ownerDocument = node as XmlDocument ?? node.OwnerDocument;
+ if (ownerDocument is null)
{
- var ownerDocument = node as XmlDocument ?? node.OwnerDocument;
- if (ownerDocument is null)
- {
- return;
- }
+ return;
+ }
- if (node.NodeType != XmlNodeType.Element)
- {
- return;
- }
+ if (node.NodeType != XmlNodeType.Element)
+ {
+ return;
+ }
- foreach (var (attribute, value) in patch.Attributes)
+ foreach (var (attribute, value) in patch.Attributes)
+ {
+ if (node.Attributes![attribute] is null)
{
- if (node.Attributes![attribute] is null)
- {
- var attr = ownerDocument.CreateAttribute(attribute);
- node.Attributes.Append(attr);
- }
-
- node.Attributes![attribute].Value = value;
+ var attr = ownerDocument.CreateAttribute(attribute);
+ node.Attributes.Append(attr);
}
- });
- }
- public static void RegisterPatch(string movie, string? xpath, PrefabExtensionReplacePatch patch)
+ node.Attributes![attribute].Value = value;
+ }
+ });
+ }
+
+ public static void RegisterPatch(string movie, string? xpath, PrefabExtensionReplacePatch patch)
+ {
+ RegisterPatch(movie, xpath, node =>
{
- RegisterPatch(movie, xpath, node =>
+ var ownerDocument = node as XmlDocument ?? node.OwnerDocument;
+ if (ownerDocument is null)
{
- var ownerDocument = node as XmlDocument ?? node.OwnerDocument;
- if (ownerDocument is null)
- {
- return;
- }
+ return;
+ }
- if (node.ParentNode is null)
- {
- return;
- }
+ if (node.ParentNode is null)
+ {
+ return;
+ }
- var extensionNode = patch.GetPrefabExtension().DocumentElement;
- if (extensionNode is null)
- {
- return;
- }
+ var extensionNode = patch.GetPrefabExtension().DocumentElement;
+ if (extensionNode is null)
+ {
+ return;
+ }
- var importedExtensionNode = ownerDocument.ImportNode(extensionNode, true);
+ var importedExtensionNode = ownerDocument.ImportNode(extensionNode, true);
- node.ParentNode.ReplaceChild(importedExtensionNode, node);
- });
- }
+ node.ParentNode.ReplaceChild(importedExtensionNode, node);
+ });
+ }
- public static void RegisterPatch(string movie, string? xpath, PrefabExtensionInsertAsSiblingPatch patch)
+ public static void RegisterPatch(string movie, string? xpath, PrefabExtensionInsertAsSiblingPatch patch)
+ {
+ RegisterPatch(movie, xpath, node =>
{
- RegisterPatch(movie, xpath, node =>
+ var ownerDocument = node as XmlDocument ?? node.OwnerDocument;
+ if (ownerDocument is null)
{
- var ownerDocument = node as XmlDocument ?? node.OwnerDocument;
- if (ownerDocument is null)
- {
- return;
- }
+ return;
+ }
- if (node.ParentNode is null)
- {
- return;
- }
+ if (node.ParentNode is null)
+ {
+ return;
+ }
- var extensionNode = patch.GetPrefabExtension().DocumentElement;
- if (extensionNode is null)
- {
- return;
- }
+ var extensionNode = patch.GetPrefabExtension().DocumentElement;
+ if (extensionNode is null)
+ {
+ return;
+ }
- var importedExtensionNode = ownerDocument.ImportNode(extensionNode, true);
+ var importedExtensionNode = ownerDocument.ImportNode(extensionNode, true);
- switch (patch.Type)
- {
- case PrefabExtensionInsertAsSiblingPatch.InsertType.Append:
- node.ParentNode.InsertAfter(importedExtensionNode, node);
- break;
+ switch (patch.Type)
+ {
+ case PrefabExtensionInsertAsSiblingPatch.InsertType.Append:
+ node.ParentNode.InsertAfter(importedExtensionNode, node);
+ break;
- case PrefabExtensionInsertAsSiblingPatch.InsertType.Prepend:
- node.ParentNode.InsertBefore(importedExtensionNode, node);
- break;
- }
- });
- }
+ case PrefabExtensionInsertAsSiblingPatch.InsertType.Prepend:
+ node.ParentNode.InsertBefore(importedExtensionNode, node);
+ break;
+ }
+ });
+ }
- public static void ProcessMovieIfNeeded(string movie, XmlDocument document)
- {
- if (!MoviePatches.TryGetValue(movie, out var patches))
- return;
+ public static void ProcessMovieIfNeeded(string movie, XmlDocument document)
+ {
+ if (!MoviePatches.TryGetValue(movie, out var patches))
+ return;
- foreach (var patch in patches)
- {
- patch(document);
- }
+ foreach (var patch in patches)
+ {
+ patch(document);
}
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Helpers/UI/Settings.cs b/src/Bannerlord.LauncherEx/Helpers/UI/Settings.cs
index b45c9bc..29a5130 100644
--- a/src/Bannerlord.LauncherEx/Helpers/UI/Settings.cs
+++ b/src/Bannerlord.LauncherEx/Helpers/UI/Settings.cs
@@ -1,55 +1,54 @@
using System.Diagnostics.CodeAnalysis;
-namespace Bannerlord.LauncherEx.Helpers
+namespace Bannerlord.LauncherEx.Helpers;
+
+///
+/// https://github.com/Aragas/Bannerlord.MBOptionScreen/blob/dev/src/MCM/Abstractions/Settings/SettingType.cs
+///
+internal enum SettingType
{
- ///
- /// https://github.com/Aragas/Bannerlord.MBOptionScreen/blob/dev/src/MCM/Abstractions/Settings/SettingType.cs
- ///
- internal enum SettingType
- {
- [SuppressMessage("CodeQuality", "IDE0079:Remove unnecessary suppression", Justification = "For ReSharper")]
- [SuppressMessage("ReSharper", "InconsistentNaming")]
- NONE = -1,
- Bool,
- Int,
- Float,
- String,
- Button,
- }
+ [SuppressMessage("CodeQuality", "IDE0079:Remove unnecessary suppression", Justification = "For ReSharper")]
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ NONE = -1,
+ Bool,
+ Int,
+ Float,
+ String,
+ Button,
+}
- ///
- /// https://github.com/Aragas/Bannerlord.MBOptionScreen/blob/dev/src/MCM/Abstractions/Settings/Models/ISettingsPropertyDefinition.cs
- ///
- internal interface ISettingsPropertyDefinition
- {
- IRef PropertyReference { get; }
+///
+/// https://github.com/Aragas/Bannerlord.MBOptionScreen/blob/dev/src/MCM/Abstractions/Settings/Models/ISettingsPropertyDefinition.cs
+///
+internal interface ISettingsPropertyDefinition
+{
+ IRef PropertyReference { get; }
- SettingType SettingType { get; }
+ SettingType SettingType { get; }
- string DisplayName { get; }
- string HintText { get; }
- decimal MinValue { get; }
- decimal MaxValue { get; }
- string Content { get; }
- }
+ string DisplayName { get; }
+ string HintText { get; }
+ decimal MinValue { get; }
+ decimal MaxValue { get; }
+ string Content { get; }
+}
- ///
- /// https://github.com/Aragas/Bannerlord.MBOptionScreen/blob/dev/src/MCM/Abstractions/Settings/Models/SettingsPropertyDefinition.cs
- ///
- internal class SettingsPropertyDefinition : ISettingsPropertyDefinition
- {
- public string DisplayName { get; init; } = string.Empty;
- public string HintText { get; init; } = string.Empty;
- public IRef PropertyReference { get; init; } = default!;
- public SettingType SettingType { get; init; } = default!;
+///
+/// https://github.com/Aragas/Bannerlord.MBOptionScreen/blob/dev/src/MCM/Abstractions/Settings/Models/SettingsPropertyDefinition.cs
+///
+internal class SettingsPropertyDefinition : ISettingsPropertyDefinition
+{
+ public string DisplayName { get; init; } = string.Empty;
+ public string HintText { get; init; } = string.Empty;
+ public IRef PropertyReference { get; init; } = default!;
+ public SettingType SettingType { get; init; } = default!;
- public decimal MinValue { get; init; } = default!;
- public decimal MaxValue { get; init; } = default!;
- public string Content { get; init; } = default!;
- }
- internal class ConfigSettingsPropertyDefinition : SettingsPropertyDefinition
- {
- public string ConfigKey { get; init; } = string.Empty;
- public string OriginalValue { get; init; } = string.Empty;
- }
+ public decimal MinValue { get; init; } = default!;
+ public decimal MaxValue { get; init; } = default!;
+ public string Content { get; init; } = default!;
+}
+internal class ConfigSettingsPropertyDefinition : SettingsPropertyDefinition
+{
+ public string ConfigKey { get; init; } = string.Empty;
+ public string OriginalValue { get; init; } = string.Empty;
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/LauncherSettings.cs b/src/Bannerlord.LauncherEx/LauncherSettings.cs
index ec8a6bd..3afbb24 100644
--- a/src/Bannerlord.LauncherEx/LauncherSettings.cs
+++ b/src/Bannerlord.LauncherEx/LauncherSettings.cs
@@ -1,21 +1,20 @@
using System.Diagnostics.CodeAnalysis;
-namespace Bannerlord.LauncherEx
+namespace Bannerlord.LauncherEx;
+
+[SuppressMessage("CodeQuality", "IDE0079:Remove unnecessary suppression", Justification = "For ReSharper")]
+[SuppressMessage("ReSharper", "UnusedMember.Global")]
+public static class LauncherSettings
{
- [SuppressMessage("CodeQuality", "IDE0079:Remove unnecessary suppression", Justification = "For ReSharper")]
- [SuppressMessage("ReSharper", "UnusedMember.Global")]
- public static class LauncherSettings
- {
- public static bool AutomaticallyCheckForUpdates { get; set; } = false;
- public static bool FixCommonIssues { get; set; } = false;
- public static bool CompactModuleList { get; set; } = false;
- public static bool DisableBinaryCheck { get; set; } = false;
- public static bool HideRandomImage { get; set; } = false;
- public static bool BetaSorting { get; set; } = false;
- public static bool BigMode { get; set; } = true;
- public static bool EnableDPIScaling { get; set; } = true;
- public static bool DisableCrashHandlerWhenDebuggerIsAttached { get; set; } = false;
- public static bool DisableCatchAutoGenExceptions { get; set; } = true;
- public static bool UseVanillaCrashHandler { get; set; } = false;
- }
+ public static bool AutomaticallyCheckForUpdates { get; set; } = false;
+ public static bool FixCommonIssues { get; set; } = false;
+ public static bool CompactModuleList { get; set; } = false;
+ public static bool DisableBinaryCheck { get; set; } = false;
+ public static bool HideRandomImage { get; set; } = false;
+ public static bool BetaSorting { get; set; } = false;
+ public static bool BigMode { get; set; } = true;
+ public static bool EnableDPIScaling { get; set; } = true;
+ public static bool DisableCrashHandlerWhenDebuggerIsAttached { get; set; } = false;
+ public static bool DisableCatchAutoGenExceptions { get; set; } = true;
+ public static bool UseVanillaCrashHandler { get; set; } = false;
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Manager.cs b/src/Bannerlord.LauncherEx/Manager.cs
index 2e0957b..d2f11a9 100644
--- a/src/Bannerlord.LauncherEx/Manager.cs
+++ b/src/Bannerlord.LauncherEx/Manager.cs
@@ -20,134 +20,133 @@
[assembly: InternalsVisibleTo("Bannerlord.LauncherEx.Tests")]
// ReSharper disable once CheckNamespace
-namespace Bannerlord.LauncherEx
+namespace Bannerlord.LauncherEx;
+
+public static class Manager
{
- public static class Manager
- {
- //internal static readonly AssemblyCompatibilityChecker _compatibilityChecker = new();
- private static readonly Harmony _launcherHarmony = new("Bannerlord.LauncherEx");
+ //internal static readonly AssemblyCompatibilityChecker _compatibilityChecker = new();
+ private static readonly Harmony _launcherHarmony = new("Bannerlord.LauncherEx");
- public static event Action? OnDisable;
+ public static event Action? OnDisable;
- public static string GetActiveLanguage() => ConfigReader.GetGameOptions(path => File.Exists(path) ? File.ReadAllBytes(path) : null).TryGetValue("Language", out var lang) ? lang : "English";
+ public static string GetActiveLanguage() => ConfigReader.GetGameOptions(path => File.Exists(path) ? File.ReadAllBytes(path) : null).TryGetValue("Language", out var lang) ? lang : "English";
- public static void Initialize()
- {
- //AssemblyLoaderPatch.Enable(_launcherHarmony);
- }
+ public static void Initialize()
+ {
+ //AssemblyLoaderPatch.Enable(_launcherHarmony);
+ }
- public static void Enable()
+ public static void Enable()
+ {
+ ProgramPatch.Enable(_launcherHarmony);
+ UserDataManagerPatch.Enable(_launcherHarmony);
+ LauncherVMPatch.Enable(_launcherHarmony);
+ LauncherModsVMPatch.Enable(_launcherHarmony);
+ LauncherConfirmStartVMPatch.Enable(_launcherHarmony);
+ LauncherUIPatch.Enable(_launcherHarmony);
+ ViewModelPatch.Enable(_launcherHarmony);
+ WidgetPrefabPatch.Enable(_launcherHarmony);
+
+ foreach (var language in typeof(Manager).Assembly.GetManifestResourceNames().Where(x => x.StartsWith("Bannerlord.LauncherEx.Resources.Localization") && x.EndsWith("strings.xml")))
+ BUTRLocalizationManager.LoadLanguage(Load(language));
+ BUTRLocalizationManager.ActiveLanguage = GetActiveLanguage();
+
+ GraphicsContextManager.Enable(_launcherHarmony);
+ GraphicsContextManager.CreateAndRegister("launcher_arrow_down", LoadStream("Bannerlord.LauncherEx.Resources.Textures.arrow_down.png"));
+ GraphicsContextManager.CreateAndRegister("launcher_arrow_left", LoadStream("Bannerlord.LauncherEx.Resources.Textures.arrow_left.png"));
+ GraphicsContextManager.CreateAndRegister("launcher_export", LoadStream("Bannerlord.LauncherEx.Resources.Textures.export.png"));
+ GraphicsContextManager.CreateAndRegister("launcher_import", LoadStream("Bannerlord.LauncherEx.Resources.Textures.import.png"));
+ GraphicsContextManager.CreateAndRegister("launcher_refresh", LoadStream("Bannerlord.LauncherEx.Resources.Textures.refresh.png"));
+ GraphicsContextManager.CreateAndRegister("launcher_folder", LoadStream("Bannerlord.LauncherEx.Resources.Textures.folder.png"));
+ GraphicsContextManager.CreateAndRegister("launcher_search", LoadStream("Bannerlord.LauncherEx.Resources.Textures.search.png"));
+ GraphicsContextManager.CreateAndRegister("warm_overlay", LoadStream("Bannerlord.LauncherEx.Resources.Textures.warm_overlay.png"));
+
+ SpriteDataManager.Enable(_launcherHarmony);
+ SpriteDataManager.CreateAndRegister("launcher_arrow_down");
+ SpriteDataManager.CreateAndRegister("launcher_arrow_left");
+ SpriteDataManager.CreateAndRegister("launcher_import");
+ SpriteDataManager.CreateAndRegister("launcher_export");
+ SpriteDataManager.CreateAndRegister("launcher_refresh");
+ SpriteDataManager.CreateAndRegister("launcher_folder");
+ SpriteDataManager.CreateAndRegister("launcher_search");
+ SpriteDataManager.CreateAndRegister("warm_overlay");
+
+ var asset = new AssetPackage(Path.Combine(BasePath.Name, ModuleInfoHelper.ModulesFolder, "Native/AssetPackages/gauntlet_ui.tpac"));
+ switch (BUTRLocalizationManager.ActiveLanguage)
{
- ProgramPatch.Enable(_launcherHarmony);
- UserDataManagerPatch.Enable(_launcherHarmony);
- LauncherVMPatch.Enable(_launcherHarmony);
- LauncherModsVMPatch.Enable(_launcherHarmony);
- LauncherConfirmStartVMPatch.Enable(_launcherHarmony);
- LauncherUIPatch.Enable(_launcherHarmony);
- ViewModelPatch.Enable(_launcherHarmony);
- WidgetPrefabPatch.Enable(_launcherHarmony);
-
- foreach (var language in typeof(Manager).Assembly.GetManifestResourceNames().Where(x => x.StartsWith("Bannerlord.LauncherEx.Resources.Localization") && x.EndsWith("strings.xml")))
- BUTRLocalizationManager.LoadLanguage(Load(language));
- BUTRLocalizationManager.ActiveLanguage = GetActiveLanguage();
-
- GraphicsContextManager.Enable(_launcherHarmony);
- GraphicsContextManager.CreateAndRegister("launcher_arrow_down", LoadStream("Bannerlord.LauncherEx.Resources.Textures.arrow_down.png"));
- GraphicsContextManager.CreateAndRegister("launcher_arrow_left", LoadStream("Bannerlord.LauncherEx.Resources.Textures.arrow_left.png"));
- GraphicsContextManager.CreateAndRegister("launcher_export", LoadStream("Bannerlord.LauncherEx.Resources.Textures.export.png"));
- GraphicsContextManager.CreateAndRegister("launcher_import", LoadStream("Bannerlord.LauncherEx.Resources.Textures.import.png"));
- GraphicsContextManager.CreateAndRegister("launcher_refresh", LoadStream("Bannerlord.LauncherEx.Resources.Textures.refresh.png"));
- GraphicsContextManager.CreateAndRegister("launcher_folder", LoadStream("Bannerlord.LauncherEx.Resources.Textures.folder.png"));
- GraphicsContextManager.CreateAndRegister("launcher_search", LoadStream("Bannerlord.LauncherEx.Resources.Textures.search.png"));
- GraphicsContextManager.CreateAndRegister("warm_overlay", LoadStream("Bannerlord.LauncherEx.Resources.Textures.warm_overlay.png"));
-
- SpriteDataManager.Enable(_launcherHarmony);
- SpriteDataManager.CreateAndRegister("launcher_arrow_down");
- SpriteDataManager.CreateAndRegister("launcher_arrow_left");
- SpriteDataManager.CreateAndRegister("launcher_import");
- SpriteDataManager.CreateAndRegister("launcher_export");
- SpriteDataManager.CreateAndRegister("launcher_refresh");
- SpriteDataManager.CreateAndRegister("launcher_folder");
- SpriteDataManager.CreateAndRegister("launcher_search");
- SpriteDataManager.CreateAndRegister("warm_overlay");
-
- var asset = new AssetPackage(Path.Combine(BasePath.Name, ModuleInfoHelper.ModulesFolder, "Native/AssetPackages/gauntlet_ui.tpac"));
- switch (BUTRLocalizationManager.ActiveLanguage)
- {
- case BUTRLocalizationManager.ChineseTraditional or BUTRLocalizationManager.ChineseSimple when asset.GetTexture("ui_fonts_1") is { } chinese:
- GraphicsContextManager.CreateAssetTextureAndRegister("simkai", chinese);
- SpriteDataManager.CreateGenericAndRegister("simkai");
- break;
- case BUTRLocalizationManager.Japanese when asset.GetTexture("ui_fonts_2") is { } japanese:
- GraphicsContextManager.CreateAssetTextureAndRegister("SourceHanSansJP", japanese);
- SpriteDataManager.CreateGenericAndRegister("SourceHanSansJP");
- break;
- case BUTRLocalizationManager.Korean when asset.GetTexture("ui_fonts_4") is { } korean:
- GraphicsContextManager.CreateAssetTextureAndRegister("NanumGothicKR", korean);
- SpriteDataManager.CreateGenericAndRegister("NanumGothicKR");
- break;
- }
-
-
- BrushFactoryManager.Enable(_launcherHarmony);
- BrushFactoryManager.CreateAndRegister(Load("Bannerlord.LauncherEx.Resources.Brushes.Launcher.xml"));
-
- WidgetFactoryManager.Enable(_launcherHarmony);
- WidgetFactoryManager.Register(typeof(LauncherToggleButtonWidget));
- WidgetFactoryManager.Register(typeof(LauncherSearchBoxWidget));
-
- WidgetFactoryManager.CreateAndRegister("Launcher.ToggleButton", Load("Bannerlord.LauncherEx.Resources.Prefabs.Widgets.Launcher.ToggleButton.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.SearchBox", Load("Bannerlord.LauncherEx.Resources.Prefabs.Widgets.Launcher.SearchBox.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.Scrollbar", Load("Bannerlord.LauncherEx.Resources.Prefabs.Widgets.Launcher.Scrollbar.xml"));
-
- WidgetFactoryManager.CreateAndRegister("Launcher.SettingsPropertyBoolView", Load("Bannerlord.LauncherEx.Resources.Prefabs.Properties.Launcher.SettingsPropertyBoolView.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.SettingsPropertyButtonView", Load("Bannerlord.LauncherEx.Resources.Prefabs.Properties.Launcher.SettingsPropertyButtonView.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.SettingsPropertyFloatView", Load("Bannerlord.LauncherEx.Resources.Prefabs.Properties.Launcher.SettingsPropertyFloatView.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.SettingsPropertyIntView", Load("Bannerlord.LauncherEx.Resources.Prefabs.Properties.Launcher.SettingsPropertyIntView.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.SettingsPropertyStringView", Load("Bannerlord.LauncherEx.Resources.Prefabs.Properties.Launcher.SettingsPropertyStringView.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.Options", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Options.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.Options.OptionTuple", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Options.OptionTuple.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.Mods2", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Mods.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.Mods.ModuleTuple2", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Mods.ModuleTuple.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.Saves", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Saves.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.Saves.SaveTuple", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Saves.SaveTuple.xml"));
- WidgetFactoryManager.CreateAndRegister("Launcher.MessageBox", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.MessageBox.xml"));
-
- FontFactoryManager.Enable(_launcherHarmony);
+ case BUTRLocalizationManager.ChineseTraditional or BUTRLocalizationManager.ChineseSimple when asset.GetTexture("ui_fonts_1") is { } chinese:
+ GraphicsContextManager.CreateAssetTextureAndRegister("simkai", chinese);
+ SpriteDataManager.CreateGenericAndRegister("simkai");
+ break;
+ case BUTRLocalizationManager.Japanese when asset.GetTexture("ui_fonts_2") is { } japanese:
+ GraphicsContextManager.CreateAssetTextureAndRegister("SourceHanSansJP", japanese);
+ SpriteDataManager.CreateGenericAndRegister("SourceHanSansJP");
+ break;
+ case BUTRLocalizationManager.Korean when asset.GetTexture("ui_fonts_4") is { } korean:
+ GraphicsContextManager.CreateAssetTextureAndRegister("NanumGothicKR", korean);
+ SpriteDataManager.CreateGenericAndRegister("NanumGothicKR");
+ break;
}
- private static XmlDocument Load(string embedPath)
- {
- using var stream = typeof(Manager).Assembly.GetManifestResourceStream(embedPath);
- if (stream is null) throw new Exception($"Could not find embed resource '{embedPath}'!");
- using var xmlReader = XmlReader.Create(stream, new XmlReaderSettings { IgnoreComments = true });
- var doc = new XmlDocument();
- doc.Load(xmlReader);
- return doc;
- }
- private static Stream LoadStream(string embedPath)
- {
- return typeof(Manager).Assembly.GetManifestResourceStream(embedPath) ?? throw new Exception($"Could not find embed resource '{embedPath}'!");
- }
- public static void Disable()
- {
- OnDisable?.Invoke();
- //_compatibilityChecker.Dispose();
- GraphicsContextManager.Clear();
- SpriteDataManager.Clear();
- BrushFactoryManager.Clear();
- WidgetFactoryManager.Clear();
- BUTRLocalizationManager.Clear();
- _launcherHarmony.UnpatchAll(_launcherHarmony.Id);
- }
+ BrushFactoryManager.Enable(_launcherHarmony);
+ BrushFactoryManager.CreateAndRegister(Load("Bannerlord.LauncherEx.Resources.Brushes.Launcher.xml"));
- public static LauncherExData CurrentSettingsSnapshot()
- {
- var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Mount and Blade II Bannerlord", "Configs", "LauncherData.xml");
- if (!File.Exists(path)) return new();
+ WidgetFactoryManager.Enable(_launcherHarmony);
+ WidgetFactoryManager.Register(typeof(LauncherToggleButtonWidget));
+ WidgetFactoryManager.Register(typeof(LauncherSearchBoxWidget));
- return LauncherExData.FromUserDataXml(path) ?? new();
- }
+ WidgetFactoryManager.CreateAndRegister("Launcher.ToggleButton", Load("Bannerlord.LauncherEx.Resources.Prefabs.Widgets.Launcher.ToggleButton.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.SearchBox", Load("Bannerlord.LauncherEx.Resources.Prefabs.Widgets.Launcher.SearchBox.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.Scrollbar", Load("Bannerlord.LauncherEx.Resources.Prefabs.Widgets.Launcher.Scrollbar.xml"));
+
+ WidgetFactoryManager.CreateAndRegister("Launcher.SettingsPropertyBoolView", Load("Bannerlord.LauncherEx.Resources.Prefabs.Properties.Launcher.SettingsPropertyBoolView.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.SettingsPropertyButtonView", Load("Bannerlord.LauncherEx.Resources.Prefabs.Properties.Launcher.SettingsPropertyButtonView.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.SettingsPropertyFloatView", Load("Bannerlord.LauncherEx.Resources.Prefabs.Properties.Launcher.SettingsPropertyFloatView.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.SettingsPropertyIntView", Load("Bannerlord.LauncherEx.Resources.Prefabs.Properties.Launcher.SettingsPropertyIntView.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.SettingsPropertyStringView", Load("Bannerlord.LauncherEx.Resources.Prefabs.Properties.Launcher.SettingsPropertyStringView.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.Options", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Options.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.Options.OptionTuple", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Options.OptionTuple.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.Mods2", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Mods.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.Mods.ModuleTuple2", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Mods.ModuleTuple.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.Saves", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Saves.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.Saves.SaveTuple", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.Saves.SaveTuple.xml"));
+ WidgetFactoryManager.CreateAndRegister("Launcher.MessageBox", Load("Bannerlord.LauncherEx.Resources.Prefabs.Launcher.MessageBox.xml"));
+
+ FontFactoryManager.Enable(_launcherHarmony);
+ }
+
+ private static XmlDocument Load(string embedPath)
+ {
+ using var stream = typeof(Manager).Assembly.GetManifestResourceStream(embedPath);
+ if (stream is null) throw new Exception($"Could not find embed resource '{embedPath}'!");
+ using var xmlReader = XmlReader.Create(stream, new XmlReaderSettings { IgnoreComments = true });
+ var doc = new XmlDocument();
+ doc.Load(xmlReader);
+ return doc;
+ }
+ private static Stream LoadStream(string embedPath)
+ {
+ return typeof(Manager).Assembly.GetManifestResourceStream(embedPath) ?? throw new Exception($"Could not find embed resource '{embedPath}'!");
+ }
+
+ public static void Disable()
+ {
+ OnDisable?.Invoke();
+ //_compatibilityChecker.Dispose();
+ GraphicsContextManager.Clear();
+ SpriteDataManager.Clear();
+ BrushFactoryManager.Clear();
+ WidgetFactoryManager.Clear();
+ BUTRLocalizationManager.Clear();
+ _launcherHarmony.UnpatchAll(_launcherHarmony.Id);
+ }
+
+ public static LauncherExData CurrentSettingsSnapshot()
+ {
+ var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Mount and Blade II Bannerlord", "Configs", "LauncherData.xml");
+ if (!File.Exists(path)) return new();
+
+ return LauncherExData.FromUserDataXml(path) ?? new();
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Mixins/LauncherConfirmStartVMMixin.cs b/src/Bannerlord.LauncherEx/Mixins/LauncherConfirmStartVMMixin.cs
index cae8de7..e71ff35 100644
--- a/src/Bannerlord.LauncherEx/Mixins/LauncherConfirmStartVMMixin.cs
+++ b/src/Bannerlord.LauncherEx/Mixins/LauncherConfirmStartVMMixin.cs
@@ -3,15 +3,14 @@
using TaleWorlds.MountAndBlade.Launcher.Library;
-namespace Bannerlord.LauncherEx.Mixins
+namespace Bannerlord.LauncherEx.Mixins;
+
+internal sealed class LauncherConfirmStartVMMixin : ViewModelMixin
{
- internal sealed class LauncherConfirmStartVMMixin : ViewModelMixin
- {
- [BUTRDataSourceProperty]
- public string CancelText2 => new BUTRTextObject("{=DzJmcvsP}Cancel").ToString();
- [BUTRDataSourceProperty]
- public string ConfirmText2 => new BUTRTextObject("{=epTxGUqT}Confirm").ToString();
+ [BUTRDataSourceProperty]
+ public string CancelText2 => new BUTRTextObject("{=DzJmcvsP}Cancel").ToString();
+ [BUTRDataSourceProperty]
+ public string ConfirmText2 => new BUTRTextObject("{=epTxGUqT}Confirm").ToString();
- public LauncherConfirmStartVMMixin(LauncherConfirmStartVM launcherNewsVM) : base(launcherNewsVM) { }
- }
+ public LauncherConfirmStartVMMixin(LauncherConfirmStartVM launcherNewsVM) : base(launcherNewsVM) { }
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Mixins/LauncherModsVMMixin.cs b/src/Bannerlord.LauncherEx/Mixins/LauncherModsVMMixin.cs
index 21cf508..84f13e3 100644
--- a/src/Bannerlord.LauncherEx/Mixins/LauncherModsVMMixin.cs
+++ b/src/Bannerlord.LauncherEx/Mixins/LauncherModsVMMixin.cs
@@ -1,209 +1,313 @@
-using Bannerlord.LauncherEx.Helpers;
+using Bannerlord.BUTR.Shared.Helpers;
+using Bannerlord.LauncherEx.Helpers;
using Bannerlord.LauncherEx.ViewModels;
using Bannerlord.LauncherManager.Localization;
using Bannerlord.LauncherManager.Models;
using Bannerlord.LauncherManager.Utils;
using Bannerlord.ModuleManager;
+using Newtonsoft.Json;
+
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
+using System.Net;
+using System.Reflection;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
using TaleWorlds.Library;
using TaleWorlds.MountAndBlade.Launcher.Library;
-namespace Bannerlord.LauncherEx.Mixins
-{
- internal enum ModuleType { Framework, Graphical, Standard, Patches }
+using ApplicationVersion = TaleWorlds.Library.ApplicationVersion;
- internal sealed class LauncherModsVMMixin : ViewModelMixin/*, IHasOrderer*/
- {
- private readonly BUTRLauncherManagerHandler _launcherManagerHandler = BUTRLauncherManagerHandler.Default;
- private readonly MBBindingList _modules = new();
- private readonly Dictionary _modulesLookup = new();
+namespace Bannerlord.LauncherEx.Mixins;
+
+// TODO:
+internal enum ModuleType { Framework, Graphical, Standard, Patches }
+
+internal sealed class LauncherModsVMMixin : ViewModelMixin/*, IHasOrderer*/
+{
+ private readonly BUTRLauncherManagerHandler _launcherManagerHandler = BUTRLauncherManagerHandler.Default;
+ private readonly MBBindingList _modules = new();
+ private readonly Dictionary _modulesLookup = new();
+ private IReadOnlyList _allModuleInfos;
- [BUTRDataSourceProperty]
- public bool GlobalCheckboxState { get => _checkboxState; set => SetField(ref _checkboxState, value); }
- private bool _checkboxState;
+ [BUTRDataSourceProperty]
+ public bool GlobalCheckboxState { get => _checkboxState; set => SetField(ref _checkboxState, value); }
+ private bool _checkboxState;
- [BUTRDataSourceProperty]
- public bool IsDisabled2 { get => _isDisabled2; set => SetField(ref _isDisabled2, value); }
- private bool _isDisabled2;
+ [BUTRDataSourceProperty]
+ public bool IsDisabled2 { get => _isDisabled2; set => SetField(ref _isDisabled2, value); }
+ private bool _isDisabled2;
- [BUTRDataSourceProperty]
- public MBBindingList Modules2 { get; } = new();
+ [BUTRDataSourceProperty]
+ public MBBindingList Modules2 { get; } = new();
- // Fast lookup for the ViewModels
+ // Fast lookup for the ViewModels
- [BUTRDataSourceProperty]
- public bool IsForceSorted { get => _isForceSorted; set => SetField(ref _isForceSorted, value); }
- private bool _isForceSorted;
+ [BUTRDataSourceProperty]
+ public bool IsForceSorted { get => _isForceSorted; set => SetField(ref _isForceSorted, value); }
+ private bool _isForceSorted;
- [BUTRDataSourceProperty]
- public LauncherHintVM? ForceSortedHint { get => _forceSortedHint; set => SetField(ref _forceSortedHint, value); }
- private LauncherHintVM? _forceSortedHint;
+ [BUTRDataSourceProperty]
+ public LauncherHintVM? ForceSortedHint { get => _forceSortedHint; set => SetField(ref _forceSortedHint, value); }
+ private LauncherHintVM? _forceSortedHint;
- [BUTRDataSourceProperty]
- public string SearchText
+ [BUTRDataSourceProperty]
+ public string SearchText
+ {
+ get => _searchText;
+ set
{
- get => _searchText;
- set
+ if (SetField(ref _searchText, value))
{
- if (SetField(ref _searchText, value))
- {
- SearchTextChanged();
- }
+ SearchTextChanged();
}
}
- private string _searchText = string.Empty;
+ }
+ private string _searchText = string.Empty;
- [BUTRDataSourceProperty]
- public string NameCategoryText2 => new BUTRTextObject("{=JtelOsIW}Name").ToString();
- [BUTRDataSourceProperty]
- public string VersionCategoryText2 => new BUTRTextObject("{=14WBFIS1}Version").ToString();
+ [BUTRDataSourceProperty]
+ public string NameCategoryText2 => new BUTRTextObject("{=JtelOsIW}Name").ToString();
+ [BUTRDataSourceProperty]
+ public string VersionCategoryText2 => new BUTRTextObject("{=14WBFIS1}Version").ToString();
- public LauncherModsVMMixin(LauncherModsVM launcherModsVM) : base(launcherModsVM)
- {
- _launcherManagerHandler.RegisterModuleViewModelProvider(() => _modules, () => Modules2, SetViewModels);
+ [BUTRDataSourceProperty]
+ public LauncherHintVM? GlobalCheckboxHint { get => _globalCheckboxHint; set => SetField(ref _globalCheckboxHint, value); }
+ private LauncherHintVM? _globalCheckboxHint;
- _launcherManagerHandler.RefreshModules();
- foreach (var moduleInfoExtended in _launcherManagerHandler.ExtendedModuleInfoCache.Values.OfType())
- {
- var moduleVM = new BUTRLauncherModuleVM(moduleInfoExtended, ToggleModuleSelection, ValidateModule);
- _modules.Add(moduleVM);
- _modulesLookup[moduleVM.ModuleInfoExtended.Id] = moduleVM;
- }
- }
+ [BUTRDataSourceProperty]
+ public LauncherHintVM? RefreshHint { get => _refreshHint; set => SetField(ref _refreshHint, value); }
+ private LauncherHintVM? _refreshHint;
+
+ [BUTRDataSourceProperty]
+ public LauncherHintVM? UpdateInfoHint { get => _updateInfoHint; set => SetField(ref _updateInfoHint, value); }
+ private LauncherHintVM? _updateInfoHint;
- public ModuleInfoExtended? GetModuleById(string id) => _launcherManagerHandler.ExtendedModuleInfoCache.TryGetValue(id, out var mie) ? mie : null;
- public ModuleInfoExtended? GetModuleByName(string name) => _launcherManagerHandler.ExtendedModuleInfoCache.Values.FirstOrDefault(x => x.Name == name);
+ public LauncherModsVMMixin(LauncherModsVM launcherModsVM) : base(launcherModsVM)
+ {
+ GlobalCheckboxHint = new LauncherHintVM(new BUTRTextObject("{=q5quVWMI}Toggle All Modules").ToString());
+ RefreshHint = new LauncherHintVM(new BUTRTextObject("{=H5nMY4WU}Refresh Modules").ToString());
+ UpdateInfoHint = new LauncherHintVM(new BUTRTextObject("{=zXWdahH9}Get Update Recommendations{NL}Clicking on this button will send your module list to the BUTR server to get compatibility scores and recommended versions.{NL}They are based on the crash reports from ButterLib.{NL}{NL}(Requires Internet Connection)")
+ .SetTextVariable("NL", Environment.NewLine).ToString());
+
+ _launcherManagerHandler.RegisterModuleViewModelProvider(() => _modules, () => Modules2, SetViewModels);
- public void Initialize()
+ _launcherManagerHandler.RefreshModules();
+ _allModuleInfos = _launcherManagerHandler.GetAllModules();
+ foreach (var moduleInfoExtended in _launcherManagerHandler.ExtendedModuleInfoCache.Values.OfType())
{
- Modules2.Clear();
+ var moduleVM = new BUTRLauncherModuleVM(moduleInfoExtended, ToggleModuleSelection, ValidateModule, GetPossibleProviders);
+ _modules.Add(moduleVM);
+ _modulesLookup[moduleVM.ModuleInfoExtended.Id] = moduleVM;
+ }
+ }
- var loadOrder = _launcherManagerHandler.LoadTWLoadOrder().ToDictionary(x => x.Key, x => x.Value.IsSelected);
- if (_launcherManagerHandler.TryOrderByLoadOrder(loadOrder.Keys, x => loadOrder.TryGetValue(x, out var isSelected) && isSelected, out var issues, out var orderedModules))
- {
- SetViewModels(orderedModules);
- IsForceSorted = false;
- }
- else
- {
- IsForceSorted = true;
- ForceSortedHint = new LauncherHintVM(new BUTRTextObject("{=pZVVdI5d}The Load Order was re-sorted with the default algorithm!{NL}Reasons:{NL}{REASONS}").SetTextVariable("REASONS", string.Join("\n", issues)).ToString());
+ public ModuleInfoExtended? GetModuleById(string id) => _launcherManagerHandler.ExtendedModuleInfoCache.TryGetValue(id, out var mie) ? mie : null;
+ public ModuleInfoExtended? GetModuleByName(string name) => _launcherManagerHandler.ExtendedModuleInfoCache.Values.FirstOrDefault(x => x.Name == name);
- // Beta sorting algorithm will fail currently in some cases, use the TW fallback
- _launcherManagerHandler.TryOrderByLoadOrderTW(Enumerable.Empty(), x => loadOrder.TryGetValue(x, out var isSelected) && isSelected, out _, out orderedModules, true);
- SetViewModels(orderedModules); // Set the ViewModels regarding the result
+ public void Initialize()
+ {
+ Modules2.Clear();
+
+ var loadOrder = _launcherManagerHandler.LoadLoadOrder().ToDictionary(x => x.Key, x => x.Value.IsSelected);
+
+ /*
+ if (!LoadOrderChecker.IsLoadOrderCorrect())
+ {
- //TryOrderByLoadOrder(Enumerable.Empty(), x => loadOrder.TryGetValue(x, out var isSelected) && isSelected);
- }
}
+ */
- private void SetViewModels(IEnumerable orderedModuleViewModels)
+ if (_launcherManagerHandler.TryOrderByLoadOrder(loadOrder.Keys, x => loadOrder.TryGetValue(x, out var isSelected) && isSelected, out var issues, out var orderedModules))
{
- Modules2.Clear();
- foreach (var viewModel in orderedModuleViewModels.OfType())
- Modules2.Add(viewModel);
+ SetViewModels(orderedModules);
+ IsForceSorted = false;
+ }
+ else
+ {
+ IsForceSorted = true;
+ ForceSortedHint = new LauncherHintVM(new BUTRTextObject("{=pZVVdI5d}The Load Order was re-sorted with the default algorithm!{NL}Reasons:{NL}{REASONS}").SetTextVariable("REASONS", string.Join("\n", issues)).ToString());
- // Validate all VM's after they were selected and ordered
- foreach (var modules in Modules2)
- modules.Validate();
+ // Beta sorting algorithm will fail currently in some cases, use the TW fallback
+ _launcherManagerHandler.TryOrderByLoadOrderTW(Enumerable.Empty(), x => loadOrder.TryGetValue(x, out var isSelected) && isSelected, out _, out orderedModules, true);
+ SetViewModels(orderedModules); // Set the ViewModels regarding the result
- _launcherManagerHandler.SetGameParametersLoadOrder(Modules2);
+ //TryOrderByLoadOrder(Enumerable.Empty(), x => loadOrder.TryGetValue(x, out var isSelected) && isSelected);
}
+ }
+
+ private void SetViewModels(IEnumerable orderedModuleViewModels)
+ {
+ Modules2.Clear();
+ foreach (var viewModel in orderedModuleViewModels.OfType())
+ Modules2.Add(viewModel);
- private IEnumerable ValidateModule(BUTRLauncherModuleVM moduleVM) => SortHelper.ValidateModule(Modules2, _modulesLookup, moduleVM);
- private void ToggleModuleSelection(BUTRLauncherModuleVM moduleVM)
+ _launcherManagerHandler.RefreshModules();
+ _allModuleInfos = _launcherManagerHandler.GetAllModules();
+
+ // Validate all VM's after they were selected and ordered
+ foreach (var modules in Modules2)
{
- SortHelper.ToggleModuleSelection(Modules2, _modulesLookup, moduleVM);
- _launcherManagerHandler.SetGameParametersLoadOrder(Modules2);
+ modules.Validate();
+ modules.Refresh();
}
- private void ChangeModulePosition(BUTRLauncherModuleVM targetModuleVM, int insertIndex, Action>? onIssues = null)
+ _launcherManagerHandler.SetGameParametersLoadOrder(Modules2);
+ }
+
+ private IEnumerable ValidateModule(BUTRLauncherModuleVM moduleVM) => SortHelper.ValidateModule(Modules2, _modulesLookup, moduleVM);
+ private void ToggleModuleSelection(BUTRLauncherModuleVM moduleVM)
+ {
+ SortHelper.ToggleModuleSelection(Modules2, _modulesLookup, moduleVM);
+ _launcherManagerHandler.SetGameParametersLoadOrder(Modules2);
+ }
+ private ICollection GetPossibleProviders(ModuleInfoExtendedWithMetadata moduleInfo) => _allModuleInfos
+ .Where(x => x.Id == moduleInfo.Id && x.ModuleProviderType != moduleInfo.ModuleProviderType)
+ .Select(x => x.ModuleProviderType)
+ .ToList();
+
+ private void ChangeModulePosition(BUTRLauncherModuleVM targetModuleVM, int insertIndex, Action>? onIssues = null)
+ {
+ if (SortHelper.ChangeModulePosition(Modules2, _modulesLookup, targetModuleVM, insertIndex, onIssues))
{
- if (SortHelper.ChangeModulePosition(Modules2, _modulesLookup, targetModuleVM, insertIndex, onIssues))
- {
- _launcherManagerHandler.SetGameParametersLoadOrder(Modules2);
- }
+ _launcherManagerHandler.SetGameParametersLoadOrder(Modules2);
}
+ }
- private void SearchTextChanged()
+ private void SearchTextChanged()
+ {
+ var searchText = SearchText;
+ if (string.IsNullOrEmpty(searchText))
{
- var searchText = SearchText;
- if (string.IsNullOrEmpty(searchText))
- {
- foreach (var moduleVM in Modules2)
- {
- moduleVM.IsVisible = true;
- }
- return;
- }
-
foreach (var moduleVM in Modules2)
{
- moduleVM.IsVisible = moduleVM.Name.IndexOf(SearchText, StringComparison.OrdinalIgnoreCase) != -1;
+ moduleVM.IsVisible = true;
}
+ return;
}
- [BUTRDataSourceMethod]
- public void ExecuteRefresh()
+ foreach (var moduleVM in Modules2)
{
- static IEnumerable Sort(IEnumerable source)
- {
- var orderedModules = source
- .OrderByDescending(x => x.IsOfficial)
- .ThenBy(x => x.Id, new AlphanumComparatorFast())
- .ToArray();
+ moduleVM.IsVisible = moduleVM.Name.IndexOf(SearchText, StringComparison.OrdinalIgnoreCase) != -1;
+ }
+ }
- return ModuleSorter.TopologySort(orderedModules, module => ModuleUtilities.GetDependencies(orderedModules, module));
- }
+ [BUTRDataSourceMethod]
+ public void ExecuteRefresh()
+ {
+ static IEnumerable Sort(IEnumerable source)
+ {
+ var orderedModules = source
+ .OrderByDescending(x => x.IsOfficial)
+ .ThenBy(x => x.Id, new AlphanumComparatorFast())
+ .ToArray();
- var sorted = Sort(Modules2.Select(x => x.ModuleInfoExtended)).Select((x, i) => new { Item = x.Id, Index = i }).ToDictionary(x => x.Item, x => x.Index);
- Modules2.Sort(new ByIndexComparer(x => sorted.TryGetValue(x.ModuleInfoExtended.Id, out var idx) ? idx : -1));
- //var sorted = Sort(Modules2.Select(x => x.ModuleInfoExtended)).Select(x => x.Id).ToList();
- //SortBy(sorted);
- _launcherManagerHandler.SetGameParametersLoadOrder(Modules2);
+ return ModuleSorter.TopologySort(orderedModules, module => ModuleUtilities.GetDependencies(orderedModules, module));
}
- [BUTRDataSourceMethod]
- public void OnDrop(BUTRLauncherModuleVM targetModuleVM, int insertIndex, string type)
+ var sorted = Sort(Modules2.Select(x => x.ModuleInfoExtended)).Select((x, i) => new { Item = x.Id, Index = i }).ToDictionary(x => x.Item, x => x.Index);
+ Modules2.Sort(new ByIndexComparer(x => sorted.TryGetValue(x.ModuleInfoExtended.Id, out var idx) ? idx : -1));
+ //var sorted = Sort(Modules2.Select(x => x.ModuleInfoExtended)).Select(x => x.Id).ToList();
+ //SortBy(sorted);
+
+ _launcherManagerHandler.RefreshModules();
+ _allModuleInfos = _launcherManagerHandler.GetAllModules();
+ foreach (var moduleVM in Modules2)
+ moduleVM.Refresh();
+
+ _launcherManagerHandler.SetGameParametersLoadOrder(Modules2);
+ }
+
+ [BUTRDataSourceMethod]
+ public void OnDrop(BUTRLauncherModuleVM targetModuleVM, int insertIndex, string type)
+ {
+ if (type == "Module")
{
- if (type == "Module")
+ ChangeModulePosition(targetModuleVM, insertIndex, issues =>
{
- ChangeModulePosition(targetModuleVM, insertIndex, issues =>
+ HintManager.ShowHint(new BUTRTextObject("{=sP1a61KE}Failed to place the module to the desired position! Placing to the nearest available!{NL}Reason:{NL}{REASONS}")
+ .SetTextVariable("REASONS", string.Join("\n", issues)).ToString());
+ Task.Factory.StartNew(async () =>
{
- HintManager.ShowHint(new BUTRTextObject("{=sP1a61KE}Failed to place the module to the desired position! Placing to the nearest available!{NL}Reason:{NL}{REASONS}")
- .SetTextVariable("REASONS", string.Join("\n", issues)).ToString());
- Task.Factory.StartNew(async () =>
- {
- await Task.Delay(5000);
- HintManager.HideHint();
- }, CancellationToken.None, TaskCreationOptions.AttachedToParent, TaskScheduler.Current);
- });
- }
+ await Task.Delay(5000);
+ HintManager.HideHint();
+ }, CancellationToken.None, TaskCreationOptions.AttachedToParent, TaskScheduler.Current);
+ });
}
+ }
- [BUTRDataSourceMethod]
- public void ExecuteGlobalCheckbox()
+ [BUTRDataSourceMethod]
+ public void ExecuteUpdateCheck()
+ {
+ try
{
- GlobalCheckboxState = !GlobalCheckboxState;
+ var uploadUrlAttr = typeof(LauncherModsVMMixin).Assembly.GetCustomAttributes().FirstOrDefault(a => a.Key == "BUTRCompatibilityScoreUrl");
+ if (uploadUrlAttr is null)
+ return;
+
+ var gameVersion = ApplicationVersionHelper.GameVersion() ?? ApplicationVersion.Empty;
+ var selectedModules = Modules2.Select(x => new
+ {
+ ModuleId = x.ModuleInfoExtended.Id,
+ ModuleVersion = x.ModuleInfoExtended.Version.ToString()
+ }).ToArray();
+ var data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new
+ {
+ GameVersion = $"{ApplicationVersion.GetPrefix(gameVersion.ApplicationVersionType)}{gameVersion.Major}.{gameVersion.Minor}.{gameVersion.Revision}",
+ Modules = selectedModules
+ }));
+
+ var responseDefinition = new { Modules = new[] { new { ModuleId = "", Compatibility = 0d, RecommendedModuleVersion = "" } } };
+
+ var httpWebRequest = WebRequest.CreateHttp(uploadUrlAttr.Value);
+ httpWebRequest.Method = "POST";
+ httpWebRequest.ContentType = "application/json";
+ httpWebRequest.UserAgent = $"BLSE LauncherEx v{typeof(LauncherModsVMMixin).Assembly.GetName().Version}";
+ httpWebRequest.Headers.Add("Tenant", "1");
+
+ using var writeStream = httpWebRequest.GetRequestStream();
+ writeStream.Write(data, 0, data.Length);
+
+ using var response = httpWebRequest.GetResponse();
+ using var stream = response.GetResponseStream();
+ using var responseReader = new StreamReader(stream ?? Stream.Null);
+ var json = responseReader.ReadLine() ?? string.Empty;
+ var result = JsonConvert.DeserializeAnonymousType(json, responseDefinition);
+ if (result is null) return;
foreach (var moduleVM in Modules2)
+ moduleVM.RemoveUpdateInfo();
+
+ foreach (var module in result.Modules)
{
- if (GlobalCheckboxState)
- {
- if (moduleVM.IsValid && !moduleVM.IsSelected)
- ToggleModuleSelection(moduleVM);
- }
- else
- {
- if (!moduleVM.ModuleInfoExtended.IsNative() && moduleVM.IsSelected)
- ToggleModuleSelection(moduleVM);
- }
+ if (Modules2.FirstOrDefault(x => x.ModuleInfoExtended.Id == module.ModuleId) is not { } moduleVM) continue;
+ if (module.Compatibility > 0d)
+ moduleVM.SetUpdateInfo(module.Compatibility, module.RecommendedModuleVersion);
+ }
+ }
+ catch (Exception) { /* ignore */ }
+ }
+
+ [BUTRDataSourceMethod]
+ public void ExecuteGlobalCheckbox()
+ {
+ GlobalCheckboxState = !GlobalCheckboxState;
+
+ foreach (var moduleVM in Modules2)
+ {
+ if (GlobalCheckboxState)
+ {
+ if (moduleVM.IsValid && !moduleVM.IsSelected)
+ ToggleModuleSelection(moduleVM);
+ }
+ else
+ {
+ if (!moduleVM.ModuleInfoExtended.IsNative() && moduleVM.IsSelected)
+ ToggleModuleSelection(moduleVM);
}
}
}
diff --git a/src/Bannerlord.LauncherEx/Mixins/LauncherNewsVMMixin.cs b/src/Bannerlord.LauncherEx/Mixins/LauncherNewsVMMixin.cs
index 4521185..130371e 100644
--- a/src/Bannerlord.LauncherEx/Mixins/LauncherNewsVMMixin.cs
+++ b/src/Bannerlord.LauncherEx/Mixins/LauncherNewsVMMixin.cs
@@ -2,14 +2,13 @@
using TaleWorlds.MountAndBlade.Launcher.Library;
-namespace Bannerlord.LauncherEx.Mixins
+namespace Bannerlord.LauncherEx.Mixins;
+
+internal sealed class LauncherNewsVMMixin : ViewModelMixin
{
- internal sealed class LauncherNewsVMMixin : ViewModelMixin
- {
- [BUTRDataSourceProperty]
- public bool IsDisabled2 { get => _isDisabled2; set => SetField(ref _isDisabled2, value); }
- private bool _isDisabled2;
-
- public LauncherNewsVMMixin(LauncherNewsVM launcherNewsVM) : base(launcherNewsVM) { }
- }
+ [BUTRDataSourceProperty]
+ public bool IsDisabled2 { get => _isDisabled2; set => SetField(ref _isDisabled2, value); }
+ private bool _isDisabled2;
+
+ public LauncherNewsVMMixin(LauncherNewsVM launcherNewsVM) : base(launcherNewsVM) { }
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Mixins/LauncherVMMixin.cs b/src/Bannerlord.LauncherEx/Mixins/LauncherVMMixin.cs
index df5aa48..bfbe935 100644
--- a/src/Bannerlord.LauncherEx/Mixins/LauncherVMMixin.cs
+++ b/src/Bannerlord.LauncherEx/Mixins/LauncherVMMixin.cs
@@ -17,525 +17,524 @@
using TaleWorlds.MountAndBlade.Launcher.Library;
using TaleWorlds.MountAndBlade.Launcher.Library.UserDatas;
-namespace Bannerlord.LauncherEx.Mixins
+namespace Bannerlord.LauncherEx.Mixins;
+
+internal sealed class LauncherVMMixin : ViewModelMixin
{
- internal sealed class LauncherVMMixin : ViewModelMixin
- {
- private delegate void ExecuteConfirmUnverifiedDLLStartDelegate(LauncherVM instance);
- private static readonly ExecuteConfirmUnverifiedDLLStartDelegate? ExecuteConfirmUnverifiedDLLStartOriginal =
- AccessTools2.GetDelegate(typeof(LauncherVM), "ExecuteConfirmUnverifiedDLLStart");
+ private delegate void ExecuteConfirmUnverifiedDLLStartDelegate(LauncherVM instance);
+ private static readonly ExecuteConfirmUnverifiedDLLStartDelegate? ExecuteConfirmUnverifiedDLLStartOriginal =
+ AccessTools2.GetDelegate(typeof(LauncherVM), "ExecuteConfirmUnverifiedDLLStart");
- private delegate void ExecuteStartGameDelegate(LauncherVM instance, int mode);
- private static readonly ExecuteStartGameDelegate? ExecuteStartGame =
- AccessTools2.GetDelegate(typeof(LauncherVM), "ExecuteStartGame");
+ private delegate void ExecuteStartGameDelegate(LauncherVM instance, int mode);
+ private static readonly ExecuteStartGameDelegate? ExecuteStartGame =
+ AccessTools2.GetDelegate(typeof(LauncherVM), "ExecuteStartGame");
- private static readonly AccessTools.FieldRef? UserDataManagerFieldRef =
- AccessTools2.FieldRefAccess("_userDataManager");
+ private static readonly AccessTools.FieldRef? UserDataManagerFieldRef =
+ AccessTools2.FieldRefAccess("_userDataManager");
- private delegate void SetIsDigitalCompanionDelegate(LauncherVM instance, bool value);
- private static readonly SetIsDigitalCompanionDelegate? SetIsDigitalCompanion =
- AccessTools2.GetPropertySetterDelegate(typeof(LauncherVM), "IsDigitalCompanion");
+ private delegate void SetIsDigitalCompanionDelegate(LauncherVM instance, bool value);
+ private static readonly SetIsDigitalCompanionDelegate? SetIsDigitalCompanion =
+ AccessTools2.GetPropertySetterDelegate(typeof(LauncherVM), "IsDigitalCompanion");
- private delegate void UpdateAndSaveUserModsDataDelegate(LauncherVM instance, bool isMultiplayer);
- private static readonly UpdateAndSaveUserModsDataDelegate? UpdateAndSaveUserModsDataMethod =
- AccessTools2.GetDelegate(typeof(LauncherVM), "UpdateAndSaveUserModsData");
+ private delegate void UpdateAndSaveUserModsDataDelegate(LauncherVM instance, bool isMultiplayer);
+ private static readonly UpdateAndSaveUserModsDataDelegate? UpdateAndSaveUserModsDataMethod =
+ AccessTools2.GetDelegate(typeof(LauncherVM), "UpdateAndSaveUserModsData");
- private delegate void RefreshDelegate(LauncherVM instance);
- private static readonly RefreshDelegate? Refresh =
- AccessTools2.GetDelegate(typeof(LauncherVM), "Refresh");
+ private delegate void RefreshDelegate(LauncherVM instance);
+ private static readonly RefreshDelegate? Refresh =
+ AccessTools2.GetDelegate(typeof(LauncherVM), "Refresh");
- private enum TopTabs { NONE, Singleplayer, Multiplayer, Options, DigitalCompanion }
- private TopTabs _state;
+ private enum TopTabs { NONE, Singleplayer, Multiplayer, Options, DigitalCompanion }
+ private TopTabs _state;
- [BUTRDataSourceProperty]
- public bool IsSingleplayer2
+ [BUTRDataSourceProperty]
+ public bool IsSingleplayer2
+ {
+ get => _state == TopTabs.Singleplayer;
+ set
{
- get => _state == TopTabs.Singleplayer;
- set
+ if (value && _state != TopTabs.Singleplayer && ViewModel is not null)
{
- if (value && _state != TopTabs.Singleplayer && ViewModel is not null)
+ if (_state == TopTabs.Options)
{
- if (_state == TopTabs.Options)
- {
- SaveOptions();
- }
+ SaveOptions();
+ }
- _state = TopTabs.Singleplayer;
+ _state = TopTabs.Singleplayer;
- SetState();
- }
+ SetState();
}
}
+ }
- [BUTRDataSourceProperty]
- public bool IsMultiplayer2
+ [BUTRDataSourceProperty]
+ public bool IsMultiplayer2
+ {
+ get => _state == TopTabs.Multiplayer;
+ set
{
- get => _state == TopTabs.Multiplayer;
- set
+ if (value && _state != TopTabs.Multiplayer && ViewModel is not null)
{
- if (value && _state != TopTabs.Multiplayer && ViewModel is not null)
+ if (_state == TopTabs.Options)
{
- if (_state == TopTabs.Options)
- {
- SaveOptions();
- }
+ SaveOptions();
+ }
- _state = TopTabs.Multiplayer;
+ _state = TopTabs.Multiplayer;
- SetState();
- }
+ SetState();
}
}
+ }
- [BUTRDataSourceProperty]
- public bool IsOptions
+ [BUTRDataSourceProperty]
+ public bool IsOptions
+ {
+ get => _state == TopTabs.Options;
+ set
{
- get => _state == TopTabs.Options;
- set
+ if (value && _state != TopTabs.Options && ViewModel is not null)
{
- if (value && _state != TopTabs.Options && ViewModel is not null)
- {
- _state = TopTabs.Options;
+ _state = TopTabs.Options;
- SetState();
- }
+ SetState();
}
}
+ }
- [BUTRDataSourceProperty]
- public bool IsDigitalCompanion2
+ [BUTRDataSourceProperty]
+ public bool IsDigitalCompanion2
+ {
+ get => _state == TopTabs.DigitalCompanion;
+ set
{
- get => _state == TopTabs.DigitalCompanion;
- set
+ if (value && _state != TopTabs.DigitalCompanion && ViewModel is not null)
{
- if (value && _state != TopTabs.DigitalCompanion && ViewModel is not null)
+ if (_state == TopTabs.Options)
{
- if (_state == TopTabs.Options)
- {
- SaveOptions();
- }
+ SaveOptions();
+ }
- _state = TopTabs.DigitalCompanion;
+ _state = TopTabs.DigitalCompanion;
- SetState();
- }
+ SetState();
}
}
+ }
- [BUTRDataSourceProperty]
- public bool IsModsDataSelected
+ [BUTRDataSourceProperty]
+ public bool IsModsDataSelected
+ {
+ get => _isModsDataSelected;
+ set
{
- get => _isModsDataSelected;
- set
+ if (SetField(ref _isModsDataSelected, value))
{
- if (SetField(ref _isModsDataSelected, value))
- {
- OnPropertyChanged(nameof(ShowImportExport));
- OnPropertyChanged(nameof(ShowContinueSingleplayerButton));
- }
+ OnPropertyChanged(nameof(ShowImportExport));
+ OnPropertyChanged(nameof(ShowContinueSingleplayerButton));
}
}
- private bool _isModsDataSelected;
+ }
+ private bool _isModsDataSelected;
- [BUTRDataSourceProperty]
- public bool IsSavesDataSelected
+ [BUTRDataSourceProperty]
+ public bool IsSavesDataSelected
+ {
+ get => _isSavesDataSelected;
+ set
{
- get => _isSavesDataSelected;
- set
+ if (SetField(ref _isSavesDataSelected, value))
{
- if (SetField(ref _isSavesDataSelected, value))
- {
- OnPropertyChanged(nameof(ShowPlaySingleplayerButton));
- OnPropertyChanged(nameof(ShowContinueSingleplayerButton));
- OnPropertyChanged(nameof(ShowImportExport));
- }
+ OnPropertyChanged(nameof(ShowPlaySingleplayerButton));
+ OnPropertyChanged(nameof(ShowContinueSingleplayerButton));
+ OnPropertyChanged(nameof(ShowImportExport));
}
}
- private bool _isSavesDataSelected;
+ }
+ private bool _isSavesDataSelected;
- [BUTRDataSourceProperty]
- public HorizontalAlignment PlayButtonAlignment => _state == TopTabs.Singleplayer ? HorizontalAlignment.Right : HorizontalAlignment.Center;
+ [BUTRDataSourceProperty]
+ public HorizontalAlignment PlayButtonAlignment => _state == TopTabs.Singleplayer ? HorizontalAlignment.Right : HorizontalAlignment.Center;
- [BUTRDataSourceProperty]
- public bool RandomImageSwitch { get => _randomImageSwitch; set => SetField(ref _randomImageSwitch, value); }
- private bool _randomImageSwitch;
-
- [BUTRDataSourceProperty]
- public string OptionsText { get => _optionsText; set => SetField(ref _optionsText, value); }
- private string _optionsText = new BUTRTextObject("{=yS5hbWCL}Options").ToString();
-
- [BUTRDataSourceProperty]
- public string LauncherText { get => _launcherText; set => SetField(ref _launcherText, value); }
- private string _launcherText = new BUTRTextObject("{=V66qoU6n}Launcher").ToString();
-
- [BUTRDataSourceProperty]
- public string GameText { get => _gameText; set => SetField(ref _gameText, value); }
- private string _gameText = new BUTRTextObject("{=ro4RMgyt}Game").ToString();
-
- [BUTRDataSourceProperty]
- public string EngineText { get => _engineText; set => SetField(ref _engineText, value); }
- private string _engineText = new BUTRTextObject("{=q4rQuTgG}Engine").ToString();
-
- [BUTRDataSourceProperty]
- public string SavesText { get => _savesText; set => SetField(ref _savesText, value); }
- private string _savesText = new BUTRTextObject("{=d5OjKcGE}Saves").ToString();
-
- [BUTRDataSourceProperty]
- public string BLSEVersionText { get => _blseVersionText; set => SetField(ref _blseVersionText, value); }
- private string _blseVersionText;
-
- [BUTRDataSourceProperty]
- public string BUTRLoaderVersionText { get => _butrLoaderVersionText; set => SetField(ref _butrLoaderVersionText, value); }
- private string _butrLoaderVersionText;
-
- [BUTRDataSourceProperty]
- public BUTRLauncherOptionsVM OptionsLauncherData { get => _optionsLauncherData; set => SetField(ref _optionsLauncherData, value); }
- private BUTRLauncherOptionsVM _optionsLauncherData;
-
- [BUTRDataSourceProperty]
- public BUTRLauncherOptionsVM OptionsGameData { get => _optionsGameData; set => SetField(ref _optionsGameData, value); }
- private BUTRLauncherOptionsVM _optionsGameData;
-
- [BUTRDataSourceProperty]
- public BUTRLauncherOptionsVM OptionsEngineData { get => _optionsEngineData; set => SetField(ref _optionsEngineData, value); }
- private BUTRLauncherOptionsVM _optionsEngineData;
-
- [BUTRDataSourceProperty]
- public BUTRLauncherSavesVM? SavesData { get => _savesData; set => SetField(ref _savesData, value); }
- private BUTRLauncherSavesVM? _savesData;
-
- [BUTRDataSourceProperty]
- public BUTRLauncherMessageBoxVM? MessageBox { get => _messageBox; set => SetField(ref _messageBox, value); }
- private BUTRLauncherMessageBoxVM? _messageBox = new();
-
- [BUTRDataSourceProperty]
- public bool ShowMods => IsSingleplayer2 || IsMultiplayer2;
- [BUTRDataSourceProperty]
- public bool ShowNews => IsSingleplayer2 || IsMultiplayer2 || IsDigitalCompanion2;
-
- [BUTRDataSourceProperty]
- public bool ShowRandomImage { get => _showRandomImage; set => SetField(ref _showRandomImage, value); }
- private bool _showRandomImage;
-
- [BUTRDataSourceProperty]
- public bool ShowImportExport => IsSingleplayer2 && (IsModsDataSelected || (IsSavesDataSelected && SavesData?.Selected is not null));
-
- [BUTRDataSourceProperty]
- public bool ShowBUTRLoaderVersionText => IsSingleplayer2 || IsOptions;
-
- [BUTRDataSourceProperty]
- public bool ShowPlaySingleplayerButton => IsSingleplayer2 && !IsSavesDataSelected;
- [BUTRDataSourceProperty]
- public bool ShowContinueSingleplayerButton => IsSingleplayer2 && (!IsSavesDataSelected || SavesData?.Selected is not null);
-
- [BUTRDataSourceProperty]
- public float ContentTabControlMarginRight { get => _contentTabControlMarginRight; set => SetField(ref _contentTabControlMarginRight, value); }
- private float _contentTabControlMarginRight = 0;
-
- [BUTRDataSourceProperty]
- public float ContentTabControlMarginBottom { get => _contentTabControlMarginBottom; set => SetField(ref _contentTabControlMarginBottom, value); }
- private float _contentTabControlMarginBottom = 114;
-
- [BUTRDataSourceProperty]
- public float BUTRLoaderVersionMarginBottom { get => _butrLoaderVersionMarginBottom; set => SetField(ref _butrLoaderVersionMarginBottom, value); }
- private float _butrLoaderVersionMarginBottom = 90;
-
- [BUTRDataSourceProperty]
- public float BLSEVersionMarginBottom { get => _blseLoaderVersionMarginBottom; set => SetField(ref _blseLoaderVersionMarginBottom, value); }
- private float _blseLoaderVersionMarginBottom = 70;
-
- [BUTRDataSourceProperty]
- public float DividerMarginBottom { get => _dividerMarginBottom; set => SetField(ref _dividerMarginBottom, value); }
- private float _dividerMarginBottom = 113;
-
- [BUTRDataSourceProperty]
- public float BackgroundHeight { get => _backgroundHeight; set => SetField(ref _backgroundHeight, value); }
- private float _backgroundHeight = 581; // 700
-
- [BUTRDataSourceProperty]
- public string SingleplayerText2 => new BUTRTextObject("{=Hk7FBBSa}Singleplayer").ToString();
- [BUTRDataSourceProperty]
- public string MultiplayerText2 => new BUTRTextObject("{=UOGhdUWE}Multiplayer").ToString();
- [BUTRDataSourceProperty]
- public string DigitalCompanionText2 => new BUTRTextObject("{=VDTcZpPr}Digital Companion").ToString();
- [BUTRDataSourceProperty]
- public string NewsText2 => new BUTRTextObject("{=Tg0If68v}News").ToString();
- [BUTRDataSourceProperty]
- public string ModsText2 => new BUTRTextObject("{=YGU9eXM0}Mods").ToString();
- [BUTRDataSourceProperty]
- public string PlayText2 => new BUTRTextObject("{=xYv4iv7C}PLAY").ToString();
- [BUTRDataSourceProperty]
- public string ContinueText2 => new BUTRTextObject("{=6B3iZLqR}CONTINUE").ToString();
- [BUTRDataSourceProperty]
- public string LaunchText2 => new BUTRTextObject("{=eUt6GKkQ}LAUNCH").ToString();
-
- private readonly UserDataManager? _userDataManager;
- private readonly LauncherModsVMMixin? _launcherModsVMMixin;
- private readonly BUTRLauncherManagerHandler _launcherManagerHandler = BUTRLauncherManagerHandler.Default;
-
- private ModuleListHandler? _currentModuleListHandler;
-
- public LauncherVMMixin(LauncherVM launcherVM) : base(launcherVM)
- {
- _launcherManagerHandler.RegisterStateProvider(() => new LauncherState(isSingleplayer: IsSingleplayer2));
+ [BUTRDataSourceProperty]
+ public bool RandomImageSwitch { get => _randomImageSwitch; set => SetField(ref _randomImageSwitch, value); }
+ private bool _randomImageSwitch;
+
+ [BUTRDataSourceProperty]
+ public string OptionsText { get => _optionsText; set => SetField(ref _optionsText, value); }
+ private string _optionsText = new BUTRTextObject("{=yS5hbWCL}Options").ToString();
+
+ [BUTRDataSourceProperty]
+ public string LauncherText { get => _launcherText; set => SetField(ref _launcherText, value); }
+ private string _launcherText = new BUTRTextObject("{=V66qoU6n}Launcher").ToString();
+
+ [BUTRDataSourceProperty]
+ public string GameText { get => _gameText; set => SetField(ref _gameText, value); }
+ private string _gameText = new BUTRTextObject("{=ro4RMgyt}Game").ToString();
+
+ [BUTRDataSourceProperty]
+ public string EngineText { get => _engineText; set => SetField(ref _engineText, value); }
+ private string _engineText = new BUTRTextObject("{=q4rQuTgG}Engine").ToString();
+
+ [BUTRDataSourceProperty]
+ public string SavesText { get => _savesText; set => SetField(ref _savesText, value); }
+ private string _savesText = new BUTRTextObject("{=d5OjKcGE}Saves").ToString();
+
+ [BUTRDataSourceProperty]
+ public string BLSEVersionText { get => _blseVersionText; set => SetField(ref _blseVersionText, value); }
+ private string _blseVersionText;
+
+ [BUTRDataSourceProperty]
+ public string BUTRLoaderVersionText { get => _butrLoaderVersionText; set => SetField(ref _butrLoaderVersionText, value); }
+ private string _butrLoaderVersionText;
+
+ [BUTRDataSourceProperty]
+ public BUTRLauncherOptionsVM OptionsLauncherData { get => _optionsLauncherData; set => SetField(ref _optionsLauncherData, value); }
+ private BUTRLauncherOptionsVM _optionsLauncherData;
+
+ [BUTRDataSourceProperty]
+ public BUTRLauncherOptionsVM OptionsGameData { get => _optionsGameData; set => SetField(ref _optionsGameData, value); }
+ private BUTRLauncherOptionsVM _optionsGameData;
+
+ [BUTRDataSourceProperty]
+ public BUTRLauncherOptionsVM OptionsEngineData { get => _optionsEngineData; set => SetField(ref _optionsEngineData, value); }
+ private BUTRLauncherOptionsVM _optionsEngineData;
+
+ [BUTRDataSourceProperty]
+ public BUTRLauncherSavesVM? SavesData { get => _savesData; set => SetField(ref _savesData, value); }
+ private BUTRLauncherSavesVM? _savesData;
+
+ [BUTRDataSourceProperty]
+ public BUTRLauncherMessageBoxVM? MessageBox { get => _messageBox; set => SetField(ref _messageBox, value); }
+ private BUTRLauncherMessageBoxVM? _messageBox = new();
+
+ [BUTRDataSourceProperty]
+ public bool ShowMods => IsSingleplayer2 || IsMultiplayer2;
+ [BUTRDataSourceProperty]
+ public bool ShowNews => IsSingleplayer2 || IsMultiplayer2 || IsDigitalCompanion2;
+
+ [BUTRDataSourceProperty]
+ public bool ShowRandomImage { get => _showRandomImage; set => SetField(ref _showRandomImage, value); }
+ private bool _showRandomImage;
+
+ [BUTRDataSourceProperty]
+ public bool ShowImportExport => IsSingleplayer2 && (IsModsDataSelected || (IsSavesDataSelected && SavesData?.Selected is not null));
+
+ [BUTRDataSourceProperty]
+ public bool ShowBUTRLoaderVersionText => IsSingleplayer2 || IsOptions;
+
+ [BUTRDataSourceProperty]
+ public bool ShowPlaySingleplayerButton => IsSingleplayer2 && !IsSavesDataSelected;
+ [BUTRDataSourceProperty]
+ public bool ShowContinueSingleplayerButton => IsSingleplayer2 && (!IsSavesDataSelected || SavesData?.Selected is not null);
+
+ [BUTRDataSourceProperty]
+ public float ContentTabControlMarginRight { get => _contentTabControlMarginRight; set => SetField(ref _contentTabControlMarginRight, value); }
+ private float _contentTabControlMarginRight = 0;
+
+ [BUTRDataSourceProperty]
+ public float ContentTabControlMarginBottom { get => _contentTabControlMarginBottom; set => SetField(ref _contentTabControlMarginBottom, value); }
+ private float _contentTabControlMarginBottom = 114;
+
+ [BUTRDataSourceProperty]
+ public float BUTRLoaderVersionMarginBottom { get => _butrLoaderVersionMarginBottom; set => SetField(ref _butrLoaderVersionMarginBottom, value); }
+ private float _butrLoaderVersionMarginBottom = 90;
+
+ [BUTRDataSourceProperty]
+ public float BLSEVersionMarginBottom { get => _blseLoaderVersionMarginBottom; set => SetField(ref _blseLoaderVersionMarginBottom, value); }
+ private float _blseLoaderVersionMarginBottom = 70;
+
+ [BUTRDataSourceProperty]
+ public float DividerMarginBottom { get => _dividerMarginBottom; set => SetField(ref _dividerMarginBottom, value); }
+ private float _dividerMarginBottom = 113;
+
+ [BUTRDataSourceProperty]
+ public float BackgroundHeight { get => _backgroundHeight; set => SetField(ref _backgroundHeight, value); }
+ private float _backgroundHeight = 581; // 700
+
+ [BUTRDataSourceProperty]
+ public string SingleplayerText2 => new BUTRTextObject("{=Hk7FBBSa}Singleplayer").ToString();
+ [BUTRDataSourceProperty]
+ public string MultiplayerText2 => new BUTRTextObject("{=UOGhdUWE}Multiplayer").ToString();
+ [BUTRDataSourceProperty]
+ public string DigitalCompanionText2 => new BUTRTextObject("{=VDTcZpPr}Digital Companion").ToString();
+ [BUTRDataSourceProperty]
+ public string NewsText2 => new BUTRTextObject("{=Tg0If68v}News").ToString();
+ [BUTRDataSourceProperty]
+ public string ModsText2 => new BUTRTextObject("{=YGU9eXM0}Mods").ToString();
+ [BUTRDataSourceProperty]
+ public string PlayText2 => new BUTRTextObject("{=xYv4iv7C}PLAY").ToString();
+ [BUTRDataSourceProperty]
+ public string ContinueText2 => new BUTRTextObject("{=6B3iZLqR}CONTINUE").ToString();
+ [BUTRDataSourceProperty]
+ public string LaunchText2 => new BUTRTextObject("{=eUt6GKkQ}LAUNCH").ToString();
+
+ private readonly UserDataManager? _userDataManager;
+ private readonly LauncherModsVMMixin? _launcherModsVMMixin;
+ private readonly BUTRLauncherManagerHandler _launcherManagerHandler = BUTRLauncherManagerHandler.Default;
+
+ private ModuleListHandler? _currentModuleListHandler;
+
+ public LauncherVMMixin(LauncherVM launcherVM) : base(launcherVM)
+ {
+ _launcherManagerHandler.RegisterStateProvider(() => new LauncherState(isSingleplayer: IsSingleplayer2));
- _userDataManager = UserDataManagerFieldRef?.Invoke(launcherVM);
+ _userDataManager = UserDataManagerFieldRef?.Invoke(launcherVM);
- var blseMetadata = AccessTools2.TypeByName("Bannerlord.BLSE.BLSEInterceptorAttribute")?.Assembly.GetCustomAttributes();
- var launcherExMetadata = typeof(LauncherVMMixin).Assembly.GetCustomAttributes();
- _blseVersionText = $"BLSE v{blseMetadata?.FirstOrDefault(x => x.Key == "BLSEVersion")?.Value ?? "0.0.0.0"}";
- _butrLoaderVersionText = $"LauncherEx v{launcherExMetadata.FirstOrDefault(x => x.Key == "LauncherExVersion")?.Value ?? "0.0.0.0"}";
+ var blseMetadata = AccessTools2.TypeByName("Bannerlord.BLSE.BLSEInterceptorAttribute")?.Assembly.GetCustomAttributes();
+ var launcherExMetadata = typeof(LauncherVMMixin).Assembly.GetCustomAttributes();
+ _blseVersionText = $"BLSE v{blseMetadata?.FirstOrDefault(x => x.Key == "BLSEVersion")?.Value ?? "0.0.0.0"}";
+ _butrLoaderVersionText = $"LauncherEx v{launcherExMetadata.FirstOrDefault(x => x.Key == "LauncherExVersion")?.Value ?? "0.0.0.0"}";
- _optionsEngineData = new BUTRLauncherOptionsVM(OptionsType.Engine, SaveUserData, RefreshOptions);
- _optionsGameData = new BUTRLauncherOptionsVM(OptionsType.Game, SaveUserData, RefreshOptions);
- _optionsLauncherData = new BUTRLauncherOptionsVM(OptionsType.Launcher, SaveUserData, RefreshOptions);
+ _optionsEngineData = new BUTRLauncherOptionsVM(OptionsType.Engine, SaveUserData, RefreshOptions);
+ _optionsGameData = new BUTRLauncherOptionsVM(OptionsType.Game, SaveUserData, RefreshOptions);
+ _optionsLauncherData = new BUTRLauncherOptionsVM(OptionsType.Launcher, SaveUserData, RefreshOptions);
- if (launcherVM.GetPropertyValue(nameof(LauncherVM.ModsData)) is LauncherModsVM lmvm && lmvm.GetMixin() is { } mixin)
- {
- _launcherModsVMMixin = mixin;
+ if (launcherVM.GetPropertyValue(nameof(LauncherVM.ModsData)) is LauncherModsVM lmvm && lmvm.GetMixin() is { } mixin)
+ {
+ _launcherModsVMMixin = mixin;
- _savesData = new BUTRLauncherSavesVM(mixin.GetModuleById, mixin.GetModuleByName);
- _savesData.PropertyChanged += (_, args) =>
+ _savesData = new BUTRLauncherSavesVM(mixin.GetModuleById, mixin.GetModuleByName);
+ _savesData.PropertyChanged += (_, args) =>
+ {
+ if (args.PropertyName == "SaveSelected")
{
- if (args.PropertyName == "SaveSelected")
- {
- OnPropertyChanged(nameof(ShowImportExport));
- OnPropertyChanged(nameof(ShowContinueSingleplayerButton));
- }
- };
- }
+ OnPropertyChanged(nameof(ShowImportExport));
+ OnPropertyChanged(nameof(ShowContinueSingleplayerButton));
+ }
+ };
+ }
- ShowRandomImage = !LauncherSettings.HideRandomImage;
- ContentTabControlMarginRight = LauncherSettings.HideRandomImage ? 5 : 114;
- BackgroundHeight = LauncherSettings.BigMode ? 700 : 581;
+ ShowRandomImage = !LauncherSettings.HideRandomImage;
+ ContentTabControlMarginRight = LauncherSettings.HideRandomImage ? 5 : 114;
+ BackgroundHeight = LauncherSettings.BigMode ? 700 : 581;
- IsDigitalCompanion2 = (bool?) launcherVM.GetPropertyValue("IsDigitalCompanion") ?? false;
- IsMultiplayer2 = launcherVM.IsMultiplayer;
- IsSingleplayer2 = launcherVM.IsSingleplayer;
+ IsDigitalCompanion2 = (bool?) launcherVM.GetPropertyValue("IsDigitalCompanion") ?? false;
+ IsMultiplayer2 = launcherVM.IsMultiplayer;
+ IsSingleplayer2 = launcherVM.IsSingleplayer;
- Refresh?.Invoke(launcherVM);
- }
+ Refresh?.Invoke(launcherVM);
+ }
- private void SetState()
- {
- if (ViewModel is null) return;
-
- OnPropertyChanged(nameof(IsSingleplayer2));
- OnPropertyChanged(nameof(IsMultiplayer2));
- OnPropertyChanged(nameof(IsOptions));
- OnPropertyChanged(nameof(IsDigitalCompanion2));
- OnPropertyChanged(nameof(ShowBUTRLoaderVersionText));
- OnPropertyChanged(nameof(PlayButtonAlignment));
- OnPropertyChanged(nameof(ShowNews));
- OnPropertyChanged(nameof(ShowMods));
- OnPropertyChanged(nameof(ShowPlaySingleplayerButton));
- OnPropertyChanged(nameof(ShowContinueSingleplayerButton));
-
- ViewModel.IsSingleplayer = IsSingleplayer2;
- ViewModel.IsMultiplayer = IsMultiplayer2;
- SetIsDigitalCompanion?.Invoke(ViewModel, IsDigitalCompanion2);
-
- RandomImageSwitch = !RandomImageSwitch;
-
- ViewModel.News.SetPropertyValue(nameof(LauncherNewsVMMixin.IsDisabled2), !ShowNews);
- ViewModel.ModsData.SetPropertyValue(nameof(LauncherModsVMMixin.IsDisabled2), !ShowMods);
- if (SavesData is not null)
- SavesData.IsDisabled = !IsSingleplayer2;
- OptionsLauncherData.IsDisabled = !IsOptions;
- OptionsGameData.IsDisabled = !IsOptions;
- OptionsEngineData.IsDisabled = !IsOptions;
- if (IsOptions)
- RefreshOptions();
-
- ContentTabControlMarginBottom = IsOptions ? 65 : 114;
- BUTRLoaderVersionMarginBottom = IsOptions ? 45 : 90;
- BLSEVersionMarginBottom = IsOptions ? 25 : 70;
- DividerMarginBottom = IsOptions ? 64 : 113;
- }
+ private void SetState()
+ {
+ if (ViewModel is null) return;
+
+ OnPropertyChanged(nameof(IsSingleplayer2));
+ OnPropertyChanged(nameof(IsMultiplayer2));
+ OnPropertyChanged(nameof(IsOptions));
+ OnPropertyChanged(nameof(IsDigitalCompanion2));
+ OnPropertyChanged(nameof(ShowBUTRLoaderVersionText));
+ OnPropertyChanged(nameof(PlayButtonAlignment));
+ OnPropertyChanged(nameof(ShowNews));
+ OnPropertyChanged(nameof(ShowMods));
+ OnPropertyChanged(nameof(ShowPlaySingleplayerButton));
+ OnPropertyChanged(nameof(ShowContinueSingleplayerButton));
+
+ ViewModel.IsSingleplayer = IsSingleplayer2;
+ ViewModel.IsMultiplayer = IsMultiplayer2;
+ SetIsDigitalCompanion?.Invoke(ViewModel, IsDigitalCompanion2);
+
+ RandomImageSwitch = !RandomImageSwitch;
+
+ ViewModel.News.SetPropertyValue(nameof(LauncherNewsVMMixin.IsDisabled2), !ShowNews);
+ ViewModel.ModsData.SetPropertyValue(nameof(LauncherModsVMMixin.IsDisabled2), !ShowMods);
+ if (SavesData is not null)
+ SavesData.IsDisabled = !IsSingleplayer2;
+ OptionsLauncherData.IsDisabled = !IsOptions;
+ OptionsGameData.IsDisabled = !IsOptions;
+ OptionsEngineData.IsDisabled = !IsOptions;
+ if (IsOptions)
+ RefreshOptions();
+
+ ContentTabControlMarginBottom = IsOptions ? 65 : 114;
+ BUTRLoaderVersionMarginBottom = IsOptions ? 45 : 90;
+ BLSEVersionMarginBottom = IsOptions ? 25 : 70;
+ DividerMarginBottom = IsOptions ? 64 : 113;
+ }
- public void RefreshOptions()
- {
- OptionsLauncherData.Refresh();
- OptionsGameData.Refresh();
- OptionsEngineData.Refresh();
- }
+ public void RefreshOptions()
+ {
+ OptionsLauncherData.Refresh();
+ OptionsGameData.Refresh();
+ OptionsEngineData.Refresh();
+ }
- public void SaveUserData()
- {
- if (ViewModel is null) return;
+ public void SaveUserData()
+ {
+ if (ViewModel is null) return;
- ShowRandomImage = !LauncherSettings.HideRandomImage;
- ContentTabControlMarginRight = LauncherSettings.HideRandomImage ? 5 : 114;
- BackgroundHeight = LauncherSettings.BigMode ? 700 : 581;
- UpdateAndSaveUserModsDataMethod?.Invoke(ViewModel, IsMultiplayer2);
- }
+ ShowRandomImage = !LauncherSettings.HideRandomImage;
+ ContentTabControlMarginRight = LauncherSettings.HideRandomImage ? 5 : 114;
+ BackgroundHeight = LauncherSettings.BigMode ? 700 : 581;
+ UpdateAndSaveUserModsDataMethod?.Invoke(ViewModel, IsMultiplayer2);
+ }
- public void SaveOptions()
- {
- OptionsLauncherData.Save();
- OptionsGameData.Save();
- OptionsEngineData.Save();
- }
+ public void SaveOptions()
+ {
+ OptionsLauncherData.Save();
+ OptionsGameData.Save();
+ OptionsEngineData.Save();
+ }
- // Ensure save is triggered when launching the game
- [BUTRDataSourceMethod]
- public void ExecuteConfirmUnverifiedDLLStart()
- {
- if (ViewModel is null) return;
+ // Ensure save is triggered when launching the game
+ [BUTRDataSourceMethod]
+ public void ExecuteConfirmUnverifiedDLLStart()
+ {
+ if (ViewModel is null) return;
- SaveUserData();
- ExecuteConfirmUnverifiedDLLStartOriginal?.Invoke(ViewModel);
- }
+ SaveUserData();
+ ExecuteConfirmUnverifiedDLLStartOriginal?.Invoke(ViewModel);
+ }
- [BUTRDataSourceMethod]
- public void ExecuteBeginHintImport()
+ [BUTRDataSourceMethod]
+ public void ExecuteBeginHintImport()
+ {
+ if (IsSingleplayer2 && IsModsDataSelected)
{
- if (IsSingleplayer2 && IsModsDataSelected)
- {
- HintManager.ShowHint(new BUTRTextObject("{=Aws9irMU}Import Load Order"));
- }
- if (IsSingleplayer2 && IsSavesDataSelected)
- {
- HintManager.ShowHint(new BUTRTextObject("{=4wKr76gx}Import Save's Load Order"));
- }
+ HintManager.ShowHint(new BUTRTextObject("{=Aws9irMU}Import Load Order"));
}
-
- [BUTRDataSourceMethod]
- public void ExecuteBeginHintExport()
+ if (IsSingleplayer2 && IsSavesDataSelected)
{
- if (IsSingleplayer2 && IsModsDataSelected)
- {
- HintManager.ShowHint(new BUTRTextObject("{=XdZGqnFW}Export Current Load Order"));
- }
- if (IsSingleplayer2 && IsSavesDataSelected)
- {
- HintManager.ShowHint(new BUTRTextObject("{=G55IdM6M}Export Save's Load Order"));
- }
+ HintManager.ShowHint(new BUTRTextObject("{=4wKr76gx}Import Save's Load Order"));
}
+ }
- [BUTRDataSourceMethod]
- public void ExecuteEndHint()
+ [BUTRDataSourceMethod]
+ public void ExecuteBeginHintExport()
+ {
+ if (IsSingleplayer2 && IsModsDataSelected)
{
- HintManager.HideHint();
+ HintManager.ShowHint(new BUTRTextObject("{=XdZGqnFW}Export Current Load Order"));
}
-
- [BUTRDataSourceMethod]
- public void ExecuteImport()
+ if (IsSingleplayer2 && IsSavesDataSelected)
{
- if (ViewModel is null || _launcherModsVMMixin is null || UpdateAndSaveUserModsDataMethod is null) return;
+ HintManager.ShowHint(new BUTRTextObject("{=G55IdM6M}Export Save's Load Order"));
+ }
+ }
+
+ [BUTRDataSourceMethod]
+ public void ExecuteEndHint()
+ {
+ HintManager.HideHint();
+ }
- _currentModuleListHandler = new ModuleListHandler(_launcherManagerHandler);
+ [BUTRDataSourceMethod]
+ public void ExecuteImport()
+ {
+ if (ViewModel is null || _launcherModsVMMixin is null || UpdateAndSaveUserModsDataMethod is null) return;
+
+ _currentModuleListHandler = new ModuleListHandler(_launcherManagerHandler);
- if (IsSingleplayer2 && IsModsDataSelected)
+ if (IsSingleplayer2 && IsModsDataSelected)
+ {
+ var thread = new Thread(() =>
{
- var thread = new Thread(() =>
+ _currentModuleListHandler.Import(result =>
{
- _currentModuleListHandler.Import(result =>
- {
- if (!result) return;
- UpdateAndSaveUserModsDataMethod(ViewModel, false);
- HintManager.ShowHint(new BUTRTextObject("{=eohqbvHU}Successfully imported list!"));
- });
+ if (!result) return;
+ UpdateAndSaveUserModsDataMethod(ViewModel, false);
+ HintManager.ShowHint(new BUTRTextObject("{=eohqbvHU}Successfully imported list!"));
});
- thread.SetApartmentState(ApartmentState.STA);
- thread.Start();
- thread.Join();
- }
- if (IsSingleplayer2 && IsSavesDataSelected && SavesData?.Selected?.Name is { } saveName)
+ });
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
+ thread.Join();
+ }
+ if (IsSingleplayer2 && IsSavesDataSelected && SavesData?.Selected?.Name is { } saveName)
+ {
+ var thread = new Thread(() =>
{
- var thread = new Thread(() =>
+ _currentModuleListHandler.ImportSaveFile(saveName, result =>
{
- _currentModuleListHandler.ImportSaveFile(saveName, result =>
- {
- if (!result) return;
- UpdateAndSaveUserModsDataMethod(ViewModel, false);
- HintManager.ShowHint(new BUTRTextObject("{=eohqbvHU}Successfully imported list!"));
- });
+ if (!result) return;
+ UpdateAndSaveUserModsDataMethod(ViewModel, false);
+ HintManager.ShowHint(new BUTRTextObject("{=eohqbvHU}Successfully imported list!"));
});
- thread.SetApartmentState(ApartmentState.STA);
- thread.Start();
- thread.Join();
- }
+ });
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
+ thread.Join();
}
+ }
- [BUTRDataSourceMethod]
- public void ExecuteExport()
- {
- if (ViewModel is null || _launcherModsVMMixin is null) return;
+ [BUTRDataSourceMethod]
+ public void ExecuteExport()
+ {
+ if (ViewModel is null || _launcherModsVMMixin is null) return;
- _currentModuleListHandler = new ModuleListHandler(_launcherManagerHandler);
+ _currentModuleListHandler = new ModuleListHandler(_launcherManagerHandler);
- if (IsSingleplayer2 && IsModsDataSelected)
+ if (IsSingleplayer2 && IsModsDataSelected)
+ {
+ var thread = new Thread(() =>
{
- var thread = new Thread(() =>
- {
- _currentModuleListHandler.Export();
- });
- thread.SetApartmentState(ApartmentState.STA);
- thread.Start();
- thread.Join();
- }
- if (IsSingleplayer2 && IsSavesDataSelected && SavesData?.Selected?.Name is { } saveName)
+ _currentModuleListHandler.Export();
+ });
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
+ thread.Join();
+ }
+ if (IsSingleplayer2 && IsSavesDataSelected && SavesData?.Selected?.Name is { } saveName)
+ {
+ var thread = new Thread(() =>
{
- var thread = new Thread(() =>
- {
- _currentModuleListHandler.ExportSaveFile(saveName);
- });
- thread.SetApartmentState(ApartmentState.STA);
- thread.Start();
- thread.Join();
- }
+ _currentModuleListHandler.ExportSaveFile(saveName);
+ });
+ thread.SetApartmentState(ApartmentState.STA);
+ thread.Start();
+ thread.Join();
}
+ }
- [BUTRDataSourceMethod(OverrideName = "ExecuteStartGame")]
- public void ExecuteStartGameOverride(int mode)
- {
- if (ViewModel is null || ExecuteStartGame is null) return;
+ [BUTRDataSourceMethod(OverrideName = "ExecuteStartGame")]
+ public void ExecuteStartGameOverride(int mode)
+ {
+ if (ViewModel is null || ExecuteStartGame is null) return;
- if (IsSavesDataSelected && SavesData?.Selected is { } saveVM)
+ if (IsSavesDataSelected && SavesData?.Selected is { } saveVM)
+ {
+ _launcherManagerHandler.SetGameParameterSaveFile(saveVM.Name);
+ if (saveVM.HasWarning || saveVM.HasError)
{
- _launcherManagerHandler.SetGameParameterSaveFile(saveVM.Name);
- if (saveVM.HasWarning || saveVM.HasError)
+ var description = new StringBuilder();
+ if (saveVM.HasError)
+ {
+ description.Append(saveVM.ErrorHint?.Text ?? string.Empty);
+ }
+
+ if (saveVM is { HasError: true, HasWarning: true })
{
- var description = new StringBuilder();
- if (saveVM.HasError)
- {
- description.Append(saveVM.ErrorHint?.Text ?? string.Empty);
- }
-
- if (saveVM is { HasError: true, HasWarning: true })
- {
- description.Append("\n");
- }
-
- if (saveVM.HasWarning)
- {
- description.Append(saveVM.WarningHint?.Text ?? string.Empty);
- }
-
- description.Append("\n\n");
- description.Append(new BUTRTextObject("{=MlYQ0uX7}An unstable experience could occur."));
description.Append("\n");
- description.Append(new BUTRTextObject("{=qvzptzrE}Do you wish to continue loading the save?"));
+ }
- MessageBox?.Show(new BUTRTextObject("{=dDprK7Mz}WARNING").ToString(), description.ToString(), () => ExecuteStartGame(ViewModel, 0), null);
- return;
+ if (saveVM.HasWarning)
+ {
+ description.Append(saveVM.WarningHint?.Text ?? string.Empty);
}
- ExecuteStartGame(ViewModel, 0);
+ description.Append("\n\n");
+ description.Append(new BUTRTextObject("{=MlYQ0uX7}An unstable experience could occur."));
+ description.Append("\n");
+ description.Append(new BUTRTextObject("{=qvzptzrE}Do you wish to continue loading the save?"));
+
+ MessageBox?.Show(new BUTRTextObject("{=dDprK7Mz}WARNING").ToString(), description.ToString(), () => ExecuteStartGame(ViewModel, 0), null);
return;
}
- if (mode == 1)
- {
- _launcherManagerHandler.SetGameParameterContinueLastSaveFile(true);
+ ExecuteStartGame(ViewModel, 0);
+ return;
+ }
- ExecuteStartGame(ViewModel, 1);
- return;
- }
+ if (mode == 1)
+ {
+ _launcherManagerHandler.SetGameParameterContinueLastSaveFile(true);
- ExecuteStartGame(ViewModel, mode);
+ ExecuteStartGame(ViewModel, 1);
+ return;
}
+
+ ExecuteStartGame(ViewModel, mode);
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Options/LauncherExData.cs b/src/Bannerlord.LauncherEx/Options/LauncherExData.cs
index dfe853f..2c187af 100644
--- a/src/Bannerlord.LauncherEx/Options/LauncherExData.cs
+++ b/src/Bannerlord.LauncherEx/Options/LauncherExData.cs
@@ -3,62 +3,61 @@
using System.Xml;
using System.Xml.Serialization;
-namespace Bannerlord.LauncherEx.Options
+namespace Bannerlord.LauncherEx.Options;
+
+public sealed class LauncherExData
{
- public sealed class LauncherExData
+ public static LauncherExData? FromUserDataXml(string path)
{
- public static LauncherExData? FromUserDataXml(string path)
+ var xmlSerializer = new XmlSerializer(typeof(LauncherExData), new XmlRootAttribute("UserData"));
+ try
{
- var xmlSerializer = new XmlSerializer(typeof(LauncherExData), new XmlRootAttribute("UserData"));
- try
- {
- using var xmlReader = XmlReader.Create(path);
- return (LauncherExData) xmlSerializer.Deserialize(xmlReader);
- }
- catch (Exception e)
- {
- Trace.WriteLine(e);
- return null;
- }
+ using var xmlReader = XmlReader.Create(path);
+ return (LauncherExData) xmlSerializer.Deserialize(xmlReader);
}
-
- public bool AutomaticallyCheckForUpdates { get; set; }
- public bool FixCommonIssues { get; set; }
- public bool CompactModuleList { get; set; }
- public bool DisableBinaryCheck { get; set; }
- public bool HideRandomImage { get; set; }
- public bool BetaSorting { get; set; }
- public bool BigMode { get; set; }
- public bool EnableDPIScaling { get; set; }
- public bool DisableCrashHandlerWhenDebuggerIsAttached { get; set; }
- public bool DisableCatchAutoGenExceptions { get; set; }
- public bool UseVanillaCrashHandler { get; set; }
-
- public LauncherExData() { }
- public LauncherExData(
- bool automaticallyCheckForUpdates,
- bool fixCommonIssues,
- bool compactModuleList,
- bool hideRandomImage,
- bool disableBinaryCheck,
- bool betaSorting,
- bool bigMode,
- bool enableDPIScaling,
- bool disableCrashHandlerWhenDebuggerIsAttached,
- bool disableCatchAutoGenExceptions,
- bool useVanillaCrashHandler)
+ catch (Exception e)
{
- AutomaticallyCheckForUpdates = automaticallyCheckForUpdates;
- FixCommonIssues = fixCommonIssues;
- CompactModuleList = compactModuleList;
- DisableBinaryCheck = disableBinaryCheck;
- HideRandomImage = hideRandomImage;
- BetaSorting = betaSorting;
- BigMode = bigMode;
- EnableDPIScaling = enableDPIScaling;
- DisableCrashHandlerWhenDebuggerIsAttached = disableCrashHandlerWhenDebuggerIsAttached;
- DisableCatchAutoGenExceptions = disableCatchAutoGenExceptions;
- UseVanillaCrashHandler = useVanillaCrashHandler;
+ Trace.WriteLine(e);
+ return null;
}
}
+
+ public bool AutomaticallyCheckForUpdates { get; set; }
+ public bool FixCommonIssues { get; set; }
+ public bool CompactModuleList { get; set; }
+ public bool DisableBinaryCheck { get; set; }
+ public bool HideRandomImage { get; set; }
+ public bool BetaSorting { get; set; }
+ public bool BigMode { get; set; }
+ public bool EnableDPIScaling { get; set; }
+ public bool DisableCrashHandlerWhenDebuggerIsAttached { get; set; }
+ public bool DisableCatchAutoGenExceptions { get; set; }
+ public bool UseVanillaCrashHandler { get; set; }
+
+ public LauncherExData() { }
+ public LauncherExData(
+ bool automaticallyCheckForUpdates,
+ bool fixCommonIssues,
+ bool compactModuleList,
+ bool hideRandomImage,
+ bool disableBinaryCheck,
+ bool betaSorting,
+ bool bigMode,
+ bool enableDPIScaling,
+ bool disableCrashHandlerWhenDebuggerIsAttached,
+ bool disableCatchAutoGenExceptions,
+ bool useVanillaCrashHandler)
+ {
+ AutomaticallyCheckForUpdates = automaticallyCheckForUpdates;
+ FixCommonIssues = fixCommonIssues;
+ CompactModuleList = compactModuleList;
+ DisableBinaryCheck = disableBinaryCheck;
+ HideRandomImage = hideRandomImage;
+ BetaSorting = betaSorting;
+ BigMode = bigMode;
+ EnableDPIScaling = enableDPIScaling;
+ DisableCrashHandlerWhenDebuggerIsAttached = disableCrashHandlerWhenDebuggerIsAttached;
+ DisableCatchAutoGenExceptions = disableCatchAutoGenExceptions;
+ UseVanillaCrashHandler = useVanillaCrashHandler;
+ }
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Patches/LauncherConfirmStartVMPatch.cs b/src/Bannerlord.LauncherEx/Patches/LauncherConfirmStartVMPatch.cs
index 94f38b3..854ebc4 100644
--- a/src/Bannerlord.LauncherEx/Patches/LauncherConfirmStartVMPatch.cs
+++ b/src/Bannerlord.LauncherEx/Patches/LauncherConfirmStartVMPatch.cs
@@ -5,23 +5,22 @@
using TaleWorlds.MountAndBlade.Launcher.Library;
-namespace Bannerlord.LauncherEx.Patches
+namespace Bannerlord.LauncherEx.Patches;
+
+internal static class LauncherConfirmStartVMPatch
{
- internal static class LauncherConfirmStartVMPatch
+ public static bool Enable(Harmony harmony)
{
- public static bool Enable(Harmony harmony)
- {
- var res1 = harmony.TryPatch(
- AccessTools2.Method(typeof(LauncherConfirmStartVM), "EnableWith"),
- prefix: AccessTools2.DeclaredMethod(typeof(LauncherConfirmStartVMPatch), nameof(EnableWithPrefix)));
+ var res1 = harmony.TryPatch(
+ AccessTools2.Method(typeof(LauncherConfirmStartVM), "EnableWith"),
+ prefix: AccessTools2.DeclaredMethod(typeof(LauncherConfirmStartVMPatch), nameof(EnableWithPrefix)));
- return res1;
- }
+ return res1;
+ }
- public static bool EnableWithPrefix(Action? ____onConfirm)
- {
- ____onConfirm?.Invoke();
- return false;
- }
+ public static bool EnableWithPrefix(Action? ____onConfirm)
+ {
+ ____onConfirm?.Invoke();
+ return false;
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Patches/LauncherModsVMPatch.cs b/src/Bannerlord.LauncherEx/Patches/LauncherModsVMPatch.cs
index 4e0a659..a80f66a 100644
--- a/src/Bannerlord.LauncherEx/Patches/LauncherModsVMPatch.cs
+++ b/src/Bannerlord.LauncherEx/Patches/LauncherModsVMPatch.cs
@@ -7,31 +7,30 @@
using TaleWorlds.MountAndBlade.Launcher.Library;
using TaleWorlds.MountAndBlade.Launcher.Library.UserDatas;
-namespace Bannerlord.LauncherEx.Patches
+namespace Bannerlord.LauncherEx.Patches;
+
+internal static class LauncherModsVMPatch
{
- internal static class LauncherModsVMPatch
+ private static readonly AccessTools.FieldRef? _userData =
+ AccessTools2.FieldRefAccess("_userData");
+
+ public static bool Enable(Harmony harmony)
{
- private static readonly AccessTools.FieldRef? _userData =
- AccessTools2.FieldRefAccess("_userData");
+ var res1 = harmony.TryPatch(
+ AccessTools2.Method(typeof(LauncherModsVM), "LoadSubModules"),
+ prefix: AccessTools2.DeclaredMethod(typeof(LauncherModsVMPatch), nameof(LoadSubModulesPrefix)));
- public static bool Enable(Harmony harmony)
- {
- var res1 = harmony.TryPatch(
- AccessTools2.Method(typeof(LauncherModsVM), "LoadSubModules"),
- prefix: AccessTools2.DeclaredMethod(typeof(LauncherModsVMPatch), nameof(LoadSubModulesPrefix)));
+ return true;
+ }
+ public static bool LoadSubModulesPrefix(LauncherModsVM __instance)
+ {
+ if (_userData is null)
return true;
- }
-
- public static bool LoadSubModulesPrefix(LauncherModsVM __instance)
- {
- if (_userData is null)
- return true;
- if (__instance.GetMixin() is { } mixin)
- mixin.Initialize();
+ if (__instance.GetMixin() is { } mixin)
+ mixin.Initialize();
- return false;
- }
+ return false;
}
}
\ No newline at end of file
diff --git a/src/Bannerlord.LauncherEx/Patches/LauncherUIPatch.cs b/src/Bannerlord.LauncherEx/Patches/LauncherUIPatch.cs
index 4a7bb1b..b70b34a 100644
--- a/src/Bannerlord.LauncherEx/Patches/LauncherUIPatch.cs
+++ b/src/Bannerlord.LauncherEx/Patches/LauncherUIPatch.cs
@@ -12,68 +12,67 @@
using TaleWorlds.MountAndBlade.Launcher.Library;
using TaleWorlds.MountAndBlade.Launcher.Library.UserDatas;
-namespace Bannerlord.LauncherEx.Patches
+namespace Bannerlord.LauncherEx.Patches;
+
+internal static class LauncherUIPatch
{
- internal static class LauncherUIPatch
+ public static bool Enable(Harmony harmony)
{
- public static bool Enable(Harmony harmony)
- {
- var res1 = harmony.TryPatch(
- AccessTools2.DeclaredMethod(typeof(LauncherUI), "Initialize"),
- postfix: AccessTools2.DeclaredMethod(typeof(LauncherUIPatch), nameof(InitializePostfix)));
- if (!res1) return false;
+ var res1 = harmony.TryPatch(
+ AccessTools2.DeclaredMethod(typeof(LauncherUI), "Initialize"),
+ postfix: AccessTools2.DeclaredMethod(typeof(LauncherUIPatch), nameof(InitializePostfix)));
+ if (!res1) return false;
- var res2 = harmony.TryPatch(
- AccessTools2.DeclaredMethod(typeof(LauncherUI), "Update"),
- postfix: AccessTools2.DeclaredMethod(typeof(LauncherUIPatch), nameof(UpdatePostfix)));
- if (!res2) return false;
+ var res2 = harmony.TryPatch(
+ AccessTools2.DeclaredMethod(typeof(LauncherUI), "Update"),
+ postfix: AccessTools2.DeclaredMethod(typeof(LauncherUIPatch), nameof(UpdatePostfix)));
+ if (!res2) return false;
- var res3 = harmony.TryPatch(
- AccessTools2.DeclaredPropertyGetter(typeof(LauncherUI), "AdditionalArgs"),
- postfix: AccessTools2.DeclaredMethod(typeof(LauncherUIPatch), nameof(AdditionalArgsPostfix)));
- if (!res3) return false;
+ var res3 = harmony.TryPatch(
+ AccessTools2.DeclaredPropertyGetter(typeof(LauncherUI), "AdditionalArgs"),
+ postfix: AccessTools2.DeclaredMethod(typeof(LauncherUIPatch), nameof(AdditionalArgsPostfix)));
+ if (!res3) return false;
- return true;
- }
+ return true;
+ }
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static void InitializePostfix(GauntletMovie ____movie, LauncherVM ____viewModel, UserDataManager ____userDataManager)
- {
- BUTRLauncherManagerHandler.Initialize(____userDataManager);
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void InitializePostfix(GauntletMovie ____movie, LauncherVM ____viewModel, UserDataManager ____userDataManager)
+ {
+ BUTRLauncherManagerHandler.Initialize(____userDataManager);
- // Add to the existing VM our own properties
- MixinManager.AddMixins(____viewModel);
- ____movie.RefreshDataSource(____viewModel);
- }
+ // Add to the existing VM our own properties
+ MixinManager.AddMixins(____viewModel);
+ ____movie.RefreshDataSource(____viewModel);
+ }
- private static void UpdatePostfix(UIContext ____context)
+ private static void UpdatePostfix(UIContext ____context)
+ {
+ if (Input.InputManager is BUTRInputManager butrInputManager)
{
- if (Input.InputManager is BUTRInputManager butrInputManager)
+ if (____context.EventManager?.FocusedWidget is { } focusedWidget)
{
- if (____context.EventManager?.FocusedWidget is { } focusedWidget)
- {
- butrInputManager.Update();
+ butrInputManager.Update();
- focusedWidget.HandleInput(butrInputManager.ReleasedChars);
- }
- }
- else
- {
- Input.Initialize(new BUTRInputManager(Input.InputManager), null);
+ focusedWidget.HandleInput(butrInputManager.ReleasedChars);
}
}
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static void AdditionalArgsPostfix()
+ else
{
- if (Input.InputManager is BUTRInputManager butrInputManager)
- {
- Input.Initialize(butrInputManager.InputManager, null);
- butrInputManager.Dispose();
- }
+ Input.Initialize(new BUTRInputManager(Input.InputManager), null);
}
+ }
- [MethodImpl(MethodImplOptions.NoInlining)]
- private static IEnumerable BlankTranspiler(IEnumerable instructions) => instructions;
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void AdditionalArgsPostfix()
+ {
+ if (Input.InputManager is BUTRInputManager butrInputManager)
+ {
+ Input.Initialize(butrInputManager.InputManager, null);
+ butrInputManager.Dispose();
+ }
}
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static IEnumerable