mirror of
https://github.com/PaperMC/Paper.git
synced 2025-12-05 13:04:44 +01:00
Merge 021df303a1 into ffce96cf3e
This commit is contained in:
commit
05d68b195b
@ -0,0 +1,83 @@
|
||||
package org.bukkit.event.block;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
|
||||
/**
|
||||
* Called when the Creaking Heart block attempts to spawn or remove its protector (Creaking mob).
|
||||
* <p>
|
||||
* Examples:
|
||||
* <ul>
|
||||
* <li>Protector is about to spawn near the Creaking Heart block.
|
||||
* <li>Protector is about to be removed (due to death, distance, or other reasons).
|
||||
* </ul>
|
||||
* <p>
|
||||
*/
|
||||
@NullMarked
|
||||
public class CreakingHeartProtectorChangeEvent extends BlockEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
|
||||
public boolean spawn = false;
|
||||
@Nullable
|
||||
private final LivingEntity protector;
|
||||
private boolean cancelled;
|
||||
|
||||
/**
|
||||
* Constructs a new CreakingHeartProtectorChangeEvent.
|
||||
*
|
||||
* @param block the Creaking Heart block involved in this event
|
||||
* @param protector the protector entity (may be null for REMOVE if not available)
|
||||
* @param spawn the indicator of whether the mob is spawned or not
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public CreakingHeartProtectorChangeEvent(Block block, @Nullable LivingEntity protector, boolean spawn) {
|
||||
super(block);
|
||||
this.protector = protector;
|
||||
this.spawn = spawn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the protector entity involved in this event.
|
||||
*
|
||||
* @return the protector entity, or null if not available
|
||||
*/
|
||||
@Nullable
|
||||
public LivingEntity getProtector() {
|
||||
return protector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the protector is being spawned.
|
||||
*
|
||||
* @return whether the protector is being spawned
|
||||
*/
|
||||
public boolean isSpawned() {
|
||||
return spawn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.cancelled = cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return HANDLER_LIST;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLER_LIST;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
package org.bukkit.event.block;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.data.type.CreakingHeart.State;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* Called when a Creaking Heart block changes its state (e.g., AWAKE, DORMANT, UPROOTED) due to world conditions.
|
||||
* <p>
|
||||
* Examples:
|
||||
* <ul>
|
||||
* <li>Creaking Heart becoming AWAKE at night.
|
||||
* <li>Creaking Heart becoming DORMANT during the day.
|
||||
* <li>Creaking Heart becoming UPROOTED when requirements are not met.
|
||||
* </ul>
|
||||
* <p>
|
||||
*/
|
||||
@NullMarked
|
||||
public class CreakingHeartTransformEvent extends BlockEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
|
||||
private final BlockState oldState;
|
||||
private final BlockState newState;
|
||||
private final State oldCreakingHeartState;
|
||||
private final State newCreakingHeartState;
|
||||
private boolean cancelled;
|
||||
|
||||
/**
|
||||
* Constructs a new CreakingHeartTransformEvent.
|
||||
*
|
||||
* @param block the block being transformed
|
||||
* @param newState the new state of the block after transformation
|
||||
* @param oldState the previous state of the block before transformation
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public CreakingHeartTransformEvent(
|
||||
Block block,
|
||||
BlockState oldState,
|
||||
BlockState newState,
|
||||
State oldCreakingHeartState,
|
||||
State newCreakingHeartState
|
||||
) {
|
||||
super(Preconditions.checkNotNull(block, "block cannot be null"));
|
||||
this.oldState = Preconditions.checkNotNull(oldState, "oldState cannot be null");
|
||||
this.newState = Preconditions.checkNotNull(newState, "newState cannot be null");
|
||||
this.oldCreakingHeartState = Preconditions.checkNotNull(oldCreakingHeartState, "oldCreakingHeartState cannot be null");
|
||||
this.newCreakingHeartState = Preconditions.checkNotNull(newCreakingHeartState, "newCreakingHeartState cannot be null");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the new state of the block after the transformation.
|
||||
*
|
||||
* @return the new block state for this event's block
|
||||
*/
|
||||
public BlockState getNewState() {
|
||||
return this.newState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the previous state of the block before the transformation.
|
||||
*
|
||||
* @return the old block state for this event's block
|
||||
*/
|
||||
public BlockState getOldState() {
|
||||
return this.oldState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the previous logical state of the creaking heart.
|
||||
*
|
||||
* @return the old logical state
|
||||
*/
|
||||
public State getOldCreakingHeartState() {
|
||||
return this.oldCreakingHeartState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the new logical state of the creaking heart.
|
||||
*
|
||||
* @return the new logical state
|
||||
*/
|
||||
public State getNewCreakingHeartState() {
|
||||
return this.newCreakingHeartState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.cancelled = cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return HANDLER_LIST;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLER_LIST;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
package org.bukkit.event.block;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* Called when an Eyeblossom opens or closes (transforms its state) due to world conditions.
|
||||
* <p>
|
||||
* Examples:
|
||||
* <ul>
|
||||
* <li>Eyeblossom opening at night.
|
||||
* <li>Eyeblossom closing during the day.
|
||||
* </ul>
|
||||
* <p>
|
||||
*/
|
||||
@NullMarked
|
||||
public class EyeblossomTransformEvent extends BlockEvent implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLER_LIST = new HandlerList();
|
||||
|
||||
private final BlockState newState;
|
||||
private boolean cancelled;
|
||||
|
||||
/**
|
||||
* Constructs a new EyeblossomTransformEvent.
|
||||
*
|
||||
* @param block the block being transformed
|
||||
* @param newState the new state of the block after transformation
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
public EyeblossomTransformEvent(final Block block,final BlockState newState) {
|
||||
super(Preconditions.checkNotNull(block, "block"));
|
||||
this.newState = Preconditions.checkNotNull(newState, "newState");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the new state of the block after the transformation.
|
||||
*
|
||||
* @return the new block state for this event's block
|
||||
*/
|
||||
public BlockState getNewState() {
|
||||
return this.newState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean cancel) {
|
||||
this.cancelled = cancel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandlerList getHandlers() {
|
||||
return HANDLER_LIST;
|
||||
}
|
||||
|
||||
public static HandlerList getHandlerList() {
|
||||
return HANDLER_LIST;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
--- a/net/minecraft/world/level/block/CreakingHeartBlock.java
|
||||
+++ b/net/minecraft/world/level/block/CreakingHeartBlock.java
|
||||
@@ -106,9 +_,46 @@
|
||||
}
|
||||
|
||||
private static BlockState updateState(BlockState state, Level level, BlockPos pos) {
|
||||
+
|
||||
+ // Paper Start - Fire CreakingHeartTransformEvent
|
||||
+ net.minecraft.world.level.block.state.properties.CreakingHeartState oldState = state.getValue(STATE);
|
||||
+ net.minecraft.world.level.block.state.properties.CreakingHeartState newState;
|
||||
+
|
||||
boolean hasRequiredLogs = hasRequiredLogs(state, level, pos);
|
||||
- boolean flag = state.getValue(STATE) == CreakingHeartState.UPROOTED;
|
||||
- return hasRequiredLogs && flag ? state.setValue(STATE, isNaturalNight(level) ? CreakingHeartState.AWAKE : CreakingHeartState.DORMANT) : state;
|
||||
+
|
||||
+ boolean flag = oldState == net.minecraft.world.level.block.state.properties.CreakingHeartState.UPROOTED;
|
||||
+ if (hasRequiredLogs && flag) {
|
||||
+ newState = isNaturalNight(level)
|
||||
+ ? net.minecraft.world.level.block.state.properties.CreakingHeartState.AWAKE
|
||||
+ : net.minecraft.world.level.block.state.properties.CreakingHeartState.DORMANT;
|
||||
+ } else {
|
||||
+ newState = oldState;
|
||||
+ }
|
||||
+
|
||||
+ if (oldState != newState && level instanceof net.minecraft.server.level.ServerLevel serverLevel) {
|
||||
+
|
||||
+ org.bukkit.World bukkitWorld = serverLevel.getWorld();
|
||||
+ org.bukkit.block.Block bukkitBlock = bukkitWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ());
|
||||
+ org.bukkit.block.BlockState bukkitOldState = bukkitBlock.getState();
|
||||
+ net.minecraft.world.level.block.state.BlockState newNmsState = state.setValue(STATE, newState);
|
||||
+ org.bukkit.block.BlockState bukkitNewState = bukkitBlock.getState();
|
||||
+ bukkitNewState.setBlockData(org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(newNmsState));
|
||||
+ bukkitNewState.setType(org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(state.getBlock()));
|
||||
+
|
||||
+ org.bukkit.block.data.type.CreakingHeart.State apiOldState = org.bukkit.block.data.type.CreakingHeart.State.valueOf(oldState.name());
|
||||
+ org.bukkit.block.data.type.CreakingHeart.State apiNewState = org.bukkit.block.data.type.CreakingHeart.State.valueOf(newState.name());
|
||||
+
|
||||
+ org.bukkit.event.block.CreakingHeartTransformEvent event =
|
||||
+ new org.bukkit.event.block.CreakingHeartTransformEvent(
|
||||
+ bukkitBlock, bukkitOldState, bukkitNewState, apiOldState, apiNewState
|
||||
+ );
|
||||
+ if (!event.callEvent() || event.isCancelled()) {
|
||||
+ return state;
|
||||
+ }
|
||||
+ return state.setValue(STATE, newState);
|
||||
+ }
|
||||
+ return state;
|
||||
+ // Paper End - Fire CreakingHeartTransformEvent
|
||||
}
|
||||
|
||||
public static boolean hasRequiredLogs(BlockState state, LevelReader level, BlockPos pos) {
|
||||
@ -1,5 +1,25 @@
|
||||
--- a/net/minecraft/world/level/block/EyeblossomBlock.java
|
||||
+++ b/net/minecraft/world/level/block/EyeblossomBlock.java
|
||||
@@ -82,6 +_,19 @@
|
||||
} else if (CreakingHeartBlock.isNaturalNight(level) == this.type.open) {
|
||||
return false;
|
||||
} else {
|
||||
+
|
||||
+ // Paper Start - Fire EyeblossomTransformEvent before changing block
|
||||
+ org.bukkit.World bukkitWorld = level.getWorld();
|
||||
+ org.bukkit.block.Block bukkitBlock = bukkitWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ());
|
||||
+ org.bukkit.block.BlockState newState = bukkitBlock.getState();
|
||||
+ // Set the new state type to the transformed block (OPEN or CLOSED)
|
||||
+ newState.setType(org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(this.type.transform().block()));
|
||||
+ org.bukkit.event.block.EyeblossomTransformEvent event = new org.bukkit.event.block.EyeblossomTransformEvent(bukkitBlock, newState);
|
||||
+ if (!event.callEvent() || event.isCancelled()) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ // Paper End - Fire EyeblossomTransformEvent before changing block
|
||||
+
|
||||
EyeblossomBlock.Type type = this.type.transform();
|
||||
level.setBlock(pos, type.state(), 3);
|
||||
level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(state));
|
||||
@@ -100,6 +_,7 @@
|
||||
|
||||
@Override
|
||||
|
||||
@ -38,3 +38,23 @@
|
||||
if (!player.addItem(itemStack)) {
|
||||
player.drop(itemStack, false);
|
||||
}
|
||||
@@ -135,6 +_,19 @@
|
||||
boolean flag = this.potted == Blocks.OPEN_EYEBLOSSOM;
|
||||
boolean isNaturalNight = CreakingHeartBlock.isNaturalNight(level);
|
||||
if (flag != isNaturalNight) {
|
||||
+
|
||||
+ // Paper Start - Fire EyeblossomTransformEvent before changing block
|
||||
+ org.bukkit.World bukkitWorld = level.getWorld();
|
||||
+ org.bukkit.block.Block bukkitBlock = bukkitWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ());
|
||||
+ org.bukkit.block.BlockState newState = bukkitBlock.getState();
|
||||
+ // Set the new state type to the transformed block (OPEN or CLOSED)
|
||||
+ newState.setType(org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(EyeblossomBlock.Type.fromBoolean(flag).transform().block()));
|
||||
+ org.bukkit.event.block.EyeblossomTransformEvent event = new org.bukkit.event.block.EyeblossomTransformEvent(bukkitBlock, newState);
|
||||
+ if (!event.callEvent() || event.isCancelled()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper End - Fire EyeblossomTransformEvent before changing block
|
||||
+
|
||||
level.setBlock(pos, this.opposite(state), 3);
|
||||
EyeblossomBlock.Type type = EyeblossomBlock.Type.fromBoolean(flag).transform();
|
||||
type.spawnTransformParticle(level, pos, random);
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
--- a/net/minecraft/world/level/block/entity/CreakingHeartBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/CreakingHeartBlockEntity.java
|
||||
@@ -138,12 +_,40 @@
|
||||
}
|
||||
|
||||
private static BlockState updateCreakingState(Level level, BlockState state, BlockPos pos, CreakingHeartBlockEntity creakingHeart) {
|
||||
+ // Paper Start - Fire CreakingHeartTransformEvent
|
||||
+ CreakingHeartState oldState = state.getValue(CreakingHeartBlock.STATE);
|
||||
+ CreakingHeartState newState;
|
||||
if (!CreakingHeartBlock.hasRequiredLogs(state, level, pos) && creakingHeart.creakingInfo == null) {
|
||||
- return state.setValue(CreakingHeartBlock.STATE, CreakingHeartState.UPROOTED);
|
||||
+ newState = CreakingHeartState.UPROOTED;
|
||||
} else {
|
||||
boolean isNaturalNight = CreakingHeartBlock.isNaturalNight(level);
|
||||
- return state.setValue(CreakingHeartBlock.STATE, isNaturalNight ? CreakingHeartState.AWAKE : CreakingHeartState.DORMANT);
|
||||
- }
|
||||
+ newState = isNaturalNight ? CreakingHeartState.AWAKE : CreakingHeartState.DORMANT;
|
||||
+ }
|
||||
+ if (oldState != newState && level instanceof ServerLevel serverLevel) {
|
||||
+
|
||||
+ org.bukkit.World bukkitWorld = serverLevel.getWorld();
|
||||
+ org.bukkit.block.Block bukkitBlock = bukkitWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ());
|
||||
+ org.bukkit.block.BlockState bukkitOldState = bukkitBlock.getState();
|
||||
+ net.minecraft.world.level.block.state.BlockState newNmsState = state.setValue(CreakingHeartBlock.STATE, newState);
|
||||
+ org.bukkit.block.BlockState bukkitNewState = bukkitBlock.getState();
|
||||
+ bukkitNewState.setBlockData(org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(newNmsState));
|
||||
+ bukkitNewState.setType(org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(state.getBlock()));
|
||||
+
|
||||
+ org.bukkit.block.data.type.CreakingHeart.State apiOldState = org.bukkit.block.data.type.CreakingHeart.State.valueOf(oldState.name());
|
||||
+ org.bukkit.block.data.type.CreakingHeart.State apiNewState = org.bukkit.block.data.type.CreakingHeart.State.valueOf(newState.name());
|
||||
+
|
||||
+ org.bukkit.event.block.CreakingHeartTransformEvent event =
|
||||
+ new org.bukkit.event.block.CreakingHeartTransformEvent(
|
||||
+ bukkitBlock, bukkitOldState, bukkitNewState, apiOldState, apiNewState
|
||||
+ );
|
||||
+ if (!event.callEvent() || event.isCancelled()) {
|
||||
+ return state;
|
||||
+ }
|
||||
+ return state.setValue(CreakingHeartBlock.STATE, newState);
|
||||
+ }
|
||||
+ return state;
|
||||
+ // Paper End - Fire CreakingHeartTransformEvent
|
||||
+
|
||||
}
|
||||
|
||||
private double distanceToCreaking() {
|
||||
@@ -207,6 +_,21 @@
|
||||
return null;
|
||||
} else {
|
||||
Creaking creaking = optional.get();
|
||||
+
|
||||
+ // Paper Start - Fire CreakingHeartProtectorChangeEvent (SPAWN)
|
||||
+ org.bukkit.World bukkitWorld = level.getWorld();
|
||||
+ org.bukkit.block.Block bukkitBlock = bukkitWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
||||
+ org.bukkit.entity.LivingEntity bukkitProtector = (org.bukkit.entity.LivingEntity) creaking.getBukkitEntity();
|
||||
+ org.bukkit.event.block.CreakingHeartProtectorChangeEvent event =
|
||||
+ new org.bukkit.event.block.CreakingHeartProtectorChangeEvent(
|
||||
+ bukkitBlock, bukkitProtector, true
|
||||
+ );
|
||||
+ if (!event.callEvent() || event.isCancelled()) {
|
||||
+ creaking.discard();
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper End - Fire CreakingHeartProtectorChangeEvent (SPAWN)
|
||||
+
|
||||
level.gameEvent(creaking, GameEvent.ENTITY_PLACE, creaking.position());
|
||||
level.broadcastEntityEvent(creaking, (byte)60);
|
||||
creaking.setTransient(blockPos);
|
||||
@@ -316,6 +_,22 @@
|
||||
|
||||
public void removeProtector(@Nullable DamageSource damageSource) {
|
||||
if (this.getCreakingProtector().orElse(null) instanceof Creaking creaking) {
|
||||
+
|
||||
+ // Paper Start: Fire CreakingHeartProtectorChangeEvent (REMOVE)
|
||||
+ if (this.level instanceof ServerLevel serverLevel) {
|
||||
+ org.bukkit.World bukkitWorld = serverLevel.getWorld();
|
||||
+ org.bukkit.block.Block bukkitBlock = bukkitWorld.getBlockAt(this.getBlockPos().getX(), this.getBlockPos().getY(), this.getBlockPos().getZ());
|
||||
+ org.bukkit.entity.LivingEntity bukkitProtector = (org.bukkit.entity.LivingEntity) creaking.getBukkitEntity();
|
||||
+ org.bukkit.event.block.CreakingHeartProtectorChangeEvent event =
|
||||
+ new org.bukkit.event.block.CreakingHeartProtectorChangeEvent(
|
||||
+ bukkitBlock, bukkitProtector, false
|
||||
+ );
|
||||
+ if (!event.callEvent() || event.isCancelled()) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper End - Fire CreakingHeartProtectorChangeEvent (REMOVE)
|
||||
+
|
||||
if (damageSource == null) {
|
||||
creaking.tearDown();
|
||||
} else {
|
||||
Loading…
Reference in New Issue
Block a user