--- title: Blocks type: docs weight: 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 ```java 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: ```java 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 >}} ```java 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` | 0° | | `Rotation.Ninety` | 90° | | `Rotation.OneEighty` | 180° | | `Rotation.TwoSeventy` | 270° | ## Breaking Blocks ```java // Break block at position (requires settings parameter) world.breakBlock(x, y, z, 0); // 0 = default settings ``` ## BlockType Assets BlockType assets define block properties: ```java 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: ```java 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: ```java 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): ```java 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): ```java 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 ```java 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 ```java 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 ```java 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 ```java 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 >}} ```java // 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 |