Skip to content

Commit d10e2e5

Browse files
committed
Add support for custom tags in item meta
1 parent dad5b79 commit d10e2e5

File tree

8 files changed

+484
-0
lines changed

8 files changed

+484
-0
lines changed

src/main/java/com/laytonsmith/abstraction/MCItemMeta.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,8 @@ public interface MCItemMeta extends AbstractionObject {
128128
List<MCAttributeModifier> getAttributeModifiers();
129129

130130
void setAttributeModifiers(List<MCAttributeModifier> modifiers);
131+
132+
boolean hasCustomTags();
133+
134+
MCTagContainer getCustomTags();
131135
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.laytonsmith.abstraction;
2+
3+
import com.laytonsmith.abstraction.enums.MCTagType;
4+
5+
import java.util.Collection;
6+
7+
/**
8+
* Minecraft NBT containers that can be used to read and modify tags in supported game objects.
9+
* This includes item meta, entities, block entities, chunks, worlds, etc.
10+
*/
11+
public interface MCTagContainer extends AbstractionObject {
12+
13+
/**
14+
* Returns whether the tag container does not contain any tags.
15+
* @return whether container is empty
16+
*/
17+
boolean isEmpty();
18+
19+
/**
20+
* Gets a set of key objects for each tag that exists in this container.
21+
* These are minecraft formatted namespaced keys. (e.g. "namespace:key")
22+
* These key objects can be passed to other methods in this class.
23+
* @return a set of keys
24+
*/
25+
Collection getKeys();
26+
27+
/**
28+
* Returns the tag type with the given key.
29+
* MCTagType can be used to convert tags to and from MethodScript constructs.
30+
* Returns null if a tag with that key does not exist.
31+
* @param key the tag key
32+
* @return the type for the tag
33+
*/
34+
MCTagType getType(Object key);
35+
36+
/**
37+
* Returns the tag value with the given key and tag type.
38+
* Returns null if a tag with that key and type does not exist.
39+
* @param key the tag key
40+
* @param type the tag type
41+
* @return the value for the tag
42+
*/
43+
Object get(Object key, MCTagType type);
44+
45+
/**
46+
* Sets the tag value with the given key and tag type.
47+
* Throws an IllegalArgumentException if the type and value do not match.
48+
* @param key the tag key
49+
* @param type the tag type
50+
* @param value the tag value
51+
*/
52+
void set(Object key, MCTagType type, Object value);
53+
54+
/**
55+
* Deletes the tag with the given key from this container.
56+
* @param key the tag key
57+
*/
58+
void remove(Object key);
59+
60+
/**
61+
* Creates a new tag container from this container context.
62+
* This can then be used to nest a tag container with the {@link #set} method.
63+
* @return a new tag container
64+
*/
65+
MCTagContainer newContainer();
66+
67+
}

src/main/java/com/laytonsmith/abstraction/bukkit/BukkitMCItemMeta.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.laytonsmith.abstraction.MCAttributeModifier;
77
import com.laytonsmith.abstraction.MCEnchantment;
88
import com.laytonsmith.abstraction.MCItemMeta;
9+
import com.laytonsmith.abstraction.MCTagContainer;
910
import com.laytonsmith.abstraction.blocks.MCBlockData;
1011
import com.laytonsmith.abstraction.blocks.MCMaterial;
1112
import com.laytonsmith.abstraction.bukkit.blocks.BukkitMCBlockData;
@@ -225,4 +226,13 @@ public void setAttributeModifiers(List<MCAttributeModifier> modifiers) {
225226
}
226227
im.setAttributeModifiers(map);
227228
}
229+
230+
@Override
231+
public boolean hasCustomTags() {
232+
return !im.getPersistentDataContainer().isEmpty();
233+
}
234+
235+
public MCTagContainer getCustomTags() {
236+
return new BukkitMCTagContainer(im.getPersistentDataContainer());
237+
}
228238
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package com.laytonsmith.abstraction.bukkit;
2+
3+
import com.laytonsmith.abstraction.MCTagContainer;
4+
import com.laytonsmith.abstraction.enums.MCTagType;
5+
import com.laytonsmith.commandhelper.CommandHelperPlugin;
6+
import org.bukkit.NamespacedKey;
7+
import org.bukkit.persistence.PersistentDataContainer;
8+
import org.bukkit.persistence.PersistentDataType;
9+
10+
import java.util.Collection;
11+
12+
public class BukkitMCTagContainer implements MCTagContainer {
13+
14+
PersistentDataContainer pdc;
15+
16+
public BukkitMCTagContainer(PersistentDataContainer pdc) {
17+
this.pdc = pdc;
18+
}
19+
20+
@Override
21+
public MCTagContainer newContainer() {
22+
return new BukkitMCTagContainer(pdc.getAdapterContext().newPersistentDataContainer());
23+
}
24+
25+
@Override
26+
public boolean isEmpty() {
27+
return this.pdc.isEmpty();
28+
}
29+
30+
@Override
31+
public Collection getKeys() {
32+
return pdc.getKeys();
33+
}
34+
35+
@Override
36+
public MCTagType getType(Object key) {
37+
NamespacedKey namespacedKey = NamespacedKey(key);
38+
// Check tag types in order of most frequently used
39+
if(pdc.has(namespacedKey, PersistentDataType.STRING)) {
40+
return MCTagType.STRING;
41+
} else if(pdc.has(namespacedKey, PersistentDataType.INTEGER)) {
42+
return MCTagType.INTEGER;
43+
} else if(pdc.has(namespacedKey, PersistentDataType.BYTE)) {
44+
return MCTagType.BYTE;
45+
} else if(pdc.has(namespacedKey, PersistentDataType.DOUBLE)) {
46+
return MCTagType.DOUBLE;
47+
} else if(pdc.has(namespacedKey, PersistentDataType.LONG)) {
48+
return MCTagType.LONG;
49+
} else if(pdc.has(namespacedKey, PersistentDataType.FLOAT)) {
50+
return MCTagType.FLOAT;
51+
} else if(pdc.has(namespacedKey, PersistentDataType.TAG_CONTAINER)) {
52+
return MCTagType.TAG_CONTAINER;
53+
} else if(pdc.has(namespacedKey, PersistentDataType.BYTE_ARRAY)) {
54+
return MCTagType.BYTE_ARRAY;
55+
} else if(pdc.has(namespacedKey, PersistentDataType.SHORT)) {
56+
return MCTagType.SHORT;
57+
} else if(pdc.has(namespacedKey, PersistentDataType.INTEGER_ARRAY)) {
58+
return MCTagType.INTEGER_ARRAY;
59+
} else if(pdc.has(namespacedKey, PersistentDataType.LONG_ARRAY)) {
60+
return MCTagType.LONG_ARRAY;
61+
} else if(pdc.has(namespacedKey, PersistentDataType.TAG_CONTAINER_ARRAY)) {
62+
return MCTagType.TAG_CONTAINER_ARRAY;
63+
}
64+
return null;
65+
}
66+
67+
@Override
68+
public Object get(Object key, MCTagType type) {
69+
PersistentDataType bukkitType = GetPersistentDataType(type);
70+
Object value = pdc.get(NamespacedKey(key), bukkitType);
71+
if(value instanceof PersistentDataContainer) {
72+
return new BukkitMCTagContainer((PersistentDataContainer) value);
73+
} else if(value instanceof PersistentDataContainer[] concreteContainers) {
74+
MCTagContainer[] abstractContainers = new MCTagContainer[concreteContainers.length];
75+
for(int i = 0; i < concreteContainers.length; i++) {
76+
abstractContainers[i] = new BukkitMCTagContainer(concreteContainers[i]);
77+
}
78+
return abstractContainers;
79+
}
80+
return value;
81+
}
82+
83+
@Override
84+
public void set(Object key, MCTagType type, Object value) {
85+
PersistentDataType bukkitType = GetPersistentDataType(type);
86+
if(value instanceof MCTagContainer) {
87+
value = ((MCTagContainer) value).getHandle();
88+
} else if(value instanceof MCTagContainer[] abstractContainers) {
89+
PersistentDataContainer[] concreteContainers = new PersistentDataContainer[abstractContainers.length];
90+
for(int i = 0; i < abstractContainers.length; i++) {
91+
concreteContainers[i] = (PersistentDataContainer) abstractContainers[i].getHandle();
92+
}
93+
value = concreteContainers;
94+
}
95+
pdc.set(NamespacedKey(key), bukkitType, value);
96+
}
97+
98+
@Override
99+
public void remove(Object key) {
100+
pdc.remove(NamespacedKey(key));
101+
}
102+
103+
private static NamespacedKey NamespacedKey(Object key) {
104+
if(key instanceof NamespacedKey) {
105+
return (NamespacedKey) key;
106+
} else if(key instanceof String) {
107+
NamespacedKey namespacedKey = NamespacedKey.fromString((String) key, CommandHelperPlugin.self);
108+
if(namespacedKey != null) {
109+
return namespacedKey;
110+
}
111+
}
112+
throw new IllegalArgumentException("Invalid namespaced key.");
113+
}
114+
115+
private static PersistentDataType GetPersistentDataType(MCTagType type) {
116+
switch(type) {
117+
case BYTE:
118+
return PersistentDataType.BYTE;
119+
case BYTE_ARRAY:
120+
return PersistentDataType.BYTE_ARRAY;
121+
case DOUBLE:
122+
return PersistentDataType.DOUBLE;
123+
case FLOAT:
124+
return PersistentDataType.FLOAT;
125+
case INTEGER:
126+
return PersistentDataType.INTEGER;
127+
case INTEGER_ARRAY:
128+
return PersistentDataType.INTEGER_ARRAY;
129+
case LONG:
130+
return PersistentDataType.LONG;
131+
case LONG_ARRAY:
132+
return PersistentDataType.LONG_ARRAY;
133+
case SHORT:
134+
return PersistentDataType.SHORT;
135+
case STRING:
136+
return PersistentDataType.STRING;
137+
case TAG_CONTAINER:
138+
return PersistentDataType.TAG_CONTAINER;
139+
case TAG_CONTAINER_ARRAY:
140+
return PersistentDataType.TAG_CONTAINER_ARRAY;
141+
}
142+
throw new IllegalArgumentException("Invalid persistent data type: " + type.name());
143+
}
144+
145+
@Override
146+
public Object getHandle() {
147+
return pdc;
148+
}
149+
150+
@Override
151+
public boolean equals(Object o) {
152+
return o instanceof MCTagContainer && this.pdc.equals(((MCTagContainer) o).getHandle());
153+
}
154+
155+
@Override
156+
public int hashCode() {
157+
return pdc.hashCode();
158+
}
159+
160+
@Override
161+
public String toString() {
162+
return pdc.toString();
163+
}
164+
}

0 commit comments

Comments
 (0)