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

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
```