Rebrand LegacyForge to Weave Loader

Rename across entire codebase:
- LegacyForge -> WeaveLoader (identifiers, namespaces, classes, DLLs)
- LegacyForgeRuntime -> WeaveLoaderRuntime (C++ project)
- LegacyForge.API/Core/Launcher -> WeaveLoader.API/Core/Launcher (C# projects)
- [LegacyForge] -> [WeaveLoader] (log prefixes)
- legacyforge -> weaveloader (config files, log files, backup suffixes)
- Display name "Weave Loader" in README, CONTRIBUTING, LICENSE
This commit is contained in:
Jacobwasbeast
2026-03-06 23:31:18 -06:00
parent f5805fc740
commit fa195fdc2e
70 changed files with 336 additions and 336 deletions

View File

@@ -1,13 +1,13 @@
# Contributing to LegacyForge
# Contributing to Weave Loader
Thank you for your interest in contributing to LegacyForge!
Thank you for your interest in contributing to Weave Loader!
## Project Structure
- **LegacyForge.Launcher/** -- C# console app that launches the game and injects the runtime DLL
- **LegacyForgeRuntime/** -- C++ DLL injected into the game process (hooks, .NET hosting, native exports)
- **LegacyForge.Core/** -- C# assembly loaded inside the game process (mod discovery, lifecycle management)
- **LegacyForge.API/** -- C# class library that mod authors reference (IMod, Registry, Events)
- **WeaveLoader.Launcher/** -- C# console app that launches the game and injects the runtime DLL
- **WeaveLoaderRuntime/** -- C++ DLL injected into the game process (hooks, .NET hosting, native exports)
- **WeaveLoader.Core/** -- C# assembly loaded inside the game process (mod discovery, lifecycle management)
- **WeaveLoader.API/** -- C# class library that mod authors reference (IMod, Registry, Events)
- **ExampleMod/** -- Sample mod demonstrating the API
## Building
@@ -21,7 +21,7 @@ Thank you for your interest in contributing to LegacyForge!
### C++ Runtime
```bash
cd LegacyForgeRuntime
cd WeaveLoaderRuntime
cmake -B build -A x64
cmake --build build --config Release
```
@@ -29,7 +29,7 @@ cmake --build build --config Release
### C# Projects
```bash
dotnet build LegacyForge.sln -c Release
dotnet build Weave Loader.sln -c Release
```
## Guidelines

View File

@@ -1,12 +1,12 @@
using LegacyForge.API;
using LegacyForge.API.Block;
using LegacyForge.API.Item;
using LegacyForge.API.Events;
using WeaveLoader.API;
using WeaveLoader.API.Block;
using WeaveLoader.API.Item;
using WeaveLoader.API.Events;
namespace ExampleMod;
[Mod("examplemod", Name = "Example Mod", Version = "1.0.0", Author = "LegacyForge",
Description = "A sample mod demonstrating the LegacyForge API")]
[Mod("examplemod", Name = "Example Mod", Version = "1.0.0", Author = "WeaveLoader",
Description = "A sample mod demonstrating the WeaveLoader API")]
public class ExampleMod : IMod
{
public static RegisteredBlock? RubyOre;

View File

@@ -6,7 +6,7 @@
<Nullable>enable</Nullable>
<RootNamespace>ExampleMod</RootNamespace>
<AssemblyName>ExampleMod</AssemblyName>
<Description>Example mod for LegacyForge demonstrating the mod API</Description>
<Description>Example mod for WeaveLoader demonstrating the mod API</Description>
<Version>1.0.0</Version>
<OutputPath>..\build\mods\ExampleMod</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
@@ -14,8 +14,8 @@
</PropertyGroup>
<ItemGroup>
<!-- Private=false: do not copy LegacyForge.API into ExampleMod. API lives in mods/LegacyForge.API/ -->
<ProjectReference Include="..\LegacyForge.API\LegacyForge.API.csproj">
<!-- Private=false: do not copy WeaveLoader.API into ExampleMod. API lives in mods/WeaveLoader.API/ -->
<ProjectReference Include="..\WeaveLoader.API\WeaveLoader.API.csproj">
<Private>false</Private>
</ProjectReference>
</ItemGroup>

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2026 LegacyForge Contributors
Copyright (c) 2026 Weave Loader Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,3 +0,0 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("LegacyForge.Core")]

View File

@@ -1,14 +0,0 @@
using LegacyForge.API;
namespace LegacyForge.Core;
/// <summary>
/// Built-in mod representing the LegacyForge API. Counts in the mod list and appears
/// when mods/LegacyForge.API/ exists. Does not run lifecycle hooks.
/// </summary>
[Mod("legacyforge.api", Name = "LegacyForge API", Version = "1.0.0", Author = "LegacyForge",
Description = "Mod API and shared types")]
internal sealed class LegacyForgeApiMod : IMod
{
public void OnInitialize() { }
}

View File

@@ -1,24 +1,24 @@
# LegacyForge
# Weave Loader
An SKSE-style mod loader for Minecraft Legacy Edition. LegacyForge injects into the game process at runtime, hooks key engine functions, and hosts the .NET runtime to load C# mods. **Zero game source modifications required.**
An SKSE-style mod loader for Minecraft Legacy Edition. Weave Loader injects into the game process at runtime, hooks key engine functions, and hosts the .NET runtime to load C# mods. **Zero game source modifications required.**
## How It Works
1. **LegacyForge.exe** launches the game in a suspended state and injects `LegacyForgeRuntime.dll`
1. **Weave Loader.exe** launches the game in a suspended state and injects `WeaveLoaderRuntime.dll`
2. The runtime DLL uses PDB debug symbols to locate game functions (`MinecraftWorld_RunStaticCtors`, `Minecraft::tick`, etc.)
3. MinHook detours those functions to insert mod lifecycle callbacks
4. The .NET CoreCLR runtime is hosted inside the game process via hostfxr
5. `LegacyForge.Core` discovers and loads C# mod assemblies from the `mods/` folder
6. Mods use the `LegacyForge.API` to register blocks, items, entities, and subscribe to game events using Fabric-style namespaced string IDs
5. `WeaveLoader.Core` discovers and loads C# mod assemblies from the `mods/` folder
6. Mods use the `WeaveLoader.API` to register blocks, items, entities, and subscribe to game events using Fabric-style namespaced string IDs
## Project Structure
```
ModLoader/
├── LegacyForge.Launcher/ C# launcher (the exe users run)
├── LegacyForgeRuntime/ C++ DLL (injected into game process)
├── LegacyForge.Core/ C# mod management (loaded inside game)
├── LegacyForge.API/ C# mod API (what mod authors reference)
├── WeaveLoader.Launcher/ C# launcher (the exe users run)
├── WeaveLoaderRuntime/ C++ DLL (injected into game process)
├── WeaveLoader.Core/ C# mod management (loaded inside game)
├── WeaveLoader.API/ C# mod API (what mod authors reference)
└── ExampleMod/ Sample mod for reference
```
@@ -36,7 +36,7 @@ ModLoader/
**C++ Runtime DLL:**
```bash
cd LegacyForgeRuntime
cd WeaveLoaderRuntime
cmake -B build -A x64
cmake --build build --config Release
```
@@ -44,27 +44,27 @@ cmake --build build --config Release
**C# Projects:**
```bash
dotnet build LegacyForge.sln
dotnet build Weave Loader.sln
```
## Usage
1. Build LegacyForge (see above)
1. Build Weave Loader (see above)
2. Copy the output files to a folder:
- `LegacyForge.exe`
- `LegacyForgeRuntime.dll`
- `LegacyForge.Core.dll`
- `LegacyForge.API.dll`
- `Weave Loader.exe`
- `WeaveLoaderRuntime.dll`
- `WeaveLoader.Core.dll`
- `WeaveLoader.API.dll`
3. Create a `mods/` folder and drop mod DLLs in it
4. Run `LegacyForge.exe` -- it will ask for the game exe path on first launch
4. Run `Weave Loader.exe` -- it will ask for the game exe path on first launch
5. The game starts with mods loaded
## Writing a Mod
Create a new .NET 8 class library and reference `LegacyForge.API`:
Create a new .NET 8 class library and reference `WeaveLoader.API`:
```csharp
using LegacyForge.API;
using WeaveLoader.API;
[Mod("mymod", Name = "My Mod", Version = "1.0.0", Author = "You")]
public class MyMod : IMod
@@ -82,7 +82,7 @@ public class MyMod : IMod
}
```
Build it, copy the DLL to `mods/`, and launch via LegacyForge.
Build it, copy the DLL to `mods/`, and launch via Weave Loader.
## License

View File

@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("WeaveLoader.Core")]

View File

@@ -1,4 +1,4 @@
namespace LegacyForge.API.Assets;
namespace WeaveLoader.API.Assets;
/// <summary>
/// Asset registration for mods. Use for language strings and (future) texture paths.

View File

@@ -1,4 +1,4 @@
namespace LegacyForge.API.Block;
namespace WeaveLoader.API.Block;
public enum MaterialType
{

View File

@@ -1,4 +1,4 @@
namespace LegacyForge.API.Block;
namespace WeaveLoader.API.Block;
/// <summary>
/// Represents a block that has been registered with the game engine.
@@ -19,7 +19,7 @@ public class RegisteredBlock
}
/// <summary>
/// Block registration via the LegacyForge registry.
/// Block registration via the WeaveLoader registry.
/// Accessed through <see cref="Registry.Block"/>.
/// </summary>
public static class BlockRegistry

View File

@@ -1,4 +1,4 @@
namespace LegacyForge.API;
namespace WeaveLoader.API;
/// <summary>
/// Creative inventory tabs matching the game's internal group indices.

View File

@@ -1,4 +1,4 @@
namespace LegacyForge.API.Entity;
namespace WeaveLoader.API.Entity;
/// <summary>
/// Fluent builder for defining entity properties.

View File

@@ -1,4 +1,4 @@
namespace LegacyForge.API.Entity;
namespace WeaveLoader.API.Entity;
/// <summary>
/// Represents an entity type that has been registered with the game engine.
@@ -16,7 +16,7 @@ public class RegisteredEntity
}
/// <summary>
/// Entity registration via the LegacyForge registry.
/// Entity registration via the WeaveLoader registry.
/// Accessed through <see cref="Registry.Entity"/>.
/// </summary>
public static class EntityRegistry

View File

@@ -1,4 +1,4 @@
namespace LegacyForge.API.Events;
namespace WeaveLoader.API.Events;
public class TickEventArgs : EventArgs { }
@@ -42,7 +42,7 @@ public class PlayerJoinEventArgs : EventArgs
/// <summary>
/// Global game event subscriptions. Subscribe to these in your mod's OnInitialize().
/// Events are fired from the game's main thread via hooks in LegacyForgeRuntime.
/// Events are fired from the game's main thread via hooks in WeaveLoaderRuntime.
/// </summary>
public static class GameEvents
{

View File

@@ -1,7 +1,7 @@
namespace LegacyForge.API;
namespace WeaveLoader.API;
/// <summary>
/// The main interface all LegacyForge mods must implement.
/// The main interface all WeaveLoader mods must implement.
/// Default interface methods allow mods to only override what they need.
/// </summary>
public interface IMod

View File

@@ -1,4 +1,4 @@
namespace LegacyForge.API;
namespace WeaveLoader.API;
/// <summary>
/// A namespaced identifier in the form "namespace:path" (e.g. "minecraft:stone", "mymod:ruby_ore").

View File

@@ -1,4 +1,4 @@
namespace LegacyForge.API.Item;
namespace WeaveLoader.API.Item;
/// <summary>
/// Fluent builder for defining item properties.

View File

@@ -1,4 +1,4 @@
namespace LegacyForge.API.Item;
namespace WeaveLoader.API.Item;
/// <summary>
/// Represents an item that has been registered with the game engine.
@@ -19,7 +19,7 @@ public class RegisteredItem
}
/// <summary>
/// Item registration via the LegacyForge registry.
/// Item registration via the WeaveLoader registry.
/// Accessed through <see cref="Registry.Item"/>.
/// </summary>
public static class ItemRegistry

View File

@@ -1,4 +1,4 @@
namespace LegacyForge.API;
namespace WeaveLoader.API;
public enum LogLevel
{
@@ -17,7 +17,7 @@ public static class Logger
/// <summary>
/// Set the log handler that routes messages to the native runtime.
/// Called by LegacyForge.Core during initialization.
/// Called by WeaveLoader.Core during initialization.
/// </summary>
public static void SetLogHandler(Action<string, LogLevel> handler) => LogHandler = handler;
@@ -31,6 +31,6 @@ public static class Logger
if (LogHandler != null)
LogHandler(message, level);
else
Console.WriteLine($"[LegacyForge/{level}] {message}");
Console.WriteLine($"[WeaveLoader/{level}] {message}");
}
}

View File

@@ -1,7 +1,7 @@
namespace LegacyForge.API;
namespace WeaveLoader.API;
/// <summary>
/// Marks a class as a LegacyForge mod and provides metadata.
/// Marks a class as a WeaveLoader mod and provides metadata.
/// The class must also implement <see cref="IMod"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]

View File

@@ -1,14 +1,14 @@
using System.Runtime.InteropServices;
namespace LegacyForge.API;
namespace WeaveLoader.API;
/// <summary>
/// Internal P/Invoke bindings to LegacyForgeRuntime.dll native exports.
/// Internal P/Invoke bindings to WeaveLoaderRuntime.dll native exports.
/// Mod authors should use the Registry and Logger classes instead of calling these directly.
/// </summary>
internal static class NativeInterop
{
private const string RuntimeDll = "LegacyForgeRuntime";
private const string RuntimeDll = "WeaveLoaderRuntime";
[DllImport(RuntimeDll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
internal static extern int native_register_block(

View File

@@ -1,7 +1,7 @@
namespace LegacyForge.API.Recipe;
namespace WeaveLoader.API.Recipe;
/// <summary>
/// Recipe registration via the LegacyForge registry.
/// Recipe registration via the WeaveLoader registry.
/// Accessed through <see cref="Registry.Recipe"/>.
/// </summary>
public static class RecipeRegistry

View File

@@ -1,13 +1,13 @@
using LegacyForge.API.Block;
using LegacyForge.API.Item;
using LegacyForge.API.Entity;
using LegacyForge.API.Recipe;
using LegacyForge.API.Assets;
using WeaveLoader.API.Block;
using WeaveLoader.API.Item;
using WeaveLoader.API.Entity;
using WeaveLoader.API.Recipe;
using WeaveLoader.API.Assets;
namespace LegacyForge.API;
namespace WeaveLoader.API;
/// <summary>
/// Central access point for all LegacyForge registries.
/// Central access point for all WeaveLoader registries.
/// Use Registry.Block, Registry.Item, Registry.Entity, Registry.Recipe, or Registry.Assets.
/// </summary>
public static class Registry

View File

@@ -4,11 +4,11 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>LegacyForge.API</RootNamespace>
<AssemblyName>LegacyForge.API</AssemblyName>
<Description>Mod API for LegacyForge - Minecraft Legacy Edition mod loader</Description>
<RootNamespace>WeaveLoader.API</RootNamespace>
<AssemblyName>WeaveLoader.API</AssemblyName>
<Description>Mod API for WeaveLoader - Minecraft Legacy Edition mod loader</Description>
<Version>1.0.0</Version>
<OutputPath>..\build\mods\LegacyForge.API</OutputPath>
<OutputPath>..\build\mods\WeaveLoader.API</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>

View File

@@ -1,8 +1,8 @@
using System.Reflection;
using System.Runtime.Loader;
using LegacyForge.API;
using WeaveLoader.API;
namespace LegacyForge.Core;
namespace WeaveLoader.Core;
internal static class ModDiscovery
{
@@ -21,18 +21,18 @@ internal static class ModDiscovery
return mods;
}
// Count LegacyForge.API as a mod when its folder exists (mods/LegacyForge.API/)
var apiFolder = Path.Combine(modsPath, "LegacyForge.API");
// Count WeaveLoader.API as a mod when its folder exists (mods/WeaveLoader.API/)
var apiFolder = Path.Combine(modsPath, "WeaveLoader.API");
if (Directory.Exists(apiFolder))
{
var apiMod = new LegacyForgeApiMod();
var attr = typeof(LegacyForgeApiMod).GetCustomAttribute<ModAttribute>()!;
var apiMod = new WeaveLoaderApiMod();
var attr = typeof(WeaveLoaderApiMod).GetCustomAttribute<ModAttribute>()!;
mods.Add(new DiscoveredMod(apiMod, attr, typeof(ModDiscovery).Assembly));
Logger.Info($"Discovered mod: {attr.Name} v{attr.Version} by {attr.Author} (mods/LegacyForge.API/)");
Logger.Info($"Discovered mod: {attr.Name} v{attr.Version} by {attr.Author} (mods/WeaveLoader.API/)");
}
// Scan each mod folder: mods/ExampleMod/, mods/SomeMod/, etc.
// Each subfolder may contain one or more mod DLLs (we skip LegacyForge.API.dll)
// Each subfolder may contain one or more mod DLLs (we skip WeaveLoader.API.dll)
var modFolders = Directory.GetDirectories(modsPath);
foreach (var folder in modFolders)
{
@@ -44,7 +44,7 @@ internal static class ModDiscovery
string fileName = Path.GetFileName(dllPath);
// Skip the API assembly -- it's in its own folder and counted above
if (fileName.Equals("LegacyForge.API.dll", StringComparison.OrdinalIgnoreCase))
if (fileName.Equals("WeaveLoader.API.dll", StringComparison.OrdinalIgnoreCase))
continue;
try
@@ -69,8 +69,8 @@ internal static class ModDiscovery
var fileName = Path.GetFileName(dllPath);
var fullPath = Path.GetFullPath(dllPath);
// Load into the SAME ALC that LegacyForge.Core lives in (the hostfxr component context).
// This ensures LegacyForge.API types (IMod, ModAttribute, etc.) have the same identity.
// Load into the SAME ALC that WeaveLoader.Core lives in (the hostfxr component context).
// This ensures WeaveLoader.API types (IMod, ModAttribute, etc.) have the same identity.
var coreContext = AssemblyLoadContext.GetLoadContext(typeof(ModDiscovery).Assembly)
?? AssemblyLoadContext.Default;
var assembly = coreContext.LoadFromAssemblyPath(fullPath);

View File

@@ -1,6 +1,6 @@
using LegacyForge.API;
using WeaveLoader.API;
namespace LegacyForge.Core;
namespace WeaveLoader.Core;
/// <summary>
/// Manages the lifecycle of all loaded mods.

View File

@@ -4,9 +4,9 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>LegacyForge.Core</RootNamespace>
<AssemblyName>LegacyForge.Core</AssemblyName>
<Description>LegacyForge core runtime - mod discovery and lifecycle management</Description>
<RootNamespace>WeaveLoader.Core</RootNamespace>
<AssemblyName>WeaveLoader.Core</AssemblyName>
<Description>WeaveLoader core runtime - mod discovery and lifecycle management</Description>
<Version>1.0.0</Version>
<OutputPath>..\build</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
@@ -14,7 +14,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\LegacyForge.API\LegacyForge.API.csproj" />
<ProjectReference Include="..\WeaveLoader.API\WeaveLoader.API.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,14 @@
using WeaveLoader.API;
namespace WeaveLoader.Core;
/// <summary>
/// Built-in mod representing the WeaveLoader API. Counts in the mod list and appears
/// when mods/WeaveLoader.API/ exists. Does not run lifecycle hooks.
/// </summary>
[Mod("weaveloader.api", Name = "WeaveLoader API", Version = "1.0.0", Author = "WeaveLoader",
Description = "Mod API and shared types")]
internal sealed class WeaveLoaderApiMod : IMod
{
public void OnInitialize() { }
}

View File

@@ -1,9 +1,9 @@
using System.Runtime.InteropServices;
using LegacyForge.API;
using WeaveLoader.API;
namespace LegacyForge.Core;
namespace WeaveLoader.Core;
public static class LegacyForgeCore
public static class WeaveLoaderCore
{
private static ModManager? _modManager;
private static bool _initialized;
@@ -15,7 +15,7 @@ public static class LegacyForgeCore
Logger.SetLogHandler((message, level) =>
{
string formatted = $"[LegacyForge/{level}] {message}";
string formatted = $"[WeaveLoader/{level}] {message}";
try
{
NativeInterop.native_log(formatted, (int)level);
@@ -26,7 +26,7 @@ public static class LegacyForgeCore
}
});
Logger.Info("LegacyForge Core initialized");
Logger.Info("WeaveLoader Core initialized");
_modManager = new ModManager();
return 0;
}
@@ -89,7 +89,7 @@ public static class LegacyForgeCore
public static int Shutdown(IntPtr args, int sizeBytes)
{
_modManager?.Shutdown();
Logger.Info("LegacyForge shut down.");
Logger.Info("WeaveLoader shut down.");
return 0;
}
}

View File

@@ -1,6 +1,6 @@
using System.Text.Json;
namespace LegacyForge.Launcher;
namespace WeaveLoader.Launcher;
public class Config
{

View File

@@ -1,6 +1,6 @@
using System.Runtime.InteropServices;
namespace LegacyForge.Launcher;
namespace WeaveLoader.Launcher;
/// <summary>
/// Thin wrapper around the Win32 GetOpenFileName API.

View File

@@ -3,11 +3,11 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
namespace LegacyForge.Launcher;
namespace WeaveLoader.Launcher;
/// <summary>
/// Handles launching the game process in a suspended state and injecting
/// the LegacyForgeRuntime DLL via CreateRemoteThread + LoadLibraryW.
/// the WeaveLoaderRuntime DLL via CreateRemoteThread + LoadLibraryW.
/// </summary>
public static class Injector
{

View File

@@ -1,23 +1,23 @@
using System.Runtime.InteropServices;
namespace LegacyForge.Launcher;
namespace WeaveLoader.Launcher;
class Program
{
private const string RuntimeDllName = "LegacyForgeRuntime.dll";
private const string RuntimeDllName = "WeaveLoaderRuntime.dll";
[STAThread]
static int Main(string[] args)
{
Console.WriteLine("╔══════════════════════════════════╗");
Console.WriteLine("║ LegacyForge v1.0 ║");
Console.WriteLine("║ WeaveLoader v1.0 ║");
Console.WriteLine("║ Mod Loader for MC Legacy Edition║");
Console.WriteLine("╚══════════════════════════════════╝");
Console.WriteLine();
// All paths relative to where the exe lives, not the working directory
string baseDir = AppContext.BaseDirectory;
string configFile = Path.Combine(baseDir, "legacyforge.json");
string configFile = Path.Combine(baseDir, "weaveloader.json");
string runtimeDll = Path.Combine(baseDir, RuntimeDllName);
string modsDir = Path.Combine(baseDir, "mods");
@@ -55,11 +55,11 @@ class Program
Console.Error.WriteLine($"Expected at: {runtimeDll}");
Console.Error.WriteLine();
Console.Error.WriteLine("The C++ runtime DLL must be built separately with CMake:");
Console.Error.WriteLine(" cd LegacyForgeRuntime");
Console.Error.WriteLine(" cd WeaveLoaderRuntime");
Console.Error.WriteLine(" cmake -B build -A x64");
Console.Error.WriteLine(" cmake --build build --config Release");
Console.Error.WriteLine();
Console.Error.WriteLine("Then copy LegacyForgeRuntime.dll to the same folder as LegacyForge.exe.");
Console.Error.WriteLine("Then copy WeaveLoaderRuntime.dll to the same folder as WeaveLoader.exe.");
return 1;
}
@@ -81,7 +81,7 @@ class Program
Console.WriteLine($"[OK] {RuntimeDllName} injected and loaded in target process.");
Injector.ResumeProcess(process);
Console.WriteLine("[OK] Game resumed. LegacyForge is active.");
Console.WriteLine("[OK] Game resumed. WeaveLoader is active.");
Console.WriteLine();
Console.WriteLine("Press any key to exit the launcher (game will keep running).");
Console.ReadKey(true);

View File

@@ -5,9 +5,9 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>LegacyForge.Launcher</RootNamespace>
<AssemblyName>LegacyForge</AssemblyName>
<Description>LegacyForge launcher - injects the mod loader runtime into Minecraft Legacy Edition</Description>
<RootNamespace>WeaveLoader.Launcher</RootNamespace>
<AssemblyName>WeaveLoader</AssemblyName>
<Description>WeaveLoader launcher - injects the mod loader runtime into Minecraft Legacy Edition</Description>
<Version>1.0.0</Version>
<OutputPath>..\build</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
@@ -16,17 +16,17 @@
<!-- Build the C++ runtime DLL via CMake before the launcher -->
<Target Name="BuildNativeRuntime" BeforeTargets="Build">
<Message Importance="high" Text="[LegacyForge] Configuring C++ runtime with CMake..." />
<Exec Command="cmake -B &quot;$(MSBuildThisFileDirectory)..\LegacyForgeRuntime\build&quot; -S &quot;$(MSBuildThisFileDirectory)..\LegacyForgeRuntime&quot; -A x64"
WorkingDirectory="$(MSBuildThisFileDirectory)..\LegacyForgeRuntime" />
<Message Importance="high" Text="[LegacyForge] Building C++ runtime..." />
<Exec Command="cmake --build &quot;$(MSBuildThisFileDirectory)..\LegacyForgeRuntime\build&quot; --config $(Configuration)"
WorkingDirectory="$(MSBuildThisFileDirectory)..\LegacyForgeRuntime" />
<Message Importance="high" Text="[WeaveLoader] Configuring C++ runtime with CMake..." />
<Exec Command="cmake -B &quot;$(MSBuildThisFileDirectory)..\WeaveLoaderRuntime\build&quot; -S &quot;$(MSBuildThisFileDirectory)..\WeaveLoaderRuntime&quot; -A x64"
WorkingDirectory="$(MSBuildThisFileDirectory)..\WeaveLoaderRuntime" />
<Message Importance="high" Text="[WeaveLoader] Building C++ runtime..." />
<Exec Command="cmake --build &quot;$(MSBuildThisFileDirectory)..\WeaveLoaderRuntime\build&quot; --config $(Configuration)"
WorkingDirectory="$(MSBuildThisFileDirectory)..\WeaveLoaderRuntime" />
</Target>
<!-- Copy the runtimeconfig.json to the build output -->
<Target Name="CopyRuntimeConfig" AfterTargets="Build">
<Copy SourceFiles="$(MSBuildThisFileDirectory)..\LegacyForge.Core\LegacyForge.Core.runtimeconfig.json"
<Copy SourceFiles="$(MSBuildThisFileDirectory)..\WeaveLoader.Core\WeaveLoader.Core.runtimeconfig.json"
DestinationFolder="$(OutputPath)"
SkipUnchangedFiles="true" />
</Target>

View File

@@ -3,11 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LegacyForge.Launcher", "LegacyForge.Launcher\LegacyForge.Launcher.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WeaveLoader.Launcher", "WeaveLoader.Launcher\WeaveLoader.Launcher.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LegacyForge.API", "LegacyForge.API\LegacyForge.API.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WeaveLoader.API", "WeaveLoader.API\WeaveLoader.API.csproj", "{B2C3D4E5-F6A7-8901-BCDE-F12345678901}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LegacyForge.Core", "LegacyForge.Core\LegacyForge.Core.csproj", "{C3D4E5F6-A7B8-9012-CDEF-123456789012}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WeaveLoader.Core", "WeaveLoader.Core\WeaveLoader.Core.csproj", "{C3D4E5F6-A7B8-9012-CDEF-123456789012}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleMod", "ExampleMod\ExampleMod.csproj", "{D4E5F6A7-B8C9-0123-DEF0-234567890123}"
EndProject

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.24)
cmake_policy(SET CMP0091 NEW)
project(LegacyForgeRuntime LANGUAGES CXX)
project(WeaveLoaderRuntime LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@@ -76,7 +76,7 @@ else()
endif()
# Runtime DLL target
add_library(LegacyForgeRuntime SHARED
add_library(WeaveLoaderRuntime SHARED
src/dllmain.cpp
src/LogUtil.cpp
src/CrashHandler.cpp
@@ -94,35 +94,35 @@ add_library(LegacyForgeRuntime SHARED
src/ModAtlas.cpp
)
target_include_directories(LegacyForgeRuntime PRIVATE
target_include_directories(WeaveLoaderRuntime PRIVATE
"${NETHOST_INCLUDE_DIR}"
"${STB_DIR}"
)
target_link_libraries(LegacyForgeRuntime PRIVATE
target_link_libraries(WeaveLoaderRuntime PRIVATE
minhook
raw_pdb
)
if(EXISTS "${NETHOST_LIB}")
target_link_libraries(LegacyForgeRuntime PRIVATE "${NETHOST_LIB}")
target_link_libraries(WeaveLoaderRuntime PRIVATE "${NETHOST_LIB}")
if(NETHOST_STATIC)
target_compile_definitions(LegacyForgeRuntime PRIVATE NETHOST_USE_AS_STATIC)
target_compile_definitions(WeaveLoaderRuntime PRIVATE NETHOST_USE_AS_STATIC)
endif()
else()
message(WARNING "nethost lib not found. You may need to set NETHOST_DIR.")
endif()
target_compile_definitions(LegacyForgeRuntime PRIVATE
target_compile_definitions(WeaveLoaderRuntime PRIVATE
WIN32_LEAN_AND_MEAN
_CRT_SECURE_NO_WARNINGS
)
if(MSVC)
target_compile_options(LegacyForgeRuntime PRIVATE /W3 /MP)
target_compile_options(WeaveLoaderRuntime PRIVATE /W3 /MP)
endif()
set_target_properties(LegacyForgeRuntime PROPERTIES
set_target_properties(WeaveLoaderRuntime PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../build"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../build"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_SOURCE_DIR}/../build"

View File

@@ -186,7 +186,7 @@ static LONG WINAPI VectoredHandler(EXCEPTION_POINTERS* ep)
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
LogUtil::LogCrash("========================================");
LogUtil::LogCrash(" LegacyForge Crash Report");
LogUtil::LogCrash(" WeaveLoader Crash Report");
LogUtil::LogCrash(" %s", timeBuf);
LogUtil::LogCrash("========================================");
LogUtil::LogCrash("");
@@ -263,7 +263,7 @@ static LONG WINAPI VectoredHandler(EXCEPTION_POINTERS* ep)
LogUtil::LogCrash("========================================");
LogUtil::LogCrash("");
LogUtil::Log("[LegacyForge] CRASH DETECTED - see logs/crash.log for details");
LogUtil::Log("[WeaveLoader] CRASH DETECTED - see logs/crash.log for details");
InterlockedExchange(&s_handling, 0);
return EXCEPTION_CONTINUE_SEARCH;
@@ -281,7 +281,7 @@ void Install(HMODULE runtimeModule)
void SetGameBase(uintptr_t base)
{
s_gameBase = base;
LogUtil::Log("[LegacyForge] Crash handler: game base set to 0x%016llX", (DWORD64)base);
LogUtil::Log("[WeaveLoader] Crash handler: game base set to 0x%016llX", (DWORD64)base);
}
} // namespace CrashHandler

View File

@@ -49,7 +49,7 @@ typedef void (__fastcall *VectorPushBackMove_fn)(void* vectorThis, void* sharedP
void AddPending(int itemId, int count, int auxValue, int groupIndex)
{
s_pendingItems.push_back({ itemId, count, auxValue, groupIndex });
LogUtil::Log("[LegacyForge] Queued creative item: id=%d group=%d", itemId, groupIndex);
LogUtil::Log("[WeaveLoader] Queued creative item: id=%d group=%d", itemId, groupIndex);
}
bool ResolveSymbols(SymbolResolver& resolver)
@@ -70,22 +70,22 @@ bool ResolveSymbols(SymbolResolver& resolver)
pSpecs = resolver.Resolve(
"?specs@IUIScene_CreativeMenu@@1PEAPEAUTabSpec@1@EA");
if (pCategoryGroups) LogUtil::Log("[LegacyForge] categoryGroups @ %p", pCategoryGroups);
else LogUtil::Log("[LegacyForge] MISSING: categoryGroups");
if (pCategoryGroups) LogUtil::Log("[WeaveLoader] categoryGroups @ %p", pCategoryGroups);
else LogUtil::Log("[WeaveLoader] MISSING: categoryGroups");
if (pItemInstanceCtor) LogUtil::Log("[LegacyForge] ItemInstance ctor @ %p", pItemInstanceCtor);
else LogUtil::Log("[LegacyForge] MISSING: ItemInstance(int,int,int)");
if (pItemInstanceCtor) LogUtil::Log("[WeaveLoader] ItemInstance ctor @ %p", pItemInstanceCtor);
else LogUtil::Log("[WeaveLoader] MISSING: ItemInstance(int,int,int)");
if (pSharedPtrCtor) LogUtil::Log("[LegacyForge] shared_ptr<II> ctor @ %p", pSharedPtrCtor);
else LogUtil::Log("[LegacyForge] MISSING: shared_ptr<ItemInstance>(ItemInstance*)");
if (pSharedPtrCtor) LogUtil::Log("[WeaveLoader] shared_ptr<II> ctor @ %p", pSharedPtrCtor);
else LogUtil::Log("[WeaveLoader] MISSING: shared_ptr<ItemInstance>(ItemInstance*)");
if (pVectorPushBack) LogUtil::Log("[LegacyForge] vector::push_back @ %p", pVectorPushBack);
else LogUtil::Log("[LegacyForge] MISSING: vector<shared_ptr<II>>::push_back");
if (pVectorPushBack) LogUtil::Log("[WeaveLoader] vector::push_back @ %p", pVectorPushBack);
else LogUtil::Log("[WeaveLoader] MISSING: vector<shared_ptr<II>>::push_back");
if (pSpecs) LogUtil::Log("[LegacyForge] specs @ %p", pSpecs);
if (pSpecs) LogUtil::Log("[WeaveLoader] specs @ %p", pSpecs);
else
{
LogUtil::Log("[LegacyForge] MISSING: specs (page counts won't be updated)");
LogUtil::Log("[WeaveLoader] MISSING: specs (page counts won't be updated)");
PdbParser::DumpMatching("specs@IUIScene_CreativeMenu");
}
@@ -104,7 +104,7 @@ void UpdateTabPageCounts()
{
if (!pSpecs || !pCategoryGroups)
{
LogUtil::Log("[LegacyForge] Cannot update tab page counts: specs=%p categoryGroups=%p",
LogUtil::Log("[WeaveLoader] Cannot update tab page counts: specs=%p categoryGroups=%p",
pSpecs, pCategoryGroups);
return;
}
@@ -112,7 +112,7 @@ void UpdateTabPageCounts()
void** specsArray = *reinterpret_cast<void***>(pSpecs);
if (!specsArray)
{
LogUtil::Log("[LegacyForge] specs pointer is null, TabSpec array not yet allocated");
LogUtil::Log("[WeaveLoader] specs pointer is null, TabSpec array not yet allocated");
return;
}
@@ -148,7 +148,7 @@ void UpdateTabPageCounts()
if (totalItems != oldItems)
{
LogUtil::Log("[LegacyForge] Tab %d: staticItems %u -> %u, pages %u -> %u",
LogUtil::Log("[WeaveLoader] Tab %d: staticItems %u -> %u, pages %u -> %u",
tabIdx, oldItems, totalItems, oldPages, static_cast<unsigned int>(newPages));
}
}
@@ -158,13 +158,13 @@ void InjectItems()
{
if (!pCategoryGroups || !pItemInstanceCtor || !pSharedPtrCtor || !pVectorPushBack)
{
LogUtil::Log("[LegacyForge] Cannot inject creative items: missing symbols");
LogUtil::Log("[WeaveLoader] Cannot inject creative items: missing symbols");
return;
}
if (s_pendingItems.empty())
{
LogUtil::Log("[LegacyForge] No creative items to inject");
LogUtil::Log("[WeaveLoader] No creative items to inject");
return;
}
@@ -180,7 +180,7 @@ void InjectItems()
{
if (item.groupIndex < 0 || item.groupIndex >= CREATIVE_GROUP_COUNT)
{
LogUtil::Log("[LegacyForge] Skipping creative item id=%d: invalid group %d",
LogUtil::Log("[WeaveLoader] Skipping creative item id=%d: invalid group %d",
item.itemId, item.groupIndex);
continue;
}
@@ -191,7 +191,7 @@ void InjectItems()
// Verify ItemInstance vtable was set (first 8 bytes should be non-null)
void* vtable = *reinterpret_cast<void**>(rawItem);
LogUtil::Log("[LegacyForge] ItemInstance(%d,%d,%d) @ %p, vtable=%p",
LogUtil::Log("[WeaveLoader] ItemInstance(%d,%d,%d) @ %p, vtable=%p",
item.itemId, item.count, item.auxValue, rawItem, vtable);
char spBuf[16];
@@ -201,7 +201,7 @@ void InjectItems()
// Log shared_ptr contents (ptr + control block)
void* spPtr = *reinterpret_cast<void**>(spBuf);
void* spCtrl = *reinterpret_cast<void**>(spBuf + 8);
LogUtil::Log("[LegacyForge] shared_ptr: ptr=%p ctrl=%p", spPtr, spCtrl);
LogUtil::Log("[WeaveLoader] shared_ptr: ptr=%p ctrl=%p", spPtr, spCtrl);
char* vec = groups + item.groupIndex * SIZEOF_MSVC_VECTOR;
size_t sizeBefore = ReadVectorSize(vec);
@@ -209,12 +209,12 @@ void InjectItems()
pushFn(vec, spBuf);
size_t sizeAfter = ReadVectorSize(vec);
LogUtil::Log("[LegacyForge] Injected item id=%d into creative group %d "
LogUtil::Log("[WeaveLoader] Injected item id=%d into creative group %d "
"(vector @ %p, size: %zu -> %zu)",
item.itemId, item.groupIndex, vec, sizeBefore, sizeAfter);
}
LogUtil::Log("[LegacyForge] Injected %zu items into creative inventory", s_pendingItems.size());
LogUtil::Log("[WeaveLoader] Injected %zu items into creative inventory", s_pendingItems.size());
s_pendingItems.clear();
}

View File

@@ -31,14 +31,14 @@ static bool LoadHostfxr()
int rc = get_hostfxr_path(buffer, &buffer_size, nullptr);
if (rc != 0)
{
LogUtil::Log("[LegacyForge] get_hostfxr_path failed: 0x%x", rc);
LogUtil::Log("[WeaveLoader] get_hostfxr_path failed: 0x%x", rc);
return false;
}
HMODULE lib = LoadLibraryW(buffer);
if (!lib)
{
LogUtil::Log("[LegacyForge] Failed to load hostfxr");
LogUtil::Log("[WeaveLoader] Failed to load hostfxr");
return false;
}
@@ -58,7 +58,7 @@ static load_assembly_and_get_function_pointer_fn GetDotNetLoadAssembly(const wch
int rc = init_fptr(configPath, nullptr, &cxt);
if (rc != 0 || cxt == nullptr)
{
LogUtil::Log("[LegacyForge] hostfxr_initialize failed: 0x%x", rc);
LogUtil::Log("[WeaveLoader] hostfxr_initialize failed: 0x%x", rc);
if (cxt) close_fptr(cxt);
return nullptr;
}
@@ -67,7 +67,7 @@ static load_assembly_and_get_function_pointer_fn GetDotNetLoadAssembly(const wch
rc = get_delegate_fptr(cxt, hdt_load_assembly_and_get_function_pointer, &load_fn);
if (rc != 0 || load_fn == nullptr)
{
LogUtil::Log("[LegacyForge] hostfxr_get_runtime_delegate failed: 0x%x", rc);
LogUtil::Log("[WeaveLoader] hostfxr_get_runtime_delegate failed: 0x%x", rc);
}
close_fptr(cxt);
@@ -82,7 +82,7 @@ static bool ResolveManagedMethod(
{
int rc = load_fn(
assemblyPath,
L"LegacyForge.Core.LegacyForgeCore, LegacyForge.Core",
L"WeaveLoader.Core.WeaveLoaderCore, WeaveLoader.Core",
methodName,
nullptr,
nullptr,
@@ -95,7 +95,7 @@ bool DotNetHost::Initialize()
{
if (!LoadHostfxr())
{
LogUtil::Log("[LegacyForge] Failed to load hostfxr library");
LogUtil::Log("[WeaveLoader] Failed to load hostfxr library");
return false;
}
@@ -123,13 +123,13 @@ bool DotNetHost::Initialize()
else
selfDir = L".\\";
std::wstring configPath = selfDir + L"LegacyForge.Core.runtimeconfig.json";
std::wstring assemblyPath = selfDir + L"LegacyForge.Core.dll";
std::wstring configPath = selfDir + L"WeaveLoader.Core.runtimeconfig.json";
std::wstring assemblyPath = selfDir + L"WeaveLoader.Core.dll";
auto load_fn = GetDotNetLoadAssembly(configPath.c_str());
if (!load_fn)
{
LogUtil::Log("[LegacyForge] Failed to get load_assembly_and_get_function_pointer");
LogUtil::Log("[WeaveLoader] Failed to get load_assembly_and_get_function_pointer");
return false;
}
@@ -144,11 +144,11 @@ bool DotNetHost::Initialize()
if (!ok)
{
LogUtil::Log("[LegacyForge] Failed to resolve one or more managed entry points");
LogUtil::Log("[WeaveLoader] Failed to resolve one or more managed entry points");
return false;
}
LogUtil::Log("[LegacyForge] All managed entry points resolved");
LogUtil::Log("[WeaveLoader] All managed entry points resolved");
return true;
}

View File

@@ -2,7 +2,7 @@
#include <cstdint>
/// Hosts the .NET CoreCLR runtime inside the game process using the hostfxr API.
/// Loads LegacyForge.Core.dll and resolves managed entry point methods.
/// Loads WeaveLoader.Core.dll and resolves managed entry point methods.
namespace DotNetHost
{
bool Initialize();

View File

@@ -27,12 +27,12 @@ namespace GameHooks
void __fastcall Hooked_LoadUVs(void* thisPtr)
{
LogUtil::Log("[LegacyForge] Hooked_LoadUVs: ENTER (textureMap=%p)", thisPtr);
LogUtil::Log("[WeaveLoader] Hooked_LoadUVs: ENTER (textureMap=%p)", thisPtr);
if (Original_LoadUVs)
Original_LoadUVs(thisPtr);
LogUtil::Log("[LegacyForge] Hooked_LoadUVs: original returned, creating mod icons");
LogUtil::Log("[WeaveLoader] Hooked_LoadUVs: original returned, creating mod icons");
ModAtlas::CreateModIcons(thisPtr);
LogUtil::Log("[LegacyForge] Hooked_LoadUVs: DONE");
LogUtil::Log("[WeaveLoader] Hooked_LoadUVs: DONE");
}
static int s_registerIconCallCount = 0;
@@ -43,14 +43,14 @@ namespace GameHooks
void* modIcon = ModAtlas::LookupModIcon(name);
if (modIcon)
{
LogUtil::Log("[LegacyForge] registerIcon #%d: '%ls' -> MOD ICON %p",
LogUtil::Log("[WeaveLoader] registerIcon #%d: '%ls' -> MOD ICON %p",
s_registerIconCallCount, name.c_str(), modIcon);
return modIcon;
}
void* result = Original_RegisterIcon ? Original_RegisterIcon(thisPtr, name) : nullptr;
if (s_registerIconCallCount <= 30 || !result)
{
LogUtil::Log("[LegacyForge] registerIcon #%d: '%ls' -> vanilla %p",
LogUtil::Log("[WeaveLoader] registerIcon #%d: '%ls' -> vanilla %p",
s_registerIconCallCount, name.c_str(), result);
}
return result;
@@ -66,13 +66,13 @@ namespace GameHooks
if (!terrainPath.empty() && path->find(L"terrain.png") != std::wstring::npos)
{
std::wstring ourPath(terrainPath.begin(), terrainPath.end());
LogUtil::Log("[LegacyForge] getResourceAsStream: redirecting terrain.png to merged atlas");
LogUtil::Log("[WeaveLoader] getResourceAsStream: redirecting terrain.png to merged atlas");
return Original_GetResourceAsStream(&ourPath);
}
if (!itemsPath.empty() && path->find(L"items.png") != std::wstring::npos)
{
std::wstring ourPath(itemsPath.begin(), itemsPath.end());
LogUtil::Log("[LegacyForge] getResourceAsStream: redirecting items.png to merged atlas");
LogUtil::Log("[WeaveLoader] getResourceAsStream: redirecting items.png to merged atlas");
return Original_GetResourceAsStream(&ourPath);
}
}
@@ -85,7 +85,7 @@ namespace GameHooks
if (ModStrings::IsModId(id))
{
const wchar_t* modStr = ModStrings::Get(id);
LogUtil::Log("[LegacyForge] GetString(id=%d) -> mod '%ls'", id,
LogUtil::Log("[WeaveLoader] GetString(id=%d) -> mod '%ls'", id,
(modStr && modStr[0]) ? modStr : L"<null/empty>");
if (modStr && modStr[0])
return modStr;
@@ -95,7 +95,7 @@ namespace GameHooks
{
s_loggedGetString = true;
const wchar_t* r = Original_GetString ? Original_GetString(id) : L"";
LogUtil::Log("[LegacyForge] GetString(id=%d) -> vanilla '%ls' (first call sample)", id, r ? r : L"<null>");
LogUtil::Log("[WeaveLoader] GetString(id=%d) -> vanilla '%ls' (first call sample)", id, r ? r : L"<null>");
return r;
}
return Original_GetString ? Original_GetString(id) : L"";
@@ -104,12 +104,12 @@ namespace GameHooks
void Hooked_RunStaticCtors()
{
LogUtil::Log("[LegacyForge] Hook: RunStaticCtors -- calling PreInit");
LogUtil::Log("[WeaveLoader] Hook: RunStaticCtors -- calling PreInit");
DotNetHost::CallPreInit();
Original_RunStaticCtors();
LogUtil::Log("[LegacyForge] Hook: RunStaticCtors complete -- calling Init");
LogUtil::Log("[WeaveLoader] Hook: RunStaticCtors complete -- calling Init");
DotNetHost::CallInit();
// Inject mod strings directly into the game's StringTable vector.
@@ -167,13 +167,13 @@ namespace GameHooks
// fully populated. Copy it to our mod icons so getSourceHeight() works.
ModAtlas::FixupModIcons();
LogUtil::Log("[LegacyForge] Hook: Minecraft::init complete -- calling PostInit");
LogUtil::Log("[WeaveLoader] Hook: Minecraft::init complete -- calling PostInit");
DotNetHost::CallPostInit();
}
void __fastcall Hooked_ExitGame(void* thisPtr)
{
LogUtil::Log("[LegacyForge] Hook: ExitGame -- calling Shutdown");
LogUtil::Log("[WeaveLoader] Hook: ExitGame -- calling Shutdown");
DotNetHost::CallShutdown();
Original_ExitGame(thisPtr);
@@ -183,15 +183,15 @@ namespace GameHooks
{
// Inject mod items BEFORE vanilla staticCtor so they are included in the
// TabSpec page-count calculation that happens at the end of staticCtor.
LogUtil::Log("[LegacyForge] Hook: CreativeStaticCtor -- injecting modded items first");
LogUtil::Log("[WeaveLoader] Hook: CreativeStaticCtor -- injecting modded items first");
CreativeInventory::InjectItems();
LogUtil::Log("[LegacyForge] Hook: CreativeStaticCtor -- building vanilla creative lists");
LogUtil::Log("[WeaveLoader] Hook: CreativeStaticCtor -- building vanilla creative lists");
Original_CreativeStaticCtor();
// Safety: recalculate TabSpec page counts in case the injection-before
// approach didn't fully account for all items (e.g. different binary).
LogUtil::Log("[LegacyForge] Hook: CreativeStaticCtor -- updating tab page counts");
LogUtil::Log("[WeaveLoader] Hook: CreativeStaticCtor -- updating tab page counts");
CreativeInventory::UpdateTabPageCounts();
}

View File

@@ -68,7 +68,7 @@ namespace GameObjectFactory
bool ResolveSymbols(SymbolResolver& resolver)
{
LogUtil::Log("[LegacyForge] GameObjectFactory: resolving symbols...");
LogUtil::Log("[WeaveLoader] GameObjectFactory: resolving symbols...");
// Tile constructor — protected (IEAA not QEAA)
fnTileCtor = (TileCtor_fn)resolver.Resolve("??0Tile@@IEAA@HPEAVMaterial@@_N@Z");
@@ -104,23 +104,23 @@ bool ResolveSymbols(SymbolResolver& resolver)
{
// mov eax, [rcx+disp8] — 8B 41 XX
s_itemDescIdOffset = static_cast<int>(code[2]);
LogUtil::Log("[LegacyForge] Item descriptionId offset = 0x%X (from getDescriptionId disp8)", s_itemDescIdOffset);
LogUtil::Log("[WeaveLoader] Item descriptionId offset = 0x%X (from getDescriptionId disp8)", s_itemDescIdOffset);
}
else if (code[0] == 0x8B && code[1] == 0x81)
{
// mov eax, [rcx+disp32] — 8B 81 XX XX XX XX
s_itemDescIdOffset = *reinterpret_cast<const int*>(code + 2);
LogUtil::Log("[LegacyForge] Item descriptionId offset = 0x%X (from getDescriptionId disp32)", s_itemDescIdOffset);
LogUtil::Log("[WeaveLoader] Item descriptionId offset = 0x%X (from getDescriptionId disp32)", s_itemDescIdOffset);
}
else
{
LogUtil::Log("[LegacyForge] Item::getDescriptionId has unexpected opcode pattern: %02X %02X %02X",
LogUtil::Log("[WeaveLoader] Item::getDescriptionId has unexpected opcode pattern: %02X %02X %02X",
code[0], code[1], code[2]);
}
}
else
{
LogUtil::Log("[LegacyForge] MISSING: Item::getDescriptionId — cannot set item display names");
LogUtil::Log("[WeaveLoader] MISSING: Item::getDescriptionId — cannot set item display names");
}
// Resolve Material* static pointer ADDRESSES (values are NULL until staticCtor runs)
@@ -160,8 +160,8 @@ bool ResolveSymbols(SymbolResolver& resolver)
resolveSound(9, "?SOUND_SNOW@Tile@@2PEAVSoundType@1@EA");
auto logSym = [](const char* name, void* ptr) {
if (ptr) LogUtil::Log("[LegacyForge] GOF %-20s @ %p", name, ptr);
else LogUtil::Log("[LegacyForge] GOF MISSING: %s", name);
if (ptr) LogUtil::Log("[WeaveLoader] GOF %-20s @ %p", name, ptr);
else LogUtil::Log("[WeaveLoader] GOF MISSING: %s", name);
};
logSym("Tile::Tile", (void*)fnTileCtor);
@@ -190,9 +190,9 @@ bool ResolveSymbols(SymbolResolver& resolver)
s_resolved = fnTileCtor && fnTileItemCtor && fnItemCtor;
if (s_resolved)
LogUtil::Log("[LegacyForge] GameObjectFactory: core symbols resolved OK");
LogUtil::Log("[WeaveLoader] GameObjectFactory: core symbols resolved OK");
else
LogUtil::Log("[LegacyForge] GameObjectFactory: MISSING core symbols -- block/item creation disabled");
LogUtil::Log("[WeaveLoader] GameObjectFactory: MISSING core symbols -- block/item creation disabled");
return s_resolved;
}
@@ -202,7 +202,7 @@ bool CreateTile(int tileId, int materialType, float hardness, float resistance,
{
if (!s_resolved || !fnTileCtor)
{
LogUtil::Log("[LegacyForge] CreateTile: symbols not resolved");
LogUtil::Log("[WeaveLoader] CreateTile: symbols not resolved");
return false;
}
@@ -213,7 +213,7 @@ bool CreateTile(int tileId, int materialType, float hardness, float resistance,
if (!mat)
{
LogUtil::Log("[LegacyForge] CreateTile: no material pointer for type %d", materialType);
LogUtil::Log("[WeaveLoader] CreateTile: no material pointer for type %d", materialType);
return false;
}
@@ -242,7 +242,7 @@ bool CreateTile(int tileId, int materialType, float hardness, float resistance,
fnTileSetDescriptionId(tile, static_cast<unsigned int>(descriptionId));
}
LogUtil::Log("[LegacyForge] Created Tile id=%d (material=%d, icon=%ls, descId=%d)", tileId, materialType,
LogUtil::Log("[WeaveLoader] Created Tile id=%d (material=%d, icon=%ls, descId=%d)", tileId, materialType,
iconName ? iconName : L"<none>", descriptionId);
// Create the corresponding TileItem so the block can appear in inventory.
@@ -252,7 +252,7 @@ bool CreateTile(int tileId, int materialType, float hardness, float resistance,
void* tileItem = ::operator new(TILEITEM_ALLOC_SIZE);
memset(tileItem, 0, TILEITEM_ALLOC_SIZE);
fnTileItemCtor(tileItem, tileId - 256);
LogUtil::Log("[LegacyForge] Created TileItem for tile %d", tileId);
LogUtil::Log("[WeaveLoader] Created TileItem for tile %d", tileId);
}
return true;
@@ -262,7 +262,7 @@ bool CreateItem(int itemId, int maxStackSize, const wchar_t* iconName, int descr
{
if (!s_resolved || !fnItemCtor)
{
LogUtil::Log("[LegacyForge] CreateItem: symbols not resolved");
LogUtil::Log("[WeaveLoader] CreateItem: symbols not resolved");
return false;
}
@@ -286,7 +286,7 @@ bool CreateItem(int itemId, int maxStackSize, const wchar_t* iconName, int descr
static_cast<unsigned int>(descriptionId);
}
LogUtil::Log("[LegacyForge] Created Item id=%d (ctorParam=%d, icon=%ls, descId=%d)",
LogUtil::Log("[WeaveLoader] Created Item id=%d (ctorParam=%d, icon=%ls, descId=%d)",
itemId, ctorParam, iconName ? iconName : L"<none>", descriptionId);
return true;

View File

@@ -13,7 +13,7 @@ bool HookManager::Install(const SymbolResolver& symbols)
{
if (MH_Initialize() != MH_OK)
{
LogUtil::Log("[LegacyForge] MH_Initialize failed");
LogUtil::Log("[WeaveLoader] MH_Initialize failed");
return false;
}
@@ -23,10 +23,10 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_RunStaticCtors),
reinterpret_cast<void**>(&GameHooks::Original_RunStaticCtors)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Failed to hook RunStaticCtors");
LogUtil::Log("[WeaveLoader] Failed to hook RunStaticCtors");
return false;
}
LogUtil::Log("[LegacyForge] Hooked RunStaticCtors");
LogUtil::Log("[WeaveLoader] Hooked RunStaticCtors");
}
if (symbols.pMinecraftTick)
@@ -35,10 +35,10 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_MinecraftTick),
reinterpret_cast<void**>(&GameHooks::Original_MinecraftTick)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Failed to hook Minecraft::tick");
LogUtil::Log("[WeaveLoader] Failed to hook Minecraft::tick");
return false;
}
LogUtil::Log("[LegacyForge] Hooked Minecraft::tick");
LogUtil::Log("[WeaveLoader] Hooked Minecraft::tick");
}
if (symbols.pMinecraftInit)
@@ -47,10 +47,10 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_MinecraftInit),
reinterpret_cast<void**>(&GameHooks::Original_MinecraftInit)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Failed to hook Minecraft::init");
LogUtil::Log("[WeaveLoader] Failed to hook Minecraft::init");
return false;
}
LogUtil::Log("[LegacyForge] Hooked Minecraft::init");
LogUtil::Log("[WeaveLoader] Hooked Minecraft::init");
}
if (symbols.pExitGame)
@@ -59,11 +59,11 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_ExitGame),
reinterpret_cast<void**>(&GameHooks::Original_ExitGame)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Warning: Failed to hook ExitGame (shutdown hook unavailable)");
LogUtil::Log("[WeaveLoader] Warning: Failed to hook ExitGame (shutdown hook unavailable)");
}
else
{
LogUtil::Log("[LegacyForge] Hooked ExitGame");
LogUtil::Log("[WeaveLoader] Hooked ExitGame");
}
}
@@ -76,11 +76,11 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_LoadUVs),
reinterpret_cast<void**>(&GameHooks::Original_LoadUVs)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Warning: Failed to hook PreStitchedTextureMap::loadUVs (mod textures may not appear)");
LogUtil::Log("[WeaveLoader] Warning: Failed to hook PreStitchedTextureMap::loadUVs (mod textures may not appear)");
}
else
{
LogUtil::Log("[LegacyForge] Hooked PreStitchedTextureMap::loadUVs (mod texture injection)");
LogUtil::Log("[WeaveLoader] Hooked PreStitchedTextureMap::loadUVs (mod texture injection)");
}
if (symbols.pRegisterIcon)
@@ -89,11 +89,11 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_RegisterIcon),
reinterpret_cast<void**>(&GameHooks::Original_RegisterIcon)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Warning: Failed to hook PreStitchedTextureMap::registerIcon");
LogUtil::Log("[WeaveLoader] Warning: Failed to hook PreStitchedTextureMap::registerIcon");
}
else
{
LogUtil::Log("[LegacyForge] Hooked PreStitchedTextureMap::registerIcon (mod icon lookup)");
LogUtil::Log("[WeaveLoader] Hooked PreStitchedTextureMap::registerIcon (mod icon lookup)");
// Pass the trampoline to ModAtlas so it can look up vanilla icons
// for copying internal state (field_0x48 source image pointer).
ModAtlas::SetRegisterIconFn(GameHooks::Original_RegisterIcon);
@@ -102,7 +102,7 @@ bool HookManager::Install(const SymbolResolver& symbols)
}
else if (symbols.pLoadUVs)
{
LogUtil::Log("[LegacyForge] Mod texture injection unavailable: SimpleIcon/operator new not resolved");
LogUtil::Log("[WeaveLoader] Mod texture injection unavailable: SimpleIcon/operator new not resolved");
}
if (symbols.pCreativeStaticCtor)
@@ -113,11 +113,11 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_CreativeStaticCtor),
reinterpret_cast<void**>(&GameHooks::Original_CreativeStaticCtor)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Warning: Failed to hook CreativeStaticCtor");
LogUtil::Log("[WeaveLoader] Warning: Failed to hook CreativeStaticCtor");
}
else
{
LogUtil::Log("[LegacyForge] Hooked CreativeStaticCtor");
LogUtil::Log("[WeaveLoader] Hooked CreativeStaticCtor");
}
}
@@ -127,11 +127,11 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_MainMenuCustomDraw),
reinterpret_cast<void**>(&GameHooks::Original_MainMenuCustomDraw)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Warning: Failed to hook MainMenuCustomDraw");
LogUtil::Log("[WeaveLoader] Warning: Failed to hook MainMenuCustomDraw");
}
else
{
LogUtil::Log("[LegacyForge] Hooked MainMenuCustomDraw");
LogUtil::Log("[WeaveLoader] Hooked MainMenuCustomDraw");
}
}
@@ -143,11 +143,11 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_Present),
reinterpret_cast<void**>(&GameHooks::Original_Present)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Warning: Failed to hook C4JRender::Present");
LogUtil::Log("[WeaveLoader] Warning: Failed to hook C4JRender::Present");
}
else
{
LogUtil::Log("[LegacyForge] Hooked C4JRender::Present");
LogUtil::Log("[WeaveLoader] Hooked C4JRender::Present");
}
}
@@ -160,11 +160,11 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_GetString),
reinterpret_cast<void**>(&GameHooks::Original_GetString)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Warning: Failed to hook CMinecraftApp::GetString (mod names unavailable)");
LogUtil::Log("[WeaveLoader] Warning: Failed to hook CMinecraftApp::GetString (mod names unavailable)");
}
else
{
LogUtil::Log("[LegacyForge] Hooked CMinecraftApp::GetString (mod localization)");
LogUtil::Log("[WeaveLoader] Hooked CMinecraftApp::GetString (mod localization)");
}
}
@@ -175,11 +175,11 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_GetResourceAsStream),
reinterpret_cast<void**>(&GameHooks::Original_GetResourceAsStream)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Warning: Failed to hook InputStream::getResourceAsStream (mod atlas unavailable)");
LogUtil::Log("[WeaveLoader] Warning: Failed to hook InputStream::getResourceAsStream (mod atlas unavailable)");
}
else
{
LogUtil::Log("[LegacyForge] Hooked InputStream::getResourceAsStream (mod textures)");
LogUtil::Log("[WeaveLoader] Hooked InputStream::getResourceAsStream (mod textures)");
}
}
@@ -192,22 +192,22 @@ bool HookManager::Install(const SymbolResolver& symbols)
reinterpret_cast<void*>(&GameHooks::Hooked_OutputDebugStringA),
reinterpret_cast<void**>(&GameHooks::Original_OutputDebugStringA)) != MH_OK)
{
LogUtil::Log("[LegacyForge] Warning: Failed to hook OutputDebugStringA");
LogUtil::Log("[WeaveLoader] Warning: Failed to hook OutputDebugStringA");
}
else
{
LogUtil::Log("[LegacyForge] Hooked OutputDebugStringA (game log capture)");
LogUtil::Log("[WeaveLoader] Hooked OutputDebugStringA (game log capture)");
}
}
}
if (MH_EnableHook(MH_ALL_HOOKS) != MH_OK)
{
LogUtil::Log("[LegacyForge] MH_EnableHook(MH_ALL_HOOKS) failed");
LogUtil::Log("[WeaveLoader] MH_EnableHook(MH_ALL_HOOKS) failed");
return false;
}
LogUtil::Log("[LegacyForge] All hooks installed and enabled");
LogUtil::Log("[WeaveLoader] All hooks installed and enabled");
return true;
}

View File

@@ -34,7 +34,7 @@ int IdRegistry::Register(Type type, const std::string& namespacedId)
if (reg.nextFreeId > maxId)
{
LogUtil::Log("[LegacyForge] IdRegistry: No free IDs for type %d (max %d)",
LogUtil::Log("[WeaveLoader] IdRegistry: No free IDs for type %d (max %d)",
static_cast<int>(type), maxId);
return -1;
}

View File

@@ -26,7 +26,7 @@ void SetBaseDir(const char* baseDir)
{
s_logsDir = std::string(baseDir) + "logs\\";
CreateDirectoryA(s_logsDir.c_str(), nullptr);
s_logPath = s_logsDir + "legacyforge.log";
s_logPath = s_logsDir + "weaveloader.log";
s_gameLogPath = s_logsDir + "game_debug.log";
s_crashLogPath = s_logsDir + "crash.log";
}

View File

@@ -10,7 +10,7 @@ namespace LogUtil
// Returns the logs directory path (with trailing backslash)
const char* GetLogsDir();
// Appends a timestamped line to legacyforge.log and prints to stdout
// Appends a timestamped line to weaveloader.log and prints to stdout
void Log(const char* fmt, ...);
// Writes game debug output to game_debug.log with a timestamp

View File

@@ -83,9 +83,9 @@ bool ResolveSymbols(SymbolResolver& resolver)
fnMatrixTranslate && fnDepthTest && fnDrawShadow;
if (s_symbolsOk)
LogUtil::Log("[LegacyForge] MainMenuOverlay symbols resolved OK");
LogUtil::Log("[WeaveLoader] MainMenuOverlay symbols resolved OK");
else
LogUtil::Log("[LegacyForge] Warning: some MainMenuOverlay symbols missing -- branding text disabled");
LogUtil::Log("[WeaveLoader] Warning: some MainMenuOverlay symbols missing -- branding text disabled");
return s_symbolsOk;
}
@@ -115,7 +115,7 @@ void RenderBranding()
if (!s_loggedOnce)
{
LogUtil::Log("[LegacyForge] MainMenuOverlay: first render (screen %dx%d, font=%p, rm=%p)",
LogUtil::Log("[WeaveLoader] MainMenuOverlay: first render (screen %dx%d, font=%p, rm=%p)",
pixelW, pixelH, font, pRenderManager);
s_loggedOnce = true;
}
@@ -145,7 +145,7 @@ void RenderBranding()
fnDepthTest(rm, false);
if (fnBlendEnable) fnBlendEnable(rm, true);
std::wstring line1 = L"LegacyForge v" LEGACYFORGE_VERSION;
std::wstring line1 = L"WeaveLoader v" LEGACYFORGE_VERSION;
wchar_t line2Buf[64];
swprintf(line2Buf, 64, L"%d mod(s) loaded successfully", s_modCount);

View File

@@ -168,7 +168,7 @@ namespace ModAtlas
}
}
LogUtil::Log("[LegacyForge] ModAtlas: found %zu empty cells in %dx%d atlas",
LogUtil::Log("[WeaveLoader] ModAtlas: found %zu empty cells in %dx%d atlas",
emptyCells.size(), gridCols, gridRows);
size_t cellIdx = 0;
@@ -179,7 +179,7 @@ namespace ModAtlas
if (cellIdx >= emptyCells.size())
{
LogUtil::Log("[LegacyForge] ModAtlas: no empty cells left for %s!", iconName.c_str());
LogUtil::Log("[WeaveLoader] ModAtlas: no empty cells left for %s!", iconName.c_str());
break;
}
@@ -187,7 +187,7 @@ namespace ModAtlas
unsigned char* src = nullptr;
if (!LoadPng(path, &sw, &sh, &sc, &src))
{
LogUtil::Log("[LegacyForge] ModAtlas: failed to load %s", path.c_str());
LogUtil::Log("[WeaveLoader] ModAtlas: failed to load %s", path.c_str());
continue;
}
@@ -201,7 +201,7 @@ namespace ModAtlas
std::wstring wname(iconName.begin(), iconName.end());
entries.push_back({ wname, 0, row, col });
LogUtil::Log("[LegacyForge] ModAtlas: placed '%s' at row=%d col=%d", iconName.c_str(), row, col);
LogUtil::Log("[WeaveLoader] ModAtlas: placed '%s' at row=%d col=%d", iconName.c_str(), row, col);
}
std::string dir = outPath.substr(0, outPath.find_last_of("\\/"));
@@ -223,7 +223,7 @@ namespace ModAtlas
if (blockPaths.empty() && itemPaths.empty())
{
LogUtil::Log("[LegacyForge] ModAtlas: no mod textures found");
LogUtil::Log("[WeaveLoader] ModAtlas: no mod textures found");
return "";
}
@@ -248,7 +248,7 @@ namespace ModAtlas
if (BuildAtlas(vanillaTerrain, outTerrain, blockPaths, 16, 32, 16, s_blockEntries))
{
s_hasModTextures = true;
LogUtil::Log("[LegacyForge] ModAtlas: built terrain.png with %zu mod textures", s_blockEntries.size());
LogUtil::Log("[WeaveLoader] ModAtlas: built terrain.png with %zu mod textures", s_blockEntries.size());
}
}
@@ -258,7 +258,7 @@ namespace ModAtlas
{
s_hasModTextures = true;
for (auto& e : s_itemEntries) e.atlasType = 1;
LogUtil::Log("[LegacyForge] ModAtlas: built items.png with %zu mod textures", s_itemEntries.size());
LogUtil::Log("[WeaveLoader] ModAtlas: built items.png with %zu mod textures", s_itemEntries.size());
}
}
@@ -312,32 +312,32 @@ namespace ModAtlas
if (!mergedTerrain.empty() && !s_blockEntries.empty())
{
s_backupTerrainPath = vanillaTerrain + ".legacyforge_backup";
s_backupTerrainPath = vanillaTerrain + ".weaveloader_backup";
CopyFileA(vanillaTerrain.c_str(), s_backupTerrainPath.c_str(), FALSE);
if (CopyFileA(mergedTerrain.c_str(), vanillaTerrain.c_str(), FALSE))
LogUtil::Log("[LegacyForge] ModAtlas: installed merged terrain.png over game file");
LogUtil::Log("[WeaveLoader] ModAtlas: installed merged terrain.png over game file");
else
LogUtil::Log("[LegacyForge] ModAtlas: WARNING - failed to copy merged terrain.png (err=%lu)", GetLastError());
LogUtil::Log("[WeaveLoader] ModAtlas: WARNING - failed to copy merged terrain.png (err=%lu)", GetLastError());
}
if (!mergedItems.empty() && !s_itemEntries.empty())
{
s_backupItemsPath = vanillaItems + ".legacyforge_backup";
s_backupItemsPath = vanillaItems + ".weaveloader_backup";
CopyFileA(vanillaItems.c_str(), s_backupItemsPath.c_str(), FALSE);
if (CopyFileA(mergedItems.c_str(), vanillaItems.c_str(), FALSE))
LogUtil::Log("[LegacyForge] ModAtlas: installed merged items.png over game file");
LogUtil::Log("[WeaveLoader] ModAtlas: installed merged items.png over game file");
else
LogUtil::Log("[LegacyForge] ModAtlas: WARNING - failed to copy merged items.png (err=%lu)", GetLastError());
LogUtil::Log("[WeaveLoader] ModAtlas: WARNING - failed to copy merged items.png (err=%lu)", GetLastError());
}
}
void CreateModIcons(void* textureMap)
{
if (!s_hasModTextures || !s_simpleIconCtor || !textureMap) return;
if (!s_operatorNew) { LogUtil::Log("[LegacyForge] ModAtlas: operator new not resolved, skipping icon creation"); return; }
if (!s_operatorNew) { LogUtil::Log("[WeaveLoader] ModAtlas: operator new not resolved, skipping icon creation"); return; }
int iconType = *reinterpret_cast<int*>(reinterpret_cast<char*>(textureMap) + 8);
LogUtil::Log("[LegacyForge] ModAtlas: CreateModIcons called for atlas type %d (textureMap=%p)", iconType, textureMap);
LogUtil::Log("[WeaveLoader] ModAtlas: CreateModIcons called for atlas type %d (textureMap=%p)", iconType, textureMap);
if (iconType == 0) s_terrainTextureMap = textureMap;
else if (iconType == 1) s_itemsTextureMap = textureMap;
@@ -363,7 +363,7 @@ namespace ModAtlas
memset(icon, 0, 128);
ctor(icon, &e.iconName, &e.iconName, u0, v0, u1, v1);
s_modIcons[e.iconName] = icon;
LogUtil::Log("[LegacyForge] ModAtlas: created icon '%ls' (atlas=%d, row=%d, col=%d)",
LogUtil::Log("[WeaveLoader] ModAtlas: created icon '%ls' (atlas=%d, row=%d, col=%d)",
e.iconName.c_str(), iconType, e.row, e.col);
}
}
@@ -374,7 +374,7 @@ namespace ModAtlas
else if (iconType == 1)
create(s_itemEntries, 1.0f / 16.0f);
LogUtil::Log("[LegacyForge] ModAtlas: s_modIcons now has %zu entries total", s_modIcons.size());
LogUtil::Log("[WeaveLoader] ModAtlas: s_modIcons now has %zu entries total", s_modIcons.size());
}
void FixupModIcons()
@@ -391,16 +391,16 @@ namespace ModAtlas
void* probeIcon = s_originalRegisterIcon(textureMap, probeStr);
if (!probeIcon)
{
LogUtil::Log("[LegacyForge] FixupModIcons: could not find vanilla icon '%ls'", probeName);
LogUtil::Log("[WeaveLoader] FixupModIcons: could not find vanilla icon '%ls'", probeName);
return;
}
void* srcPtr = *reinterpret_cast<void**>(static_cast<char*>(probeIcon) + 0x48);
LogUtil::Log("[LegacyForge] FixupModIcons: vanilla '%ls' field_0x48 = %p", probeName, srcPtr);
LogUtil::Log("[WeaveLoader] FixupModIcons: vanilla '%ls' field_0x48 = %p", probeName, srcPtr);
if (!srcPtr)
{
LogUtil::Log("[LegacyForge] FixupModIcons: WARNING - vanilla source ptr still NULL for atlas %d", atlasType);
LogUtil::Log("[WeaveLoader] FixupModIcons: WARNING - vanilla source ptr still NULL for atlas %d", atlasType);
return;
}
@@ -415,7 +415,7 @@ namespace ModAtlas
fixed++;
}
}
LogUtil::Log("[LegacyForge] FixupModIcons: patched field_0x48 on %d mod icons (atlas %d, srcPtr=%p)",
LogUtil::Log("[WeaveLoader] FixupModIcons: patched field_0x48 on %d mod icons (atlas %d, srcPtr=%p)",
fixed, atlasType, srcPtr);
};
@@ -427,14 +427,14 @@ namespace ModAtlas
{
std::string vanillaTerrain = s_gameResPath + "\\terrain.png";
if (MoveFileExA(s_backupTerrainPath.c_str(), vanillaTerrain.c_str(), MOVEFILE_REPLACE_EXISTING))
LogUtil::Log("[LegacyForge] ModAtlas: restored original terrain.png");
LogUtil::Log("[WeaveLoader] ModAtlas: restored original terrain.png");
s_backupTerrainPath.clear();
}
if (!s_backupItemsPath.empty())
{
std::string vanillaItems = s_gameResPath + "\\items.png";
if (MoveFileExA(s_backupItemsPath.c_str(), vanillaItems.c_str(), MOVEFILE_REPLACE_EXISTING))
LogUtil::Log("[LegacyForge] ModAtlas: restored original items.png");
LogUtil::Log("[WeaveLoader] ModAtlas: restored original items.png");
s_backupItemsPath.clear();
}
}

View File

@@ -21,7 +21,7 @@ namespace ModStrings
if (!value) return;
std::lock_guard<std::mutex> lock(s_mutex);
s_strings[descriptionId] = value;
LogUtil::Log("[LegacyForge] ModStrings: registered id=%d -> %ls", descriptionId, value);
LogUtil::Log("[WeaveLoader] ModStrings: registered id=%d -> %ls", descriptionId, value);
}
const wchar_t* Get(int descriptionId)
@@ -51,13 +51,13 @@ namespace ModStrings
if (!pGetStringFunc) return;
const uint8_t* code = static_cast<const uint8_t*>(pGetStringFunc);
LogUtil::Log("[LegacyForge] ModStrings: scanning GetString prologue at %p", pGetStringFunc);
LogUtil::Log("[WeaveLoader] ModStrings: scanning GetString prologue at %p", pGetStringFunc);
// Log first 32 bytes for diagnostics
char hexBuf[200];
for (int i = 0; i < 32 && i < 200/3; i++)
sprintf(hexBuf + i * 3, "%02X ", code[i]);
LogUtil::Log("[LegacyForge] ModStrings: bytes: %s", hexBuf);
LogUtil::Log("[WeaveLoader] ModStrings: bytes: %s", hexBuf);
// Search for RIP-relative memory accesses in first 80 bytes.
// GetString is: return app.m_stringTable->getString(iID);
@@ -86,7 +86,7 @@ namespace ModStrings
// For a static member or global struct, the compiler often uses a direct
// RIP-relative MOV to load the m_stringTable pointer field.
s_pStringTableField = reinterpret_cast<void**>(effectiveAddr);
LogUtil::Log("[LegacyForge] ModStrings: MOV [RIP+disp] -> field at %p", s_pStringTableField);
LogUtil::Log("[WeaveLoader] ModStrings: MOV [RIP+disp] -> field at %p", s_pStringTableField);
break;
}
else // LEA
@@ -104,14 +104,14 @@ namespace ModStrings
{
int8_t off = static_cast<int8_t>(code[j + 3]);
s_pStringTableField = reinterpret_cast<void**>(appAddr + off);
LogUtil::Log("[LegacyForge] ModStrings: LEA+MOV [reg+%d] -> field at %p", (int)off, s_pStringTableField);
LogUtil::Log("[WeaveLoader] ModStrings: LEA+MOV [reg+%d] -> field at %p", (int)off, s_pStringTableField);
break;
}
else if (mod2 == 2)
{
int32_t off = *reinterpret_cast<const int32_t*>(code + j + 3);
s_pStringTableField = reinterpret_cast<void**>(appAddr + off);
LogUtil::Log("[LegacyForge] ModStrings: LEA+MOV [reg+%d] -> field at %p", off, s_pStringTableField);
LogUtil::Log("[WeaveLoader] ModStrings: LEA+MOV [reg+%d] -> field at %p", off, s_pStringTableField);
break;
}
}
@@ -119,7 +119,7 @@ namespace ModStrings
}
if (!s_pStringTableField)
LogUtil::Log("[LegacyForge] ModStrings: WARNING - could not locate string table reference");
LogUtil::Log("[WeaveLoader] ModStrings: WARNING - could not locate string table reference");
}
// Heuristic: find the vector<wstring> inside a StringTable object.
@@ -154,7 +154,7 @@ namespace ModStrings
if (first->size() > 0 && first->size() < 10000)
{
s_vecOffset = off;
LogUtil::Log("[LegacyForge] ModStrings: found m_stringsVec at StringTable+0x%X (%zu entries)",
LogUtil::Log("[WeaveLoader] ModStrings: found m_stringsVec at StringTable+0x%X (%zu entries)",
off, count);
return reinterpret_cast<std::vector<std::wstring>*>(base + off);
}
@@ -166,30 +166,30 @@ namespace ModStrings
{
if (!s_pStringTableField)
{
LogUtil::Log("[LegacyForge] ModStrings: no string table ref - cannot inject");
LogUtil::Log("[WeaveLoader] ModStrings: no string table ref - cannot inject");
return;
}
void* stringTable = *s_pStringTableField;
if (!stringTable)
{
LogUtil::Log("[LegacyForge] ModStrings: m_stringTable pointer is NULL");
LogUtil::Log("[WeaveLoader] ModStrings: m_stringTable pointer is NULL");
return;
}
LogUtil::Log("[LegacyForge] ModStrings: StringTable object at %p", stringTable);
LogUtil::Log("[WeaveLoader] ModStrings: StringTable object at %p", stringTable);
std::vector<std::wstring>* vec = FindStringsVec(stringTable);
if (!vec)
{
LogUtil::Log("[LegacyForge] ModStrings: FAILED to locate m_stringsVec in StringTable");
LogUtil::Log("[WeaveLoader] ModStrings: FAILED to locate m_stringsVec in StringTable");
return;
}
std::lock_guard<std::mutex> lock(s_mutex);
if (s_strings.empty())
{
LogUtil::Log("[LegacyForge] ModStrings: no mod strings to inject");
LogUtil::Log("[WeaveLoader] ModStrings: no mod strings to inject");
return;
}
@@ -202,7 +202,7 @@ namespace ModStrings
if (static_cast<size_t>(maxId) >= oldSize)
{
vec->resize(maxId + 1);
LogUtil::Log("[LegacyForge] ModStrings: resized m_stringsVec %zu -> %zu", oldSize, vec->size());
LogUtil::Log("[WeaveLoader] ModStrings: resized m_stringsVec %zu -> %zu", oldSize, vec->size());
}
int count = 0;
@@ -212,6 +212,6 @@ namespace ModStrings
count++;
}
LogUtil::Log("[LegacyForge] ModStrings: injected %d mod strings into game string table", count);
LogUtil::Log("[WeaveLoader] ModStrings: injected %d mod strings into game string table", count);
}
}

View File

@@ -37,11 +37,11 @@ int native_register_block(
int id = IdRegistry::Instance().Register(IdRegistry::Type::Block, namespacedId);
if (id < 0)
{
LogUtil::Log("[LegacyForge] Failed to allocate block ID for '%s'", namespacedId);
LogUtil::Log("[WeaveLoader] Failed to allocate block ID for '%s'", namespacedId);
return -1;
}
LogUtil::Log("[LegacyForge] Registered block '%s' -> ID %d (hardness=%.1f, resistance=%.1f)",
LogUtil::Log("[WeaveLoader] Registered block '%s' -> ID %d (hardness=%.1f, resistance=%.1f)",
namespacedId, id, hardness, resistance);
std::wstring wIcon = Utf8ToWide(iconName);
@@ -57,7 +57,7 @@ int native_register_block(
if (!GameObjectFactory::CreateTile(id, materialId, hardness, resistance,
soundType, wIcon.empty() ? nullptr : wIcon.c_str(), descId))
{
LogUtil::Log("[LegacyForge] Warning: failed to create game Tile for block '%s' id=%d", namespacedId, id);
LogUtil::Log("[WeaveLoader] Warning: failed to create game Tile for block '%s' id=%d", namespacedId, id);
}
return id;
@@ -75,11 +75,11 @@ int native_register_item(
int id = IdRegistry::Instance().Register(IdRegistry::Type::Item, namespacedId);
if (id < 0)
{
LogUtil::Log("[LegacyForge] Failed to allocate item ID for '%s'", namespacedId);
LogUtil::Log("[WeaveLoader] Failed to allocate item ID for '%s'", namespacedId);
return -1;
}
LogUtil::Log("[LegacyForge] Registered item '%s' -> ID %d (stack=%d, durability=%d)",
LogUtil::Log("[WeaveLoader] Registered item '%s' -> ID %d (stack=%d, durability=%d)",
namespacedId, id, maxStackSize, maxDamage);
std::wstring wIcon = Utf8ToWide(iconName);
@@ -94,7 +94,7 @@ int native_register_item(
if (!GameObjectFactory::CreateItem(id, maxStackSize, wIcon.empty() ? nullptr : wIcon.c_str(), descId))
{
LogUtil::Log("[LegacyForge] Warning: failed to create game Item for '%s' id=%d", namespacedId, id);
LogUtil::Log("[WeaveLoader] Warning: failed to create game Item for '%s' id=%d", namespacedId, id);
}
return id;
@@ -123,11 +123,11 @@ int native_register_entity(
int id = IdRegistry::Instance().Register(IdRegistry::Type::Entity, namespacedId);
if (id < 0)
{
LogUtil::Log("[LegacyForge] Failed to allocate entity ID for '%s'", namespacedId);
LogUtil::Log("[WeaveLoader] Failed to allocate entity ID for '%s'", namespacedId);
return -1;
}
LogUtil::Log("[LegacyForge] Registered entity '%s' -> ID %d (%.1fx%.1f)",
LogUtil::Log("[WeaveLoader] Registered entity '%s' -> ID %d (%.1fx%.1f)",
namespacedId, id, width, height);
return id;
@@ -139,7 +139,7 @@ void native_add_shaped_recipe(
const char* pattern,
const char* ingredientIds)
{
LogUtil::Log("[LegacyForge] Added shaped recipe: %dx %s", resultCount, resultId);
LogUtil::Log("[WeaveLoader] Added shaped recipe: %dx %s", resultCount, resultId);
}
void native_add_furnace_recipe(
@@ -147,7 +147,7 @@ void native_add_furnace_recipe(
const char* outputId,
float xp)
{
LogUtil::Log("[LegacyForge] Added furnace recipe: %s -> %s (%.1f xp)", inputId, outputId, xp);
LogUtil::Log("[WeaveLoader] Added furnace recipe: %s -> %s (%.1f xp)", inputId, outputId, xp);
}
void native_log(const char* message, int level)
@@ -176,7 +176,7 @@ int native_get_entity_id(const char* namespacedId)
void native_subscribe_event(const char* eventName, void* managedFnPtr)
{
LogUtil::Log("[LegacyForge] Event subscription: %s", eventName ? eventName : "(null)");
LogUtil::Log("[WeaveLoader] Event subscription: %s", eventName ? eventName : "(null)");
}
void native_add_to_creative(int numericId, int count, int auxValue, int groupIndex)

View File

@@ -104,17 +104,17 @@ bool Open(const char* pdbPath)
{
if (s_open) Close();
LogUtil::Log("[LegacyForge] PdbParser: opening %s", pdbPath);
LogUtil::Log("[WeaveLoader] PdbParser: opening %s", pdbPath);
if (!OpenMappedFile(pdbPath, s_mapped))
{
LogUtil::Log("[LegacyForge] PdbParser: failed to memory-map PDB file");
LogUtil::Log("[WeaveLoader] PdbParser: failed to memory-map PDB file");
return false;
}
if (PDB::ValidateFile(s_mapped.baseAddress, s_mapped.fileSize) != PDB::ErrorCode::Success)
{
LogUtil::Log("[LegacyForge] PdbParser: PDB validation failed");
LogUtil::Log("[WeaveLoader] PdbParser: PDB validation failed");
CloseMappedFile(s_mapped);
return false;
}
@@ -123,7 +123,7 @@ bool Open(const char* pdbPath)
if (PDB::HasValidDBIStream(*s_rawFile) != PDB::ErrorCode::Success)
{
LogUtil::Log("[LegacyForge] PdbParser: invalid DBI stream");
LogUtil::Log("[WeaveLoader] PdbParser: invalid DBI stream");
Close();
return false;
}
@@ -131,7 +131,7 @@ bool Open(const char* pdbPath)
const PDB::InfoStream infoStream(*s_rawFile);
if (infoStream.UsesDebugFastLink())
{
LogUtil::Log("[LegacyForge] PdbParser: PDB uses unsupported /DEBUG:FASTLINK");
LogUtil::Log("[WeaveLoader] PdbParser: PDB uses unsupported /DEBUG:FASTLINK");
Close();
return false;
}
@@ -140,25 +140,25 @@ bool Open(const char* pdbPath)
if (s_dbiStream->HasValidImageSectionStream(*s_rawFile) != PDB::ErrorCode::Success)
{
LogUtil::Log("[LegacyForge] PdbParser: invalid image section stream");
LogUtil::Log("[WeaveLoader] PdbParser: invalid image section stream");
Close();
return false;
}
if (s_dbiStream->HasValidPublicSymbolStream(*s_rawFile) != PDB::ErrorCode::Success)
{
LogUtil::Log("[LegacyForge] PdbParser: invalid public symbol stream");
LogUtil::Log("[WeaveLoader] PdbParser: invalid public symbol stream");
Close();
return false;
}
if (s_dbiStream->HasValidGlobalSymbolStream(*s_rawFile) != PDB::ErrorCode::Success)
{
LogUtil::Log("[LegacyForge] PdbParser: invalid global symbol stream");
LogUtil::Log("[WeaveLoader] PdbParser: invalid global symbol stream");
Close();
return false;
}
if (s_dbiStream->HasValidSymbolRecordStream(*s_rawFile) != PDB::ErrorCode::Success)
{
LogUtil::Log("[LegacyForge] PdbParser: invalid symbol record stream");
LogUtil::Log("[WeaveLoader] PdbParser: invalid symbol record stream");
Close();
return false;
}
@@ -170,7 +170,7 @@ bool Open(const char* pdbPath)
s_moduleStream = new PDB::ModuleInfoStream(s_dbiStream->CreateModuleInfoStream(*s_rawFile));
s_open = true;
LogUtil::Log("[LegacyForge] PdbParser: PDB opened successfully");
LogUtil::Log("[WeaveLoader] PdbParser: PDB opened successfully");
return true;
}
@@ -286,7 +286,7 @@ void DumpMatching(const char* substring)
{
if (!s_open) return;
LogUtil::Log("[LegacyForge] PdbParser: dumping symbols containing '%s'...", substring);
LogUtil::Log("[WeaveLoader] PdbParser: dumping symbols containing '%s'...", substring);
int count = 0;
// Public symbols
@@ -369,7 +369,7 @@ void DumpMatching(const char* substring)
}
}
LogUtil::Log("[LegacyForge] PdbParser: found %d matching symbols", count);
LogUtil::Log("[WeaveLoader] PdbParser: found %d matching symbols", count);
}
void BuildAddressIndex()
@@ -454,7 +454,7 @@ void BuildAddressIndex()
[](const SymEntry& a, const SymEntry& b) { return a.rva == b.rva; });
s_addrIndex.erase(last, s_addrIndex.end());
LogUtil::Log("[LegacyForge] PdbParser: built address index with %zu symbols", s_addrIndex.size());
LogUtil::Log("[WeaveLoader] PdbParser: built address index with %zu symbols", s_addrIndex.size());
}
bool FindNameByRVA(uint32_t rva, char* outName, size_t nameSize, uint32_t* outOffset)

View File

@@ -24,7 +24,7 @@ bool SymbolResolver::Initialize()
m_moduleBase = reinterpret_cast<uintptr_t>(GetModuleHandleA(nullptr));
if (!m_moduleBase)
{
LogUtil::Log("[LegacyForge] Failed to get module base address");
LogUtil::Log("[WeaveLoader] Failed to get module base address");
return false;
}
@@ -38,12 +38,12 @@ bool SymbolResolver::Initialize()
else
pdbPath += ".pdb";
LogUtil::Log("[LegacyForge] PDB path: %s", pdbPath.c_str());
LogUtil::Log("[LegacyForge] Module base: %p", reinterpret_cast<void*>(m_moduleBase));
LogUtil::Log("[WeaveLoader] PDB path: %s", pdbPath.c_str());
LogUtil::Log("[WeaveLoader] Module base: %p", reinterpret_cast<void*>(m_moduleBase));
if (!PdbParser::Open(pdbPath.c_str()))
{
LogUtil::Log("[LegacyForge] ERROR: Failed to open PDB file");
LogUtil::Log("[WeaveLoader] ERROR: Failed to open PDB file");
return false;
}
@@ -58,7 +58,7 @@ void* SymbolResolver::Resolve(const char* decoratedName)
uint32_t rva = PdbParser::FindSymbolRVA(decoratedName);
if (rva == 0)
{
LogUtil::Log("[LegacyForge] Symbol not found in PDB: '%s'", decoratedName);
LogUtil::Log("[WeaveLoader] Symbol not found in PDB: '%s'", decoratedName);
return nullptr;
}
@@ -67,7 +67,7 @@ void* SymbolResolver::Resolve(const char* decoratedName)
bool SymbolResolver::ResolveGameFunctions()
{
LogUtil::Log("[LegacyForge] Resolving game functions via raw PDB parser...");
LogUtil::Log("[WeaveLoader] Resolving game functions via raw PDB parser...");
pRunStaticCtors = Resolve(SYM_RUN_STATIC_CTORS);
pMinecraftTick = Resolve(SYM_MINECRAFT_TICK);
@@ -96,9 +96,9 @@ bool SymbolResolver::ResolveGameFunctions()
auto logSym = [](const char* name, void* ptr) {
if (ptr)
LogUtil::Log("[LegacyForge] %-25s @ %p", name, ptr);
LogUtil::Log("[WeaveLoader] %-25s @ %p", name, ptr);
else
LogUtil::Log("[LegacyForge] MISSING: %s", name);
LogUtil::Log("[WeaveLoader] MISSING: %s", name);
};
logSym("RunStaticCtors", pRunStaticCtors);
@@ -117,9 +117,9 @@ bool SymbolResolver::ResolveGameFunctions()
bool ok = pRunStaticCtors && pMinecraftTick && pMinecraftInit;
if (ok)
LogUtil::Log("[LegacyForge] All critical symbols resolved (via raw PDB parser)");
LogUtil::Log("[WeaveLoader] All critical symbols resolved (via raw PDB parser)");
else
LogUtil::Log("[LegacyForge] CRITICAL symbols missing - hooks will not be installed");
LogUtil::Log("[WeaveLoader] CRITICAL symbols missing - hooks will not be installed");
return ok;
}

View File

@@ -24,41 +24,41 @@ static std::string GetDllDirectory(HMODULE hModule)
DWORD WINAPI InitThread(LPVOID lpParam)
{
LogUtil::Log("[LegacyForge] InitThread started (module=%p)", g_hModule);
LogUtil::Log("[WeaveLoader] InitThread started (module=%p)", g_hModule);
std::string baseDir = GetDllDirectory(g_hModule);
LogUtil::Log("[LegacyForge] Runtime DLL directory: %s", baseDir.c_str());
LogUtil::Log("[WeaveLoader] Runtime DLL directory: %s", baseDir.c_str());
char cwd[MAX_PATH] = {0};
GetCurrentDirectoryA(MAX_PATH, cwd);
LogUtil::Log("[LegacyForge] Game working directory: %s", cwd);
LogUtil::Log("[WeaveLoader] Game working directory: %s", cwd);
char exePath[MAX_PATH] = {0};
GetModuleFileNameA(nullptr, exePath, MAX_PATH);
LogUtil::Log("[LegacyForge] Host executable: %s", exePath);
LogUtil::Log("[WeaveLoader] Host executable: %s", exePath);
SymbolResolver symbols;
if (!symbols.Initialize())
{
LogUtil::Log("[LegacyForge] ERROR: Failed to initialize symbol resolver. Is the PDB present?");
LogUtil::Log("[WeaveLoader] ERROR: Failed to initialize symbol resolver. Is the PDB present?");
return 1;
}
LogUtil::Log("[LegacyForge] Symbol resolver initialized");
LogUtil::Log("[WeaveLoader] Symbol resolver initialized");
if (!symbols.ResolveGameFunctions())
{
LogUtil::Log("[LegacyForge] ERROR: Failed to resolve critical game functions.");
LogUtil::Log("[WeaveLoader] ERROR: Failed to resolve critical game functions.");
return 1;
}
LogUtil::Log("[LegacyForge] Game functions resolved from PDB");
LogUtil::Log("[WeaveLoader] Game functions resolved from PDB");
if (!HookManager::Install(symbols))
{
LogUtil::Log("[LegacyForge] ERROR: Failed to install hooks");
LogUtil::Log("[WeaveLoader] ERROR: Failed to install hooks");
symbols.Cleanup();
return 1;
}
LogUtil::Log("[LegacyForge] Hooks installed");
LogUtil::Log("[WeaveLoader] Hooks installed");
// Build the RVA->name index before releasing the PDB.
// This index survives PdbParser::Close() and is used by the crash handler.
@@ -69,18 +69,18 @@ DWORD WINAPI InitThread(LPVOID lpParam)
if (!DotNetHost::Initialize())
{
LogUtil::Log("[LegacyForge] ERROR: Failed to initialize .NET host");
LogUtil::Log("[WeaveLoader] ERROR: Failed to initialize .NET host");
return 1;
}
LogUtil::Log("[LegacyForge] .NET runtime initialized");
LogUtil::Log("[WeaveLoader] .NET runtime initialized");
std::string modsPath = baseDir + "mods";
LogUtil::Log("[LegacyForge] Mods directory: %s", modsPath.c_str());
LogUtil::Log("[WeaveLoader] Mods directory: %s", modsPath.c_str());
DotNetHost::CallManagedInit();
int modCount = DotNetHost::CallDiscoverMods(modsPath.c_str());
MainMenuOverlay::SetModCount(modCount);
LogUtil::Log("[LegacyForge] Mod discovery complete (%d mods). Ready.", modCount);
LogUtil::Log("[WeaveLoader] Mod discovery complete (%d mods). Ready.", modCount);
return 0;
}