diff --git a/demo/src/main/java/net/minestom/demo/Main.java b/demo/src/main/java/net/minestom/demo/Main.java index dcc337b18..363990328 100644 --- a/demo/src/main/java/net/minestom/demo/Main.java +++ b/demo/src/main/java/net/minestom/demo/Main.java @@ -5,6 +5,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; +import net.minestom.demo.block.TestBlockHandler; import net.minestom.demo.commands.*; import net.minestom.server.MinecraftServer; import net.minestom.server.command.CommandManager; @@ -27,6 +28,7 @@ public class Main { MinecraftServer minecraftServer = MinecraftServer.init(); BlockManager blockManager = MinecraftServer.getBlockManager(); + blockManager.registerHandler(TestBlockHandler.INSTANCE.getNamespaceId(), () -> TestBlockHandler.INSTANCE); CommandManager commandManager = MinecraftServer.getCommandManager(); commandManager.register(new TestCommand()); diff --git a/demo/src/main/java/net/minestom/demo/block/TestBlockHandler.java b/demo/src/main/java/net/minestom/demo/block/TestBlockHandler.java new file mode 100644 index 000000000..1f7f6f3ee --- /dev/null +++ b/demo/src/main/java/net/minestom/demo/block/TestBlockHandler.java @@ -0,0 +1,24 @@ +package net.minestom.demo.block; + +import net.minestom.server.instance.block.BlockHandler; +import net.minestom.server.utils.NamespaceID; +import org.jetbrains.annotations.NotNull; + +public class TestBlockHandler implements BlockHandler { + public static final BlockHandler INSTANCE = new TestBlockHandler(); + + @Override + public @NotNull NamespaceID getNamespaceId() { + return NamespaceID.from("minestom", "test"); + } + + @Override + public void onPlace(@NotNull Placement placement) { + System.out.println(placement); + } + + @Override + public void onDestroy(@NotNull Destroy destroy) { + System.out.println(destroy); + } +} diff --git a/demo/src/main/java/net/minestom/demo/commands/SetBlockCommand.java b/demo/src/main/java/net/minestom/demo/commands/SetBlockCommand.java index 3f5ef2cab..58d738222 100644 --- a/demo/src/main/java/net/minestom/demo/commands/SetBlockCommand.java +++ b/demo/src/main/java/net/minestom/demo/commands/SetBlockCommand.java @@ -1,9 +1,11 @@ package net.minestom.demo.commands; +import net.minestom.demo.block.TestBlockHandler; import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.arguments.minecraft.ArgumentBlockState; import net.minestom.server.command.builder.arguments.relative.ArgumentRelativeBlockPosition; import net.minestom.server.entity.Player; +import net.minestom.server.instance.block.Block; import static net.minestom.server.command.builder.arguments.ArgumentType.BlockState; import static net.minestom.server.command.builder.arguments.ArgumentType.RelativeBlockPosition; @@ -17,7 +19,12 @@ public class SetBlockCommand extends Command { addSyntax((sender, context) -> { final Player player = (Player) sender; - player.getInstance().setBlock(context.get(position).from(player), context.get(block)); + + Block blockToPlace = context.get(block); + if (blockToPlace.stateId() == Block.GOLD_BLOCK.stateId()) + blockToPlace = blockToPlace.withHandler(TestBlockHandler.INSTANCE); + + player.getInstance().setBlock(context.get(position).from(player), blockToPlace); }, position, block); } } diff --git a/src/main/java/net/minestom/server/instance/Chunk.java b/src/main/java/net/minestom/server/instance/Chunk.java index 3c24e2db1..1653eafbb 100644 --- a/src/main/java/net/minestom/server/instance/Chunk.java +++ b/src/main/java/net/minestom/server/instance/Chunk.java @@ -7,6 +7,7 @@ import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Player; import net.minestom.server.entity.pathfinding.PFColumnarSpace; import net.minestom.server.instance.block.Block; +import net.minestom.server.instance.block.BlockHandler; import net.minestom.server.network.packet.server.play.ChunkDataPacket; import net.minestom.server.snapshot.Snapshotable; import net.minestom.server.tag.TagHandler; @@ -15,6 +16,7 @@ import net.minestom.server.utils.chunk.ChunkSupplier; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.world.biomes.Biome; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Set; @@ -85,7 +87,13 @@ public abstract class Chunk implements Block.Getter, Block.Setter, Biome.Getter, * @param block the block to place */ @Override - public abstract void setBlock(int x, int y, int z, @NotNull Block block); + public void setBlock(int x, int y, int z, @NotNull Block block) { + setBlock(x, y, z, block, null, null); + } + + protected abstract void setBlock(int x, int y, int z, @NotNull Block block, + @Nullable BlockHandler.Placement placement, + @Nullable BlockHandler.Destroy destroy); public abstract @NotNull List
getSections(); diff --git a/src/main/java/net/minestom/server/instance/DynamicChunk.java b/src/main/java/net/minestom/server/instance/DynamicChunk.java index 6d2ece6f6..2a6918421 100644 --- a/src/main/java/net/minestom/server/instance/DynamicChunk.java +++ b/src/main/java/net/minestom/server/instance/DynamicChunk.java @@ -4,6 +4,7 @@ import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minestom.server.MinecraftServer; import net.minestom.server.coordinate.Point; +import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Entity; import net.minestom.server.entity.Player; import net.minestom.server.entity.pathfinding.PFBlock; @@ -56,7 +57,9 @@ public class DynamicChunk extends Chunk { } @Override - public void setBlock(int x, int y, int z, @NotNull Block block) { + public void setBlock(int x, int y, int z, @NotNull Block block, + @Nullable BlockHandler.Placement placement, + @Nullable BlockHandler.Destroy destroy) { assertLock(); this.lastChange = System.currentTimeMillis(); this.chunkCache.invalidate(); @@ -68,16 +71,21 @@ public class DynamicChunk extends Chunk { columnarOcclusionFieldList.onBlockChanged(x, y, z, blockDescription, 0); } Section section = getSectionAt(y); - section.blockPalette() - .set(toSectionRelativeCoordinate(x), toSectionRelativeCoordinate(y), toSectionRelativeCoordinate(z), block.stateId()); + section.blockPalette().set( + toSectionRelativeCoordinate(x), + toSectionRelativeCoordinate(y), + toSectionRelativeCoordinate(z), + block.stateId() + ); final int index = ChunkUtils.getBlockIndex(x, y, z); // Handler final BlockHandler handler = block.handler(); + final Block lastCachedBlock; if (handler != null || block.hasNbt() || block.registry().isBlockEntity()) { - this.entries.put(index, block); + lastCachedBlock = this.entries.put(index, block); } else { - this.entries.remove(index); + lastCachedBlock = this.entries.remove(index); } // Block tick if (handler != null && handler.isTickable()) { @@ -85,6 +93,21 @@ public class DynamicChunk extends Chunk { } else { this.tickableMap.remove(index); } + + // Update block handlers + var blockPosition = new Vec(x, y, z); + if (lastCachedBlock != null && lastCachedBlock.handler() != null) { + // Previous destroy + lastCachedBlock.handler().onDestroy(Objects.requireNonNullElseGet(destroy, + () -> new BlockHandler.Destroy(lastCachedBlock, instance, blockPosition))); + } + if (handler != null) { + // New placement + final Block finalBlock = block; + handler.onPlace(Objects.requireNonNullElseGet(placement, + () -> new BlockHandler.Placement(finalBlock, instance, blockPosition))); + } + } @Override diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index 170f3e541..b1f3d7486 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -125,9 +125,6 @@ public class InstanceContainer extends Instance { } this.currentlyChangingBlocks.put(blockPosition, block); - final Block previousBlock = chunk.getBlock(blockPosition); - final BlockHandler previousHandler = previousBlock.handler(); - // Change id based on neighbors final BlockPlacementRule blockPlacementRule = MinecraftServer.getBlockManager().getBlockPlacementRule(block); if (blockPlacementRule != null) { @@ -135,7 +132,7 @@ public class InstanceContainer extends Instance { } // Set the block - chunk.setBlock(x, y, z, block); + chunk.setBlock(x, y, z, block, placement, destroy); // Refresh neighbors since a new block has been placed executeNeighboursBlockPlacementRule(blockPosition); @@ -149,19 +146,6 @@ public class InstanceContainer extends Instance { chunk.sendPacketToViewers(new BlockEntityDataPacket(blockPosition, registry.blockEntityId(), data)); } } - - if (previousHandler != null) { - // Previous destroy - previousHandler.onDestroy(Objects.requireNonNullElseGet(destroy, - () -> new BlockHandler.Destroy(previousBlock, this, blockPosition))); - } - final BlockHandler handler = block.handler(); - if (handler != null) { - // New placement - final Block finalBlock = block; - handler.onPlace(Objects.requireNonNullElseGet(placement, - () -> new BlockHandler.Placement(finalBlock, this, blockPosition))); - } } } diff --git a/src/main/java/net/minestom/server/instance/LightingChunk.java b/src/main/java/net/minestom/server/instance/LightingChunk.java index 55e43bd25..1528c265e 100644 --- a/src/main/java/net/minestom/server/instance/LightingChunk.java +++ b/src/main/java/net/minestom/server/instance/LightingChunk.java @@ -8,6 +8,7 @@ import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.BlockFace; +import net.minestom.server.instance.block.BlockHandler; import net.minestom.server.instance.light.Light; import net.minestom.server.network.packet.server.CachedPacket; import net.minestom.server.network.packet.server.play.data.LightData; @@ -17,6 +18,7 @@ import net.minestom.server.timer.TaskSchedule; import net.minestom.server.utils.NamespaceID; import net.minestom.server.utils.chunk.ChunkUtils; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.locks.ReentrantLock; @@ -101,8 +103,10 @@ public class LightingChunk extends DynamicChunk { } @Override - public void setBlock(int x, int y, int z, @NotNull Block block) { - super.setBlock(x, y, z, block); + public void setBlock(int x, int y, int z, @NotNull Block block, + @Nullable BlockHandler.Placement placement, + @Nullable BlockHandler.Destroy destroy) { + super.setBlock(x, y, z, block, placement, destroy); this.heightmap = null; // Invalidate neighbor chunks, since they can be updated by this block change