From d42c408f8c532ed624912ee885af852bf5b52025 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 01:02:06 +0800 Subject: [PATCH 01/28] refactor bush block --- .../default/configuration/plants.yml | 3 + .../block/behavior/BukkitBlockBehaviors.java | 2 + .../block/behavior/BushBlockBehavior.java | 72 +++++++++++++++---- .../block/behavior/HangingBlockBehavior.java | 38 ++++++++++ .../block/behavior/OnLiquidBlockBehavior.java | 7 +- .../block/behavior/SaplingBlockBehavior.java | 20 +++--- .../behavior/SugarCaneBlockBehavior.java | 11 +++ .../bukkit/loot/BukkitVanillaLootManager.java | 2 +- .../plugin/network/BukkitNetworkManager.java | 1 - .../bukkit/util/BlockStateUtils.java | 35 ++++++++- .../core/plugin/network/NetworkManager.java | 2 - 11 files changed, 160 insertions(+), 33 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 8f4d7e973..8016ddf9c 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -34,6 +34,9 @@ blocks: push-reaction: DESTROY behavior: type: bush_block + bottom-block-tags: + - minecraft:dirt + - minecraft:farmland loot: template: "default:loot_table/basic" arguments: diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index fc6fd3488..9cf2a38b6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.shared.block.EmptyBlockBehavior; public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key BUSH_BLOCK = Key.from("craftengine:bush_block"); + public static final Key HANGING_BLOCK = Key.from("craftengine:hanging_block"); public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block"); public static final Key LEAVES_BLOCK = Key.from("craftengine:leaves_block"); public static final Key STRIPPABLE_BLOCK = Key.from("craftengine:strippable_block"); @@ -18,6 +19,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); register(FALLING_BLOCK, FallingBlockBehavior.FACTORY); register(BUSH_BLOCK, BushBlockBehavior.FACTORY); + register(HANGING_BLOCK, HangingBlockBehavior.FACTORY); register(LEAVES_BLOCK, LeavesBlockBehavior.FACTORY); register(STRIPPABLE_BLOCK, StrippableBlockBehavior.FACTORY); register(SAPLING_BLOCK, SaplingBlockBehavior.FACTORY); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index 6de0a63b8..19fa6e522 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -14,26 +14,29 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.parameter.LootParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.Tuple; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.shared.block.BlockBehavior; -import org.bukkit.World; +import org.bukkit.*; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.Callable; public class BushBlockBehavior extends AbstractBlockBehavior { public static final Factory FACTORY = new Factory(); - protected static final Object DIRT_TAG = BlockTags.getOrCreate(Key.of("minecraft", "dirt")); - protected static final Object FARMLAND = BlockTags.getOrCreate(Key.of("minecraft", "farmland")); - public static final BushBlockBehavior INSTANCE = new BushBlockBehavior(List.of(DIRT_TAG, FARMLAND)); protected final List tagsCanSurviveOn; + protected final Set blocksCansSurviveOn; + protected final Set customBlocksCansSurviveOn; + protected final boolean any; - public BushBlockBehavior(List tagsCanSurviveOn) { + public BushBlockBehavior(List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { this.tagsCanSurviveOn = tagsCanSurviveOn; + this.blocksCansSurviveOn = blocksCansSurviveOn; + this.customBlocksCansSurviveOn = customBlocksCansSurviveOn; + this.any = this.tagsCanSurviveOn.isEmpty() && this.blocksCansSurviveOn.isEmpty() && this.customBlocksCansSurviveOn.isEmpty(); } @Override @@ -82,19 +85,41 @@ public class BushBlockBehavior extends AbstractBlockBehavior { } public static class Factory implements BlockBehaviorFactory { + @Override public BlockBehavior create(CustomBlock block, Map arguments) { - if (arguments.containsKey("bottom-block-tags")) { - return new BushBlockBehavior(MiscUtils.getAsStringList(arguments.get("bottom-block-tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList()); - } else if (arguments.containsKey("tags")) { - return new BushBlockBehavior(MiscUtils.getAsStringList(arguments.get("tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList()); - } else { - return INSTANCE; - } + Tuple, Set, Set> tuple = readTagsAndState(arguments); + return new BushBlockBehavior(tuple.left(), tuple.mid(), tuple.right()); } } - private boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { + public static Tuple, Set, Set> readTagsAndState(Map arguments) { + List mcTags = new ArrayList<>(); + for (String tag : MiscUtils.getAsStringList(arguments.getOrDefault("bottom-block-tags", List.of()))) { + mcTags.add(BlockTags.getOrCreate(Key.of(tag))); + } + Set mcBlocks = new HashSet<>(); + Set customBlocks = new HashSet<>(); + for (String blockStateStr : MiscUtils.getAsStringList(arguments.getOrDefault("bottom-blocks", List.of()))) { + int index = blockStateStr.indexOf('['); + Key blockType = index != -1 ? Key.from(blockStateStr.substring(0, index)) : Key.from(blockStateStr); + Material material = Registry.MATERIAL.get(new NamespacedKey(blockType.namespace(), blockType.value())); + if (material != null) { + if (index == -1) { + // vanilla + mcBlocks.addAll(BlockStateUtils.getAllVanillaBlockStates(blockType)); + } else { + mcBlocks.add(BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(blockStateStr))); + } + } else { + // custom maybe + customBlocks.add(blockStateStr); + } + } + return new Tuple<>(mcTags, mcBlocks, customBlocks); + } + + protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { int y = Reflections.field$Vec3i$y.getInt(blockPos); int x = Reflections.field$Vec3i$x.getInt(blockPos); int z = Reflections.field$Vec3i$z.getInt(blockPos); @@ -104,11 +129,28 @@ public class BushBlockBehavior extends AbstractBlockBehavior { } protected boolean mayPlaceOn(Object belowState, Object world, Object belowPos) throws ReflectiveOperationException { + if (this.any) return true; for (Object tag : this.tagsCanSurviveOn) { if ((boolean) Reflections.method$BlockStateBase$hasTag.invoke(belowState, tag)) { return true; } } + int id = BlockStateUtils.blockStateToId(belowState); + if (BlockStateUtils.isVanillaBlock(id)) { + if (!this.blocksCansSurviveOn.isEmpty() && this.blocksCansSurviveOn.contains(belowState)) { + return true; + } + } else { + ImmutableBlockState previousState = BukkitBlockManager.instance().getImmutableBlockState(id); + if (previousState != null && !previousState.isEmpty()) { + if (this.customBlocksCansSurviveOn.contains(previousState.owner().value().id().toString())) { + return true; + } + if (this.customBlocksCansSurviveOn.contains(previousState.toString())) { + return true; + } + } + } return false; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java new file mode 100644 index 000000000..034608fa6 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java @@ -0,0 +1,38 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.util.Tuple; +import net.momirealms.craftengine.shared.block.BlockBehavior; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class HangingBlockBehavior extends BushBlockBehavior { + public static final Factory FACTORY = new Factory(); + + public HangingBlockBehavior(List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + } + + @Override + protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { + int y = Reflections.field$Vec3i$y.getInt(blockPos); + int x = Reflections.field$Vec3i$x.getInt(blockPos); + int z = Reflections.field$Vec3i$z.getInt(blockPos); + Object belowPos = Reflections.constructor$BlockPos.newInstance(x, y + 1, z); + Object belowState = Reflections.method$BlockGetter$getBlockState.invoke(world, belowPos); + return mayPlaceOn(belowState, world, belowPos); + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Tuple, Set, Set> tuple = readTagsAndState(arguments); + return new HangingBlockBehavior(tuple.left(), tuple.mid(), tuple.right()); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java index 1aca9d2bf..cb5934a2e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/OnLiquidBlockBehavior.java @@ -9,14 +9,15 @@ import net.momirealms.craftengine.shared.block.BlockBehavior; import java.util.List; import java.util.Map; +import java.util.Set; public class OnLiquidBlockBehavior extends BushBlockBehavior { public static final Factory FACTORY = new Factory(); private final boolean onWater; private final boolean onLava; - public OnLiquidBlockBehavior(List tagsCanSurviveOn, boolean onWater, boolean onLava) { - super(tagsCanSurviveOn); + public OnLiquidBlockBehavior(boolean onWater, boolean onLava) { + super(List.of(), Set.of(), Set.of()); this.onWater = onWater; this.onLava = onLava; } @@ -33,7 +34,7 @@ public class OnLiquidBlockBehavior extends BushBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { List liquidTypes = MiscUtils.getAsStringList(arguments.getOrDefault("liquid-type", List.of("water"))); - return new OnLiquidBlockBehavior(List.of(), liquidTypes.contains("water"), liquidTypes.contains("lava")); + return new OnLiquidBlockBehavior(liquidTypes.contains("water"), liquidTypes.contains("lava")); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java index 2998fa762..3f17a7320 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java @@ -2,7 +2,10 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.util.*; +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.Reflections; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; @@ -12,6 +15,7 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.Tuple; import net.momirealms.craftengine.shared.block.BlockBehavior; import org.bukkit.Location; import org.bukkit.World; @@ -19,6 +23,7 @@ import org.bukkit.World; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import java.util.concurrent.Callable; public class SaplingBlockBehavior extends BushBlockBehavior { @@ -27,8 +32,8 @@ public class SaplingBlockBehavior extends BushBlockBehavior { private final Property stageProperty; private final double boneMealSuccessChance; - public SaplingBlockBehavior(Key feature, Property stageProperty, List tagsCanSurviveOn, double boneMealSuccessChance) { - super(tagsCanSurviveOn); + public SaplingBlockBehavior(Key feature, Property stageProperty, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, double boneMealSuccessChance) { + super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); this.feature = feature; this.stageProperty = stageProperty; this.boneMealSuccessChance = boneMealSuccessChance; @@ -121,13 +126,8 @@ public class SaplingBlockBehavior extends BushBlockBehavior { throw new IllegalArgumentException("stage property not set for sapling"); } double boneMealSuccessChance = MiscUtils.getAsDouble(arguments.getOrDefault("bone-meal-success-chance", 0.45)); - if (arguments.containsKey("bottom-block-tags")) { - return new SaplingBlockBehavior(Key.of(feature), stageProperty, MiscUtils.getAsStringList(arguments.get("bottom-block-tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList(), boneMealSuccessChance); - } else if (arguments.containsKey("tags")) { - return new SaplingBlockBehavior(Key.of(feature), stageProperty, MiscUtils.getAsStringList(arguments.get("tags")).stream().map(it -> BlockTags.getOrCreate(Key.of(it))).toList(), boneMealSuccessChance); - } else { - return new SaplingBlockBehavior(Key.of(feature), stageProperty, List.of(DIRT_TAG, FARMLAND), boneMealSuccessChance); - } + Tuple, Set, Set> tuple = readTagsAndState(arguments); + return new SaplingBlockBehavior(Key.of(feature), stageProperty, tuple.left(), tuple.mid(), tuple.right(), boneMealSuccessChance); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java new file mode 100644 index 000000000..615518c79 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java @@ -0,0 +1,11 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import java.util.List; +import java.util.Set; + +public class SugarCaneBlockBehavior extends BushBlockBehavior { + + public SugarCaneBlockBehavior(List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java index b477c47bc..9a47edb92 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java @@ -118,7 +118,7 @@ public class BukkitVanillaLootManager implements VanillaLootManager, Listener { VanillaLoot vanillaLoot = this.blockLoots.computeIfAbsent(BlockStateUtils.blockStateToId(blockState), k -> new VanillaLoot(VanillaLoot.Type.BLOCK)); vanillaLoot.addLootTable(lootTable); } else { - for (Object blockState : BlockStateUtils.getAllBlockStates(Key.of(target))) { + for (Object blockState : BlockStateUtils.getAllVanillaBlockStates(Key.of(target))) { if (blockState == Reflections.instance$Blocks$AIR$defaultState) { this.plugin.logger().warn(path, "Failed to load " + id + ". Invalid target " + target); return; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index f7fa9cddd..b3a773023 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -6,7 +6,6 @@ import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.network.impl.*; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java index 0cdb7db6e..52b298618 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockStateUtils.java @@ -1,18 +1,23 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.core.block.BlockStateParser; +import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.PushReaction; import net.momirealms.craftengine.core.util.Instrument; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MapColor; import net.momirealms.craftengine.core.world.BlockPos; +import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.event.block.BlockPhysicsEvent; import java.util.IdentityHashMap; import java.util.List; +import java.util.Optional; public class BlockStateUtils { public static final IdentityHashMap CLIENT_SIDE_NOTE_BLOCKS = new IdentityHashMap<>(); @@ -27,8 +32,36 @@ public class BlockStateUtils { hasInit = true; } - @SuppressWarnings("unchecked") + public static List getAllBlockStates(String blockState) { + int index = blockState.indexOf('['); + if (index == -1) { + return getAllBlockStates(Key.of(blockState)); + } else { + String blockTypeString = blockState.substring(0, index); + Key block = Key.of(blockTypeString); + Optional optionalCustomBlock = BukkitBlockManager.instance().getBlock(block); + if (optionalCustomBlock.isPresent()) { + ImmutableBlockState state = BlockStateParser.deserialize(blockState); + if (state == null) { + return List.of(); + } else { + return List.of(state.customBlockState().handle()); + } + } else { + BlockData blockData = Bukkit.createBlockData(blockState); + return List.of(blockDataToBlockState(blockData)); + } + } + } + public static List getAllBlockStates(Key block) { + Optional optionalCustomBlock = BukkitBlockManager.instance().getBlock(block); + return optionalCustomBlock.map(customBlock -> customBlock.variantProvider().states().stream().map(it -> it.customBlockState().handle()).toList()) + .orElseGet(() -> getAllVanillaBlockStates(block)); + } + + @SuppressWarnings("unchecked") + public static List getAllVanillaBlockStates(Key block) { try { Object blockIns = Reflections.method$Registry$get.invoke(Reflections.instance$BuiltInRegistries$BLOCK, Reflections.method$ResourceLocation$fromNamespaceAndPath.invoke(null, block.namespace(), block.value())); Object definition = Reflections.field$Block$StateDefinition.get(blockIns); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java index f2aa345f1..31e6f79e8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java @@ -3,8 +3,6 @@ package net.momirealms.craftengine.core.plugin.network; import io.netty.channel.Channel; import net.momirealms.craftengine.core.entity.player.Player; -import java.util.Collection; - public interface NetworkManager { String MOD_CHANNEL = "craftengine:payload"; From db55c6409c328978bc08af27619f5af398368c8e Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 28 Mar 2025 01:32:45 +0800 Subject: [PATCH 02/28] =?UTF-8?q?fix(network):=20=E9=80=82=E9=85=8D=20Pape?= =?UTF-8?q?r1.21.4-222=20=E7=89=88=E6=9C=AC=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/network/PacketConsumers.java | 11 ++++++++--- .../craftengine/bukkit/util/Reflections.java | 11 ++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index a220f5f1b..18e80d2dc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -909,9 +909,14 @@ public class PacketConsumers { Object id = Reflections.method$CustomPacketPayload$Type$id.invoke(type); String channel = id.toString(); if (!channel.equals(NetworkManager.MOD_CHANNEL)) return; - ByteBuf buf = (ByteBuf) Reflections.method$DiscardedPayload$data.invoke(payload); - byte[] data = new byte[buf.readableBytes()]; - buf.readBytes(data); + byte[] data; + if (Reflections.method$DiscardedPayload$data != null) { + ByteBuf buf = (ByteBuf) Reflections.method$DiscardedPayload$data.invoke(payload); + data = new byte[buf.readableBytes()]; + buf.readBytes(data); + } else { + data = (byte[]) Reflections.method$DiscardedPayload$dataByteArray.invoke(payload); + } String decodeData = new String(data, StandardCharsets.UTF_8); if (!decodeData.endsWith("init")) return; int firstColon = decodeData.indexOf(':'); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 672dc1922..3aba8d9d2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -5667,11 +5667,20 @@ public class Reflections { .map(it -> ReflectionUtils.getMethod(it, clazz$ResourceLocation)) .orElse(null); - // 1.20.5+ + // 1.20.5~1.21.4#221 public static final Method method$DiscardedPayload$data = Optional.ofNullable(clazz$DiscardedPayload) .map(it -> ReflectionUtils.getMethod(it, ByteBuf.class)) .orElse(null); + // 1.21.4#222+ + // 我tm服了这个 sb paper 你 tmd 乱改签名干什么有病啊 + public static final Method method$DiscardedPayload$dataByteArray = Optional.ofNullable(method$DiscardedPayload$data) + .map(m -> (Method) null) + .orElseGet(() -> Optional.ofNullable(clazz$DiscardedPayload) + .map(clazz -> ReflectionUtils.getMethod(clazz, byte[].class)) + .orElse(null) + ); + public static final Class clazz$ClientboundDisconnectPacket = requireNonNull( ReflectionUtils.getClazz( BukkitReflectionUtils.assembleMCClass("network.protocol.common.ClientboundDisconnectPacket"), From 2c648e46f82bffd93a7121347593088e5062ed0a Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 01:35:27 +0800 Subject: [PATCH 03/28] optimize nms --- .../bukkit/api/CraftEngineBlocks.java | 5 +- .../bukkit/block/BlockEventListener.java | 2 +- .../block/behavior/BushBlockBehavior.java | 13 ++--- .../behavior/ConcretePowderBlockBehavior.java | 7 +-- .../block/behavior/FallingBlockBehavior.java | 15 +++--- .../block/behavior/HangingBlockBehavior.java | 11 +++-- .../block/behavior/LeavesBlockBehavior.java | 5 +- .../block/behavior/SaplingBlockBehavior.java | 16 +++--- .../behavior/SugarCaneBlockBehavior.java | 45 ++++++++++++++++- .../item/behavior/BlockItemBehavior.java | 7 +-- .../LiquidCollisionBlockItemBehavior.java | 3 +- .../plugin/network/BukkitNetworkManager.java | 5 +- .../plugin/network/PacketConsumers.java | 19 +++---- .../plugin/user/BukkitServerPlayer.java | 9 ++-- .../craftengine/bukkit/util/EntityUtils.java | 9 ++-- .../bukkit/util/LocationUtils.java | 34 +++++-------- .../util/NoteBlockChainUpdateUtils.java | 3 +- .../craftengine/bukkit/util/Reflections.java | 49 ++++++++++--------- gradle.properties | 2 +- 19 files changed, 144 insertions(+), 115 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index cf8ef367f..ed4dc7d2e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.api; 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.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; @@ -108,9 +109,9 @@ public final class CraftEngineBlocks { boolean success; try { Object worldServer = Reflections.field$CraftWorld$ServerLevel.get(location.getWorld()); - Object blockPos = Reflections.constructor$BlockPos.newInstance(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); Object blockState = block.customBlockState().handle(); - Object oldBlockState = Reflections.method$BlockGetter$getBlockState.invoke(worldServer, blockPos); + Object oldBlockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(worldServer, blockPos); success = (boolean) Reflections.method$LevelWriter$setBlock.invoke(worldServer, blockPos, blockState, option.flags()); if (success) { Reflections.method$BlockStateBase$onPlace.invoke(blockState, worldServer, blockPos, oldBlockState, true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index d41a97e73..befb9a1e2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -318,7 +318,7 @@ public class BlockEventListener implements Listener { if (direction == BlockFace.UP || direction == BlockFace.DOWN) { Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(world); Object chunkSource = Reflections.field$ServerLevel$chunkSource.get(serverLevel); - Object blockPos = Reflections.constructor$BlockPos.newInstance(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + Object blockPos = LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); Reflections.method$ServerChunkCache$blockChanged.invoke(chunkSource, blockPos); if (direction == BlockFace.UP) { NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, Reflections.instance$Direction$UP, blockPos, 0); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index 19fa6e522..9ce8d502e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -1,6 +1,7 @@ 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.BlockTags; import net.momirealms.craftengine.bukkit.util.LocationUtils; @@ -64,7 +65,7 @@ public class BushBlockBehavior extends AbstractBlockBehavior { ContextHolder.Builder builder = ContextHolder.builder(); BlockPos pos = LocationUtils.fromBlockPos(blockPos); Vec3d vec3d = Vec3d.atCenterOf(pos); - net.momirealms.craftengine.core.world.World world = new BukkitWorld((World) Reflections.method$Level$getCraftWorld.invoke(level)); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.WORLD, world); for (Item item : previousState.getDrops(builder, world)) { @@ -120,11 +121,11 @@ public class BushBlockBehavior extends AbstractBlockBehavior { } protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { - int y = Reflections.field$Vec3i$y.getInt(blockPos); - int x = Reflections.field$Vec3i$x.getInt(blockPos); - int z = Reflections.field$Vec3i$z.getInt(blockPos); - Object belowPos = Reflections.constructor$BlockPos.newInstance(x, y - 1, z); - Object belowState = Reflections.method$BlockGetter$getBlockState.invoke(world, belowPos); + int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos); + int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); + int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); + Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y - 1, z); + Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos); return mayPlaceOn(belowState, world, belowPos); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java index 801e8605a..3df82844d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ConcretePowderBlockBehavior.java @@ -1,6 +1,7 @@ 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.EventUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; @@ -65,7 +66,7 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior { Object level = context.getLevel().serverWorld(); Object blockPos = LocationUtils.toBlockPos(context.getClickedPos()); try { - Object previousState = Reflections.method$BlockGetter$getBlockState.invoke(level, blockPos); + Object previousState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos); if (!shouldSolidify(level, blockPos, previousState)) { return super.updateStateForPlacement(context, state); } else { @@ -137,10 +138,10 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior { int j = Direction.values().length; for (int k = 0; k < j; k++) { Object direction = Reflections.instance$Directions[k]; - Object blockState = Reflections.method$BlockGetter$getBlockState.invoke(level, mutablePos); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, mutablePos); if (direction != Reflections.instance$Direction$DOWN || canSolidify(blockState)) { Reflections.method$MutableBlockPos$setWithOffset.invoke(mutablePos, pos, direction); - blockState = Reflections.method$BlockGetter$getBlockState.invoke(level, mutablePos); + blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, mutablePos); if (canSolidify(blockState) && !(boolean) Reflections.method$BlockStateBase$isFaceSturdy.invoke(blockState, level, pos, Reflections.getOppositeDirection(direction), Reflections.instance$SupportType$FULL)) { flag = true; break; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java index 9517544c6..6fbe0caa4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java @@ -1,6 +1,7 @@ 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.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; @@ -56,17 +57,17 @@ public class FallingBlockBehavior extends AbstractBlockBehavior { @Override public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { Object blockPos = args[2]; - int y = Reflections.field$Vec3i$y.getInt(blockPos); + int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos); Object world = args[1]; Object dimension = Reflections.method$$LevelReader$dimensionType.invoke(world); int minY = Reflections.field$DimensionType$minY.getInt(dimension); if (y < minY) { return; } - int x = Reflections.field$Vec3i$x.getInt(blockPos); - int z = Reflections.field$Vec3i$z.getInt(blockPos); - Object belowPos = Reflections.constructor$BlockPos.newInstance(x, y - 1, z); - Object belowState = Reflections.method$BlockGetter$getBlockState.invoke(world, belowPos); + int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); + int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); + Object belowPos = LocationUtils.toBlockPos(x, y - 1, z); + Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos); boolean isFree = (boolean) Reflections.method$FallingBlock$isFree.invoke(null, belowState); if (!isFree) { return; @@ -96,7 +97,7 @@ public class FallingBlockBehavior extends AbstractBlockBehavior { double y = Reflections.field$Entity$yo.getDouble(fallingBlockEntity); double z = Reflections.field$Entity$zo.getDouble(fallingBlockEntity); Vec3d vec3d = new Vec3d(x, y, z); - net.momirealms.craftengine.core.world.World world = new BukkitWorld((World) Reflections.method$Level$getCraftWorld.invoke(level)); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.WORLD, world); for (Item item : immutableBlockState.getDrops(builder, world)) { @@ -121,7 +122,7 @@ public class FallingBlockBehavior extends AbstractBlockBehavior { if (immutableBlockState == null || immutableBlockState.isEmpty()) return; Object level = args[0]; Object pos = args[1]; - net.momirealms.craftengine.core.world.World world = new BukkitWorld((World) Reflections.method$Level$getCraftWorld.invoke(level)); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); world.playBlockSound(Vec3d.atCenterOf(LocationUtils.fromBlockPos(pos)), immutableBlockState.sounds().landSound()); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java index 034608fa6..aa35a9777 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.block.behavior; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; @@ -19,11 +20,11 @@ public class HangingBlockBehavior extends BushBlockBehavior { @Override protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { - int y = Reflections.field$Vec3i$y.getInt(blockPos); - int x = Reflections.field$Vec3i$x.getInt(blockPos); - int z = Reflections.field$Vec3i$z.getInt(blockPos); - Object belowPos = Reflections.constructor$BlockPos.newInstance(x, y + 1, z); - Object belowState = Reflections.method$BlockGetter$getBlockState.invoke(world, belowPos); + int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos); + int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); + int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); + Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y + 1, z); + Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos); return mayPlaceOn(belowState, world, belowPos); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java index 34dd0d031..d454b2c1b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/LeavesBlockBehavior.java @@ -1,6 +1,7 @@ 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.BlockTags; import net.momirealms.craftengine.bukkit.util.LocationUtils; @@ -108,7 +109,7 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { Object blockPos = args[2]; ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(args[0])); if (immutableBlockState != null && immutableBlockState.behavior() instanceof LeavesBlockBehavior behavior && behavior.isDecaying(immutableBlockState)) { - World bukkitWorld = (World) Reflections.method$Level$getCraftWorld.invoke(level); + World bukkitWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(level); BlockPos pos = LocationUtils.fromBlockPos(blockPos); // call bukkit event LeavesDecayEvent event = new LeavesDecayEvent(bukkitWorld.getBlockAt(pos.x(), pos.y(), pos.z())); @@ -142,7 +143,7 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { for (int k = 0; k < j; ++k) { Object direction = Reflections.instance$Directions[k]; Reflections.method$MutableBlockPos$setWithOffset.invoke(mutablePos, blockPos, direction); - Object blockState = Reflections.method$BlockGetter$getBlockState.invoke(world, mutablePos); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, mutablePos); i = Math.min(i, getDistanceAt(blockState) + 1); if (i == 1) { break; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java index 3f17a7320..2db55684c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; 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.FeatureUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; @@ -48,10 +49,7 @@ public class SaplingBlockBehavior extends BushBlockBehavior { Object world = args[1]; Object blockPos = args[2]; Object blockState = args[0]; - int x = (int) Reflections.field$Vec3i$x.get(blockPos); - int y = (int) Reflections.field$Vec3i$y.get(blockPos); - int z = (int) Reflections.field$Vec3i$z.get(blockPos); - Object aboveBlockPos = LocationUtils.toBlockPos(x, y + 1, z); + Object aboveBlockPos = LocationUtils.above(blockPos); if ((int) Reflections.method$LevelReader$getMaxLocalRawBrightness.invoke(world, aboveBlockPos) >= 9 && (float) Reflections.method$RandomSource$nextFloat.invoke(args[3]) < (1.0f / 7.0f)) { increaseStage(world, blockPos, blockState, args[3]); } @@ -63,10 +61,10 @@ public class SaplingBlockBehavior extends BushBlockBehavior { int currentStage = immutableBlockState.get(this.stageProperty); if (currentStage != this.stageProperty.possibleValues().get(this.stageProperty.possibleValues().size() - 1)) { ImmutableBlockState nextStage = immutableBlockState.cycle(this.stageProperty); - World bukkitWorld = (World) Reflections.method$Level$getCraftWorld.invoke(world); - int x = (int) Reflections.field$Vec3i$x.get(blockPos); - int y = (int) Reflections.field$Vec3i$y.get(blockPos); - int z = (int) Reflections.field$Vec3i$z.get(blockPos); + World bukkitWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(world); + int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); + int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos); + int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); CraftEngineBlocks.place(new Location(bukkitWorld, x, y, z), nextStage, UpdateOption.UPDATE_NONE, false); } else { generateTree(world, blockPos, blockState, randomSource); @@ -88,7 +86,7 @@ public class SaplingBlockBehavior extends BushBlockBehavior { Object legacyState = Reflections.method$FluidState$createLegacyBlock.invoke(fluidState); Reflections.method$Level$setBlock.invoke(world, blockPos, legacyState, UpdateOption.UPDATE_NONE.flags()); if ((boolean) Reflections.method$ConfiguredFeature$place.invoke(configuredFeature, world, chunkGenerator, randomSource, blockPos)) { - if (Reflections.method$BlockGetter$getBlockState.invoke(world, blockPos) == legacyState) { + if (FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, blockPos) == legacyState) { Reflections.method$ServerLevel$sendBlockUpdated.invoke(world, blockPos, blockState, legacyState, 2); } } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java index 615518c79..ff82948d4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java @@ -1,11 +1,54 @@ 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.LocationUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.bukkit.world.BukkitWorld; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.UpdateOption; +import net.momirealms.craftengine.core.block.properties.IntegerProperty; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.util.context.ContextHolder; +import net.momirealms.craftengine.core.world.Vec3d; +import org.bukkit.Material; + import java.util.List; import java.util.Set; +import java.util.concurrent.Callable; public class SugarCaneBlockBehavior extends BushBlockBehavior { + private final int maxHeight; + private final boolean nearWater; + private final boolean nearLava; + private final IntegerProperty age; - public SugarCaneBlockBehavior(List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + public SugarCaneBlockBehavior(List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, IntegerProperty age, int maxHeight, boolean nearWater, boolean nearLava) { super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + this.nearWater = nearWater; + this.nearLava = nearLava; + this.maxHeight = maxHeight; + this.age = age; + } + + @Override + public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object blockState = args[0]; + Object level = args[1]; + Object blockPos = args[2]; + ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + if (currentState != null && !currentState.isEmpty()) { + Reflections.method$Level$removeBlock.invoke(level, blockPos, false); + Vec3d vec3d = Vec3d.atCenterOf(LocationUtils.fromBlockPos(blockPos)); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(LootParameters.LOCATION, vec3d) + .withParameter(LootParameters.WORLD, world); + for (Item item : currentState.getDrops(builder, world)) { + world.dropItemNaturally(vec3d, item); + } + } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index 312486736..fbc4d03fe 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -147,12 +147,7 @@ public class BlockItemBehavior extends ItemBehavior { protected boolean canPlace(BlockPlaceContext context, ImmutableBlockState state) { try { - Object player; - try { - player = Reflections.method$CraftPlayer$getHandle.invoke(context.getPlayer().platformPlayer()); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException("Failed to get server player", e); - } + Object player = context.getPlayer().serverPlayer(); Object blockState = state.customBlockState().handle(); Object blockPos = LocationUtils.toBlockPos(context.getClickedPos()); Object voxelShape = Reflections.method$CollisionContext$of.invoke(null, player); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java index 194a1bbba..1163a1ab8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.item.behavior; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.entity.player.InteractionHand; @@ -41,7 +42,7 @@ public class LiquidCollisionBlockItemBehavior extends BlockItemBehavior { try { Object blockHitResult = Reflections.method$Item$getPlayerPOVHitResult.invoke(null, world.serverWorld(), player.serverPlayer(), Reflections.instance$ClipContext$Fluid$SOURCE_ONLY); Object blockPos = Reflections.field$BlockHitResul$blockPos.get(blockHitResult); - BlockPos above = new BlockPos(Reflections.field$Vec3i$x.getInt(blockPos), Reflections.field$Vec3i$y.getInt(blockPos) + offsetY, Reflections.field$Vec3i$z.getInt(blockPos)); + BlockPos above = new BlockPos(FastNMS.INSTANCE.field$Vec3i$x(blockPos), FastNMS.INSTANCE.field$Vec3i$y(blockPos) + offsetY, FastNMS.INSTANCE.field$Vec3i$z(blockPos)); Direction direction = Direction.values()[(int) Reflections.method$Direction$ordinal.invoke(Reflections.field$BlockHitResul$direction.get(blockHitResult))]; boolean miss = Reflections.field$BlockHitResul$miss.getBoolean(blockHitResult); Vec3d hitPos = LocationUtils.fromVec(Reflections.field$HitResult$location.get(blockHitResult)); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index b3a773023..638405a24 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -6,6 +6,7 @@ import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.network.impl.*; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; @@ -253,7 +254,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes return (Channel) Reflections.field$Channel.get( Reflections.field$NetworkManager.get( Reflections.field$ServerPlayer$connection.get( - Reflections.method$CraftPlayer$getHandle.invoke(player) + FastNMS.INSTANCE.method$CraftPlayer$getHandle(player) ) ) ); @@ -264,7 +265,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes public void sendPacket(@NotNull Player player, @NotNull Object packet) { try { - Object serverPlayer = Reflections.method$CraftPlayer$getHandle.invoke(player); + Object serverPlayer = FastNMS.INSTANCE.method$CraftPlayer$getHandle(player); this.immediatePacketConsumer.accept(serverPlayer, packet); } catch (Exception e) { this.plugin.logger().warn("Failed to send packet", e); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java index a220f5f1b..cceb6c1fa 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java @@ -11,6 +11,7 @@ import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.entity.furniture.LoadedFurniture; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; @@ -268,11 +269,7 @@ public class PacketConsumers { Player platformPlayer = player.platformPlayer(); World world = platformPlayer.getWorld(); Object blockPos = Reflections.field$ServerboundPlayerActionPacket$pos.get(packet); - BlockPos pos = new BlockPos( - (int) Reflections.field$Vec3i$x.get(blockPos), - (int) Reflections.field$Vec3i$y.get(blockPos), - (int) Reflections.field$Vec3i$z.get(blockPos) - ); + BlockPos pos = LocationUtils.fromBlockPos(blockPos); if (VersionHelper.isFolia()) { BukkitCraftEngine.instance().scheduler().sync().run(() -> { try { @@ -293,7 +290,7 @@ public class PacketConsumers { Object action = Reflections.field$ServerboundPlayerActionPacket$action.get(packet); if (action == Reflections.instance$ServerboundPlayerActionPacket$Action$START_DESTROY_BLOCK) { Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(world); - Object blockState = Reflections.method$BlockGetter$getBlockState.invoke(serverLevel, LocationUtils.toBlockPos(pos)); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, LocationUtils.toBlockPos(pos)); int stateId = BlockStateUtils.blockStateToId(blockState); // not a custom block if (BlockStateUtils.isVanillaBlock(stateId)) { @@ -311,7 +308,7 @@ public class PacketConsumers { } if (player.isAdventureMode()) { Object itemStack = Reflections.method$CraftItemStack$asNMSCopy.invoke(null, player.platformPlayer().getInventory().getItemInMainHand()); - Object blockPos = Reflections.constructor$BlockPos.newInstance(pos.x(), pos.y(), pos.z()); + Object blockPos = LocationUtils.toBlockPos(pos); Object blockInWorld = Reflections.constructor$BlockInWorld.newInstance(serverLevel, blockPos, false); if (VersionHelper.isVersionNewerThan1_20_5()) { if (Reflections.method$ItemStack$canBreakBlockInAdventureMode != null @@ -523,8 +520,8 @@ public class PacketConsumers { if (player == null) return; Object pos = Reflections.field$ServerboundPickItemFromBlockPacket$pos.get(packet); if (VersionHelper.isFolia()) { - int x = (int) Reflections.field$Vec3i$x.get(pos); - int z = (int) Reflections.field$Vec3i$z.get(pos); + int x = FastNMS.INSTANCE.field$Vec3i$x(pos); + int z = FastNMS.INSTANCE.field$Vec3i$z(pos); BukkitCraftEngine.instance().scheduler().sync().run(() -> { try { handlePickItemFromBlockPacketOnMainThread(player, pos); @@ -548,7 +545,7 @@ public class PacketConsumers { private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Exception { Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(player.getWorld()); - Object blockState = Reflections.method$BlockGetter$getBlockState.invoke(serverLevel, pos); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, pos); ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); if (state == null) return; Key itemId = state.settings().itemId(); @@ -603,7 +600,7 @@ public class PacketConsumers { } assert Reflections.method$ServerGamePacketListenerImpl$tryPickItem != null; Reflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( - Reflections.field$ServerPlayer$connection.get(Reflections.method$CraftPlayer$getHandle.invoke(player)), Reflections.method$CraftItemStack$asNMSCopy.invoke(null, itemStack)); + Reflections.field$ServerPlayer$connection.get(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), Reflections.method$CraftItemStack$asNMSCopy.invoke(null, itemStack)); } public static final TriConsumer ADD_ENTITY = (user, event, packet) -> { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 3fb0627e6..030a31379 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -4,6 +4,7 @@ import com.google.common.collect.Lists; import io.netty.channel.Channel; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.world.BukkitWorld; @@ -75,11 +76,7 @@ public class BukkitServerPlayer extends Player { public void setPlayer(org.bukkit.entity.Player player) { playerRef = new WeakReference<>(player); - try { - serverPlayerRef = new WeakReference<>(Reflections.method$CraftPlayer$getHandle.invoke(player)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } + serverPlayerRef = new WeakReference<>(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)); } @Override @@ -298,7 +295,7 @@ public class BukkitServerPlayer extends Player { public float getDestroyProgress(Object blockState, BlockPos pos) { try { Object serverPlayer = serverPlayer(); - Object blockPos = Reflections.constructor$BlockPos.newInstance(pos.x(), pos.y(), pos.z()); + Object blockPos = LocationUtils.toBlockPos(pos.x(), pos.y(), pos.z()); return (float) Reflections.method$BlockStateBase$getDestroyProgress.invoke(blockState, serverPlayer, Reflections.method$Entity$level.invoke(serverPlayer), blockPos); } catch (ReflectiveOperationException e) { this.plugin.logger().warn("Failed to get destroy progress for player " + platformPlayer().getName()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java index cb44a126b..c5fe84760 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.Location; import org.bukkit.World; @@ -14,13 +15,9 @@ public class EntityUtils { public static BlockPos getOnPos(Player player) { try { - Object serverPlayer = Reflections.method$CraftPlayer$getHandle.invoke(player); + Object serverPlayer = FastNMS.INSTANCE.method$CraftPlayer$getHandle(player); Object blockPos = Reflections.method$Entity$getOnPos.invoke(serverPlayer, 1.0E-5F); - return new BlockPos( - (int) Reflections.field$Vec3i$x.get(blockPos), - (int) Reflections.field$Vec3i$y.get(blockPos), - (int) Reflections.field$Vec3i$z.get(blockPos) - ); + return LocationUtils.fromBlockPos(blockPos); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java index b960901d0..01c719118 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LocationUtils.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import org.bukkit.Location; @@ -13,48 +14,39 @@ public class LocationUtils { return new Vec3d(loc.getX(), loc.getY(), loc.getZ()); } - public static Vec3d fromVec(Object vec) throws ReflectiveOperationException { + public static Vec3d fromVec(Object vec) { return new Vec3d( - Reflections.field$Vec3$x.getDouble(vec), - Reflections.field$Vec3$y.getDouble(vec), - Reflections.field$Vec3$z.getDouble(vec) + FastNMS.INSTANCE.field$Vec3$x(vec), + FastNMS.INSTANCE.field$Vec3$y(vec), + FastNMS.INSTANCE.field$Vec3$y(vec) ); } public static Object toBlockPos(BlockPos pos) { - try { - return Reflections.constructor$BlockPos.newInstance(pos.x(), pos.y(), pos.z()); - } catch (ReflectiveOperationException e) { - throw new RuntimeException("Failed to create BlockPos", e); - } + return toBlockPos(pos.x(), pos.y(), pos.z()); } public static Object above(Object blockPos) throws ReflectiveOperationException { return toBlockPos( - Reflections.field$Vec3i$x.getInt(blockPos), - Reflections.field$Vec3i$y.getInt(blockPos) + 1, - Reflections.field$Vec3i$z.getInt(blockPos) + FastNMS.INSTANCE.field$Vec3i$x(blockPos), + FastNMS.INSTANCE.field$Vec3i$y(blockPos) + 1, + FastNMS.INSTANCE.field$Vec3i$z(blockPos) ); } public static Object toBlockPos(int x, int y, int z) { - try { - return Reflections.constructor$BlockPos.newInstance(x, y, z); - } catch (ReflectiveOperationException e) { - throw new RuntimeException("Failed to create BlockPos", e); - } + return FastNMS.INSTANCE.constructor$BlockPos(x, y, z); } - public static BlockPos toBlockPos(Location pos) { return new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()); } public static BlockPos fromBlockPos(Object pos) throws ReflectiveOperationException { return new BlockPos( - Reflections.field$Vec3i$x.getInt(pos), - Reflections.field$Vec3i$y.getInt(pos), - Reflections.field$Vec3i$z.getInt(pos) + FastNMS.INSTANCE.field$Vec3i$x(pos), + FastNMS.INSTANCE.field$Vec3i$y(pos), + FastNMS.INSTANCE.field$Vec3i$z(pos) ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java index badab57bf..5b4f28f4a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.plugin.config.ConfigManager; public class NoteBlockChainUpdateUtils { @@ -9,7 +10,7 @@ public class NoteBlockChainUpdateUtils { public static void noteBlockChainUpdate(Object level, Object chunkSource, Object direction, Object blockPos, int times) throws ReflectiveOperationException { if (times >= ConfigManager.maxChainUpdate()) return; Object relativePos = Reflections.method$BlockPos$relative.invoke(blockPos, direction); - Object state = Reflections.method$BlockGetter$getBlockState.invoke(level, relativePos); + Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, relativePos); if (BlockStateUtils.isClientSideNoteBlock(state)) { Reflections.method$ServerChunkCache$blockChanged.invoke(chunkSource, relativePos); noteBlockChainUpdate(level, chunkSource, direction, relativePos, times+1); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 672dc1922..be56d9e0a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -471,9 +471,9 @@ public class Reflections { BukkitReflectionUtils.assembleCBClass("entity.CraftPlayer") )); - public static final Method method$CraftPlayer$getHandle = requireNonNull( - ReflectionUtils.getMethod(clazz$CraftPlayer, new String[] { "getHandle" }) - ); +// public static final Method method$CraftPlayer$getHandle = requireNonNull( +// ReflectionUtils.getMethod(clazz$CraftPlayer, new String[] { "getHandle" }) +// ); public static final Field field$ServerPlayer$connection = requireNonNull( ReflectionUtils.getInstanceDeclaredField(clazz$ServerPlayer, clazz$ServerGamePacketListenerImpl, 0) @@ -1355,17 +1355,17 @@ public class Reflections { ) ); - public static final Field field$Vec3i$x = requireNonNull( - ReflectionUtils.getDeclaredField(clazz$Vec3i, int.class, 0) - ); - - public static final Field field$Vec3i$y = requireNonNull( - ReflectionUtils.getDeclaredField(clazz$Vec3i, int.class, 1) - ); - - public static final Field field$Vec3i$z = requireNonNull( - ReflectionUtils.getDeclaredField(clazz$Vec3i, int.class, 2) - ); +// public static final Field field$Vec3i$x = requireNonNull( +// ReflectionUtils.getDeclaredField(clazz$Vec3i, int.class, 0) +// ); +// +// public static final Field field$Vec3i$y = requireNonNull( +// ReflectionUtils.getDeclaredField(clazz$Vec3i, int.class, 1) +// ); +// +// public static final Field field$Vec3i$z = requireNonNull( +// ReflectionUtils.getDeclaredField(clazz$Vec3i, int.class, 2) +// ); public static final Class clazz$BlockState = requireNonNull( ReflectionUtils.getClazz( @@ -1588,11 +1588,11 @@ public class Reflections { ) ); - public static final Constructor constructor$BlockPos = requireNonNull( - ReflectionUtils.getConstructor( - clazz$BlockPos, int.class, int.class, int.class - ) - ); +// public static final Constructor constructor$BlockPos = requireNonNull( +// ReflectionUtils.getConstructor( +// clazz$BlockPos, int.class, int.class, int.class +// ) +// ); public static final Method method$Vec3i$relative = requireNonNull( ReflectionUtils.getMethod( @@ -2462,11 +2462,11 @@ public class Reflections { ) ); - public static final Method method$BlockGetter$getBlockState = requireNonNull( - ReflectionUtils.getMethod( - clazz$BlockGetter, clazz$BlockState, clazz$BlockPos - ) - ); +// public static final Method method$BlockGetter$getBlockState = requireNonNull( +// ReflectionUtils.getMethod( +// clazz$BlockGetter, clazz$BlockState, clazz$BlockPos +// ) +// ); public static final Method method$LevelAccessor$scheduleTick = requireNonNull( ReflectionUtils.getMethod( @@ -3407,6 +3407,7 @@ public class Reflections { ) ); + @Deprecated public static final Method method$Level$getCraftWorld = requireNonNull( ReflectionUtils.getMethod( clazz$Level, clazz$CraftWorld diff --git a/gradle.properties b/gradle.properties index dd0543dbb..1e9902df2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -49,7 +49,7 @@ mojang_brigadier_version=1.0.18 byte_buddy_version=1.15.11 snake_yaml_version=2.3 anti_grief_version=0.13 -nms_helper_version=0.6 +nms_helper_version=0.10 # Ignite Dependencies mixinextras_version=0.4.1 mixin_version=0.15.2+mixin.0.8.7 From 1f7fb926d2373025c7280546156781de0c984750 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 03:25:30 +0800 Subject: [PATCH 04/28] add sugarcane block --- .../main/resources/additional-real-blocks.yml | 6 +- .../default/configuration/categories.yml | 1 + .../resources/default/configuration/i18n.yml | 2 + .../default/configuration/plants.yml | 106 +++++++++- .../textures/block/custom/flame_cane_1.png | Bin 0 -> 290 bytes .../textures/block/custom/flame_cane_2.png | Bin 0 -> 293 bytes .../textures/item/custom/flame_cane.png | Bin 0 -> 267 bytes .../block/behavior/BukkitBlockBehaviors.java | 2 + .../block/behavior/SaplingBlockBehavior.java | 9 +- .../behavior/SugarCaneBlockBehavior.java | 186 ++++++++++++++++-- .../craftengine/bukkit/util/Reflections.java | 6 + .../core/pack/AbstractPackManager.java | 3 + gradle.properties | 2 +- 13 files changed, 300 insertions(+), 23 deletions(-) create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_1.png create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_2.png create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/flame_cane.png diff --git a/bukkit/loader/src/main/resources/additional-real-blocks.yml b/bukkit/loader/src/main/resources/additional-real-blocks.yml index 91993a87d..4fe5d6d61 100644 --- a/bukkit/loader/src/main/resources/additional-real-blocks.yml +++ b/bukkit/loader/src/main/resources/additional-real-blocks.yml @@ -14,9 +14,7 @@ # Q: When do I need to configure this file? # A: When the number of real block IDs is insufficient, but there are still available appearances. -# By default, the plugin only registers an additional 112 oak leaf block states (for the default configuration needs [>=28 states]). minecraft:oak_leaves: 112 - minecraft:oak_sapling: 1 minecraft:birch_sapling: 1 minecraft:spruce_sapling: 1 @@ -24,5 +22,5 @@ minecraft:jungle_sapling: 1 minecraft:dark_oak_sapling: 1 minecraft:acacia_sapling: 1 minecraft:cherry_sapling: 1 - -minecraft:anvil: 2 \ No newline at end of file +minecraft:anvil: 2 +minecraft:sugarcane: 14 \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml index 7df2d92c5..e99de8717 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml @@ -59,5 +59,6 @@ categories: - default:netherite_anvil - default:fairy_flower - default:reed + - default:flame_cane - default:gunpowder_block - default:solid_gunpowder_block \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml index c3ad09c0a..dc46c4640 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml @@ -3,6 +3,7 @@ i18n: item.chinese_lantern: "Chinese Lantern" item.fairy_flower: "Fairy Flower" item.reed: "Reed" + item.flame_cane: "Flame Cane" item.bench: "Bench" item.table_lamp: "Table Lamp" item.wooden_chair: "Wooden Chair" @@ -41,6 +42,7 @@ i18n: item.chinese_lantern: "灯笼" item.fairy_flower: "仙灵花" item.reed: "芦苇" + item.flame_cane: "烈焰甘蔗" item.bench: "长椅" item.table_lamp: "台灯" item.wooden_chair: "木椅" diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 8016ddf9c..172600da7 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -23,6 +23,18 @@ items: behavior: type: liquid_collision_block_item block: default:reed + default:flame_cane: + material: paper + custom-model-data: 4002 + data: + item-name: "" + model: + template: default:model/simplified_generated + arguments: + path: "minecraft:item/custom/flame_cane" + behavior: + type: block_item + block: default:flame_cane blocks: default:fairy_flower: settings: @@ -32,6 +44,7 @@ blocks: overrides: item: default:fairy_flower push-reaction: DESTROY + map-color: 19 behavior: type: bush_block bottom-block-tags: @@ -73,6 +86,7 @@ blocks: overrides: item: default:reed push-reaction: DESTROY + map-color: 60 behavior: type: on_liquid_block liquid-type: water @@ -85,6 +99,74 @@ blocks: state: sugar_cane:1 model: path: "minecraft:block/custom/reed" + default:flame_cane: + settings: + template: + - default:hardness/none + - default:sound/grass + overrides: + item: default:flame_cane + push-reaction: DESTROY + map-color: 15 + is-randomly-ticking: true + behavior: + type: sugar_cane_block + max-height: 4 + required-adjacent-liquids: lava + grow-speed: 0.333 + bottom-blocks: + - minecraft:netherrack + - minecraft:soul_sand + - minecraft:soul_soil + - minecraft:magma_block + - minecraft:warped_nylium + - minecraft:crimson_nylium + - minecraft:basalt + loot: + template: "default:loot_table/basic" + arguments: + item: default:flame_cane + states: + properties: + age: + type: int + default: 0 + range: 0~5 + appearances: + default: + state: "sugar_cane:2" + models: + - path: "minecraft:block/custom/flame_cane_1" + weight: 1 + generation: + parent: "minecraft:block/sugar_cane" + textures: + "cross": "minecraft:block/custom/flame_cane_1" + - path: "minecraft:block/custom/flame_cane_2" + weight: 1 + generation: + parent: "minecraft:block/sugar_cane" + textures: + "cross": "minecraft:block/custom/flame_cane_2" + variants: + age=0: + appearance: default + id: 2 + age=1: + appearance: default + id: 3 + age=2: + appearance: default + id: 4 + age=3: + appearance: default + id: 5 + age=4: + appearance: default + id: 6 + age=5: + appearance: default + id: 7 recipes: default:paper_from_reed: type: shaped @@ -94,4 +176,26 @@ recipes: A: "default:reed" result: id: minecraft:paper - count: 3 \ No newline at end of file + count: 3 + default:magma_cream: + type: shaped + pattern: + - " A " + - "ABA" + - " A " + ingredients: + A: "default:flame_cane" + B: "minecraft:slime_ball" + result: + id: minecraft:magma_cream + count: 1 + default:magma_block: + type: shapeless + ingredients: + A1: "minecraft:cobblestone" + A2: "minecraft:cobblestone" + B1: "default:flame_cane" + B2: "default:flame_cane" + result: + id: minecraft:magma_block + count: 2 \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_1.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_1.png new file mode 100644 index 0000000000000000000000000000000000000000..98e0e595b3d4e1d094d96731f393f5aeecd27594 GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|?s&R5hFJ72 zoxG8^$w9*HzTh{5jmsA-C}B9vqw|1aQzy4X4`0F^MlP_Ue($HJdz5RkX5h^juf5e!y_YW|=|HC+4`|4fUI9UmhrA m5&xEIEa~<(`cpiA1N%CY(#KMt()xh@WbkzLb6Mw<&;$VE#c?$N literal 0 HcmV?d00001 diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_2.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_2.png new file mode 100644 index 0000000000000000000000000000000000000000..ba13d4c71100e98af47904a72d96e993fff9c328 GIT binary patch literal 293 zcmV+=0owkFP)Px#-$_J4R5*>LlCcegFc3wbE%smr3d&TeB4%KL43G>IA!PxUAVMza5lR^;D{v_= z$R-XD@haOo|NHiR07Oc;pAan4A=PEuUIRR?8SfX{iA&mMSZaXu4CxW1Ph{zy+=i}h z!^o>BjDMj|L}{bOy~)U|uj;oC$`|p~KPQmtcS>bm&@i1?NbgNKjx+aH241 z=@VJ9xP;14n!@bLL8Nk&bT(zRopoH&HW^^E@${$hI|tTQ)nqa`DhwR_8uw3Dr{FmZ r5X`|B&YQ`!9>4}9_9Z|95nxD+hVzKCv_q22A z`|Izw?VrHYc|vw&kcwQ8!@CZilQj`iOSEx>0^s?w4k1kJeSZ@kyEy3I-VaBpU_6;qw|_s5$Zm(PE&vx?zJ`D%aToFDN( P4>5SU`njxgN@xNAl%r;J literal 0 HcmV?d00001 diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index 9cf2a38b6..046911410 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -14,6 +14,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key ON_LIQUID_BLOCK = Key.from("craftengine:on_liquid_block"); public static final Key WATERLOGGED_BLOCK = Key.from("craftengine:waterlogged_block"); 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 void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -26,5 +27,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(ON_LIQUID_BLOCK, OnLiquidBlockBehavior.FACTORY); register(WATERLOGGED_BLOCK, WaterLoggedBlockBehavior.FACTORY); register(CONCRETE_POWDER_BLOCK, ConcretePowderBlockBehavior.FACTORY); + register(SUGARCANE_BLOCK, SugarCaneBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java index 2db55684c..7fb110cac 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java @@ -32,12 +32,14 @@ public class SaplingBlockBehavior extends BushBlockBehavior { private final Key feature; private final Property stageProperty; private final double boneMealSuccessChance; + private final float growSpeed; - public SaplingBlockBehavior(Key feature, Property stageProperty, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, double boneMealSuccessChance) { + public SaplingBlockBehavior(Key feature, Property stageProperty, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, double boneMealSuccessChance, float growSpeed) { super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); this.feature = feature; this.stageProperty = stageProperty; this.boneMealSuccessChance = boneMealSuccessChance; + this.growSpeed = growSpeed; } public Key treeFeature() { @@ -50,7 +52,7 @@ public class SaplingBlockBehavior extends BushBlockBehavior { Object blockPos = args[2]; Object blockState = args[0]; Object aboveBlockPos = LocationUtils.above(blockPos); - if ((int) Reflections.method$LevelReader$getMaxLocalRawBrightness.invoke(world, aboveBlockPos) >= 9 && (float) Reflections.method$RandomSource$nextFloat.invoke(args[3]) < (1.0f / 7.0f)) { + if ((int) Reflections.method$LevelReader$getMaxLocalRawBrightness.invoke(world, aboveBlockPos) >= 9 && (float) RandomUtils.generateRandomFloat(0, 1) < growSpeed) { increaseStage(world, blockPos, blockState, args[3]); } } @@ -125,7 +127,8 @@ public class SaplingBlockBehavior extends BushBlockBehavior { } double boneMealSuccessChance = MiscUtils.getAsDouble(arguments.getOrDefault("bone-meal-success-chance", 0.45)); Tuple, Set, Set> tuple = readTagsAndState(arguments); - return new SaplingBlockBehavior(Key.of(feature), stageProperty, tuple.left(), tuple.mid(), tuple.right(), boneMealSuccessChance); + return new SaplingBlockBehavior(Key.of(feature), stageProperty, tuple.left(), tuple.mid(), tuple.right(), boneMealSuccessChance, + MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 1.0 / 7.0))); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java index ff82948d4..04ce54160 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java @@ -1,36 +1,55 @@ package net.momirealms.craftengine.bukkit.block.behavior; +import com.sk89q.worldedit.blocks.Blocks; 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.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.world.BukkitWorld; +import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.IntegerProperty; +import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.Tuple; +import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.util.context.ContextHolder; +import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; -import org.bukkit.Material; +import net.momirealms.craftengine.shared.block.BlockBehavior; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; public class SugarCaneBlockBehavior extends BushBlockBehavior { + public static final Factory FACTORY = new Factory(); + private static final List WATER = List.of(Reflections.instance$Fluids$WATER, Reflections.instance$Fluids$FLOWING_WATER); + private static final List LAVA = List.of(Reflections.instance$Fluids$LAVA, Reflections.instance$Fluids$FLOWING_LAVA); + private static final List HORIZON_DIRECTIONS = List.of(Reflections.instance$Direction$NORTH, Reflections.instance$Direction$EAST, Reflections.instance$Direction$SOUTH, Reflections.instance$Direction$WEST); private final int maxHeight; private final boolean nearWater; private final boolean nearLava; - private final IntegerProperty age; + private final IntegerProperty ageProperty; + private final float growSpeed; + private final CustomBlock customBlock; - public SugarCaneBlockBehavior(List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, IntegerProperty age, int maxHeight, boolean nearWater, boolean nearLava) { + public SugarCaneBlockBehavior(CustomBlock customBlock, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, Property ageProperty, + int maxHeight, boolean nearWater, boolean nearLava, float growSpeed) { super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); this.nearWater = nearWater; this.nearLava = nearLava; this.maxHeight = maxHeight; - this.age = age; + this.ageProperty = (IntegerProperty) ageProperty; + this.growSpeed = growSpeed; + this.customBlock = customBlock; } @Override @@ -38,17 +57,156 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { Object blockState = args[0]; Object level = args[1]; Object blockPos = args[2]; - ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); - if (currentState != null && !currentState.isEmpty()) { - Reflections.method$Level$removeBlock.invoke(level, blockPos, false); - Vec3d vec3d = Vec3d.atCenterOf(LocationUtils.fromBlockPos(blockPos)); - net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); - ContextHolder.Builder builder = ContextHolder.builder() - .withParameter(LootParameters.LOCATION, vec3d) - .withParameter(LootParameters.WORLD, world); - for (Item item : currentState.getDrops(builder, world)) { - world.dropItemNaturally(vec3d, item); + if (!canSurvive(thisBlock, blockState, level, blockPos)) { + ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + if (currentState != null && !currentState.isEmpty()) { + // break the sugar cane + Reflections.method$Level$removeBlock.invoke(level, blockPos, false); + Vec3d vec3d = Vec3d.atCenterOf(LocationUtils.fromBlockPos(blockPos)); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); + // TODO client side particles? + ContextHolder.Builder builder = ContextHolder.builder() + .withParameter(LootParameters.LOCATION, vec3d) + .withParameter(LootParameters.WORLD, world); + for (Item item : currentState.getDrops(builder, world)) { + world.dropItemNaturally(vec3d, item); + } } } } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object world; + Object blockPos; + if (VersionHelper.isVersionNewerThan1_21_2()) { + world = args[1]; + blockPos = args[3]; + } else { + world = args[3]; + blockPos = args[4]; + } + Reflections.method$LevelAccessor$scheduleTick.invoke(world, blockPos, thisBlock, 1); + // return state, do not call super. + return superMethod.call(); + } + + @Override + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object blockState = args[0]; + Object level = args[1]; + Object blockPos = args[2]; + // above block is empty + if (FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, LocationUtils.above(blockPos)) == Reflections.instance$Blocks$AIR$defaultState) { + int currentHeight = 1; + BlockPos currentPos = LocationUtils.fromBlockPos(blockPos); + ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + if (currentState != null && !currentState.isEmpty()) { + while (true) { + Object belowPos = LocationUtils.toBlockPos(currentPos.x(), currentPos.y() - currentHeight, currentPos.z()); + Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, belowPos); + ImmutableBlockState belowImmutableState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(belowState)); + if (belowImmutableState != null && !belowImmutableState.isEmpty() && belowImmutableState.owner() == currentState.owner()) { + currentHeight++; + } else { + break; + } + } + } else { + return; + } + + if (currentHeight < this.maxHeight) { + int age = currentState.get(ageProperty); + if (age >= this.ageProperty.max || RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) { + Object abovePos = LocationUtils.above(blockPos); + Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, customBlock.defaultState().customBlockState().handle()); + Reflections.method$Level$setBlock.invoke(level, blockPos, currentState.with(this.ageProperty, this.ageProperty.min).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); + } else if (RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) { + Reflections.method$Level$setBlock.invoke(level, blockPos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); + } + } + } + } + + @Override + protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { + int y = FastNMS.INSTANCE.field$Vec3i$y(blockPos); + int x = FastNMS.INSTANCE.field$Vec3i$x(blockPos); + int z = FastNMS.INSTANCE.field$Vec3i$z(blockPos); + Object belowPos = FastNMS.INSTANCE.constructor$BlockPos(x, y - 1, z); + Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, belowPos); + int id = BlockStateUtils.blockStateToId(belowState); + // 如果下方是同种方块 + if (!BlockStateUtils.isVanillaBlock(id)) { + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id); + if (immutableBlockState.owner().value() == this.customBlock) { + return true; + } + } + if (!super.mayPlaceOn(belowState, world, belowPos)) { + return false; + } + // 如果不需要依靠流体 + if (!this.nearWater && !this.nearLava) { + return true; + } + // 需要流体 + if (this.nearWater) { + if (hasNearbyLiquid(world, belowPos, true)) { + return true; + } + } + if (this.nearLava) { + if (hasNearbyLiquid(world, belowPos, false)) { + return true; + } + } + return false; + } + + private boolean hasNearbyLiquid(Object world, Object blockPos, boolean waterOrLava) throws ReflectiveOperationException { + for (Object direction : HORIZON_DIRECTIONS) { + Object relativePos = Reflections.method$BlockPos$relative.invoke(blockPos, direction); + if (waterOrLava) { + // water + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, relativePos); + if (Reflections.method$BlockStateBase$getBlock.invoke(blockState) == Reflections.instance$Blocks$ICE) { + return true; + } + Object fluidState = Reflections.method$Level$getFluidState.invoke(world, relativePos); + Object fluidType = Reflections.method$FluidState$getType.invoke(fluidState); + if (WATER.contains(fluidType)) { + return true; + } + } else { + // lava + Object fluidState = Reflections.method$Level$getFluidState.invoke(world, relativePos); + Object fluidType = Reflections.method$FluidState$getType.invoke(fluidState); + if (LAVA.contains(fluidType)) { + return true; + } + } + } + return false; + } + + public static class Factory implements BlockBehaviorFactory { + + @SuppressWarnings("unchecked") + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Tuple, Set, Set> tuple = readTagsAndState(arguments); + Property ageProperty = (Property) block.getProperty("age"); + if (ageProperty == null) { + throw new IllegalArgumentException("age property not set for sugar cane"); + } + int maxHeight = MiscUtils.getAsInt(arguments.getOrDefault("max-height", 3)); + List nearbyLiquids = MiscUtils.getAsStringList(arguments.getOrDefault("required-adjacent-liquids", List.of())); + boolean nearWater = nearbyLiquids.contains("water"); + boolean nearLava = nearbyLiquids.contains("lava"); + return new SugarCaneBlockBehavior(block, tuple.left(), tuple.mid(), tuple.right(), ageProperty, maxHeight, nearWater, nearLava, + MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 1))); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index be56d9e0a..181191bbb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -5685,4 +5685,10 @@ public class Reflections { clazz$ClientboundDisconnectPacket, clazz$Component ) ); + + public static final Method method$CraftEventFactory$handleBlockGrowEvent = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$CraftEventFactory, boolean.class, clazz$Level, clazz$BlockPos, clazz$BlockState + ) + ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 6add299f1..60168df84 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -286,6 +286,8 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/netherite_anvil_top.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/solid_gunpowder_block.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/gunpowder_block.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_1.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_2.png"); // items plugin.saveResource("resources/default/configuration/items.yml"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_rod.png"); @@ -300,6 +302,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow_pulling_1.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow_pulling_2.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/flame_cane.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/entity/equipment/humanoid/topaz.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/entity/equipment/humanoid_leggings/topaz.png"); for (String item : List.of("helmet", "chestplate", "leggings", "boots", "pickaxe", "axe", "sword", "hoe", "shovel")) { diff --git a/gradle.properties b/gradle.properties index 1e9902df2..4d226ad8c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.39 +project_version=0.0.40 config_version=18 lang_version=3 project_group=net.momirealms From f095479c2e435ce0bcfdbc271aa9ac1156a90d19 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 28 Mar 2025 03:36:33 +0800 Subject: [PATCH 05/28] =?UTF-8?q?fix(bukkit):=20=E4=BF=AE=E5=A4=8D=201.21.?= =?UTF-8?q?5=20=E9=83=A8=E5=88=86=E5=90=AF=E5=8A=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/BukkitRecipeManager.java | 17 +++- .../craftengine/bukkit/util/LightUtils.java | 10 +- .../craftengine/bukkit/util/Reflections.java | 94 +++++++++++++------ 3 files changed, 89 insertions(+), 32 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 07fc4fab6..a6d749316 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -39,6 +39,7 @@ import org.jetbrains.annotations.Nullable; import java.io.Reader; import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.file.Path; import java.util.*; @@ -988,8 +989,22 @@ public class BukkitRecipeManager implements RecipeManager { } } + // 1.21.5+ + private static Object toTransmuteResult(ItemStack item) throws InvocationTargetException, IllegalAccessException, InstantiationException { + Object itemStack = Reflections.method$CraftItemStack$asNMSCopy.invoke(null, item); + Object nmsItem = Reflections.method$ItemStack$getItem.invoke(itemStack); + return Reflections.constructor$TransmuteResult.newInstance(nmsItem); + } + private static Object createMinecraftSmithingTransformRecipe(CustomSmithingTransformRecipe ceRecipe) throws ReflectiveOperationException { - if (VersionHelper.isVersionNewerThan1_21_2()) { + if (VersionHelper.isVersionNewerThan1_21_5()) { + return Reflections.constructor$SmithingTransformRecipe.newInstance( + toOptionalMinecraftIngredient(ceRecipe.template()), + toMinecraftIngredient(ceRecipe.base()), + toOptionalMinecraftIngredient(ceRecipe.addition()), + toTransmuteResult(ceRecipe.result(ItemBuildContext.EMPTY)) + ); + } else if (VersionHelper.isVersionNewerThan1_21_2()) { return Reflections.constructor$SmithingTransformRecipe.newInstance( toOptionalMinecraftIngredient(ceRecipe.template()), toOptionalMinecraftIngredient(ceRecipe.base()), diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java index 11d772e19..27bb4e598 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/LightUtils.java @@ -11,6 +11,7 @@ public class LightUtils { private LightUtils() {} + @SuppressWarnings("unchecked") public static void updateChunkLight(World world, Map sectionPosSet) { try { Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(world); @@ -19,8 +20,13 @@ public class LightUtils { long chunkKey = entry.getKey(); Object chunkHolder = Reflections.method$ServerChunkCache$getVisibleChunkIfPresent.invoke(chunkSource, chunkKey); if (chunkHolder == null) continue; - @SuppressWarnings("unchecked") - List players = (List) Reflections.method$ChunkHolder$getPlayers.invoke(chunkHolder, false); + List players; + if (Reflections.method$ChunkHolder$getPlayers != null) { + players = (List) Reflections.method$ChunkHolder$getPlayers.invoke(chunkHolder, false); + } else { + Object chunkHolder$PlayerProvider = Reflections.field$ChunkHolder$playerProvider.get(chunkHolder); + players = (List) Reflections.method$ChunkHolder$PlayerProvider$getPlayers.invoke(chunkHolder$PlayerProvider, false); + } if (players.isEmpty()) continue; Object lightEngine = Reflections.field$ChunkHolder$lightEngine.get(chunkHolder); BitSet blockChangedLightSectionFilter = (BitSet) Reflections.field$ChunkHolder$blockChangedLightSectionFilter.get(chunkHolder); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 3aba8d9d2..8251653e5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -1263,9 +1263,18 @@ public class Reflections { ) ); + public static final Class clazz$Team$Visibility = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.scores.Team$Visibility"), + BukkitReflectionUtils.assembleMCClass("world.scores.ScoreboardTeamBase$EnumTeamPush") + ) + ); + public static final Field field$ClientboundSetPlayerTeamPacket$Parameters$nametagVisibility = requireNonNull( ReflectionUtils.getInstanceDeclaredField( - clazz$ClientboundSetPlayerTeamPacket$Parameters, String.class, 0 + clazz$ClientboundSetPlayerTeamPacket$Parameters, + VersionHelper.isVersionNewerThan1_21_5() ? clazz$Team$Visibility : String.class, + 0 ) ); @@ -2660,12 +2669,31 @@ public class Reflections { ) ); - public static final Method method$ChunkHolder$getPlayers = requireNonNull( - ReflectionUtils.getMethod( - clazz$ChunkHolder, List.class, boolean.class + public static final Class clazz$ChunkHolder$PlayerProvider = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("server.level.ChunkHolder$PlayerProvider"), + BukkitReflectionUtils.assembleMCClass("server.level.PlayerChunk$d") ) ); + public static final Field field$ChunkHolder$playerProvider = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ChunkHolder, clazz$ChunkHolder$PlayerProvider, 0 + ) + ); + + public static final Method method$ChunkHolder$PlayerProvider$getPlayers = requireNonNull( + ReflectionUtils.getMethod( + clazz$ChunkHolder$PlayerProvider, List.class, clazz$ChunkPos, boolean.class + ) + ); + + // 1.20 ~ 1.21.4 + public static final Method method$ChunkHolder$getPlayers = + ReflectionUtils.getMethod( + clazz$ChunkHolder, List.class, boolean.class + ); + public static final Field field$ChunkHolder$lightEngine = requireNonNull( ReflectionUtils.getDeclaredField( clazz$ChunkHolder, clazz$LevelLightEngine, 0 @@ -3923,9 +3951,9 @@ public class Reflections { ); public static final Method method$CraftEventFactory$callBlockPlaceEvent = requireNonNull( - ReflectionUtils.getStaticMethod( - clazz$CraftEventFactory, BlockPlaceEvent.class, clazz$ServerLevel, clazz$Player, clazz$InteractionHand, BlockState.class, int.class, int.class, int.class - ) + VersionHelper.isVersionNewerThan1_21_5() + ? ReflectionUtils.getStaticMethod(clazz$CraftEventFactory, BlockPlaceEvent.class, clazz$ServerLevel, clazz$Player, clazz$InteractionHand, BlockState.class, clazz$BlockPos) + : ReflectionUtils.getStaticMethod(clazz$CraftEventFactory, BlockPlaceEvent.class, clazz$ServerLevel, clazz$Player, clazz$InteractionHand, BlockState.class, int.class, int.class, int.class) ); public static final Class clazz$Abilities = requireNonNull( @@ -4816,9 +4844,9 @@ public class Reflections { ); public static final Method method$ServerLevel$levelEvent = requireNonNull( - ReflectionUtils.getMethod( - clazz$ServerLevel, void.class, clazz$Player, int.class, clazz$BlockPos, int.class - ) + VersionHelper.isVersionNewerThan1_21_5() + ? ReflectionUtils.getMethod(clazz$ServerLevel, void.class, clazz$Entity, int.class, clazz$BlockPos, int.class) + : ReflectionUtils.getMethod(clazz$ServerLevel, void.class, clazz$Player, int.class, clazz$BlockPos, int.class) ); public static final Method method$PalettedContainer$getAndSet = Objects.requireNonNull( @@ -5104,12 +5132,24 @@ public class Reflections { ) ); + // 1.21.5+ + public static final Class clazz$TransmuteResult = + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.item.crafting.TransmuteResult") + ); + + public static final Constructor constructor$TransmuteResult = Optional.ofNullable(clazz$TransmuteResult) + .map(it -> ReflectionUtils.getConstructor(it, clazz$Item)) + .orElse(null); + public static final Constructor constructor$SmithingTransformRecipe = requireNonNull( - VersionHelper.isVersionNewerThan1_21_2() ? - ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, Optional.class, Optional.class, clazz$ItemStack) : - VersionHelper.isVersionNewerThan1_20_2() ? - ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack) : - ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack) + VersionHelper.isVersionNewerThan1_21_5() + ? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, clazz$Ingredient, Optional.class, clazz$TransmuteResult) + : VersionHelper.isVersionNewerThan1_21_2() + ? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, Optional.class, Optional.class, Optional.class, clazz$ItemStack) + : VersionHelper.isVersionNewerThan1_20_2() + ? ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack) + : ReflectionUtils.getConstructor(clazz$SmithingTransformRecipe, clazz$ResourceLocation, clazz$Ingredient, clazz$Ingredient, clazz$Ingredient, clazz$ItemStack) ); public static final Method method$RecipeManager$addRecipe = requireNonNull( @@ -5415,13 +5455,11 @@ public class Reflections { ); public static final Method method$SimpleWaterloggedBlock$canPlaceLiquid = requireNonNull( - VersionHelper.isVersionNewerThan1_20_2() ? - ReflectionUtils.getMethod( - clazz$SimpleWaterloggedBlock, boolean.class, clazz$Player, clazz$BlockGetter, clazz$BlockPos, clazz$BlockState, clazz$Fluid - ) : - ReflectionUtils.getMethod( - clazz$SimpleWaterloggedBlock, boolean.class, clazz$BlockGetter, clazz$BlockPos, clazz$BlockState, clazz$Fluid - ) + VersionHelper.isVersionNewerThan1_21_5() + ? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, boolean.class, clazz$LivingEntity, clazz$BlockGetter, clazz$BlockPos, clazz$BlockState, clazz$Fluid) + : VersionHelper.isVersionNewerThan1_20_2() + ? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, boolean.class, clazz$Player, clazz$BlockGetter, clazz$BlockPos, clazz$BlockState, clazz$Fluid) + : ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, boolean.class, clazz$BlockGetter, clazz$BlockPos, clazz$BlockState, clazz$Fluid) ); public static final Method method$SimpleWaterloggedBlock$placeLiquid = requireNonNull( @@ -5431,13 +5469,11 @@ public class Reflections { ); public static final Method method$SimpleWaterloggedBlock$pickupBlock = requireNonNull( - VersionHelper.isVersionNewerThan1_20_2() ? - ReflectionUtils.getMethod( - clazz$SimpleWaterloggedBlock, clazz$ItemStack, clazz$Player, clazz$LevelAccessor, clazz$BlockPos, clazz$BlockState - ) : - ReflectionUtils.getMethod( - clazz$SimpleWaterloggedBlock, clazz$ItemStack, clazz$LevelAccessor, clazz$BlockPos, clazz$BlockState - ) + VersionHelper.isVersionNewerThan1_21_5() + ? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, clazz$ItemStack, clazz$LivingEntity, clazz$LevelAccessor, clazz$BlockPos, clazz$BlockState) + : VersionHelper.isVersionNewerThan1_20_2() + ? ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, clazz$ItemStack, clazz$Player, clazz$LevelAccessor, clazz$BlockPos, clazz$BlockState) + : ReflectionUtils.getMethod(clazz$SimpleWaterloggedBlock, clazz$ItemStack, clazz$LevelAccessor, clazz$BlockPos, clazz$BlockState) ); public static final Method method$Fluid$getTickDelay = requireNonNull( From 2c1e18498562f1b17024b753064517294a515280 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 04:09:00 +0800 Subject: [PATCH 06/28] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/SugarCaneBlockBehavior.java | 7 ++++++- .../craftengine/bukkit/plugin/injector/BukkitInjector.java | 2 ++ .../momirealms/craftengine/bukkit/util/Reflections.java | 4 ++++ gradle.properties | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java index 04ce54160..b327e7fea 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.block.behavior; import com.sk89q.worldedit.blocks.Blocks; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; @@ -120,7 +121,11 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { int age = currentState.get(ageProperty); if (age >= this.ageProperty.max || RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) { Object abovePos = LocationUtils.above(blockPos); - Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, customBlock.defaultState().customBlockState().handle()); + if (VersionHelper.isVersionNewerThan1_21_5()) { + Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, customBlock.defaultState().customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); + } else { + Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, customBlock.defaultState().customBlockState().handle()); + } Reflections.method$Level$setBlock.invoke(level, blockPos, currentState.with(this.ageProperty, this.ageProperty.min).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); } else if (RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) { Reflections.method$Level$setBlock.invoke(level, blockPos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java index 388f70160..cc4bd7942 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java @@ -96,6 +96,8 @@ public class BukkitInjector { .method(ElementMatchers.any() .and(ElementMatchers.not(ElementMatchers.is(Reflections.method$PalettedContainer$getAndSet))) .and(ElementMatchers.not(ElementMatchers.isDeclaredBy(Object.class))) + // 1.21.5+, do + .and(ElementMatchers.not(ElementMatchers.named("get").and(ElementMatchers.takesArguments(int.class)).and(ElementMatchers.returns(Object.class)))) ) .intercept(MethodDelegation.toField("target")) .method(ElementMatchers.is(Reflections.method$PalettedContainer$getAndSet)) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 6a73063e9..2193e2758 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -5732,6 +5732,10 @@ public class Reflections { ); public static final Method method$CraftEventFactory$handleBlockGrowEvent = requireNonNull( + VersionHelper.isVersionNewerThan1_21_5() ? + ReflectionUtils.getStaticMethod( + clazz$CraftEventFactory, boolean.class, clazz$Level, clazz$BlockPos, clazz$BlockState, int.class + ) : ReflectionUtils.getStaticMethod( clazz$CraftEventFactory, boolean.class, clazz$Level, clazz$BlockPos, clazz$BlockState ) diff --git a/gradle.properties b/gradle.properties index 4d226ad8c..96a6a3b08 100644 --- a/gradle.properties +++ b/gradle.properties @@ -49,7 +49,7 @@ mojang_brigadier_version=1.0.18 byte_buddy_version=1.15.11 snake_yaml_version=2.3 anti_grief_version=0.13 -nms_helper_version=0.10 +nms_helper_version=0.12 # Ignite Dependencies mixinextras_version=0.4.1 mixin_version=0.15.2+mixin.0.8.7 From 64e572066ba8d4186b124b2c9f874978a96e550e Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 04:19:21 +0800 Subject: [PATCH 07/28] fix packet id --- .../behavior/SugarCaneBlockBehavior.java | 1 + .../plugin/network/BukkitNetworkManager.java | 4 ++- .../plugin/network/impl/PacketIds1_21_5.java | 31 +++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21_5.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java index b327e7fea..da133315d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java @@ -4,6 +4,7 @@ import com.sk89q.worldedit.blocks.Blocks; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index 638405a24..939cf62f8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -72,7 +72,9 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes public BukkitNetworkManager(BukkitCraftEngine plugin) { this.plugin = plugin; - if (VersionHelper.isVersionNewerThan1_21_2()) { + if (VersionHelper.isVersionNewerThan1_21_5()) { + this.packetIds = new PacketIds1_21_5(); + } else if (VersionHelper.isVersionNewerThan1_21_2()) { this.packetIds = new PacketIds1_21_2(); } else if (VersionHelper.isVersionNewerThan1_20_5()) { this.packetIds = new PacketIds1_20_5(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21_5.java new file mode 100644 index 000000000..f54faf5cb --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/impl/PacketIds1_21_5.java @@ -0,0 +1,31 @@ +package net.momirealms.craftengine.bukkit.plugin.network.impl; + +import net.momirealms.craftengine.bukkit.plugin.network.PacketIds; + +public class PacketIds1_21_5 implements PacketIds { + + @Override + public int clientboundBlockUpdatePacket() { + return 8; + } + + @Override + public int clientboundSectionBlocksUpdatePacket() { + return 72; + } + + @Override + public int clientboundLevelParticlesPacket() { + return 40; + } + + @Override + public int clientboundLevelEventPacket() { + return 39; + } + + @Override + public int clientboundAddEntityPacket() { + return 1; + } +} From 1ac0ab193870dfe4eeab6d732caa0d5abf1f86cf Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 04:41:06 +0800 Subject: [PATCH 08/28] fix changes --- .../craftengine/bukkit/plugin/injector/BukkitInjector.java | 4 ++-- .../net/momirealms/craftengine/bukkit/util/Reflections.java | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java index cc4bd7942..a2656ed50 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BukkitInjector.java @@ -96,8 +96,8 @@ public class BukkitInjector { .method(ElementMatchers.any() .and(ElementMatchers.not(ElementMatchers.is(Reflections.method$PalettedContainer$getAndSet))) .and(ElementMatchers.not(ElementMatchers.isDeclaredBy(Object.class))) - // 1.21.5+, do - .and(ElementMatchers.not(ElementMatchers.named("get").and(ElementMatchers.takesArguments(int.class)).and(ElementMatchers.returns(Object.class)))) + // TODO Requires Paper Patch + //.and(ElementMatchers.not(ElementMatchers.named("get").and(ElementMatchers.takesArguments(int.class)).and(ElementMatchers.returns(Object.class)))) ) .intercept(MethodDelegation.toField("target")) .method(ElementMatchers.is(Reflections.method$PalettedContainer$getAndSet)) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index 2193e2758..bcd33e054 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -5710,7 +5710,6 @@ public class Reflections { .orElse(null); // 1.21.4#222+ - // 我tm服了这个 sb paper 你 tmd 乱改签名干什么有病啊 public static final Method method$DiscardedPayload$dataByteArray = Optional.ofNullable(method$DiscardedPayload$data) .map(m -> (Method) null) .orElseGet(() -> Optional.ofNullable(clazz$DiscardedPayload) From 24b04901b172029c4472f13bb37c72bb48cbbd7f Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 28 Mar 2025 04:55:35 +0800 Subject: [PATCH 09/28] =?UTF-8?q?refactor(bukkit):=20=E4=BC=98=E5=8C=96imp?= =?UTF-8?q?ort?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/block/behavior/BushBlockBehavior.java | 5 ++++- .../bukkit/block/behavior/FallingBlockBehavior.java | 1 - .../bukkit/block/behavior/HangingBlockBehavior.java | 1 - .../bukkit/block/behavior/SugarCaneBlockBehavior.java | 3 --- .../craftengine/bukkit/item/behavior/BlockItemBehavior.java | 1 - .../craftengine/bukkit/item/recipe/BukkitRecipeManager.java | 2 +- .../craftengine/bukkit/item/recipe/RecipeEventListener.java | 2 +- .../craftengine/bukkit/plugin/user/BukkitServerPlayer.java | 2 +- .../core/plugin/gui/category/ItemBrowserManagerImpl.java | 2 +- 9 files changed, 8 insertions(+), 11 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index 9ce8d502e..13b6e32ae 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -21,7 +21,10 @@ import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.shared.block.BlockBehavior; -import org.bukkit.*; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; import java.util.*; import java.util.concurrent.Callable; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java index 6fbe0caa4..08bbc708a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FallingBlockBehavior.java @@ -17,7 +17,6 @@ import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.shared.block.BlockBehavior; -import org.bukkit.World; import java.util.Map; import java.util.concurrent.Callable; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java index aa35a9777..2c43e4ea8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.util.Tuple; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java index da133315d..c8f0dfc67 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SugarCaneBlockBehavior.java @@ -1,10 +1,7 @@ package net.momirealms.craftengine.bukkit.block.behavior; -import com.sk89q.worldedit.blocks.Blocks; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; -import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.util.Reflections; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index fbc4d03fe..e19d88049 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -40,7 +40,6 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.util.Vector; import javax.annotation.Nullable; -import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; import java.util.Map; import java.util.Optional; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index a6d749316..00d3087e4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -12,8 +12,8 @@ import net.momirealms.craftengine.bukkit.util.RecipeUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.*; +import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.vanilla.*; import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index c513dc9b1..02a555fad 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -11,8 +11,8 @@ import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.*; -import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.*; +import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 030a31379..f6f38caa2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -18,8 +18,8 @@ import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.*; +import net.momirealms.craftengine.core.world.World; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.inventory.EquipmentSlot; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index 2b203b19d..12460c8c5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -7,8 +7,8 @@ import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.recipe.*; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.gui.Ingredient; import net.momirealms.craftengine.core.plugin.gui.*; +import net.momirealms.craftengine.core.plugin.gui.Ingredient; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; From 5b5145199abdd375e9815253fea6bd5bf05a4850 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 28 Mar 2025 10:25:51 +0800 Subject: [PATCH 10/28] =?UTF-8?q?feat(bukkit):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BD=9C=E7=89=A9=E6=96=B9=E5=9D=97=E8=A1=8C=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/behavior/BukkitBlockBehaviors.java | 2 + .../block/behavior/CropBlockBehavior.java | 120 ++++++++++++++++++ .../craftengine/bukkit/util/Reflections.java | 32 +++++ .../craftengine/core/util/RandomUtils.java | 4 + 4 files changed, 158 insertions(+) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java index 046911410..6d8de9243 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehaviors.java @@ -15,6 +15,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key WATERLOGGED_BLOCK = Key.from("craftengine:waterlogged_block"); 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 void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -28,5 +29,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(WATERLOGGED_BLOCK, WaterLoggedBlockBehavior.FACTORY); register(CONCRETE_POWDER_BLOCK, ConcretePowderBlockBehavior.FACTORY); register(SUGARCANE_BLOCK, SugarCaneBlockBehavior.FACTORY); + register(CROP_BLOCK, CropBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java new file mode 100644 index 000000000..4cc1a8fea --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -0,0 +1,120 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +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.block.properties.IntegerProperty; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.Tuple; +import net.momirealms.craftengine.shared.block.BlockBehavior; + +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Callable; + +public class CropBlockBehavior extends BushBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final IntegerProperty ageProperty; + private final float growSpeed; + private final int minGrowLight; + + public CropBlockBehavior(List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, + Property ageProperty, float growSpeed, int minGrowLight) { + super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + this.ageProperty = (IntegerProperty) ageProperty; + this.growSpeed = growSpeed; + this.minGrowLight = minGrowLight; + } + + public final boolean isMaxAge(Object state) { + return this.getAge(state) >= this.ageProperty.max; + } + + public static ImmutableBlockState getCEBlockState(Object nmsState) { + return BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(nmsState)); + } + + public final int getAge(Object state) { + return getCEBlockState(state).get(ageProperty); + } + + public Object getStateForAge(Object state, int age) { + ImmutableBlockState afterState = getCEBlockState(state).owner().value().defaultState().with(ageProperty, age); + return afterState.customBlockState().handle(); + } + + public void growCrops(Object level, Object pos, Object state) throws InvocationTargetException, IllegalAccessException { + int i = this.getAge(state) + RandomUtils.generateRandomInt(2, 5); + int maxAge = this.ageProperty.max; + if (i > maxAge) { + i = maxAge; + } + Reflections.method$ServerLevel$sendBlockUpdated.invoke(level, pos, state, getStateForAge(state, i), 3); + } + + private static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { + return (int) Reflections.method$BlockAndTintGetter$getRawBrightness.invoke(level, pos, 0); + } + + private boolean hasSufficientLight(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { + return getRawBrightness(level, pos) >= minGrowLight - 1; + } + + @Override + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object state = args[0]; + Object level = args[1]; + Object pos = args[2]; + if (getRawBrightness(level, pos) >= minGrowLight) { + int age = this.getAge(state); + if (age < this.ageProperty.max && RandomUtils.generateRandomFloat(0, 1) >= this.growSpeed) { + Reflections.method$ServerLevel$sendBlockUpdated.invoke(level, pos, state, getStateForAge(state, age + 1), 3); + } + } + } + + @Override + protected boolean canSurvive(Object thisBlock, Object state, Object world, Object blockPos) throws ReflectiveOperationException { + return hasSufficientLight(world, blockPos) && super.canSurvive(thisBlock, state, world, blockPos); + } + + @Override + public boolean isBoneMealSuccess(Object thisBlock, Object[] args) { + return true; + } + + @Override + public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) { + Object state = args[2]; + return !this.isMaxAge(state); + } + + @Override + public void performBoneMeal(Object thisBlock, Object[] args) throws Exception { + this.growCrops(args[0], args[2], args[3]); + } + + public static class Factory implements BlockBehaviorFactory { + + @SuppressWarnings("unchecked") + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Tuple, Set, Set> tuple = readTagsAndState(arguments); + Property ageProperty = (Property) block.getProperty("age"); + if (ageProperty == null) { + throw new IllegalArgumentException("age property not set for crop"); + } + // 存活条件是最小生长亮度-1 + int minGrowLight = MiscUtils.getAsInt(arguments.getOrDefault("min-grow-light", 9)); + float growSpeed = MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 1)); + return new CropBlockBehavior(tuple.left(), tuple.mid(), tuple.right(), ageProperty, growSpeed, minGrowLight); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java index bcd33e054..d859d3bf8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/Reflections.java @@ -5739,4 +5739,36 @@ public class Reflections { clazz$CraftEventFactory, boolean.class, clazz$Level, clazz$BlockPos, clazz$BlockState ) ); + + public static final Class clazz$BlockAndTintGetter = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.level.BlockAndTintGetter"), + BukkitReflectionUtils.assembleMCClass("world.level.IBlockLightAccess") + ) + ); + + public static final Method method$BlockAndTintGetter$getRawBrightness = requireNonNull( + ReflectionUtils.getMethod( + clazz$BlockAndTintGetter, int.class, clazz$BlockPos, int.class + ) + ); + + public static final Field field$Level$random = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$Level, clazz$RandomSource, 0 + ) + ); + + public static final Class clazz$Mth = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("util.Mth"), + BukkitReflectionUtils.assembleMCClass("util.MathHelper") + ) + ); + + public static final Method method$nextInt = requireNonNull( + ReflectionUtils.getMethod( + clazz$Mth, int.class, clazz$RandomSource, int.class, int.class + ) + ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java index 38d5f78dd..34c0b03e7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java @@ -26,6 +26,10 @@ public class RandomUtils { return min + (max - min) * getInstance().random.nextFloat(); } + public static int generateRandomInt(int min, int max) { + return min >= max ? min : getInstance().random.nextInt(max - min + 1) + min; + } + public static boolean generateRandomBoolean() { return getInstance().random.nextBoolean(); } From 6c94e4f2aba29d9fd6247d2c584f848637f84f02 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 28 Mar 2025 11:22:06 +0800 Subject: [PATCH 11/28] =?UTF-8?q?feat(bukkit):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BD=9C=E7=89=A9=E6=96=B9=E5=9D=97=E6=9D=A1=E4=BB=B6=E5=88=A4?= =?UTF-8?q?=E6=96=AD=E5=92=8C=E9=83=A8=E5=88=86=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/default/configuration/i18n.yml | 2 + .../default/configuration/plants.yml | 126 ++++++++++++++++++ .../bukkit/block/BlockEventListener.java | 4 + .../loot/condition/CropRipeCondition.java | 29 ++++ .../core/loot/condition/LootConditions.java | 2 + .../core/loot/parameter/LootParameters.java | 1 + 6 files changed, 164 insertions(+) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml index dc46c4640..4e3cc366f 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml @@ -4,6 +4,7 @@ i18n: item.fairy_flower: "Fairy Flower" item.reed: "Reed" item.flame_cane: "Flame Cane" + item.ender_pearl_crop_seed: "Ender Pearl Flower Seeds" item.bench: "Bench" item.table_lamp: "Table Lamp" item.wooden_chair: "Wooden Chair" @@ -43,6 +44,7 @@ i18n: item.fairy_flower: "仙灵花" item.reed: "芦苇" item.flame_cane: "烈焰甘蔗" + item.ender_pearl_crop_seed: "末影珍珠花种子" item.bench: "长椅" item.table_lamp: "台灯" item.wooden_chair: "木椅" diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 172600da7..86f223217 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -35,6 +35,18 @@ items: behavior: type: block_item block: default:flame_cane + default:ender_pearl_crop_seed: + material: paper + custom-model-data: 4003 + data: + item-name: "" + model: + template: default:model/simplified_generated + arguments: + path: "minecraft:item/custom/ender_pearl_crop_seed" + behavior: + type: block_item + block: default:ender_pearl_crop blocks: default:fairy_flower: settings: @@ -167,6 +179,120 @@ blocks: age=5: appearance: default id: 7 + default:ender_pearl_crop: + settings: + template: + - default:hardness/none + - default:sound/grass + overrides: + item: default:ender_pearl_crop_seed + push-reaction: DESTROY + map-color: 15 + is-randomly-ticking: true + behavior: + type: crop_block + grow-speed: 1 + min-grow-light: 9 + bottom-blocks: + - minecraft:end_stone + loot: + pools: + - rolls: 1 + entries: + - type: alternatives + children: + - type: item + item: "default:ender_pearl_crop_seed" + conditions: + - type: survives_explosion + - type: item + item: "minecraft:ender_pearl" + conditions: + - type: crop_ripe + functions: + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: ore_drops + - type: explosion_decay + count: + type: uniform + min: "1" + max: "5" + states: + properties: + age: + type: int + default: 0 + range: 0~5 + appearances: + default: + state: "sugar_cane:3" + models: + - path: "minecraft:block/custom/ender_pearl_crop_stage1" + generation: + parent: "minecraft:block/crop" + textures: + "crop": "minecraft:block/custom/ender_pearl_crop_stage1" + age1: + state: "sugar_cane:4" + models: + - path: "minecraft:block/custom/ender_pearl_crop_stage2" + generation: + parent: "minecraft:block/crop" + textures: + "crop": "minecraft:block/custom/ender_pearl_crop_stage2" + age2: + state: "sugar_cane:5" + models: + - path: "minecraft:block/custom/ender_pearl_crop_stage3" + generation: + parent: "minecraft:block/crop" + textures: + "crop": "minecraft:block/custom/ender_pearl_crop_stage3" + age3: + state: "sugar_cane:6" + models: + - path: "minecraft:block/custom/ender_pearl_crop_stage4" + generation: + parent: "minecraft:block/crop" + textures: + "crop": "minecraft:block/custom/ender_pearl_crop_stage4" + age4: + state: "sugar_cane:7" + models: + - path: "minecraft:block/custom/ender_pearl_crop_stage5" + generation: + parent: "minecraft:block/crop" + textures: + "crop": "minecraft:block/custom/ender_pearl_crop_stage5" + age5: + state: "sugar_cane:8" + models: + - path: "minecraft:block/custom/ender_pearl_crop_stage6" + generation: + parent: "minecraft:block/crop" + textures: + "crop": "minecraft:block/custom/ender_pearl_crop_stage6" + variants: + age=0: + appearance: default + id: 8 + age=1: + appearance: age1 + id: 9 + age=2: + appearance: age2 + id: 10 + age=3: + appearance: age3 + id: 11 + age=4: + appearance: age4 + id: 12 + age=5: + appearance: age5 + id: 13 recipes: default:paper_from_reed: type: shaped diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index befb9a1e2..ec3b798ec 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.block; import io.papermc.paper.event.block.BlockBreakBlockEvent; import net.momirealms.craftengine.bukkit.api.event.CustomBlockBreakEvent; +import net.momirealms.craftengine.bukkit.block.behavior.CropBlockBehavior; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; @@ -138,6 +139,9 @@ public class BlockEventListener implements Listener { builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.PLAYER, serverPlayer); builder.withOptionalParameter(LootParameters.TOOL, itemInHand); + if (state.behavior() instanceof CropBlockBehavior) { + builder.withParameter(LootParameters.CROP_BLOCK, true); + } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java new file mode 100644 index 000000000..05248b2c0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java @@ -0,0 +1,29 @@ +package net.momirealms.craftengine.core.loot.condition; + +import net.momirealms.craftengine.core.loot.LootContext; +import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.util.Key; + +import java.util.Map; + +public class CropRipeCondition implements LootCondition { + public static final Factory FACTORY = new Factory(); + public static final CropRipeCondition INSTANCE = new CropRipeCondition(); + + @Override + public Key type() { + return LootConditions.CROP_RIPE; + } + + @Override + public boolean test(LootContext lootContext) { + return lootContext.getOptionalParameter(LootParameters.CROP_BLOCK).orElse(false); + } + + public static class Factory implements LootConditionFactory { + @Override + public LootCondition create(Map arguments) { + return INSTANCE; + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java index 806172e90..4dd4ffabc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java @@ -21,6 +21,7 @@ public class LootConditions { public static final Key ENCHANTMENT = Key.from("craftengine:enchantment"); public static final Key INVERTED = Key.from("craftengine:inverted"); public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block"); + public static final Key CROP_RIPE = Key.from("craftengine:crop_ripe"); static { register(MATCH_ITEM, MatchItemCondition.FACTORY); @@ -31,6 +32,7 @@ public class LootConditions { register(ENCHANTMENT, EnchantmentCondition.FACTORY); register(INVERTED, InvertedCondition.FACTORY); register(FALLING_BLOCK, FallingCondition.FACTORY); + register(CROP_RIPE, CropRipeCondition.FACTORY); } public static void register(Key key, LootConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java b/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java index ca09453ea..29b531ea2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java @@ -18,4 +18,5 @@ public class LootParameters { public static final ContextKey PLAYER = new ContextKey<>(Key.of("craftengine:player")); public static final ContextKey> TOOL = new ContextKey<>(Key.of("craftengine:tool")); public static final ContextKey BLOCK_STATE = new ContextKey<>(Key.of("craftengine:block_state")); + public static final ContextKey CROP_BLOCK = new ContextKey<>(Key.of("craftengine:crop_block")); } From d98032160f81ed0ab1406363eeff17d52617b97d Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 28 Mar 2025 12:01:13 +0800 Subject: [PATCH 12/28] =?UTF-8?q?feat(block):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BD=9C=E7=89=A9=E6=96=B9=E5=9D=97=E8=A1=8C=E4=B8=BA=E5=92=8C?= =?UTF-8?q?=E6=8E=89=E8=90=BD=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/plants.yml | 35 ++++++++----------- .../bukkit/api/CraftEngineBlocks.java | 4 +++ .../bukkit/block/BlockEventListener.java | 3 ++ .../block/behavior/BushBlockBehavior.java | 3 ++ .../block/behavior/CropBlockBehavior.java | 7 ++-- 5 files changed, 29 insertions(+), 23 deletions(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 86f223217..93b12fd24 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -43,7 +43,7 @@ items: model: template: default:model/simplified_generated arguments: - path: "minecraft:item/custom/ender_pearl_crop_seed" + path: "minecraft:block/custom/ender_pearl_crop_seed" behavior: type: block_item block: default:ender_pearl_crop @@ -199,26 +199,19 @@ blocks: pools: - rolls: 1 entries: - - type: alternatives - children: - - type: item - item: "default:ender_pearl_crop_seed" - conditions: - - type: survives_explosion - - type: item - item: "minecraft:ender_pearl" - conditions: - - type: crop_ripe - functions: - - type: apply_bonus - enchantment: minecraft:fortune - formula: - type: ore_drops - - type: explosion_decay - count: - type: uniform - min: "1" - max: "5" + - type: item + item: "default:ender_pearl_crop_seed" + conditions: + - type: survives_explosion + - rolls: + type: uniform + min: "1" + max: "5" + entries: + - type: item + item: "minecraft:ender_pearl" + conditions: + - type: crop_ripe states: properties: age: diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index ed4dc7d2e..c39947497 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.api; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.block.behavior.CropBlockBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; @@ -181,6 +182,9 @@ public final class CraftEngineBlocks { builder.withParameter(LootParameters.PLAYER, serverPlayer); builder.withOptionalParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); } + if (state.behavior() instanceof CropBlockBehavior) { + builder.withParameter(LootParameters.CROP_BLOCK, true); + } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index ec3b798ec..2e8c2e4af 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -300,6 +300,9 @@ public class BlockEventListener implements Listener { if (yield < 1f) { builder.withParameter(LootParameters.EXPLOSION_RADIUS, 1.0f / yield); } + if (state.behavior() instanceof CropBlockBehavior) { + builder.withParameter(LootParameters.CROP_BLOCK, true); + } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index 13b6e32ae..f1ff84512 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -71,6 +71,9 @@ public class BushBlockBehavior extends AbstractBlockBehavior { net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.WORLD, world); + if (this instanceof CropBlockBehavior) { + builder.withParameter(LootParameters.CROP_BLOCK, true); + } for (Item item : previousState.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index 4cc1a8fea..f44010e81 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.bukkit.util.BlockStateUtils; 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.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.Property; @@ -56,7 +57,7 @@ public class CropBlockBehavior extends BushBlockBehavior { if (i > maxAge) { i = maxAge; } - Reflections.method$ServerLevel$sendBlockUpdated.invoke(level, pos, state, getStateForAge(state, i), 3); + Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, i), UpdateOption.UPDATE_NONE.flags()); } private static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { @@ -74,8 +75,10 @@ public class CropBlockBehavior extends BushBlockBehavior { Object pos = args[2]; if (getRawBrightness(level, pos) >= minGrowLight) { int age = this.getAge(state); + System.out.println("age: " + age); if (age < this.ageProperty.max && RandomUtils.generateRandomFloat(0, 1) >= this.growSpeed) { - Reflections.method$ServerLevel$sendBlockUpdated.invoke(level, pos, state, getStateForAge(state, age + 1), 3); + System.out.println("grow"); + Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, age + 1), UpdateOption.UPDATE_NONE.flags()); } } } From b248c265dcfd5e27ecf5c0a901072b96916adeb6 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 28 Mar 2025 12:09:08 +0800 Subject: [PATCH 13/28] =?UTF-8?q?fix(block):=20=E4=BF=AE=E5=A4=8D=E4=BD=9C?= =?UTF-8?q?=E7=89=A9=E6=88=90=E7=86=9F=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/api/CraftEngineBlocks.java | 6 ++++-- .../craftengine/bukkit/block/BlockEventListener.java | 12 ++++++++---- .../bukkit/block/behavior/BushBlockBehavior.java | 6 ++++-- .../bukkit/block/behavior/CropBlockBehavior.java | 12 ++++++++++-- .../core/loot/condition/CropRipeCondition.java | 2 +- .../core/loot/parameter/LootParameters.java | 2 +- 6 files changed, 28 insertions(+), 12 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index c39947497..7f2ad0a7b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -182,8 +182,10 @@ public final class CraftEngineBlocks { builder.withParameter(LootParameters.PLAYER, serverPlayer); builder.withOptionalParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); } - if (state.behavior() instanceof CropBlockBehavior) { - builder.withParameter(LootParameters.CROP_BLOCK, true); + if (state.behavior() instanceof CropBlockBehavior cropBlockBehavior) { + if (cropBlockBehavior.isMaxAge(state)) { + builder.withParameter(LootParameters.CROP_RIPE, true); + } } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 2e8c2e4af..0bdc7364f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -139,8 +139,10 @@ public class BlockEventListener implements Listener { builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.PLAYER, serverPlayer); builder.withOptionalParameter(LootParameters.TOOL, itemInHand); - if (state.behavior() instanceof CropBlockBehavior) { - builder.withParameter(LootParameters.CROP_BLOCK, true); + if (state.behavior() instanceof CropBlockBehavior cropBlockBehavior) { + if (cropBlockBehavior.isMaxAge(state)) { + builder.withParameter(LootParameters.CROP_RIPE, true); + } } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); @@ -300,8 +302,10 @@ public class BlockEventListener implements Listener { if (yield < 1f) { builder.withParameter(LootParameters.EXPLOSION_RADIUS, 1.0f / yield); } - if (state.behavior() instanceof CropBlockBehavior) { - builder.withParameter(LootParameters.CROP_BLOCK, true); + if (state.behavior() instanceof CropBlockBehavior cropBlockBehavior) { + if (cropBlockBehavior.isMaxAge(state)) { + builder.withParameter(LootParameters.CROP_RIPE, true); + } } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index f1ff84512..f5226c5f8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -71,8 +71,10 @@ public class BushBlockBehavior extends AbstractBlockBehavior { net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.WORLD, world); - if (this instanceof CropBlockBehavior) { - builder.withParameter(LootParameters.CROP_BLOCK, true); + if (this instanceof CropBlockBehavior cropBlockBehavior) { + if (cropBlockBehavior.isMaxAge(state)) { + builder.withParameter(LootParameters.CROP_RIPE, true); + } } for (Item item : previousState.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index f44010e81..4c4c63409 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -37,6 +37,9 @@ public class CropBlockBehavior extends BushBlockBehavior { public final boolean isMaxAge(Object state) { return this.getAge(state) >= this.ageProperty.max; } + public final boolean isMaxAge(ImmutableBlockState state) { + return this.getAge(state) >= this.ageProperty.max; + } public static ImmutableBlockState getCEBlockState(Object nmsState) { return BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(nmsState)); @@ -45,6 +48,9 @@ public class CropBlockBehavior extends BushBlockBehavior { public final int getAge(Object state) { return getCEBlockState(state).get(ageProperty); } + public final int getAge(ImmutableBlockState state) { + return state.get(ageProperty); + } public Object getStateForAge(Object state, int age) { ImmutableBlockState afterState = getCEBlockState(state).owner().value().defaultState().with(ageProperty, age); @@ -75,8 +81,10 @@ public class CropBlockBehavior extends BushBlockBehavior { Object pos = args[2]; if (getRawBrightness(level, pos) >= minGrowLight) { int age = this.getAge(state); - System.out.println("age: " + age); - if (age < this.ageProperty.max && RandomUtils.generateRandomFloat(0, 1) >= this.growSpeed) { + float randomFloat = RandomUtils.generateRandomFloat(0, 1); + System.out.println("age: " + age + "ageProperty.max: " + this.ageProperty.max + " -> " + (age < this.ageProperty.max)); + System.out.println("randomFloat: " + randomFloat + "growSpeed: " + this.growSpeed + " -> " + (randomFloat < this.growSpeed)); + if (age < this.ageProperty.max && randomFloat >= this.growSpeed) { System.out.println("grow"); Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, age + 1), UpdateOption.UPDATE_NONE.flags()); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java index 05248b2c0..10d30ac74 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java @@ -17,7 +17,7 @@ public class CropRipeCondition implements LootCondition { @Override public boolean test(LootContext lootContext) { - return lootContext.getOptionalParameter(LootParameters.CROP_BLOCK).orElse(false); + return lootContext.getOptionalParameter(LootParameters.CROP_RIPE).orElse(false); } public static class Factory implements LootConditionFactory { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java b/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java index 29b531ea2..35e145b56 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java @@ -18,5 +18,5 @@ public class LootParameters { public static final ContextKey PLAYER = new ContextKey<>(Key.of("craftengine:player")); public static final ContextKey> TOOL = new ContextKey<>(Key.of("craftengine:tool")); public static final ContextKey BLOCK_STATE = new ContextKey<>(Key.of("craftengine:block_state")); - public static final ContextKey CROP_BLOCK = new ContextKey<>(Key.of("craftengine:crop_block")); + public static final ContextKey CROP_RIPE = new ContextKey<>(Key.of("craftengine:crop_ripe")); } From 2c449404b2a7b2bec42739701342e38bb4e3cb20 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 28 Mar 2025 12:30:41 +0800 Subject: [PATCH 14/28] =?UTF-8?q?fix(block):=20=E4=BF=AE=E5=A4=8D=E4=BD=9C?= =?UTF-8?q?=E7=89=A9=E7=94=9F=E9=95=BF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/CropBlockBehavior.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index 4c4c63409..639379a79 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -82,11 +82,9 @@ public class CropBlockBehavior extends BushBlockBehavior { if (getRawBrightness(level, pos) >= minGrowLight) { int age = this.getAge(state); float randomFloat = RandomUtils.generateRandomFloat(0, 1); - System.out.println("age: " + age + "ageProperty.max: " + this.ageProperty.max + " -> " + (age < this.ageProperty.max)); - System.out.println("randomFloat: " + randomFloat + "growSpeed: " + this.growSpeed + " -> " + (randomFloat < this.growSpeed)); - if (age < this.ageProperty.max && randomFloat >= this.growSpeed) { + if (age < this.ageProperty.max && randomFloat < 1.0 / Math.floor(25.0 / this.growSpeed + 1.0)) { System.out.println("grow"); - Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, age + 1), UpdateOption.UPDATE_NONE.flags()); + Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, age + 1), UpdateOption.UPDATE_ALL.flags()); } } } From afcc95b2514b071fec6dbfdca61df86ff9153d35 Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 28 Mar 2025 12:37:32 +0800 Subject: [PATCH 15/28] =?UTF-8?q?refactor(bukkit):=20=E7=A7=BB=E9=99=A4?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/block/behavior/CropBlockBehavior.java | 1 - 1 file changed, 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index 639379a79..a9449b023 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -83,7 +83,6 @@ public class CropBlockBehavior extends BushBlockBehavior { int age = this.getAge(state); float randomFloat = RandomUtils.generateRandomFloat(0, 1); if (age < this.ageProperty.max && randomFloat < 1.0 / Math.floor(25.0 / this.growSpeed + 1.0)) { - System.out.println("grow"); Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, age + 1), UpdateOption.UPDATE_ALL.flags()); } } From 14ecdffaf5c02bacf454fcda2d5a82542030dbae Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 28 Mar 2025 12:53:40 +0800 Subject: [PATCH 16/28] =?UTF-8?q?feat(crop):=20=E4=BF=AE=E6=94=B9=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/categories.yml | 3 +- .../default/configuration/plants.yml | 44 +++---------------- 2 files changed, 8 insertions(+), 39 deletions(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml index e99de8717..328706d8c 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml @@ -61,4 +61,5 @@ categories: - default:reed - default:flame_cane - default:gunpowder_block - - default:solid_gunpowder_block \ No newline at end of file + - default:solid_gunpowder_block + - default:ender_pearl_crop_seed \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 93b12fd24..46421ed0c 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -227,7 +227,7 @@ blocks: parent: "minecraft:block/crop" textures: "crop": "minecraft:block/custom/ender_pearl_crop_stage1" - age1: + ripe: state: "sugar_cane:4" models: - path: "minecraft:block/custom/ender_pearl_crop_stage2" @@ -235,56 +235,24 @@ blocks: parent: "minecraft:block/crop" textures: "crop": "minecraft:block/custom/ender_pearl_crop_stage2" - age2: - state: "sugar_cane:5" - models: - - path: "minecraft:block/custom/ender_pearl_crop_stage3" - generation: - parent: "minecraft:block/crop" - textures: - "crop": "minecraft:block/custom/ender_pearl_crop_stage3" - age3: - state: "sugar_cane:6" - models: - - path: "minecraft:block/custom/ender_pearl_crop_stage4" - generation: - parent: "minecraft:block/crop" - textures: - "crop": "minecraft:block/custom/ender_pearl_crop_stage4" - age4: - state: "sugar_cane:7" - models: - - path: "minecraft:block/custom/ender_pearl_crop_stage5" - generation: - parent: "minecraft:block/crop" - textures: - "crop": "minecraft:block/custom/ender_pearl_crop_stage5" - age5: - state: "sugar_cane:8" - models: - - path: "minecraft:block/custom/ender_pearl_crop_stage6" - generation: - parent: "minecraft:block/crop" - textures: - "crop": "minecraft:block/custom/ender_pearl_crop_stage6" variants: age=0: appearance: default id: 8 age=1: - appearance: age1 + appearance: default id: 9 age=2: - appearance: age2 + appearance: default id: 10 age=3: - appearance: age3 + appearance: default id: 11 age=4: - appearance: age4 + appearance: default id: 12 age=5: - appearance: age5 + appearance: ripe id: 13 recipes: default:paper_from_reed: From b5a027e3519afcc1fcab8028f677c31048293fef Mon Sep 17 00:00:00 2001 From: jhqwqmc <2110242767@qq.com> Date: Fri, 28 Mar 2025 13:07:38 +0800 Subject: [PATCH 17/28] =?UTF-8?q?feat(crop):=20=E4=BF=AE=E6=94=B9=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/plants.yml | 8 +++--- .../models/block/custom/tinted_cross.json | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 46421ed0c..988d348dd 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -224,17 +224,17 @@ blocks: models: - path: "minecraft:block/custom/ender_pearl_crop_stage1" generation: - parent: "minecraft:block/crop" + parent: "minecraft:block/custom/tinted_cross" textures: - "crop": "minecraft:block/custom/ender_pearl_crop_stage1" + "cross": "minecraft:block/custom/ender_pearl_crop_stage1" ripe: state: "sugar_cane:4" models: - path: "minecraft:block/custom/ender_pearl_crop_stage2" generation: - parent: "minecraft:block/crop" + parent: "minecraft:block/custom/tinted_cross" textures: - "crop": "minecraft:block/custom/ender_pearl_crop_stage2" + "cross": "minecraft:block/custom/ender_pearl_crop_stage2" variants: age=0: appearance: default diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json new file mode 100644 index 000000000..37c8b09f2 --- /dev/null +++ b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json @@ -0,0 +1,26 @@ +{ + "ambientocclusion": false, + "textures": { + "particle": "#cross" + }, + "elements": [ + { "from": [ 0.8, 0, 8 ], + "to": [ 15.2, 16, 8 ], + "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": 45, "rescale": true }, + "shade": false, + "faces": { + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" } + } + }, + { "from": [ 8, 0, 0.8 ], + "to": [ 8, 16, 15.2 ], + "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": 45, "rescale": true }, + "shade": false, + "faces": { + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" } + } + } + ] +} From 736627ab8bc1a62c5b58870e621ee0246e0054d3 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 20:25:31 +0800 Subject: [PATCH 18/28] refactor crops --- .../default/configuration/categories.yml | 2 +- .../resources/default/configuration/i18n.yml | 4 +- .../default/configuration/plants.yml | 87 ++++++------- .../default/configuration/templates.yml | 115 +++++++++++++++++- .../models/block/custom/tinted_cross.json | 26 ---- .../bukkit/api/CraftEngineBlocks.java | 5 - .../bukkit/block/BlockEventListener.java | 10 -- .../block/behavior/BushBlockBehavior.java | 5 - .../block/behavior/CropBlockBehavior.java | 3 + .../config/additional-real-blocks.yml | 6 +- .../craftengine/core/loot/LootTable.java | 9 +- .../loot/condition/CropRipeCondition.java | 29 ----- .../core/loot/condition/LootConditions.java | 4 +- .../MatchBlockPropertyCondition.java | 58 +++++++++ .../function/ApplyBonusCountFunction.java | 39 ++++++ .../core/loot/parameter/LootParameters.java | 1 - .../craftengine/core/util/MiscUtils.java | 10 ++ 17 files changed, 270 insertions(+), 143 deletions(-) delete mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml index 328706d8c..f7678758f 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml @@ -62,4 +62,4 @@ categories: - default:flame_cane - default:gunpowder_block - default:solid_gunpowder_block - - default:ender_pearl_crop_seed \ No newline at end of file + - default:ender_pearl_flower_seed \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml index 4e3cc366f..23a9f8b8a 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml @@ -4,7 +4,7 @@ i18n: item.fairy_flower: "Fairy Flower" item.reed: "Reed" item.flame_cane: "Flame Cane" - item.ender_pearl_crop_seed: "Ender Pearl Flower Seeds" + item.ender_pearl_flower_seed: "Ender Pearl Flower Seeds" item.bench: "Bench" item.table_lamp: "Table Lamp" item.wooden_chair: "Wooden Chair" @@ -44,7 +44,7 @@ i18n: item.fairy_flower: "仙灵花" item.reed: "芦苇" item.flame_cane: "烈焰甘蔗" - item.ender_pearl_crop_seed: "末影珍珠花种子" + item.ender_pearl_flower_seed: "末影珍珠花种子" item.bench: "长椅" item.table_lamp: "台灯" item.wooden_chair: "木椅" diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 988d348dd..961e7bdbc 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -35,18 +35,18 @@ items: behavior: type: block_item block: default:flame_cane - default:ender_pearl_crop_seed: + default:ender_pearl_flower_seed: material: paper custom-model-data: 4003 data: - item-name: "" + item-name: "" model: template: default:model/simplified_generated arguments: - path: "minecraft:block/custom/ender_pearl_crop_seed" + path: "minecraft:block/custom/ender_pearl_flower_seed" behavior: type: block_item - block: default:ender_pearl_crop + block: default:ender_pearl_flower blocks: default:fairy_flower: settings: @@ -179,15 +179,15 @@ blocks: age=5: appearance: default id: 7 - default:ender_pearl_crop: + default:ender_pearl_flower: settings: template: - default:hardness/none - default:sound/grass overrides: - item: default:ender_pearl_crop_seed + item: default:ender_pearl_flower_seed push-reaction: DESTROY - map-color: 15 + map-color: 24 is-randomly-ticking: true behavior: type: crop_block @@ -196,64 +196,47 @@ blocks: bottom-blocks: - minecraft:end_stone loot: - pools: - - rolls: 1 - entries: - - type: item - item: "default:ender_pearl_crop_seed" - conditions: - - type: survives_explosion - - rolls: - type: uniform - min: "1" - max: "5" - entries: - - type: item - item: "minecraft:ender_pearl" - conditions: - - type: crop_ripe + template: default:loot_table/seed_crop + arguments: + crop_item: minecraft:ender_pearl + crop_seed: default:ender_pearl_flower_seed + ripe_age: 4 states: properties: age: type: int default: 0 - range: 0~5 + range: 0~3 appearances: - default: + stage_0: + state: "tripwire:0" + models: + - path: "minecraft:block/custom/ender_pearl_flower_stage_0" + stage_1: + state: "tripwire:1" + models: + - path: "minecraft:block/custom/ender_pearl_flower_stage_1" + stage_2: + state: "tripwire:2" + models: + - path: "minecraft:block/custom/ender_pearl_flower_stage_2" + stage_3: state: "sugar_cane:3" models: - - path: "minecraft:block/custom/ender_pearl_crop_stage1" - generation: - parent: "minecraft:block/custom/tinted_cross" - textures: - "cross": "minecraft:block/custom/ender_pearl_crop_stage1" - ripe: - state: "sugar_cane:4" - models: - - path: "minecraft:block/custom/ender_pearl_crop_stage2" - generation: - parent: "minecraft:block/custom/tinted_cross" - textures: - "cross": "minecraft:block/custom/ender_pearl_crop_stage2" + - path: "minecraft:block/custom/ender_pearl_flower_stage_3" variants: age=0: - appearance: default - id: 8 + appearance: stage_0 + id: 0 age=1: - appearance: default - id: 9 + appearance: stage_1 + id: 1 age=2: - appearance: default - id: 10 + appearance: stage_2 + id: 2 age=3: - appearance: default - id: 11 - age=4: - appearance: default - id: 12 - age=5: - appearance: ripe - id: 13 + appearance: stage_3 + id: 8 recipes: default:paper_from_reed: type: shaped diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml b/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml index f20f99fcc..641bf7396 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/templates.yml @@ -953,7 +953,12 @@ templates#recipes: # loot tables templates#loot_tables: + # drop one item + + # template: default:loot_table/basic + # arguments: + # item: the item default:loot_table/basic: pools: - rolls: 1 @@ -962,7 +967,12 @@ templates#loot_tables: entries: - type: item item: "{item}" + # drop with silk touch + + # template: default:loot_table/silk_touch + # arguments: + # item: the item default:loot_table/silk_touch: pools: - rolls: 1 @@ -972,7 +982,78 @@ templates#loot_tables: entries: - type: item item: "{item}" - # drop ores + + # crop drops + + # template: default:loot_table/seed_crop + # arguments: + # crop_item: the ripe crop + # crop_seed: the seed of the crop + # ripe_age: the max age + default:loot_table/seed_crop: + pools: + - rolls: 1 + entries: + - type: alternatives + children: + - type: item + item: "{crop_item}" + conditions: + - type: match_block_property + properties: + age: "{ripe_age}" + - type: item + item: "{crop_seed}" + - rolls: 1 + conditions: + - type: match_block_property + properties: + age: "{ripe_age}" + entries: + - type: item + item: "{crop_seed}" + functions: + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: binomial_with_bonus_count + extra: 3 + probability: 0.5714286 + + # template: default:loot_table/crop + # arguments: + # crop_item: the ripe crop + # ripe_age: the max age + default:loot_table/crop: + pools: + - rolls: 1 + entries: + - type: item + item: "{crop_item}" + - rolls: 1 + conditions: + - type: match_block_property + properties: + age: "{ripe_age}" + entries: + - type: item + item: "{crop_item}" + functions: + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: binomial_with_bonus_count + extra: 3 + probability: 0.5714286 + + # ore drops + + # template: default:loot_table/ore + # arguments: + # ore_block: the ore block + # ore_drop: the drops of the ore + # min_exp: the min exp to drop + # max_exp: the max exp to drop default:loot_table/ore: pools: - rolls: 1 @@ -997,7 +1078,37 @@ templates#loot_tables: type: uniform min: "{min_exp}" max: "{max_exp}" - # leaves + + # template: default:loot_table/ore_no_exp + # arguments: + # ore_block: the ore block + # ore_drop: the drops of the ore + default:loot_table/ore_no_exp: + pools: + - rolls: 1 + entries: + - type: alternatives + children: + - type: item + item: "{ore_block}" + conditions: + - type: enchantment + predicate: minecraft:silk_touch>=1 + - type: item + item: "{ore_drop}" + functions: + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: ore_drops + - type: explosion_decay + + # leaves drops + + # template: default:loot_table/leaves + # arguments: + # leaves: the leaves block + # sapling: the sapling item default:loot_table/leaves: pools: - rolls: 1 diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json deleted file mode 100644 index 37c8b09f2..000000000 --- a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/tinted_cross.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "ambientocclusion": false, - "textures": { - "particle": "#cross" - }, - "elements": [ - { "from": [ 0.8, 0, 8 ], - "to": [ 15.2, 16, 8 ], - "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": 45, "rescale": true }, - "shade": false, - "faces": { - "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" }, - "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" } - } - }, - { "from": [ 8, 0, 0.8 ], - "to": [ 8, 16, 15.2 ], - "rotation": { "origin": [ 8, 8, 8 ], "axis": "y", "angle": 45, "rescale": true }, - "shade": false, - "faces": { - "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" }, - "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#cross" } - } - } - ] -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index 7f2ad0a7b..7c716c0a6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -182,11 +182,6 @@ public final class CraftEngineBlocks { builder.withParameter(LootParameters.PLAYER, serverPlayer); builder.withOptionalParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); } - if (state.behavior() instanceof CropBlockBehavior cropBlockBehavior) { - if (cropBlockBehavior.isMaxAge(state)) { - builder.withParameter(LootParameters.CROP_RIPE, true); - } - } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 0bdc7364f..58ef2c0c0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -139,11 +139,6 @@ public class BlockEventListener implements Listener { builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.PLAYER, serverPlayer); builder.withOptionalParameter(LootParameters.TOOL, itemInHand); - if (state.behavior() instanceof CropBlockBehavior cropBlockBehavior) { - if (cropBlockBehavior.isMaxAge(state)) { - builder.withParameter(LootParameters.CROP_RIPE, true); - } - } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } @@ -302,11 +297,6 @@ public class BlockEventListener implements Listener { if (yield < 1f) { builder.withParameter(LootParameters.EXPLOSION_RADIUS, 1.0f / yield); } - if (state.behavior() instanceof CropBlockBehavior cropBlockBehavior) { - if (cropBlockBehavior.isMaxAge(state)) { - builder.withParameter(LootParameters.CROP_RIPE, true); - } - } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index f5226c5f8..13b6e32ae 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -71,11 +71,6 @@ public class BushBlockBehavior extends AbstractBlockBehavior { net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.WORLD, world); - if (this instanceof CropBlockBehavior cropBlockBehavior) { - if (cropBlockBehavior.isMaxAge(state)) { - builder.withParameter(LootParameters.CROP_RIPE, true); - } - } for (Item item : previousState.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index a9449b023..a90f2366e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -1,6 +1,7 @@ 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.Reflections; import net.momirealms.craftengine.core.block.CustomBlock; @@ -37,6 +38,7 @@ public class CropBlockBehavior extends BushBlockBehavior { public final boolean isMaxAge(Object state) { return this.getAge(state) >= this.ageProperty.max; } + public final boolean isMaxAge(ImmutableBlockState state) { return this.getAge(state) >= this.ageProperty.max; } @@ -48,6 +50,7 @@ public class CropBlockBehavior extends BushBlockBehavior { public final int getAge(Object state) { return getCEBlockState(state).get(ageProperty); } + public final int getAge(ImmutableBlockState state) { return state.get(ageProperty); } diff --git a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/config/additional-real-blocks.yml b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/config/additional-real-blocks.yml index 91993a87d..4fe5d6d61 100644 --- a/client-mod/src/main/resources/assets/craft-engine-fabric-mod/config/additional-real-blocks.yml +++ b/client-mod/src/main/resources/assets/craft-engine-fabric-mod/config/additional-real-blocks.yml @@ -14,9 +14,7 @@ # Q: When do I need to configure this file? # A: When the number of real block IDs is insufficient, but there are still available appearances. -# By default, the plugin only registers an additional 112 oak leaf block states (for the default configuration needs [>=28 states]). minecraft:oak_leaves: 112 - minecraft:oak_sapling: 1 minecraft:birch_sapling: 1 minecraft:spruce_sapling: 1 @@ -24,5 +22,5 @@ minecraft:jungle_sapling: 1 minecraft:dark_oak_sapling: 1 minecraft:acacia_sapling: 1 minecraft:cherry_sapling: 1 - -minecraft:anvil: 2 \ No newline at end of file +minecraft:anvil: 2 +minecraft:sugarcane: 14 \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java index 94bc14963..0af5630ca 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootTable.java @@ -10,6 +10,7 @@ import net.momirealms.craftengine.core.loot.function.LootFunction; import net.momirealms.craftengine.core.loot.function.LootFunctions; import net.momirealms.craftengine.core.loot.number.NumberProvider; import net.momirealms.craftengine.core.loot.number.NumberProviders; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.context.ContextHolder; import net.momirealms.craftengine.core.world.World; import org.jetbrains.annotations.Nullable; @@ -43,19 +44,19 @@ public class LootTable { NumberProvider rolls = NumberProviders.fromObject(pool.getOrDefault("rolls", 1)); NumberProvider bonus_rolls = NumberProviders.fromObject(pool.getOrDefault("bonus_rolls", 0)); List conditions = Optional.ofNullable(pool.get("conditions")) - .map(it -> LootConditions.fromMapList((List>) it)) + .map(it -> LootConditions.fromMapList(MiscUtils.castToMapListOrThrow(it, () -> new RuntimeException("'conditions' should be a map list, current type: " + it.getClass().getSimpleName())))) .orElse(Lists.newArrayList()); List> containers = Optional.ofNullable(pool.get("entries")) - .map(it -> (List>) new ArrayList>(LootEntryContainers.fromMapList((List>) it))) + .map(it -> (List>) new ArrayList>(LootEntryContainers.fromMapList(MiscUtils.castToMapListOrThrow(it, () -> new RuntimeException("'entries' should be a map list, current type: " + it.getClass().getSimpleName()))))) .orElse(Lists.newArrayList()); List> functions = Optional.ofNullable(pool.get("functions")) - .map(it -> (List>) new ArrayList>(LootFunctions.fromMapList((List>) it))) + .map(it -> (List>) new ArrayList>(LootFunctions.fromMapList(MiscUtils.castToMapListOrThrow(it, () -> new RuntimeException("'functions' should be a map list, current type: " + it.getClass().getSimpleName()))))) .orElse(Lists.newArrayList()); lootPools.add(new LootPool<>(containers, conditions, functions, rolls, bonus_rolls)); } return new LootTable<>(lootPools, Optional.ofNullable(map.get("functions")) - .map(it -> (List>) new ArrayList>(LootFunctions.fromMapList((List>) it))) + .map(it -> (List>) new ArrayList>(LootFunctions.fromMapList(MiscUtils.castToMapListOrThrow(it, () -> new RuntimeException("'functions' should be a map list, current type: " + it.getClass().getSimpleName()))))) .orElse(Lists.newArrayList()) ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java deleted file mode 100644 index 10d30ac74..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/CropRipeCondition.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.momirealms.craftengine.core.loot.condition; - -import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; -import net.momirealms.craftengine.core.util.Key; - -import java.util.Map; - -public class CropRipeCondition implements LootCondition { - public static final Factory FACTORY = new Factory(); - public static final CropRipeCondition INSTANCE = new CropRipeCondition(); - - @Override - public Key type() { - return LootConditions.CROP_RIPE; - } - - @Override - public boolean test(LootContext lootContext) { - return lootContext.getOptionalParameter(LootParameters.CROP_RIPE).orElse(false); - } - - public static class Factory implements LootConditionFactory { - @Override - public LootCondition create(Map arguments) { - return INSTANCE; - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java index 4dd4ffabc..1ee957df9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java @@ -14,6 +14,7 @@ import java.util.function.Predicate; public class LootConditions { public static final Key MATCH_ITEM = Key.from("craftengine:match_item"); + public static final Key MATCH_BLOCK_PROPERTY = Key.from("craftengine:match_block_property"); public static final Key TABLE_BONUS = Key.from("craftengine:table_bonus"); public static final Key SURVIVES_EXPLOSION = Key.from("craftengine:survives_explosion"); public static final Key ANY_OF = Key.from("craftengine:any_of"); @@ -21,10 +22,10 @@ public class LootConditions { public static final Key ENCHANTMENT = Key.from("craftengine:enchantment"); public static final Key INVERTED = Key.from("craftengine:inverted"); public static final Key FALLING_BLOCK = Key.from("craftengine:falling_block"); - public static final Key CROP_RIPE = Key.from("craftengine:crop_ripe"); static { register(MATCH_ITEM, MatchItemCondition.FACTORY); + register(MATCH_BLOCK_PROPERTY, MatchBlockPropertyCondition.FACTORY); register(TABLE_BONUS, TableBonusCondition.FACTORY); register(SURVIVES_EXPLOSION, SurvivesExplosionCondition.FACTORY); register(ANY_OF, AnyOfCondition.FACTORY); @@ -32,7 +33,6 @@ public class LootConditions { register(ENCHANTMENT, EnchantmentCondition.FACTORY); register(INVERTED, InvertedCondition.FACTORY); register(FALLING_BLOCK, FallingCondition.FACTORY); - register(CROP_RIPE, CropRipeCondition.FACTORY); } public static void register(Key key, LootConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java new file mode 100644 index 000000000..a56ea70ea --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java @@ -0,0 +1,58 @@ +package net.momirealms.craftengine.core.loot.condition; + +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.loot.LootContext; +import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.Pair; + +import java.util.*; + +public class MatchBlockPropertyCondition implements LootCondition { + public static final Factory FACTORY = new Factory(); + private final List> properties; + + public MatchBlockPropertyCondition(List> properties) { + this.properties = properties; + } + + @Override + public Key type() { + return LootConditions.MATCH_BLOCK_PROPERTY; + } + + @Override + public boolean test(LootContext lootContext) { + return lootContext.getOptionalParameter(LootParameters.BLOCK_STATE).map(state -> { + CustomBlock block = state.owner().value(); + for (Pair property : this.properties) { + Property propertyIns = block.getProperty(property.left()); + if (propertyIns == null) { + return false; + } + if (!state.get(propertyIns).toString().toLowerCase(Locale.ENGLISH).equals(property.right())) { + return false; + } + } + return true; + }).orElse(false); + } + + public static class Factory implements LootConditionFactory { + + @SuppressWarnings("unchecked") + @Override + public LootCondition create(Map arguments) { + Map properties = (Map) arguments.get("properties"); + if (properties == null) { + throw new IllegalArgumentException("Missing 'properties' argument for 'match_block_property'"); + } + List> propertyList = new ArrayList<>(); + for (Map.Entry entry : properties.entrySet()) { + propertyList.add(new Pair<>(entry.getKey(), entry.getValue().toString())); + } + return new MatchBlockPropertyCondition(propertyList); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java index 219f0f44f..180e6c100 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/ApplyBonusCountFunction.java @@ -12,6 +12,7 @@ import net.momirealms.craftengine.core.registry.Registries; import net.momirealms.craftengine.core.registry.WritableRegistry; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceKey; import java.util.Collections; @@ -78,9 +79,11 @@ public class ApplyBonusCountFunction extends AbstractLootConditionalFunction< public static class Formulas { public static final Key ORE_DROPS = Key.of("craftengine:ore_drops"); + public static final Key CROP_DROPS = Key.of("craftengine:binomial_with_bonus_count"); static { register(ORE_DROPS, OreDrops.FACTORY); + register(CROP_DROPS, CropDrops.FACTORY); } public static void register(Key key, FormulaFactory factory) { @@ -133,4 +136,40 @@ public class ApplyBonusCountFunction extends AbstractLootConditionalFunction< } } } + + public static class CropDrops implements Formula { + public static final Factory FACTORY = new Factory(); + private final int extra; + private final float probability; + + public CropDrops(int extra, float probability) { + this.extra = extra; + this.probability = probability; + } + + @Override + public int apply(int initialCount, int enchantmentLevel) { + for (int i = 0; i < enchantmentLevel + this.extra; i++) { + if (RandomUtils.generateRandomFloat(0,1) < this.probability) { + initialCount++; + } + } + return initialCount; + } + + @Override + public Key type() { + return Formulas.CROP_DROPS; + } + + public static class Factory implements FormulaFactory { + + @Override + public Formula create(Map arguments) { + int extra = MiscUtils.getAsInt(arguments.getOrDefault("extra", 1)); + float probability = MiscUtils.getAsFloat(arguments.getOrDefault("probability", 0.5f)); + return new CropDrops(extra, probability); + } + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java b/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java index 35e145b56..ca09453ea 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/parameter/LootParameters.java @@ -18,5 +18,4 @@ public class LootParameters { public static final ContextKey PLAYER = new ContextKey<>(Key.of("craftengine:player")); public static final ContextKey> TOOL = new ContextKey<>(Key.of("craftengine:tool")); public static final ContextKey BLOCK_STATE = new ContextKey<>(Key.of("craftengine:block_state")); - public static final ContextKey CROP_RIPE = new ContextKey<>(Key.of("craftengine:crop_ripe")); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java index 28b8f4a42..dfb84b83e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java @@ -6,6 +6,7 @@ import org.joml.Vector3f; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.function.Supplier; public class MiscUtils { @@ -22,6 +23,15 @@ public class MiscUtils { throw new IllegalArgumentException("Expected Map, got: " + obj.getClass().getSimpleName()); } + @SuppressWarnings("unchecked") + public static List> castToMapListOrThrow(Object obj, Supplier exceptionSupplier) { + if (obj instanceof List list) { + return (List>) list; + } else { + throw exceptionSupplier.get(); + } + } + @SuppressWarnings("unchecked") public static List castToList(Object obj, boolean allowNull) { if (allowNull && obj == null) { From 1c5582308759191f70d9aaa781513877f945c974 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 20:33:34 +0800 Subject: [PATCH 19/28] added random condition --- .../default/configuration/plants.yml | 21 ++++++++++- .../core/loot/condition/LootConditions.java | 2 + .../core/loot/condition/RandomCondition.java | 37 +++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/loot/condition/RandomCondition.java diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 961e7bdbc..05ef4a11f 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -268,4 +268,23 @@ recipes: B2: "default:flame_cane" result: id: minecraft:magma_block - count: 2 \ No newline at end of file + count: 2 +vanilla-loots: + minecraft:ender_pearl_flower_seed_from_endermite: + type: entity + target: "minecraft:endermite" + override: false + loot: + pools: + - rolls: 1 + conditions: + - type: table_bonus + enchantment: minecraft:looting + chances: + - 0.1 + - 0.5 + - 0.8 + - 1 + entries: + - type: item + item: "default:ender_pearl_flower_seed" \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java index 1ee957df9..7fac12892 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/LootConditions.java @@ -17,6 +17,7 @@ public class LootConditions { public static final Key MATCH_BLOCK_PROPERTY = Key.from("craftengine:match_block_property"); public static final Key TABLE_BONUS = Key.from("craftengine:table_bonus"); public static final Key SURVIVES_EXPLOSION = Key.from("craftengine:survives_explosion"); + public static final Key RANDOM = Key.from("craftengine:random"); public static final Key ANY_OF = Key.from("craftengine:any_of"); public static final Key ALL_OF = Key.from("craftengine:all_of"); public static final Key ENCHANTMENT = Key.from("craftengine:enchantment"); @@ -33,6 +34,7 @@ public class LootConditions { register(ENCHANTMENT, EnchantmentCondition.FACTORY); register(INVERTED, InvertedCondition.FACTORY); register(FALLING_BLOCK, FallingCondition.FACTORY); + register(RANDOM, RandomCondition.FACTORY); } public static void register(Key key, LootConditionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/RandomCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/RandomCondition.java new file mode 100644 index 000000000..471caa605 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/RandomCondition.java @@ -0,0 +1,37 @@ +package net.momirealms.craftengine.core.loot.condition; + +import net.momirealms.craftengine.core.loot.LootContext; +import net.momirealms.craftengine.core.loot.parameter.LootParameters; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.RandomUtils; + +import java.util.Map; +import java.util.Optional; + +public class RandomCondition implements LootCondition { + public static final Factory FACTORY = new Factory(); + private final float chance; + + public RandomCondition(float chance) { + this.chance = chance; + } + + @Override + public Key type() { + return LootConditions.RANDOM; + } + + @Override + public boolean test(LootContext lootContext) { + return RandomUtils.generateRandomFloat(0, 1) < this.chance; + } + + public static class Factory implements LootConditionFactory { + @Override + public LootCondition create(Map arguments) { + float chance = MiscUtils.getAsFloat(arguments.getOrDefault("value", 0.5f)); + return new RandomCondition(chance); + } + } +} From 6ead653923be2bdfaaa886fe9218ce59b970040e Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 20:41:31 +0800 Subject: [PATCH 20/28] Update plants.yml --- .../main/resources/resources/default/configuration/plants.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 05ef4a11f..e5e40e9d5 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -200,7 +200,7 @@ blocks: arguments: crop_item: minecraft:ender_pearl crop_seed: default:ender_pearl_flower_seed - ripe_age: 4 + ripe_age: 3 states: properties: age: From 7fcd4f1d1ee878829e0e7aea416194fc3bf42831 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 21:33:04 +0800 Subject: [PATCH 21/28] move other plugins to compatibility module --- bukkit/build.gradle.kts | 6 ------ bukkit/compatibility/build.gradle.kts | 7 +++++++ .../bukkit/compatibility}/papi/ImageExpansion.java | 2 +- .../bukkit/compatibility/papi}/PlaceholderAPIUtils.java | 8 +++++++- .../bukkit/compatibility}/papi/ShiftExpansion.java | 2 +- .../compatibility}/worldedit/WorldEditBlockRegister.java | 2 +- .../craftengine/bukkit/block/BukkitBlockManager.java | 3 +-- .../block/{worldedit => }/WorldEditCommandHelper.java | 3 +-- .../craftengine/bukkit/plugin/BukkitCraftEngine.java | 9 ++++----- 9 files changed, 23 insertions(+), 19 deletions(-) rename bukkit/{src/main/java/net/momirealms/craftengine/bukkit/plugin => compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility}/papi/ImageExpansion.java (97%) rename bukkit/{src/main/java/net/momirealms/craftengine/bukkit/util => compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi}/PlaceholderAPIUtils.java (50%) rename bukkit/{src/main/java/net/momirealms/craftengine/bukkit/plugin => compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility}/papi/ShiftExpansion.java (97%) rename bukkit/{src/main/java/net/momirealms/craftengine/bukkit/block => compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility}/worldedit/WorldEditBlockRegister.java (93%) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/{worldedit => }/WorldEditCommandHelper.java (95%) diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index 356626a34..7b21b01a6 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -5,9 +5,7 @@ plugins { repositories { maven("https://jitpack.io/") - maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // papi maven("https://repo.papermc.io/repository/maven-public/") - maven("https://maven.enginehub.org/repo/") // worldguard worldedit maven("https://repo.momirealms.net/releases/") mavenCentral() } @@ -24,8 +22,6 @@ dependencies { compileOnly("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}") // NMS compileOnly("net.momirealms:craft-engine-nms-helper:${rootProject.properties["nms_helper_version"]}") - // Placeholder - compileOnly("me.clip:placeholderapi:${rootProject.properties["placeholder_api_version"]}") // Platform compileOnly("dev.folia:folia-api:${rootProject.properties["paper_version"]}-R0.1-SNAPSHOT") // OpenGL Math @@ -56,8 +52,6 @@ dependencies { compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}") { exclude("com.google.code.gson", "gson") } - compileOnly("com.sk89q.worldedit:worldedit-core:7.2.19") - compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.19") // Data Fixer Upper compileOnly("com.mojang:datafixerupper:${rootProject.properties["datafixerupper_version"]}") // BStats diff --git a/bukkit/compatibility/build.gradle.kts b/bukkit/compatibility/build.gradle.kts index bc8304b72..55c07995f 100644 --- a/bukkit/compatibility/build.gradle.kts +++ b/bukkit/compatibility/build.gradle.kts @@ -2,6 +2,8 @@ repositories { mavenCentral() maven("https://repo.papermc.io/repository/maven-public/") maven("https://r.irepo.space/maven/") + maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // papi + maven("https://maven.enginehub.org/repo/") // worldguard worldedit } dependencies { @@ -10,6 +12,11 @@ dependencies { compileOnly("dev.folia:folia-api:${rootProject.properties["paper_version"]}-R0.1-SNAPSHOT") // NeigeItems compileOnly("pers.neige.neigeitems:NeigeItems:1.21.42") + // Placeholder + compileOnly("me.clip:placeholderapi:${rootProject.properties["placeholder_api_version"]}") + // WorldEdit + compileOnly("com.sk89q.worldedit:worldedit-core:7.2.19") + compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.19") } java { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/papi/ImageExpansion.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/ImageExpansion.java similarity index 97% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/papi/ImageExpansion.java rename to bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/ImageExpansion.java index 9a5ca429c..4f527f7af 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/papi/ImageExpansion.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/ImageExpansion.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.bukkit.plugin.papi; +package net.momirealms.craftengine.bukkit.compatibility.papi; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import net.momirealms.craftengine.core.font.BitmapImage; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlaceholderAPIUtils.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/PlaceholderAPIUtils.java similarity index 50% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlaceholderAPIUtils.java rename to bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/PlaceholderAPIUtils.java index 200ab0b88..824236dda 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlaceholderAPIUtils.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/PlaceholderAPIUtils.java @@ -1,6 +1,7 @@ -package net.momirealms.craftengine.bukkit.util; +package net.momirealms.craftengine.bukkit.compatibility.papi; import me.clip.placeholderapi.PlaceholderAPI; +import net.momirealms.craftengine.core.plugin.CraftEngine; import org.bukkit.OfflinePlayer; public class PlaceholderAPIUtils { @@ -10,4 +11,9 @@ public class PlaceholderAPIUtils { public static String parse(OfflinePlayer player, String text) { return PlaceholderAPI.setPlaceholders(player, text); } + + public static void registerExpansions(CraftEngine plugin) { + new ImageExpansion(plugin).register(); + new ShiftExpansion(plugin).register(); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/papi/ShiftExpansion.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/ShiftExpansion.java similarity index 97% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/papi/ShiftExpansion.java rename to bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/ShiftExpansion.java index f8650a55d..ea10750f9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/papi/ShiftExpansion.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/papi/ShiftExpansion.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.bukkit.plugin.papi; +package net.momirealms.craftengine.bukkit.compatibility.papi; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import net.momirealms.craftengine.core.plugin.CraftEngine; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/worldedit/WorldEditBlockRegister.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/WorldEditBlockRegister.java similarity index 93% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/worldedit/WorldEditBlockRegister.java rename to bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/WorldEditBlockRegister.java index 279ada1c2..6905c77c7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/worldedit/WorldEditBlockRegister.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/worldedit/WorldEditBlockRegister.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.bukkit.block.worldedit; +package net.momirealms.craftengine.bukkit.compatibility.worldedit; import com.sk89q.worldedit.bukkit.BukkitBlockRegistry; import com.sk89q.worldedit.util.concurrency.LazyReference; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index 014a5a5d5..0757e0cf4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -7,8 +7,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import dev.dejvokep.boostedyaml.YamlDocument; -import net.momirealms.craftengine.bukkit.block.worldedit.WorldEditBlockRegister; -import net.momirealms.craftengine.bukkit.block.worldedit.WorldEditCommandHelper; +import net.momirealms.craftengine.bukkit.compatibility.worldedit.WorldEditBlockRegister; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/worldedit/WorldEditCommandHelper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/WorldEditCommandHelper.java similarity index 95% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/worldedit/WorldEditCommandHelper.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/WorldEditCommandHelper.java index cdd32e55d..88839c776 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/worldedit/WorldEditCommandHelper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/WorldEditCommandHelper.java @@ -1,6 +1,5 @@ -package net.momirealms.craftengine.bukkit.block.worldedit; +package net.momirealms.craftengine.bukkit.block; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.block.BlockStateParser; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index b86f0af22..6fae96c4d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -17,13 +17,13 @@ import net.momirealms.craftengine.bukkit.plugin.command.BukkitSenderFactory; import net.momirealms.craftengine.bukkit.plugin.gui.BukkitGuiManager; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; -import net.momirealms.craftengine.bukkit.plugin.papi.ImageExpansion; -import net.momirealms.craftengine.bukkit.plugin.papi.ShiftExpansion; +import net.momirealms.craftengine.bukkit.compatibility.papi.ImageExpansion; +import net.momirealms.craftengine.bukkit.compatibility.papi.ShiftExpansion; import net.momirealms.craftengine.bukkit.plugin.scheduler.BukkitSchedulerAdapter; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.sound.BukkitSoundManager; import net.momirealms.craftengine.bukkit.util.EventUtils; -import net.momirealms.craftengine.bukkit.util.PlaceholderAPIUtils; +import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; import net.momirealms.craftengine.core.entity.player.Player; @@ -176,8 +176,7 @@ public class BukkitCraftEngine extends CraftEngine { // compatibility // register expansion if (this.isPluginEnabled("PlaceholderAPI")) { - new ShiftExpansion(this).register(); - new ImageExpansion(this).register(); + PlaceholderAPIUtils.registerExpansions(this); this.hasPlaceholderAPI = true; } } From 80570d6f42d8fc25681d436f5f329bec79dea3f1 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 28 Mar 2025 21:33:15 +0800 Subject: [PATCH 22/28] code clean up --- .../momirealms/craftengine/bukkit/api/CraftEngineBlocks.java | 1 - .../craftengine/bukkit/block/BlockEventListener.java | 1 - .../craftengine/bukkit/block/behavior/CropBlockBehavior.java | 1 - .../craftengine/bukkit/item/recipe/BukkitRecipeManager.java | 2 +- .../craftengine/bukkit/item/recipe/RecipeEventListener.java | 2 +- .../craftengine/bukkit/plugin/BukkitCraftEngine.java | 4 +--- .../craftengine/bukkit/plugin/user/BukkitServerPlayer.java | 2 +- .../core/loot/condition/MatchBlockPropertyCondition.java | 5 ++++- .../craftengine/core/loot/condition/RandomCondition.java | 2 -- .../core/plugin/gui/category/ItemBrowserManagerImpl.java | 2 +- 10 files changed, 9 insertions(+), 13 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index 7c716c0a6..ed4dc7d2e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.api; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.block.behavior.CropBlockBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index 58ef2c0c0..befb9a1e2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.bukkit.block; import io.papermc.paper.event.block.BlockBreakBlockEvent; import net.momirealms.craftengine.bukkit.api.event.CustomBlockBreakEvent; -import net.momirealms.craftengine.bukkit.block.behavior.CropBlockBehavior; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index a90f2366e..21e375a24 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -1,7 +1,6 @@ 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.Reflections; import net.momirealms.craftengine.core.block.CustomBlock; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 00d3087e4..a6d749316 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -12,8 +12,8 @@ import net.momirealms.craftengine.bukkit.util.RecipeUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.recipe.*; import net.momirealms.craftengine.core.item.recipe.Recipe; +import net.momirealms.craftengine.core.item.recipe.*; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.vanilla.*; import net.momirealms.craftengine.core.item.recipe.vanilla.reader.VanillaRecipeReader1_20; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 02a555fad..c513dc9b1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -11,8 +11,8 @@ import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.*; -import net.momirealms.craftengine.core.item.recipe.*; import net.momirealms.craftengine.core.item.recipe.Recipe; +import net.momirealms.craftengine.core.item.recipe.*; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index 6fae96c4d..9bb2e79a6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -4,6 +4,7 @@ import net.momirealms.antigrieflib.AntiGriefLib; import net.momirealms.craftengine.bukkit.api.event.CraftEngineReloadEvent; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.block.behavior.BukkitBlockBehaviors; +import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; import net.momirealms.craftengine.bukkit.font.BukkitImageManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; @@ -17,13 +18,10 @@ import net.momirealms.craftengine.bukkit.plugin.command.BukkitSenderFactory; import net.momirealms.craftengine.bukkit.plugin.gui.BukkitGuiManager; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; -import net.momirealms.craftengine.bukkit.compatibility.papi.ImageExpansion; -import net.momirealms.craftengine.bukkit.compatibility.papi.ShiftExpansion; import net.momirealms.craftengine.bukkit.plugin.scheduler.BukkitSchedulerAdapter; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.sound.BukkitSoundManager; import net.momirealms.craftengine.bukkit.util.EventUtils; -import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; import net.momirealms.craftengine.core.entity.player.Player; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index f6f38caa2..030a31379 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java @@ -18,8 +18,8 @@ import net.momirealms.craftengine.core.plugin.network.ConnectionState; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.world.*; import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.*; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.inventory.EquipmentSlot; diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java index a56ea70ea..24c91cd6e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/MatchBlockPropertyCondition.java @@ -7,7 +7,10 @@ import net.momirealms.craftengine.core.loot.parameter.LootParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Pair; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; public class MatchBlockPropertyCondition implements LootCondition { public static final Factory FACTORY = new Factory(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/RandomCondition.java b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/RandomCondition.java index 471caa605..547daf8ed 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/condition/RandomCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/condition/RandomCondition.java @@ -1,13 +1,11 @@ package net.momirealms.craftengine.core.loot.condition; import net.momirealms.craftengine.core.loot.LootContext; -import net.momirealms.craftengine.core.loot.parameter.LootParameters; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.RandomUtils; import java.util.Map; -import java.util.Optional; public class RandomCondition implements LootCondition { public static final Factory FACTORY = new Factory(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index 12460c8c5..2b203b19d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -7,8 +7,8 @@ import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.item.recipe.*; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.gui.*; import net.momirealms.craftengine.core.plugin.gui.Ingredient; +import net.momirealms.craftengine.core.plugin.gui.*; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; From cd30c5b3b3f3acb0134b6386850f820d86bffd6d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 29 Mar 2025 00:39:09 +0800 Subject: [PATCH 23/28] add crop block --- bukkit/compatibility/build.gradle.kts | 6 ++ .../slimeworld/SlimeFormatStorageAdaptor.java | 40 ++++++++++ .../slimeworld/SlimeWorldDataStorage.java | 68 +++++++++++++++++ .../default/configuration/categories.yml | 2 +- .../resources/default/configuration/i18n.yml | 4 +- .../resources/default/configuration/icons.yml | 2 +- .../default/configuration/plants.yml | 42 ++++++----- .../custom/ender_pearl_flower_stage_3.json | 43 +++++++++++ .../custom/ender_pearl_flower_stage_0.png | Bin 0 -> 183 bytes .../custom/ender_pearl_flower_stage_1.png | Bin 0 -> 331 bytes .../custom/ender_pearl_flower_stage_2.png | Bin 0 -> 455 bytes .../custom/ender_pearl_flower_stage_3.png | Bin 0 -> 362 bytes .../item/custom/ender_pearl_flower_seeds.png | Bin 0 -> 280 bytes .../block/behavior/CropBlockBehavior.java | 70 ++++++++---------- .../bukkit/world/BukkitCEWorld.java | 5 +- .../bukkit/world/BukkitWorldManager.java | 67 +++++++++++++---- .../core/pack/AbstractPackManager.java | 10 ++- .../craftengine/core/world/CEWorld.java | 6 +- .../craftengine/core/world/WorldManager.java | 10 +++ .../chunk/storage/DefaultStorageAdaptor.java | 13 ++++ .../world/chunk/storage/StorageAdaptor.java | 10 +++ gradle.properties | 2 +- 22 files changed, 316 insertions(+), 84 deletions(-) create mode 100644 bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java create mode 100644 bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/ender_pearl_flower_stage_3.json create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_0.png create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_1.png create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_2.png create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_3.png create mode 100644 bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/ender_pearl_flower_seeds.png create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultStorageAdaptor.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/StorageAdaptor.java diff --git a/bukkit/compatibility/build.gradle.kts b/bukkit/compatibility/build.gradle.kts index 55c07995f..71a1c68ae 100644 --- a/bukkit/compatibility/build.gradle.kts +++ b/bukkit/compatibility/build.gradle.kts @@ -4,10 +4,14 @@ repositories { maven("https://r.irepo.space/maven/") maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") // papi maven("https://maven.enginehub.org/repo/") // worldguard worldedit + maven("https://repo.rapture.pw/repository/maven-releases/") // slime world + maven("https://repo.infernalsuite.com/repository/maven-snapshots/") // slime world + maven("https://repo.momirealms.net/releases/") } dependencies { compileOnly(project(":core")) + compileOnly("net.momirealms:sparrow-nbt:${rootProject.properties["sparrow_nbt_version"]}") // Platform compileOnly("dev.folia:folia-api:${rootProject.properties["paper_version"]}-R0.1-SNAPSHOT") // NeigeItems @@ -17,6 +21,8 @@ dependencies { // WorldEdit compileOnly("com.sk89q.worldedit:worldedit-core:7.2.19") compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.19") + // SlimeWorld + compileOnly("com.infernalsuite.asp:api:4.0.0-SNAPSHOT") } java { diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java new file mode 100644 index 000000000..b5ce5a6e6 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.bukkit.compatibility.slimeworld; + +import com.infernalsuite.asp.api.AdvancedSlimePaperAPI; +import com.infernalsuite.asp.api.events.LoadSlimeWorldEvent; +import com.infernalsuite.asp.api.world.SlimeWorld; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldManager; +import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor; +import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; + +public class SlimeFormatStorageAdaptor extends DefaultStorageAdaptor implements Listener { + private final WorldManager worldManager; + + @EventHandler + public void onWorldLoad(LoadSlimeWorldEvent event) { + org.bukkit.World world = Bukkit.getWorld(event.getSlimeWorld().getName()); + this.worldManager.loadWorld(this.worldManager.wrap(world)); + } + + public SlimeFormatStorageAdaptor(WorldManager worldManager) { + this.worldManager = worldManager; + } + + public SlimeWorld getWorld(String name) { + return AdvancedSlimePaperAPI.instance().getLoadedWorld(name); + } + + @Override + public @NotNull WorldDataStorage adapt(@NotNull World world) { + SlimeWorld slimeWorld = getWorld(world.name()); + if (slimeWorld == null) { + return super.adapt(world); + } + return new SlimeWorldDataStorage(slimeWorld); + } +} diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java new file mode 100644 index 000000000..b9b63ded4 --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java @@ -0,0 +1,68 @@ +package net.momirealms.craftengine.bukkit.compatibility.slimeworld; + +import com.infernalsuite.asp.api.world.SlimeChunk; +import com.infernalsuite.asp.api.world.SlimeWorld; +import net.kyori.adventure.nbt.BinaryTag; +import net.kyori.adventure.nbt.ByteArrayBinaryTag; +import net.momirealms.craftengine.core.world.ChunkPos; +import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.NBT; +import org.jetbrains.annotations.Nullable; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.lang.ref.WeakReference; + +public class SlimeWorldDataStorage implements WorldDataStorage { + private final WeakReference slimeWorld; + + public SlimeWorldDataStorage(SlimeWorld slimeWorld) { + this.slimeWorld = new WeakReference<>(slimeWorld); + } + + public SlimeWorld getWorld() { + return slimeWorld.get(); + } + + @Nullable + @Override + public CompoundTag readChunkTagAt(ChunkPos pos) { + SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); + if (slimeChunk == null) return null; + BinaryTag tag = slimeChunk.getExtraData().get("craftengine"); + if (tag == null) return null; + ByteArrayBinaryTag byteArrayBinaryTag = (ByteArrayBinaryTag) tag; + try { + return NBT.readCompound(new DataInputStream(new ByteArrayInputStream(byteArrayBinaryTag.value()))); + } catch (IOException e) { + throw new RuntimeException("Failed to read chunk tag from slime world. " + pos, e); + } + } + + @Override + public void writeChunkTagAt(ChunkPos pos, @Nullable CompoundTag nbt) { + SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); + if (slimeChunk == null) return; + if (nbt == null) { + slimeChunk.getExtraData().remove("craftengine"); + } else { + slimeChunk.getExtraData().computeIfAbsent("craftengine", l -> { + try { + return ByteArrayBinaryTag.byteArrayBinaryTag(NBT.toBytes(nbt)); + } catch (IOException e) { + throw new RuntimeException("Failed to write chunk tag to slime world. " + pos, e); + } + }); + } + } + + @Override + public void flush() { + } + + @Override + public void close() throws IOException { + } +} diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml index f7678758f..3c8d218d6 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/categories.yml @@ -62,4 +62,4 @@ categories: - default:flame_cane - default:gunpowder_block - default:solid_gunpowder_block - - default:ender_pearl_flower_seed \ No newline at end of file + - default:ender_pearl_flower_seeds \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml index 23a9f8b8a..51b178e1b 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/i18n.yml @@ -4,7 +4,7 @@ i18n: item.fairy_flower: "Fairy Flower" item.reed: "Reed" item.flame_cane: "Flame Cane" - item.ender_pearl_flower_seed: "Ender Pearl Flower Seeds" + item.ender_pearl_flower_seeds: "Ender Pearl Flower Seeds" item.bench: "Bench" item.table_lamp: "Table Lamp" item.wooden_chair: "Wooden Chair" @@ -44,7 +44,7 @@ i18n: item.fairy_flower: "仙灵花" item.reed: "芦苇" item.flame_cane: "烈焰甘蔗" - item.ender_pearl_flower_seed: "末影珍珠花种子" + item.ender_pearl_flower_seeds: "末影珍珠花种子" item.bench: "长椅" item.table_lamp: "台灯" item.wooden_chair: "木椅" diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/icons.yml b/bukkit/loader/src/main/resources/resources/default/configuration/icons.yml index 47cda9d4c..6b2db4498 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/icons.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/icons.yml @@ -2,7 +2,7 @@ images: default:icons: height: 10 ascent: 9 - font: minecraft:default # Consider using other fonts if other plugins support custom font! + font: minecraft:icons # Do not use 'minecraft:default' unless other plugins don't support custom font! file: minecraft:font/image/icons.png chars: - '\ub000\ub001' diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index e5e40e9d5..989ef3b9a 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -35,15 +35,15 @@ items: behavior: type: block_item block: default:flame_cane - default:ender_pearl_flower_seed: + default:ender_pearl_flower_seeds: material: paper custom-model-data: 4003 data: - item-name: "" + item-name: "" model: template: default:model/simplified_generated arguments: - path: "minecraft:block/custom/ender_pearl_flower_seed" + path: "minecraft:item/custom/ender_pearl_flower_seeds" behavior: type: block_item block: default:ender_pearl_flower @@ -185,45 +185,53 @@ blocks: - default:hardness/none - default:sound/grass overrides: - item: default:ender_pearl_flower_seed + item: default:ender_pearl_flower_seeds push-reaction: DESTROY map-color: 24 is-randomly-ticking: true behavior: type: crop_block - grow-speed: 1 - min-grow-light: 9 + grow-speed: 0.25 + light-requirement: 9 bottom-blocks: - minecraft:end_stone loot: template: default:loot_table/seed_crop arguments: crop_item: minecraft:ender_pearl - crop_seed: default:ender_pearl_flower_seed - ripe_age: 3 + crop_seed: default:ender_pearl_flower_seeds + ripe_age: 2 states: properties: age: type: int default: 0 - range: 0~3 + range: 0~2 appearances: stage_0: state: "tripwire:0" models: - path: "minecraft:block/custom/ender_pearl_flower_stage_0" + generation: + parent: "minecraft:block/cross" + textures: + "cross": "minecraft:block/custom/ender_pearl_flower_stage_0" stage_1: state: "tripwire:1" models: - path: "minecraft:block/custom/ender_pearl_flower_stage_1" + generation: + parent: "minecraft:block/cross" + textures: + "cross": "minecraft:block/custom/ender_pearl_flower_stage_1" stage_2: state: "tripwire:2" models: - path: "minecraft:block/custom/ender_pearl_flower_stage_2" - stage_3: - state: "sugar_cane:3" - models: - - path: "minecraft:block/custom/ender_pearl_flower_stage_3" + generation: + parent: "minecraft:block/cross" + textures: + "cross": "minecraft:block/custom/ender_pearl_flower_stage_2" variants: age=0: appearance: stage_0 @@ -234,9 +242,6 @@ blocks: age=2: appearance: stage_2 id: 2 - age=3: - appearance: stage_3 - id: 8 recipes: default:paper_from_reed: type: shaped @@ -269,8 +274,9 @@ recipes: result: id: minecraft:magma_block count: 2 + vanilla-loots: - minecraft:ender_pearl_flower_seed_from_endermite: + minecraft:ender_pearl_flower_seeds_from_endermite: type: entity target: "minecraft:endermite" override: false @@ -287,4 +293,4 @@ vanilla-loots: - 1 entries: - type: item - item: "default:ender_pearl_flower_seed" \ No newline at end of file + item: "default:ender_pearl_flower_seeds" \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/ender_pearl_flower_stage_3.json b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/ender_pearl_flower_stage_3.json new file mode 100644 index 000000000..c65bc426f --- /dev/null +++ b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/ender_pearl_flower_stage_3.json @@ -0,0 +1,43 @@ +{ + "ambientocclusion": false, + "textures": { + "1": "item/ender_pearl", + "particle": "block/custom/ender_pearl_flower_stage_3", + "cross": "block/custom/ender_pearl_flower_stage_3" + }, + "elements": [ + { + "from": [0.8, 0, 8], + "to": [15.2, 16, 8], + "shade": false, + "rotation": {"angle": 45, "axis": "y", "origin": [8, 8, 8], "rescale": true}, + "faces": { + "north": {"uv": [0, 0, 16, 16], "texture": "#cross"}, + "south": {"uv": [0, 0, 16, 16], "texture": "#cross"} + } + }, + { + "from": [8, 0, 0.8], + "to": [8, 16, 15.2], + "shade": false, + "rotation": {"angle": 45, "axis": "y", "origin": [8, 8, 8], "rescale": true}, + "faces": { + "east": {"uv": [0, 0, 16, 16], "texture": "#cross"}, + "west": {"uv": [0, 0, 16, 16], "texture": "#cross"} + } + }, + { + "from": [8, 5, -1], + "to": [8, 21, 15], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 5, 7]}, + "faces": { + "north": {"uv": [0, 0, 0, 16], "texture": "#1"}, + "east": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "south": {"uv": [0, 0, 0, 16], "texture": "#1"}, + "west": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "up": {"uv": [0, 0, 0, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 0, 16], "texture": "#1"} + } + } + ] +} \ No newline at end of file diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_0.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_0.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd8a2d81a9792d9a23b4538f4ab2a8867f4d10d GIT binary patch literal 183 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|3O!vMLo9le z6C_v{CwMf>dNJ$&k0&!%WJ<&c`Xp}gG?~-uZLDl|Fk|wI|6Q-Tc-+6qCvGU*lDMP( zv)$p#>Hd;@Hr5RbPx$1xZ9fR5*?8kFiR_P!xv0R3AVnI3&~M1~MqP>WF}1;oY0 zEg+6gZWgSAkj3#r%bjipp>JThoe~m_Qb)lv{pTG1@0=h0>km|Tb7_Ct54JJyot-q0 zG)in5B~3r*8`gU9@(RF*(f~~2i4{_Ij_lS#NJ*aMcJ;nuT1=fdjP3Z)=lu4L3;!6s zKCl4gb4gJaPVH;N$Q@bF^$>voKr4+11i{e`>TQiy8dDi&)y!!Qv^?AHs z^qPACH3Xmy5`kd2KSVE=09-v>J6`~4lvp7pS)Ms@7+X`B4&>Jn=1+4x*TYl>VEYJd d5b$k&fDK>Fb^ZZLvc>=a002ovPDHLkV1f&ThtmK6 literal 0 HcmV?d00001 diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_2.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_2.png new file mode 100644 index 0000000000000000000000000000000000000000..1fd5925e48f44e2c07658ca344bc32698b4e6f71 GIT binary patch literal 455 zcmV;&0XY7NP)Px$fk{L`R5*>bl08eqU=YWDk5!ipMRZDrR(uB+A&Xn+q=Ty<5jr>&K@f^#5RncJ z(p54z6zm5O1;L>@bkxB~Q_!f8ZVrNlF7=!e5@Wl0%L8}+x92$c&obR3G2J5>gc<5L zIR1K;H xm^w{Mw**MI2JHYKMFtrD-3UPzmi*QKT|eY^yUz_PY<2(u002ovPDHLkV1nRI!=3;D literal 0 HcmV?d00001 diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_3.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_3.png new file mode 100644 index 0000000000000000000000000000000000000000..358b7874c5eb77c4525cd4422ed30fc4470ae8f3 GIT binary patch literal 362 zcmV-w0hRuVP)Px$BuPX;R5*?8ks(jRKp2Lf8@P!HT$^UOgrpL|e!xk70p>y`>nl(V2}$+*1fmJ$ zXTU-xnZQxiEKBPv>VQLCckM_B36f8K_rA~feec14{cSB5bF*B`&2Mz0;p2ER{c(`1 z8M(A5&P3a6Np#X}aesHy+bGeAd3*fa11!;nqiV_=mPJYak_$UfxWPO>ydy)|gIrvmQoMdJG><1!+Ge{C(XLb$C1p{P z=)_cYg*Y)iGr(>W&^BA5I1|GCHVe@+Z2)8_SwF4uJ)f$s@I4pmxlmGw#07*qo IM6N<$g2dsPWdHyG literal 0 HcmV?d00001 diff --git a/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/ender_pearl_flower_seeds.png b/bukkit/loader/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/ender_pearl_flower_seeds.png new file mode 100644 index 0000000000000000000000000000000000000000..48b377350277ffe75ddf249ef2af1751e646df0f GIT binary patch literal 280 zcmV+z0q6dSP)Px#(n&-?R5*>rQn3nyFcds%2f?3k5&|9l0tcu1UtPMlpHb?Rp7~&B8i9!}h zrx#u%mTVqm3GeP*?gH$MEM=(dTL%DE8!XctaE>Wtaqa*B3KAA@T;#AGF8kKyb>%qO zHUespQ3nC}^nSSJe(?eTkk^%?6XW?OSZz>@3TlwSz~;s^^12G_Z@HvE2|j~mnlr1- z<^m#$a|ga8Xo1@$!uR>|cN8c`v_@XtM;k}(6eR5R_FsTkSBxrfxBdfB0oo*hq(-6@ e@sN^h+zmhUS$4!nKsXuz0000= this.ageProperty.max; - } - - public final boolean isMaxAge(ImmutableBlockState state) { - return this.getAge(state) >= this.ageProperty.max; - } - - public static ImmutableBlockState getCEBlockState(Object nmsState) { - return BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(nmsState)); - } - - public final int getAge(Object state) { - return getCEBlockState(state).get(ageProperty); - } - public final int getAge(ImmutableBlockState state) { return state.get(ageProperty); } - public Object getStateForAge(Object state, int age) { - ImmutableBlockState afterState = getCEBlockState(state).owner().value().defaultState().with(ageProperty, age); - return afterState.customBlockState().handle(); - } - - public void growCrops(Object level, Object pos, Object state) throws InvocationTargetException, IllegalAccessException { - int i = this.getAge(state) + RandomUtils.generateRandomInt(2, 5); - int maxAge = this.ageProperty.max; - if (i > maxAge) { - i = maxAge; - } - Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, i), UpdateOption.UPDATE_NONE.flags()); - } - private static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { return (int) Reflections.method$BlockAndTintGetter$getRawBrightness.invoke(level, pos, 0); } private boolean hasSufficientLight(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { - return getRawBrightness(level, pos) >= minGrowLight - 1; + return getRawBrightness(level, pos) >= this.minGrowLight - 1; } @Override @@ -81,11 +51,13 @@ public class CropBlockBehavior extends BushBlockBehavior { Object state = args[0]; Object level = args[1]; Object pos = args[2]; - if (getRawBrightness(level, pos) >= minGrowLight) { - int age = this.getAge(state); - float randomFloat = RandomUtils.generateRandomFloat(0, 1); - if (age < this.ageProperty.max && randomFloat < 1.0 / Math.floor(25.0 / this.growSpeed + 1.0)) { - Reflections.method$Level$setBlock.invoke(level, pos, getStateForAge(state, age + 1), UpdateOption.UPDATE_ALL.flags()); + if (getRawBrightness(level, pos) >= this.minGrowLight) { + ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state)); + if (currentState != null && !currentState.isEmpty()) { + int age = this.getAge(currentState); + if (age < this.ageProperty.max && RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) { + Reflections.method$Level$setBlock.invoke(level, pos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); + } } } } @@ -103,12 +75,30 @@ public class CropBlockBehavior extends BushBlockBehavior { @Override public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) { Object state = args[2]; - return !this.isMaxAge(state); + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state)); + if (immutableBlockState != null && !immutableBlockState.isEmpty()) { + return getAge(immutableBlockState) != this.ageProperty.max; + } else { + return false; + } } @Override public void performBoneMeal(Object thisBlock, Object[] args) throws Exception { - this.growCrops(args[0], args[2], args[3]); + this.performBoneMeal(args[0], args[2], args[3]); + } + + private void performBoneMeal(Object level, Object pos, Object state) throws InvocationTargetException, IllegalAccessException { + ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state)); + if (immutableBlockState == null || immutableBlockState.isEmpty()) { + return; + } + int i = this.getAge(immutableBlockState) + RandomUtils.generateRandomInt(2, 5); + int maxAge = this.ageProperty.max; + if (i > maxAge) { + i = maxAge; + } + Reflections.method$Level$setBlock.invoke(level, pos, immutableBlockState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); } public static class Factory implements BlockBehaviorFactory { @@ -122,8 +112,8 @@ public class CropBlockBehavior extends BushBlockBehavior { throw new IllegalArgumentException("age property not set for crop"); } // 存活条件是最小生长亮度-1 - int minGrowLight = MiscUtils.getAsInt(arguments.getOrDefault("min-grow-light", 9)); - float growSpeed = MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 1)); + int minGrowLight = MiscUtils.getAsInt(arguments.getOrDefault("light-requirement", 9)); + float growSpeed = MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 0.25f)); return new CropBlockBehavior(tuple.left(), tuple.mid(), tuple.right(), ageProperty, growSpeed, minGrowLight); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java index b5cddf244..fb4f0e365 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java @@ -5,11 +5,12 @@ import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.util.SectionPosUtils; import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; public class BukkitCEWorld extends CEWorld { - public BukkitCEWorld(World world) { - super(world); + public BukkitCEWorld(World world, StorageAdaptor adaptor) { + super(world, adaptor); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index 8248c227f..623540d88 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.world; +import net.momirealms.craftengine.bukkit.compatibility.slimeworld.SlimeFormatStorageAdaptor; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector; @@ -8,6 +9,7 @@ import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.config.ConfigManager; import net.momirealms.craftengine.core.plugin.scheduler.SchedulerTask; +import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.ChunkPos; import net.momirealms.craftengine.core.world.SectionPos; @@ -15,6 +17,8 @@ import net.momirealms.craftengine.core.world.WorldManager; import net.momirealms.craftengine.core.world.chunk.CEChunk; import net.momirealms.craftengine.core.world.chunk.CESection; import net.momirealms.craftengine.core.world.chunk.serialization.ChunkSerializer; +import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor; +import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; import net.momirealms.sparrow.nbt.CompoundTag; import org.bukkit.Bukkit; import org.bukkit.Chunk; @@ -27,6 +31,7 @@ import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.event.world.WorldLoadEvent; import org.bukkit.event.world.WorldUnloadEvent; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.util.HashMap; @@ -38,18 +43,34 @@ public class BukkitWorldManager implements WorldManager, Listener { private static BukkitWorldManager instance; private final BukkitCraftEngine plugin; private final Map worlds; - private CEWorld[] worldArray; + private CEWorld[] worldArray = new CEWorld[0]; private final ReentrantReadWriteLock worldMapLock = new ReentrantReadWriteLock(); private SchedulerTask tickTask; // cache private UUID lastVisitedUUID; private CEWorld lastVisitedWorld; + private StorageAdaptor storageAdaptor; public BukkitWorldManager(BukkitCraftEngine plugin) { instance = this; this.plugin = plugin; this.worlds = new HashMap<>(); - resetWorldArray(); + if (VersionHelper.isVersionNewerThan1_21_4()) { + try { + Class.forName("com.infernalsuite.asp.api.AdvancedSlimePaperAPI"); + SlimeFormatStorageAdaptor adaptor = new SlimeFormatStorageAdaptor(this); + this.storageAdaptor = adaptor; + Bukkit.getPluginManager().registerEvents(adaptor, plugin.bootstrap()); + return; + } catch (ClassNotFoundException ignored) { + } + } + this.storageAdaptor = new DefaultStorageAdaptor(); + } + + @Override + public void setStorageAdaptor(@NotNull StorageAdaptor storageAdaptor) { + this.storageAdaptor = storageAdaptor; } public static BukkitWorldManager instance() { @@ -95,7 +116,7 @@ public class BukkitWorldManager implements WorldManager, Listener { this.worldMapLock.writeLock().lock(); try { for (World world : Bukkit.getWorlds()) { - CEWorld ceWorld = new BukkitCEWorld(new BukkitWorld(world)); + CEWorld ceWorld = new BukkitCEWorld(new BukkitWorld(world), this.storageAdaptor); this.worlds.put(world.getUID(), ceWorld); this.resetWorldArray(); for (Chunk chunk : world.getLoadedChunks()) { @@ -110,8 +131,11 @@ public class BukkitWorldManager implements WorldManager, Listener { @Override public void disable() { HandlerList.unregisterAll(this); - if (tickTask != null && !tickTask.cancelled()) { - tickTask.cancel(); + if (this.storageAdaptor instanceof Listener listener) { + HandlerList.unregisterAll(listener); + } + if (this.tickTask != null && !this.tickTask.cancelled()) { + this.tickTask.cancel(); } for (World world : Bukkit.getWorlds()) { @@ -125,14 +149,18 @@ public class BukkitWorldManager implements WorldManager, Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onWorldLoad(WorldLoadEvent event) { - World world = event.getWorld(); - CEWorld ceWorld = new BukkitCEWorld(new BukkitWorld(world)); + this.loadWorld(new BukkitWorld(event.getWorld())); + } + + @Override + public void loadWorld(net.momirealms.craftengine.core.world.World world) { this.worldMapLock.writeLock().lock(); try { - if (this.worlds.containsKey(world.getUID())) return; - this.worlds.put(event.getWorld().getUID(), ceWorld); + if (this.worlds.containsKey(world.uuid())) return; + CEWorld ceWorld = new BukkitCEWorld(world, this.storageAdaptor); + this.worlds.put(world.uuid(), ceWorld); this.resetWorldArray(); - for (Chunk chunk : world.getLoadedChunks()) { + for (Chunk chunk : ((World) world.platformWorld()).getLoadedChunks()) { handleChunkLoad(ceWorld, chunk); } } finally { @@ -142,11 +170,15 @@ public class BukkitWorldManager implements WorldManager, Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onWorldUnload(WorldUnloadEvent event) { - World world = event.getWorld(); + unloadWorld(new BukkitWorld(event.getWorld())); + } + + @Override + public void unloadWorld(net.momirealms.craftengine.core.world.World world) { CEWorld ceWorld; this.worldMapLock.writeLock().lock(); try { - ceWorld = this.worlds.remove(world.getUID()); + ceWorld = this.worlds.remove(world.uuid()); if (ceWorld == null) { return; } @@ -158,11 +190,20 @@ public class BukkitWorldManager implements WorldManager, Listener { } finally { this.worldMapLock.writeLock().unlock(); } - for (Chunk chunk : world.getLoadedChunks()) { + for (Chunk chunk : ((World) world.platformWorld()).getLoadedChunks()) { handleChunkUnload(ceWorld, chunk); } } + @Override + public net.momirealms.craftengine.core.world.World wrap(T world) { + if (world instanceof World w) { + return new BukkitWorld(w); + } else { + throw new IllegalArgumentException(world.getClass() + " is not a Bukkit World"); + } + } + @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onChunkLoad(ChunkLoadEvent event) { this.worldMapLock.readLock().lock(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 60168df84..8e5093864 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -286,8 +286,6 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/netherite_anvil_top.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/solid_gunpowder_block.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/gunpowder_block.png"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_1.png"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_2.png"); // items plugin.saveResource("resources/default/configuration/items.yml"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_rod.png"); @@ -302,7 +300,6 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow_pulling_1.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow_pulling_2.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/topaz_crossbow.png"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/flame_cane.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/entity/equipment/humanoid/topaz.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/entity/equipment/humanoid_leggings/topaz.png"); for (String item : List.of("helmet", "chestplate", "leggings", "boots", "pickaxe", "axe", "sword", "hoe", "shovel")) { @@ -334,8 +331,15 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/fairy_flower_3.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/fairy_flower_4.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/reed.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_1.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/flame_cane_2.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_0.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_1.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/ender_pearl_flower_stage_2.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/fairy_flower.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/reed.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/flame_cane.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/ender_pearl_flower_seeds.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/fairy_flower_1.json"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/reed.json"); // furniture diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java index cae381027..f604df05d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.world; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.world.chunk.CEChunk; -import net.momirealms.craftengine.core.world.chunk.storage.DefaultRegionFileStorage; +import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; import org.jetbrains.annotations.Nullable; @@ -25,10 +25,10 @@ public abstract class CEWorld { private CEChunk lastChunk; private long lastChunkPos; - public CEWorld(World world) { + public CEWorld(World world, StorageAdaptor adaptor) { this.world = world; this.loadedChunkMap = new Long2ObjectOpenHashMap<>(1024, 0.5f); - this.worldDataStorage = new DefaultRegionFileStorage(world.directory().resolve(REGION_DIRECTORY)); + this.worldDataStorage = adaptor.adapt(world); this.worldHeightAccessor = world.worldHeight(); this.lastChunkPos = ChunkPos.INVALID_CHUNK_POS; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java index 24f615730..ee5ab39a0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java @@ -1,12 +1,22 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.plugin.Reloadable; +import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; +import org.jetbrains.annotations.NotNull; import java.util.UUID; public interface WorldManager extends Reloadable { + void setStorageAdaptor(@NotNull StorageAdaptor storageAdaptor); + CEWorld getWorld(UUID uuid); void delayedInit(); + + void loadWorld(World world); + + void unloadWorld(World world); + + World wrap(T world); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultStorageAdaptor.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultStorageAdaptor.java new file mode 100644 index 000000000..9de5d571c --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/DefaultStorageAdaptor.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.core.world.chunk.storage; + +import net.momirealms.craftengine.core.world.CEWorld; +import net.momirealms.craftengine.core.world.World; +import org.jetbrains.annotations.NotNull; + +public class DefaultStorageAdaptor implements StorageAdaptor { + + @Override + public @NotNull WorldDataStorage adapt(@NotNull World world) { + return new DefaultRegionFileStorage(world.directory().resolve(CEWorld.REGION_DIRECTORY)); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/StorageAdaptor.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/StorageAdaptor.java new file mode 100644 index 000000000..8a9790462 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/storage/StorageAdaptor.java @@ -0,0 +1,10 @@ +package net.momirealms.craftengine.core.world.chunk.storage; + +import net.momirealms.craftengine.core.world.World; +import org.jetbrains.annotations.NotNull; + +public interface StorageAdaptor { + + @NotNull + WorldDataStorage adapt(@NotNull World world); +} diff --git a/gradle.properties b/gradle.properties index 96a6a3b08..77319d3f9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -40,7 +40,7 @@ geantyref_version=1.3.16 zstd_version=1.5.6-9 commons_io_version=2.17.0 sparrow_nbt_version=0.3 -sparrow_util_version=0.33 +sparrow_util_version=0.34 fastutil_version=8.5.15 netty_version=4.1.119.Final joml_version=1.10.8 From a8847abb25c7c9882fe03dc531971d883238fb2d Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 29 Mar 2025 00:53:19 +0800 Subject: [PATCH 24/28] Update plants.yml --- .../resources/resources/default/configuration/plants.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml index 989ef3b9a..6cb154363 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -209,7 +209,7 @@ blocks: range: 0~2 appearances: stage_0: - state: "tripwire:0" + state: "tripwire:1" models: - path: "minecraft:block/custom/ender_pearl_flower_stage_0" generation: @@ -217,7 +217,7 @@ blocks: textures: "cross": "minecraft:block/custom/ender_pearl_flower_stage_0" stage_1: - state: "tripwire:1" + state: "tripwire:0" models: - path: "minecraft:block/custom/ender_pearl_flower_stage_1" generation: @@ -225,7 +225,7 @@ blocks: textures: "cross": "minecraft:block/custom/ender_pearl_flower_stage_1" stage_2: - state: "tripwire:2" + state: "sugar_cane:3" models: - path: "minecraft:block/custom/ender_pearl_flower_stage_2" generation: @@ -241,7 +241,7 @@ blocks: id: 1 age=2: appearance: stage_2 - id: 2 + id: 8 recipes: default:paper_from_reed: type: shaped From 7b1855d76fb6b669831d41f304c994343f41bc7f Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 29 Mar 2025 00:57:32 +0800 Subject: [PATCH 25/28] fix filter --- .../craftengine/fabric/util/LoggerFilter.java | 1 + .../core/plugin/config/ConfigManager.java | 2 ++ .../logger/filter/DisconnectLogFilter.java | 18 +++++++++++++++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/LoggerFilter.java b/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/LoggerFilter.java index 2dc648a6a..99f9aec0f 100644 --- a/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/LoggerFilter.java +++ b/client-mod/src/main/java/net/momirealms/craftengine/fabric/util/LoggerFilter.java @@ -6,6 +6,7 @@ import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.filter.AbstractFilter; public class LoggerFilter { + public static void filter() { Logger rootLogger = (Logger) LogManager.getRootLogger(); rootLogger.addFilter(new AbstractFilter() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java index 73ffa8ba7..46586334c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/ConfigManager.java @@ -16,6 +16,7 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.PluginProperties; import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.plugin.logger.filter.DisconnectLogFilter; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; @@ -183,6 +184,7 @@ public class ConfigManager implements Reloadable { metrics = config.getBoolean("metrics", false); checkUpdate = config.getBoolean("update-checker", false); filterConfigurationPhaseDisconnect = config.getBoolean("filter-configuration-phase-disconnect", false); + DisconnectLogFilter.instance().setEnable(filterConfigurationPhaseDisconnect); // resource pack resource_pack$override_uniform_font = config.getBoolean("resource-pack.override-uniform-font", false); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/logger/filter/DisconnectLogFilter.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/logger/filter/DisconnectLogFilter.java index 4e9e8136e..68338896a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/logger/filter/DisconnectLogFilter.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/logger/filter/DisconnectLogFilter.java @@ -1,7 +1,5 @@ package net.momirealms.craftengine.core.plugin.logger.filter; - -import net.momirealms.craftengine.core.plugin.config.ConfigManager; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.LogEvent; import org.apache.logging.log4j.core.config.Node; @@ -13,10 +11,24 @@ import org.apache.logging.log4j.core.impl.MutableLogEvent; public class DisconnectLogFilter extends AbstractFilter { private static final String TARGET_LOGGER = "net.minecraft.server.network.ServerConfigurationPacketListenerImpl"; private static final String TARGET_MESSAGE_PATTERN = "{} lost connection: {}"; + private static DisconnectLogFilter instance; + private boolean enable = false; + + public DisconnectLogFilter() { + instance = this; + } + + public static DisconnectLogFilter instance() { + return instance; + } + + public void setEnable(boolean enable) { + this.enable = enable; + } @Override public Result filter(LogEvent event) { - if (!ConfigManager.filterConfigurationPhaseDisconnect()) { + if (!enable) { return Result.NEUTRAL; } From 81ac75adb05ca46f66b50d90f07308b33d22fd97 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 29 Mar 2025 01:49:37 +0800 Subject: [PATCH 26/28] add slime world support --- .../slimeworld/SlimeFormatStorageAdaptor.java | 27 +++++++++++++++-- .../slimeworld/SlimeWorldDataStorage.java | 30 ++++++++++--------- .../bukkit/world/BukkitCEWorld.java | 5 ++++ .../bukkit/world/BukkitWorldManager.java | 21 +++++++++++++ .../craftengine/core/world/CEWorld.java | 8 +++++ .../craftengine/core/world/WorldManager.java | 5 ++++ 6 files changed, 80 insertions(+), 16 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java index b5ce5a6e6..b01a6e1c1 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeFormatStorageAdaptor.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.compatibility.slimeworld; import com.infernalsuite.asp.api.AdvancedSlimePaperAPI; import com.infernalsuite.asp.api.events.LoadSlimeWorldEvent; import com.infernalsuite.asp.api.world.SlimeWorld; +import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldManager; import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor; @@ -12,13 +13,18 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.jetbrains.annotations.NotNull; +import java.lang.reflect.Method; + public class SlimeFormatStorageAdaptor extends DefaultStorageAdaptor implements Listener { private final WorldManager worldManager; + private final Class byteArrayTagClass = ReflectionUtils.getClazz("net{}kyori{}adventure{}nbt{}ByteArrayBinaryTag".replace("{}", ".")); + private final Method method$ByteArrayBinaryTag$byteArrayBinaryTag = ReflectionUtils.getStaticMethod(byteArrayTagClass, byteArrayTagClass, byte.class.arrayType()); + private final Method method$ByteArrayBinaryTag$value = ReflectionUtils.getMethod(byteArrayTagClass, byte.class.arrayType()); @EventHandler public void onWorldLoad(LoadSlimeWorldEvent event) { org.bukkit.World world = Bukkit.getWorld(event.getSlimeWorld().getName()); - this.worldManager.loadWorld(this.worldManager.wrap(world)); + this.worldManager.loadWorld(this.worldManager.createWorld(this.worldManager.wrap(world), new SlimeWorldDataStorage(event.getSlimeWorld(), this))); } public SlimeFormatStorageAdaptor(WorldManager worldManager) { @@ -29,12 +35,29 @@ public class SlimeFormatStorageAdaptor extends DefaultStorageAdaptor implements return AdvancedSlimePaperAPI.instance().getLoadedWorld(name); } + // 请注意,在加载事件的时候,无法通过AdvancedSlimePaperAPI.instance().getLoadedWorld来判断是否为slime世界 @Override public @NotNull WorldDataStorage adapt(@NotNull World world) { SlimeWorld slimeWorld = getWorld(world.name()); if (slimeWorld == null) { return super.adapt(world); } - return new SlimeWorldDataStorage(slimeWorld); + return new SlimeWorldDataStorage(slimeWorld, this); + } + + public byte[] byteArrayTagToBytes(Object byteArrayTag) { + try { + return (byte[]) method$ByteArrayBinaryTag$value.invoke(byteArrayTag); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to convert byte array tag to byte[]", e); + } + } + + public Object bytesToByteArrayTag(byte[] bytes) { + try { + return method$ByteArrayBinaryTag$byteArrayBinaryTag.invoke(null, (Object) bytes); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Failed to convert byte array tag to byte[]", e); + } } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java index b9b63ded4..feeb6505f 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/slimeworld/SlimeWorldDataStorage.java @@ -2,8 +2,6 @@ package net.momirealms.craftengine.bukkit.compatibility.slimeworld; import com.infernalsuite.asp.api.world.SlimeChunk; import com.infernalsuite.asp.api.world.SlimeWorld; -import net.kyori.adventure.nbt.BinaryTag; -import net.kyori.adventure.nbt.ByteArrayBinaryTag; import net.momirealms.craftengine.core.world.ChunkPos; import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; import net.momirealms.sparrow.nbt.CompoundTag; @@ -14,12 +12,15 @@ import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.lang.ref.WeakReference; +import java.util.Map; public class SlimeWorldDataStorage implements WorldDataStorage { private final WeakReference slimeWorld; + private final SlimeFormatStorageAdaptor adaptor; - public SlimeWorldDataStorage(SlimeWorld slimeWorld) { + public SlimeWorldDataStorage(SlimeWorld slimeWorld, SlimeFormatStorageAdaptor adaptor) { this.slimeWorld = new WeakReference<>(slimeWorld); + this.adaptor = adaptor; } public SlimeWorld getWorld() { @@ -31,16 +32,16 @@ public class SlimeWorldDataStorage implements WorldDataStorage { public CompoundTag readChunkTagAt(ChunkPos pos) { SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); if (slimeChunk == null) return null; - BinaryTag tag = slimeChunk.getExtraData().get("craftengine"); + Object tag = slimeChunk.getExtraData().get("craftengine"); if (tag == null) return null; - ByteArrayBinaryTag byteArrayBinaryTag = (ByteArrayBinaryTag) tag; try { - return NBT.readCompound(new DataInputStream(new ByteArrayInputStream(byteArrayBinaryTag.value()))); - } catch (IOException e) { + return NBT.readCompound(new DataInputStream(new ByteArrayInputStream(adaptor.byteArrayTagToBytes(tag)))); + } catch (Exception e) { throw new RuntimeException("Failed to read chunk tag from slime world. " + pos, e); } } + @SuppressWarnings("unchecked") @Override public void writeChunkTagAt(ChunkPos pos, @Nullable CompoundTag nbt) { SlimeChunk slimeChunk = getWorld().getChunk(pos.x, pos.z); @@ -48,13 +49,14 @@ public class SlimeWorldDataStorage implements WorldDataStorage { if (nbt == null) { slimeChunk.getExtraData().remove("craftengine"); } else { - slimeChunk.getExtraData().computeIfAbsent("craftengine", l -> { - try { - return ByteArrayBinaryTag.byteArrayBinaryTag(NBT.toBytes(nbt)); - } catch (IOException e) { - throw new RuntimeException("Failed to write chunk tag to slime world. " + pos, e); - } - }); + try { + Object tag = adaptor.bytesToByteArrayTag(NBT.toBytes(nbt)); + Map data1 = slimeChunk.getExtraData(); + Map data2 = (Map) data1; + data2.put("craftengine", tag); + } catch (Exception e) { + throw new RuntimeException("Failed to write chunk tag to slime world. " + pos, e); + } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java index fb4f0e365..73ca854da 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.core.util.SectionPosUtils; import net.momirealms.craftengine.core.world.CEWorld; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; +import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; public class BukkitCEWorld extends CEWorld { @@ -13,6 +14,10 @@ public class BukkitCEWorld extends CEWorld { super(world, adaptor); } + public BukkitCEWorld(World world, WorldDataStorage dataStorage) { + super(world, dataStorage); + } + @Override public void tick() { if (ConfigManager.enableLightSystem()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index 623540d88..001dc1754 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java @@ -19,6 +19,7 @@ import net.momirealms.craftengine.core.world.chunk.CESection; import net.momirealms.craftengine.core.world.chunk.serialization.ChunkSerializer; import net.momirealms.craftengine.core.world.chunk.storage.DefaultStorageAdaptor; import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; +import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; import net.momirealms.sparrow.nbt.CompoundTag; import org.bukkit.Bukkit; import org.bukkit.Chunk; @@ -168,6 +169,26 @@ public class BukkitWorldManager implements WorldManager, Listener { } } + @Override + public void loadWorld(CEWorld world) { + this.worldMapLock.writeLock().lock(); + try { + if (this.worlds.containsKey(world.world().uuid())) return; + this.worlds.put(world.world().uuid(), world); + this.resetWorldArray(); + for (Chunk chunk : ((World) world.world().platformWorld()).getLoadedChunks()) { + handleChunkLoad(world, chunk); + } + } finally { + this.worldMapLock.writeLock().unlock(); + } + } + + @Override + public CEWorld createWorld(net.momirealms.craftengine.core.world.World world, WorldDataStorage storage) { + return new BukkitCEWorld(world, storage); + } + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onWorldUnload(WorldUnloadEvent event) { unloadWorld(new BukkitWorld(event.getWorld())); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java index f604df05d..59a4978f3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java @@ -33,6 +33,14 @@ public abstract class CEWorld { this.lastChunkPos = ChunkPos.INVALID_CHUNK_POS; } + public CEWorld(World world, WorldDataStorage dataStorage) { + this.world = world; + this.loadedChunkMap = new Long2ObjectOpenHashMap<>(1024, 0.5f); + this.worldDataStorage = dataStorage; + this.worldHeightAccessor = world.worldHeight(); + this.lastChunkPos = ChunkPos.INVALID_CHUNK_POS; + } + public World world() { return world; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java index ee5ab39a0..58db10caf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/WorldManager.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.plugin.Reloadable; import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; +import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; import org.jetbrains.annotations.NotNull; import java.util.UUID; @@ -16,6 +17,10 @@ public interface WorldManager extends Reloadable { void loadWorld(World world); + void loadWorld(CEWorld world); + + CEWorld createWorld(World world, WorldDataStorage storage); + void unloadWorld(World world); World wrap(T world); From 8b357432d615452e5ea1000e9d2a4b36695a5285 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 29 Mar 2025 02:24:24 +0800 Subject: [PATCH 27/28] swing hand/particles for crop --- .../block/behavior/CropBlockBehavior.java | 26 +++++++ .../block/behavior/SaplingBlockBehavior.java | 35 +++++++-- .../bukkit/item/BukkitItemManager.java | 2 + .../item/behavior/BoneMealItemBehavior.java | 73 +++++++++++++++++++ .../item/behavior/BukkitItemBehaviors.java | 2 + .../bukkit/util/ParticleUtils.java | 18 +++++ 6 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index 5fcaaba2e..9e3d8080c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -1,7 +1,9 @@ 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; @@ -13,6 +15,7 @@ import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.Tuple; import net.momirealms.craftengine.shared.block.BlockBehavior; +import org.bukkit.World; import java.lang.reflect.InvocationTargetException; import java.util.List; @@ -38,6 +41,10 @@ public class CropBlockBehavior extends BushBlockBehavior { return state.get(ageProperty); } + public boolean isMaxAge(ImmutableBlockState state) { + return state.get(ageProperty) == ageProperty.max; + } + private static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { return (int) Reflections.method$BlockAndTintGetter$getRawBrightness.invoke(level, pos, 0); } @@ -93,12 +100,31 @@ public class CropBlockBehavior extends BushBlockBehavior { if (immutableBlockState == null || immutableBlockState.isEmpty()) { return; } + boolean sendParticles = false; + Object visualState = immutableBlockState.vanillaBlockState().handle(); + Object visualStateBlock = Reflections.method$BlockStateBase$getBlock.invoke(visualState); + if (Reflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) { + boolean is = (boolean) Reflections.method$BonemealableBlock$isValidBonemealTarget.invoke(visualStateBlock, level, pos, visualState); + if (!is) { + sendParticles = true; + } + } else { + sendParticles = true; + } + int i = this.getAge(immutableBlockState) + RandomUtils.generateRandomInt(2, 5); int maxAge = this.ageProperty.max; if (i > maxAge) { i = maxAge; } Reflections.method$Level$setBlock.invoke(level, pos, immutableBlockState.with(this.ageProperty, i).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); + if (sendParticles) { + World world = FastNMS.INSTANCE.method$Level$getCraftWorld(level); + int x = FastNMS.INSTANCE.field$Vec3i$x(pos); + int y = FastNMS.INSTANCE.field$Vec3i$y(pos); + int z = FastNMS.INSTANCE.field$Vec3i$z(pos); + world.spawnParticle(ParticleUtils.getParticle("HAPPY_VILLAGER"), x + 0.5, y + 0.5, z + 0.5, 12, 0.2, 0.2, 0.2); + } } public static class Factory implements BlockBehaviorFactory { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java index 7fb110cac..93206d75d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java @@ -3,10 +3,7 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; 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.FeatureUtils; -import net.momirealms.craftengine.bukkit.util.LocationUtils; -import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; @@ -98,8 +95,34 @@ public class SaplingBlockBehavior extends BushBlockBehavior { } @Override - public boolean isBoneMealSuccess(Object thisBlock, Object[] args) { - return RandomUtils.generateRandomDouble(0d, 1d) < this.boneMealSuccessChance; + public boolean isBoneMealSuccess(Object thisBlock, Object[] args) throws Exception { + boolean success = RandomUtils.generateRandomDouble(0d, 1d) < this.boneMealSuccessChance; + 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 = (boolean) Reflections.method$BonemealableBlock$isValidBonemealTarget.invoke(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 + 0.5, z + 0.5, 12, 0.2, 0.2, 0.2); + } + return success; } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index 0f965dbc8..bba404771 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.item; import net.momirealms.craftengine.bukkit.compatibility.item.NeigeItemsProvider; import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior; +import net.momirealms.craftengine.bukkit.item.behavior.BoneMealItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior; import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior; import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory; @@ -50,6 +51,7 @@ public class BukkitItemManager extends AbstractItemManager { registerVanillaItemExtraBehavior(AxeItemBehavior.INSTANCE, ItemKeys.AXES); registerVanillaItemExtraBehavior(WaterBucketItemBehavior.INSTANCE, ItemKeys.WATER_BUCKETS); registerVanillaItemExtraBehavior(BucketItemBehavior.INSTANCE, ItemKeys.BUCKET); + registerVanillaItemExtraBehavior(BoneMealItemBehavior.INSTANCE, ItemKeys.BONE_MEAL); } private static BukkitItemManager instance; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java new file mode 100644 index 000000000..4a71f53bf --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BoneMealItemBehavior.java @@ -0,0 +1,73 @@ +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.SaplingBlockBehavior; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.bukkit.world.BukkitWorldBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.block.Block; + +import java.nio.file.Path; +import java.util.Map; + +public class BoneMealItemBehavior extends ItemBehavior { + public static final Factory FACTORY = new Factory(); + public static final BoneMealItemBehavior INSTANCE = new BoneMealItemBehavior(); + + @Override + public InteractionResult useOnBlock(UseOnContext context) { + BukkitWorldBlock clicked = (BukkitWorldBlock) context.getLevel().getBlockAt(context.getClickedPos()); + Block block = clicked.block(); + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); + if (state == null || state.isEmpty()) return InteractionResult.PASS; + + boolean shouldHandle =false; + if (state.behavior() instanceof CropBlockBehavior blockBehavior) { + if (!blockBehavior.isMaxAge(state)) { + shouldHandle = true; + } + } else if (state.behavior() instanceof SaplingBlockBehavior) { + shouldHandle = true; + } + + if (!shouldHandle) return InteractionResult.PASS; + + boolean sendSwing = false; + try { + Object visualState = state.vanillaBlockState().handle(); + Object visualStateBlock = Reflections.method$BlockStateBase$getBlock.invoke(visualState); + if (Reflections.clazz$BonemealableBlock.isInstance(visualStateBlock)) { + boolean is = (boolean) Reflections.method$BonemealableBlock$isValidBonemealTarget.invoke(visualStateBlock, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), visualState); + if (!is) { + sendSwing = true; + } + } else { + sendSwing = true; + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to check visual state bone meal state", e); + } + if (sendSwing) { + context.getPlayer().swingHand(context.getHand()); + } + return InteractionResult.SUCCESS; + } + + public static class Factory implements ItemBehaviorFactory { + + @Override + public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { + return INSTANCE; + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java index 40bed4810..ed3e35737 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BukkitItemBehaviors.java @@ -11,6 +11,7 @@ public class BukkitItemBehaviors extends ItemBehaviors { public static final Key AXE_ITEM = Key.from("craftengine:axe_item"); public static final Key WATER_BUCKET_ITEM = Key.from("craftengine:water_bucket_item"); public static final Key BUCKET_ITEM = Key.from("craftengine:bucket_item"); + public static final Key BONE_MEAL_ITEM = Key.from("craftengine:bone_meal_item"); public static void init() { register(EMPTY, EmptyItemBehavior.FACTORY); @@ -20,5 +21,6 @@ public class BukkitItemBehaviors extends ItemBehaviors { register(AXE_ITEM, AxeItemBehavior.FACTORY); register(WATER_BUCKET_ITEM, WaterBucketItemBehavior.FACTORY); register(BUCKET_ITEM, BucketItemBehavior.FACTORY); + register(BONE_MEAL_ITEM, BoneMealItemBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java new file mode 100644 index 000000000..efe651614 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ParticleUtils.java @@ -0,0 +1,18 @@ +package net.momirealms.craftengine.bukkit.util; + +import org.bukkit.Particle; + +public class ParticleUtils { + + public static Particle getParticle(String particle) { + try { + return Particle.valueOf(particle); + } catch (IllegalArgumentException e) { + return switch (particle) { + case "REDSTONE" -> Particle.valueOf("DUST"); + case "VILLAGER_HAPPY" -> Particle.valueOf("HAPPY_VILLAGER"); + default -> Particle.valueOf(particle); + }; + } + } +} From 09a38fb7d6344c22248576f2e61a0c4f9ceac5e1 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sat, 29 Mar 2025 02:26:06 +0800 Subject: [PATCH 28/28] increase offset --- .../craftengine/bukkit/block/behavior/CropBlockBehavior.java | 2 +- .../craftengine/bukkit/block/behavior/SaplingBlockBehavior.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java index 9e3d8080c..b4cde1bd8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/CropBlockBehavior.java @@ -123,7 +123,7 @@ public class CropBlockBehavior extends BushBlockBehavior { int x = FastNMS.INSTANCE.field$Vec3i$x(pos); int y = FastNMS.INSTANCE.field$Vec3i$y(pos); int z = FastNMS.INSTANCE.field$Vec3i$z(pos); - world.spawnParticle(ParticleUtils.getParticle("HAPPY_VILLAGER"), x + 0.5, y + 0.5, z + 0.5, 12, 0.2, 0.2, 0.2); + world.spawnParticle(ParticleUtils.getParticle("HAPPY_VILLAGER"), x + 0.5, y + 0.5, z + 0.5, 12, 0.25, 0.25, 0.25); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java index 93206d75d..04df34dc8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SaplingBlockBehavior.java @@ -120,7 +120,7 @@ public class SaplingBlockBehavior extends BushBlockBehavior { 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 + 0.5, z + 0.5, 12, 0.2, 0.2, 0.2); + world.spawnParticle(ParticleUtils.getParticle("HAPPY_VILLAGER"), x + 0.5, y + 0.5, z + 0.5, 12, 0.25, 0.25, 0.25); } return success; }