wip: added persistent data tags on items

This commit is contained in:
Elias Müller 2024-09-03 21:35:23 +02:00
parent e35145f8ed
commit 4f4a6aef10
6 changed files with 52 additions and 53 deletions

View File

@ -11,30 +11,52 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe; import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
public class PixelBlockItem { public class PixelBlockItem {
public static UUID unusedBlockID = UUID.fromString("98fdf0ae-c3ab-4ef7-ae25-efd518d600de");
public static final String itemTexture = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzE5NGU5ZTc3NTdkMDZkNmY1ZTViZTg0NTQ4YTdjYjUyMTczZDY4Y2NmODAyZDIxMTI3NWQzMWNkYmEwYTA2ZSJ9fX0=";
public static final NamespacedKey recipeKey = new NamespacedKey(PixelBlocksPlugin.plugin, "pixelblock"); public static final NamespacedKey recipeKey = new NamespacedKey(PixelBlocksPlugin.plugin, "pixelblock");
public static NamespacedKey idProperty = new NamespacedKey(PixelBlocksPlugin.plugin, "id");
public static NamespacedKey ownerProperty = new NamespacedKey(PixelBlocksPlugin.plugin, "owner");
public static final String itemTexture = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzE5NGU5ZTc3NTdkMDZkNmY1ZTViZTg0NTQ4YTdjYjUyMTczZDY4Y2NmODAyZDIxMTI3NWQzMWNkYmEwYTA2ZSJ9fX0=";
public record BlockInfo(UUID id, @Nullable UUID owner) {
public boolean hasOwner() {
return owner != null;
}
}
public static @Nullable BlockInfo getBlockInfo(ItemStack item) {
PersistentDataContainer container = item.getItemMeta().getPersistentDataContainer();
if(!container.has(idProperty)) return null;
UUID blockId = UUID.fromString(Objects.requireNonNull(container.get(idProperty, PersistentDataType.STRING)));
UUID ownerId = container.has(ownerProperty)
? UUID.fromString(Objects.requireNonNull(container.get(ownerProperty, PersistentDataType.STRING)))
: null;
return new BlockInfo(blockId, ownerId);
}
public static @NotNull ItemStack getBlockAsItem(@NotNull PixelBlock block) { public static @NotNull ItemStack getBlockAsItem(@NotNull PixelBlock block) {
String ownerName = Optional.ofNullable(Bukkit.getOfflinePlayer(block.ownerUUID).getName()).orElseGet(() -> block.ownerUUID.toString()); String ownerName = Optional.ofNullable(Bukkit.getOfflinePlayer(block.ownerUUID).getName()).orElseGet(() -> block.ownerUUID.toString());
ItemStack itemStack = HeadUtil.getCustomTextureHead(itemTexture); ItemStack itemStack = HeadUtil.getCustomTextureHead(itemTexture);
ItemMeta meta = itemStack.getItemMeta(); ItemMeta meta = itemStack.getItemMeta();
meta.itemName(Component.text(block.blockUUID.toString())); meta.setMaxStackSize(1);
meta.getPersistentDataContainer().set(idProperty, PersistentDataType.STRING, block.blockUUID.toString());
meta.getPersistentDataContainer().set(ownerProperty, PersistentDataType.STRING, block.ownerUUID.toString());
meta.displayName(Component.text("Pixelblock von " + ownerName)); meta.displayName(Component.text("Pixelblock von " + ownerName));
meta.lore(List.of( meta.lore(List.of(
Component.text(ownerName + " ist der Besitzer dieses Blocks."), Component.text(ownerName + " ist der Besitzer dieses Blocks."),
Component.text("Klicke auf den gesetzten Block, um diesen zu bearbeiten!"), Component.text("Klicke auf den gesetzten Block, um diesen zu bearbeiten!"),
Component.text(block.blockUUID.toString()).color(NamedTextColor.DARK_GRAY) Component.text(block.blockUUID.toString()).color(NamedTextColor.DARK_GRAY)
)); ));
meta.setEnchantmentGlintOverride(true);
itemStack.setItemMeta(meta); itemStack.setItemMeta(meta);
return itemStack; return itemStack;
@ -43,13 +65,13 @@ public class PixelBlockItem {
public static @NotNull ItemStack getEmptyPixelBlock() { public static @NotNull ItemStack getEmptyPixelBlock() {
ItemStack item = HeadUtil.getCustomTextureHead(itemTexture); ItemStack item = HeadUtil.getCustomTextureHead(itemTexture);
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
meta.setMaxStackSize(1);
meta.displayName(Component.text("Leerer Pixelblock")); meta.displayName(Component.text("Leerer Pixelblock"));
meta.lore(List.of( meta.lore(List.of(
Component.text("Der erste Spieler, der den Block platziert wird zum Besitzer des Blocks."), Component.text("Der erste Spieler, der den Block platziert wird zum Besitzer des Blocks."),
Component.text("Klicke auf den gesetzten Block, um diesen zu bearbeiten!") Component.text("Klicke auf den gesetzten Block, um diesen zu bearbeiten!")
)); ));
meta.setEnchantmentGlintOverride(true); meta.getPersistentDataContainer().set(idProperty, PersistentDataType.STRING, UUID.randomUUID().toString());
meta.itemName(Component.text(unusedBlockID.toString()));
item.setItemMeta(meta); item.setItemMeta(meta);
return item; return item;
} }
@ -61,7 +83,7 @@ public class PixelBlockItem {
recipe.setIngredient('B', Material.DIAMOND_BLOCK); recipe.setIngredient('B', Material.DIAMOND_BLOCK);
recipe.setIngredient('C', Material.HEART_OF_THE_SEA); recipe.setIngredient('C', Material.HEART_OF_THE_SEA);
recipe.setIngredient('D', Material.GRASS_BLOCK); recipe.setIngredient('D', Material.GRASS_BLOCK);
recipe.setIngredient('E', Material.GLOW_BERRIES); recipe.setIngredient('E', Material.END_CRYSTAL);
return recipe; return recipe;
} }
} }

View File

@ -52,7 +52,6 @@ public final class PixelBlocksPlugin extends JavaPlugin {
new PlacePixelBlockListener(), new PlacePixelBlockListener(),
new PreventInventorysListener(), new PreventInventorysListener(),
new ExitPixelWorldListener(), new ExitPixelWorldListener(),
new CraftPixelBlockListener(),
new PreventIllegalBlocksListener(), new PreventIllegalBlocksListener(),
new BreakPixelBlockListener(), new BreakPixelBlockListener(),
new PlacePixelListener(), new PlacePixelListener(),

View File

@ -1,25 +0,0 @@
package eu.mhsl.minecraft.pixelblocks.listeners;
import eu.mhsl.minecraft.pixelblocks.PixelBlockItem;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.Objects;
public class CraftPixelBlockListener implements Listener {
@EventHandler
static void onCraftItem(CraftItemEvent event) {
ItemStack craftedItem = event.getCurrentItem();
Objects.requireNonNull(craftedItem);
ItemMeta craftedItemMeta = craftedItem.getItemMeta();
String itemName = PlainTextComponentSerializer.plainText().serialize(craftedItemMeta.itemName());
if(!itemName.equals(PixelBlockItem.unusedBlockID.toString())) return;
if(event.isShiftClick()) event.setCancelled(true);
}
}

View File

@ -17,8 +17,8 @@ public class DiscoverRecipesListener implements Listener {
public void shouldDiscover(InventoryClickEvent event) { public void shouldDiscover(InventoryClickEvent event) {
ItemStack clickedItem = event.getCurrentItem(); ItemStack clickedItem = event.getCurrentItem();
if(clickedItem == null) return; if(clickedItem == null) return;
if(!List.of(Material.HEART_OF_THE_SEA, Material.GLOW_BERRIES).contains(clickedItem.getType())) return;
if(!(event.getWhoClicked() instanceof Player player)) return; if(!(event.getWhoClicked() instanceof Player player)) return;
if(!List.of(Material.HEART_OF_THE_SEA, Material.END_CRYSTAL).contains(clickedItem.getType())) return;
if(player.hasDiscoveredRecipe(PixelBlockItem.recipeKey)) return; if(player.hasDiscoveredRecipe(PixelBlockItem.recipeKey)) return;
PixelBlocksPlugin.plugin.getLogger().log(Level.INFO, String.format("%s unlocked tne PixelBlock recipe!", player.getName())); PixelBlocksPlugin.plugin.getLogger().log(Level.INFO, String.format("%s unlocked tne PixelBlock recipe!", player.getName()));
player.discoverRecipe(PixelBlockItem.recipeKey); player.discoverRecipe(PixelBlockItem.recipeKey);

View File

@ -6,7 +6,7 @@ import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlock;
import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld; import eu.mhsl.minecraft.pixelblocks.pixelblock.PixelBlockWorld;
import eu.mhsl.minecraft.pixelblocks.utils.Direction; import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
@ -14,7 +14,6 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.UUID; import java.util.UUID;
@ -22,15 +21,12 @@ public class PlacePixelBlockListener implements Listener {
@EventHandler @EventHandler
static void onBlockPlace(BlockPlaceEvent event) { static void onBlockPlace(BlockPlaceEvent event) {
ItemStack usedItem = event.getItemInHand(); ItemStack usedItem = event.getItemInHand();
ItemMeta usedItemMeta = usedItem.getItemMeta(); PixelBlockItem.BlockInfo info = PixelBlockItem.getBlockInfo(usedItem);
Component displayName = usedItemMeta.displayName(); if(info == null) return;
if(displayName == null) return;
if(!displayName.toString().contains("Pixelblock")) return;
if(!usedItemMeta.getEnchantmentGlintOverride()) return;
World playerWorld = event.getPlayer().getWorld(); World playerWorld = event.getPlayer().getWorld();
if(PixelBlockWorld.isPixelWorld(playerWorld)) { if(PixelBlockWorld.isPixelWorld(playerWorld)) {
event.getPlayer().sendMessage("In Pixelblöcken kann kein Pixelblock erstellt werden."); event.getPlayer().sendMessage(Component.text("In Pixelblöcken kann kein Pixelblock platziert werden.", NamedTextColor.RED));
event.setCancelled(true); event.setCancelled(true);
return; return;
} }
@ -39,10 +35,9 @@ public class PlacePixelBlockListener implements Listener {
playerWorld.getBlockAt(newBlockLocation).setType(Material.AIR); playerWorld.getBlockAt(newBlockLocation).setType(Material.AIR);
Direction direction = Direction.vectorToDirection(event.getPlayer().getLocation().getDirection()); Direction direction = Direction.vectorToDirection(event.getPlayer().getLocation().getDirection());
String itemName = PlainTextComponentSerializer.plainText().serialize(usedItemMeta.itemName());
PixelBlock pixelBlock; PixelBlock pixelBlock;
if(itemName.equals(PixelBlockItem.unusedBlockID.toString())) { if(!info.hasOwner()) {
pixelBlock = new PixelBlock( pixelBlock = new PixelBlock(
newBlockLocation, newBlockLocation,
event.getPlayer().getUniqueId(), event.getPlayer().getUniqueId(),
@ -50,7 +45,7 @@ public class PlacePixelBlockListener implements Listener {
direction direction
); );
} else { } else {
UUID itemUUID = UUID.fromString(itemName); UUID itemUUID = info.id();
pixelBlock = PixelBlocksPlugin.pixelBlocks.stream() pixelBlock = PixelBlocksPlugin.pixelBlocks.stream()
.filter(block -> block.blockUUID.equals(itemUUID)) .filter(block -> block.blockUUID.equals(itemUUID))
.findFirst() .findFirst()

View File

@ -4,6 +4,8 @@ import eu.mhsl.minecraft.pixelblocks.PixelBlockItem;
import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin; import eu.mhsl.minecraft.pixelblocks.PixelBlocksPlugin;
import eu.mhsl.minecraft.pixelblocks.utils.Direction; import eu.mhsl.minecraft.pixelblocks.utils.Direction;
import eu.mhsl.minecraft.pixelblocks.utils.MinMaxUtil; import eu.mhsl.minecraft.pixelblocks.utils.MinMaxUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.entity.*; import org.bukkit.entity.*;
@ -23,7 +25,7 @@ public class PixelBlock {
public Location pixelBlockLocation; public Location pixelBlockLocation;
public Direction facingDirection; public Direction facingDirection;
public ArrayList<Pixel> pixels = new ArrayList<>(); public List<Pixel> pixels = new ArrayList<>();
public Interaction hitbox; public Interaction hitbox;
public ItemDisplay barrier; public ItemDisplay barrier;
@ -33,6 +35,8 @@ public class PixelBlock {
public UUID ownerUUID; public UUID ownerUUID;
public UUID blockUUID; public UUID blockUUID;
public static final int maxPixelsPerBlock = 2000;
public static @NotNull String getWorldName(@NotNull PixelBlock pixelBlock) { public static @NotNull String getWorldName(@NotNull PixelBlock pixelBlock) {
return PixelBlocksPlugin.plugin.getDataFolder().getPath() + File.separator + pixelBlock.blockUUID; return PixelBlocksPlugin.plugin.getDataFolder().getPath() + File.separator + pixelBlock.blockUUID;
} }
@ -58,7 +62,7 @@ public class PixelBlock {
searchLocation.setYaw(0); searchLocation.setYaw(0);
return PixelBlocksPlugin.pixelBlocks.stream() return PixelBlocksPlugin.pixelBlocks.stream()
.filter(block -> block.pixelBlockLocation.equals(searchLocation)) .filter(block -> Objects.equals(block.pixelBlockLocation, searchLocation))
.findFirst() .findFirst()
.orElse(null); .orElse(null);
} }
@ -80,7 +84,7 @@ public class PixelBlock {
public void enterBlock(@NotNull Player player) { public void enterBlock(@NotNull Player player) {
if(PixelBlocksPlugin.configuration.onlyEditableByOwner() && !player.getUniqueId().equals(ownerUUID)) { if(PixelBlocksPlugin.configuration.onlyEditableByOwner() && !player.getUniqueId().equals(ownerUUID)) {
player.sendMessage("Dieser Pixelblock gehört nicht dir!"); player.sendMessage(Component.text("Dieser Pixelblock gehört nicht dir!", NamedTextColor.RED));
return; return;
} }
@ -169,15 +173,18 @@ public class PixelBlock {
BlockData block = blockLocation.getBlock().getBlockData(); BlockData block = blockLocation.getBlock().getBlockData();
if(block.getMaterial() != Material.AIR) { if(block.getMaterial() != Material.AIR) {
Pixel newPixel = new Pixel(relativeLocation, block, ((double) 1 /pixelsPerBlock)); pixels.add(new Pixel(relativeLocation, block, ((double) 1/pixelsPerBlock)));
pixels.add(newPixel);
} }
} }
} }
} }
for(Pixel pixel : this.pixels) { this.pixels.stream()
pixel.place(this.pixelBlockLocation); .limit(maxPixelsPerBlock)
.forEach(pixel -> pixel.place(this.pixelBlockLocation));
if(this.pixels.size() > maxPixelsPerBlock) {
} }
if(this.pixels.size() < 5) { if(this.pixels.size() < 5) {
@ -222,7 +229,7 @@ public class PixelBlock {
} }
this.pixelWorld.getPlayersInWorld().forEach(p -> { this.pixelWorld.getPlayersInWorld().forEach(p -> {
p.sendMessage("Der Pixelblock wurde von einem anderen Spieler abgebaut."); p.sendMessage(Component.text("Der Pixelblock wurde von einem anderen Spieler abgebaut!", NamedTextColor.RED));
p.teleport(this.lastEntryLocation); p.teleport(this.lastEntryLocation);
}); });
@ -234,6 +241,7 @@ public class PixelBlock {
PixelBlocksPlugin.database.deletePixelBlock(this); PixelBlocksPlugin.database.deletePixelBlock(this);
this.pixelBlockLocation.getWorld().playSound(this.pixelBlockLocation, Sound.BLOCK_COPPER_BULB_BREAK, 1.0F, 30); this.pixelBlockLocation.getWorld().playSound(this.pixelBlockLocation, Sound.BLOCK_COPPER_BULB_BREAK, 1.0F, 30);
this.pixelBlockLocation.getWorld().dropItem(this.pixelBlockLocation.add(new Vector(0.5, 0.5, 0.5)), PixelBlockItem.getBlockAsItem(this)); this.pixelBlockLocation.getWorld().dropItem(this.pixelBlockLocation.add(new Vector(0.5, 0.5, 0.5)), PixelBlockItem.getBlockAsItem(this));
this.pixelBlockLocation = null;
} }
private void clearEntities() { private void clearEntities() {