📄 Templates [MUST READ]

This page mainly explains how to add new templates to your server.

Introduction

The plugin boasts an exceptionally high degree of customization, but it's impossible to configure it without providing any settings. Even a very brief option requires a line in your YAML file. With numerous such options, a configuration file can become excessively long. Therefore, the plugin has introduced a template system, allowing you to define a base template and use parameters and overrides to fill in or overwrite certain parameters, significantly simplifying the process and reducing the time spent on repetitive configurations. Below, I will guide you through several examples to familiarize you with how the template system operates.

How to Create a Template?

Create a Basic Template

To configure a template, you need to use templates as the root key in your YAML file.

templates:
  namespace:template_id:
    option_1: true
    option_2: false
    option_3: 
      - hello
    option_4: 20.25

namespace:template_id serves as the unique identifier for your template. This name must be used whenever referencing or invoking this template elsewhere.

The configuration area under namespace:template_id is entirely customizable, as long as it adheres to YAML syntax. You have complete freedom to define it according to your needs.

Create a Template with Aruguments

templates:
  namespace:template_id:
    option_1: "{value_1}"
    option_2: "{value_2}"
    option_3:
      - "{value_3}"
    option_4: "{value_4}"

If you wish to create a custom parameter, simply enclose it with {}. For example, here {value_1} is used as a placeholder for a parameter.

How to Apply a Template?

Apply a Basic Template

Now, let's assume we are creating an item configuration test:item_1. Without using a template, its configuration might look like the following:

items:
  test:item_1:
    option_1: true
    option_2: false
    option_3: 
      - hello
    option_4: 20.25

However, when we utilize a template, the configuration would appear as follows:

items:
  test:item_1:
    template: namespace:template_id

These two configurations are entirely equivalent. You can think of a template as a pre-packed box. When you use this template in a specific section, the box is opened, and the parameters inside are unpacked and placed into the corresponding configuration area.

You cannot use both a template and normal configuration within the same section simultaneously! The correct approach is to use overrides to configure options within the same area.

❌ī¸
items:
  invalid:item:
    template: invalid:template
    option_1: a
    option_2: c

✅ī¸
items:
  invalid:item:
    template: invalid:template
    overrides:
      option_1: a
      option_2: c

Apply a Template with Arguments

The following example demonstrates how to assign values to custom placeholders registered within a template:

items:
  test:item_1:
    template: namespace:template_id
    arguments:
      value_1: true
      value_2: false
      value_3: hello
      value_4: 20.25

Here, we employ the simplest method of direct value assignment, which means the corresponding parameter will be directly inserted into the target option. Of course, besides direct value assignment, we also offer a variety of other practical parameter types, such as auto-incrementing IDs. You can explore all the available parameter types here đŸŸĸ Argument Types

Apply a Template with Overrides

However, there are times when a template's configuration may lack a specific option. If you need to add or override an option, you can use the overrides feature. Refer to the following configuration for guidance:

items:
  test:item_1:
    template: namespace:template_id
    overrides:
      option_1: false
      missing_option: 2025

In this case, the original template had the value of option_1 set to true. We have overridden it to false and additionally introduced a new parameter missing_option, assigning it the value 2025.

Using overrides does not have the restrictions of arguments regarding data type.

overrides:
  map:
    a: b
  list:
    - 1
    - 2

Apply Multiple Templates

If you are an ardent fan of Rust, you will undoubtedly appreciate this design pattern. The composition of an object is based on combination rather than inheritance. By combining multiple templates, we can amalgamate the characteristics of various elements.

templates:
  namespace:template_1:
    option_1: true
  namespace:template_2:
    option_2: false

items:
  test:item_1:
    template:
      - namespace:template_1
      - namespace:template_2

If you have multiple templates with overlapping parameters, they will be applied in sequential order, with later parameters overriding the earlier ones.

Config

templates:
  namespace:template_1:
    option_1: true
  namespace:template_2:
    option_1: false

items:
  test:item_1:
    template:
      - namespace:template_1
      - namespace:template_2

Result

items:
  test:item_1:
    option_1: false

Combine all the features!

Config

templates:
  namespace:template_1:
    option_1: true
    option_3: "{value}"
  namespace:template_2:
    option_2: false

items:
  test:item_1:
    template:
      - namespace:template_1
      - namespace:template_2
    arguments:
      value: 2025
    overrides:
      option_4:
        - hello

Result

