diff --git a/README.md b/README.md index d766c3f46..d1a6aa1e9 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ repositories { ``` ```kotlin dependencies { - compileOnly("net.momirealms:craft-engine-core:0.0.38") - compileOnly("net.momirealms:craft-engine-bukkit:0.0.38") + compileOnly("net.momirealms:craft-engine-core:0.0.42") + compileOnly("net.momirealms:craft-engine-bukkit:0.0.42") } ``` 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 6cb154363..22f13a2cc 100644 --- a/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml +++ b/bukkit/loader/src/main/resources/resources/default/configuration/plants.yml @@ -193,6 +193,8 @@ blocks: type: crop_block grow-speed: 0.25 light-requirement: 9 + is-bone-meal-target: true + bone-meal-age-bonus: 1 bottom-blocks: - minecraft:end_stone loot: 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..3618b8d43 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 @@ -5,6 +5,7 @@ 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; +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; @@ -107,21 +108,16 @@ public final class CraftEngineBlocks { @NotNull UpdateOption option, boolean playSound) { boolean success; - try { - Object worldServer = Reflections.field$CraftWorld$ServerLevel.get(location.getWorld()); - Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - Object blockState = block.customBlockState().handle(); - 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); - if (playSound) { - location.getWorld().playSound(location, block.sounds().placeSound().toString(), SoundCategory.BLOCKS, block.sounds().placeSound().volume(), block.sounds().placeSound().pitch()); - } + Object worldServer = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(location.getWorld()); + Object blockPos = FastNMS.INSTANCE.constructor$BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + Object blockState = block.customBlockState().handle(); + Object oldBlockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(worldServer, blockPos); + success = FastNMS.INSTANCE.method$LevelWriter$setBlock(worldServer, blockPos, blockState, option.flags()); + if (success) { + FastNMS.INSTANCE.method$BlockStateBase$onPlace(blockState, worldServer, blockPos, oldBlockState, false); + if (playSound) { + location.getWorld().playSound(location, block.sounds().placeSound().toString(), SoundCategory.BLOCKS, block.sounds().placeSound().volume(), block.sounds().placeSound().pitch()); } - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to set nms block", e); - return false; } return success; } @@ -189,8 +185,7 @@ public final class CraftEngineBlocks { world.playBlockSound(vec3d, state.sounds().breakSound()); } if (sendParticles) { - // TODO Particles - //ParticleUtils.addBlockBreakParticles(block.getWorld(), LocationUtils.toBlockPos(location), state.customBlockState().handle()); + FastNMS.INSTANCE.method$Level$levelEvent(world.serverWorld(), 2001, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), state.customBlockState().registryId()); } block.setType(Material.AIR, applyPhysics); return true; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java index 04f57f418..436f677b3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java @@ -139,7 +139,7 @@ public class CraftEngineFurniture { */ @Nullable public static LoadedFurniture getLoadedFurnitureByBaseEntity(@NotNull Entity baseEntity) { - return BukkitFurnitureManager.instance().getLoadedFurnitureByBaseEntityId(baseEntity.getEntityId()); + return BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(baseEntity.getEntityId()); } /** @@ -152,7 +152,7 @@ public class CraftEngineFurniture { public static LoadedFurniture getLoadedFurnitureBySeat(@NotNull Entity seat) { Integer baseEntityId = seat.getPersistentDataContainer().get(BukkitFurnitureManager.FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER); if (baseEntityId == null) return null; - return BukkitFurnitureManager.instance().getLoadedFurnitureByBaseEntityId(baseEntityId); + return BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(baseEntityId); } /** @@ -163,7 +163,7 @@ public class CraftEngineFurniture { */ public static boolean remove(@NotNull Entity furniture) { if (!isFurniture(furniture)) return false; - LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().getLoadedFurnitureByBaseEntityId(furniture.getEntityId()); + LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(furniture.getEntityId()); if (loadedFurniture == null) return false; loadedFurniture.destroy(); return true; @@ -181,7 +181,7 @@ public class CraftEngineFurniture { boolean dropLoot, boolean playSound) { if (!isFurniture(furniture)) return false; - LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().getLoadedFurnitureByBaseEntityId(furniture.getEntityId()); + LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(furniture.getEntityId()); if (loadedFurniture == null) return false; remove(loadedFurniture, (net.momirealms.craftengine.core.entity.player.Player) null, dropLoot, playSound); return true; @@ -201,7 +201,7 @@ public class CraftEngineFurniture { boolean dropLoot, boolean playSound) { if (!isFurniture(furniture)) return false; - LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().getLoadedFurnitureByBaseEntityId(furniture.getEntityId()); + LoadedFurniture loadedFurniture = BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(furniture.getEntityId()); if (loadedFurniture == null) return false; remove(loadedFurniture, player, dropLoot, playSound); return 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 befb9a1e2..3bc68b877 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.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.*; @@ -183,34 +184,48 @@ public class BlockEventListener implements Listener { } } - // override vanilla block loots + // BlockBreakBlockEvent = liquid + piston @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onBlockBreakBlock(BlockBreakBlockEvent event) { Block block = event.getBlock(); Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData()); int stateId = BlockStateUtils.blockStateToId(blockState); if (!BlockStateUtils.isVanillaBlock(stateId)) { - return; - } - this.plugin.vanillaLootManager().getBlockLoot(stateId).ifPresent(it -> { - if (it.override()) { - event.getDrops().clear(); - event.setExpToDrop(0); - } - - Location location = block.getLocation(); - Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); - net.momirealms.craftengine.core.world.World world = new BukkitWorld(location.getWorld()); - ContextHolder.Builder builder = ContextHolder.builder(); - builder.withParameter(LootParameters.WORLD, world); - builder.withParameter(LootParameters.LOCATION, vec3d); - ContextHolder contextHolder = builder.build(); - for (LootTable lootTable : it.lootTables()) { - for (Item item : lootTable.getRandomItems(contextHolder, world)) { + // custom blocks + ImmutableBlockState immutableBlockState = this.manager.getImmutableBlockStateUnsafe(stateId); + if (!immutableBlockState.isEmpty()) { + Location location = block.getLocation(); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(block.getWorld()); + Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); + ContextHolder.Builder builder = ContextHolder.builder(); + builder.withParameter(LootParameters.WORLD, world); + builder.withParameter(LootParameters.LOCATION, vec3d); + for (Item item : immutableBlockState.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } } - }); + } else { + // override vanilla block loots + this.plugin.vanillaLootManager().getBlockLoot(stateId).ifPresent(it -> { + if (it.override()) { + event.getDrops().clear(); + event.setExpToDrop(0); + } + + Location location = block.getLocation(); + Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(location.getWorld()); + ContextHolder.Builder builder = ContextHolder.builder(); + builder.withParameter(LootParameters.WORLD, world); + builder.withParameter(LootParameters.LOCATION, vec3d); + ContextHolder contextHolder = builder.build(); + for (LootTable lootTable : it.lootTables()) { + for (Item item : lootTable.getRandomItems(contextHolder, world)) { + world.dropItemNaturally(vec3d, item); + } + } + }); + } } @EventHandler(ignoreCancelled = true) @@ -240,37 +255,38 @@ public class BlockEventListener implements Listener { } } - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onPistonRetract(BlockPistonRetractEvent event) { - handlePistonEvent(event.getDirection(), event.getBlocks(), event.getBlock()); - } - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onPistonExtend(BlockPistonExtendEvent event) { - handlePistonEvent(event.getDirection(), event.getBlocks(), event.getBlock()); - } - - private void handlePistonEvent(BlockFace face, List blocksList, Block piston) { - int blocks = blocksList.size(); - net.momirealms.craftengine.core.world.World world = new BukkitWorld(piston.getWorld()); - for (int i = blocks - 1; i >= 0; --i) { - Location oldLocation = blocksList.get(i).getLocation(); - BlockPos oldPos = new BlockPos(oldLocation.getBlockX(), oldLocation.getBlockY(), oldLocation.getBlockZ()); - Block block = blocksList.get(i); - ImmutableBlockState blockState = manager.getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); - if (blockState != null && blockState.pushReaction() == PushReaction.DESTROY) { - // break actions - ContextHolder.Builder builder = ContextHolder.builder(); - Vec3d vec3d = Vec3d.atCenterOf(oldPos); - builder.withParameter(LootParameters.LOCATION, vec3d); - builder.withParameter(LootParameters.WORLD, world); - for (Item item : blockState.getDrops(builder, world)) { - world.dropItemNaturally(vec3d, item); - } - world.playBlockSound(vec3d, blockState.sounds().breakSound()); - } - } - } +// Use BlockBreakBlock event +// @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) +// public void onPistonRetract(BlockPistonRetractEvent event) { +// handlePistonEvent(event.getDirection(), event.getBlocks(), event.getBlock()); +// } +// +// @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) +// public void onPistonExtend(BlockPistonExtendEvent event) { +// handlePistonEvent(event.getDirection(), event.getBlocks(), event.getBlock()); +// } +// +// private void handlePistonEvent(BlockFace face, List blocksList, Block piston) { +// int blocks = blocksList.size(); +// net.momirealms.craftengine.core.world.World world = new BukkitWorld(piston.getWorld()); +// for (int i = blocks - 1; i >= 0; --i) { +// Location oldLocation = blocksList.get(i).getLocation(); +// BlockPos oldPos = new BlockPos(oldLocation.getBlockX(), oldLocation.getBlockY(), oldLocation.getBlockZ()); +// Block block = blocksList.get(i); +// ImmutableBlockState blockState = manager.getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData())); +// if (blockState != null && blockState.pushReaction() == PushReaction.DESTROY) { +// // break actions +// ContextHolder.Builder builder = ContextHolder.builder(); +// Vec3d vec3d = Vec3d.atCenterOf(oldPos); +// builder.withParameter(LootParameters.LOCATION, vec3d); +// builder.withParameter(LootParameters.WORLD, world); +// for (Item item : blockState.getDrops(builder, world)) { +// world.dropItemNaturally(vec3d, item); +// } +// world.playBlockSound(vec3d, blockState.sounds().breakSound()); +// } +// } +// } @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onEntityExplode(EntityExplodeEvent event) { @@ -316,10 +332,10 @@ public class BlockEventListener implements Listener { Block sourceBlock = event.getSourceBlock(); BlockFace direction = sourceBlock.getFace(block); if (direction == BlockFace.UP || direction == BlockFace.DOWN) { - Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(world); - Object chunkSource = Reflections.field$ServerLevel$chunkSource.get(serverLevel); + Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world); + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel); Object blockPos = LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - Reflections.method$ServerChunkCache$blockChanged.invoke(chunkSource, blockPos); + FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos); if (direction == BlockFace.UP) { NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, Reflections.instance$Direction$UP, blockPos, 0); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehavior.java new file mode 100644 index 000000000..86b481813 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BukkitBlockBehavior.java @@ -0,0 +1,121 @@ +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.MirrorUtils; +import net.momirealms.craftengine.bukkit.util.RotationUtils; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.HorizontalDirection; +import net.momirealms.craftengine.core.util.Mirror; +import net.momirealms.craftengine.core.util.Rotation; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.Callable; +import java.util.function.BiConsumer; + +public class BukkitBlockBehavior extends AbstractBlockBehavior { + private static final Map>> HARD_CODED_PROPERTY_DATA = new HashMap<>(); + static { + HARD_CODED_PROPERTY_DATA.put("axis", (behavior, property) -> { + @SuppressWarnings("unchecked") + Property axisProperty = (Property) property; + behavior.rotateFunction = (thisBlock, blockState, rotation) -> { + Direction.Axis axis = blockState.get(axisProperty); + return switch (rotation) { + case COUNTERCLOCKWISE_90, CLOCKWISE_90 -> switch (axis) { + case X -> blockState.with(axisProperty, Direction.Axis.Z).customBlockState().handle(); + case Z -> blockState.with(axisProperty, Direction.Axis.X).customBlockState().handle(); + default -> blockState.customBlockState().handle(); + }; + default -> blockState.customBlockState().handle(); + }; + }; + }); + HARD_CODED_PROPERTY_DATA.put("facing", (behavior, property) -> { + if (property.valueClass() == HorizontalDirection.class) { + @SuppressWarnings("unchecked") + Property directionProperty = (Property) property; + behavior.rotateFunction = (thisBlock, blockState, rotation) -> + blockState.with(directionProperty, rotation.rotate(blockState.get(directionProperty).toDirection()).toHorizontalDirection()) + .customBlockState().handle(); + behavior.mirrorFunction = (thisBlock, blockState, mirror) -> { + Rotation rotation = mirror.getRotation(blockState.get(directionProperty).toDirection()); + return behavior.rotateFunction.rotate(thisBlock, blockState, rotation); + }; + } else if (property.valueClass() == Direction.class) { + @SuppressWarnings("unchecked") + Property directionProperty = (Property) property; + behavior.rotateFunction = (thisBlock, blockState, rotation) -> + blockState.with(directionProperty, rotation.rotate(blockState.get(directionProperty))) + .customBlockState().handle(); + behavior.mirrorFunction = (thisBlock, blockState, mirror) -> { + Rotation rotation = mirror.getRotation(blockState.get(directionProperty)); + return behavior.rotateFunction.rotate(thisBlock, blockState, rotation); + }; + } + }); + HARD_CODED_PROPERTY_DATA.put("facing_clockwise", (behavior, property) -> { + if (property.valueClass() == HorizontalDirection.class) { + @SuppressWarnings("unchecked") + Property directionProperty = (Property) property; + behavior.rotateFunction = (thisBlock, blockState, rotation) -> + blockState.with(directionProperty, rotation.rotate(blockState.get(directionProperty).toDirection()).toHorizontalDirection()) + .customBlockState().handle(); + behavior.mirrorFunction = (thisBlock, blockState, mirror) -> { + Rotation rotation = mirror.getRotation(blockState.get(directionProperty).toDirection()); + return behavior.rotateFunction.rotate(thisBlock, blockState, rotation); + }; + } + }); + } + + private MirrorFunction mirrorFunction; + private RotateFunction rotateFunction; + + public BukkitBlockBehavior(CustomBlock customBlock) { + super(customBlock); + for (Property property : customBlock.properties()) { + Optional.ofNullable(HARD_CODED_PROPERTY_DATA.get(property.name())).ifPresent( + c -> c.accept(this, property) + ); + } + } + + @Override + public Object mirror(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + if (this.mirrorFunction != null) { + int id = BlockStateUtils.blockStateToId(args[0]); + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(id); + return this.mirrorFunction.mirror(thisBlock, state, MirrorUtils.fromNMSMirror(args[1])); + } + return super.mirror(thisBlock, args, superMethod); + } + + @Override + public Object rotate(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + if (this.rotateFunction != null) { + int id = BlockStateUtils.blockStateToId(args[0]); + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(id); + return this.rotateFunction.rotate(thisBlock, state, RotationUtils.fromNMSRotation(args[1])); + } + return super.rotate(thisBlock, args, superMethod); + } + + @FunctionalInterface + interface MirrorFunction { + + Object mirror(Object thisBlock, ImmutableBlockState state, Mirror mirror) throws Exception; + } + + @FunctionalInterface + interface RotateFunction { + + Object rotate(Object thisBlock, ImmutableBlockState state, Rotation rotation) throws Exception; + } +} 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..77a537757 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 @@ -9,7 +9,6 @@ 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.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.parameter.LootParameters; @@ -29,14 +28,15 @@ import org.bukkit.Registry; import java.util.*; import java.util.concurrent.Callable; -public class BushBlockBehavior extends AbstractBlockBehavior { +public class BushBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); protected final List tagsCanSurviveOn; protected final Set blocksCansSurviveOn; protected final Set customBlocksCansSurviveOn; protected final boolean any; - public BushBlockBehavior(List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + public BushBlockBehavior(CustomBlock block, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + super(block); this.tagsCanSurviveOn = tagsCanSurviveOn; this.blocksCansSurviveOn = blocksCansSurviveOn; this.customBlocksCansSurviveOn = customBlocksCansSurviveOn; @@ -63,7 +63,8 @@ public class BushBlockBehavior extends AbstractBlockBehavior { blockPos = args[4]; } if (!canSurvive(thisBlock, state, level, blockPos)) { - ImmutableBlockState previousState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state)); + int stateId = BlockStateUtils.blockStateToId(state); + ImmutableBlockState previousState = BukkitBlockManager.instance().getImmutableBlockState(stateId); if (previousState != null && !previousState.isEmpty()) { ContextHolder.Builder builder = ContextHolder.builder(); BlockPos pos = LocationUtils.fromBlockPos(blockPos); @@ -74,6 +75,8 @@ public class BushBlockBehavior extends AbstractBlockBehavior { for (Item item : previousState.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } + world.playBlockSound(vec3d, previousState.sounds().breakSound()); + FastNMS.INSTANCE.method$Level$levelEvent(level, 2001, blockPos, stateId); } return Reflections.method$Block$defaultBlockState.invoke(Reflections.instance$Blocks$AIR); } @@ -93,7 +96,7 @@ public class BushBlockBehavior extends AbstractBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { Tuple, Set, Set> tuple = readTagsAndState(arguments); - return new BushBlockBehavior(tuple.left(), tuple.mid(), tuple.right()); + return new BushBlockBehavior(block, tuple.left(), tuple.mid(), tuple.right()); } } 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 3df82844d..2f79abc20 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 @@ -32,9 +32,9 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior { private Object defaultBlockState; private ImmutableBlockState defaultImmutableBlockState; - public ConcretePowderBlockBehavior(float hurtAmount, int maxHurt, Key block) { - super(hurtAmount, maxHurt); - this.targetBlock = block; + public ConcretePowderBlockBehavior(CustomBlock block, float hurtAmount, int maxHurt, Key targetBlock) { + super(block, hurtAmount, maxHurt); + this.targetBlock = targetBlock; } public ImmutableBlockState defaultImmutableBlockState() { @@ -161,7 +161,7 @@ public class ConcretePowderBlockBehavior extends FallingBlockBehavior { if (solidBlock == null) { throw new IllegalArgumentException("No `solid-block` specified for concrete powder block behavior"); } - return new ConcretePowderBlockBehavior(hurtAmount, hurtMax, Key.of(solidBlock)); + return new ConcretePowderBlockBehavior(block, hurtAmount, hurtMax, Key.of(solidBlock)); } } } 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 b4cde1bd8..cb2651ba5 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,36 +5,51 @@ 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.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.loot.LootContext; +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.loot.number.NumberProvider; +import net.momirealms.craftengine.core.loot.number.NumberProviders; +import net.momirealms.craftengine.core.util.context.ContextHolder; +import net.momirealms.craftengine.core.util.context.ContextKey; +import net.momirealms.craftengine.core.world.Vec3d; +import net.momirealms.craftengine.core.world.Vec3i; import net.momirealms.craftengine.shared.block.BlockBehavior; import org.bukkit.World; import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.ThreadLocalRandom; public class CropBlockBehavior extends BushBlockBehavior { public static final Factory FACTORY = new Factory(); private final IntegerProperty ageProperty; private final float growSpeed; private final int minGrowLight; + private final boolean isBoneMealTarget; + private final NumberProvider boneMealBonus; - public CropBlockBehavior(List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, - Property ageProperty, float growSpeed, int minGrowLight) { - super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + public CropBlockBehavior(CustomBlock block, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, + Property ageProperty, float growSpeed, int minGrowLight, boolean isBoneMealTarget, NumberProvider boneMealBonus) { + super(block, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); this.ageProperty = (IntegerProperty) ageProperty; this.growSpeed = growSpeed; this.minGrowLight = minGrowLight; + this.isBoneMealTarget = isBoneMealTarget; + this.boneMealBonus = boneMealBonus; } public final int getAge(ImmutableBlockState state) { @@ -45,6 +60,22 @@ public class CropBlockBehavior extends BushBlockBehavior { return state.get(ageProperty) == ageProperty.max; } + public float growSpeed() { + return growSpeed; + } + + public boolean isBoneMealTarget() { + return isBoneMealTarget; + } + + public NumberProvider boneMealBonus() { + return boneMealBonus; + } + + public int minGrowLight() { + return minGrowLight; + } + private static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { return (int) Reflections.method$BlockAndTintGetter$getRawBrightness.invoke(level, pos, 0); } @@ -63,7 +94,7 @@ public class CropBlockBehavior extends BushBlockBehavior { 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()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); } } } @@ -81,6 +112,7 @@ public class CropBlockBehavior extends BushBlockBehavior { @Override public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) { + if (!this.isBoneMealTarget) return false; Object state = args[2]; ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(state)); if (immutableBlockState != null && !immutableBlockState.isEmpty()) { @@ -112,17 +144,22 @@ public class CropBlockBehavior extends BushBlockBehavior { sendParticles = true; } - int i = this.getAge(immutableBlockState) + RandomUtils.generateRandomInt(2, 5); + 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); + + net.momirealms.craftengine.core.world.World wrappedWorld = new BukkitWorld(world); + int i = this.getAge(immutableBlockState) + this.boneMealBonus.getInt(new LootContext(wrappedWorld, ContextHolder.builder() + .withParameter(LootParameters.WORLD, wrappedWorld) + .withParameter(LootParameters.LOCATION, Vec3d.atCenterOf(new Vec3i(x, y, z))) + .build(), ThreadLocalRandom.current(), 1)); 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()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(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.25, 0.25, 0.25); } } @@ -137,10 +174,11 @@ public class CropBlockBehavior extends BushBlockBehavior { if (ageProperty == null) { throw new IllegalArgumentException("age property not set for crop"); } - // 存活条件是最小生长亮度-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); + float growSpeed = MiscUtils.getAsFloat(arguments.getOrDefault("grow-speed", 0.125f)); + boolean isBoneMealTarget = (boolean) arguments.getOrDefault("is-bone-meal-target", true); + NumberProvider boneMealAgeBonus = NumberProviders.fromObject(arguments.getOrDefault("bone-meal-age-bonus", 1)); + return new CropBlockBehavior(block, tuple.left(), tuple.mid(), tuple.right(), ageProperty, growSpeed, minGrowLight, isBoneMealTarget, boneMealAgeBonus); } } } 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 08bbc708a..8b2813ea9 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 @@ -8,7 +8,6 @@ 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.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.parameter.LootParameters; @@ -21,12 +20,13 @@ import net.momirealms.craftengine.shared.block.BlockBehavior; import java.util.Map; import java.util.concurrent.Callable; -public class FallingBlockBehavior extends AbstractBlockBehavior { +public class FallingBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final float hurtAmount; private final int maxHurt; - public FallingBlockBehavior(float hurtAmount, int maxHurt) { + public FallingBlockBehavior(CustomBlock block, float hurtAmount, int maxHurt) { + super(block); this.hurtAmount = hurtAmount; this.maxHurt = maxHurt; } @@ -131,7 +131,7 @@ public class FallingBlockBehavior extends AbstractBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { float hurtAmount = MiscUtils.getAsFloat(arguments.getOrDefault("hurt-amount", -1f)); int hurtMax = MiscUtils.getAsInt(arguments.getOrDefault("max-hurt", -1)); - return new FallingBlockBehavior(hurtAmount, hurtMax); + return new FallingBlockBehavior(block, hurtAmount, hurtMax); } } } 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 2c43e4ea8..2d802ed2b 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 @@ -13,8 +13,8 @@ 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); + public HangingBlockBehavior(CustomBlock block, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { + super(block, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); } @Override @@ -32,7 +32,7 @@ public class HangingBlockBehavior extends BushBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { Tuple, Set, Set> tuple = readTagsAndState(arguments); - return new HangingBlockBehavior(tuple.left(), tuple.mid(), tuple.right()); + return new HangingBlockBehavior(block, tuple.left(), tuple.mid(), tuple.right()); } } } 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 d454b2c1b..99b543466 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 @@ -39,8 +39,8 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { @Nullable private final Property waterloggedProperty; - public LeavesBlockBehavior(int maxDistance, Property distanceProperty, Property persistentProperty, @Nullable Property waterloggedProperty) { - super(waterloggedProperty); + public LeavesBlockBehavior(CustomBlock block, int maxDistance, Property distanceProperty, Property persistentProperty, @Nullable Property waterloggedProperty) { + super(block, waterloggedProperty); this.maxDistance = maxDistance; this.distanceProperty = distanceProperty; this.persistentProperty = persistentProperty; @@ -97,7 +97,7 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { if (blockState == newState.customBlockState().handle()) { Reflections.method$BlockStateBase$updateNeighbourShapes.invoke(blockState, level, blockPos, UpdateOption.UPDATE_ALL.flags(), 512); } else { - Reflections.method$Level$setBlock.invoke(level, blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, newState.customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); } } } @@ -182,7 +182,7 @@ public class LeavesBlockBehavior extends WaterLoggedBlockBehavior { } Property waterlogged = (Property) block.getProperty("waterlogged"); int actual = distance.possibleValues().get(distance.possibleValues().size() - 1); - return new LeavesBlockBehavior(actual, distance, persistent, waterlogged); + return new LeavesBlockBehavior(block, actual, distance, persistent, waterlogged); } } } 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 cb5934a2e..dda596013 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 @@ -16,8 +16,8 @@ public class OnLiquidBlockBehavior extends BushBlockBehavior { private final boolean onWater; private final boolean onLava; - public OnLiquidBlockBehavior(boolean onWater, boolean onLava) { - super(List.of(), Set.of(), Set.of()); + public OnLiquidBlockBehavior(CustomBlock block, boolean onWater, boolean onLava) { + super(block, List.of(), Set.of(), Set.of()); this.onWater = onWater; this.onLava = onLava; } @@ -34,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(liquidTypes.contains("water"), liquidTypes.contains("lava")); + return new OnLiquidBlockBehavior(block, 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 04df34dc8..e985c3d24 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 @@ -31,8 +31,8 @@ public class SaplingBlockBehavior extends BushBlockBehavior { private final double boneMealSuccessChance; private final float growSpeed; - public SaplingBlockBehavior(Key feature, Property stageProperty, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, double boneMealSuccessChance, float growSpeed) { - super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + public SaplingBlockBehavior(CustomBlock block, Key feature, Property stageProperty, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, double boneMealSuccessChance, float growSpeed) { + super(block, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); this.feature = feature; this.stageProperty = stageProperty; this.boneMealSuccessChance = boneMealSuccessChance; @@ -79,18 +79,18 @@ public class SaplingBlockBehavior extends BushBlockBehavior { CraftEngine.instance().logger().warn("Configured feature not found: " + treeFeature()); return; } - Object chunkGenerator = Reflections.method$ServerChunkCache$getGenerator.invoke(Reflections.field$ServerLevel$chunkSource.get(world)); + Object chunkGenerator = Reflections.method$ServerChunkCache$getGenerator.invoke(FastNMS.INSTANCE.method$ServerLevel$getChunkSource(world)); Object configuredFeature = Reflections.method$Holder$value.invoke(holder.get()); Object fluidState = Reflections.method$Level$getFluidState.invoke(world, blockPos); Object legacyState = Reflections.method$FluidState$createLegacyBlock.invoke(fluidState); - Reflections.method$Level$setBlock.invoke(world, blockPos, legacyState, UpdateOption.UPDATE_NONE.flags()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, legacyState, UpdateOption.UPDATE_NONE.flags()); if ((boolean) Reflections.method$ConfiguredFeature$place.invoke(configuredFeature, world, chunkGenerator, randomSource, blockPos)) { if (FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, blockPos) == legacyState) { Reflections.method$ServerLevel$sendBlockUpdated.invoke(world, blockPos, blockState, legacyState, 2); } } else { // failed to place, rollback changes - Reflections.method$Level$setBlock.invoke(world, blockPos, blockState, UpdateOption.UPDATE_NONE.flags()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(world, blockPos, blockState, UpdateOption.UPDATE_NONE.flags()); } } @@ -150,7 +150,7 @@ 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(block, 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/StrippableBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java index 6d0429c37..6a5d4ee7f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java @@ -1,18 +1,18 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.core.block.CustomBlock; -import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.shared.block.BlockBehavior; import java.util.Map; -public class StrippableBlockBehavior extends AbstractBlockBehavior { +public class StrippableBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final Key stripped; - public StrippableBlockBehavior(Key stripped) { + public StrippableBlockBehavior(CustomBlock block, Key stripped) { + super(block); this.stripped = stripped; } @@ -28,7 +28,7 @@ public class StrippableBlockBehavior extends AbstractBlockBehavior { if (stripped == null) { throw new IllegalArgumentException("stripped is null"); } - return new StrippableBlockBehavior(Key.of(stripped)); + return new StrippableBlockBehavior(block, Key.of(stripped)); } } } 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 c8f0dfc67..c11a5d511 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 @@ -38,17 +38,15 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { private final boolean nearLava; private final IntegerProperty ageProperty; private final float growSpeed; - private final CustomBlock customBlock; public SugarCaneBlockBehavior(CustomBlock customBlock, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn, Property ageProperty, int maxHeight, boolean nearWater, boolean nearLava, float growSpeed) { - super(tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + super(customBlock, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); this.nearWater = nearWater; this.nearLava = nearLava; this.maxHeight = maxHeight; this.ageProperty = (IntegerProperty) ageProperty; this.growSpeed = growSpeed; - this.customBlock = customBlock; } @Override @@ -57,19 +55,21 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { Object level = args[1]; Object blockPos = args[2]; if (!canSurvive(thisBlock, blockState, level, blockPos)) { - ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + int stateId = BlockStateUtils.blockStateToId(blockState); + ImmutableBlockState currentState = BukkitBlockManager.instance().getImmutableBlockState(stateId); 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); } + world.playBlockSound(vec3d, currentState.sounds().breakSound()); + FastNMS.INSTANCE.method$Level$levelEvent(level, 2001, blockPos, stateId); } } } @@ -120,13 +120,13 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { if (age >= this.ageProperty.max || RandomUtils.generateRandomFloat(0, 1) < this.growSpeed) { Object abovePos = LocationUtils.above(blockPos); if (VersionHelper.isVersionNewerThan1_21_5()) { - Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, customBlock.defaultState().customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); + Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, super.customBlock.defaultState().customBlockState().handle(), UpdateOption.UPDATE_ALL.flags()); } else { - Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, customBlock.defaultState().customBlockState().handle()); + Reflections.method$CraftEventFactory$handleBlockGrowEvent.invoke(null, level, abovePos, super.customBlock.defaultState().customBlockState().handle()); } - Reflections.method$Level$setBlock.invoke(level, blockPos, currentState.with(this.ageProperty, this.ageProperty.min).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(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()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, currentState.with(this.ageProperty, age + 1).customBlockState().handle(), UpdateOption.UPDATE_NONE.flags()); } } } @@ -143,7 +143,7 @@ public class SugarCaneBlockBehavior extends BushBlockBehavior { // 如果下方是同种方块 if (!BlockStateUtils.isVanillaBlock(id)) { ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(id); - if (immutableBlockState.owner().value() == this.customBlock) { + if (immutableBlockState.owner().value() == super.customBlock) { return true; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WaterLoggedBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WaterLoggedBlockBehavior.java index 401c56bc0..ae874f173 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WaterLoggedBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WaterLoggedBlockBehavior.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.core.block.CustomBlock; -import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.shared.block.BlockBehavior; @@ -9,12 +8,13 @@ import org.jetbrains.annotations.Nullable; import java.util.Map; -public class WaterLoggedBlockBehavior extends AbstractBlockBehavior { +public class WaterLoggedBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); @Nullable private final Property waterloggedProperty; - public WaterLoggedBlockBehavior(@Nullable Property waterloggedProperty) { + public WaterLoggedBlockBehavior(CustomBlock block, @Nullable Property waterloggedProperty) { + super(block); this.waterloggedProperty = waterloggedProperty; } @@ -82,7 +82,7 @@ public class WaterLoggedBlockBehavior extends AbstractBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { Property waterlogged = (Property) block.getProperty("waterlogged"); - return new WaterLoggedBlockBehavior(waterlogged); + return new WaterLoggedBlockBehavior(block, waterlogged); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java index 3066082fb..c499b31c8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/BukkitFurnitureManager.java @@ -41,9 +41,8 @@ public class BukkitFurnitureManager implements FurnitureManager { private final Map byId = new HashMap<>(); - private final Map furnitureByBaseEntityId = new ConcurrentHashMap<>(256, 0.5f); + private final Map furnitureByRealEntityId = new ConcurrentHashMap<>(256, 0.5f); private final Map furnitureByEntityId = new ConcurrentHashMap<>(512, 0.5f); - private final Map furnitureByCollisionEntitiesId = new ConcurrentHashMap<>(256, 0.5f); // Event listeners private final Listener dismountListener; private final FurnitureEventListener furnitureEventListener; @@ -78,7 +77,7 @@ public class BukkitFurnitureManager implements FurnitureManager { SoundData data = furniture.settings().sounds().placeSound(); location.getWorld().playSound(location, data.id().toString(), SoundCategory.BLOCKS, data.volume(), data.pitch()); } - return getLoadedFurnitureByBaseEntityId(furnitureEntity.getEntityId()); + return getLoadedFurnitureByRealEntityId(furnitureEntity.getEntityId()); } @Override @@ -258,13 +257,13 @@ public class BukkitFurnitureManager implements FurnitureManager { } @Override - public boolean isFurnitureBaseEntity(int entityId) { - return this.furnitureByBaseEntityId.containsKey(entityId); + public boolean isFurnitureRealEntity(int entityId) { + return this.furnitureByRealEntityId.containsKey(entityId); } @Nullable - public LoadedFurniture getLoadedFurnitureByBaseEntityId(int entityId) { - return this.furnitureByBaseEntityId.get(entityId); + public LoadedFurniture getLoadedFurnitureByRealEntityId(int entityId) { + return this.furnitureByRealEntityId.get(entityId); } @Nullable @@ -272,19 +271,22 @@ public class BukkitFurnitureManager implements FurnitureManager { return this.furnitureByEntityId.get(entityId); } - @Nullable - public LoadedFurniture getLoadedFurnitureByCollisionEntityId(int entityId) { - return this.furnitureByCollisionEntitiesId.get(entityId); - } - protected void handleBaseFurnitureUnload(Entity entity) { int id = entity.getEntityId(); - LoadedFurniture furniture = this.furnitureByBaseEntityId.remove(id); + LoadedFurniture furniture = this.furnitureByRealEntityId.remove(id); if (furniture != null) { - furniture.destroySeats(); + Location location = entity.getLocation(); + boolean isPreventing = FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4); + if (!isPreventing) { + furniture.destroySeats(); + } for (int sub : furniture.entityIds()) { this.furnitureByEntityId.remove(sub); } + for (CollisionEntity collision : furniture.collisionEntities()) { + this.furnitureByRealEntityId.remove(FastNMS.INSTANCE.method$Entity$getId(collision)); + if (!isPreventing) collision.destroy(); + } } } @@ -297,7 +299,7 @@ public class BukkitFurnitureManager implements FurnitureManager { Optional optionalFurniture = getFurniture(key); if (optionalFurniture.isEmpty()) return; CustomFurniture customFurniture = optionalFurniture.get(); - LoadedFurniture previous = this.furnitureByBaseEntityId.get(display.getEntityId()); + LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId()); if (previous != null) return; Location location = entity.getLocation(); if (FastNMS.INSTANCE.isPreventingStatusUpdates(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4)) { @@ -319,7 +321,7 @@ public class BukkitFurnitureManager implements FurnitureManager { Optional optionalFurniture = getFurniture(key); if (optionalFurniture.isPresent()) { CustomFurniture customFurniture = optionalFurniture.get(); - LoadedFurniture previous = this.furnitureByBaseEntityId.get(display.getEntityId()); + LoadedFurniture previous = this.furnitureByRealEntityId.get(display.getEntityId()); if (previous != null) return; addNewFurniture(display, customFurniture, getAnchorType(entity, customFurniture)); return; @@ -351,13 +353,13 @@ public class BukkitFurnitureManager implements FurnitureManager { private synchronized LoadedFurniture addNewFurniture(ItemDisplay display, CustomFurniture furniture, AnchorType anchorType) { LoadedFurniture loadedFurniture = new LoadedFurniture(display, furniture, anchorType); - this.furnitureByBaseEntityId.put(loadedFurniture.baseEntityId(), loadedFurniture); + this.furnitureByRealEntityId.put(loadedFurniture.baseEntityId(), loadedFurniture); for (int entityId : loadedFurniture.entityIds()) { this.furnitureByEntityId.put(entityId, loadedFurniture); } for (CollisionEntity collisionEntity : loadedFurniture.collisionEntities()) { int collisionEntityId = FastNMS.INSTANCE.method$Entity$getId(collisionEntity); - this.furnitureByCollisionEntitiesId.put(collisionEntityId, loadedFurniture); + this.furnitureByRealEntityId.put(collisionEntityId, loadedFurniture); } loadedFurniture.initializeColliders(); return loadedFurniture; @@ -373,7 +375,7 @@ public class BukkitFurnitureManager implements FurnitureManager { Integer baseFurniture = vehicle.getPersistentDataContainer().get(FURNITURE_SEAT_BASE_ENTITY_KEY, PersistentDataType.INTEGER); if (baseFurniture == null) return; vehicle.remove(); - LoadedFurniture furniture = getLoadedFurnitureByBaseEntityId(baseFurniture); + LoadedFurniture furniture = getLoadedFurnitureByRealEntityId(baseFurniture); if (furniture == null) { return; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java index 90841f3e7..668c35060 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/LoadedFurniture.java @@ -112,9 +112,9 @@ public class LoadedFurniture { }); } try { - this.cachedSpawnPacket = Reflections.constructor$ClientboundBundlePacket.newInstance(packets); + this.cachedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); if (this.minimized) { - this.cachedMinimizedSpawnPacket = Reflections.constructor$ClientboundBundlePacket.newInstance(minimizedPackets); + this.cachedMinimizedSpawnPacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(minimizedPackets); } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to init spawn packets for furniture " + id, e); @@ -126,6 +126,7 @@ public class LoadedFurniture { if (colliderSize != 0) { Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(this.location.getWorld()); for (int i = 0; i < colliderSize; i++) { + // TODO better shulker hitbox Collider collider = placement.colliders()[i]; Vector3f offset = conjugated.transform(new Vector3f(collider.position())); Vector3d offset1 = collider.point1(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java index f4bcbebb7..f4d61ad0d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java @@ -44,7 +44,7 @@ public class ShulkerHitBox extends AbstractHitBox { if (this.interactionEntity) { // make it a litter bigger - InteractionEntityData.Height.addEntityDataIfNotDefaultValue(getPhysicalPeek(peek * 0.01F) * scale + 1.01f, cachedInteractionValues); + InteractionEntityData.Height.addEntityDataIfNotDefaultValue((getPhysicalPeek(peek * 0.01F) + 1) * scale + 0.01f, cachedInteractionValues); InteractionEntityData.Width.addEntityDataIfNotDefaultValue(scale + 0.005f, cachedInteractionValues); InteractionEntityData.Responsive.addEntityDataIfNotDefaultValue(interactive, cachedInteractionValues); } 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 e19d88049..511a3845b 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 @@ -150,7 +150,7 @@ public class BlockItemBehavior extends ItemBehavior { Object blockState = state.customBlockState().handle(); Object blockPos = LocationUtils.toBlockPos(context.getClickedPos()); Object voxelShape = Reflections.method$CollisionContext$of.invoke(null, player); - Object world = Reflections.field$CraftWorld$ServerLevel.get(context.getLevel().platformWorld()); + Object world = FastNMS.INSTANCE.field$CraftWorld$ServerLevel((World) context.getLevel().platformWorld()); boolean defaultReturn = ((!this.checkStatePlacement() || (boolean) Reflections.method$BlockStateBase$canSurvive.invoke(blockState, world, blockPos)) && (boolean) Reflections.method$ServerLevel$checkEntityCollision.invoke(world, blockState, player, voxelShape, blockPos, true)); Block block = FastNMS.INSTANCE.method$CraftBlock$at(world, blockPos); 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..2a2f64bc8 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 @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.item.recipe; import com.destroystokyo.paper.event.inventory.PrepareResultEvent; 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.plugin.injector.BukkitInjector; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; @@ -347,7 +348,7 @@ public class RecipeEventListener implements Listener { BukkitRecipeManager.minecraftRecipeManager(), Reflections.instance$RecipeType$CAMPFIRE_COOKING, Reflections.constructor$SingleRecipeInput.newInstance(Reflections.method$CraftItemStack$asNMSCopy.invoke(null, itemStack)), - Reflections.field$CraftWorld$ServerLevel.get(event.getPlayer().getWorld()), + FastNMS.INSTANCE.field$CraftWorld$ServerLevel(event.getPlayer().getWorld()), null ); if (optionalMCRecipe.isEmpty()) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java index 608c891bc..688e8743b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TestCommand.java @@ -1,9 +1,6 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.momirealms.craftengine.bukkit.nms.CollisionEntity; -import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import org.bukkit.Location; @@ -25,11 +22,7 @@ public class TestCommand extends BukkitCommandFeature { Player player = context.sender(); Location location = player.getLocation(); try { - Object level = Reflections.field$CraftWorld$ServerLevel.get(player.getWorld()); - Object aabb = FastNMS.INSTANCE.constructor$AABB(location.getBlockX(), location.getBlockY(), location.getBlockZ(), - location.getBlockX() + 1, location.getBlockY() + 1, location.getBlockZ() + 1); - CollisionEntity nmsEntity = FastNMS.INSTANCE.createCollisionEntity(level, aabb, location.getBlockX() + 0.5, location.getBlockY(), location.getBlockZ() + 0.5, false); - FastNMS.INSTANCE.method$LevelWriter$addFreshEntity(level, nmsEntity); + } catch (Exception e) { e.printStackTrace(); } 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 a2656ed50..5be2a0711 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 @@ -174,6 +174,12 @@ public class BukkitInjector { // getShape .method(ElementMatchers.is(Reflections.method$BlockBehaviour$getShape)) .intercept(MethodDelegation.to(GetShapeInterceptor.INSTANCE)) + // mirror + .method(ElementMatchers.is(Reflections.method$BlockBehaviour$mirror)) + .intercept(MethodDelegation.to(MirrorInterceptor.INSTANCE)) + // rotate + .method(ElementMatchers.is(Reflections.method$BlockBehaviour$rotate)) + .intercept(MethodDelegation.to(RotateInterceptor.INSTANCE)) // tick .method(ElementMatchers.is(Reflections.method$BlockBehaviour$tick)) .intercept(MethodDelegation.to(TickInterceptor.INSTANCE)) @@ -711,8 +717,8 @@ public class BukkitInjector { int id = (int) Reflections.field$Direction$data3d.get(direction); // Y axis if (id == 0 || id == 1) { - Object chunkSource = Reflections.field$ServerLevel$chunkSource.get(serverLevel); - Reflections.method$ServerChunkCache$blockChanged.invoke(chunkSource, blockPos); + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel); + FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, blockPos); if (id == 1) { NoteBlockChainUpdateUtils.noteBlockChainUpdate(serverLevel, chunkSource, Reflections.instance$Direction$DOWN, blockPos, 0); } else { @@ -736,6 +742,36 @@ public class BukkitInjector { } } + public static class MirrorInterceptor { + public static final MirrorInterceptor INSTANCE = new MirrorInterceptor(); + + @RuntimeType + public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) throws Exception { + ObjectHolder holder = ((BehaviorHolder) thisObj).getBehaviorHolder(); + try { + return holder.value().mirror(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run mirror", e); + return superMethod.call(); + } + } + } + + public static class RotateInterceptor { + public static final RotateInterceptor INSTANCE = new RotateInterceptor(); + + @RuntimeType + public Object intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) throws Exception { + ObjectHolder holder = ((BehaviorHolder) thisObj).getBehaviorHolder(); + try { + return holder.value().rotate(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run rotate", e); + return superMethod.call(); + } + } + } + public static class RandomTickInterceptor { public static final RandomTickInterceptor INSTANCE = new RandomTickInterceptor(); 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 c87622e84..d55ca3054 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 @@ -92,31 +92,19 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } this.registerConsumers(); this.packetsConsumer = ((serverPlayer, packets) -> { - try { - Object bundle = Reflections.constructor$ClientboundBundlePacket.newInstance(packets); - Reflections.method$ServerGamePacketListenerImpl$sendPacket.invoke( - Reflections.field$ServerPlayer$connection.get(serverPlayer), bundle); - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to create bundle packet", e); - } + Object bundle = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); + FastNMS.INSTANCE.sendPacket(serverPlayer, bundle); }); - this.delayedPacketConsumer = (serverPlayer, packet) -> { - try { - Reflections.method$ServerGamePacketListenerImpl$sendPacket.invoke( - Reflections.field$ServerPlayer$connection.get(serverPlayer), packet); - } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to invoke send packet", e); - } - }; + this.delayedPacketConsumer = FastNMS.INSTANCE::sendPacket; this.immediatePacketConsumer = (serverPlayer, packet) -> { try { - Reflections.method$Connection$sendPacketImmediate.invoke(Reflections.field$ServerCommonPacketListenerImpl$connection.get(Reflections.field$ServerPlayer$connection.get(serverPlayer)), packet, null, true); + Reflections.method$Connection$sendPacketImmediate.invoke(FastNMS.INSTANCE.field$Player$connection$connection(serverPlayer), packet, null, true); } catch (ReflectiveOperationException e) { plugin.logger().warn("Failed to invoke send packet", e); } }; this.active = true; - this.hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; + hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; instance = this; } @@ -258,17 +246,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } public Channel getChannel(Player player) { - try { - return (Channel) Reflections.field$Channel.get( - Reflections.field$NetworkManager.get( - Reflections.field$ServerPlayer$connection.get( - FastNMS.INSTANCE.method$CraftPlayer$getHandle(player) - ) - ) - ); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } + return (Channel) FastNMS.INSTANCE.field$Player$connection$connection$channel(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)); } public void sendPacket(@NotNull Player player, @NotNull Object packet) { 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 c8ec39fe2..424b361e6 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 @@ -70,7 +70,8 @@ public class PacketConsumers { } public static int remapMOD(int stateId) { - return mappingsMOD[stateId]; + int modStateId = mappingsMOD[stateId]; + return BlockStateUtils.isVanillaBlock(modStateId) ? remap(modStateId) : modStateId; } public static final TriConsumer LEVEL_CHUNK_WITH_LIGHT = (user, event, packet) -> { @@ -290,7 +291,7 @@ public class PacketConsumers { private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) throws Exception { 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 serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world); Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, LocationUtils.toBlockPos(pos)); int stateId = BlockStateUtils.blockStateToId(blockState); // not a custom block @@ -545,7 +546,7 @@ public class PacketConsumers { }; private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Exception { - Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(player.getWorld()); + Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld()); Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, pos); ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); if (state == null) return; @@ -617,7 +618,7 @@ public class PacketConsumers { } else if (entityType == Reflections.instance$EntityType$ITEM_DISPLAY) { // Furniture int entityId = (int) Reflections.field$ClientboundAddEntityPacket$entityId.get(packet); - LoadedFurniture furniture = BukkitFurnitureManager.instance().getLoadedFurnitureByBaseEntityId(entityId); + LoadedFurniture furniture = BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(entityId); if (furniture != null) { user.furnitureView().computeIfAbsent(furniture.baseEntityId(), k -> new ArrayList<>()).addAll(furniture.fakeEntityIds()); user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); @@ -628,7 +629,7 @@ public class PacketConsumers { } else if (entityType == Reflections.instance$EntityType$SHULKER) { // Cancel collider entity packet int entityId = (int) Reflections.field$ClientboundAddEntityPacket$entityId.get(packet); - LoadedFurniture furniture = BukkitFurnitureManager.instance().getLoadedFurnitureByCollisionEntityId(entityId); + LoadedFurniture furniture = BukkitFurnitureManager.instance().getLoadedFurnitureByRealEntityId(entityId); if (furniture != null) { event.setCancelled(true); } @@ -641,7 +642,7 @@ public class PacketConsumers { public static final TriConsumer SYNC_ENTITY_POSITION = (user, event, packet) -> { try { int entityId = (int) Reflections.field$ClientboundEntityPositionSyncPacket$id.get(packet); - if (BukkitFurnitureManager.instance().isFurnitureBaseEntity(entityId)) { + if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { event.setCancelled(true); } } catch (Exception e) { @@ -652,7 +653,7 @@ public class PacketConsumers { public static final TriConsumer MOVE_ENTITY = (user, event, packet) -> { try { int entityId = (int) Reflections.field$ClientboundMoveEntityPacket$entityId.get(packet); - if (BukkitFurnitureManager.instance().isFurnitureBaseEntity(entityId)) { + if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { event.setCancelled(true); } } catch (Exception e) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java index 1f587764e..1a2e8be93 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/DirectionUtils.java @@ -40,4 +40,13 @@ public class DirectionUtils { case EAST -> Reflections.instance$Direction$EAST; }; } + + public static Direction fromNMSDirection(Object direction) { + try { + int index = (int) Reflections.method$Direction$ordinal.invoke(direction); + return Direction.values()[index]; + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } } 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 27bb4e598..7d84c1a83 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 @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.plugin.CraftEngine; import org.bukkit.World; @@ -11,30 +12,25 @@ public class LightUtils { private LightUtils() {} - @SuppressWarnings("unchecked") public static void updateChunkLight(World world, Map sectionPosSet) { try { - Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(world); - Object chunkSource = Reflections.field$ServerLevel$chunkSource.get(serverLevel); + Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world); + Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(serverLevel); for (Map.Entry entry : sectionPosSet.entrySet()) { long chunkKey = entry.getKey(); - Object chunkHolder = Reflections.method$ServerChunkCache$getVisibleChunkIfPresent.invoke(chunkSource, chunkKey); + Object chunkHolder = FastNMS.INSTANCE.method$ServerChunkCache$getVisibleChunkIfPresent(chunkSource, chunkKey); if (chunkHolder == null) continue; - 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); - } + List players = FastNMS.INSTANCE.method$ChunkHolder$getPlayers(chunkHolder); if (players.isEmpty()) continue; Object lightEngine = Reflections.field$ChunkHolder$lightEngine.get(chunkHolder); BitSet blockChangedLightSectionFilter = (BitSet) Reflections.field$ChunkHolder$blockChangedLightSectionFilter.get(chunkHolder); blockChangedLightSectionFilter.or(entry.getValue()); BitSet skyChangedLightSectionFilter = (BitSet) Reflections.field$ChunkHolder$skyChangedLightSectionFilter.get(chunkHolder); - Object chunkPos = Reflections.constructor$ChunkPos.newInstance((int) chunkKey, (int) (chunkKey >> 32)); - Object lightPacket = Reflections.constructor$ClientboundLightUpdatePacket.newInstance(chunkPos, lightEngine, skyChangedLightSectionFilter, blockChangedLightSectionFilter); - Reflections.method$ChunkHolder$broadcast.invoke(chunkHolder, players, lightPacket); + Object chunkPos = FastNMS.INSTANCE.constructor$ChunkPos((int) chunkKey, (int) (chunkKey >> 32)); + Object lightPacket = FastNMS.INSTANCE.constructor$ClientboundLightUpdatePacket(chunkPos, lightEngine, skyChangedLightSectionFilter, blockChangedLightSectionFilter); + for (Object player : players) { + FastNMS.INSTANCE.sendPacket(player, lightPacket); + } blockChangedLightSectionFilter.clear(); skyChangedLightSectionFilter.clear(); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MirrorUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MirrorUtils.java new file mode 100644 index 000000000..1aae07bd1 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/MirrorUtils.java @@ -0,0 +1,31 @@ +package net.momirealms.craftengine.bukkit.util; + +import net.momirealms.craftengine.core.util.Mirror; + +public class MirrorUtils { + + private MirrorUtils() {} + + public static Mirror fromNMSMirror(Object mirror) { + try { + int index = (int) Reflections.method$Mirror$ordinal.invoke(mirror); + return Mirror.values()[index]; + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + public static Object toNMSMirror(Mirror mirror) { + switch (mirror) { + case FRONT_BACK -> { + return Reflections.instance$Mirror$FRONT_BACK; + } + case LEFT_RIGHT -> { + return Reflections.instance$Mirror$LEFT_RIGHT; + } + default -> { + return Reflections.instance$Mirror$NONE; + } + } + } +} 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 5b4f28f4a..5127e9916 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 @@ -12,7 +12,7 @@ public class NoteBlockChainUpdateUtils { Object relativePos = Reflections.method$BlockPos$relative.invoke(blockPos, direction); Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, relativePos); if (BlockStateUtils.isClientSideNoteBlock(state)) { - Reflections.method$ServerChunkCache$blockChanged.invoke(chunkSource, relativePos); + FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(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 16ecc73d9..6932a75b8 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 @@ -421,9 +421,9 @@ public class Reflections { ) ); - public static final Constructor constructor$ClientboundBundlePacket = requireNonNull( - ReflectionUtils.getConstructor(clazz$ClientboundBundlePacket, Iterable.class) - ); +// public static final Constructor constructor$ClientboundBundlePacket = requireNonNull( +// ReflectionUtils.getConstructor(clazz$ClientboundBundlePacket, Iterable.class) +// ); public static final Class clazz$Packet = requireNonNull( ReflectionUtils.getClazz( @@ -494,12 +494,6 @@ public class Reflections { ) ); - public static final Field field$NetworkManager = requireNonNull( - VersionHelper.isVersionNewerThan1_20_2() ? - ReflectionUtils.getDeclaredField(clazz$ServerGamePacketListenerImpl.getSuperclass(), clazz$Connection, 0) : - ReflectionUtils.getDeclaredField(clazz$ServerGamePacketListenerImpl, clazz$Connection, 0) - ); - public static final Field field$Channel = requireNonNull( ReflectionUtils.getDeclaredField( clazz$Connection, Channel.class, 0 @@ -1053,11 +1047,12 @@ public class Reflections { ) ); - public static final Field field$CraftWorld$ServerLevel = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$CraftWorld, clazz$ServerLevel, 0 - ) - ); +// @Deprecated +// public static final Field field$CraftWorld$ServerLevel = requireNonNull( +// ReflectionUtils.getDeclaredField( +// clazz$CraftWorld, clazz$ServerLevel, 0 +// ) +// ); public static final Method method$ServerLevel$getNoiseBiome = requireNonNull( ReflectionUtils.getMethod( @@ -1806,17 +1801,18 @@ public class Reflections { ) ); - public static final Field field$ServerLevel$chunkSource = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$ServerLevel, clazz$ServerChunkCache, 0 - ) - ); + @Deprecated +// public static final Field field$ServerLevel$chunkSource = requireNonNull( +// ReflectionUtils.getDeclaredField( +// clazz$ServerLevel, clazz$ServerChunkCache, 0 +// ) +// ); - public static final Method method$ServerChunkCache$blockChanged = requireNonNull( - ReflectionUtils.getMethod( - clazz$ServerChunkCache, void.class, clazz$BlockPos - ) - ); +// public static final Method method$ServerChunkCache$blockChanged = requireNonNull( +// ReflectionUtils.getMethod( +// clazz$ServerChunkCache, void.class, clazz$BlockPos +// ) +// ); // public static final Method method$ServerChunkCache$getChunkAtIfLoadedMainThread = requireNonNull( // ReflectionUtils.getMethod( @@ -2644,6 +2640,7 @@ public class Reflections { ) ); + @Deprecated public static final Constructor constructor$ChunkPos = requireNonNull( ReflectionUtils.getConstructor( clazz$ChunkPos, int.class, int.class @@ -2695,7 +2692,7 @@ public class Reflections { ) ); - // 1.20 ~ 1.21.4 + // 1.20 ~ 1.21.4 moonrise public static final Method method$ChunkHolder$getPlayers = ReflectionUtils.getMethod( clazz$ChunkHolder, List.class, boolean.class @@ -2725,6 +2722,7 @@ public class Reflections { ) ); + @Deprecated public static final Method method$ServerChunkCache$getVisibleChunkIfPresent = requireNonNull( ReflectionUtils.getDeclaredMethod( clazz$ServerChunkCache, clazz$ChunkHolder, long.class @@ -3577,12 +3575,6 @@ public class Reflections { ) ); - public static final Method method$Level$setBlock = requireNonNull( - ReflectionUtils.getMethod( - clazz$Level, boolean.class, clazz$BlockPos, clazz$BlockState, int.class - ) - ); - public static final Method method$Block$updateFromNeighbourShapes = requireNonNull( ReflectionUtils.getStaticMethod( clazz$Block, clazz$BlockState, clazz$BlockState, clazz$LevelAccessor, clazz$BlockPos @@ -3735,6 +3727,7 @@ public class Reflections { ) ); + @Deprecated public static final Method method$LevelWriter$setBlock = requireNonNull( ReflectionUtils.getMethod( clazz$LevelWriter, boolean.class, clazz$BlockPos, clazz$BlockState, int.class @@ -5930,4 +5923,131 @@ public class Reflections { ? ReflectionUtils.getMethod(clazz$Entity, int.class, new String[]{"af"}) : ReflectionUtils.getMethod(clazz$Entity, int.class, new String[]{"getId", "aj", "ah", "af"}) ); + + public static final Class clazz$ClientboundMoveEntityPacket$PosRot = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundMoveEntityPacket$PosRot"), + BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayOutEntity$PacketPlayOutRelEntityMoveLook") + ) + ); + + public static final Class clazz$ClientboundRotateHeadPacket = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundRotateHeadPacket"), + BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayOutEntityHeadRotation") + ) + ); + + public static final Field field$ClientboundRotateHeadPacket$entityId = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ClientboundRotateHeadPacket, int.class, 0 + ) + ); + + public static final Class clazz$ClientboundSetEntityMotionPacket = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("network.protocol.game.ClientboundSetEntityMotionPacket"), + BukkitReflectionUtils.assembleMCClass("network.protocol.game.PacketPlayOutEntityVelocity") + ) + ); + + public static final Field field$ClientboundSetEntityMotionPacket$id = requireNonNull( + ReflectionUtils.getDeclaredField( + clazz$ClientboundSetEntityMotionPacket, int.class, 0 + ) + ); + + public static final Class clazz$Rotation = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.level.block.Rotation"), + BukkitReflectionUtils.assembleMCClass("world.level.block.EnumBlockRotation") + ) + ); + + public static final Method method$Rotation$values = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$Rotation, clazz$Rotation.arrayType() + ) + ); + + public static final Object instance$Rotation$NONE; + public static final Object instance$Rotation$CLOCKWISE_90; + public static final Object instance$Rotation$CLOCKWISE_180; + public static final Object instance$Rotation$COUNTERCLOCKWISE_90; + + static { + try { + Object[] values = (Object[]) method$Rotation$values.invoke(null); + instance$Rotation$NONE = values[0]; + instance$Rotation$CLOCKWISE_90 = values[1]; + instance$Rotation$CLOCKWISE_180 = values[2]; + instance$Rotation$COUNTERCLOCKWISE_90 = values[3]; + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + public static final Method method$Rotation$ordinal = requireNonNull( + ReflectionUtils.getMethod( + clazz$Rotation, int.class, new String[]{"ordinal"} + ) + ); + + public static final Class clazz$Mirror = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.level.block.Mirror"), + BukkitReflectionUtils.assembleMCClass("world.level.block.EnumBlockMirror") + ) + ); + + public static final Method method$Mirror$values = requireNonNull( + ReflectionUtils.getStaticMethod( + clazz$Mirror, clazz$Mirror.arrayType() + ) + ); + + public static final Object instance$Mirror$NONE; + public static final Object instance$Mirror$LEFT_RIGHT; + public static final Object instance$Mirror$FRONT_BACK; + + static { + try { + Object[] values = (Object[]) method$Mirror$values.invoke(null); + instance$Mirror$NONE = values[0]; + instance$Mirror$LEFT_RIGHT = values[1]; + instance$Mirror$FRONT_BACK = values[2]; + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + public static final Method method$Mirror$ordinal = requireNonNull( + ReflectionUtils.getMethod( + clazz$Mirror, int.class, new String[]{"ordinal"} + ) + ); + + public static final Method method$BlockBehaviour$rotate = requireNonNull( + ReflectionUtils.getDeclaredMethod( + clazz$BlockBehaviour, clazz$BlockState, clazz$BlockState, clazz$Rotation + ) + ); + + public static final Method method$BlockBehaviour$mirror = requireNonNull( + ReflectionUtils.getDeclaredMethod( + clazz$BlockBehaviour, clazz$BlockState, clazz$BlockState, clazz$Mirror + ) + ); + + public static final Method method$BlockStateBase$rotate = requireNonNull( + ReflectionUtils.getMethod( + clazz$BlockStateBase, clazz$BlockState, clazz$Rotation + ) + ); + + public static final Method method$BlockStateBase$mirror = requireNonNull( + ReflectionUtils.getMethod( + clazz$BlockStateBase, clazz$BlockState, clazz$Mirror + ) + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RotationUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RotationUtils.java new file mode 100644 index 000000000..95cd0b40c --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/RotationUtils.java @@ -0,0 +1,34 @@ +package net.momirealms.craftengine.bukkit.util; + +import net.momirealms.craftengine.core.util.Rotation; + +public class RotationUtils { + + private RotationUtils() {} + + public static Rotation fromNMSRotation(Object rotation) { + try { + int index = (int) Reflections.method$Rotation$ordinal.invoke(rotation); + return Rotation.values()[index]; + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + public static Object toNMSRotation(Rotation rotation) { + switch (rotation) { + case CLOCKWISE_90 -> { + return Reflections.instance$Rotation$CLOCKWISE_90; + } + case CLOCKWISE_180 -> { + return Reflections.instance$Rotation$CLOCKWISE_180; + } + case COUNTERCLOCKWISE_90 -> { + return Reflections.instance$Rotation$COUNTERCLOCKWISE_90; + } + default -> { + return Reflections.instance$Rotation$NONE; + } + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java index 89192c5ac..5e6aa6235 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorld.java @@ -1,8 +1,8 @@ package net.momirealms.craftengine.bukkit.world; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.util.ItemUtils; -import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; @@ -36,7 +36,7 @@ public class BukkitWorld implements World { @Override public Object serverWorld() { try { - return Reflections.field$CraftWorld$ServerLevel.get(platformWorld()); + return FastNMS.INSTANCE.field$CraftWorld$ServerLevel(platformWorld()); } catch (Exception e) { throw new RuntimeException("Failed to get server world", e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldBlock.java index c7840ffb8..c1addb16d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldBlock.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.bukkit.world; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.item.behavior.BlockItemBehavior; +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; @@ -51,7 +52,7 @@ public class BukkitWorldBlock implements WorldBlock { public boolean isWaterSource(BlockPlaceContext blockPlaceContext) { try { Location location = block.getLocation(); - Object serverLevel = Reflections.field$CraftWorld$ServerLevel.get(block.getWorld()); + Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(block.getWorld()); Object fluidData = Reflections.method$Level$getFluidState.invoke(serverLevel, LocationUtils.toBlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ())); if (fluidData == null) return false; return (boolean) Reflections.method$FluidState$isSource.invoke(fluidData); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/AbstractBlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/AbstractBlockBehavior.java index 948700454..ae8d38e1e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/AbstractBlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/AbstractBlockBehavior.java @@ -1,10 +1,16 @@ package net.momirealms.craftengine.core.block.behavior; +import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.shared.block.BlockBehavior; public abstract class AbstractBlockBehavior extends BlockBehavior { + protected CustomBlock customBlock; + + public AbstractBlockBehavior(CustomBlock customBlock) { + this.customBlock = customBlock; + } public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { return state; diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java index 100a41b5c..965337964 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/furniture/FurnitureManager.java @@ -33,5 +33,5 @@ public interface FurnitureManager extends Reloadable, ConfigSectionParser { Optional getFurniture(Key id); - boolean isFurnitureBaseEntity(int entityId); + boolean isFurnitureRealEntity(int entityId); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/EmojiManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/EmojiManager.java deleted file mode 100644 index 868846fd6..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/font/EmojiManager.java +++ /dev/null @@ -1,9 +0,0 @@ -package net.momirealms.craftengine.core.font; - -import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; - -public interface EmojiManager extends ConfigSectionParser { - String CONFIG_SECTION_NAME = "emojis"; - - -} diff --git a/gradle.properties b/gradle.properties index 0d5805a02..005ca4cf7 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.41 +project_version=0.0.42 config_version=19 lang_version=3 project_group=net.momirealms @@ -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.28 +nms_helper_version=0.34 # Ignite Dependencies mixinextras_version=0.4.1 mixin_version=0.15.2+mixin.0.8.7 diff --git a/readme/README_zh-CN.md b/readme/README_zh-CN.md index 724d29b68..3d3b00dd4 100644 --- a/readme/README_zh-CN.md +++ b/readme/README_zh-CN.md @@ -135,7 +135,7 @@ repositories { ``` ```kotlin dependencies { - compileOnly("net.momirealms:craft-engine-core:0.0.38") - compileOnly("net.momirealms:craft-engine-bukkit:0.0.38") + compileOnly("net.momirealms:craft-engine-core:0.0.42") + compileOnly("net.momirealms:craft-engine-bukkit:0.0.42") } ``` diff --git a/readme/README_zh-TW.md b/readme/README_zh-TW.md index 2b814d637..4bf349bdd 100644 --- a/readme/README_zh-TW.md +++ b/readme/README_zh-TW.md @@ -135,7 +135,7 @@ repositories { ``` ```kotlin dependencies { - compileOnly("net.momirealms:craft-engine-core:0.0.38") - compileOnly("net.momirealms:craft-engine-bukkit:0.0.38") + compileOnly("net.momirealms:craft-engine-core:0.0.42") + compileOnly("net.momirealms:craft-engine-bukkit:0.0.42") } ``` diff --git a/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java b/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java index 54effc4b0..f7d481ee7 100644 --- a/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java +++ b/server-mod/src/main/java/net/momirealms/craftengine/mod/CraftEngineBlock.java @@ -10,10 +10,7 @@ import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.BonemealableBlock; -import net.minecraft.world.level.block.Fallable; +import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; @@ -68,10 +65,30 @@ public class CraftEngineBlock } } + @Override + protected @NotNull BlockState rotate(@NotNull BlockState state, @NotNull Rotation rotation) { + try { + return (BlockState) this.behaviorHolder.value().rotate(this, new Object[]{state, rotation}, () -> super.rotate(state, rotation)); + } catch (Exception e) { + e.printStackTrace(); + return super.rotate(state, rotation); + } + } + + @Override + protected @NotNull BlockState mirror(@NotNull BlockState state, @NotNull Mirror mirror) { + try { + return (BlockState) this.behaviorHolder.value().mirror(this, new Object[]{state, mirror}, () -> super.mirror(state, mirror)); + } catch (Exception e) { + e.printStackTrace(); + return super.mirror(state, mirror); + } + } + @Override protected void tick(@NotNull BlockState state, @NotNull ServerLevel level, @NotNull BlockPos pos, @NotNull RandomSource random) { try { - behaviorHolder.value().tick(this, new Object[]{state, level, pos, random}, () -> { + this.behaviorHolder.value().tick(this, new Object[]{state, level, pos, random}, () -> { super.tick(state, level, pos, random); return null; }); diff --git a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java index 957e207d2..67c22fbd8 100644 --- a/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java +++ b/shared/src/main/java/net/momirealms/craftengine/shared/block/BlockBehavior.java @@ -4,6 +4,14 @@ import java.util.concurrent.Callable; public abstract class BlockBehavior { + public Object rotate(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + return superMethod.call(); + } + + public Object mirror(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + return superMethod.call(); + } + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { return superMethod.call(); }