mirror of
https://github.com/Minestom/Minestom.git
synced 2024-11-20 01:25:27 +01:00
hollow-cube/prevent-block-updates
(cherry picked from commit 55a1349049
)
This commit is contained in:
parent
47a5f9dea4
commit
c879c1753d
@ -6,6 +6,7 @@ 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.block.placement.DripstonePlacementRule;
|
||||
import net.minestom.demo.commands.*;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.CommandManager;
|
||||
@ -28,6 +29,7 @@ public class Main {
|
||||
MinecraftServer minecraftServer = MinecraftServer.init();
|
||||
|
||||
BlockManager blockManager = MinecraftServer.getBlockManager();
|
||||
blockManager.registerBlockPlacementRule(new DripstonePlacementRule());
|
||||
blockManager.registerHandler(TestBlockHandler.INSTANCE.getNamespaceId(), () -> TestBlockHandler.INSTANCE);
|
||||
|
||||
CommandManager commandManager = MinecraftServer.getCommandManager();
|
||||
|
@ -133,6 +133,9 @@ public class PlayerInit {
|
||||
|
||||
event.getInstance().setBlock(event.getPosition(), block);
|
||||
|
||||
})
|
||||
.addListener(PlayerBlockPlaceEvent.class, event -> {
|
||||
event.setDoBlockUpdates(false);
|
||||
});
|
||||
|
||||
static {
|
||||
|
@ -0,0 +1,62 @@
|
||||
package net.minestom.demo.block.placement;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.rule.BlockPlacementRule;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class DripstonePlacementRule extends BlockPlacementRule {
|
||||
private static final String PROP_VERTICAL_DIRECTION = "vertical_direction"; // Tip, frustum, middle(0 or more), base
|
||||
private static final String PROP_THICKNESS = "thickness";
|
||||
|
||||
public DripstonePlacementRule() {
|
||||
super(Block.POINTED_DRIPSTONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Block blockPlace(@NotNull PlacementState placementState) {
|
||||
var blockFace = placementState.blockFace();
|
||||
var y = placementState.cursorPosition().y();
|
||||
return block.withProperty(PROP_VERTICAL_DIRECTION, switch (blockFace) {
|
||||
case TOP -> "up";
|
||||
case BOTTOM -> "down";
|
||||
default -> y < 0.5 ? "up" : "down";
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Block blockUpdate(@NotNull UpdateState updateState) {
|
||||
return updateState.currentBlock()
|
||||
.withProperty(PROP_THICKNESS, getThickness(updateState));
|
||||
}
|
||||
|
||||
private @NotNull String getThickness(@NotNull UpdateState updateState) {
|
||||
var direction = updateState.currentBlock().getProperty(PROP_VERTICAL_DIRECTION).equals("up");
|
||||
var abovePosition = updateState.blockPosition().add(0, direction ? 1 : -1, 0);
|
||||
var aboveBlock = updateState.instance().getBlock(abovePosition, Block.Getter.Condition.TYPE);
|
||||
|
||||
// If there is no dripstone above, it is always a tip
|
||||
if (aboveBlock.id() != Block.POINTED_DRIPSTONE.id())
|
||||
return "tip";
|
||||
// If there is an opposite facing dripstone above, it is always a merged tip
|
||||
if ((direction ? "down" : "up").equals(aboveBlock.getProperty(PROP_VERTICAL_DIRECTION)))
|
||||
return "tip_merge";
|
||||
|
||||
// If the dripstone above this is a tip, it is a frustum
|
||||
var aboveThickness = aboveBlock.getProperty(PROP_THICKNESS);
|
||||
if ("tip".equals(aboveThickness) || "tip_merge".equals(aboveThickness))
|
||||
return "frustum";
|
||||
|
||||
// At this point we know that there is a dripstone above, and that the dripstone is facing the same direction.
|
||||
var belowPosition = updateState.blockPosition().add(0, direction ? -1 : 1, 0);
|
||||
var belowBlock = updateState.instance().getBlock(belowPosition, Block.Getter.Condition.TYPE);
|
||||
|
||||
// If there is no dripstone below, it is always a base
|
||||
if (belowBlock.id() != Block.POINTED_DRIPSTONE.id())
|
||||
return "base";
|
||||
|
||||
// Otherwise it is a middle
|
||||
return "middle";
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C
|
||||
private final Player.Hand hand;
|
||||
|
||||
private boolean consumeBlock;
|
||||
private boolean doBlockUpdates;
|
||||
|
||||
private boolean cancelled;
|
||||
|
||||
@ -33,6 +34,7 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C
|
||||
this.blockPosition = blockPosition;
|
||||
this.hand = hand;
|
||||
this.consumeBlock = true;
|
||||
this.doBlockUpdates = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,6 +96,22 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C
|
||||
return consumeBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the place trigger updates (on self and neighbors)
|
||||
* @param doBlockUpdates true if this placement should do block updates
|
||||
*/
|
||||
public void setDoBlockUpdates(boolean doBlockUpdates) {
|
||||
this.doBlockUpdates = doBlockUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the place trigger updates (on self and neighbors)
|
||||
* @return true if this placement should do block updates
|
||||
*/
|
||||
public boolean shouldDoBlockUpdates() {
|
||||
return doBlockUpdates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
|
@ -153,8 +153,24 @@ public abstract class Instance implements Block.Getter, Block.Setter,
|
||||
this.scheduler.scheduleNextTick(() -> callback.accept(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, @NotNull Block block) {
|
||||
setBlock(x, y, z, block, true);
|
||||
}
|
||||
|
||||
public void setBlock(@NotNull Point blockPosition, @NotNull Block block, boolean doBlockUpdates) {
|
||||
setBlock(blockPosition.blockX(), blockPosition.blockY(), blockPosition.blockZ(), block, doBlockUpdates);
|
||||
}
|
||||
|
||||
public abstract void setBlock(int x, int y, int z, @NotNull Block block, boolean doBlockUpdates);
|
||||
|
||||
@ApiStatus.Internal
|
||||
public abstract boolean placeBlock(@NotNull BlockHandler.Placement placement);
|
||||
public boolean placeBlock(@NotNull BlockHandler.Placement placement) {
|
||||
return placeBlock(placement, true);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public abstract boolean placeBlock(@NotNull BlockHandler.Placement placement, boolean doBlockUpdates);
|
||||
|
||||
/**
|
||||
* Does call {@link net.minestom.server.event.player.PlayerBlockBreakEvent}
|
||||
@ -165,7 +181,21 @@ public abstract class Instance implements Block.Getter, Block.Setter,
|
||||
* @return true if the block has been broken, false if it has been cancelled
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public abstract boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition, @NotNull BlockFace blockFace);
|
||||
public boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition, @NotNull BlockFace blockFace) {
|
||||
return breakBlock(player, blockPosition, blockFace, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does call {@link net.minestom.server.event.player.PlayerBlockBreakEvent}
|
||||
* and send particle packets
|
||||
*
|
||||
* @param player the {@link Player} who break the block
|
||||
* @param blockPosition the position of the broken block
|
||||
* @param doBlockUpdates true to do block updates, false otherwise
|
||||
* @return true if the block has been broken, false if it has been cancelled
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public abstract boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition, @NotNull BlockFace blockFace, boolean doBlockUpdates);
|
||||
|
||||
/**
|
||||
* Forces the generation of a {@link Chunk}, even if no file and {@link ChunkGenerator} are defined.
|
||||
|
@ -100,14 +100,14 @@ public class InstanceContainer extends Instance {
|
||||
}
|
||||
|
||||
@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, boolean doBlockUpdates) {
|
||||
Chunk chunk = getChunkAt(x, z);
|
||||
if (chunk == null) {
|
||||
Check.stateCondition(!hasEnabledAutoChunkLoad(),
|
||||
"Tried to set a block to an unloaded chunk with auto chunk load disabled");
|
||||
chunk = loadChunk(getChunkCoordinate(x), getChunkCoordinate(z)).join();
|
||||
}
|
||||
if (isLoaded(chunk)) UNSAFE_setBlock(chunk, x, y, z, block, null, null);
|
||||
if (isLoaded(chunk)) UNSAFE_setBlock(chunk, x, y, z, block, null, null, doBlockUpdates);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -122,7 +122,8 @@ public class InstanceContainer extends Instance {
|
||||
* @param block the block to place
|
||||
*/
|
||||
private synchronized void UNSAFE_setBlock(@NotNull Chunk chunk, int x, int y, int z, @NotNull Block block,
|
||||
@Nullable BlockHandler.Placement placement, @Nullable BlockHandler.Destroy destroy) {
|
||||
@Nullable BlockHandler.Placement placement, @Nullable BlockHandler.Destroy destroy,
|
||||
boolean doBlockUpdates) {
|
||||
if (chunk.isReadOnly()) return;
|
||||
synchronized (chunk) {
|
||||
// Refresh the last block change time
|
||||
@ -137,7 +138,7 @@ public class InstanceContainer extends Instance {
|
||||
|
||||
// Change id based on neighbors
|
||||
final BlockPlacementRule blockPlacementRule = MinecraftServer.getBlockManager().getBlockPlacementRule(block);
|
||||
if (blockPlacementRule != null) {
|
||||
if (blockPlacementRule != null && doBlockUpdates) {
|
||||
block = blockPlacementRule.blockUpdate(new BlockPlacementRule.UpdateState(this, blockPosition, block));
|
||||
}
|
||||
|
||||
@ -145,7 +146,9 @@ public class InstanceContainer extends Instance {
|
||||
chunk.setBlock(x, y, z, block, placement, destroy);
|
||||
|
||||
// Refresh neighbors since a new block has been placed
|
||||
executeNeighboursBlockPlacementRule(blockPosition);
|
||||
if (doBlockUpdates) {
|
||||
executeNeighboursBlockPlacementRule(blockPosition);
|
||||
}
|
||||
|
||||
// Refresh player chunk block
|
||||
{
|
||||
@ -160,17 +163,17 @@ public class InstanceContainer extends Instance {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean placeBlock(@NotNull BlockHandler.Placement placement) {
|
||||
public boolean placeBlock(@NotNull BlockHandler.Placement placement, boolean doBlockUpdates) {
|
||||
final Point blockPosition = placement.getBlockPosition();
|
||||
final Chunk chunk = getChunkAt(blockPosition);
|
||||
if (!isLoaded(chunk)) return false;
|
||||
UNSAFE_setBlock(chunk, blockPosition.blockX(), blockPosition.blockY(), blockPosition.blockZ(),
|
||||
placement.getBlock(), placement, null);
|
||||
placement.getBlock(), placement, null, doBlockUpdates);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition, @NotNull BlockFace blockFace) {
|
||||
public boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition, @NotNull BlockFace blockFace, boolean doBlockUpdates) {
|
||||
final Chunk chunk = getChunkAt(blockPosition);
|
||||
Check.notNull(chunk, "You cannot break blocks in a null chunk!");
|
||||
if (chunk.isReadOnly()) return false;
|
||||
@ -192,7 +195,7 @@ public class InstanceContainer extends Instance {
|
||||
// Break or change the broken block based on event result
|
||||
final Block resultBlock = blockBreakEvent.getResultBlock();
|
||||
UNSAFE_setBlock(chunk, x, y, z, resultBlock, null,
|
||||
new BlockHandler.PlayerDestroy(block, this, blockPosition, player));
|
||||
new BlockHandler.PlayerDestroy(block, this, blockPosition, player), doBlockUpdates);
|
||||
// Send the block break effect packet
|
||||
PacketUtils.sendGroupedPacket(chunk.getViewers(),
|
||||
new EffectPacket(2001 /*Block break + block break sound*/, blockPosition, block.stateId(), false),
|
||||
|
@ -27,18 +27,18 @@ public class SharedInstance extends Instance {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, @NotNull Block block) {
|
||||
this.instanceContainer.setBlock(x, y, z, block);
|
||||
public void setBlock(int x, int y, int z, @NotNull Block block, boolean doBlockUpdates) {
|
||||
this.instanceContainer.setBlock(x, y, z, block, doBlockUpdates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean placeBlock(@NotNull BlockHandler.Placement placement) {
|
||||
return instanceContainer.placeBlock(placement);
|
||||
public boolean placeBlock(@NotNull BlockHandler.Placement placement, boolean doBlockUpdates) {
|
||||
return instanceContainer.placeBlock(placement, doBlockUpdates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition, @NotNull BlockFace blockFace) {
|
||||
return instanceContainer.breakBlock(player, blockPosition, blockFace);
|
||||
public boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition, @NotNull BlockFace blockFace, boolean doBlockUpdates) {
|
||||
return instanceContainer.breakBlock(player, blockPosition, blockFace, doBlockUpdates);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -153,7 +153,7 @@ public class BlockPlacementListener {
|
||||
// BlockPlacementRule check
|
||||
Block resultBlock = playerBlockPlaceEvent.getBlock();
|
||||
final BlockPlacementRule blockPlacementRule = BLOCK_MANAGER.getBlockPlacementRule(resultBlock);
|
||||
if (blockPlacementRule != null) {
|
||||
if (blockPlacementRule != null && playerBlockPlaceEvent.shouldDoBlockUpdates()) {
|
||||
// Get id from block placement rule instead of the event
|
||||
resultBlock = blockPlacementRule.blockPlace(new BlockPlacementRule.PlacementState(
|
||||
instance, resultBlock, blockFace,
|
||||
@ -168,7 +168,7 @@ public class BlockPlacementListener {
|
||||
// Place the block
|
||||
player.sendPacket(new AcknowledgeBlockChangePacket(packet.sequence()));
|
||||
instance.placeBlock(new BlockHandler.PlayerPlacement(resultBlock, instance, placementPosition, player, hand, blockFace,
|
||||
packet.cursorPositionX(), packet.cursorPositionY(), packet.cursorPositionZ()));
|
||||
packet.cursorPositionX(), packet.cursorPositionY(), packet.cursorPositionZ()), playerBlockPlaceEvent.shouldDoBlockUpdates());
|
||||
// Block consuming
|
||||
if (playerBlockPlaceEvent.doesConsumeBlock()) {
|
||||
// Consume the block in the player's hand
|
||||
|
Loading…
Reference in New Issue
Block a user