Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,7 @@ ModelManifest.xml

.vs
.vscode

# JetBrains Rider
*.sln.iml
.idea
35 changes: 18 additions & 17 deletions CSharpManager/CSharpManager.csproj
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net472</TargetFramework>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
<AssemblyVersion>0.0.6.0</AssemblyVersion>
</PropertyGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net472</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<ImplicitUsings>true</ImplicitUsings>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<AssemblyVersion>0.0.6.0</AssemblyVersion>
</PropertyGroup>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="move /Y $(TargetPath) $(OutDir)CSharpManager.bin" />
</Target>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="move /Y $(TargetPath) $(OutDir)CSharpManager.bin"/>
</Target>

<ItemGroup>
<ProjectReference Include="..\CSharpModBase\CSharpModBase.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CSharpModBase\CSharpModBase.csproj"/>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.11.5"/>
</ItemGroup>

</Project>
262 changes: 134 additions & 128 deletions CSharpManager/CSharpModManager.cs
Original file line number Diff line number Diff line change
@@ -1,175 +1,181 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using CSharpModBase;
using CSharpModBase.Input;
using Mono.Cecil;
using static CSharpModBase.Common;

namespace CSharpManager
namespace CSharpManager;

public class CSharpModManager
{
public class CSharpModManager
{
static string? LoadingModName { get; set; }
private Thread? _loopThread;
private static string? LoadingModName { get; set; }

public List<ICSharpMod> LoadedMods { get; } = new();
public InputManager InputManager { get; } = new();
public bool Develop { get; set; }
private Thread? loopThread;
public List<ICSharpMod> LoadedMods { get; } = [];
public InputManager InputManager { get; } = new();
public bool Develop { get; set; }

static CSharpModManager()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += AssemblyResolve;
currentDomain.UnhandledException += OnUnhandledException;
static CSharpModManager()
{
var currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += AssemblyResolve;
currentDomain.UnhandledException += OnUnhandledException;

TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
}
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
}

private static Assembly? TryLoadDll(string path)
public CSharpModManager()
{
Utils.InitInputManager(InputManager);
// load config from ini
Ini iniFile = new(Path.Combine(LoaderDir, "b1cs.ini"));
Develop = iniFile.GetValue("Develop", "Settings", "1").Trim() == "1";
Log.Debug($"Develop: {Develop}");
}

private static Assembly? TryLoadDll(string path)
{
if (File.Exists(path))
{
if (File.Exists(path))
{
return Assembly.LoadFrom(path);
}
return null;
return Assembly.LoadFrom(path);
}

private static Assembly? AssemblyResolve(object sender, ResolveEventArgs args)
return null;
}

private static Assembly? AssemblyResolve(object sender, ResolveEventArgs args)
{
try
{
try
if (LoadingModName == null)
{
if (LoadingModName == null)
{
return null;
}
string dllName = $"{new AssemblyName(args.Name).Name}.dll";
return TryLoadDll(Path.Combine(Common.ModDir, LoadingModName, dllName)) ??
TryLoadDll(Path.Combine(Common.ModDir, "Common", dllName)) ??
TryLoadDll(Path.Combine(Common.LoaderDir, dllName));
return null;
}
catch (Exception e)
{
Log.Error($"Load assembly {args.Name} failed:");
Log.Error(e);
}
return Assembly.Load(args.Name);
}

private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Log.Error($"UnhandledException:");
Log.Error((Exception)e.ExceptionObject);
var dllName = $"{new AssemblyName(args.Name).Name}.dll";
return TryLoadDll(Path.Combine(ModDir, LoadingModName, dllName)) ??
TryLoadDll(Path.Combine(ModDir, "CommonDirs", dllName)) ??
TryLoadDll(Path.Combine(LoaderDir, dllName));
}

private static void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
catch (Exception e)
{
Log.Error($"UnobservedTaskException:");
Log.Error(e.Exception);
Log.Error($"Load assembly {args.Name} failed:");
Log.Error(e);
}

public CSharpModManager()
return Assembly.Load(args.Name);
}

private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Log.Error("UnhandledException:");
Log.Error((Exception)e.ExceptionObject);
}

private static void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
Log.Error("UnobservedTaskException:");
Log.Error(e.Exception);
}

