mirror of
https://github.com/Minestom/Minestom.git
synced 2024-09-28 14:37:31 +02: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 Data data;
|
||||
|
||||
private Set<String> canDestroy;
|
||||
private Set<String> canPlaceOn;
|
||||
|
||||
{
|
||||
if (defaultStackingRule == null)
|
||||
defaultStackingRule = VANILLA_STACKING_RULE;
|
||||
@ -83,6 +86,9 @@ public class ItemStack implements DataContainer, PublicCloneable<ItemStack> {
|
||||
this.enchantmentMap = new Object2ShortOpenHashMap<>();
|
||||
this.attributes = new ArrayList<>();
|
||||
|
||||
this.canDestroy = new HashSet<>();
|
||||
this.canPlaceOn = new HashSet<>();
|
||||
|
||||
this.itemMeta = findMeta();
|
||||
}
|
||||
|
||||
@ -195,6 +201,76 @@ public class ItemStack implements DataContainer, PublicCloneable<ItemStack> {
|
||||
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).
|
||||
*
|
||||
@ -555,7 +631,9 @@ public class ItemStack implements DataContainer, PublicCloneable<ItemStack> {
|
||||
hideFlag != 0 ||
|
||||
customModelData != 0 ||
|
||||
(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.customModelData = customModelData;
|
||||
|
||||
itemStack.canPlaceOn = new HashSet<>(canPlaceOn);
|
||||
itemStack.canDestroy = new HashSet<>(canDestroy);
|
||||
|
||||
if (itemMeta != null)
|
||||
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.Material;
|
||||
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.Direction;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
@ -72,14 +74,19 @@ public class BlockPlacementListener {
|
||||
final Material useMaterial = usedItem.getMaterial();
|
||||
|
||||
// Verify if the player can place the block
|
||||
boolean canPlaceBlock = true;
|
||||
{
|
||||
if (useMaterial == Material.AIR) { // Can't place air
|
||||
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
|
||||
@ -89,6 +96,16 @@ public class BlockPlacementListener {
|
||||
|
||||
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);
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.minestom.server.listener;
|
||||
|
||||
import net.minestom.server.entity.GameMode;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.item.ItemUpdateStateEvent;
|
||||
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.item.ItemStack;
|
||||
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.server.play.AcknowledgePlayerDiggingPacket;
|
||||
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.PotionEffect;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
@ -36,8 +39,23 @@ public class PlayerDiggingListener {
|
||||
return;
|
||||
|
||||
if (status == ClientPlayerDiggingPacket.Status.STARTED_DIGGING) {
|
||||
|
||||
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() ||
|
||||
player.isInstantBreak() ||
|
||||
Block.fromStateId(blockStateId).breaksInstantaneously();
|
||||
|
@ -26,10 +26,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
|
||||
// for lack of a better name
|
||||
public final class NBTUtils {
|
||||
@ -124,6 +121,7 @@ public final class NBTUtils {
|
||||
return item;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public static void loadDataIntoItem(@NotNull ItemStack item, @NotNull NBTCompound nbt) {
|
||||
if (nbt.containsKey("Damage")) item.setDamage(nbt.getInt("Damage"));
|
||||
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) {
|
||||
@ -368,6 +381,26 @@ public final class NBTUtils {
|
||||
}
|
||||
}
|
||||
// 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