Show / Hide Table of Contents

Pieces and PieceTables

Pieces in Valheim are anything that can be built in the game, through means such as the Hammer, Cultivator, Hoe or your own custom tool items. This includes things such as plant sapplings, the workbench, and walls. In order for a prefab to be a piece, it must have the Piece component attached to the prefab.

Piece Tables in Valheim are connecting the buildable pieces to the tools used for building. They also define if a tool can remove pieces again. In order for a prefab to be a piece table, it must have the PieceTable component attached to the prefab.

Since Valheim 1.0 the build menu doesn't group pieces by piece table categories anymore. Instead every piece carries a set of usage tags (Piece.UsageTagFlags) and the menu shows one tag button per tag in use. Jötunn keeps the piece categories working on top of that: a piece with a custom category gets its own tag button, named after the category. Piece tables themselves don't own categories any longer, the corresponding PieceTableConfig and CustomPieceTable members are deprecated.

Custom pieces and piece tables are handled by the PieceManager singleton.

This example requires assets to be loaded. The code snippets are taken from our example mod.

Note

You must only use names of existing prefabs. This can be prefabs you created, that have already been registered by another mod, or that already exist in the game.

Creating custom pieces

Custom pieces using PieceConfigs

Now we will load a new piece from an asset bundle. In order to better facilitate creation of pieces we have introduced the abstractions of PieceConfig's and RequirementConfig. These allow us to quickly and easily define common properties for pieces, such as the table they belong too, any restrictions or resources required.

private void Awake()
{
    AssetBundle pieceBundle = AssetUtils.LoadAssetBundleFromResources("pieces");

    PieceConfig cylinder = new PieceConfig();
    cylinder.Name = "$cylinder_display_name";
    cylinder.Description = "$cylinder_description";
    cylinder.PieceTable = PieceTables.Hammer;
    cylinder.CraftingStation = CraftingStations.Workbench;
    cylinder.Category = PieceCategories.Misc;
    cylinder.AddRequirement("Wood", 2);

    PieceManager.Instance.AddPiece(new CustomPiece(pieceBundle, "Cylinder", fixReference: false, cylinder));
}

To clone an existing pieces, they first have to be loaded by the game and are not available in Awake. Jötunn provides the PrefabManager.OnVanillaPrefabsAvailable event where vanilla prefabs are loaded. This event is called every time before a new is copied. This means we have to unregister after adding our custom pieces, because Jötunn already cached the custom piece.

private void Awake()
{
    PrefabManager.OnVanillaPrefabsAvailable += CreateDeerRugPiece;
}

private void CreateDeerRugPiece()
{
    PieceConfig rug = new PieceConfig();
    rug.Name = "$our_rug_deer_display_name";
    rug.PieceTable = PieceTableNames.Hammer;
    rug.Category = PieceCategoryNames.Misc;
    rug.AddRequirement("Wood", 2);

    PieceManager.Instance.AddPiece(new CustomPiece("our_rug_deer", "rug_deer", rug));

    // You want that to run only once, Jotunn has the piece cached for the game session
    PrefabManager.OnVanillaPrefabsAvailable -= CreateDeerRugPiece;
}

And here we have our final results:
Blue Print Rune Piece Table

As you can see in the screenshot the name and description are not yet localized. To read more about localization/translation head over to the localization tutorial pages.

Note

A PieceConfig has an empty array of requirements by default and doesn't change original requirements of that piece unless requirements were explicitely added to the PieceConfig object. So in case you really want to remove all requirements from a specific piece (for example a cloned vanilla piece), you have to do it manually: CustomPiece.Piece.m_resources = Array.Empty<Piece.Requirement>();

Hammer tags

The build menu groups pieces by their usage tags. Set them explicitly with PieceConfig.Usage, see PieceUsages for the valid names.

PieceConfig chest = new PieceConfig();
chest.PieceTable = PieceTables.Hammer;
chest.Usage = new[] { PieceUsages.Storage, PieceUsages.Furniture };

If Usage is left empty, Jötunn guesses tags from the piece's category, its components and its name, so your pieces show up somewhere sensible without any extra work. To opt out of that guessing for a custom piece table, set PieceTableConfig.GuessUsage to false. Pieces on that table then keep exactly the usage tags defined on their prefabs.

PieceTableConfig runeTable = new PieceTableConfig();
runeTable.GuessUsage = false;

Adding pieces to custom categories