public void LoadMods()
{
LoadedMods.Clear();
if (!Directory.Exists(ModDir))
{
Utils.InitInputManager(InputManager);
// load config from ini
Ini iniFile = new(Path.Combine(Common.LoaderDir, "b1cs.ini"));
Develop = iniFile.GetValue("Develop", "Settings", "1").Trim() == "1";
Log.Debug($"Develop: {Develop}");
Log.Error($"Mod dir {ModDir} not exists");
return;
}

public void LoadMods()
string[] dirs = Directory.GetDirectories(ModDir);
var ICSharpModType = typeof(ICSharpMod);
foreach (var dir in dirs)
{
LoadedMods.Clear();
if (!Directory.Exists(Common.ModDir))
LoadingModName = Path.GetFileName(dir);
var dllPath = Path.Combine(dir, $"{LoadingModName}.dll");
if (!File.Exists(dllPath))
{
Log.Error($"Mod dir {Common.ModDir} not exists");
return;
continue;
}
string[] dirs = Directory.GetDirectories(Common.ModDir);
Type ICSharpModType = typeof(ICSharpMod);
foreach (var dir in dirs)

try
{
LoadingModName = Path.GetFileName(dir);
string dllPath = Path.Combine(dir, $"{LoadingModName}.dll");
if (!File.Exists(dllPath)) continue;
try
Log.Debug($"======== Loading {dllPath} ========");
Assembly assembly;
if (Develop)
{
Log.Debug($"======== Loading {dllPath} ========");
Assembly assembly;
if (Develop)
{
using var assemblyDef = AssemblyDefinition.ReadAssembly(dllPath);
assemblyDef.Name.Name += DateTime.Now.ToString("_yyyyMMdd_HHmmssffff");
using MemoryStream stream = new();
assemblyDef.Write(stream);
assembly = Assembly.Load(stream.GetBuffer());
}
else
{
assembly = Assembly.LoadFrom(dllPath);
}
foreach (Type type in assembly.GetTypes())
using var assemblyDef = AssemblyDefinition.ReadAssembly(dllPath);
assemblyDef.Name.Name += DateTime.Now.ToString("_yyyyMMdd_HHmmssffff");
using MemoryStream stream = new();
assemblyDef.Write(stream);
assembly = Assembly.Load(stream.GetBuffer());
}
else
{
assembly = Assembly.LoadFrom(dllPath);
}

foreach (var type in assembly.GetTypes())
{
if (ICSharpModType.IsAssignableFrom(type))
{
if (ICSharpModType.IsAssignableFrom(type))
Log.Debug($"Found ICSharpMod: {type}");

if (Activator.CreateInstance(type) is ICSharpMod mod)
{
Log.Debug($"Found ICSharpMod: {type}");

if (Activator.CreateInstance(type) is ICSharpMod mod)
{
mod.Init();
LoadedMods.Add(mod);
Log.Debug($"Loaded mod {mod.Name} {mod.Version}");
}
mod.Init();
LoadedMods.Add(mod);
Log.Debug($"Loaded mod {mod.Name} {mod.Version}");
}
}
LoadingModName = null;
}
catch (Exception e)
{
Log.Error($"Load {dllPath} failed:");
Log.Error(e);
}

LoadingModName = null;
}
catch (Exception e)
{
Log.Error($"Load {dllPath} failed:");
Log.Error(e);
}
}
}

public void ReloadMods()
public void ReloadMods()
{
Log.Debug("ReloadMods");
InputManager.Clear();
foreach (var mod in LoadedMods)
{
Log.Debug("ReloadMods");
InputManager.Clear();
foreach (var mod in LoadedMods)
try
{
try
{
mod.DeInit();
}
catch (Exception e)
{
Log.Error($"DeInit {mod.Name} failed:");
Log.Error(e);
}
mod.DeInit();
}
catch (Exception e)
{
Log.Error($"DeInit {mod.Name} failed:");
Log.Error(e);
}
LoadMods();
}

public void StartLoop()
LoadMods();
}

public void StartLoop()
{
InputManager.RegisterBuiltinKeyBind(ModifierKeys.Control, Key.F5, ReloadMods);
_loopThread = new Thread(Loop)
{
InputManager.RegisterBuiltinKeyBind(ModifierKeys.Control, Key.F5, ReloadMods);
loopThread = new Thread(Loop)
{
// IsBackground = true,
};
loopThread.Start();
}
// IsBackground = true,
};
_loopThread.Start();
}

private void Loop()
private void Loop()
{
while (true)
{
while (true)
{
InputManager.Update();
Thread.Sleep(10); // 10ms
}
InputManager.Update();
Thread.Sleep(10); // 10ms
}
}
}
}
Loading