Skip to content

Commit

Permalink
Merge pull request #61 from TheNextLvl-net/data-components
Browse files Browse the repository at this point in the history
Replace all item meta uses with data components
  • Loading branch information
NonSwag authored Dec 22, 2024
2 parents b2e4e7c + 80cac08 commit 5d6dfc1
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 63 deletions.
16 changes: 6 additions & 10 deletions src/main/java/net/thenextlvl/tweaks/command/item/HeadCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
import core.paper.item.ItemBuilder;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.datacomponent.DataComponentTypes;
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import net.thenextlvl.tweaks.TweaksPlugin;
import net.thenextlvl.tweaks.command.suggestion.OfflinePlayerSuggestionProvider;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

Expand Down Expand Up @@ -105,14 +105,12 @@ private int url(CommandContext<CommandSourceStack> context) {
}

private static @Nullable String getValue(ItemStack item) {
if (!(item.getItemMeta() instanceof SkullMeta skull)) return null;
var profile = skull.getPlayerProfile();
if (profile == null || !profile.hasTextures()) return null;
return profile.getProperties().stream()
var profile = item.getData(DataComponentTypes.PROFILE);
return profile != null ? profile.properties().stream()
.filter(property -> property.getName().equalsIgnoreCase("textures"))
.findFirst()
.map(ProfileProperty::getValue)
.orElse(null);
.orElse(null) : null;
}

private @Nullable String getUrl(ItemStack item) {
Expand All @@ -129,9 +127,7 @@ private int url(CommandContext<CommandSourceStack> context) {
}

private @Nullable String getOwner(ItemStack item) {
return item.getItemMeta() instanceof SkullMeta skull
? skull.getOwningPlayer() != null
? skull.getOwningPlayer().getName()
: null : null;
var profile = item.getData(DataComponentTypes.PROFILE);
return profile != null ? profile.name() : null;
}
}
57 changes: 31 additions & 26 deletions src/main/java/net/thenextlvl/tweaks/command/item/LoreCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import core.paper.item.ItemBuilder;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.datacomponent.DataComponentTypes;
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextReplacementConfig;
import net.thenextlvl.tweaks.TweaksPlugin;
import org.bukkit.entity.Player;
import org.bukkit.inventory.meta.ItemMeta;
import org.jspecify.annotations.NullMarked;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

@NullMarked
Expand Down Expand Up @@ -54,57 +55,61 @@ private LiteralArgumentBuilder<CommandSourceStack> modify(String literal, Comman
}

