mirror of
https://github.com/Minestom/Minestom.git
synced 2024-11-04 17:59:49 +01:00
Added CanPlaceOn and CanDestroy properties for ItemStacks and implemented checks for them
This commit is contained in:
parent
419ebe7553
commit
7abf6ba9e7
@ -67,6 +67,9 @@ public class ItemStack implements DataContainer, PublicCloneable<ItemStack> {
|
|||||||
private StackingRule stackingRule;
|
private StackingRule stackingRule;
|
||||||
private Data data;
|
private Data data;
|
||||||
|
|
||||||
|
private Set<String> canDestroy;
|
||||||
|
private Set<String> canPlaceOn;
|
||||||
|
|
||||||
{
|
{
|
||||||
if (defaultStackingRule == null)
|
if (defaultStackingRule == null)
|
||||||
defaultStackingRule = VANILLA_STACKING_RULE;
|
defaultStackingRule = VANILLA_STACKING_RULE;
|
||||||
@ -83,6 +86,9 @@ public class ItemStack implements DataContainer, PublicCloneable<ItemStack> {
|
|||||||
this.enchantmentMap = new Object2ShortOpenHashMap<>();
|
this.enchantmentMap = new Object2ShortOpenHashMap<>();
|
||||||
this.attributes = new ArrayList<>();
|
this.attributes = new ArrayList<>();
|
||||||
|
|
||||||
|
this.canDestroy = new HashSet<>();
|
||||||
|
this.canPlaceOn = new HashSet<>();
|
||||||
|
|
||||||
this.itemMeta = findMeta();
|
this.itemMeta = findMeta();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,6 +201,76 @@ public class ItemStack implements DataContainer, PublicCloneable<ItemStack> {
|
|||||||
isSimilar((ItemStack) o) && ((ItemStack) o).getAmount() == getAmount();
|
isSimilar((ItemStack) o) && ((ItemStack) o).getAmount() == getAmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this item can be placed on the block.
|
||||||
|
* This should be enforced only for adventure mode players.
|
||||||
|
* @param block the block's namespaceID
|
||||||
|
* @return <code>true</code> if it can be placed, <code>false</code> otherwise
|
||||||
|
*/
|
||||||
|
public boolean canPlaceOn(String block) {
|
||||||
|
return canPlaceOn.contains(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the block to the list of blocks that
|
||||||
|
* this item can be placed on.
|
||||||
|
* @param block the block's namespaceID
|
||||||
|
*/
|
||||||
|
public void addCanPlaceOn(String block) {
|
||||||
|
canPlaceOn.add(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the block from the set of blocks that
|
||||||
|
* this item can be placed on.
|
||||||
|
* @param block the block's namespaceID
|
||||||
|
*/
|
||||||
|
public void removeCanPlaceOn(String block) {
|
||||||
|
canPlaceOn.remove(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the blocks that this item can be placed on
|
||||||
|
* @return an unmodifiable {@link Set} of blocks
|
||||||
|
*/
|
||||||
|
public Set<String> getCanPlaceOn() {
|
||||||
|
return Collections.unmodifiableSet(canPlaceOn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this item is allowed to break the provided block.
|
||||||
|
* This should be enforced only for adventure mode players.
|
||||||
|
* @param block the block's namespaceID
|
||||||
|
* @return <code>true</code> if this item can destroy it, otherwise <code>false</code>
|
||||||
|
*/
|
||||||
|
public boolean canDestroy(String block) {
|
||||||
|
return canDestroy.contains(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the block to the set of blocks that can be destroyed by this item.
|
||||||
|
* @param block the block's namespaceID
|
||||||
|
*/
|
||||||
|
public void addCanDestroy(String block) {
|
||||||
|
canDestroy.add(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the block from the set of blocks that can be destroyed by this item.
|
||||||
|
* @param block the block's namespaceID
|
||||||
|
*/
|
||||||
|
public void removeCanDestroy(String block) {
|
||||||
|
canDestroy.remove(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the blocks that this item can destroy
|
||||||
|
* @return an unmodifiable {@link Set} of blocks
|
||||||
|
*/
|
||||||
|
public Set<String> getCanDestroy() {
|
||||||
|
return Collections.unmodifiableSet(canDestroy);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the item damage (durability).
|
* Gets the item damage (durability).
|
||||||
*
|
*
|
||||||
@ -555,7 +631,9 @@ public class ItemStack implements DataContainer, PublicCloneable<ItemStack> {
|
|||||||
hideFlag != 0 ||
|
hideFlag != 0 ||
|
||||||
customModelData != 0 ||
|
customModelData != 0 ||
|
||||||
(itemMeta != null && itemMeta.hasNbt()) ||
|
(itemMeta != null && itemMeta.hasNbt()) ||
|
||||||
(data != null && !data.isEmpty());
|
(data != null && !data.isEmpty()) ||
|
||||||
|
canDestroy.size() != 0 ||
|
||||||
|
canPlaceOn.size() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -594,6 +672,9 @@ public class ItemStack implements DataContainer, PublicCloneable<ItemStack> {
|
|||||||
itemStack.hideFlag = hideFlag;
|
itemStack.hideFlag = hideFlag;
|
||||||
itemStack.customModelData = customModelData;
|
itemStack.customModelData = customModelData;
|
||||||
|
|
||||||
|
itemStack.canPlaceOn = new HashSet<>(canPlaceOn);
|
||||||
|
itemStack.canDestroy = new HashSet<>(canDestroy);
|
||||||
|
|
||||||
if (itemMeta != null)
|
if (itemMeta != null)
|
||||||
itemStack.itemMeta = itemMeta.clone();
|
itemStack.itemMeta = itemMeta.clone();
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ import net.minestom.server.inventory.PlayerInventory;
|
|||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import net.minestom.server.item.Material;
|
import net.minestom.server.item.Material;
|
||||||
import net.minestom.server.network.packet.client.play.ClientPlayerBlockPlacementPacket;
|
import net.minestom.server.network.packet.client.play.ClientPlayerBlockPlacementPacket;
|
||||||
|
import net.minestom.server.network.packet.client.play.ClientPlayerDiggingPacket;
|
||||||
|
import net.minestom.server.network.packet.server.play.BlockChangePacket;
|
||||||
import net.minestom.server.utils.BlockPosition;
|
import net.minestom.server.utils.BlockPosition;
|
||||||
import net.minestom.server.utils.Direction;
|
import net.minestom.server.utils.Direction;
|
||||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||||
@ -72,14 +74,19 @@ public class BlockPlacementListener {
|
|||||||
final Material useMaterial = usedItem.getMaterial();
|
final Material useMaterial = usedItem.getMaterial();
|
||||||
|
|
||||||
// Verify if the player can place the block
|
// Verify if the player can place the block
|
||||||
|
boolean canPlaceBlock = true;
|
||||||
{
|
{
|
||||||
if (useMaterial == Material.AIR) { // Can't place air
|
if (useMaterial == Material.AIR) { // Can't place air
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (player.getGameMode().equals(GameMode.ADVENTURE)) { // Can't place in adventure mode
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//Check if the player is allowed to place blocks based on their game mode
|
||||||
|
if (player.getGameMode() == GameMode.SPECTATOR) {
|
||||||
|
canPlaceBlock = false; //Spectators can't place blocks
|
||||||
|
} else if (player.getGameMode() == GameMode.ADVENTURE) {
|
||||||
|
//Check if the block can placed on the block
|
||||||
|
canPlaceBlock = usedItem.canPlaceOn(instance.getBlock(blockPosition).getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the newly placed block position
|
// Get the newly placed block position
|
||||||
@ -89,6 +96,16 @@ public class BlockPlacementListener {
|
|||||||
|
|
||||||
blockPosition.add(offsetX, offsetY, offsetZ);
|
blockPosition.add(offsetX, offsetY, offsetZ);
|
||||||
|
|
||||||
|
if(!canPlaceBlock) {
|
||||||
|
//Send a block change with AIR as block to keep the client in sync,
|
||||||
|
//using refreshChunk results in the client not being in sync
|
||||||
|
//after rapid invalid block placements
|
||||||
|
BlockChangePacket blockChangePacket = new BlockChangePacket();
|
||||||
|
blockChangePacket.blockPosition = blockPosition;
|
||||||
|
blockChangePacket.blockStateId = Block.AIR.getBlockId();
|
||||||
|
player.getPlayerConnection().sendPacket(blockChangePacket);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final Chunk chunk = instance.getChunkAt(blockPosition);
|
final Chunk chunk = instance.getChunkAt(blockPosition);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.minestom.server.listener;
|
package net.minestom.server.listener;
|
||||||
|
|
||||||
|
import net.minestom.server.entity.GameMode;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.event.item.ItemUpdateStateEvent;
|
import net.minestom.server.event.item.ItemUpdateStateEvent;
|
||||||
import net.minestom.server.event.player.PlayerStartDiggingEvent;
|
import net.minestom.server.event.player.PlayerStartDiggingEvent;
|
||||||
@ -10,6 +11,7 @@ import net.minestom.server.instance.block.CustomBlock;
|
|||||||
import net.minestom.server.inventory.PlayerInventory;
|
import net.minestom.server.inventory.PlayerInventory;
|
||||||
import net.minestom.server.item.ItemStack;
|
import net.minestom.server.item.ItemStack;
|
||||||
import net.minestom.server.item.StackingRule;
|
import net.minestom.server.item.StackingRule;
|
||||||
|
import net.minestom.server.item.attribute.ItemAttribute;
|
||||||
import net.minestom.server.network.packet.client.play.ClientPlayerDiggingPacket;
|
import net.minestom.server.network.packet.client.play.ClientPlayerDiggingPacket;
|
||||||
import net.minestom.server.network.packet.server.play.AcknowledgePlayerDiggingPacket;
|
import net.minestom.server.network.packet.server.play.AcknowledgePlayerDiggingPacket;
|
||||||
import net.minestom.server.network.packet.server.play.EntityEffectPacket;
|
import net.minestom.server.network.packet.server.play.EntityEffectPacket;
|
||||||
@ -17,6 +19,7 @@ import net.minestom.server.network.packet.server.play.RemoveEntityEffectPacket;
|
|||||||
import net.minestom.server.potion.Potion;
|
import net.minestom.server.potion.Potion;
|
||||||
import net.minestom.server.potion.PotionEffect;
|
import net.minestom.server.potion.PotionEffect;
|
||||||
import net.minestom.server.utils.BlockPosition;
|
import net.minestom.server.utils.BlockPosition;
|
||||||
|
import net.minestom.server.utils.NamespaceID;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -36,8 +39,23 @@ public class PlayerDiggingListener {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (status == ClientPlayerDiggingPacket.Status.STARTED_DIGGING) {
|
if (status == ClientPlayerDiggingPacket.Status.STARTED_DIGGING) {
|
||||||
|
|
||||||
final short blockStateId = instance.getBlockStateId(blockPosition);
|
final short blockStateId = instance.getBlockStateId(blockPosition);
|
||||||
|
|
||||||
|
//Check if the player is allowed to break blocks based on their game mode
|
||||||
|
if (player.getGameMode() == GameMode.SPECTATOR) {
|
||||||
|
sendAcknowledgePacket(player, blockPosition, blockStateId,
|
||||||
|
ClientPlayerDiggingPacket.Status.STARTED_DIGGING, false);
|
||||||
|
return; //Spectators can't break blocks
|
||||||
|
} else if (player.getGameMode() == GameMode.ADVENTURE) {
|
||||||
|
//Check if the item can break the block with the current item
|
||||||
|
ItemStack itemInMainHand = player.getItemInMainHand();
|
||||||
|
if (!itemInMainHand.canDestroy(instance.getBlock(blockPosition).getName())) {
|
||||||
|
sendAcknowledgePacket(player, blockPosition, blockStateId,
|
||||||
|
ClientPlayerDiggingPacket.Status.STARTED_DIGGING, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final boolean instantBreak = player.isCreative() ||
|
final boolean instantBreak = player.isCreative() ||
|
||||||
player.isInstantBreak() ||
|
player.isInstantBreak() ||
|
||||||
Block.fromStateId(blockStateId).breaksInstantaneously();
|
Block.fromStateId(blockStateId).breaksInstantaneously();
|
||||||
|
@ -26,10 +26,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
// for lack of a better name
|
// for lack of a better name
|
||||||
public final class NBTUtils {
|
public final class NBTUtils {
|
||||||
@ -124,6 +121,7 @@ public final class NBTUtils {
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
public static void loadDataIntoItem(@NotNull ItemStack item, @NotNull NBTCompound nbt) {
|
public static void loadDataIntoItem(@NotNull ItemStack item, @NotNull NBTCompound nbt) {
|
||||||
if (nbt.containsKey("Damage")) item.setDamage(nbt.getInt("Damage"));
|
if (nbt.containsKey("Damage")) item.setDamage(nbt.getInt("Damage"));
|
||||||
if (nbt.containsKey("Unbreakable")) item.setUnbreakable(nbt.getAsByte("Unbreakable") == 1);
|
if (nbt.containsKey("Unbreakable")) item.setUnbreakable(nbt.getAsByte("Unbreakable") == 1);
|
||||||
@ -222,6 +220,21 @@ public final class NBTUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//CanPlaceOn
|
||||||
|
{
|
||||||
|
if (nbt.containsKey("CanPlaceOn")) {
|
||||||
|
NBTList<NBTString> canPlaceOn = nbt.getList("CanPlaceOn");
|
||||||
|
canPlaceOn.forEach(x -> item.addCanPlaceOn(x.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//CanDestroy
|
||||||
|
{
|
||||||
|
if (nbt.containsKey("CanDestroy")) {
|
||||||
|
NBTList<NBTString> canPlaceOn = nbt.getList("CanDestroy");
|
||||||
|
canPlaceOn.forEach(x -> item.addCanDestroy(x.getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void loadEnchantments(NBTList<NBTCompound> enchantments, EnchantmentSetter setter) {
|
public static void loadEnchantments(NBTList<NBTCompound> enchantments, EnchantmentSetter setter) {
|
||||||
@ -368,6 +381,26 @@ public final class NBTUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// End ownership
|
// End ownership
|
||||||
|
|
||||||
|
//CanDestroy
|
||||||
|
{
|
||||||
|
Set<String> canDestroy = itemStack.getCanDestroy();
|
||||||
|
if (canDestroy.size() > 0) {
|
||||||
|
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
||||||
|
canDestroy.forEach(x -> list.add(new NBTString(x.toString())));
|
||||||
|
itemNBT.set("CanDestroy", list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//CanDestroy
|
||||||
|
{
|
||||||
|
Set<String> canPlaceOn = itemStack.getCanPlaceOn();
|
||||||
|
if (canPlaceOn.size() > 0) {
|
||||||
|
NBTList<NBTString> list = new NBTList<>(NBTTypes.TAG_String);
|
||||||
|
canPlaceOn.forEach(x -> list.add(new NBTString(x.toString())));
|
||||||
|
itemNBT.set("CanPlaceOn", list);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user