Files
Documentation/content/world/blocks.en.md
2026-01-20 20:33:59 +01:00

9.5 KiB

title, type, weight
title type weight
Blocks docs 3

Block manipulation is a core part of world modification in Hytale plugins. The World class provides block access through the IChunkAccessorSync interface, while WorldChunk implements the full BlockAccessor interface for rotation-aware placement.

{{< callout type="warning" >}} Important: World does NOT implement BlockAccessor directly. For placeBlock() with rotation, you must get the chunk first using world.getChunk(). {{< /callout >}}

Getting Blocks

import com.hypixel.hytale.server.core.universe.Universe;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.math.vector.Vector3i;

World world = Universe.get().getWorld("default");

// Get block ID (int index) at position
int blockId = world.getBlock(x, y, z);
int blockId = world.getBlock(new Vector3i(x, y, z));

// Get BlockType at position
BlockType blockType = world.getBlockType(x, y, z);
BlockType blockType = world.getBlockType(new Vector3i(x, y, z));

// Check if block is empty
if (blockType == BlockType.EMPTY) {
    // Air or empty space
}

Setting Blocks

The setBlock method takes a String block type key, not a BlockType object or int ID:

import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;

World world = player.getWorld();

// Set block by block type key (string ID)
world.setBlock(x, y, z, "stone");
world.setBlock(x, y, z, "oak_planks", 0);  // with settings

// Using BlockType - get the ID string first
BlockType stone = BlockType.getAssetMap().getAsset("stone");
if (stone != null) {
    world.setBlock(x, y, z, stone.getId());  // Use getId() to get the string key
}

// Block ID index (for internal use)
int stoneIndex = BlockType.getAssetMap().getIndex("stone");
// Note: setBlock takes String, not int - use the key directly

Block Placement with Rotation

{{< callout type="info" >}} placeBlock() is on WorldChunk, not World! You must get the chunk first to place blocks with rotation. {{< /callout >}}

import com.hypixel.hytale.server.core.universe.world.chunk.WorldChunk;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.Rotation;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.RotationTuple;
import com.hypixel.hytale.math.util.ChunkUtil;

// Get the chunk containing this block position
WorldChunk chunk = world.getChunk(ChunkUtil.indexChunkFromBlock(x, z));

if (chunk != null) {
    // Place block with rotation
    // Rotation values: None, Ninety, OneEighty, TwoSeventy
    chunk.placeBlock(x, y, z, "oak_log",
        Rotation.Ninety,   // yaw (90 degrees)
        Rotation.None,     // pitch
        Rotation.None      // roll
    );

    // Place with rotation tuple and options
    chunk.placeBlock(x, y, z, "oak_log",
        RotationTuple.of(Rotation.Ninety, Rotation.None, Rotation.None),
        0,      // settings
        true    // validatePlacement
    );
}

Rotation Values

The Rotation enum has these values (NOT cardinal directions):

Rotation Degrees
Rotation.None
Rotation.Ninety 90°
Rotation.OneEighty 180°
Rotation.TwoSeventy 270°

Breaking Blocks

// Break block at position (requires settings parameter)
world.breakBlock(x, y, z, 0);  // 0 = default settings

BlockType Assets

BlockType assets define block properties:

import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.protocol.BlockMaterial;

// Get block type by ID
BlockType blockType = BlockType.getAssetMap().getAsset("stone");

if (blockType != null) {
    // Get block ID string
    String blockId = blockType.getId();

    // Get material
    BlockMaterial material = blockType.getMaterial();
}

// Get block ID index (for internal use)
int blockIndex = BlockType.getAssetMap().getIndex("stone");

// Get block from index
BlockType fromIndex = BlockType.getAssetMap().getAsset(blockIndex);

Block Events

BreakBlockEvent

Fired when a block is broken:

import com.hypixel.hytale.server.core.event.events.ecs.BreakBlockEvent;
import com.hypixel.hytale.math.vector.Vector3i;
import java.util.logging.Level;

getEventRegistry().register(BreakBlockEvent.class, event -> {
    // Get break info
    Vector3i position = event.getTargetBlock();
    BlockType blockType = event.getBlockType();

    getLogger().at(Level.INFO).log("Block broken at " + position);

    // Cancel if protected
    event.setCancelled(true);
});

PlaceBlockEvent

Fired when a block is placed:

import com.hypixel.hytale.server.core.event.events.ecs.PlaceBlockEvent;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.RotationTuple;