items:
  test:item_1:
    option_1: true
    option_2: false
    option_3: 2025
    option_4:
      - hello

Examples

Ore

In this example, both arguments and overrides are utilized to populate the loot and settings sections with the template.

templates:
  loot_table:ore:
    pools:
      - rolls: 1
        entries:
          - type: alternatives
            children:
              - type: item
                item: "{ore_block}"
                conditions:
                  - type: enchantment
                    predicate: minecraft:silk_touch>=1
              - type: item
                item: "{ore_drop}"
                functions:
                  - type: apply_bonus
                    enchantment: minecraft:fortune
                    formula:
                      type: ore_drops
                  - type: explosion_decay
                  - type: drop_exp
                    count:
                      type: uniform
                      min: "{min_exp}"
                      max: "{max_exp}"
  block_settings:pickaxe_level_2:
    correct-tools:
      - minecraft:stone_pickaxe
      - minecraft:iron_pickaxe
      - minecraft:golden_pickaxe
      - minecraft:diamond_pickaxe
      - minecraft:netherite_pickaxe
      - default:topaz_pickaxe
  block_settings:ore:
    hardness: 4.5
    resistance: 3.0
    push-reaction: NORMAL
    is-redstone-conductor: true
    is-suffocating: true
    instrument: BASEDRUM
    can-occlude: true
    map-color: 11
    tags:
      - minecraft:mineable/pickaxe
    sounds:
      break: minecraft:block.stone.break
      step: minecraft:block.stone.step
      place: minecraft:block.stone.place
      hit: minecraft:block.stone.hit
      fall: minecraft:block.stone.fall
blocks:
  default:topaz_ore:
    loot:
      template: loot_table:ore
      arguments:
        ore_drop: default:topaz
        ore_block: default:topaz_ore
        min_exp: 3
        max_exp: 7
    settings:
      template:
        - block_settings:ore
        - block_settings:pickaxe_level_2
      overrides:
        item: default:topaz_ore

Bow

In this example, we use a template to create an auto-generated model configuration for a 2D bow.

templates:
  models:bow_2d:
    type: "minecraft:condition"
    property: "minecraft:using_item"
    on-false:
      type: "minecraft:model"
      path: "{bow_model}"
      generation:
        parent: "minecraft:item/bow"
        textures:
          "layer0": "{bow_texture}"
    on-true:
      type: "minecraft:range_dispatch"
      property: "minecraft:use_duration"
      scale: 0.05
      entries:
        - model:
            type: minecraft:model
            path: "{bow_pulling_1_model}"
            generation:
              parent: "minecraft:item/bow_pulling_1"
              textures:
                "layer0": "{bow_pulling_1_texture}"
          threshold: 0.65
        - model:
            type: minecraft:model
            path: "{bow_pulling_2_model}"
            generation:
              parent: "minecraft:item/bow_pulling_2"
              textures:
                "layer0": "{bow_pulling_2_texture}"
          threshold: 0.9
      fallback:
        type: minecraft:model
        path: "{bow_pulling_0_model}"
        generation:
          parent: "minecraft:item/bow_pulling_0"
          textures:
            "layer0": "{bow_pulling_0_texture}"
items:
  default:topaz_bow:
    material: bow
    custom-model-data: 1000
    data:
      display-name: "<!i><#FF8C00>Topaz Bow"
    model:
      template: models:bow_2d
      arguments:
        bow_model: minecraft:item/custom/topaz_bow
        bow_texture: minecraft:item/custom/topaz_bow
        bow_pulling_0_model: minecraft:item/custom/topaz_bow_pulling_0
        bow_pulling_0_texture: minecraft:item/custom/topaz_bow_pulling_0
        bow_pulling_1_model: minecraft:item/custom/topaz_bow_pulling_1
        bow_pulling_1_texture: minecraft:item/custom/topaz_bow_pulling_1
        bow_pulling_2_model: minecraft:item/custom/topaz_bow_pulling_2
        bow_pulling_2_texture: minecraft:item/custom/topaz_bow_pulling_2

Summary

Overall, the introduction of templates has significantly enhanced users' ability to customize configurations. If the plugin's original configuration format is akin to C, then using templates is more like programming in Python. Writing in C can be headache-inducing and complex, but using Python is quick and straightforward. The plugin will continue to integrate practical templates in future versions, and you are also welcome to contribute your templates by opening a PR on GitHub!

Last updated