mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2026-01-04 15:41:38 +00:00
重新实现grass block
This commit is contained in:
@@ -2,7 +2,10 @@ 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.bukkit.plugin.reflection.minecraft.MBlocks;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.FeatureUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.LocationUtils;
|
||||
import net.momirealms.craftengine.bukkit.util.ParticleUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitBlockInWorld;
|
||||
@@ -14,7 +17,8 @@ import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.Item;
|
||||
import net.momirealms.craftengine.core.item.ItemKeys;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.util.VersionHelper;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.util.*;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
@@ -25,9 +29,15 @@ import java.util.Optional;
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class GrassBlockBehavior extends BukkitBlockBehavior {
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private final Key feature;
|
||||
|
||||
public GrassBlockBehavior(CustomBlock block) {
|
||||
public GrassBlockBehavior(CustomBlock block, Key feature) {
|
||||
super(block);
|
||||
this.feature = feature;
|
||||
}
|
||||
|
||||
public Key boneMealFeature() {
|
||||
return feature;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,15 +107,58 @@ public class GrassBlockBehavior extends BukkitBlockBehavior {
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void performBoneMeal(Object thisBlock, Object[] args) {
|
||||
// TODO 使用骨粉
|
||||
public void performBoneMeal(Object thisBlock, Object[] args) throws Exception {
|
||||
Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.PLACED_FEATURE);
|
||||
if (registry == null) return;
|
||||
Optional<Object> holder = (Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createPlacedFeatureKey(boneMealFeature()));
|
||||
if (holder.isEmpty()) {
|
||||
CraftEngine.instance().logger().warn("Placed feature not found: " + boneMealFeature());
|
||||
return;
|
||||
}
|
||||
BlockPos grassPos = LocationUtils.fromBlockPos(args[2]);
|
||||
Object world = args[0];
|
||||
Object random = args[1];
|
||||
BlockPos topPos = grassPos.above();
|
||||
out:
|
||||
for (int i = 0; i < 128; i++) {
|
||||
BlockPos currentPos = topPos;
|
||||
for (int j = 0; j < i / 16; ++j) {
|
||||
currentPos = currentPos.offset(
|
||||
RandomUtils.generateRandomInt(-1, 2), RandomUtils.generateRandomInt(-1, 2) * RandomUtils.generateRandomInt(0, 3) / 2, RandomUtils.generateRandomInt(-1, 2)
|
||||
);
|
||||
BlockPos belowPos = currentPos.relative(Direction.DOWN);
|
||||
Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, LocationUtils.toBlockPos(belowPos));
|
||||
Optional<ImmutableBlockState> optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(belowState);
|
||||
if (optionalCustomState.isEmpty()) {
|
||||
continue out;
|
||||
}
|
||||
if (optionalCustomState.get().owner().value() != super.customBlock) {
|
||||
continue out;
|
||||
}
|
||||
Object nmsCurrentPos = LocationUtils.toBlockPos(currentPos);
|
||||
Object currentState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, nmsCurrentPos);
|
||||
if (FastNMS.INSTANCE.method$BlockStateBase$isCollisionShapeFullBlock(currentState, world, nmsCurrentPos)) {
|
||||
continue out;
|
||||
}
|
||||
if (BlockStateUtils.getBlockOwner(currentState) == MBlocks.SHORT_GRASS && RandomUtils.generateRandomInt(0, 10) == 0) {
|
||||
CoreReflections.method$BonemealableBlock$performBonemeal.invoke(MBlocks.SHORT_GRASS, world, random, nmsCurrentPos, currentState);
|
||||
}
|
||||
if (FastNMS.INSTANCE.method$BlockStateBase$isAir(currentState)) {
|
||||
Object chunkGenerator = CoreReflections.method$ServerChunkCache$getGenerator.invoke(FastNMS.INSTANCE.method$ServerLevel$getChunkSource(world));
|
||||
Object placedFeature = CoreReflections.method$Holder$value.invoke(holder.get());
|
||||
CoreReflections.method$PlacedFeature$place.invoke(placedFeature, world, chunkGenerator, random, nmsCurrentPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory implements BlockBehaviorFactory {
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
return new GrassBlockBehavior(block);
|
||||
String feature = ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(arguments, "feature", "placed-feature"), "warning.config.block.behavior.grass.missing_feature");
|
||||
return new GrassBlockBehavior(block, Key.of(feature));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
|
||||
Object registry = CoreReflections.method$RegistryAccess$registryOrThrow.invoke(FastNMS.INSTANCE.registryAccess(), MRegistries.CONFIGURED_FEATURE);
|
||||
if (registry == null) return;
|
||||
@SuppressWarnings("unchecked")
|
||||
Optional<Object> holder = (Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createFeatureKey(treeFeature()));
|
||||
Optional<Object> holder = (Optional<Object>) CoreReflections.method$Registry$getHolder1.invoke(registry, FeatureUtils.createConfiguredFeatureKey(treeFeature()));
|
||||
if (holder.isEmpty()) {
|
||||
CraftEngine.instance().logger().warn("Configured feature not found: " + treeFeature());
|
||||
return;
|
||||
@@ -172,7 +172,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public BlockBehavior create(CustomBlock block, Map<String, Object> arguments) {
|
||||
String feature = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("feature"), "warning.config.block.behavior.sapling.missing_feature");
|
||||
String feature = ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(arguments, "feature", "configured-feature"), "warning.config.block.behavior.sapling.missing_feature");
|
||||
Property<Integer> stageProperty = (Property<Integer>) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("stage"), "warning.config.block.behavior.sapling.missing_stage");
|
||||
double boneMealSuccessChance = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("bone-meal-success-chance", 0.45), "bone-meal-success-chance");
|
||||
return new SaplingBlockBehavior(block, Key.of(feature), (IntegerProperty) stageProperty, boneMealSuccessChance,
|
||||
|
||||
@@ -2149,6 +2149,10 @@ public final class CoreReflections {
|
||||
ReflectionUtils.getMethod(clazz$ConfiguredFeature, boolean.class, clazz$WorldGenLevel, clazz$ChunkGenerator, clazz$RandomSource, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Method method$PlacedFeature$place = requireNonNull(
|
||||
ReflectionUtils.getMethod(clazz$PlacedFeature, boolean.class, clazz$WorldGenLevel, clazz$ChunkGenerator, clazz$RandomSource, clazz$BlockPos)
|
||||
);
|
||||
|
||||
public static final Class<?> clazz$BonemealableBlock = requireNonNull(
|
||||
BukkitReflectionUtils.findReobfOrMojmapClass(
|
||||
"world.level.block.IBlockFragilePlantElement",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.nms.FastNMS;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections;
|
||||
import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
@@ -8,11 +9,11 @@ public class FeatureUtils {
|
||||
|
||||
private FeatureUtils() {}
|
||||
|
||||
public static Object createFeatureKey(Key id) {
|
||||
try {
|
||||
return CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.CONFIGURED_FEATURE, KeyUtils.toResourceLocation(id));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
public static Object createConfiguredFeatureKey(Key id) {
|
||||
return FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.CONFIGURED_FEATURE, KeyUtils.toResourceLocation(id));
|
||||
}
|
||||
|
||||
public static Object createPlacedFeatureKey(Key id) {
|
||||
return FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.PLACED_FEATURE, KeyUtils.toResourceLocation(id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,6 +272,7 @@ warning.config.block.behavior.stairs.missing_facing: "<yellow>Issue found in fil
|
||||
warning.config.block.behavior.stairs.missing_half: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'half' property for 'stairs_block' behavior.</yellow>"
|
||||
warning.config.block.behavior.stairs.missing_shape: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'shape' property for 'stairs_block' behavior.</yellow>"
|
||||
warning.config.block.behavior.pressure_plate.missing_powered: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'powered' property for 'pressure_plate_block' behavior.</yellow>"
|
||||
warning.config.block.behavior.grass.missing_feature: "<yellow>Issue found in file <arg:0> - The block '<arg:1>' is missing the required 'feature' argument for 'grass_block' behavior.</yellow>"
|
||||
warning.config.model.generation.missing_parent: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is missing the required 'parent' argument in 'generation' section.</yellow>"
|
||||
warning.config.model.generation.invalid_display_position: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid display position '<arg:2>' in 'generation.display' section. Allowed display positions: [<arg:3>]</yellow>"
|
||||
warning.config.model.generation.invalid_gui_light: "<yellow>Issue found in file <arg:0> - The config '<arg:1>' is using an invalid gui-light option '<arg:2>' in 'generation' section. Allowed gui light options: [<arg:3>]</yellow>"
|
||||
|
||||
@@ -273,6 +273,7 @@ warning.config.block.behavior.stairs.missing_facing: "<yellow>在文件 <arg:0>
|
||||
warning.config.block.behavior.stairs.missing_half: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'stairs_block' 行为缺少必需的 'half' 属性</yellow>"
|
||||
warning.config.block.behavior.stairs.missing_shape: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'stairs_block' 行为缺少必需的 'shape' 属性</yellow>"
|
||||
warning.config.block.behavior.pressure_plate.missing_powered: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'pressure_plate_block' 行为缺少必需的 'powered' 属性</yellow>"
|
||||
warning.config.block.behavior.grass.missing_feature: "<yellow>在文件 <arg:0> 发现问题 - 方块 '<arg:1>' 的 'grass_block' 行为缺少必需的 'feature' 参数</yellow>"
|
||||
warning.config.model.generation.missing_parent: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 的 'generation' 段落缺少必需的 'parent' 参数</yellow>"
|
||||
warning.config.model.generation.conflict: "<yellow>在文件 <arg:0> 发现问题 - 无法为 '<arg:1>' 生成模型 存在多个配置尝试使用相同路径 '<arg:2>' 生成不同的 JSON 模型</yellow>"
|
||||
warning.config.model.generation.invalid_display_position: "<yellow>在文件 <arg:0> 发现问题 - 配置项 '<arg:1>' 在 'generation.display' 区域使用了无效的 display 位置类型 '<arg:2>'. 可用展示类型: [<arg:3>]</yellow>"
|
||||
|
||||
@@ -50,4 +50,8 @@ public class BlockPos extends Vec3i {
|
||||
public static long asLong(int x, int y, int z) {
|
||||
return (((long) x & (long) 67108863) << 38) | (((long) y & (long) 4095)) | (((long) z & (long) 67108863) << 12);
|
||||
}
|
||||
|
||||
public BlockPos offset(int x, int y, int z) {
|
||||
return x == 0 && y == 0 && z == 0 ? this : new BlockPos(this.x() + x, this.y() + y, this.z() + z);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user