Files
LegacyWeaveLoader/docs/MIXINS.md
2026-03-10 22:37:07 -05:00

196 lines
4.1 KiB
Markdown

# 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.