


Part of the BreakoutMods modding suite.
CIR, short for Custom Item Registry, is a Valheim modding API for developers who want to ship custom 3D item prefabs from AssetBundles without rewriting ObjectDB, ZNetScene, recipe, and multiplayer registration glue in every mod.
Repository: BreakoutMods/CIR-CustomItemRegistry
Community: BreakoutMods Discord
Support development: BreakoutMods Patreon
The library is built for BepInEx 5.x, Harmony, and Jotunn. It leans on Jotunn's PrefabManager and ItemManager for multiplayer-safe prefab and recipe registration, while exposing the original small API, the CIR 0.2 raw builder API, CIR 0.3 typed item templates, and CIR 0.4 typed recipe helpers.
Reference CustomItemRegistry.dll from your mod project and add BepInEx dependencies:
[BepInDependency(CustomItemRegistryPlugin.PluginGuid)]
[BepInDependency(Jotunn.Main.ModGuid)]
Valheim also has a game type named CraftingStation. If your project references Valheim assemblies, add an alias for CIR's enum:
using CIRCraftingStation = ValheimCustomItemRegistry.CraftingStation;
Register a templated item from Awake:
CustomItemRegistry.Item("BM_IronLongsword")
.FromEmbeddedResource("MyMod.Assets.items", typeof(MyPlugin).Assembly, "BM_IronLongsword")
.DisplayName("$item_bm_ironlongsword")
.Description("$item_bm_ironlongsword_desc")
.Icon("BM_IronLongswordIcon")
.AsSword(sword => sword
.Slash(48f, perLevel: 6f)
.Block(24f, force: 18f, parry: 2f)
.Durability(250f, perLevel: 50f)
.Attack(stamina: 14f, force: 35f)
.Movement(-0.05f))
.Recipe(recipe => recipe
.At(CIRCraftingStation.Forge)
.StationLevel(2)
.Requires(VanillaItem.FineWood, 4)
.Requires(VanillaItem.Iron, 10)
.Requires(VanillaItem.Iron, 0, 8))
.Register();
Typed helpers remove most recipe string memorization, but raw prefab strings remain supported:
using static ValheimCustomItemRegistry.ItemRefs;
CustomItemRegistry.Item("BM_MagicBlade")
.FromBundle(assetBundlePath, "BM_MagicBladePrefab")
.AsSword(sword => sword.Slash(40f).Spirit(10f))
.Recipe(recipe => recipe
.At(CIRCraftingStation.Forge)
.Requires(VanillaItem.Silver, 10)
.Requires(Modded("com.otherauthor.valheim.magicmod", "MagicCore"), 1))
.Register();
You can still use the raw 0.2 builder when you need direct shared-data control:
CustomItemRegistry.Item("BreakoutMaterial")
.FromBundle(assetBundlePath, "BreakoutMaterialPrefab")
.Icon("BreakoutMaterialIcon")
.Gear(gear => gear.Material().StackSize(50))
.ConfigureSharedData(shared => shared.m_value = 25)
.Register();
The original API remains supported:
CustomItemRegistry.RegisterItem(
"MyCrystalSword",
Path.Combine(Path.GetDirectoryName(Info.Location), "myitems"),
"MyCrystalSwordPrefab",
new CraftingRecipe(
new List<Ingredient>
{
new Ingredient("FineWood", 8),
new Ingredient("Crystal", 12),
new Ingredient("Silver", 4)
},
"forge",
1));
The AssetBundle prefab must include an ItemDrop component. If it does not already include a ZNetView, CIR adds one and marks it persistent for networked item drops.
CustomItemRegistry.Item(string itemName) fluent builder entrypoint.RegisterItem(string itemName, string assetBundlePath, string prefabName, CraftingRecipe recipe) legacy API.RegisterItem(CustomItemDefinition definition), TryRegisterItem(...), and RegisterItems(...).CustomItemBuilder, RecipeBuilder, GearBuilder, CustomItemDefinition, ItemRegistrationResult, and CustomItemRegistrationException.WeaponTemplateBuilder, ShieldTemplateBuilder, ArmorTemplateBuilder, BowTemplateBuilder, AmmoTemplateBuilder, ToolTemplateBuilder, FoodTemplateBuilder, and MaterialTemplateBuilder.VanillaItem, CraftingStation, ItemRef, ItemRefs, and ToPrefabName() extension methods.CraftingRecipe with ingredients, crafting station, repair station, station level, amount, enabled flag, require-only-one ingredient, and quality result multiplier.AssetBundle instances, or loaded from embedded resources with .FromEmbeddedResource(...).RecipeBuilder.At(CIRCraftingStation.Forge) and RepairAt(CIRCraftingStation.Workbench) map known stations to Jotunn prefab names.RecipeBuilder.Requires(VanillaItem.Iron, 10) maps common Valheim ingredients to prefab names.RecipeBuilder.Requires(ItemRef.Modded("com.author.mod", "MagicCore"), 1) soft-links third-party mod items without compile-time references.ItemRef.Prefab("SomePrefab") and raw .Requires("SomePrefab", 1) remain available for custom or newly added prefabs..AsSword(...), .AsAxe(...), .AsMace(...), .AsSpear(...), .AsKnife(...), and .AsAtgeir(...) for melee weapons..AsBow(...) and .AsArrow(...) for ranged weapons and ammo..AsShield(...), .AsArmorChest(...), .AsArmorLegs(...), .AsHelmet(...), and .AsCape(...) for defense items..AsTool(...), .AsFood(...), and .AsMaterial(...) for common non-weapon items.Sprite..ConfigureSharedData(...) escape hatch for advanced ItemDrop.ItemData.SharedData edits.BepInEx/plugins.PrefabManager for multiplayer-safe ZNetScene registration.ItemManager.ObjectDB.CopyOtherDB and ZNetScene.Awake to flush items into live databases when Valheim creates or copies them.ItemDrop, duplicate item names, invalid recipes, and missing craftable item icons with clearer log messages.The src/ExampleCustomItemPlugin project shows template, raw builder, definition, try-register, validation harness, and legacy API usage. Its sample AssetBundle and prefab names are placeholders, so replace them with real assets before shipping.
CIR-CustomItemRegistry/
CIR-CustomItemRegistry.sln
build.ps1
docs/
recipes.md
templates.md
roadmap/
developer-helper-api.md
src/
CustomItemRegistry/
API/ Public API contracts and registration facade
Builders/ Fluent item, recipe, and gear builders
Helpers/ Vanilla item, station, and modded item refs
Templates/ Typed Valheim item template builders
Patches/ Harmony timing patches
Plugin/ BepInEx plugin entrypoint
ExampleCustomItemPlugin/
Examples/ Developer-facing usage examples
Testing/ Lightweight compile/validation harnesses
The public namespace and assembly identity stay stable even though the source files are grouped by responsibility.
If you're using a mod manager, you can likely ignore this section.
CustomItemRegistry.dll into BepInEx/plugins/CustomItemRegistry.BepInEx/plugins.This repo expects to live under a Valheim install like:
Valheim dedicated server/
BepInEx/
valheim_server_Data/
Modding/
CIR-CustomItemRegistry/
Build with:
.\build.ps1 -Configuration Release
Debug builds copy the API DLL into BepInEx/plugins/CustomItemRegistry and the example DLL into BepInEx/plugins/ExampleCustomItemPlugin.
VanillaItem and CraftingStation for common ingredients and stations. Use raw strings for uncommon or newly added prefabs.ItemRef.Modded("other.mod.guid", "PrefabName") when depending on a third-party item. CIR logs that source mod GUID if the prefab is missing.piece_workbench, forge, and piece_cauldron. Passing null or an empty string makes the recipe craftable without a station.ItemDrop shared data, pass a direct Sprite, or call .Icon("SpriteAssetName") for craftable items..Requires("Bronze", 0, 4) when an ingredient should only be consumed by upgrades..FromEmbeddedResource("Namespace.BundleName", typeof(MyPlugin).Assembly, "PrefabName")..Gear(...) or .ConfigureSharedData(...) only for unusual behavior.Please open issues with the Valheim version, BepInEx version, Jotunn version, the item prefab name, and the relevant BepInEx log lines. Pull requests that keep the public API small and improve interop with Jotunn are welcome.
See CHANGELOG.md.