mirror of
https://github.com/Minestom/Minestom.git
synced 2024-06-25 22:14:53 +02:00
Merge pull request #154 from Kebab11noel/master
Added CanPlaceOn and CanDestroy for ItemStacks
This commit is contained in:
commit
85998cabd9
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -185,7 +191,9 @@ public class ItemStack implements DataContainer, PublicCloneable<ItemStack> {
|
|||
itemStack.attributes.equals(attributes) &&
|
||||
itemStack.hideFlag == hideFlag &&
|
||||
sameMeta &&
|
||||
dataCheck;
|
||||
dataCheck &&
|
||||
itemStack.canPlaceOn.equals(canPlaceOn) &&
|
||||
itemStack.canDestroy.equals(canDestroy);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -195,6 +203,42 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the blocks that this item can be placed on
|
||||
* @return the {@link Set} of blocks
|
||||
*/
|
||||
public Set<String> getCanPlaceOn() {
|
||||
return 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the blocks that this item can destroy
|
||||
* @return the {@link Set} of blocks
|
||||
*/
|
||||
public Set<String> getCanDestroy() {
|
||||
return canDestroy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item damage (durability).
|
||||
*
|
||||
|
@ -555,7 +599,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.isEmpty() ||
|
||||
!canPlaceOn.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -594,6 +640,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,7 @@ 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.server.play.BlockChangePacket;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
import net.minestom.server.utils.Direction;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
|
@ -72,14 +73,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 +95,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;
|
||||
|
@ -36,8 +37,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.getCanPlaceOn().add(x.getValue()));
|
||||
}
|
||||
}
|
||||
//CanDestroy
|
||||
{
|
||||
if (nbt.containsKey("CanDestroy")) {
|
||||
NBTList<NBTString> canPlaceOn = nbt.getList("CanDestroy");
|
||||
canPlaceOn.forEach(x -> item.getCanDestroy().add(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)));
|
||||
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)));
|
||||
itemNBT.set("CanPlaceOn", list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue
Block a user