With PieceConfig's it is possible to add your pieces to a vanilla or to an own category. Pieces of a custom category are shown under an own tag button in the build menu, named after the category. For this example we create "empty" pieces (GameObjects with just a cube model and a Piece component) and add them to a new category "Lulzies" on the Hammer.

Note

The vanilla category All doesn't show a piece under every tag anymore, it only appears under the All tag of the build menu. Use PieceConfig.Usage to control where a piece shows up.

// Implementation of custom pieces from an "empty" prefab with new piece categories
private void AddPieceCategories()
{
    // load a test texture from out mod folder
    var testTexture = AssetUtils.LoadTexture("TestMod/Assets/test_tex.jpg");

    GameObject cube = PrefabManager.Instance.CreateEmptyPrefab("piece_lul");
    // Add our test texture to the Unity MeshRenderer
    cube.GetComponent<MeshRenderer>().material.mainTexture = testTexture;

    PieceConfig lulConfig = new PieceConfig();
    lulConfig.Name = "$piece_lul";
    lulConfig.Description = "$piece_lul_description";
    lulConfig.PieceTable = PieceTableNames.Hammer;
    lulConfig.Icon = RenderManager.Instance.Render(cube, RenderManager.IsometricRotation); // render a new icon at runtime
    lulConfig.ExtendStation = CraftingStations.Workbench; // Makes this piece a station extension
    lulConfig.Category = "Lulzies";  // Adds a custom category for the Hammer
    PieceManager.Instance.AddPiece(new CustomPiece(cube, false, lulConfig));
}

The result is a new tag in the build menu of the Hammer, listing all pieces of that category.

One of the pieces placed in the world:
Piece Stub Placed

Custom piece table

After loading our custom item, we will load a piece table GameObject from our example asset bundle, create a CustomPieceTable from it and add it to the PieceManager.

private void CreateRunePieceTable()
{
    GameObject tablePrefab = blueprintRuneBundle.LoadAsset<GameObject>("_BlueprintTestTable");
    CustomPieceTable CPT = new CustomPieceTable(tablePrefab);
    PieceManager.Instance.AddPieceTable(CPT);
}

Custom categories on a custom piece table

Custom categories also work on custom piece tables. For that you will need to use PieceTableConfig's when creating a CustomPieceTable. This example is not used in our example mod but in our TestMod for Jötunn. Keep that in mind as you will not find the code in the example mod. We are still using the piece table of the example Blueprint Rune but this time add the custom pieces to own categories.

Note

The table itself doesn't declare its categories, they are created by the pieces using them. PieceTableConfig.UseCategories, UseCustomCategories, CustomCategories and CustomPieceTable.Categories are deprecated since Valheim 1.0 and have no effect on the build menu anymore.

private void AddItemsWithConfigs()
{
    // Add a custom piece table, the categories are created by the pieces below
    PieceTableConfig runeTable = new PieceTableConfig();
    runeTable.CanRemovePieces = false;
    PieceManager.Instance.AddPieceTable(new CustomPieceTable(BlueprintRuneBundle, "_BlueprintTestTable", runeTable));

    // Create and add a custom item
    ItemConfig runeConfig = new ItemConfig();
    runeConfig.Amount = 1;
    runeConfig.AddRequirement("Stone", 1);
    // Prefab did not use mocked refs so no need to fix them
    var runeItem = new CustomItem(BlueprintRuneBundle, "BlueprintTestRune", fixReference: false, runeConfig);
    ItemManager.Instance.AddItem(runeItem);

    // Create and add custom pieces
    PieceConfig makeConfig = new PieceConfig();
    makeConfig.PieceTable = "_BlueprintTestTable";
    makeConfig.Category = "Make";
    var makePiece = new CustomPiece(BlueprintRuneBundle, "make_testblueprint", fixReference: false, makeConfig);
    PieceManager.Instance.AddPiece(makePiece);

    var placeConfig = new PieceConfig();
    placeConfig.PieceTable = "_BlueprintTestTable";
    placeConfig.Category = "Place";
    placeConfig.AllowedInDungeons = true;
    placeConfig.AddRequirement("Wood", 2);
    var placePiece = new CustomPiece(BlueprintRuneBundle, "piece_testblueprint", fixReference: false, placeConfig);
    PieceManager.Instance.AddPiece(placePiece);
}

The result is a tool with two tags in the build menu, one per custom category.

Translating your custom categories

You can provide localized versions of your custom categories. Please see our localization tutorial on how to do this.

  • Edit this page
☀
☾
In this article
Back to top
Generated by DocFX
☀
☾