Creating Your First Mod
This example uses the same registration, version, lifecycle, and cleanup contracts exercised by FTK2.ModAPI.ExampleMod.
using System;
using BepInEx;
using FTK2.ModAPI;
using FTK2.ModAPI.Core;
using FTK2.ModAPI.Events;
[BepInPlugin("author.demo", "Demo Mod", "0.1.0")]
[BepInDependency(FTK2API.PluginId, FTK2API.VersionString)]
public sealed class DemoPlugin : BaseUnityPlugin
{
private IModContext? mod;
private IDisposable? readySubscription;
private void Awake()
{
var metadata = new ModMetadata(
"author.demo", "Demo Mod", "Your Name",
new ApiVersion(0, 1, 0), new ApiVersion(0, 5, 9));
if (!FTK2API.TryRegister(metadata, out mod, out var error) || mod == null)
{
Logger.LogError(error);
return;
}
readySubscription = mod.Events.Subscribe<GameDataReady>(OnGameDataReady);
mod.Log.Info("Startup", "Demo Mod registered.");
}
private void OnGameDataReady(GameDataReady ready)
{
mod!.Log.Info("Startup",
$"FTK2 {ready.GameVersion}; generation {ready.Generation}; {ready.ItemCount} items");
}
private void OnApplicationQuit()
{
readySubscription?.Dispose();
(mod as IModSession)?.Dispose();
}
}
BepInDependencyloads ModAPI first.- ModMetadata declares one stable owner and API requirement.
- FTK2API.TryRegister returns an isolated IModContext.
- GameDataReady tells you native templates are usable.
- Dispose the subscription and optional IModSession on the main thread during real shutdown.
Use lowercase dotted mod IDs such as author.demo. Owned content then uses IDs such as author.demo:ember_axe.
Important
Subscribe during Awake; events are not replayed. Keep runtime service calls and subscription disposal on Unity's main thread.
Next: create an item or follow the Flame Cleave tutorial.