diff --git a/pom.xml b/pom.xml
index e74de44..0fa646d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,14 +6,14 @@
tech.sbdevelopment
ShowControl
- 1.6.1
+ 1.7
jar
ShowControl
https://sbdevelopment.tech
Create shows easily using this plugin!
- 11
+ 17
UTF-8
${project.build.directory}/javadoc-delombok
@@ -39,7 +39,7 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.11.0
+ 3.13.0
${release}
@@ -57,7 +57,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.4.1
+ 3.6.0
package
@@ -115,7 +115,7 @@
org.apache.maven.plugins
maven-javadoc-plugin
- 3.6.0
+ 3.11.2
${release}
${maven.lombok.delombok-target}
@@ -157,7 +157,7 @@
org.spigotmc
spigot-api
- 1.20.2-R0.1-SNAPSHOT
+ 1.21.4-R0.1-SNAPSHOT
provided
@@ -168,7 +168,7 @@
com.github.cryptomorin
XSeries
- 9.10.0
+ 13.0.0
co.aikar
@@ -179,7 +179,7 @@
com.github.SkytAsul
GuardianBeam
- 97b0078aba
+ 2.4.0
compile
diff --git a/src/main/java/tech/sbdevelopment/showcontrol/elements/Fireworks.java b/src/main/java/tech/sbdevelopment/showcontrol/elements/Fireworks.java
index 2719e38..fccd01e 100644
--- a/src/main/java/tech/sbdevelopment/showcontrol/elements/Fireworks.java
+++ b/src/main/java/tech/sbdevelopment/showcontrol/elements/Fireworks.java
@@ -50,7 +50,7 @@ public class Fireworks {
}
private void spawn(Location loc) {
- org.bukkit.entity.Firework fw = (org.bukkit.entity.Firework) loc.getWorld().spawnEntity(loc, EntityType.FIREWORK);
+ org.bukkit.entity.Firework fw = (org.bukkit.entity.Firework) loc.getWorld().spawnEntity(loc, EntityType.FIREWORK_ROCKET);
FireworkMeta fwm = fw.getFireworkMeta();
fwm.addEffect(effectBuilder.build());
fwm.setPower(power);
diff --git a/src/main/java/tech/sbdevelopment/showcontrol/utils/ItemBuilder.java b/src/main/java/tech/sbdevelopment/showcontrol/utils/ItemBuilder.java
index 64eb9ae..099fef3 100644
--- a/src/main/java/tech/sbdevelopment/showcontrol/utils/ItemBuilder.java
+++ b/src/main/java/tech/sbdevelopment/showcontrol/utils/ItemBuilder.java
@@ -1,7 +1,9 @@
package tech.sbdevelopment.showcontrol.utils;
-import com.cryptomorin.xseries.SkullUtils;
import com.cryptomorin.xseries.XMaterial;
+import com.cryptomorin.xseries.profiles.builder.XSkull;
+import com.cryptomorin.xseries.profiles.objects.ProfileInputType;
+import com.cryptomorin.xseries.profiles.objects.Profileable;
import lombok.Getter;
import org.bukkit.Color;
import org.bukkit.Material;
@@ -10,15 +12,19 @@ import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
-import org.bukkit.potion.PotionData;
+import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.function.Function;
import java.util.function.UnaryOperator;
+import static tech.sbdevelopment.showcontrol.utils.ReflectionUtil.callDeclaredConstructor;
+import static tech.sbdevelopment.showcontrol.utils.ReflectionUtil.callDeclaredMethod;
+
@Getter
public class ItemBuilder {
private final ItemStack itemStack;
@@ -87,12 +93,14 @@ public class ItemBuilder {
return flag(ItemFlag.values());
}
- public ItemBuilder customModelData(int customModelData) {
- if (XMaterial.supports(13)) {
+ public ItemBuilder customModelData(int customModelData, Function notSupportedFunction) {
+ if (XMaterial.supports(14)) {
applyToMeta(meta -> {
meta.setCustomModelData(customModelData);
return meta;
});
+ } else {
+ return notSupportedFunction.apply(this);
}
return this;
}
@@ -140,7 +148,7 @@ public class ItemBuilder {
public ItemBuilder skullTexture(String identifier) {
applyToMeta(meta -> {
- SkullUtils.applySkin(meta, identifier);
+ meta = XSkull.of(meta).profile(Profileable.of(ProfileInputType.USERNAME, identifier)).apply();
return meta;
});
return this;
@@ -160,7 +168,15 @@ public class ItemBuilder {
throw new UnsupportedOperationException("ItemStack is not a potion! (Type: " + itemStack.getType().name() + ")");
applyToMeta(meta -> {
if (!(meta instanceof org.bukkit.inventory.meta.PotionMeta)) return meta;
- ((org.bukkit.inventory.meta.PotionMeta) meta).setBasePotionData(new PotionData(type));
+ PotionMeta pm = (PotionMeta) meta;
+ try {
+ pm.setBasePotionType(type);
+ } catch (NoSuchMethodError e) {
+ // Fallback for versions below 1.20.5 (using reflection)
+ Class> potionDataClass = ReflectionUtil.getClass("org.bukkit.potion.PotionData");
+ Object potionData = callDeclaredConstructor(potionDataClass, type);
+ callDeclaredMethod(pm, "setBasePotionData", potionDataClass, potionData);
+ }
return meta;
});
return this;
diff --git a/src/main/java/tech/sbdevelopment/showcontrol/utils/ReflectionUtil.java b/src/main/java/tech/sbdevelopment/showcontrol/utils/ReflectionUtil.java
new file mode 100644
index 0000000..4b656dc
--- /dev/null
+++ b/src/main/java/tech/sbdevelopment/showcontrol/utils/ReflectionUtil.java
@@ -0,0 +1,309 @@
+package tech.sbdevelopment.showcontrol.utils;
+
+import lombok.experimental.UtilityClass;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+
+@UtilityClass
+public class ReflectionUtil {
+ private static final Map> constructorCache = new HashMap<>();
+ private static final Map methodCache = new HashMap<>();
+ private static final Map fieldCache = new HashMap<>();
+
+ /**
+ * Helper class converted to {@link List}
+ *
+ * @param The storage type
+ */
+ public static class ListParam extends ArrayList {
+ }
+
+ /**
+ * Helper class converted to {@link Collection}
+ *
+ * @param The storage type
+ */
+ public static class CollectionParam extends ArrayList {
+ }
+
+ private static Class> wrapperToPrimitive(Class> clazz) {
+ if (clazz == Boolean.class) return boolean.class;
+ if (clazz == Integer.class) return int.class;
+ if (clazz == Double.class) return double.class;
+ if (clazz == Float.class) return float.class;
+ if (clazz == Long.class) return long.class;
+ if (clazz == Short.class) return short.class;
+ if (clazz == Byte.class) return byte.class;
+ if (clazz == Void.class) return void.class;
+ if (clazz == Character.class) return char.class;
+ if (clazz == CollectionParam.class) return Collection.class;
+ if (clazz == ListParam.class) return List.class;
+ if (clazz == ArrayList.class) return Collection.class; //LEGACY!
+ if (clazz == HashMap.class) return Map.class;
+ return clazz;
+ }
+
+ private static Class>[] toParamTypes(Object... params) {
+ return Arrays.stream(params)
+ .map(obj -> obj != null ? wrapperToPrimitive(obj.getClass()) : null)
+ .toArray(Class>[]::new);
+ }
+
+ public static Class> getClass(String name) {
+ try {
+ return Class.forName(name);
+ } catch (ClassNotFoundException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static Object callConstructorNull(Class> clazz, Class> paramClass) {
+ try {
+ String cacheKey = "ConstructorNull:" + clazz.getName() + ":" + paramClass.getName();
+
+ if (constructorCache.containsKey(cacheKey)) {
+ Constructor> cachedConstructor = constructorCache.get(cacheKey);
+ return cachedConstructor.newInstance(clazz.cast(null));
+ } else {
+ Constructor> con = clazz.getConstructor(paramClass);
+ con.setAccessible(true);
+ constructorCache.put(cacheKey, con);
+ return con.newInstance(clazz.cast(null));
+ }
+ } catch (NoSuchMethodException | IllegalAccessException | InstantiationException |
+ InvocationTargetException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static Object callFirstConstructor(Class> clazz, Object... params) {
+ try {
+ String cacheKey = "FirstConstructor:" + clazz.getName();
+
+ if (constructorCache.containsKey(cacheKey)) {
+ Constructor> cachedConstructor = constructorCache.get(cacheKey);
+ return cachedConstructor.newInstance(params);
+ } else {
+ Constructor> con = clazz.getConstructors()[0];
+ con.setAccessible(true);
+ constructorCache.put(cacheKey, con);
+ return con.newInstance(params);
+ }
+ } catch (IllegalAccessException | InstantiationException |
+ InvocationTargetException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static Object callConstructor(Class> clazz, Object... params) {
+ try {
+ String cacheKey = "Constructor:" + clazz.getName() + ":" + Arrays.hashCode(params);
+
+ if (constructorCache.containsKey(cacheKey)) {
+ Constructor> cachedConstructor = constructorCache.get(cacheKey);
+ return cachedConstructor.newInstance(params);
+ } else {
+ Constructor> con = clazz.getConstructor(toParamTypes(params));
+ con.setAccessible(true);
+ constructorCache.put(cacheKey, con);
+ return con.newInstance(params);
+ }
+ } catch (NoSuchMethodException | IllegalAccessException | InstantiationException |
+ InvocationTargetException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static Object callDeclaredConstructor(Class> clazz, Object... params) {
+ try {
+ String cacheKey = "DeclaredConstructor:" + clazz.getName() + ":" + Arrays.hashCode(params);
+
+ if (constructorCache.containsKey(cacheKey)) {
+ Constructor> cachedConstructor = constructorCache.get(cacheKey);
+ return cachedConstructor.newInstance(params);
+ } else {
+ Constructor> con = clazz.getDeclaredConstructor(toParamTypes(params));
+ con.setAccessible(true);
+ constructorCache.put(cacheKey, con);
+ return con.newInstance(params);
+ }
+ } catch (NoSuchMethodException | IllegalAccessException | InstantiationException |
+ InvocationTargetException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static Object callMethod(Class> clazz, String method, Object... params) {
+ try {
+ String cacheKey = "Method:" + clazz.getName() + ":" + method + ":" + Arrays.hashCode(params);
+
+ if (methodCache.containsKey(cacheKey)) {
+ Method cachedMethod = methodCache.get(cacheKey);
+ return cachedMethod.invoke(null, params);
+ } else {
+ Method m = clazz.getMethod(method, toParamTypes(params));
+ m.setAccessible(true);
+ methodCache.put(cacheKey, m);
+ return m.invoke(null, params);
+ }
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static Object callMethod(Object obj, String method, Object... params) {
+ try {
+ String cacheKey = "Method:" + obj.getClass().getName() + ":" + method + ":" + Arrays.hashCode(params);
+
+ if (methodCache.containsKey(cacheKey)) {
+ Method cachedMethod = methodCache.get(cacheKey);
+ return cachedMethod.invoke(obj, params);
+ } else {
+ Method m = obj.getClass().getMethod(method, toParamTypes(params));
+ m.setAccessible(true);
+ methodCache.put(cacheKey, m);
+ return m.invoke(obj, params);
+ }
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static Object callDeclaredMethod(Object obj, String method, Object... params) {
+ try {
+ String cacheKey = "DeclaredMethod:" + obj.getClass().getName() + ":" + method + ":" + Arrays.hashCode(params);
+
+ if (methodCache.containsKey(cacheKey)) {
+ Method cachedMethod = methodCache.get(cacheKey);
+ return cachedMethod.invoke(obj, params);
+ } else {
+ Method m = obj.getClass().getDeclaredMethod(method, toParamTypes(params));
+ m.setAccessible(true);
+ methodCache.put(cacheKey, m);
+ return m.invoke(obj, params);
+ }
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static boolean hasField(Object packet, String field) {
+ try {
+ String cacheKey = "HasField:" + packet.getClass().getName() + ":" + field;
+
+ if (!fieldCache.containsKey(cacheKey)) {
+ packet.getClass().getDeclaredField(field);
+ fieldCache.put(cacheKey, null);
+ }
+ return true;
+ } catch (NoSuchFieldException ex) {
+ return false;
+ }
+ }
+
+ public static Object getField(Object object, String field) {
+ try {
+ String cacheKey = "Field:" + object.getClass().getName() + ":" + field;
+
+ if (fieldCache.containsKey(cacheKey)) {
+ Field cachedField = fieldCache.get(cacheKey);
+ return cachedField.get(object);
+ } else {
+ Field f = object.getClass().getField(field);
+ f.setAccessible(true);
+ fieldCache.put(cacheKey, f);
+ return f.get(object);
+ }
+ } catch (NoSuchFieldException | IllegalAccessException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static Object getDeclaredField(Class> clazz, String field) {
+ try {
+ String cacheKey = "DeclaredField:" + clazz.getName() + ":" + field;
+
+ if (fieldCache.containsKey(cacheKey)) {
+ Field cachedField = fieldCache.get(cacheKey);
+ return cachedField.get(null);
+ } else {
+ Field f = clazz.getDeclaredField(field);
+ f.setAccessible(true);
+ fieldCache.put(cacheKey, f);
+ return f.get(null);
+ }
+ } catch (NoSuchFieldException | IllegalAccessException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static Object getDeclaredField(Object object, String field) {
+ try {
+ String cacheKey = "DeclaredField:" + object.getClass().getName() + ":" + field;
+
+ if (fieldCache.containsKey(cacheKey)) {
+ Field cachedField = fieldCache.get(cacheKey);
+ return cachedField.get(object);
+ } else {
+ Field f = object.getClass().getDeclaredField(field);
+ f.setAccessible(true);
+ fieldCache.put(cacheKey, f);
+ return f.get(object);
+ }
+ } catch (NoSuchFieldException | IllegalAccessException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static Object getDeclaredField(Class> clazz, Object object, String field) {
+ try {
+ String cacheKey = "DeclaredField:" + clazz.getName() + ":" + field;
+
+ if (fieldCache.containsKey(cacheKey)) {
+ Field cachedField = fieldCache.get(cacheKey);
+ return cachedField.get(object);
+ } else {
+ Field f = clazz.getDeclaredField(field);
+ f.setAccessible(true);
+ fieldCache.put(cacheKey, f);
+ return f.get(object);
+ }
+ } catch (NoSuchFieldException | IllegalAccessException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ public static void setDeclaredField(Object object, String field, Object value) {
+ try {
+ String cacheKey = "DeclaredField:" + object.getClass().getName() + ":" + field;
+
+ if (fieldCache.containsKey(cacheKey)) {
+ Field cachedField = fieldCache.get(cacheKey);
+ cachedField.set(object, value);
+ } else {
+ Field f = object.getClass().getDeclaredField(field);
+ f.setAccessible(true);
+ fieldCache.put(cacheKey, f);
+ f.set(object, value);
+ }
+ } catch (NoSuchFieldException | IllegalAccessException ex) {
+ ex.printStackTrace();
+ }
+ }
+}
\ No newline at end of file