diff --git a/src/main/java/cn/nukkit/Player.java b/src/main/java/cn/nukkit/Player.java index 4f3812379b6..dc437f8b0c1 100644 --- a/src/main/java/cn/nukkit/Player.java +++ b/src/main/java/cn/nukkit/Player.java @@ -2755,59 +2755,40 @@ public void onCompletion(Server server) { PlayerBlockPickEvent pickEvent = new PlayerBlockPickEvent(this, block, item); if (this.isSpectator()) { - log.debug("Got block-pick request from " + this.getName() + " when in spectator mode"); pickEvent.setCancelled(); } - this.server.getPluginManager().callEvent(pickEvent); - if (!pickEvent.isCancelled()) { - boolean itemExists = false; - int itemSlot = -1; - for (int slot = 0; slot < this.inventory.getSize(); slot++) { - if (this.inventory.getItem(slot).equals(pickEvent.getItem())) { - if (slot < this.inventory.getHotbarSize()) { - this.inventory.setHeldItemSlot(slot); - } else { - itemSlot = slot; - } - itemExists = true; - break; - } - } + this.pickItem(pickEvent.getItem()); + } + break; + case ProtocolInfo.ENTITY_PICK_REQUEST_PACKET: + EntityPickRequestPacket entityPickRequestPacket = (EntityPickRequestPacket) packet; + targetEntity = this.level.getEntity(entityPickRequestPacket.entityId); + if (!(targetEntity instanceof EntityPickable)) { + break; + } - for (int slot = 0; slot < this.inventory.getHotbarSize(); slot++) { - if (this.inventory.getItem(slot).isNull()) { - if (!itemExists && this.isCreative()) { - this.inventory.setHeldItemSlot(slot); - this.inventory.setItemInHand(pickEvent.getItem()); - break packetswitch; - } else if (itemSlot > -1) { - this.inventory.setHeldItemSlot(slot); - this.inventory.setItemInHand(this.inventory.getItem(itemSlot)); - this.inventory.clear(itemSlot, true); - break packetswitch; - } - } - } + if (this.distanceSquared(targetEntity) > 1000) { + this.getServer().getLogger().debug(this.getName() + ": Entity pick request for a entity too far away"); + break; + } - if (!itemExists && this.isCreative()) { - Item itemInHand = this.inventory.getItemInHand(); - this.inventory.setItemInHand(pickEvent.getItem()); - if (!this.inventory.isFull()) { - for (int slot = 0; slot < this.inventory.getSize(); slot++) { - if (this.inventory.getItem(slot).isNull()) { - this.inventory.setItem(slot, itemInHand); - break; - } - } - } - } else if (itemSlot > -1) { - Item itemInHand = this.inventory.getItemInHand(); - this.inventory.setItemInHand(this.inventory.getItem(itemSlot)); - this.inventory.setItem(itemSlot, itemInHand); - } + item = ((EntityPickable) targetEntity).toItem(); + if (item == null || item.isNull()) { + break; + } + + PlayerEntityPickEvent entityPickEvent = new PlayerEntityPickEvent(this, targetEntity, item); + if (this.isSpectator()) { + entityPickEvent.setCancelled(); + } + this.server.getPluginManager().callEvent(entityPickEvent); + if (entityPickEvent.isCancelled()) { + break; } + + this.pickItem(entityPickEvent.getItem()); break; case ProtocolInfo.ANIMATE_PACKET: if (!this.spawned || !this.isAlive()) { @@ -5324,4 +5305,65 @@ public int getTimeSinceRest() { public void setTimeSinceRest(int timeSinceRest) { this.timeSinceRest = timeSinceRest; } + + protected void pickItem(Item item) { + if (item == null || item.isNull()) { + return; + } + + int existingSlot = -1; + for (int slot = 0; slot < this.inventory.getSize(); slot++) { + if (!this.inventory.getItem(slot).equals(item)) { + continue; + } + + if (slot < this.inventory.getHotbarSize()) { + this.inventory.setHeldItemSlot(slot); + return; + } + + existingSlot = slot; + break; + } + + if (existingSlot == -1 && !this.isCreative()) { + return; + } + + for (int slot = 0; slot < this.inventory.getHotbarSize(); slot++) { + if (!this.inventory.getItem(slot).isNull()) { + continue; + } + + this.inventory.setHeldItemSlot(slot); + if (existingSlot == -1) { + this.inventory.setItemInHand(item); + } else { + this.inventory.setItemInHand(this.inventory.getItem(existingSlot)); + this.inventory.clear(existingSlot, true); + } + return; + } + + Item itemInHand = this.inventory.getItemInHand(); + if (existingSlot != -1) { + this.inventory.setItemInHand(this.inventory.getItem(existingSlot)); + this.inventory.setItem(existingSlot, itemInHand); + return; + } + + this.inventory.setItemInHand(item); + if (this.inventory.isFull()) { + return; + } + + for (int slot = 0; slot < this.inventory.getSize(); slot++) { + if (!this.inventory.getItem(slot).isNull()) { + continue; + } + + this.inventory.setItem(slot, itemInHand); + break; + } + } } diff --git a/src/main/java/cn/nukkit/entity/EntityPickable.java b/src/main/java/cn/nukkit/entity/EntityPickable.java new file mode 100644 index 00000000000..2c7a1b550e0 --- /dev/null +++ b/src/main/java/cn/nukkit/entity/EntityPickable.java @@ -0,0 +1,8 @@ +package cn.nukkit.entity; + +import cn.nukkit.item.Item; + +public interface EntityPickable { + + Item toItem(); +} diff --git a/src/main/java/cn/nukkit/entity/item/EntityBoat.java b/src/main/java/cn/nukkit/entity/item/EntityBoat.java index 4fb25c37c23..4b4900cafe8 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityBoat.java +++ b/src/main/java/cn/nukkit/entity/item/EntityBoat.java @@ -5,6 +5,7 @@ import cn.nukkit.block.BlockWater; import cn.nukkit.entity.Entity; import cn.nukkit.entity.EntityLiving; +import cn.nukkit.entity.EntityPickable; import cn.nukkit.entity.data.ByteEntityData; import cn.nukkit.entity.data.FloatEntityData; import cn.nukkit.entity.passive.EntityWaterAnimal; @@ -29,7 +30,7 @@ /** * Created by yescallop on 2016/2/13. */ -public class EntityBoat extends EntityVehicle { +public class EntityBoat extends EntityVehicle implements EntityPickable { public static final int NETWORK_ID = 90; @@ -433,4 +434,9 @@ public boolean isFull() { public String getInteractButtonText() { return !this.isFull() ? "action.interact.ride.boat" : ""; } + + @Override + public Item toItem() { + return Item.get(Item.BOAT, this.woodID); + } } diff --git a/src/main/java/cn/nukkit/entity/item/EntityEndCrystal.java b/src/main/java/cn/nukkit/entity/item/EntityEndCrystal.java index 992397dad99..c27c512f372 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityEndCrystal.java +++ b/src/main/java/cn/nukkit/entity/item/EntityEndCrystal.java @@ -2,7 +2,9 @@ import cn.nukkit.entity.Entity; import cn.nukkit.entity.EntityExplosive; +import cn.nukkit.entity.EntityPickable; import cn.nukkit.event.entity.EntityDamageEvent; +import cn.nukkit.item.Item; import cn.nukkit.level.Explosion; import cn.nukkit.level.GameRule; import cn.nukkit.level.Position; @@ -12,7 +14,7 @@ /** * Created by PetteriM1 */ -public class EntityEndCrystal extends Entity implements EntityExplosive { +public class EntityEndCrystal extends Entity implements EntityExplosive, EntityPickable { public static final int NETWORK_ID = 71; @@ -93,6 +95,11 @@ public boolean canCollideWith(Entity entity) { return false; } + @Override + public Item toItem() { + return Item.get(Item.END_CRYSTAL); + } + public boolean showBase() { return this.getDataFlag(DATA_FLAGS, DATA_FLAG_SHOWBASE); } diff --git a/src/main/java/cn/nukkit/entity/item/EntityMinecartChest.java b/src/main/java/cn/nukkit/entity/item/EntityMinecartChest.java index d75d9bc2fa7..08267ea3ffd 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityMinecartChest.java +++ b/src/main/java/cn/nukkit/entity/item/EntityMinecartChest.java @@ -3,6 +3,7 @@ import cn.nukkit.Player; import cn.nukkit.block.Block; import cn.nukkit.entity.Entity; +import cn.nukkit.entity.EntityPickable; import cn.nukkit.inventory.InventoryHolder; import cn.nukkit.inventory.MinecartChestInventory; import cn.nukkit.item.Item; @@ -17,7 +18,7 @@ * Created by Snake1999 on 2016/1/30. * Package cn.nukkit.entity.item in project Nukkit. */ -public class EntityMinecartChest extends EntityMinecartAbstract implements InventoryHolder { +public class EntityMinecartChest extends EntityMinecartAbstract implements InventoryHolder, EntityPickable { public static final int NETWORK_ID = 98; @@ -113,4 +114,9 @@ public void saveNBT() { public String getInteractButtonText() { return "action.interact.opencontainer"; } + + @Override + public Item toItem() { + return Item.get(Item.MINECART_WITH_CHEST); + } } diff --git a/src/main/java/cn/nukkit/entity/item/EntityMinecartEmpty.java b/src/main/java/cn/nukkit/entity/item/EntityMinecartEmpty.java index 997fdb8e6d5..f4975ded213 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityMinecartEmpty.java +++ b/src/main/java/cn/nukkit/entity/item/EntityMinecartEmpty.java @@ -3,9 +3,11 @@ import cn.nukkit.Player; import cn.nukkit.entity.Entity; import cn.nukkit.entity.EntityLiving; +import cn.nukkit.entity.EntityPickable; import cn.nukkit.entity.passive.EntityWaterAnimal; import cn.nukkit.event.entity.EntityDamageByBlockEvent; import cn.nukkit.event.entity.EntityDamageEvent.DamageCause; +import cn.nukkit.item.Item; import cn.nukkit.level.format.FullChunk; import cn.nukkit.nbt.tag.CompoundTag; import cn.nukkit.utils.MinecartType; @@ -14,7 +16,7 @@ * Created by Snake1999 on 2016/1/30. * Package cn.nukkit.entity.item in project Nukkit. */ -public class EntityMinecartEmpty extends EntityMinecartAbstract { +public class EntityMinecartEmpty extends EntityMinecartAbstract implements EntityPickable { public static final int NETWORK_ID = 84; @@ -74,4 +76,9 @@ public boolean onUpdate(int currentTick) { public String getInteractButtonText() { return this.passengers.isEmpty() ? "action.interact.ride.minecart" : ""; } + + @Override + public Item toItem() { + return Item.get(Item.MINECART); + } } diff --git a/src/main/java/cn/nukkit/entity/item/EntityMinecartHopper.java b/src/main/java/cn/nukkit/entity/item/EntityMinecartHopper.java index af0bffeec40..9a8f19f0b97 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityMinecartHopper.java +++ b/src/main/java/cn/nukkit/entity/item/EntityMinecartHopper.java @@ -3,6 +3,7 @@ import cn.nukkit.Player; import cn.nukkit.block.Block; import cn.nukkit.entity.Entity; +import cn.nukkit.entity.EntityPickable; import cn.nukkit.inventory.InventoryHolder; import cn.nukkit.inventory.MinecartHopperInventory; import cn.nukkit.item.Item; @@ -13,7 +14,7 @@ import cn.nukkit.nbt.tag.ListTag; import cn.nukkit.utils.MinecartType; -public class EntityMinecartHopper extends EntityMinecartAbstract implements InventoryHolder { +public class EntityMinecartHopper extends EntityMinecartAbstract implements InventoryHolder, EntityPickable { public static final int NETWORK_ID = 96; @@ -109,4 +110,9 @@ public void saveNBT() { public String getInteractButtonText() { return "action.interact.opencontainer"; } + + @Override + public Item toItem() { + return Item.get(Item.MINECART_WITH_HOPPER); + } } diff --git a/src/main/java/cn/nukkit/entity/item/EntityMinecartTNT.java b/src/main/java/cn/nukkit/entity/item/EntityMinecartTNT.java index 8e1c3992e24..33ea08021f9 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityMinecartTNT.java +++ b/src/main/java/cn/nukkit/entity/item/EntityMinecartTNT.java @@ -5,6 +5,7 @@ import cn.nukkit.block.BlockID; import cn.nukkit.entity.Entity; import cn.nukkit.entity.EntityExplosive; +import cn.nukkit.entity.EntityPickable; import cn.nukkit.entity.data.IntEntityData; import cn.nukkit.event.entity.EntityExplosionPrimeEvent; import cn.nukkit.item.Item; @@ -24,7 +25,7 @@ *

* Nukkit Project. */ -public class EntityMinecartTNT extends EntityMinecartAbstract implements EntityExplosive { +public class EntityMinecartTNT extends EntityMinecartAbstract implements EntityExplosive, EntityPickable { public static final int NETWORK_ID = 97; private int fuse; @@ -156,6 +157,11 @@ public boolean onInteract(Player player, Item item, Vector3 clickedPos) { return interact; } + @Override + public Item toItem() { + return Item.get(Item.MINECART_WITH_TNT); + } + @Override public boolean mountEntity(Entity entity, byte mode) { return false; diff --git a/src/main/java/cn/nukkit/entity/item/EntityPainting.java b/src/main/java/cn/nukkit/entity/item/EntityPainting.java index f59f2ca860c..d420d4f3fe4 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityPainting.java +++ b/src/main/java/cn/nukkit/entity/item/EntityPainting.java @@ -3,8 +3,10 @@ import cn.nukkit.Player; import cn.nukkit.entity.Entity; import cn.nukkit.entity.EntityHanging; +import cn.nukkit.entity.EntityPickable; import cn.nukkit.event.entity.EntityDamageByEntityEvent; import cn.nukkit.event.entity.EntityDamageEvent; +import cn.nukkit.item.Item; import cn.nukkit.item.ItemPainting; import cn.nukkit.level.GameRule; import cn.nukkit.level.format.FullChunk; @@ -19,7 +21,7 @@ * author: MagicDroidX * Nukkit Project */ -public class EntityPainting extends EntityHanging { +public class EntityPainting extends EntityHanging implements EntityPickable { public static final int NETWORK_ID = 83; @@ -88,6 +90,11 @@ public Motive getMotive() { return Motive.BY_NAME.get(namedTag.getString("Motive")); } + @Override + public Item toItem() { + return Item.get(Item.PAINTING); + } + public enum Motive { KEBAB("Kebab", 1, 1), AZTEC("Aztec", 1, 1), diff --git a/src/main/java/cn/nukkit/event/player/PlayerEntityPickEvent.java b/src/main/java/cn/nukkit/event/player/PlayerEntityPickEvent.java new file mode 100644 index 00000000000..44c2f34a1c1 --- /dev/null +++ b/src/main/java/cn/nukkit/event/player/PlayerEntityPickEvent.java @@ -0,0 +1,37 @@ +package cn.nukkit.event.player; + +import cn.nukkit.Player; +import cn.nukkit.entity.Entity; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; +import cn.nukkit.item.Item; + +public class PlayerEntityPickEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + private final Entity targetEntity; + private Item item; + + public PlayerEntityPickEvent(Player player, Entity targetEntity, Item item) { + this.targetEntity = targetEntity; + this.item = item; + this.player = player; + } + + public Entity getTargetEntity() { + return targetEntity; + } + + public Item getItem() { + return item; + } + + public void setItem(Item item) { + this.item = item; + } +} diff --git a/src/main/java/cn/nukkit/network/Network.java b/src/main/java/cn/nukkit/network/Network.java index 76ef02b311f..48020bb1cde 100644 --- a/src/main/java/cn/nukkit/network/Network.java +++ b/src/main/java/cn/nukkit/network/Network.java @@ -361,6 +361,7 @@ private void registerPackets() { this.registerPacket(ProtocolInfo.DISCONNECT_PACKET, DisconnectPacket.class); this.registerPacket(ProtocolInfo.ENTITY_EVENT_PACKET, EntityEventPacket.class); this.registerPacket(ProtocolInfo.ENTITY_FALL_PACKET, EntityFallPacket.class); + this.registerPacket(ProtocolInfo.ENTITY_PICK_REQUEST_PACKET, EntityPickRequestPacket.class); this.registerPacket(ProtocolInfo.FULL_CHUNK_DATA_PACKET, LevelChunkPacket.class); this.registerPacket(ProtocolInfo.GAME_RULES_CHANGED_PACKET, GameRulesChangedPacket.class); this.registerPacket(ProtocolInfo.HURT_ARMOR_PACKET, HurtArmorPacket.class); diff --git a/src/main/java/cn/nukkit/network/protocol/EntityPickRequestPacket.java b/src/main/java/cn/nukkit/network/protocol/EntityPickRequestPacket.java index 952e9f12a59..1b26af86917 100644 --- a/src/main/java/cn/nukkit/network/protocol/EntityPickRequestPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/EntityPickRequestPacket.java @@ -7,6 +7,10 @@ public class EntityPickRequestPacket extends DataPacket { public static final byte NETWORK_ID = ProtocolInfo.ENTITY_PICK_REQUEST_PACKET; + public long entityId; + public int hotbarSlot; + public boolean withData; + @Override public byte pid() { return NETWORK_ID; @@ -14,11 +18,13 @@ public byte pid() { @Override public void decode() { - + this.entityId = this.getLLong(); + this.hotbarSlot = this.getByte(); + this.withData = this.getBoolean(); } @Override public void encode() { - //TODO + } }