private int replace(CommandContext<CommandSourceStack> context) {
return modifyLore(context, itemMeta -> {
var lore = itemMeta.lore();
if (lore == null) return;
return modifyLore(context, builder -> {
var data = builder.data(DataComponentTypes.LORE);
if (data == null || data.lines().isEmpty()) return false;
var lore = new ArrayList<>(data.lines());
var text = context.getArgument("text", String.class);
var replacement = deserialize(context.getArgument("replacement", String.class));
var config = TextReplacementConfig.builder()
.matchLiteral(text)
.replacement(replacement)
.build();
lore.replaceAll(component -> component.replaceText(config));
itemMeta.lore(lore);
builder.lore(lore);
return !Objects.equals(data, builder.data(DataComponentTypes.LORE));
});
}

private int append(CommandContext<CommandSourceStack> context) {
return modifyLore(context, itemMeta -> {
var currentLore = Objects.requireNonNullElseGet(itemMeta.lore(),
() -> new ArrayList<Component>());
currentLore.addAll(getLore(context));
itemMeta.lore(currentLore);
return modifyLore(context, builder -> {
builder.appendLore(getLore(context));
return true;
});
}

private int prepend(CommandContext<CommandSourceStack> context) {
return modifyLore(context, itemMeta -> {
var lore = getLore(context);
lore.addAll(Objects.requireNonNullElseGet(itemMeta.lore(),
ArrayList::new));
itemMeta.lore(lore);
return modifyLore(context, builder -> {
builder.prependLore(getLore(context));
return true;
});
}

private int set(CommandContext<CommandSourceStack> context) {
return modifyLore(context, itemMeta -> itemMeta.lore(getLore(context)));
return modifyLore(context, builder -> {
var lore = getLore(context);
var data = builder.data(DataComponentTypes.LORE);
if (data != null && data.lines().equals(lore)) return false;
builder.lore(lore);
return true;
});
}

private int clear(CommandContext<CommandSourceStack> context) {
return modifyLore(context, itemMeta -> itemMeta.lore(null));
return modifyLore(context, builder -> {
var lore = builder.data(DataComponentTypes.LORE);
if (lore == null || lore.lines().isEmpty()) return false;
builder.resetData(DataComponentTypes.LORE);
return true;
});
}

private int modifyLore(CommandContext<CommandSourceStack> context, Consumer<? super ItemMeta> consumer) {
private int modifyLore(CommandContext<CommandSourceStack> context, Function<ItemBuilder, Boolean> function) {
var player = (Player) context.getSource().getSender();
var item = player.getInventory().getItemInMainHand();

if (item.getType().isEmpty()) {
plugin.bundle().sendMessage(player, "command.hold.item");
return 0;
}

var success = item.editMeta(consumer);
var message = success ? "command.item.lore.success" : "command.item.lore.fail";
var success = !item.isEmpty() && function.apply(ItemBuilder.of(item));
var message = item.isEmpty() ? "command.hold.item" : success ? "command.item.lore" : "nothing.changed";

plugin.bundle().sendMessage(player, message);
return success ? Command.SINGLE_SUCCESS : 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.mojang.brigadier.context.CommandContext;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.datacomponent.DataComponentTypes;
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.thenextlvl.tweaks.TweaksPlugin;
Expand Down Expand Up @@ -34,12 +35,11 @@ private int rename(CommandContext<CommandSourceStack> context) {
var text = context.getArgument("name", String.class);
var name = MiniMessage.miniMessage().deserialize(text.replace("\\t", " "));

if (!item.editMeta(itemMeta -> itemMeta.displayName(name))) {
plugin.bundle().sendMessage(player, "command.item.rename.fail");
return 0;
}
var success = !name.equals(item.getData(DataComponentTypes.CUSTOM_NAME));
if (success) item.setData(DataComponentTypes.CUSTOM_NAME, name);
var message = item.isEmpty() ? "command.hold.item" : success ? "command.item.rename" : "nothing.changed";
plugin.bundle().sendMessage(player, message);

plugin.bundle().sendMessage(player, "command.item.rename.success");
return Command.SINGLE_SUCCESS;
return success ? Command.SINGLE_SUCCESS : 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
import com.mojang.brigadier.context.CommandContext;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.datacomponent.DataComponentTypes;
import lombok.RequiredArgsConstructor;
import net.thenextlvl.tweaks.TweaksPlugin;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

import java.util.Arrays;

@NullMarked
@RequiredArgsConstructor
@SuppressWarnings("UnstableApiUsage")
Expand Down Expand Up @@ -42,18 +44,22 @@ private int repair(CommandContext<CommandSourceStack> context) {
var message = success ? "command.item.repaired.success" : "command.item.repaired.fail";

plugin.bundle().sendMessage(player, message);
return Command.SINGLE_SUCCESS;
return success ? Command.SINGLE_SUCCESS : 0;
}

private int repairAll(CommandContext<CommandSourceStack> context) {
var player = (Player) context.getSource().getSender();
var inventory = player.getInventory();
for (var item : inventory.getContents()) repair(item);
plugin.bundle().sendMessage(player, "command.item.repaired.all");
return Command.SINGLE_SUCCESS;
var success = Arrays.stream(inventory.getContents()).map(this::repair).reduce(false, Boolean::logicalOr);
plugin.bundle().sendMessage(player, success ? "command.item.repaired.all" : "command.item.repaired.none");
return success ? Command.SINGLE_SUCCESS : 0;
}

private boolean repair(@Nullable ItemStack item) {
return item != null && item.editMeta(Damageable.class, damageable -> damageable.setDamage(0));
if (item == null) return false;
var damage = item.getData(DataComponentTypes.DAMAGE);
if (damage == null || damage == 0) return false;
item.resetData(DataComponentTypes.DAMAGE);
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.mojang.brigadier.context.CommandContext;
import io.papermc.paper.command.brigadier.CommandSourceStack;
import io.papermc.paper.command.brigadier.Commands;
import io.papermc.paper.datacomponent.DataComponentTypes;
import io.papermc.paper.datacomponent.item.Unbreakable;
import lombok.RequiredArgsConstructor;
import net.thenextlvl.tweaks.TweaksPlugin;
import org.bukkit.entity.Player;
Expand All @@ -26,11 +28,17 @@ public void register(Commands registrar) {

private int unbreakable(CommandContext<CommandSourceStack> context) {
var player = (Player) context.getSource().getSender();
if (!player.getInventory().getItemInMainHand().editMeta(itemMeta -> {
itemMeta.setUnbreakable(!itemMeta.isUnbreakable());
var message = itemMeta.isUnbreakable() ? "command.item.unbreakable.success" : "command.item.unbreakable.removed";
plugin.bundle().sendMessage(player, message);
})) plugin.bundle().sendMessage(player, "command.item.unbreakable.fail");
var item = player.getInventory().getItemInMainHand();
if (!item.hasData(DataComponentTypes.DAMAGE)) {
plugin.bundle().sendMessage(player, "command.item.unbreakable.fail");
return 0;
} else if (item.hasData(DataComponentTypes.UNBREAKABLE)) {
item.resetData(DataComponentTypes.UNBREAKABLE);
plugin.bundle().sendMessage(player, "command.item.unbreakable.removed");
} else {
item.setData(DataComponentTypes.UNBREAKABLE, Unbreakable.unbreakable().build());
plugin.bundle().sendMessage(player, "command.item.unbreakable.success");
}
return Command.SINGLE_SUCCESS;
}
}
9 changes: 4 additions & 5 deletions src/main/resources/tweaks.properties
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,17 @@ command.home.unknown=<red><prefix> You have no home called <dark_red><name></dar
command.hunger.satisfied.others=<gray><prefix> <green><player>'s</green> hunger has been satisfied</gray>
command.hunger.satisfied.self=<gray><prefix> Your hunger has been satisfied</gray>
command.inventory.full=<red><prefix> Your inventory is full</red>
command.item.head.fail=<red><prefix> You did not receive any player head</red>
command.item.head.none=<red><prefix> Could not find matching skull data</red>
command.item.head.player=<gray><prefix> Head owner<dark_gray>:</dark_gray> <click:copy_to_clipboard:'<owner>'><hover:show_text:'<lang:chat.copy.click>'><green><owner></green></hover></click></gray>
command.item.head.received=<gray><prefix> You received a player head</gray>
command.item.head.url=<gray><prefix> Head URL<dark_gray>:</dark_gray> <click:open_url:'<full_url>'><hover:show_text:'<lang:chat.copy.click>'><green><url></green></hover></click></gray>
command.item.head.value=<gray><prefix> Head Base64<dark_gray>:</dark_gray> <click:copy_to_clipboard:'<full_value>'><hover:show_text:'<lang:chat.copy.click>'><green><value></green></hover></click></gray>
command.item.lore.fail=<red><prefix> Failed to change the lore of your item</red>
command.item.lore.success=<gray><prefix> Successfully changed the lore of your item</gray>
command.item.lore=<gray><prefix> Successfully changed the lore of your item</gray>
command.item.received=<gray><prefix> You received <green><amount> x <item></green></gray>
command.item.rename.fail=<red><prefix> Failed to rename your item</red>
command.item.rename.success=<gray><prefix> Successfully renamed your item</gray>
command.item.rename=<gray><prefix> Successfully renamed your item</gray>
command.item.repaired.all=<gray><prefix> All of your items got repaired</gray>
command.item.repaired.fail=<red><prefix> Failed to repair your item</red>
command.item.repaired.none=<red><prefix> None of your items got repaired</red>
command.item.repaired.success=<gray><prefix>Your item got repaired</gray>
command.item.unbreakable.fail=<red><prefix> Failed to make your item unbreakable</red>
command.item.unbreakable.removed=<gray><prefix> Your item is no longer unbreakable</gray>
Expand Down Expand Up @@ -139,6 +137,7 @@ gui.placeholder.leggings=<dark_gray>»</dark_gray> <green>Leggings</green>
gui.placeholder.off-hand=<dark_gray>»</dark_gray> <aqua>Off Hand</aqua>
gui.title.homes=Your Homes
gui.title.warps=Warps
nothing.changed=<red><prefix> Nothing could be changed</red>
player.connected=<gray><prefix> <click:suggest_command:'/tell <player> '><green><chat_display_name></green></click> joined the game</gray>
player.disconnected=<gray><prefix> <click:suggest_command:'/tell <player> '><green><chat_display_name></green></click> left the game</gray>
player.not.found=<red><prefix> The player <dark_red><player></dark_red> has never played before</red>
Expand Down
9 changes: 4 additions & 5 deletions src/main/resources/tweaks_german.properties
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,17 @@ command.home.unknown=<red><prefix> Du hast kein Zuhause namens <dark_red><name><
command.hunger.satisfied.others=<gray><prefix> <green><player>'s</green> Hunger wurde gestillt</gray>
command.hunger.satisfied.self=<gray><prefix> Dein Hunger wurde gestillt</gray>
command.inventory.full=<red><prefix> Dein Inventar ist voll</red>
command.item.head.fail=<red><prefix> Du hast keinen Spielerkopf erhalten</red>
command.item.head.none=<red><prefix> Es konnte keine passenden Kopfdaten gefunden werden</red>
command.item.head.player=<gray><prefix> Kopf Besitzer<dark_gray>:</dark_gray> <click:copy_to_clipboard:'<owner>'><hover:show_text:'<lang:chat.copy.click>'><green><owner></green></hover></click></gray>
command.item.head.received=<gray><prefix> Du hast einen Spieler Kopf erhalten</gray>
command.item.head.url=<gray><prefix> Head URL<dark_gray>:</dark_gray> <click:open_url:'<full_url>'><hover:show_text:'<lang:chat.copy.click>'><green><url></green></hover></click></gray>
command.item.head.value=<gray><prefix> Head Base64<dark_gray>:</dark_gray> <click:copy_to_clipboard:'<full_value>'><hover:show_text:'<lang:chat.copy.click>'><green><value></green></hover></click></gray>
command.item.lore.fail=<red><prefix> Die Beschreibung deines Items konnte nicht angepasst werden</red>
command.item.lore.success=<gray><prefix> Die Beschreibung deines Items wurde erfolgreich angepasst</gray>
command.item.lore=<gray><prefix> Die Beschreibung deines Items wurde erfolgreich angepasst</gray>
command.item.received=<gray><prefix> Du hast <green><amount> x <item></green> erhalten</gray>
command.item.rename.fail=<red><prefix> Dein Item konnte nicht umbenannt werden</red>
command.item.rename.success=<gray><prefix> Dein Item wurde erfolgreich umbenannt</gray>
command.item.rename=<gray><prefix> Dein Item wurde erfolgreich umbenannt</gray>
command.item.repaired.all=<gray><prefix> Alle deine Items wurden repariert</gray>
command.item.repaired.fail=<red><prefix> Dein Item konnte nicht repariert werden</red>
command.item.repaired.none=<red><prefix> Keine deiner Items wurden repariert</red>
command.item.repaired.success=<gray><prefix> Dein Item wurde repariert</gray>
command.item.unbreakable.fail=<red><prefix> Dein Item konnte nicht unzerstörbar gemacht werden</red>
command.item.unbreakable.removed=<gray><prefix> Dein Item ist nicht länger unzerstörbar</gray>
Expand Down Expand Up @@ -134,6 +132,7 @@ gui.placeholder.leggings=<dark_gray>»</dark_gray> <green>Hose</green>
gui.placeholder.off-hand=<dark_gray>»</dark_gray> <aqua>Zweithand</aqua>
gui.title.homes=Deine Zuhausepunkte
gui.title.warps=Schnellreisepunkte
nothing.changed=<red><prefix> Es konnte nichts geändert werden</red>
player.connected=<gray><prefix> <click:suggest_command:'/tell <player> '><green><chat_display_name></green> ist dem Spiel beigetreten</gray>
player.disconnected=<gray><prefix> <click:suggest_command:'/tell <player> '><green><chat_display_name></green> hat das Spiel verlassen</gray>
player.not.found=<red><prefix> Der Spieler <dark_red><player></dark_red> war noch nie online</red>
Expand Down

0 comments on commit 5d6dfc1

Please sign in to comment.