rework(docs): better, more readable docs

This commit is contained in:
Jacobwasbeast
2026-03-10 22:37:07 -05:00
parent f4ae519d9f
commit 6fabb8fd39
7 changed files with 477 additions and 372 deletions

398
README.md
View File

@@ -1,400 +1,54 @@
# Weave Loader
A runtime mod loader for Minecraft Legacy Edition (Xbox 360 / PS3 / Windows 64-bit port). Weave Loader injects into the game process, hooks engine functions via PDB symbol resolution, and hosts the .NET runtime so mods can be written in C#. **Zero game source modifications required.**
Weave Loader is a mod loader for Minecraft Legacy Edition (Xbox 360 / PS3 / Windows 64-bit). It launches the game and loads mods from a folder. It does not modify game files.
## Features
## What it does
- **DLL injection** -- Launcher starts the game suspended, injects the runtime DLL, then resumes
- **PDB symbol resolution** -- Uses raw PDB parsing (no DIA dependency) to locate game functions by their mangled names at runtime
- **Function hooking** -- MinHook detours on game lifecycle functions (init, tick, static constructors, rendering)
- **Full .NET hosting** -- .NET 8 CoreCLR is loaded inside the game process via hostfxr; mods are standard C# class libraries
- **Block and item registration** -- Create real game objects (Tile, TileItem, Item) by calling the game's own constructors through resolved PDB symbols
- **Dynamic texture atlas merging** -- Mod textures are merged into copies of the game's atlases at runtime using empty cells; vanilla game files are never touched
- **Creative inventory injection** -- Mod items appear in the correct creative tabs with proper pagination
- **Localized display names** -- Mod strings are injected directly into the game's `StringTable` vector, bypassing inlined `GetString` calls
- **Crash reporting** -- Vectored exception handler produces detailed crash logs with register dumps, symbolicated stack traces, and loaded module lists
- **Main menu branding** -- Renders loader version and mod count on the main menu via the game's own font renderer
- **Furnace recipes** -- Register smelting recipes with input, output, and XP values
- **Event system** -- Subscribe to block break, block place, chat, entity spawn, and player join events
- Launches the game and loads mods
- Lets mods add blocks, items, recipes, and events
- Merges mod textures and models at runtime
- Shows loader info in the main menu
- Writes logs and crash reports
## Architecture
## Quick start
```
┌──────────────────────────────────────────────────────────────┐
│ WeaveLoader.Launcher │
│ Starts game, injects runtime DLL │
└────────────────────────────┬─────────────────────────────────┘
│ CreateRemoteThread
┌────────────────────────────▼─────────────────────────────────┐
│ WeaveLoaderRuntime.dll │
│ C++ runtime injected into game process │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────────────┐ │
│ │ PDB Parser │ │ Hook Mgr │ │ .NET Host (hostfxr) │ │
│ │ (raw_pdb) │ │ (MinHook) │ │ │ │
│ └──────┬──────┘ └──────┬───────┘ └───────────┬───────────┘ │
│ │ │ │ │
│ ┌──────▼──────┐ ┌──────▼───────┐ ┌───────────▼───────────┐ │
│ │ Symbol │ │ Game Hooks │ │ WeaveLoader.Core.dll │ │
│ │ Resolver │ │ (lifecycle, │ │ (mod discovery, │ │
│ │ │ │ textures, │ │ lifecycle mgmt) │ │
│ │ │ │ UI, strings)│ │ │ │
│ └─────────────┘ └─────────────┘ └───────────┬───────────┘ │
│ │ │
│ ┌────────────────────────────────────────────▼───────────┐ │
│ │ Native Exports (C ABI) │ │
│ │ register_block, register_item, add_furnace_recipe, ... │ │
│ └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
│ P/Invoke
┌────────────────────────────▼─────────────────────────────────┐
│ WeaveLoader.API │
│ Public C# API that mod authors reference │
│ │
│ Registry.Block · Registry.Item · Registry.Recipe │
│ Registry.Entity · Registry.Assets · GameEvents │
│ Logger · CreativeTab · Identifier · [Mod] attribute │
└──────────────────────────────────────────────────────────────┘
│ implements IMod
┌────────────────────────────▼─────────────────────────────────┐
│ Mod DLLs │
│ ExampleMod, user mods, etc. │
└──────────────────────────────────────────────────────────────┘
```
1. Install Visual Studio 2022 (C++ + .NET 8), CMake, and the .NET 8 SDK
2. Build: `dotnet build WeaveLoader.sln -c Debug`
3. Run: `build/WeaveLoader.exe` and select `Minecraft.Client.exe`
4. Drop mod DLLs into `build/mods/`
## Project Structure
## Writing a mod (short)
```
ModLoader/
├── WeaveLoader.Launcher/ # C# launcher executable
├── WeaveLoaderRuntime/ # C++ DLL injected into the game
│ └── src/
│ ├── dllmain.cpp # Entry point, init thread
│ ├── PdbParser.cpp # Raw PDB symbol parsing (no DIA)
│ ├── SymbolResolver.cpp # Resolves game functions by mangled name
│ ├── HookManager.cpp # MinHook-based function detouring
│ ├── GameHooks.cpp # Hook implementations (lifecycle, UI)
│ ├── GameObjectFactory.cpp # Creates Tile/Item objects via resolved ctors
│ ├── CreativeInventory.cpp # Injects mod items into creative tabs
│ ├── ModAtlas.cpp # Texture atlas merging (terrain.png, items.png)
│ ├── ModStrings.cpp # String table injection for item names
│ ├── CrashHandler.cpp # Vectored exception handler + crash logs
│ ├── MainMenuOverlay.cpp # Renders branding text on main menu
│ ├── DotNetHost.cpp # Hosts .NET CoreCLR via hostfxr
│ ├── NativeExports.cpp # C exports called by C# via P/Invoke
│ ├── IdRegistry.cpp # Namespaced ID <-> numeric ID mapping
│ └── LogUtil.cpp # Timestamped logging to files
├── WeaveLoader.Core/ # C# mod discovery and lifecycle
│ ├── ModDiscovery.cs # Scans mods/ for IMod implementations
│ ├── ModManager.cs # Calls lifecycle hooks with error isolation
│ └── WeaveLoaderCore.cs # Entry points called from C++ runtime
├── WeaveLoader.API/ # C# public API for mod authors
│ ├── IMod.cs # Mod interface with lifecycle hooks
│ ├── ModAttribute.cs # [Mod("id", Name, Version, Author)]
│ ├── Registry.cs # Static facade for all registries
│ ├── Block/ # BlockRegistry, BlockProperties, MaterialType
│ ├── Item/ # ItemRegistry, ItemProperties
│ ├── Recipe/ # RecipeRegistry (shaped, furnace)
│ ├── Entity/ # EntityRegistry, EntityDefinition
│ ├── Assets/ # AssetRegistry (string table access)
│ ├── Events/ # GameEvents (block break/place, chat, etc.)
│ ├── Logger.cs # Debug/Info/Warning/Error logging
│ ├── CreativeTab.cs # Creative inventory tab enum
│ └── Identifier.cs # Namespaced ID parsing ("namespace:path")
├── ExampleMod/ # Sample mod demonstrating the API
│ ├── ExampleMod.cs
│ └── assets/
│ ├── blocks/ruby_ore.png
│ └── items/ruby.png
├── build/ # Shared build output
│ ├── mods/ # Mod DLLs and assets go here
│ └── logs/ # weaveloader.log, game_debug.log, crash.log
├── WeaveLoader.sln
├── README.md
└── CONTRIBUTING.md
```
## Building
### Prerequisites
- Visual Studio 2022+ with **C++ Desktop Development** and **.NET 8** workloads
- CMake 3.24+
- .NET 8.0 SDK
### Build Steps
Build the C++ runtime DLL:
```bash
cd WeaveLoaderRuntime
cmake -B build -A x64
cmake --build build --config Release
```
Build all C# projects (launcher, core, API, example mod):
```bash
dotnet build WeaveLoader.sln -c Debug
```
All outputs land in `build/`.
## Usage
1. Build Weave Loader (see above)
2. Run `WeaveLoader.exe` -- it prompts for the game executable path on first launch (saved to `weaveloader.json`)
3. The launcher starts the game suspended, injects `WeaveLoaderRuntime.dll`, and resumes
4. Mods are loaded from `build/mods/` automatically
### Log Files
All logs are written to `build/logs/`:
| File | Contents |
|------|----------|
| `weaveloader.log` | Loader initialization, symbol resolution, hook installation, mod lifecycle |
| `game_debug.log` | Game's own `OutputDebugString` output (captured via hook) |
| `crash.log` | Detailed crash reports with symbolicated stack traces |
## Writing a Mod
### 1. Create a .NET 8 class library
```bash
dotnet new classlib -n MyMod --framework net8.0
```
### 2. Reference the API
Add a project reference to `WeaveLoader.API`:
```xml
<ItemGroup>
<ProjectReference Include="..\WeaveLoader.API\WeaveLoader.API.csproj" />
</ItemGroup>
```
Set the output to the mods folder:
```xml
<PropertyGroup>
<OutputPath>..\build\mods\$(AssemblyName)</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
```
### 3. Implement IMod
Create a .NET 8 class library, reference `WeaveLoader.API`, and implement `IMod`:
```csharp
using WeaveLoader.API;
using WeaveLoader.API.Block;
using WeaveLoader.API.Item;
using WeaveLoader.API.Recipe;
using WeaveLoader.API.Events;
[Mod("mymod", Name = "My Mod", Version = "1.0.0", Author = "You")]
public class MyMod : IMod
{
public void OnInitialize()
{
// Register a block
var oreBlock = Registry.Block.Register("mymod:example_ore",
new BlockProperties()
.Material(MaterialType.Stone)
.Hardness(3.0f)
.Resistance(15.0f)
.Sound(SoundType.Stone)
.Icon("mymod:block/example_ore")
.InCreativeTab(CreativeTab.BuildingBlocks)
.Name(Text.Translatable("block.mymod.example_ore")));
// Register an item
var gem = Registry.Item.Register("mymod:example_gem",
new ItemProperties()
.MaxStackSize(64)
.Icon("mymod:item/example_gem")
.InCreativeTab(CreativeTab.Materials)
.Name(Text.Translatable("item.mymod.example_gem")));
// Add a smelting recipe
Registry.Recipe.AddFurnace("mymod:example_ore", "mymod:example_gem", 1.0f);
// Subscribe to events
GameEvents.OnBlockBreak += (sender, args) =>
{
if (args.BlockId == oreBlock.NumericId)
Logger.Info("Player broke example ore!");
};
Logger.Info("My Mod loaded!");
}
}
```
### 4. Add textures
## Logs
Place 16x16 PNG textures in your mod's assets folder:
- `build/logs/weaveloader.log`
- `build/logs/game_debug.log`
- `build/logs/crash.log`
```
MyMod/
├── assets/
│ └── mymod/
│ └── textures/
│ ├── block/
│ │ └── example_ore.png # Block texture
│ └── item/
│ └── example_gem.png # Item texture
├── MyMod.cs
└── MyMod.csproj
```
## Docs
The icon name in `BlockProperties.Icon()` / `ItemProperties.Icon()` uses Java-style names like:
```csharp
.Icon("mymod:block/example_ore")
.Icon("mymod:item/example_gem")
```
### 4b. Add models (block/item/entity)
Place Java-style JSON model files under an `assets/<namespace>/models/` tree inside your mod folder:
```
MyMod/
├── assets/
│ └── mymod/
│ └── models/
│ ├── block/
│ │ └── example_ore.json
│ ├── item/
│ │ └── example_gem.json
│ └── entity/
│ └── example_entity.json # reserved for future entity model support
├── MyMod.cs
└── MyMod.csproj
```
The `namespace` folder should match your mod's ID (lowercase).
### 5. Build and run
```bash
dotnet build MyMod.csproj
# Output goes to build/mods/MyMod/
# Run WeaveLoader.exe to launch with mods
```
## Mod Lifecycle
Mods go through these phases in order:
| Phase | Method | When | Use for |
|-------|--------|------|---------|
| PreInit | `OnPreInit()` | Before vanilla static constructors | Early configuration |
| Init | `OnInitialize()` | After vanilla registries are set up | Registering blocks, items, recipes, events |
| PostInit | `OnPostInitialize()` | After `Minecraft::init` completes | Cross-mod interactions, late setup |
| Tick | `OnTick()` | Every game tick (~20 Hz) | Per-frame logic |
| Shutdown | `OnShutdown()` | When the game exits | Cleanup, saving state |
Each mod's lifecycle methods are wrapped in try/catch, so one mod crashing won't take down others.
## API Reference
### Registry.Block
```csharp
RegisteredBlock Register(string id, BlockProperties properties)
```
Creates a real `Tile` game object with the specified material, hardness, resistance, and sound type. Automatically creates a corresponding `TileItem` so the block appears in inventory.
### Registry.Item
```csharp
RegisteredItem Register(string id, ItemProperties properties)
```
Creates a real `Item` game object. The constructor parameter is derived from the numeric ID to match the game's internal convention (`Item::Item(numericId - 256)`).
### Registry.Recipe
```csharp
void AddFurnace(string inputId, string outputId, float xp)
```
Registers a furnace smelting recipe.
### GameEvents
```csharp
event EventHandler<BlockBreakEventArgs> OnBlockBreak;
event EventHandler<BlockPlaceEventArgs> OnBlockPlace;
event EventHandler<ChatEventArgs> OnChat;
event EventHandler<EntitySpawnEventArgs> OnEntitySpawn;
event EventHandler<PlayerJoinEventArgs> OnPlayerJoin;
```
### Logger
```csharp
Logger.Debug(string message)
Logger.Info(string message)
Logger.Warning(string message)
Logger.Error(string message)
```
All log output goes to `logs/weaveloader.log` with timestamps and log level prefixes.
### Identifier
Namespaced string IDs follow the `"namespace:path"` convention (e.g., `"mymod:ruby_ore"`). If no namespace is provided, `"minecraft"` is assumed.
### Localization
Use `Text.Translatable("item.examplemod.ruby")` for localized names or `Text.Literal("Ruby")` for fixed text.
Language files live at `assets/<namespace>/lang/<locale>.lang` using `key=value` lines.
By default, WeaveLoader follows the game's current language selection; disable with `Localization.UseGameLanguage = false`.
If the game reports "system default", the locale falls back to the system UI culture; override with `Localization.Locale = "en-GB"`.
## ID Ranges
| Type | Numeric Range | Notes |
|------|--------------|-------|
| Blocks (Tiles) | 174 -- 255 | 82 slots; maps to TileItem in `Item::items[]` |
| Items | 3000 -- 31999 | Constructor param = `numericId - 256` |
| Entities | 1000 -- 9999 | Reserved for mod entities |
## How It Works Internally
### Symbol Resolution
The runtime opens the game's PDB file and parses it using [raw_pdb](https://github.com/MolecularMatters/raw_pdb) (no dependency on Microsoft's DIA SDK). It searches public, global, and module symbol streams for decorated C++ names like `??0Tile@@IEAA@HPEAVMaterial@@_N@Z` (Tile's protected constructor). The resolved RVAs are added to the module base address to get callable function pointers.
### Texture Atlas Merging
1. Mod textures are discovered in `mods/*/assets/<namespace>/textures/block/` and `mods/*/assets/<namespace>/textures/item/`
2. The vanilla `terrain.png` (16x32 grid) and `items.png` (16x16 grid) are loaded via stb_image
3. Empty cells are identified by checking for fully transparent pixels
4. Mod textures are placed into empty cells
5. The merged atlas is written to `mods/ModLoader/generated/` -- **vanilla game files are never modified**
6. A `CreateFileW` hook temporarily redirects the game's file opens to the merged atlases during init, then is removed once textures are loaded into GPU memory
7. `SimpleIcon` objects are created for each mod texture with correct UV coordinates
### Model Asset Overlay
When the game requests `assets/<namespace>/models/...` via `InputStream::getResourceAsStream`,
WeaveLoader will redirect to a matching file inside `mods/*/assets/<namespace>/models/`.
Block and item models are supported today; `models/entity/` is wired up for future use.
### String Table Injection
The game's `CMinecraftApp::GetString(int)` is a thin wrapper around `StringTable::getString(int)`, which does a vector index lookup. Since MSVC's link-time optimization inlines `GetString` at call sites like `Item::getHoverName`, a MinHook detour alone isn't sufficient. The runtime parses the x64 machine code of `GetString` to locate the RIP-relative reference to `app.m_stringTable`, then directly resizes the string table's internal vector and writes mod strings at the allocated indices.
### Crash Handler
A vectored exception handler catches access violations and other fatal exceptions. It uses the PDB address index (built during initialization) to resolve crash addresses to symbol names, producing crash reports with full register dumps, symbolicated stack traces, and loaded module lists. The handler also intercepts `int 3` breakpoints in game code (used by `__debugbreak()` for assertions) and skips them so execution continues.
- Building: `docs/BUILDING.md`
- Modding guide: `docs/MODDING.md`
- API reference: `docs/API_REFERENCE.md`
- Mixins: `docs/MIXINS.md`
- Project structure: `docs/PROJECT_STRUCTURE.md`
- Internals: `docs/INTERNALS.md`
## License
[MIT](LICENSE)
MIT

48
docs/API_REFERENCE.md Normal file
View File

@@ -0,0 +1,48 @@
# API Reference (Short)
## Registry.Block
```csharp
RegisteredBlock Register(string id, BlockProperties properties)
```
Creates a block and its inventory item.
## Registry.Item
```csharp
RegisteredItem Register(string id, ItemProperties properties)
```
Creates a new item.
## Registry.Recipe
```csharp
void AddFurnace(string inputId, string outputId, float xp)
```
Adds a furnace recipe.
## GameEvents
```csharp
event EventHandler<BlockBreakEventArgs> OnBlockBreak;
event EventHandler<BlockPlaceEventArgs> OnBlockPlace;
event EventHandler<ChatEventArgs> OnChat;
event EventHandler<EntitySpawnEventArgs> OnEntitySpawn;
event EventHandler<PlayerJoinEventArgs> OnPlayerJoin;
```
## Logger
```csharp
Logger.Debug(string message)
Logger.Info(string message)
Logger.Warning(string message)
Logger.Error(string message)
```
## Identifier
Namespaced IDs use `"namespace:path"` (for example, `"mymod:ruby_ore"`). If no namespace is provided, `"minecraft"` is assumed.

28
docs/BUILDING.md Normal file
View File

@@ -0,0 +1,28 @@
# Building
## Prerequisites
- Visual Studio 2022+ with C++ Desktop Development and .NET 8 workloads
- CMake 3.24+
- .NET 8 SDK
## Build steps
Build everything from the repo root:
```bash
dotnet build WeaveLoader.sln -c Debug
```
Outputs go to `build/`.
## Notes
- The launcher builds the native runtime automatically.
- If you only need the runtime DLL, you can build it directly:
```bash
cd WeaveLoaderRuntime
cmake -B build -A x64
cmake --build build --config Release
```

37
docs/INTERNALS.md Normal file
View File

@@ -0,0 +1,37 @@
# Internals
This file covers how Weave Loader works under the hood.
## Symbol resolution
The runtime reads the game's PDB file and resolves function addresses by mangled C++ names. Resolved RVAs are added to the module base to build callable function pointers.
We use [raw_pdb](https://github.com/MolecularMatters/raw_pdb) to parse PDBs without the DIA SDK.
## Texture atlas merging
1. Mod textures are found under `mods/*/assets/<namespace>/textures/`.
2. The vanilla `terrain.png` and `items.png` are loaded.
3. Empty cells are detected and mod textures are placed into them.
4. The merged atlas is written to `mods/ModLoader/generated/`.
5. File open hooks redirect the game to the merged atlases during init.
## Model asset overlay
When the game requests `assets/<namespace>/models/...`, WeaveLoader redirects to the mod's matching file under `mods/*/assets/<namespace>/models/`.
## String table injection
The runtime locates the game's string table and appends mod strings directly. This avoids relying on inlined string lookup calls.
## Crash handler
A vectored exception handler writes crash reports with register dumps, stack traces, and loaded modules. It also skips `__debugbreak()` asserts so the game can continue running.
## ID ranges
| Type | Numeric Range | Notes |
|------|--------------|-------|
| Blocks (Tiles) | 174 -- 255 | 82 slots; maps to TileItem in `Item::items[]` |
| Items | 3000 -- 31999 | Constructor param = `numericId - 256` |
| Entities | 1000 -- 9999 | Reserved for mod entities |

195
docs/MIXINS.md Normal file
View File

@@ -0,0 +1,195 @@
# Mixins
This guide explains how to hook game functions using Weave Loader mixins.
## What is a mixin?
A mixin lets you attach your code to an existing game function. You can run code:
- At the start of a function (head)
- At the end of a function (tail)
## 1. Register a mixin class
Create a file named `weave.mixins.json` in your mod folder:
```json
{
"package": "ExampleMod.Mixins",
"mixins": [
"CreeperExplosionMixin"
]
}
```
Fields (currently supported):
- `package`: C# namespace that contains your mixin classes
- `mixins`: Class names under that namespace
- `client`, `server`: Optional lists (loaded the same way as `mixins`)
Fields (parsed but not enforced yet):
- `required`
- `injectors.defaultRequire`
Place the file next to your mod DLL in `build/mods/<YourMod>/`.
## 2. Create a mixin class
### Target class
```csharp
using WeaveLoader.API.Mixins;
[Mixin("Creeper")]
public class CreeperExplosionMixin
{
}
```
The string in `[Mixin("...")]` is the class name used in `mapping.json`.
### Inject at the start (head)
```csharp
using WeaveLoader.API.Mixins;
[Mixin("Creeper")]
public class CreeperExplosionMixin
{
[Inject("tick", At.Head)]
private static void OnTick(MixinContext ctx)
{
// Code runs before Creeper::tick
}
}
```
### Inject at the end (tail)
```csharp
using WeaveLoader.API.Mixins;
[Mixin("Creeper")]
public class CreeperExplosionMixin
{
[Inject("tick", At.Tail)]
private static void OnTick(MixinContext ctx)
{
// Code runs after Creeper::tick
}
}
```
## 3. Using arguments and return values
Mixin methods must be `static` and return `void`. They can take either:
- No parameters
- One parameter: `MixinContext`
`MixinContext` lets you read or change arguments and return values.
```csharp
using WeaveLoader.API.Mixins;
[Mixin("Item")]
public class ItemMixin
{
[Inject("use", At.Head)]
private static void OnUse(MixinContext ctx)
{
var arg0 = ctx.GetArg(0);
var arg1 = ctx.GetArg(1);
// use ctx.SetArg(index, value) to modify
}
[Inject("use", At.Tail)]
private static void AfterUse(MixinContext ctx)
{
var ret = ctx.GetReturn();
// use ctx.SetReturn(value) to modify
}
}
```
## 4. Accessing the instance (`this`)
For non-static methods, the instance pointer is always arg 0:
```csharp
var self = ctx.GetArg(0);
```
For static methods, `ctx.ThisPtr` will be `0`.
## 5. Canceling the original method
You can skip the original game method at head injection:
```csharp
using WeaveLoader.API.Mixins;
using WeaveLoader.API.Native;
[Mixin("SomeClass")]
public class ExampleCancel
{
[Inject("doThing", At.Head)]
private static void OnDoThing(MixinContext ctx)
{
ctx.SetReturn(new NativeRet { Type = NativeType.I32, Value = 0 });
ctx.Cancel();
}
}
```
Canceling is only effective at the head. Tail injections run after the original method.
## 6. Picking the right method name
`InjectAttribute` takes either:
- A method name (`"tick"`) which becomes `Class::tick`
- A full name (`"Creeper::tick"`) from `mapping.json`
If you have overloads, use the exact `fullName` from `mapping.json`.
## 7. Confirm it is hooked
When a mixin loads, you should see logs like:
```
Processing mixin: ExampleMod.Mixins.CreeperExplosionMixin -> Creeper
HookRegistry: hooked Creeper::tick
Mixin hook installed: Creeper::tick (Tail)
```
If you do not see these logs:
- Check `weave.mixins.json` is next to the mod DLL
- Check the namespace in `package`
- Check the class name and method name match the PDB mapping
- Check the mod loaded at all
## 8. Common issues
- **Wrong class or method name**: PDB names are case-sensitive.
- **Crashes when accessing args**: Make sure the method signature matches the game method exactly.
- **Mixins not running**: Verify you see the “hook installed” log.
## 9. Logging
Use `Logger.Debug` inside mixins while testing:
```csharp
Logger.Debug("Creeper mixin tick");
```
Remove or reduce logs for release builds to avoid overhead.
## 10. Limits and not supported yet
- Hooks support up to 6 arguments.
- Overwrite mixins are not supported yet.
- Invoker mixins are not supported yet.

129
docs/MODDING.md Normal file
View File

@@ -0,0 +1,129 @@
# Modding Guide
## Create a mod
Create a .NET 8 class library:
```bash
dotnet new classlib -n MyMod --framework net8.0
```
Reference the API:
```xml
<ItemGroup>
<ProjectReference Include="..\\WeaveLoader.API\\WeaveLoader.API.csproj" />
</ItemGroup>
```
Send the output to the mods folder:
```xml
<PropertyGroup>
<OutputPath>..\\build\\mods\\$(AssemblyName)</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
```
## Minimal mod
```csharp
using WeaveLoader.API;
using WeaveLoader.API.Block;
using WeaveLoader.API.Item;
using WeaveLoader.API.Recipe;
using WeaveLoader.API.Events;
[Mod("mymod", Name = "My Mod", Version = "1.0.0", Author = "You")]
public class MyMod : IMod
{
public void OnInitialize()
{
var oreBlock = Registry.Block.Register("mymod:example_ore",
new BlockProperties()
.Material(MaterialType.Stone)
.Hardness(3.0f)
.Resistance(15.0f)
.Sound(SoundType.Stone)
.Icon("mymod:block/example_ore")
.InCreativeTab(CreativeTab.BuildingBlocks)
.Name(Text.Translatable("block.mymod.example_ore")));
var gem = Registry.Item.Register("mymod:example_gem",
new ItemProperties()
.MaxStackSize(64)
.Icon("mymod:item/example_gem")
.InCreativeTab(CreativeTab.Materials)
.Name(Text.Translatable("item.mymod.example_gem")));
Registry.Recipe.AddFurnace("mymod:example_ore", "mymod:example_gem", 1.0f);
GameEvents.OnBlockBreak += (_, args) =>
{
if (args.BlockId == oreBlock.NumericId)
Logger.Info("Player broke example ore!");
};
}
}
```
## Assets
Textures go under `assets/<namespace>/textures/`:
```
MyMod/
├── assets/
│ └── mymod/
│ └── textures/
│ ├── block/
│ │ └── example_ore.png
│ └── item/
│ └── example_gem.png
├── MyMod.cs
└── MyMod.csproj
```
Models go under `assets/<namespace>/models/`:
```
MyMod/
├── assets/
│ └── mymod/
│ └── models/
│ ├── block/
│ │ └── example_ore.json
│ ├── item/
│ │ └── example_gem.json
│ └── entity/
│ └── example_entity.json
└── ...
```
## Build and run
```bash
dotnet build MyMod.csproj
```
Run `build/WeaveLoader.exe` to launch with your mod.
## Mod lifecycle
| Phase | Method | When | Use for |
|-------|--------|------|---------|
| PreInit | `OnPreInit()` | Before vanilla static constructors | Early configuration |
| Init | `OnInitialize()` | After vanilla registries are set up | Registering blocks, items, recipes, events |
| PostInit | `OnPostInitialize()` | After `Minecraft::init` completes | Cross-mod interactions, late setup |
| Tick | `OnTick()` | Every game tick | Per-frame logic |
| Shutdown | `OnShutdown()` | When the game exits | Cleanup, saving state |
Each phase is wrapped in try/catch so one mod failure does not crash others.
## Localization
Use `Text.Translatable("item.mymod.example_gem")` for localized names or
`Text.Literal("Example Gem")` for fixed text.
Language files live at `assets/<namespace>/lang/<locale>.lang` using `key=value` lines.
By default, WeaveLoader uses the game's selected language.

14
docs/PROJECT_STRUCTURE.md Normal file
View File

@@ -0,0 +1,14 @@
# Project Structure
```
ModLoader/
├── WeaveLoader.Launcher/ # C# launcher executable
├── WeaveLoaderRuntime/ # C++ DLL injected into the game
├── WeaveLoader.Core/ # C# mod discovery and lifecycle
├── WeaveLoader.API/ # C# public API for mod authors
├── ExampleMod/ # Sample mod
├── build/ # Shared build output
├── WeaveLoader.sln
├── README.md
└── CONTRIBUTING.md
```