9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-25 18:09:27 +00:00

feat(bukkit): 实现弹跳方块行为

This commit is contained in:
jhqwqmc
2025-09-08 21:29:25 +08:00
parent 0cb9843fef
commit c9d7723881
8 changed files with 141 additions and 2 deletions

View File

@@ -0,0 +1,68 @@
package net.momirealms.craftengine.bukkit.block.behavior;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
import net.momirealms.craftengine.core.block.BlockBehavior;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.util.ResourceConfigUtils;
import net.momirealms.craftengine.core.util.VersionHelper;
import java.util.Map;
import java.util.concurrent.Callable;
public class BouncingBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
private final double bounceHeight;
public BouncingBlockBehavior(CustomBlock customBlock, double bounceHeight) {
super(customBlock);
this.bounceHeight = bounceHeight;
}
@Override
public void fallOn(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object entity = args[3];
Object finalFallDistance;
if (VersionHelper.isOrAbove1_21_5()) {
double fallDistance = (double) args[4];
finalFallDistance = fallDistance * 0.5;
} else {
finalFallDistance = (float) args[4] * 0.5F;
}
FastNMS.INSTANCE.method$Entity$causeFallDamage(
entity, finalFallDistance, 1.0F,
FastNMS.INSTANCE.method$DamageSources$fall(FastNMS.INSTANCE.method$Entity$damageSources(entity))
);
}
@Override
public void updateEntityMovementAfterFallOn(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
Object entity = args[1];
if (FastNMS.INSTANCE.method$Entity$getSharedFlag(entity, 1)) {
bounceUp(entity);
}
}
private void bounceUp(Object entity) {
Object deltaMovement = FastNMS.INSTANCE.method$Entity$getDeltaMovement(entity);
if (FastNMS.INSTANCE.field$Vec3$y(deltaMovement) < 0.0) {
double d = CoreReflections.clazz$LivingEntity.isInstance(entity) ? 1.0 : 0.8;
FastNMS.INSTANCE.method$Entity$setDeltaMovement(
entity,
FastNMS.INSTANCE.field$Vec3$x(deltaMovement),
-FastNMS.INSTANCE.field$Vec3$y(deltaMovement) * this.bounceHeight * d,
FastNMS.INSTANCE.field$Vec3$z(deltaMovement)
);
}
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
double bounceHeight = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("bounce-height", 0.66), "bounce-height");
return new BouncingBlockBehavior(block, bounceHeight);
}
}
}

View File

@@ -31,6 +31,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key SIMPLE_STORAGE_BLOCK = Key.from("craftengine:simple_storage_block");
public static final Key TOGGLEABLE_LAMP_BLOCK = Key.from("craftengine:toggleable_lamp_block");
public static final Key SOFA_BLOCK = Key.from("craftengine:sofa_block");
public static final Key BOUNCING_BLOCK = Key.from("craftengine:bouncing_block");
public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -60,5 +61,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(SIMPLE_STORAGE_BLOCK, SimpleStorageBlockBehavior.FACTORY);
register(TOGGLEABLE_LAMP_BLOCK, ToggleableLampBlockBehavior.FACTORY);
register(SOFA_BLOCK, SofaBlockBehavior.FACTORY);
register(BOUNCING_BLOCK, BouncingBlockBehavior.FACTORY);
}
}

View File

@@ -336,4 +336,18 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior {
behavior.spawnAfterBreak(thisBlock, args, superMethod);
}
}
@Override
public void fallOn(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
for (AbstractBlockBehavior behavior : this.behaviors) {
behavior.fallOn(thisBlock, args, superMethod);
}
}
@Override
public void updateEntityMovementAfterFallOn(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
for (AbstractBlockBehavior behavior : this.behaviors) {
behavior.updateEntityMovementAfterFallOn(thisBlock, args, superMethod);
}
}
}

View File

@@ -159,7 +159,14 @@ public final class BlockGenerator {
.intercept(MethodDelegation.to(PlayerWillDestroyInterceptor.INSTANCE))
// spawnAfterBreak
.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$spawnAfterBreak))
.intercept(MethodDelegation.to(SpawnAfterBreakInterceptor.INSTANCE));
.intercept(MethodDelegation.to(SpawnAfterBreakInterceptor.INSTANCE))
// fallOn
.method(ElementMatchers.is(CoreReflections.method$Block$fallOn))
.intercept(MethodDelegation.to(FallOnInterceptor.INSTANCE))
// updateEntityMovementAfterFallOn
.method(ElementMatchers.is(CoreReflections.method$Block$updateEntityMovementAfterFallOn))
.intercept(MethodDelegation.to(UpdateEntityMovementAfterFallOnInterceptor.INSTANCE))
;
// 1.21.5+
if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) {
builder = builder.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval))
@@ -699,4 +706,32 @@ public final class BlockGenerator {
}
}
}
public static class FallOnInterceptor {
public static final FallOnInterceptor INSTANCE = new FallOnInterceptor();
@RuntimeType
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
try {
holder.value().fallOn(thisObj, args, superMethod);
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to run fallOn", e);
}
}
}
public static class UpdateEntityMovementAfterFallOnInterceptor {
public static final UpdateEntityMovementAfterFallOnInterceptor INSTANCE = new UpdateEntityMovementAfterFallOnInterceptor();
@RuntimeType
public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable<Object> superMethod) {
ObjectHolder<BlockBehavior> holder = ((DelegatingBlock) thisObj).behaviorDelegate();
try {
holder.value().updateEntityMovementAfterFallOn(thisObj, args, superMethod);
} catch (Exception e) {
CraftEngine.instance().logger().severe("Failed to run updateEntityMovementAfterFallOn", e);
}
}
}
}

View File

@@ -4209,4 +4209,12 @@ public final class CoreReflections {
public static final Method method$BlockAndTintGetter$getLightEngine = requireNonNull(
ReflectionUtils.getDeclaredMethod(clazz$BlockAndTintGetter, clazz$LevelLightEngine)
);
public static final Method method$Block$fallOn = requireNonNull(
ReflectionUtils.getDeclaredMethod(clazz$Block, void.class, clazz$Level, clazz$BlockState, clazz$BlockPos, clazz$Entity, VersionHelper.isOrAbove1_21_5() ? double.class : float.class)
);
public static final Method method$Block$updateEntityMovementAfterFallOn = requireNonNull(
ReflectionUtils.getDeclaredMethod(clazz$Block, void.class, clazz$BlockGetter, clazz$Entity)
);
}

View File

@@ -585,6 +585,9 @@ items#misc:
hit: minecraft:block.wood.hit
place: minecraft:block.wood.place
step: minecraft:block.wood.step
behavior:
type: bouncing_block
bounce-height: 0.66
state:
id: 0
state: white_bed[facing=west,occupied=false,part=foot]

View File

@@ -178,6 +178,15 @@ public abstract class BlockBehavior {
public void spawnAfterBreak(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
}
// 1.20.1~1.21.4 Level world, BlockState state, BlockPos pos, Entity entity, float fallDistance
// 1.21.5+ Level level, BlockState state, BlockPos pos, Entity entity, double fallDistance
public void fallOn(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
}
// BlockGetter level, Entity entity
public void updateEntityMovementAfterFallOn(Object thisBlock, Object[] args, Callable<Object> superMethod) throws Exception {
}
public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) {
return state;
}

View File

@@ -50,7 +50,7 @@ byte_buddy_version=1.17.5
ahocorasick_version=0.6.3
snake_yaml_version=2.5
anti_grief_version=0.20
nms_helper_version=1.0.80
nms_helper_version=1.0.81
evalex_version=3.5.0
reactive_streams_version=1.0.4
amazon_awssdk_version=2.33.1