mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-25 01:49:30 +00:00
兵不厌诈
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
package net.momirealms.craftengine.bukkit.item;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.AxeItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.BoneMealBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.BucketItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.behavior.WaterBucketItemBehavior;
|
||||
import net.momirealms.craftengine.bukkit.item.factory.BukkitItemFactory;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.util.ItemUtils;
|
||||
@@ -41,6 +44,9 @@ public class BukkitItemManager extends AbstractItemManager<ItemStack> {
|
||||
|
||||
static {
|
||||
registerVanillaItemExtraBehavior(AxeItemBehavior.INSTANCE, ItemKeys.WOODEN_AXE, ItemKeys.STONE_AXE, ItemKeys.IRON_AXE, ItemKeys.GOLDEN_AXE, ItemKeys.DIAMOND_AXE, ItemKeys.NETHERITE_AXE);
|
||||
registerVanillaItemExtraBehavior(WaterBucketItemBehavior.INSTANCE, ItemKeys.WATER_BUCKET, ItemKeys.COD_BUCKET, ItemKeys.SALMON_BUCKET, ItemKeys.TROPICAL_FISH_BUCKET, ItemKeys.TADPOLE_BUCKET, ItemKeys.PUFFERFISH_BUCKET, ItemKeys.AXOLOTL_BUCKET);
|
||||
registerVanillaItemExtraBehavior(BucketItemBehavior.INSTANCE, ItemKeys.BUCKET);
|
||||
registerVanillaItemExtraBehavior(BoneMealBehavior.INSTANCE, ItemKeys.BONE_MEAL);
|
||||
}
|
||||
|
||||
private static void registerVanillaItemExtraBehavior(ItemBehavior behavior, Key... items) {
|
||||
|
||||
@@ -120,8 +120,18 @@ public class ItemEventListener implements Listener {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO We need to further investigate how to handle adventure mode
|
||||
// no spectator interactions
|
||||
if (player.isSpectatorMode() || player.isAdventureMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ItemBehavior itemBehavior : optionalItemBehaviors.get()) {
|
||||
InteractionResult result = itemBehavior.useOnBlock(new UseOnContext(player, hand, hitResult));
|
||||
if (result == InteractionResult.SUCCESS_AND_CANCEL) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
int maxY = player.level().worldHeight().getMaxBuildHeight() - 1;
|
||||
if (direction == Direction.UP
|
||||
&& result != InteractionResult.SUCCESS
|
||||
@@ -129,6 +139,7 @@ public class ItemEventListener implements Listener {
|
||||
&& itemBehavior instanceof BlockItemBehavior
|
||||
) {
|
||||
player.sendActionBar(Component.translatable("build.tooHigh").arguments(Component.text(maxY)).color(NamedTextColor.RED));
|
||||
return;
|
||||
}
|
||||
if (result != InteractionResult.PASS) {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.momirealms.craftengine.bukkit.item.behavior;
|
||||
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BoneMealBehavior extends ItemBehavior {
|
||||
public static final BoneMealBehavior INSTANCE = new BoneMealBehavior();
|
||||
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context) {
|
||||
return super.useOnBlock(context);
|
||||
}
|
||||
|
||||
public static class Factory implements ItemBehaviorFactory {
|
||||
@Override
|
||||
public ItemBehavior create(Key id, Map<String, Object> arguments) {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package net.momirealms.craftengine.bukkit.item.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorldBlock;
|
||||
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.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionHand;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BucketItemBehavior extends ItemBehavior {
|
||||
public static final BucketItemBehavior INSTANCE = new BucketItemBehavior();
|
||||
public static final Factory FACTORY = new Factory();
|
||||
private static final Key ITEM_BUCKET_FILL = Key.of("item.bucket.fill");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context) {
|
||||
BukkitWorldBlock clicked = (BukkitWorldBlock) context.getLevel().getBlockAt(context.getClickedPos());
|
||||
Block block = clicked.block();
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData()));
|
||||
if (state == null || state.isEmpty()) return InteractionResult.PASS;
|
||||
CustomBlock customBlock = state.owner().value();
|
||||
Property<Boolean> waterlogged = (Property<Boolean>) customBlock.getProperty("waterlogged");
|
||||
if (waterlogged == null) return InteractionResult.PASS;
|
||||
boolean waterloggedState = state.get(waterlogged);
|
||||
if (!waterloggedState) return InteractionResult.PASS;
|
||||
BlockPos pos = context.getClickedPos();
|
||||
Player player = (Player) context.getPlayer().platformPlayer();
|
||||
World world = player.getWorld();
|
||||
Location location = new Location(world, pos.x(), pos.y(), pos.z());
|
||||
EquipmentSlot slot = context.getHand() == InteractionHand.MAIN_HAND ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND;
|
||||
|
||||
CraftEngineBlocks.place(location, state.with(waterlogged, false), UpdateOption.UPDATE_ALL);
|
||||
if (player.getGameMode() == GameMode.SURVIVAL) {
|
||||
// to prevent dupe in moment
|
||||
player.getInventory().setItem(slot, new ItemStack(Material.AIR));
|
||||
BukkitCraftEngine.instance().scheduler().sync().runDelayed(() ->
|
||||
player.getInventory().setItem(slot, new ItemStack(Material.WATER_BUCKET)), world, location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
}
|
||||
player.setStatistic(Statistic.USE_ITEM, Material.BUCKET, player.getStatistic(Statistic.USE_ITEM, Material.BUCKET) + 1);
|
||||
// client will assume it has sounds
|
||||
// context.getPlayer().level().playBlockSound(Vec3d.atCenterOf(context.getClickedPos()), ITEM_BUCKET_FILL, 1, 1);
|
||||
return InteractionResult.SUCCESS_AND_CANCEL;
|
||||
}
|
||||
|
||||
public static class Factory implements ItemBehaviorFactory {
|
||||
@Override
|
||||
public ItemBehavior create(Key id, Map<String, Object> arguments) {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,15 @@ public class BukkitItemBehaviors extends ItemBehaviors {
|
||||
public static final Key BLOCK_ITEM = Key.from("craftengine:block_item");
|
||||
public static final Key FURNITURE_ITEM = Key.from("craftengine:furniture_item");
|
||||
public static final Key AXE_ITEM = Key.from("craftengine:axe_item");
|
||||
public static final Key WATER_BUCKET_ITEM = Key.from("craftengine:water_bucket_item");
|
||||
public static final Key BUCKET_ITEM = Key.from("craftengine:bucket_item");
|
||||
|
||||
public static void init() {
|
||||
register(EMPTY, (args, id) -> EmptyItemBehavior.INSTANCE);
|
||||
register(BLOCK_ITEM, BlockItemBehavior.FACTORY);
|
||||
register(FURNITURE_ITEM, FurnitureItemBehavior.FACTORY);
|
||||
register(AXE_ITEM, AxeItemBehavior.FACTORY);
|
||||
register(WATER_BUCKET_ITEM, WaterBucketItemBehavior.FACTORY);
|
||||
register(BUCKET_ITEM, BucketItemBehavior.FACTORY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package net.momirealms.craftengine.bukkit.item.behavior;
|
||||
|
||||
import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.bukkit.world.BukkitWorldBlock;
|
||||
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.properties.Property;
|
||||
import net.momirealms.craftengine.core.entity.player.InteractionResult;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehavior;
|
||||
import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory;
|
||||
import net.momirealms.craftengine.core.item.context.UseOnContext;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class WaterBucketItemBehavior extends ItemBehavior {
|
||||
public static final WaterBucketItemBehavior INSTANCE = new WaterBucketItemBehavior();
|
||||
public static final Factory FACTORY = new Factory();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public InteractionResult useOnBlock(UseOnContext context) {
|
||||
BlockPos pos = context.getClickedPos();
|
||||
BukkitWorldBlock clicked = (BukkitWorldBlock) context.getLevel().getBlockAt(pos);
|
||||
Block block = clicked.block();
|
||||
ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockDataToId(block.getBlockData()));
|
||||
if (state == null || state.isEmpty()) return InteractionResult.PASS;
|
||||
CustomBlock customBlock = state.owner().value();
|
||||
Property<Boolean> waterlogged = (Property<Boolean>) customBlock.getProperty("waterlogged");
|
||||
if (waterlogged == null) return InteractionResult.PASS;
|
||||
|
||||
Player player = (Player) context.getPlayer().platformPlayer();
|
||||
World world = player.getWorld();
|
||||
Location location = new Location(world, pos.x(), pos.y(), pos.z());
|
||||
|
||||
// TODO Refactor all of this because it's playing a trick with the server
|
||||
block.setBlockData(BlockStateUtils.createBlockData(state.vanillaBlockState().handle()), false);
|
||||
// actually we should broadcast this change
|
||||
context.getPlayer().sendPacket(BlockStateUtils.createBlockUpdatePacket(pos, state), true);
|
||||
BukkitCraftEngine.instance().scheduler().sync().runDelayed(() ->
|
||||
CraftEngineBlocks.place(location, state.with(waterlogged, true), UpdateOption.UPDATE_ALL), world, location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
||||
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
public static class Factory implements ItemBehaviorFactory {
|
||||
@Override
|
||||
public ItemBehavior create(Key id, Map<String, Object> arguments) {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,6 +124,11 @@ public class BukkitServerPlayer extends Player {
|
||||
return platformPlayer().getGameMode() == GameMode.SPECTATOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAdventureMode() {
|
||||
return platformPlayer().getGameMode() == GameMode.ADVENTURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionBar(Component text) {
|
||||
try {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package net.momirealms.craftengine.bukkit.util;
|
||||
|
||||
import net.momirealms.craftengine.core.block.ImmutableBlockState;
|
||||
import net.momirealms.craftengine.core.block.PushReaction;
|
||||
import net.momirealms.craftengine.core.util.Instrument;
|
||||
import net.momirealms.craftengine.core.util.Key;
|
||||
import net.momirealms.craftengine.core.util.MapColor;
|
||||
import net.momirealms.craftengine.core.world.BlockPos;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
@@ -24,6 +26,14 @@ public class BlockStateUtils {
|
||||
hasInit = true;
|
||||
}
|
||||
|
||||
public static Object createBlockUpdatePacket(BlockPos pos, ImmutableBlockState state) {
|
||||
try {
|
||||
return Reflections.constructor$ClientboundBlockUpdatePacket.newInstance(LocationUtils.toBlockPos(pos), state.customBlockState().handle());
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockData createBlockData(Object blockState) {
|
||||
try {
|
||||
return (BlockData) Reflections.method$CraftBlockData$createData.invoke(null, blockState);
|
||||
|
||||
@@ -18,4 +18,15 @@ public class DirectionUtils {
|
||||
default -> throw new IllegalStateException("Unexpected value: " + face);
|
||||
};
|
||||
}
|
||||
|
||||
public static BlockFace toBlockFace(Direction direction) {
|
||||
return switch (direction) {
|
||||
case UP -> BlockFace.UP;
|
||||
case DOWN -> BlockFace.DOWN;
|
||||
case NORTH -> BlockFace.NORTH;
|
||||
case SOUTH -> BlockFace.SOUTH;
|
||||
case WEST -> BlockFace.WEST;
|
||||
case EAST -> BlockFace.EAST;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,6 @@ package net.momirealms.craftengine.core.entity.player;
|
||||
public enum InteractionResult {
|
||||
FAIL,
|
||||
SUCCESS,
|
||||
PASS
|
||||
PASS,
|
||||
SUCCESS_AND_CANCEL
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ public abstract class Player extends Entity implements NetWorkUser {
|
||||
|
||||
public abstract boolean isSpectatorMode();
|
||||
|
||||
public abstract boolean isAdventureMode();
|
||||
|
||||
public abstract void sendActionBar(Component text);
|
||||
|
||||
public abstract boolean updateLastSuccessfulInteractionTick(int tick);
|
||||
|
||||
@@ -17,4 +17,13 @@ public class ItemKeys {
|
||||
public static final Key GOLDEN_AXE = Key.of("minecraft:golden_axe");
|
||||
public static final Key DIAMOND_AXE = Key.of("minecraft:diamond_axe");
|
||||
public static final Key NETHERITE_AXE = Key.of("minecraft:netherite_axe");
|
||||
public static final Key WATER_BUCKET = Key.of("minecraft:water_bucket");
|
||||
public static final Key COD_BUCKET = Key.of("minecraft:cod_bucket");
|
||||
public static final Key SALMON_BUCKET = Key.of("minecraft:salmon_bucket");
|
||||
public static final Key TADPOLE_BUCKET = Key.of("minecraft:tadpole_bucket");
|
||||
public static final Key TROPICAL_FISH_BUCKET = Key.of("minecraft:tropical_fish_bucket");
|
||||
public static final Key PUFFERFISH_BUCKET = Key.of("minecraft:pufferfish_bucket");
|
||||
public static final Key AXOLOTL_BUCKET = Key.of("minecraft:axolotl_bucket");
|
||||
public static final Key BUCKET = Key.of("minecraft:bucket");
|
||||
public static final Key BONE_MEAL = Key.of("minecraft:bone_meal");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user