Skip to content

Commit 109dabf

Browse files
committed
Fail safe the retrieval of the underlying nbt data
Make it safe so it does not fail when the key does not exist and returns null and the cast will then throw an error.
1 parent fae256a commit 109dabf

File tree

3 files changed

+128
-24
lines changed

3 files changed

+128
-24
lines changed

Item Creator/src/main/java/org/broken/arrow/library/itemcreator/utility/compound/CompoundTag.java

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package org.broken.arrow.library.itemcreator.utility.compound;
22

33

4+
import org.broken.arrow.library.itemcreator.utility.nms.LegacyNBT;
45
import org.broken.arrow.library.logging.Validate;
56

67
import javax.annotation.Nonnull;
8+
import javax.annotation.Nullable;
79

810

911
/**
@@ -35,7 +37,7 @@ public final class CompoundTag {
3537
*
3638
* @param handle the raw NBTTagCompound instance from NMS
3739
*/
38-
CompoundTag(@Nonnull final Object handle) {
40+
public CompoundTag(@Nonnull final Object handle) {
3941
Validate.checkNotNull(handle, "CompoundTag handle cannot be null");
4042
compoundSession = LegacyNBT.compoundSession(handle);
4143
Validate.checkNotNull(compoundSession, "The compound session could not be loaded.");
@@ -53,9 +55,9 @@ public boolean hasKey(@Nonnull String key) {
5355

5456

5557
/**
56-
* Remove this {@link CompoundTag} value and the given key.
58+
* Removes the specified key from this compound.
5759
*
58-
* @param key the NBT key to remove.
60+
* @param key the key to remove
5961
*/
6062
public void remove(@Nonnull final String key) {
6163
this.compoundSession.remove(key);
@@ -75,7 +77,8 @@ public void setInt(@Nonnull final String key, final int value) {
7577
* Gets a int value from the underlying NBTTagCompound.
7678
*
7779
* @param key the key of the int value
78-
* @return the stored int value, or {@code -1} if unavailable
80+
* @return the stored int value, or {@code -1} if reflection fail
81+
* or if the key does not exist in the NBT data.
7982
*/
8083
public int getInt(@Nonnull final String key) {
8184
return this.compoundSession.getInt(key);
@@ -95,7 +98,8 @@ public void setString(@Nonnull final String key, final String value) {
9598
* Gets a string value from the underlying NBTTagCompound.
9699
*
97100
* @param key the key of the string value
98-
* @return the stored string value, or empty string if unavailable
101+
* @return the stored string value, or empty string if reflection fail
102+
* or {@code null} if the key does not exist in the NBT data.
99103
*/
100104
public String getString(@Nonnull final String key) {
101105
return this.compoundSession.getString(key);
@@ -121,6 +125,35 @@ public byte getByte(@Nonnull final String key) {
121125
return this.compoundSession.getByte(key);
122126
}
123127

128+
/**
129+
* Stores a byte array under the specified key in the underlying NBTTagCompound.
130+
* <p>
131+
* This method provides flexibility for attaching arbitrary binary data to an NBT
132+
* structure, allowing more complex or custom payloads to be stored efficiently.
133+
*
134+
* @param key the name of the tag to write
135+
* @param value the byte array to store, may be {@code null} depending on implementation
136+
*/
137+
public void setByteArray(@Nonnull final String key, final byte[] value) {
138+
this.compoundSession.setByteArray(key, value);
139+
}
140+
141+
/**
142+
* Retrieves a stored byte array associated with the given key from the underlying
143+
* NBTTagCompound.
144+
* <p>
145+
* This is useful for reading custom binary data previously written with
146+
* {@link #setByteArray(String, byte[])}.
147+
*
148+
* @param key the name of the tag to read
149+
* @return the byte array associated with the key, an empty array if reflection
150+
* access fails, or {@code null} if the key does not exist in the NBT data.
151+
*/
152+
@Nullable
153+
public byte[] getByteArray(@Nonnull final String key) {
154+
return this.compoundSession.getByteArray(key);
155+
}
156+
124157
/**
125158
* Sets a boolean value in the underlying NBTTagCompound.
126159
*

Item Creator/src/main/java/org/broken/arrow/library/itemcreator/utility/compound/NbtData.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.broken.arrow.library.itemcreator.utility.compound;
22

33

4+
import org.broken.arrow.library.itemcreator.utility.nms.LegacyNBT;
45
import org.broken.arrow.library.logging.Validate;
56
import org.bukkit.inventory.ItemStack;
67

@@ -103,7 +104,7 @@ public CompoundTag getOrCreateCompound(@Nonnull final String name) {
103104
*/
104105
@Nullable
105106
public CompoundTag getCompound() {
106-
return this.session.getOrCreateCompound();
107+
return this.session.getCompound();
107108
}
108109

109110
/**
@@ -120,7 +121,7 @@ public CompoundTag getCompound() {
120121
*/
121122
@Nullable
122123
public CompoundTag getCompound(@Nonnull final String name) {
123-
return this.session.getCompound();
124+
return this.session.getCompound(name);
124125
}
125126

126127
/**

Item Creator/src/main/java/org/broken/arrow/library/itemcreator/utility/compound/LegacyNBT.java renamed to Item Creator/src/main/java/org/broken/arrow/library/itemcreator/utility/nms/LegacyNBT.java

Lines changed: 87 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
package org.broken.arrow.library.itemcreator.utility.compound;
1+
package org.broken.arrow.library.itemcreator.utility.nms;
22

3+
import org.broken.arrow.library.itemcreator.utility.compound.CompoundTag;
4+
import org.broken.arrow.library.itemcreator.utility.compound.NbtData;
35
import org.broken.arrow.library.logging.Logging;
46
import org.broken.arrow.library.logging.Validate;
57
import org.bukkit.Bukkit;
@@ -11,7 +13,6 @@
1113
import java.lang.invoke.MethodHandles;
1214
import java.lang.invoke.MethodType;
1315
import java.lang.reflect.Constructor;
14-
import java.util.Arrays;
1516
import java.util.logging.Level;
1617

1718
/**
@@ -363,7 +364,7 @@ private CompoundTag getCompoundTag(final String name, final boolean usingName) {
363364
}
364365
}
365366
this.compoundState = CompoundState.CREATED;
366-
return new CompoundTag(nested != null ? nested : root);
367+
return new CompoundTag((nested != null ? nested : root));
367368
} catch (Throwable e) {
368369
logger.logError(e, () -> "Failed to initialize CompoundTag");
369370
this.compoundState = CompoundState.ERROR;
@@ -400,14 +401,18 @@ private CompoundTag getCompound(final String name, final boolean usingName) {
400401
}
401402
}
402403
this.compoundState = CompoundState.CREATED;
403-
return new CompoundTag(nested != null ? nested : root);
404+
return new CompoundTag((nested != null ? nested : root));
404405
} catch (Throwable e) {
405406
logger.logError(e, () -> "Failed to initialize CompoundTag");
406407
this.compoundState = CompoundState.ERROR;
407408
}
408409
return null;
409410
}
410411

412+
private static String getNbtTagBasePath() {
413+
return getNmsPath() + ".NBTBase";
414+
}
415+
411416
private static String getCraftBukkitPath() {
412417
return "org.bukkit.craftbukkit." + getPackageVersion();
413418
}
@@ -430,6 +435,8 @@ public static class CompoundSession {
430435
private static final MethodHandle setShort;
431436
private static final MethodHandle setByte;
432437
private static final MethodHandle getByte;
438+
private static final MethodHandle setByteArray;
439+
private static final MethodHandle getByteArray;
433440
private static final MethodHandle setBoolean;
434441
private static final MethodHandle getBoolean;
435442
private final Object handle;
@@ -445,6 +452,8 @@ public static class CompoundSession {
445452
MethodHandle setShortM = null;
446453
MethodHandle setByteM = null;
447454
MethodHandle getByteM = null;
455+
MethodHandle setByteArrayM = null;
456+
MethodHandle getByteArrayM = null;
448457
MethodHandle setBooleanM = null;
449458
MethodHandle getBooleanM = null;
450459
try {
@@ -471,6 +480,11 @@ public static class CompoundSession {
471480
getByteM = lookup.findVirtual(nbtTag, "getByte",
472481
MethodType.methodType(byte.class, String.class));
473482

483+
setByteArrayM = lookup.findVirtual(nbtTag, "setByteArray",
484+
MethodType.methodType(void.class, String.class, byte[].class));
485+
getByteArrayM = lookup.findVirtual(nbtTag, "getByteArray",
486+
MethodType.methodType(byte[].class, String.class));
487+
474488
setStringM = lookup.findVirtual(nbtTag, "setString",
475489
MethodType.methodType(void.class, String.class, String.class));
476490
getStringM = lookup.findVirtual(nbtTag, "getString",
@@ -494,7 +508,8 @@ public static class CompoundSession {
494508
setShort = setShortM;
495509
setByte = setByteM;
496510
getByte = getByteM;
497-
511+
setByteArray = setByteArrayM;
512+
getByteArray = getByteArrayM;
498513
setBoolean = setBooleanM;
499514
getBoolean = getBooleanM;
500515

@@ -520,7 +535,7 @@ public static boolean isReady() {
520535
* @return returns the NBTTagCompound object.
521536
*/
522537
@Nonnull
523-
Object getHandle() {
538+
public Object getHandle() {
524539
return handle;
525540
}
526541

@@ -577,13 +592,17 @@ public void setInt(@Nonnull final String key, final int value) {
577592
* Gets a int value from the underlying NBTTagCompound.
578593
*
579594
* @param key the key of the int value
580-
* @return the stored int value, or {@code -1} if unavailable
595+
* @return the stored int value, or {@code -1} if reflection fail
596+
* or if the key does not exist in the NBT data.
581597
*/
582598
public int getInt(@Nonnull final String key) {
583599
if (getInt == null) return -1;
584600

585601
try {
586-
return (int) getInt.invoke(handle, key);
602+
Object intObject = getInt.invoke(handle, key);
603+
if (intObject == null)
604+
return -1;
605+
return (int) intObject;
587606
} catch (Throwable e) {
588607
logger.logError(e, () -> "Failed to retrieve int value from reflection");
589608
}
@@ -612,11 +631,14 @@ public void setString(@Nonnull final String key, final String value) {
612631
* @param key the key of the string value
613632
* @return the stored string value, or empty string if unavailable
614633
*/
634+
@Nonnull
615635
public String getString(@Nonnull final String key) {
616636
if (getString == null) return "";
617637

618638
try {
619-
return (String) getString.invoke(handle, key);
639+
Object stringObject = getString.invoke(handle, key);
640+
if (stringObject == null) return "";
641+
return (String) stringObject;
620642
} catch (Throwable e) {
621643
logger.logError(e, () -> "Failed to retrieve string value from reflection");
622644
}
@@ -643,19 +665,65 @@ public void setByte(@Nonnull final String key, final byte value) {
643665
* Gets a byte value from the underlying NBTTagCompound.
644666
*
645667
* @param key the key of the byte value
646-
* @return the stored byte value, or {@code -1} if unavailable
668+
* @return the stored byte value, or {@code -1} if reflection fail
669+
* or if the key does not exist in the NBT data.
647670
*/
648671
public byte getByte(@Nonnull final String key) {
649672
if (getByte == null) return -1;
650673

651674
try {
652-
return (byte) getByte.invoke(handle, key);
675+
Object byteObject = getByte.invoke(handle, key);
676+
if (byteObject == null) return -1;
677+
return (byte) byteObject;
653678
} catch (Throwable e) {
654679
logger.logError(e, () -> "Failed to retrieve byte value from reflection");
655680
}
656681
return -1;
657682
}
658683

684+
685+
/**
686+
* Sets a byte array in the underlying NBTTagCompound.
687+
*
688+
* @param key the key to set
689+
* @param value the byte array to assign
690+
*/
691+
public void setByteArray(@Nonnull final String key, final byte[] value) {
692+
if (setByteArray == null) return;
693+
694+
try {
695+
setByteArray.invoke(handle, key, value);
696+
} catch (Throwable e) {
697+
logger.logError(e, () -> "Failed to set byte value from reflection");
698+
}
699+
}
700+
701+
/**
702+
* Retrieves a byte array from the underlying NBTTagCompound.
703+
*
704+
* <p>If the reflective access fails (e.g., missing method reference or an
705+
* exception during invocation), this method returns an empty byte array.
706+
* A {@code null} value is only returned if the underlying NBT structure
707+
* itself represents the tag as non-existent.</p>
708+
*
709+
* @param key the key of the stored byte array
710+
* @return the byte array associated with the key, an empty array if reflection
711+
* access fails, or {@code null} if the key does not exist in the NBT data.
712+
*/
713+
@Nullable
714+
public byte[] getByteArray(@Nonnull final String key) {
715+
if (getByteArray == null) return new byte[0];
716+
717+
try {
718+
Object byteArray = getByteArray.invoke(handle, key);
719+
if (byteArray == null) return null;
720+
return (byte[]) byteArray;
721+
} catch (Throwable e) {
722+
logger.logError(e, () -> "Failed to retrieve byte value from reflection");
723+
}
724+
return new byte[0];
725+
}
726+
659727
/**
660728
* Sets a boolean value in the underlying NBTTagCompound.
661729
*
@@ -682,7 +750,9 @@ public boolean getBoolean(@Nonnull final String key) {
682750
if (getBoolean == null) return false;
683751

684752
try {
685-
return (boolean) getBoolean.invoke(handle, key);
753+
Object booleanObject = getBoolean.invoke(handle, key);
754+
if (booleanObject == null) return false;
755+
return (boolean) booleanObject;
686756
} catch (Throwable e) {
687757
logger.logError(e, () -> "Failed to retrieve boolean value from reflection");
688758
}
@@ -709,13 +779,16 @@ public void setShort(@Nonnull final String key, final short value) {
709779
* Gets a short value from the underlying NBTTagCompound.
710780
*
711781
* @param key the key of the short value
712-
* @return the stored short value, or {@code -1} if unavailable
782+
* @return the stored short value, or {@code -1} if reflection fail
783+
* or if the key does not exist in the NBT data.
713784
*/
714785
public short getShort(@Nonnull final String key) {
715786
if (getShort == null) return -1;
716787

717788
try {
718-
return (short) getShort.invoke(handle, key);
789+
Object shortObject = getShort.invoke(handle, key);
790+
if (shortObject == null) return -1;
791+
return (short) shortObject;
719792
} catch (Throwable e) {
720793
logger.logError(e, () -> "Failed to retrieve short value from reflection");
721794
}
@@ -728,9 +801,6 @@ private static String getNbtTagPath() {
728801
return getNmsPath() + ".NBTTagCompound";
729802
}
730803

731-
private static String getNbtTagBasePath() {
732-
return getNmsPath() + ".NBTBase";
733-
}
734804

735805
private static String getNmsPath() {
736806
return "net.minecraft.server." + getPackageVersion();

0 commit comments

Comments
 (0)