diff --git a/CHANGES.md b/CHANGES.md
index c9fc2d1..beee49c 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,7 +1,7 @@
# Release notes
All notable changes should be documented in this file.
-Since v2, ModTek adheres to [Semantic Versioning](http://semver.org/).
+Since v2, ModTek adheres to [Semantic Versioning](http://semver.org/) for runtime compatibility with mods.
## Known Issues
@@ -10,6 +10,12 @@ Since v2, ModTek adheres to [Semantic Versioning](http://semver.org/).
however injected assemblies are now found under `Mods/.modtek/AssembliesInjected` or loaded directly into memory after injection.
- The HarmonyX feature works well, however some mods might rely on some buggy Harmony 1.2 behaviors that HarmonyX shims don't replicate.
+## Upcoming - CptMoore
+
+For modders:
+- (Experimental!) Added ability to run injectors as part of a build task outside of BT. API will most likely change.
+- Some libraries were renamed, as always don't just copy-paste, clean-copy-paste!
+
## 4.2 - CptMoore
For users:
@@ -22,7 +28,7 @@ For modders:
- Made run.sh depend on the doorstop.ini instead of having its own inline options
- Updated HarmonyX
- New HarmonyX is based on a major rewrite of MonoMod, several bugs were encountered and fixed
- - Still providing an older version of HarmonyX in-case the new HarmonyX feels unstable
+ - Still providing an older version of HarmonyX due to reports of instability (those went away after a restart or 2)
- Various Logging improvements and changes
- Async logging is now highly optimized
- reduction of 300+ ns to <100 ns spent on the caller thread (usually the unity main thread)
diff --git a/CommonBase.props b/CommonBase.props
index 403f7f2..134f1ac 100644
--- a/CommonBase.props
+++ b/CommonBase.props
@@ -7,6 +7,7 @@
Library
13
+ embedded
diff --git a/CommonBattleTech.props b/CommonBattleTech.props
index d77df7b..618ea48 100644
--- a/CommonBattleTech.props
+++ b/CommonBattleTech.props
@@ -9,7 +9,6 @@
$(BattleTechGameDir)\BattleTech_Data\Managed
true
- embedded
diff --git a/Directory.Packages.props b/Directory.Packages.props
index aab19cd..92732f0 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -3,6 +3,7 @@
true
+
diff --git a/ModTek.Common/Globals/Paths.cs b/ModTek.Common/Globals/Paths.cs
index 6387e9d..5d7d296 100644
--- a/ModTek.Common/Globals/Paths.cs
+++ b/ModTek.Common/Globals/Paths.cs
@@ -1,15 +1,16 @@
-using System;
-using System.IO;
+using System.IO;
+using System.Reflection;
namespace ModTek.Common.Globals;
internal class Paths
{
// Common paths
- private const string ENV_DOORSTOP_MANAGED_FOLDER_DIR = "DOORSTOP_MANAGED_FOLDER_DIR";
- internal static readonly string ManagedDirectory = Environment.GetEnvironmentVariable(ENV_DOORSTOP_MANAGED_FOLDER_DIR)
- ?? throw new Exception($"Can't find {ENV_DOORSTOP_MANAGED_FOLDER_DIR}");
- internal static readonly string BaseDirectory = Path.GetFullPath(Path.Combine(ManagedDirectory, "..", ".."));
+
+ // BATTLETECH/Mods/ModTek/lib/ModTek.Common.dll -> BATTLETECH
+ internal static readonly string BaseDirectory = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "..", "..", ".."));
+ // Mac has Data, but we have a symlink from BattleTech_Data to Data anyway
+ internal static readonly string ManagedDirectory = Path.Combine(BaseDirectory, "BattleTech_Data", "Managed");
internal static readonly string ModsDirectory = Path.Combine(BaseDirectory, "Mods");
internal static readonly string ModTekDirectory = Path.Combine(ModsDirectory, "ModTek");
diff --git a/ModTek.Common/ModTek.Common.csproj b/ModTek.Common/ModTek.Common.csproj
index e3ca030..5f710d7 100644
--- a/ModTek.Common/ModTek.Common.csproj
+++ b/ModTek.Common/ModTek.Common.csproj
@@ -1,6 +1,13 @@
+
+
+
+
+
+
+
true
@@ -8,6 +15,6 @@
-
+
\ No newline at end of file
diff --git a/ModTek.InjectorRunner/Injector/AssemblyCache.cs b/ModTek.Injectors/AssemblyCache.cs
similarity index 99%
rename from ModTek.InjectorRunner/Injector/AssemblyCache.cs
rename to ModTek.Injectors/AssemblyCache.cs
index eea022a..93d6d9a 100644
--- a/ModTek.InjectorRunner/Injector/AssemblyCache.cs
+++ b/ModTek.Injectors/AssemblyCache.cs
@@ -6,7 +6,7 @@
using ModTek.Common.Utils;
using Mono.Cecil;
-namespace ModTek.InjectorRunner.Injector;
+namespace ModTek.Injectors;
class AssemblyCache : IAssemblyResolver
{
diff --git a/ModTek.InjectorRunner/Injector/InjectionCacheManifest.cs b/ModTek.Injectors/InjectionCacheManifest.cs
similarity index 98%
rename from ModTek.InjectorRunner/Injector/InjectionCacheManifest.cs
rename to ModTek.Injectors/InjectionCacheManifest.cs
index cbe15ed..d907724 100644
--- a/ModTek.InjectorRunner/Injector/InjectionCacheManifest.cs
+++ b/ModTek.Injectors/InjectionCacheManifest.cs
@@ -6,7 +6,7 @@
using ModTek.Common.Globals;
using ModTek.Common.Utils;
-namespace ModTek.InjectorRunner.Injector;
+namespace ModTek.Injectors;
internal class InjectionCacheManifest
{
diff --git a/ModTek.InjectorRunner/Logger.cs b/ModTek.Injectors/Logger.cs
similarity index 83%
rename from ModTek.InjectorRunner/Logger.cs
rename to ModTek.Injectors/Logger.cs
index c03d20d..432810a 100644
--- a/ModTek.InjectorRunner/Logger.cs
+++ b/ModTek.Injectors/Logger.cs
@@ -1,7 +1,7 @@
using ModTek.Common.Globals;
using ModTek.Common.Logging;
-namespace ModTek.InjectorRunner;
+namespace ModTek.Injectors;
internal class Logger
{
diff --git a/ModTek.InjectorRunner/ModTek.InjectorRunner.csproj b/ModTek.Injectors/ModTek.Injectors.csproj
similarity index 61%
rename from ModTek.InjectorRunner/ModTek.InjectorRunner.csproj
rename to ModTek.Injectors/ModTek.Injectors.csproj
index 6da4c38..84d62e9 100644
--- a/ModTek.InjectorRunner/ModTek.InjectorRunner.csproj
+++ b/ModTek.Injectors/ModTek.Injectors.csproj
@@ -1,12 +1,20 @@
+
+
+
+
+
+
+
+
-
+
diff --git a/ModTek.InjectorRunner/Injector/InjectorsRunner.cs b/ModTek.Injectors/Runner.cs
similarity index 90%
rename from ModTek.InjectorRunner/Injector/InjectorsRunner.cs
rename to ModTek.Injectors/Runner.cs
index 1252a2b..643b32b 100644
--- a/ModTek.InjectorRunner/Injector/InjectorsRunner.cs
+++ b/ModTek.Injectors/Runner.cs
@@ -6,13 +6,13 @@
using ModTek.Common.Logging;
using ModTek.Common.Utils;
-namespace ModTek.InjectorRunner.Injector;
+namespace ModTek.Injectors;
-internal class InjectorsRunner : IDisposable
+internal class Runner : IDisposable
{
internal static void Run()
{
- using var injectorsRunner = new InjectorsRunner();
+ using var injectorsRunner = new Runner();
if (injectorsRunner.IsUpToDate)
{
return;
@@ -22,9 +22,14 @@ internal static void Run()
injectorsRunner.SaveToDisk();
}
+ internal static string[] GetInjectedPaths()
+ {
+ return Directory.GetFiles(Paths.AssembliesInjectedDirectory, "*.dll");
+ }
+
private readonly AssemblyCache _assemblyCache;
private readonly InjectionCacheManifest _injectionCacheManifest;
- private InjectorsRunner()
+ private Runner()
{
_assemblyCache = new AssemblyCache();
_injectionCacheManifest = new InjectionCacheManifest();
diff --git a/ModTek.InjectorsTask/ITaskItemExtensions.cs b/ModTek.InjectorsTask/ITaskItemExtensions.cs
new file mode 100644
index 0000000..13f2db0
--- /dev/null
+++ b/ModTek.InjectorsTask/ITaskItemExtensions.cs
@@ -0,0 +1,17 @@
+using Microsoft.Build.Framework;
+
+namespace ModTek.InjectorsTask;
+
+// from Krafs.Publicizer
+internal static class TaskItemExtensions
+{
+ internal static string FileName(this ITaskItem item)
+ {
+ return item.GetMetadata("Filename");
+ }
+
+ internal static string FullPath(this ITaskItem item)
+ {
+ return item.GetMetadata("Fullpath");
+ }
+}
\ No newline at end of file
diff --git a/ModTek.InjectorsTask/ModTek.InjectorsTask.csproj b/ModTek.InjectorsTask/ModTek.InjectorsTask.csproj
new file mode 100644
index 0000000..3449fcc
--- /dev/null
+++ b/ModTek.InjectorsTask/ModTek.InjectorsTask.csproj
@@ -0,0 +1,26 @@
+
+
+
+
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ All
+ runtime
+
+
+
diff --git a/ModTek.InjectorsTask/ModTek.InjectorsTask.props b/ModTek.InjectorsTask/ModTek.InjectorsTask.props
new file mode 100644
index 0000000..c0dedc8
--- /dev/null
+++ b/ModTek.InjectorsTask/ModTek.InjectorsTask.props
@@ -0,0 +1,6 @@
+
+
+
\ No newline at end of file
diff --git a/ModTek.InjectorsTask/ModTek.InjectorsTask.targets b/ModTek.InjectorsTask/ModTek.InjectorsTask.targets
new file mode 100644
index 0000000..75d1f13
--- /dev/null
+++ b/ModTek.InjectorsTask/ModTek.InjectorsTask.targets
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ModTek.InjectorsTask/ModTekInjectorsRunner.cs b/ModTek.InjectorsTask/ModTekInjectorsRunner.cs
new file mode 100644
index 0000000..29c42b1
--- /dev/null
+++ b/ModTek.InjectorsTask/ModTekInjectorsRunner.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using ModTek.Injectors;
+
+namespace ModTek.InjectorsTask;
+
+/*
+ * see https://learn.microsoft.com/en-us/visualstudio/msbuild/tutorial-custom-task-code-generation?view=vs-2022#generate-a-console-app-and-use-the-custom-task
+ * see https://github.com/krafs/Publicizer/blob/main/src/Publicizer/Krafs.Publicizer.targets and props
+ * - run before Rafs.Publicizer
+ * - needs to modify the references? or just push them ahead so they are found?
+ * - see Rafs ReferencePathsToDelete and ReferencePathsToAdd and ReferencePaths etc....
+ */
+public class ModTekInjectorsRunner : Task
+{
+ [Required]
+ public string BattleTechGameDir { get; set; } = null!;
+
+ [Required]
+ public ITaskItem[] ReferencePaths { get; set; } = null!;
+
+ [Output]
+ public ITaskItem[] ReferencePathsToDelete { get; set; } = [];
+
+ [Output]
+ public ITaskItem[] ReferencePathsToAdd { get; set; } = [];
+
+ public override bool Execute()
+ {
+ var executingAssembly = Assembly.GetExecutingAssembly();
+ var applicationDirectory = Path.GetDirectoryName(executingAssembly.Location)!;
+
+ var currentDomain = AppDomain.CurrentDomain;
+ currentDomain.AssemblyResolve += (_, args) =>
+ {
+ var resolvingName = new AssemblyName(args.Name);
+ var path = Path.Combine(applicationDirectory, resolvingName.Name + ".dll");
+ Log.LogWarning($"Loading assembly {args.Name} from {path}");
+ return Assembly.LoadFrom(path);
+ };
+
+ Runner.Run();
+
+ var referencePathsToAdd = new List();
+ var referencePathsToDelete = new List();
+ foreach (var path in Runner.GetInjectedPaths())
+ {
+ var filename = Path.GetFileNameWithoutExtension(path);
+ foreach (var referencePath in ReferencePaths)
+ {
+ if (filename == referencePath.FileName())
+ {
+ var newReference = new TaskItem(path);
+ referencePathsToAdd.Add(newReference);
+ referencePathsToDelete.Add(referencePath);
+ break;
+ }
+ }
+ }
+ ReferencePathsToDelete = referencePathsToDelete.ToArray();
+ ReferencePathsToAdd = referencePathsToAdd.ToArray();
+ return !Log.HasLoggedErrors;
+ }
+}
\ No newline at end of file
diff --git a/ModTek.Preloader/Harmony12X/ShimCacheManifest.cs b/ModTek.Preloader/Harmony12X/ShimCacheManifest.cs
index f0d3dd0..e82506e 100644
--- a/ModTek.Preloader/Harmony12X/ShimCacheManifest.cs
+++ b/ModTek.Preloader/Harmony12X/ShimCacheManifest.cs
@@ -5,7 +5,7 @@
using System.Linq;
using ModTek.Common.Globals;
using ModTek.Common.Utils;
-using ModTek.InjectorRunner.Injector;
+using ModTek.Injectors;
using Mono.Cecil;
namespace ModTek.Preloader.Harmony12X;
diff --git a/ModTek.Preloader/InjectorsAppDomain.cs b/ModTek.Preloader/InjectorsAppDomain.cs
index bb1b35c..5a9747f 100644
--- a/ModTek.Preloader/InjectorsAppDomain.cs
+++ b/ModTek.Preloader/InjectorsAppDomain.cs
@@ -1,6 +1,6 @@
using System;
using ModTek.Common.Globals;
-using ModTek.InjectorRunner.Injector;
+using ModTek.Injectors;
namespace ModTek.Preloader;
@@ -36,6 +36,6 @@ internal static void Run()
private void RunInjectors()
{
- InjectorsRunner.Run();
+ Runner.Run();
}
}
\ No newline at end of file
diff --git a/ModTek.Preloader/Loader/Preloader.cs b/ModTek.Preloader/Loader/Preloader.cs
index 26b99a7..0e11f77 100644
--- a/ModTek.Preloader/Loader/Preloader.cs
+++ b/ModTek.Preloader/Loader/Preloader.cs
@@ -4,7 +4,7 @@
using System.Reflection;
using ModTek.Common.Globals;
using ModTek.Common.Utils;
-using ModTek.InjectorRunner.Injector;
+using ModTek.Injectors;
using ModTek.Preloader.Harmony12X;
namespace ModTek.Preloader.Loader;
@@ -37,7 +37,7 @@ internal static void Run()
private static void PreloadAssembliesInjected()
{
Logger.Main.Log($"Preloading injected assemblies from `{FileUtils.GetRelativePath(Paths.AssembliesInjectedDirectory)}`:");
- foreach (var file in Directory.GetFiles(Paths.AssembliesInjectedDirectory, "*.dll").OrderBy(p => p))
+ foreach (var file in Injectors.Runner.GetInjectedPaths().OrderBy(p => p))
{
Logger.Main.Log($"\t{Path.GetFileName(file)}");
Assembly.LoadFile(file);
diff --git a/ModTek.Preloader/ModTek.Preloader.csproj b/ModTek.Preloader/ModTek.Preloader.csproj
index ed0282f..8176614 100644
--- a/ModTek.Preloader/ModTek.Preloader.csproj
+++ b/ModTek.Preloader/ModTek.Preloader.csproj
@@ -3,10 +3,10 @@
-
+
-
+
@@ -34,7 +34,7 @@
-
-
+
+
\ No newline at end of file
diff --git a/ModTek.sln b/ModTek.sln
index 5f09843..d29bedd 100644
--- a/ModTek.sln
+++ b/ModTek.sln
@@ -30,7 +30,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModTemplate", "examples\Mod
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModTek.Common", "ModTek.Common\ModTek.Common.csproj", "{67588F2A-B438-407C-AD16-ED6F4C9D12FC}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModTek.InjectorRunner", "ModTek.InjectorRunner\ModTek.InjectorRunner.csproj", "{B9F6AA09-D3CD-4FAF-ADF8-18BF78B1CCD1}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModTek.Injectors", "ModTek.Injectors\ModTek.Injectors.csproj", "{B9F6AA09-D3CD-4FAF-ADF8-18BF78B1CCD1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModTek.InjectorsTask", "ModTek.InjectorsTask\ModTek.InjectorsTask.csproj", "{D4306496-4941-47A6-9AEA-B37A3E7BD15D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -74,6 +76,10 @@ Global
{B9F6AA09-D3CD-4FAF-ADF8-18BF78B1CCD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9F6AA09-D3CD-4FAF-ADF8-18BF78B1CCD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9F6AA09-D3CD-4FAF-ADF8-18BF78B1CCD1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D4306496-4941-47A6-9AEA-B37A3E7BD15D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D4306496-4941-47A6-9AEA-B37A3E7BD15D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D4306496-4941-47A6-9AEA-B37A3E7BD15D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D4306496-4941-47A6-9AEA-B37A3E7BD15D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE