9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-23 17:09:19 +00:00

feat(block): 添加草方块行为

This commit is contained in:
jhqwqmc
2025-04-28 06:17:25 +08:00
parent dd8997d1e3
commit a1215302cd
6 changed files with 100 additions and 3 deletions

View File

@@ -16,6 +16,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
public static final Key CONCRETE_POWDER_BLOCK = Key.from("craftengine:concrete_powder_block");
public static final Key SUGARCANE_BLOCK = Key.from("craftengine:sugar_cane_block");
public static final Key CROP_BLOCK = Key.from("craftengine:crop_block");
public static final Key GRASS_BLOCK = Key.from("craftengine:grass_block");
public static void init() {
register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE);
@@ -30,5 +31,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors {
register(CONCRETE_POWDER_BLOCK, ConcretePowderBlockBehavior.FACTORY);
register(SUGARCANE_BLOCK, SugarCaneBlockBehavior.FACTORY);
register(CROP_BLOCK, CropBlockBehavior.FACTORY);
register(GRASS_BLOCK, GrassBlockBehavior.FACTORY);
}
}

View File

@@ -0,0 +1,71 @@
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.util.BlockStateUtils;
import net.momirealms.craftengine.bukkit.util.ParticleUtils;
import net.momirealms.craftengine.bukkit.util.Reflections;
import net.momirealms.craftengine.core.block.CustomBlock;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory;
import net.momirealms.craftengine.core.util.VersionHelper;
import net.momirealms.craftengine.shared.block.BlockBehavior;
import org.bukkit.World;
import java.util.Map;
public class GrassBlockBehavior extends BukkitBlockBehavior {
public static final Factory FACTORY = new Factory();
public GrassBlockBehavior(CustomBlock block) {
super(block);
}
@Override
public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) {
return FastNMS.INSTANCE.method$GrassBlock$isValidBonemealTarget(args[0], args[1], args[2]);
}
@Override
public boolean isBoneMealSuccess(Object thisBlock, Object[] args) throws Exception {
if (!VersionHelper.isOrAbove1_20_2()) return true;
Object level = args[0];
Object blockPos = args[2];
Object blockState = args[3];
ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState));
if (immutableBlockState == null || immutableBlockState.isEmpty()) {
return false;
}
boolean sendParticles = false;
Object visualState = immutableBlockState.vanillaBlockState().handle();
Object visualStateBlock = Reflections.method$BlockStateBase$getBlock.invoke(visualState);
if (Reflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) {
boolean is = FastNMS.INSTANCE.method$BonemealableBlock$isValidBonemealTarget(visualStateBlock, level, blockPos, visualState);
if (!is) {
sendParticles = true;
}
} else {
sendParticles = true;
}
if (sendParticles) {
World world = FastNMS.INSTANCE.method$Level$getCraftWorld(level);
int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos);
int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos);
int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos);
world.spawnParticle(ParticleUtils.getParticle("HAPPY_VILLAGER"), x + 0.5, y + 1.5, z + 0.5, 20, 2, 0, 2);
}
return true;
}
@Override
public void performBoneMeal(Object thisBlock, Object[] args) {
FastNMS.INSTANCE.method$GrassBlock$performBoneMeal(args[0], args[1], args[2], args[3], thisBlock);
}
public static class Factory implements BlockBehaviorFactory {
@Override
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
return new GrassBlockBehavior(block);
}
}
}

View File

@@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.item.behavior;
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
import net.momirealms.craftengine.bukkit.block.behavior.CropBlockBehavior;
import net.momirealms.craftengine.bukkit.block.behavior.GrassBlockBehavior;
import net.momirealms.craftengine.bukkit.block.behavior.SaplingBlockBehavior;
import net.momirealms.craftengine.bukkit.nms.FastNMS;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
@@ -43,6 +44,10 @@ public class BoneMealItemBehavior extends ItemBehavior {
}
} else if (state.behavior() instanceof SaplingBlockBehavior) {
shouldHandle = true;
} else if (state.behavior() instanceof GrassBlockBehavior) {
if (block.getLocation().add(0, 1, 0).getBlock().isEmpty()) {
shouldHandle = true;
}
}
if (!shouldHandle) return InteractionResult.PASS;

View File

@@ -1,5 +1,6 @@
package net.momirealms.craftengine.bukkit.util;
import net.momirealms.craftengine.core.util.VersionHelper;
import org.bukkit.Particle;
public class ParticleUtils {
@@ -10,7 +11,7 @@ public class ParticleUtils {
} catch (IllegalArgumentException e) {
return switch (particle) {
case "REDSTONE" -> Particle.valueOf("DUST");
case "VILLAGER_HAPPY" -> Particle.valueOf("HAPPY_VILLAGER");
case "VILLAGER_HAPPY" -> Particle.valueOf(VersionHelper.isOrAbove1_20_5() ? "HAPPY_VILLAGER" : "VILLAGER_HAPPY");
default -> Particle.valueOf(particle);
};
}

View File

@@ -397,7 +397,7 @@ public class Reflections {
);
public static final Class<?> clazz$HolderLookup$Provider = BukkitReflectionUtils.findReobfOrMojmapClass(
"core.HolderLookup$b",
VersionHelper.isOrAbove1_20_5() ? "core.HolderLookup$a" : "core.HolderLookup$b",
"core.HolderLookup$Provider"
);
@@ -2076,6 +2076,12 @@ public class Reflections {
)
);
public static final Class<?> clazz$PlacedFeature = requireNonNull(
ReflectionUtils.getClazz(
BukkitReflectionUtils.assembleMCClass("world.level.levelgen.placement.PlacedFeature")
)
);
// 1.21+
public static final Class<?> clazz$JukeboxSong =
ReflectionUtils.getClazz(
@@ -2092,6 +2098,7 @@ public class Reflections {
public static final Object instance$BuiltInRegistries$ENTITY_TYPE;
public static final Object instance$BuiltInRegistries$FLUID;
public static final Object instance$BuiltInRegistries$RECIPE_TYPE;
public static final Object instance$BuiltInRegistries$PLACED_FEATURE;
public static final Object instance$InternalRegistries$DIMENSION_TYPE;
@Nullable // 1.21+
public static final Object instance$InternalRegistries$JUKEBOX_SONG;
@@ -2108,6 +2115,7 @@ public class Reflections {
public static final Object instance$Registries$RECIPE_TYPE;
public static final Object instance$Registries$DIMENSION_TYPE;
public static final Object instance$Registries$CONFIGURED_FEATURE;
public static final Object instance$Registries$PLACED_FEATURE;
@Nullable // 1.21+
public static final Object instance$Registries$JUKEBOX_SONG;
@@ -2128,6 +2136,7 @@ public class Reflections {
Object registries$Fluid = null;
Object registries$RecipeType = null;
Object registries$ConfiguredFeature = null;
Object registries$PlacedFeature = null;
Object registries$JukeboxSong = null;
for (Field field : fields) {
Type fieldType = field.getGenericType();
@@ -2166,6 +2175,8 @@ public class Reflections {
registries$Fluid = field.get(null);
} else if (VersionHelper.isOrAbove1_21() && type == clazz$JukeboxSong) {
registries$JukeboxSong = field.get(null);
} else if (type == clazz$PlacedFeature) {
registries$PlacedFeature = field.get(null);
}
}
}
@@ -2184,6 +2195,7 @@ public class Reflections {
instance$Registries$FLUID = requireNonNull(registries$Fluid);
instance$Registries$RECIPE_TYPE = requireNonNull(registries$RecipeType);
instance$Registries$CONFIGURED_FEATURE = requireNonNull(registries$ConfiguredFeature);
instance$Registries$PLACED_FEATURE = requireNonNull(registries$PlacedFeature);
instance$Registries$JUKEBOX_SONG = registries$JukeboxSong;
Object server = method$MinecraftServer$getServer.invoke(null);
Object registries = field$MinecraftServer$registries.get(server);
@@ -2199,6 +2211,7 @@ public class Reflections {
instance$BuiltInRegistries$ENTITY_TYPE = method$RegistryAccess$registryOrThrow.invoke(instance$registryAccess, registries$EntityType);
instance$BuiltInRegistries$FLUID = method$RegistryAccess$registryOrThrow.invoke(instance$registryAccess, registries$Fluid);
instance$BuiltInRegistries$RECIPE_TYPE = method$RegistryAccess$registryOrThrow.invoke(instance$registryAccess, registries$RecipeType);
instance$BuiltInRegistries$PLACED_FEATURE = method$RegistryAccess$registryOrThrow.invoke(instance$registryAccess, registries$PlacedFeature);
if (registries$JukeboxSong == null) instance$InternalRegistries$JUKEBOX_SONG = null;
else instance$InternalRegistries$JUKEBOX_SONG = method$RegistryAccess$registryOrThrow.invoke(instance$registryAccess, registries$JukeboxSong);
} catch (ReflectiveOperationException e) {
@@ -3587,6 +3600,8 @@ public class Reflections {
public static final Object instance$Blocks$FIRE;
public static final Object instance$Blocks$SOUL_FIRE;
public static final Object instance$Blocks$ICE;
public static final Object instance$Blocks$SHORT_GRASS;
public static final Object instance$Blocks$SHORT_GRASS$defaultState;
static {
try {
@@ -3602,6 +3617,9 @@ public class Reflections {
instance$Blocks$STONE$defaultState = method$Block$defaultBlockState.invoke(instance$Blocks$STONE);
Object ice = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "ice");
instance$Blocks$ICE = method$Registry$get.invoke(instance$BuiltInRegistries$BLOCK, ice);
Object shortGrass = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass");
instance$Blocks$SHORT_GRASS = method$Registry$get.invoke(instance$BuiltInRegistries$BLOCK, shortGrass);
instance$Blocks$SHORT_GRASS$defaultState = method$Block$defaultBlockState.invoke(instance$Blocks$SHORT_GRASS);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}

View File

@@ -50,7 +50,7 @@ byte_buddy_version=1.17.5
ahocorasick_version=0.6.3
snake_yaml_version=2.4
anti_grief_version=0.15
nms_helper_version=0.62
nms_helper_version=0.64
reactive_streams_version=1.0.4
amazon_awssdk_version=2.31.23
amazon_awssdk_eventstream_version=1.0.1