Skip to content

Commit 046bf68

Browse files
authored
Add missing PDC syntaxes (#8528)
* Add missing PDC syntaxes * Apply suggestions from code review Co-authored-by: sovdee <10354869+sovdeeth@users.noreply.github.com> * Requested changes
1 parent d8c799c commit 046bf68

8 files changed

Lines changed: 399 additions & 75 deletions

File tree

src/main/java/ch/njol/skript/bukkitutil/NamespacedUtils.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package ch.njol.skript.bukkitutil;
22

3-
import ch.njol.skript.localization.ArgsMessage;
43
import ch.njol.skript.localization.Message;
54
import ch.njol.skript.util.ValidationResult;
65
import org.bukkit.NamespacedKey;
@@ -12,7 +11,7 @@
1211
*/
1312
public class NamespacedUtils {
1413

15-
public static final Message NAMEDSPACED_FORMAT_MESSAGE = new ArgsMessage("misc.namespacedutils.format");
14+
public static final Message NAMEDSPACED_FORMAT_MESSAGE = new Message("misc.namespacedutils.format");
1615

1716
/**
1817
* Check if {@code character} is a valid {@link Character} for the namespace section of a {@link NamespacedKey}.

src/main/java/org/skriptlang/skript/bukkit/pdc/PDCModule.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
import org.skriptlang.skript.addon.AddonModule;
55
import org.skriptlang.skript.addon.HierarchicalAddonModule;
66
import org.skriptlang.skript.addon.SkriptAddon;
7-
import org.skriptlang.skript.bukkit.pdc.expressions.ExprPersistentData;
7+
import org.skriptlang.skript.bukkit.pdc.elements.conditions.CondHasPersistentDataTag;
8+
import org.skriptlang.skript.bukkit.pdc.elements.expressions.ExprAllPersistentDataKeys;
9+
import org.skriptlang.skript.bukkit.pdc.elements.expressions.ExprPersistentData;
810

911
public class PDCModule extends HierarchicalAddonModule {
1012

@@ -14,7 +16,10 @@ public PDCModule(@Nullable AddonModule parentModule) {
1416

1517
@Override
1618
protected void loadSelf(SkriptAddon addon) {
17-
register(addon, ExprPersistentData::register);
19+
register(addon,
20+
CondHasPersistentDataTag::register,
21+
ExprAllPersistentDataKeys::register,
22+
ExprPersistentData::register);
1823
}
1924

2025
@Override
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package org.skriptlang.skript.bukkit.pdc;
2+
3+
import ch.njol.skript.aliases.ItemType;
4+
import ch.njol.skript.util.slot.Slot;
5+
import io.papermc.paper.persistence.PersistentDataContainerView;
6+
import org.bukkit.block.Block;
7+
import org.bukkit.block.TileState;
8+
import org.bukkit.inventory.ItemStack;
9+
import org.bukkit.persistence.PersistentDataContainer;
10+
import org.bukkit.persistence.PersistentDataHolder;
11+
12+
import java.util.function.Consumer;
13+
14+
/**
15+
* Utilities for working with {@link PersistentDataContainer}s.
16+
*/
17+
public final class PDCUtils {
18+
19+
/**
20+
* Gets the data container of an object.
21+
* Use {@link #editPersistentDataContainer(Object, Consumer)} if editing is desired.
22+
* @param holder Source of the container
23+
* @return The container, or null if the holder doesn't have one.
24+
*/
25+
public static PersistentDataContainerView getPersistentDataContainer(Object holder) {
26+
return getPersistentDataContainer(holder, container -> {});
27+
}
28+
29+
/**
30+
* Gets the data container of an object.
31+
* Use {@link #editPersistentDataContainer(Object, Consumer)} if editing is desired.
32+
* @param holder Source of the container
33+
* @param consumer Code to run with the container
34+
* @return The container, or null if the holder doesn't have one.
35+
*/
36+
public static PersistentDataContainerView getPersistentDataContainer(Object holder, Consumer<PersistentDataContainerView> consumer) {
37+
var container = switch (holder) {
38+
case PersistentDataHolder dataHolder -> dataHolder.getPersistentDataContainer();
39+
case ItemType itemType -> itemType.getItemMeta().getPersistentDataContainer();
40+
case ItemStack itemStack -> {
41+
if (!itemStack.hasItemMeta())
42+
yield null;
43+
yield itemStack.getPersistentDataContainer();
44+
}
45+
case Slot slot -> {
46+
var item = slot.getItem();
47+
if (item == null || !item.hasItemMeta())
48+
yield null;
49+
yield item.getPersistentDataContainer();
50+
}
51+
case Block block when block.getState() instanceof TileState tileState -> tileState.getPersistentDataContainer();
52+
case null, default -> null;
53+
};
54+
if (container == null)
55+
return null;
56+
consumer.accept(container);
57+
return container;
58+
}
59+
60+
/**
61+
* Helper to easily edit PDCs.
62+
* @param holder The holder of the PDC.
63+
* @param consumer The method to run to edit the PDC.
64+
*/
65+
public static void editPersistentDataContainer(Object holder, Consumer<PersistentDataContainer> consumer) {
66+
switch (holder) {
67+
case PersistentDataHolder dataHolder -> consumer.accept(dataHolder.getPersistentDataContainer());
68+
case ItemType itemType -> {
69+
var meta = itemType.getItemMeta();
70+
consumer.accept(meta.getPersistentDataContainer());
71+
itemType.setItemMeta(meta);
72+
}
73+
case ItemStack itemStack -> {
74+
if (!itemStack.hasItemMeta())
75+
return;
76+
itemStack.editPersistentDataContainer(consumer);
77+
}
78+
case Slot slot -> {
79+
var item = slot.getItem();
80+
if (item == null || !item.hasItemMeta())
81+
return;
82+
item.editPersistentDataContainer(consumer);
83+
slot.setItem(item);
84+
}
85+
case Block block when block.getState() instanceof TileState tileState -> {
86+
consumer.accept(tileState.getPersistentDataContainer());
87+
tileState.update();
88+
}
89+
case null, default -> {
90+
}
91+
}
92+
}
93+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package org.skriptlang.skript.bukkit.pdc.elements.conditions;
2+
3+
import ch.njol.skript.bukkitutil.NamespacedUtils;
4+
import ch.njol.skript.conditions.base.PropertyCondition;
5+
import ch.njol.skript.doc.*;
6+
import ch.njol.skript.lang.Condition;
7+
import ch.njol.skript.lang.Expression;
8+
import ch.njol.skript.lang.SkriptParser.ParseResult;
9+
import ch.njol.skript.lang.util.SimpleExpression;
10+
import ch.njol.skript.util.LiteralUtils;
11+
import ch.njol.util.Kleenean;
12+
import org.bukkit.NamespacedKey;
13+
import org.bukkit.event.Event;
14+
import org.jetbrains.annotations.Nullable;
15+
import org.skriptlang.skript.bukkit.pdc.PDCUtils;
16+
import org.skriptlang.skript.registration.SyntaxRegistry;
17+
18+
@Name("Has Persistent Data Tag")
19+
@Description("""
20+
Checks if the specified objects have persistent data tags with the given keys.
21+
Keys should be in the format "namespace:key" or "key". If a namespace is omitted, "minecraft" will be used instead.
22+
If a key is invalid, it will be ignored and a warning will be logged.
23+
""")
24+
@Example("""
25+
if player has persistent data tag "koth:capturePoint":
26+
add 1 to {points::%{team::%player%}%}
27+
""")
28+
@Example("""
29+
if player's tool has persistent data tags "custom:damage" and "custom:owner":
30+
if data tag "custom:owner" of player's tool is not player:
31+
broadcast "You are not the owner of this tool!"
32+
stop
33+
if data tag "custom:damage" of player's tool > 10:
34+
broadcast "Your tool is heavily damaged!"
35+
else:
36+
broadcast "Your tool is in good condition."
37+
""")
38+
@Since("INSERT VERSION")
39+
@Keywords({"pdc", "persistent data container", "custom data", "nbt"})
40+
public class CondHasPersistentDataTag extends Condition {
41+
42+
public static void register(SyntaxRegistry registry) {
43+
registry.register(
44+
SyntaxRegistry.CONDITION,
45+
PropertyCondition.infoBuilder(
46+
CondHasPersistentDataTag.class, PropertyCondition.PropertyType.HAVE,
47+
"[persistent] data tag[s] %strings%", "objects")
48+
.supplier(CondHasPersistentDataTag::new)
49+
.build());
50+
}
51+
52+
private Expression<String> keys;
53+
private Expression<Object> holders;
54+
55+
@Override
56+
@SuppressWarnings("unchecked")
57+
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
58+
this.holders = LiteralUtils.defendExpression(expressions[0]);
59+
this.keys = (Expression<String>) expressions[1];
60+
setNegated(matchedPattern == 1);
61+
return LiteralUtils.canInitSafely(this.holders);
62+
}
63+
64+
@Override
65+
public boolean check(Event event) {
66+
boolean keysAnd = this.keys.getAnd();
67+
NamespacedKey[] keys = this.keys.stream(event)
68+
.map(key -> NamespacedUtils.checkValidationAndSend(key, this))
69+
.toArray(NamespacedKey[]::new);
70+
if (keys.length == 0)
71+
return isNegated();
72+
73+
return this.holders.check(event, holder -> {
74+
var container = PDCUtils.getPersistentDataContainer(holder);
75+
if (container == null)
76+
return false;
77+
return SimpleExpression.check(keys, container::has, false, keysAnd);
78+
}, isNegated());
79+
}
80+
81+
@Override
82+
public String toString(@Nullable Event event, boolean debug) {
83+
return PropertyCondition.toString(this, PropertyCondition.PropertyType.HAVE, event, debug, holders, "persistent data tag " + keys.toString(event, debug));
84+
}
85+
86+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package org.skriptlang.skript.bukkit.pdc.elements.expressions;
2+
3+
import ch.njol.skript.doc.*;
4+
import ch.njol.skript.expressions.base.PropertyExpression;
5+
import ch.njol.skript.lang.Expression;
6+
import ch.njol.skript.lang.SkriptParser.ParseResult;
7+
import ch.njol.skript.util.LiteralUtils;
8+
import ch.njol.util.Kleenean;
9+
import org.bukkit.NamespacedKey;
10+
import org.bukkit.event.Event;
11+
import org.jetbrains.annotations.Nullable;
12+
import org.skriptlang.skript.bukkit.pdc.PDCUtils;
13+
import org.skriptlang.skript.registration.SyntaxInfo;
14+
import org.skriptlang.skript.registration.SyntaxRegistry;
15+
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
19+
@Name("All Persistent Data Keys")
20+
@Description("""
21+
Returns all persistent data keys stored in the specified objects.
22+
This is not limited to tags set by Skript, but includes all keys regardless of their origin.
23+
""")
24+
@Example("""
25+
set {_keys::*} to persistent data keys of player's tool
26+
if size of {_keys::*} > 0:
27+
broadcast "The tool has the following persistent data keys: %{_keys::*}%"
28+
else:
29+
broadcast "The tool has no persistent data keys."
30+
""")
31+
@Example("""
32+
for each {_key} in persistent data keys of player's tool:
33+
broadcast "Persistent data tag %{_key}%: %data tag {_key} of player's tool%"
34+
""")
35+
@Since("INSERT VERSION")
36+
@Keywords({"pdc", "persistent data container", "custom data", "nbt"})
37+
public class ExprAllPersistentDataKeys extends PropertyExpression<Object, String> {
38+
39+
public static void register(SyntaxRegistry registry) {
40+
registry.register(SyntaxRegistry.EXPRESSION,
41+
SyntaxInfo.Expression.builder(ExprAllPersistentDataKeys.class, String.class)
42+
.addPatterns(
43+
"[all [[of] the]] [persistent] data [tag] keys of %objects%",
44+
"[all of] %objects%'[s] [persistent] data [tag] keys"
45+
)
46+
.priority(DEFAULT_PRIORITY)
47+
.supplier(ExprAllPersistentDataKeys::new)
48+
.build());
49+
}
50+
51+
@Override
52+
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
53+
setExpr(LiteralUtils.defendExpression(expressions[0]));
54+
return LiteralUtils.canInitSafely(getExpr());
55+
}
56+
57+
@Override
58+
protected String[] get(Event event, Object[] source) {
59+
List<String> keys = new ArrayList<>();
60+
for (Object obj : source) {
61+
PDCUtils.getPersistentDataContainer(obj, container -> {
62+
for (NamespacedKey key : container.getKeys()) {
63+
keys.add(key.toString());
64+
}
65+
});
66+
}
67+
return keys.toArray(new String[0]);
68+
}
69+
70+
@Override
71+
public Class<String> getReturnType() {
72+
return String.class;
73+
}
74+
75+
@Override
76+
public String toString(@Nullable Event event, boolean debug) {
77+
return "persistent data keys of " + getExpr().toString(event, debug);
78+
}
79+
80+
}

0 commit comments

Comments
 (0)