Skip to content

2. Defining Custom Blocks

zawarka03 edited this page Jul 28, 2026 · 1 revision

The foundation of any custom block in Monolith API is the BlockDefinition. This class encapsulates the core properties of a block, including its unique identifier, display name, underlying material, and its specific behaviors.

2.1. Creating a BlockDefinition

It is highly recommended to create a dedicated class for each custom block type, extending BlockDefinition. This approach promotes clean architecture, encapsulates block-specific logic, and simplifies maintenance, especially in large-scale projects.

Example: Industrial Generator (Java)

This example demonstrates a complex block definition in Java, incorporating custom data keys for energy storage and processing state.

package com.example.industrial.blocks;

import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.Material;
import io.github.zawarka03.monolithAPI.api.block.BlockDefinition;
import io.github.zawarka03.monolithAPI.api.storage.data.DataKey;
import io.github.zawarka03.monolithAPI.api.storage.data.types.IntDataType;
import io.github.zawarka03.monolithAPI.api.storage.data.types.StringDataType;
import io.github.zawarka03.monolithAPI.identifier.Identifier;

public class IndustrialGenerator extends BlockDefinition {

    // Define DataKeys for persistent state
    public final DataKey<Integer> STORED_ENERGY;
    public final DataKey<String> OWNER_UUID;

    public IndustrialGenerator() {
        super(
            new Identifier("industrial", "generator"),
            Component.text("Industrial Generator")
                     .color(NamedTextColor.GOLD)
                     .decorate(TextDecoration.BOLD),
            Material.BLAST_FURNACE
        );

        // Initialize DataKeys using the protected dataKey method
        this.STORED_ENERGY = dataKey("energy", IntDataType.INSTANCE);
        this.OWNER_UUID = dataKey("owner", StringDataType.INSTANCE);

        // Register the block's specific behavior listener
        behavior().register(new GeneratorBehavior(this));
    }
}

Example: Arcane Infuser (Kotlin)

This example illustrates a Kotlin implementation, leveraging Kotlin's concise syntax and property initialization.

package com.example.magic.blocks

import net.kyori.adventure.text.Component
import net.kyori.adventure.text.format.NamedTextColor
import org.bukkit.Material
import io.github.zawarka03.monolithAPI.api.block.BlockDefinition
import io.github.zawarka03.monolithAPI.api.storage.data.types.IntDataType
import io.github.zawarka03.monolithAPI.identifier.Identifier

class ArcaneInfuser : BlockDefinition(
    Identifier("magic", "arcane_infuser"),
    Component.text("Arcane Infuser").color(NamedTextColor.DARK_PURPLE),
    Material.ENCHANTING_TABLE
) {
    // Define DataKeys for persistent state
    val infusionLevel = dataKey("infusion_level", IntDataType)
    val chargeCount = dataKey("charge_count", IntDataType)

    init {
        // Register the block's specific behavior listener
        behavior.register(InfuserBehavior(this))
    }
}

2.2. Registering Block Definitions

Block definitions must be registered with the API during the MonolithRegisterEvent. This event is dispatched during the plugin's startup sequence, ensuring all blocks are known before the world repository is loaded.

Java Registration
import org.bukkit.plugin.java.JavaPlugin;
import io.github.zawarka03.monolithAPI.MonolithAPI;
import io.github.zawarka03.monolithAPI.api.event.MonolithEventHandler;
import io.github.zawarka03.monolithAPI.api.event.events.MonolithRegisterEvent;
import io.github.zawarka03.monolithAPI.api.event.listener.MonolithListener;
import com.example.industrial.blocks.IndustrialGenerator;

public class IndustrialPlugin extends JavaPlugin {

    @Override
    public void onEnable() {
        // Register a global listener to handle the registration event
        MonolithAPI.api().events().register(new BlockRegistrationListener());
    }
}

class BlockRegistrationListener implements MonolithListener {

    @MonolithEventHandler
    public void onRegister(MonolithRegisterEvent event) {
        // Register the custom block definition
        event.registry().register(new IndustrialGenerator());
        // Register other blocks...
    }
}
Kotlin Registration
import org.bukkit.plugin.java.JavaPlugin
import io.github.zawarka03.monolithAPI.MonolithAPI
import io.github.zawarka03.monolithAPI.api.event.events.MonolithRegisterEvent
import com.example.magic.blocks.ArcaneInfuser

class MagicPlugin : JavaPlugin() {

    override fun onEnable() {
        // Register a global listener using the reified lambda syntax
        MonolithAPI.api.events.register<MonolithRegisterEvent> { event ->
            // Register the custom block definition
            event.registry.register(ArcaneInfuser())
            // Register other blocks...
        }
    }
}

Clone this wiki locally