getEventRegistry().register(PlaceBlockEvent.class, event -> {
    // Get place info
    Vector3i position = event.getTargetBlock();
    RotationTuple rotation = event.getRotation();

    getLogger().at(Level.INFO).log("Block placed at " + position);

    // Cancel if not allowed
    event.setCancelled(true);
});

DamageBlockEvent

Fired when a block is damaged (before breaking):

import com.hypixel.hytale.server.core.event.events.ecs.DamageBlockEvent;

getEventRegistry().register(DamageBlockEvent.class, event -> {
    Vector3i position = event.getTargetBlock();
    BlockType blockType = event.getBlockType();

    // Cancel to prevent damage
    event.setCancelled(true);
});

Block Interaction State

Blocks can have interaction states (like open/closed doors):

BlockType currentBlock = world.getBlockType(x, y, z);

if (currentBlock != null) {
    // Set block to a different state
    world.setBlockInteractionState(
        new Vector3i(x, y, z),
        currentBlock,
        "open"  // state name
    );
}

Working with Blocks

Check Area for Block Type

public boolean containsBlockType(World world, Vector3i min, Vector3i max, String blockTypeKey) {
    // Note: Vector3i uses getX(), getY(), getZ() - NOT x(), y(), z()
    for (int x = min.getX(); x <= max.getX(); x++) {
        for (int y = min.getY(); y <= max.getY(); y++) {
            for (int z = min.getZ(); z <= max.getZ(); z++) {
                BlockType block = world.getBlockType(x, y, z);
                if (block != null && block.getId().equals(blockTypeKey)) {
                    return true;
                }
            }
        }
    }
    return false;
}

Fill Area

public void fillArea(World world, Vector3i min, Vector3i max, String blockTypeKey) {
    for (int x = min.getX(); x <= max.getX(); x++) {
        for (int y = min.getY(); y <= max.getY(); y++) {
            for (int z = min.getZ(); z <= max.getZ(); z++) {
                world.setBlock(x, y, z, blockTypeKey);
            }
        }
    }
}

Replace Blocks

public void replaceBlocks(World world, Vector3i min, Vector3i max,
                          String fromBlock, String toBlock) {
    for (int x = min.getX(); x <= max.getX(); x++) {
        for (int y = min.getY(); y <= max.getY(); y++) {
            for (int z = min.getZ(); z <= max.getZ(); z++) {
                BlockType current = world.getBlockType(x, y, z);
                if (current != null && current.getId().equals(fromBlock)) {
                    world.setBlock(x, y, z, toBlock);
                }
            }
        }
    }
}

Block Positions

import com.hypixel.hytale.math.vector.Vector3i;

// Vector3i for integer block positions
Vector3i blockPos = new Vector3i(100, 64, 200);

// Get individual coordinates - use getX(), getY(), getZ()
int x = blockPos.getX();
int y = blockPos.getY();
int z = blockPos.getZ();

// Adjacent positions
Vector3i above = new Vector3i(x, y + 1, z);
Vector3i below = new Vector3i(x, y - 1, z);
Vector3i north = new Vector3i(x, y, z - 1);
Vector3i south = new Vector3i(x, y, z + 1);
Vector3i east = new Vector3i(x + 1, y, z);
Vector3i west = new Vector3i(x - 1, y, z);

Best Practices

{{< callout type="info" >}} Block Manipulation Tips:

  • Block operations must run on the world's ticking thread
  • Use getBlockType() for checking block types, getBlock() for raw IDs
  • Check BlockType.EMPTY for air/empty blocks
  • Events extend CancellableEcsEvent - use setCancelled(true) to prevent
  • Consider chunk boundaries when processing large areas
  • For placeBlock() with rotation, get the chunk first {{< /callout >}}
// Safe block modification from async context
world.execute(() -> {
    world.setBlock(x, y, z, "stone");
});

API Reference

World (IChunkAccessorSync) Methods

Method Returns Description
getBlock(int, int, int) int Get block ID at position
getBlock(Vector3i) int Get block ID at position
getBlockType(int, int, int) BlockType? Get BlockType at position
getBlockType(Vector3i) BlockType? Get BlockType at position
setBlock(x, y, z, String) void Set block by type key
setBlock(x, y, z, String, int) void Set block with settings
breakBlock(x, y, z, int) boolean Break block with settings
setBlockInteractionState(...) void Set block state

WorldChunk (BlockAccessor) Methods

Method Returns Description
placeBlock(x, y, z, String, Rotation, Rotation, Rotation) boolean Place with rotation
placeBlock(x, y, z, String, RotationTuple, int, boolean) boolean Place with options
testPlaceBlock(...) boolean Test if placement valid