mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-25 18:09:27 +00:00
@@ -184,7 +184,7 @@ public final class CraftEngineBlocks {
|
||||
world.playBlockSound(position, state.settings().sounds().breakSound());
|
||||
}
|
||||
if (sendParticles) {
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(world.serverWorld(), WorldEvents.BLOCK_BREAK_EFFECT, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), state.customBlockState().registryId());
|
||||
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(world.serverWorld(), WorldEvents.BLOCK_BREAK_EFFECT, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), state.customBlockState().registryId());
|
||||
}
|
||||
FastNMS.INSTANCE.method$Level$removeBlock(world.serverWorld(), LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), isMoving);
|
||||
return true;
|
||||
|
||||
@@ -75,7 +75,7 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos));
|
||||
world.playBlockSound(position, customState.settings().sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
|
||||
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
|
||||
return MBlocks.AIR$defaultState;
|
||||
}
|
||||
return state;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package net.momirealms.craftengine.bukkit.block.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.DirectionUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
@@ -15,8 +18,10 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.block.properties.Property;
|
||||
import net.momirealms.craftengine.core.block.state.properties.DoorHinge;
|
||||
import net.momirealms.craftengine.core.block.state.properties.DoubleBlockHalf;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.entity.player.Player;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.context.BlockPlaceContext;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.sound.SoundData;
|
||||
@@ -32,6 +37,7 @@ import org.bukkit.block.data.Bisected;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Door;
|
||||
import org.bukkit.event.block.BlockRedstoneEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@@ -111,13 +117,44 @@ public class DoorBlockBehavior extends AbstractCanSurviveBlockBehavior {
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos));
|
||||
world.playBlockSound(position, customState.settings().sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
|
||||
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
|
||||
return MBlocks.AIR$defaultState;
|
||||
}
|
||||
return blockState;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object playerWillDestroy(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object level = args[0];
|
||||
Object pos = args[1];
|
||||
Object state = args[2];
|
||||
Object player = args[3];
|
||||
ImmutableBlockState blockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state));
|
||||
if (blockState == null || blockState.isEmpty()) return superMethod.call();
|
||||
org.bukkit.entity.Player bukkitPlayer = FastNMS.INSTANCE.method$ServerPlayer$getBukkitEntity(player);
|
||||
BukkitServerPlayer cePlayer = BukkitCraftEngine.instance().adapt(bukkitPlayer);
|
||||
Item<ItemStack> item = cePlayer.getItemInHand(InteractionHand.MAIN_HAND);
|
||||
if (cePlayer.canInstabuild() || !BlockStateUtils.isCorrectTool(blockState, item)) {
|
||||
preventDropFromBottomPart(level, pos, blockState, player);
|
||||
}
|
||||
return superMethod.call();
|
||||
}
|
||||
|
||||
private void preventDropFromBottomPart(Object level, Object pos, ImmutableBlockState state, Object player) {
|
||||
DoubleBlockHalf half = state.get(this.halfProperty);
|
||||
if (half == DoubleBlockHalf.UPPER) {
|
||||
Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, CoreReflections.instance$Direction$DOWN);
|
||||
Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos);
|
||||
ImmutableBlockState belowState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
|
||||
if (belowState == null || belowState.isEmpty()) return;
|
||||
Optional<DoorBlockBehavior> belowDoorBehavior = belowState.behavior().getAs(DoorBlockBehavior.class);
|
||||
if (belowDoorBehavior.isEmpty() || belowState.get(this.halfProperty) != DoubleBlockHalf.LOWER) return;
|
||||
FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, MBlocks.AIR$defaultState, UpdateOption.builder().updateSuppressDrops().updateClients().updateNeighbors().build().flags());
|
||||
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, player, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, belowState.customBlockState().registryId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExplosionHit(Object thisBlock, Object[] args, Callable<Object> superMethod) {
|
||||
if (this.canOpenByWindCharge && FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3])) {
|
||||
|
||||
@@ -70,7 +70,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior {
|
||||
net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level));
|
||||
WorldPosition position = new WorldPosition(world, Vec3d.atCenterOf(pos));
|
||||
world.playBlockSound(position, customState.settings().sounds().breakSound());
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
|
||||
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, customState.customBlockState().registryId());
|
||||
return MBlocks.AIR$defaultState;
|
||||
}
|
||||
return state;
|
||||
|
||||
@@ -256,4 +256,16 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object playerWillDestroy(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
Object previous = args[0];
|
||||
for (AbstractBlockBehavior behavior : this.behaviors) {
|
||||
Object processed = behavior.playerWillDestroy(thisBlock, args, superMethod);
|
||||
if (processed != previous) {
|
||||
return processed;
|
||||
}
|
||||
}
|
||||
return previous;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +177,10 @@ public final class BlockGenerator {
|
||||
.intercept(MethodDelegation.to(GetDirectSignalInterceptor.INSTANCE))
|
||||
// isSignalSource
|
||||
.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$isSignalSource))
|
||||
.intercept(MethodDelegation.to(IsSignalSourceInterceptor.INSTANCE));
|
||||
.intercept(MethodDelegation.to(IsSignalSourceInterceptor.INSTANCE))
|
||||
// playerWillDestroy
|
||||
.method(ElementMatchers.is(CoreReflections.method$Block$playerWillDestroy))
|
||||
.intercept(MethodDelegation.to(PlayerWillDestroyInterceptor.INSTANCE));
|
||||
if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) {
|
||||
builder.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval))
|
||||
.intercept(MethodDelegation.to(AffectNeighborsAfterRemovalInterceptor.INSTANCE));
|
||||
@@ -625,4 +628,19 @@ public final class BlockGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerWillDestroyInterceptor {
|
||||
public static final PlayerWillDestroyInterceptor INSTANCE = new PlayerWillDestroyInterceptor();
|
||||
|
||||
@RuntimeType
|
||||
public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) throws Exception {
|
||||
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
|
||||
try {
|
||||
return holder.value().playerWillDestroy(thisObj, args, superMethod);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().severe("Failed to run playerWillDestroy", e);
|
||||
return superMethod.call();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1824,18 +1824,10 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getInstanceDeclaredField(clazz$Abilities, boolean.class, 2)
|
||||
);
|
||||
|
||||
public static final Field field$Abilities$instabuild = requireNonNull(
|
||||
ReflectionUtils.getInstanceDeclaredField(clazz$Abilities, boolean.class, 3)
|
||||
);
|
||||
|
||||
public static final Field field$Abilities$mayBuild = requireNonNull(
|
||||
ReflectionUtils.getInstanceDeclaredField(clazz$Abilities, boolean.class, 4)
|
||||
);
|
||||
|
||||
public static final Field field$Player$abilities = requireNonNull(
|
||||
ReflectionUtils.getInstanceDeclaredField(clazz$Player, clazz$Abilities, 0)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$FlowingFluid = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.material.FluidTypeFlowing",
|
||||
@@ -3764,4 +3756,12 @@ public final class CoreReflections {
|
||||
throw new ReflectionInitException("Failed to initialize reflection", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Method method$Block$playerWillDestroy = requireNonNull(
|
||||
ReflectionUtils.getDeclaredMethod(
|
||||
clazz$Block,
|
||||
VersionHelper.isOrAbove1_20_3() ? clazz$BlockState : void.class,
|
||||
clazz$Level, clazz$BlockPos, clazz$BlockState, clazz$Player
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -250,13 +250,8 @@ public class BukkitServerPlayer extends Player {
|
||||
|
||||
@Override
|
||||
public boolean canInstabuild() {
|
||||
try {
|
||||
Object abilities = CoreReflections.field$Player$abilities.get(serverPlayer());
|
||||
return (boolean) CoreReflections.field$Abilities$instabuild.get(abilities);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
CraftEngine.instance().logger().warn("Failed to get canInstabuild for " + name(), e);
|
||||
return false;
|
||||
}
|
||||
Object abilities = FastNMS.INSTANCE.field$Player$abilities(serverPlayer());
|
||||
return FastNMS.INSTANCE.field$Abilities$instabuild(abilities);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -121,6 +121,6 @@ public class BukkitWorld implements World {
|
||||
|
||||
@Override
|
||||
public void levelEvent(int id, BlockPos pos, int data) {
|
||||
FastNMS.INSTANCE.method$Level$levelEvent(serverWorld(), id, LocationUtils.toBlockPos(pos), data);
|
||||
FastNMS.INSTANCE.method$LevelAccessor$levelEvent(serverWorld(), id, LocationUtils.toBlockPos(pos), data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,6 +138,11 @@ public abstract class BlockBehavior {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Level level, BlockPos pos, BlockState state, Player player
|
||||
public Object playerWillDestroy(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
|
||||
return superMethod.call();
|
||||
}
|
||||
|
||||
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ byte_buddy_version=1.17.5
|
||||
ahocorasick_version=0.6.3
|
||||
snake_yaml_version=2.4
|
||||
anti_grief_version=0.18
|
||||
nms_helper_version=1.0.28
|
||||
nms_helper_version=1.0.29
|
||||
evalex_version=3.5.0
|
||||
reactive_streams_version=1.0.4
|
||||
amazon_awssdk_version=2.31.23
|
||||
|
||||
Reference in New Issue
Block a user