Compare commits

4 Commits
4.0.0 ... main

Author SHA1 Message Date
53a2d261ff Upload dependency-reduced-pom.xml via GUI 2026-01-15 12:34:30 +00:00
1dd1f6b541 Update from Git Manager GUI 2026-01-15 13:34:29 +01:00
b87eaae396 Upload pom.xml via GUI 2026-01-15 12:34:28 +00:00
ccf47fbc67 Upload plugin.yml via GUI 2026-01-15 12:34:27 +00:00
3 changed files with 388 additions and 358 deletions

View File

@@ -4,7 +4,7 @@
<groupId>be.maximvdw</groupId> <groupId>be.maximvdw</groupId>
<artifactId>MVdWPlaceholderAPI</artifactId> <artifactId>MVdWPlaceholderAPI</artifactId>
<name>MVdWPlaceholderAPI</name> <name>MVdWPlaceholderAPI</name>
<version>3.1.1-SNAPSHOT</version> <version>4.0.0</version>
<description>Placeholder API for MVdW Software plugins</description> <description>Placeholder API for MVdW Software plugins</description>
<build> <build>
<resources> <resources>

View File

@@ -10,109 +10,117 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public abstract class ReflectionUtil { public abstract class ReflectionUtil {
private static volatile Map<Class<?>, Class<?>> CORRESPONDING_TYPES = new HashMap<Class<?>, Class<?>>(); private static volatile Map<Class<?>, Class<?>> CORRESPONDING_TYPES = new HashMap<Class<?>, Class<?>>();
public static Class<?> obcPlayer = ReflectionUtil.getOBCClass("entity.CraftPlayer"); public static Class<?> obcPlayer = ReflectionUtil.getOBCClass("entity.CraftPlayer");
public static Method methodPlayerGetHandle = getMethod("getHandle", obcPlayer); public static Method methodPlayerGetHandle = getMethod("getHandle", obcPlayer);
static { static {
CORRESPONDING_TYPES.put(Byte.class, byte.class); CORRESPONDING_TYPES.put(Byte.class, byte.class);
CORRESPONDING_TYPES.put(Short.class, short.class); CORRESPONDING_TYPES.put(Short.class, short.class);
CORRESPONDING_TYPES.put(Integer.class, int.class); CORRESPONDING_TYPES.put(Integer.class, int.class);
CORRESPONDING_TYPES.put(Long.class, long.class); CORRESPONDING_TYPES.put(Long.class, long.class);
CORRESPONDING_TYPES.put(Character.class, char.class); CORRESPONDING_TYPES.put(Character.class, char.class);
CORRESPONDING_TYPES.put(Float.class, float.class); CORRESPONDING_TYPES.put(Float.class, float.class);
CORRESPONDING_TYPES.put(Double.class, double.class); CORRESPONDING_TYPES.put(Double.class, double.class);
CORRESPONDING_TYPES.put(Boolean.class, boolean.class); CORRESPONDING_TYPES.put(Boolean.class, boolean.class);
} }
public enum DynamicPackage { public enum DynamicPackage {
MINECRAFT_SERVER { MINECRAFT_SERVER {
@Override @Override
public String toString() { public String toString() {
return "net.minecraft.server." + Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; String pkgName = Bukkit.getServer().getClass().getPackage().getName();
} // Fix für 1.21+: Prüfen der Länge, da split("\\.")[3] fehlschlägt
}, String[] parts = pkgName.split("\\.");
CRAFTBUKKIT { if (parts.length > 3) {
@Override return "net.minecraft.server." + parts[3];
public String toString() { } else {
return Bukkit.getServer().getClass().getPackage().getName(); // Fallback für 1.21+, obwohl NMS Packages dort komplett anders sind
} return "net.minecraft.server";
} }
} }
},
CRAFTBUKKIT {
@Override
public String toString() {
return Bukkit.getServer().getClass().getPackage().getName();
}
}
}
public static class FieldEntry { public static class FieldEntry {
String key; String key;
Object value; Object value;
public FieldEntry(String key, Object value) { public FieldEntry(String key, Object value) {
this.key = key; this.key = key;
this.value = value; this.value = value;
} }
public String getKey() { public String getKey() {
return this.key; return this.key;
} }
public Object getValue() { public Object getValue() {
return this.value; return this.value;
} }
} }
private static Class<?> getPrimitiveType(Class<?> clazz) { private static Class<?> getPrimitiveType(Class<?> clazz) {
return CORRESPONDING_TYPES.containsKey(clazz) ? CORRESPONDING_TYPES.get(clazz) : clazz; return CORRESPONDING_TYPES.containsKey(clazz) ? CORRESPONDING_TYPES.get(clazz) : clazz;
} }
private static Class<?>[] toPrimitiveTypeArray(Object[] objects) { private static Class<?>[] toPrimitiveTypeArray(Object[] objects) {
int a = objects != null ? objects.length : 0; int a = objects != null ? objects.length : 0;
Class<?>[] types = new Class<?>[a]; Class<?>[] types = new Class<?>[a];
for (int i = 0; i < a; i++) for (int i = 0; i < a; i++)
types[i] = getPrimitiveType(objects[i].getClass()); types[i] = getPrimitiveType(objects[i].getClass());
return types; return types;
} }
private static Class<?>[] toPrimitiveTypeArray(Class<?>[] classes) { private static Class<?>[] toPrimitiveTypeArray(Class<?>[] classes) {
int a = classes != null ? classes.length : 0; int a = classes != null ? classes.length : 0;
Class<?>[] types = new Class<?>[a]; Class<?>[] types = new Class<?>[a];
for (int i = 0; i < a; i++) for (int i = 0; i < a; i++)
types[i] = getPrimitiveType(classes[i]); types[i] = getPrimitiveType(classes[i]);
return types; return types;
} }
private static boolean equalsTypeArray(Class<?>[] a, Class<?>[] o) { private static boolean equalsTypeArray(Class<?>[] a, Class<?>[] o) {
if (a.length != o.length) if (a.length != o.length)
return false; return false;
for (int i = 0; i < a.length; i++) for (int i = 0; i < a.length; i++)
if (!a[i].equals(o[i]) && !a[i].isAssignableFrom(o[i])) if (!a[i].equals(o[i]) && !a[i].isAssignableFrom(o[i]))
return false; return false;
return true; return true;
} }
public static Class<?> getClass(String name, DynamicPackage pack, String subPackage) throws Exception { public static Class<?> getClass(String name, DynamicPackage pack, String subPackage) throws Exception {
return Class return Class
.forName(pack + (subPackage != null && subPackage.length() > 0 ? "." + subPackage : "") + "." + name); .forName(pack + (subPackage != null && subPackage.length() > 0 ? "." + subPackage : "") + "." + name);
} }
public static Class<?> getClass(String name, DynamicPackage pack) { public static Class<?> getClass(String name, DynamicPackage pack) {
try { try {
return getClass(name, pack, null); return getClass(name, pack, null);
} catch (Exception e) { } catch (Exception e) {
} }
return null; return null;
} }
public static Class<?> getClass(String name, String namespace) throws Exception { public static Class<?> getClass(String name, String namespace) throws Exception {
return Class.forName(namespace + "." + name); return Class.forName(namespace + "." + name);
} }
public static Object getHandle(Object obj) { public static Object getHandle(Object obj) {
try { try {
return getMethod("getHandle", obj.getClass()).invoke(obj); return getMethod("getHandle", obj.getClass()).invoke(obj);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }
} }
public static Object getHandle(Player player) { public static Object getHandle(Player player) {
try { try {
@@ -123,187 +131,199 @@ public abstract class ReflectionUtil {
} }
} }
public static Constructor<?> getConstructor(Class<?> clazz, Class<?>... paramTypes) { public static Constructor<?> getConstructor(Class<?> clazz, Class<?>... paramTypes) {
Class<?>[] t = toPrimitiveTypeArray(paramTypes); Class<?>[] t = toPrimitiveTypeArray(paramTypes);
for (Constructor<?> c : clazz.getConstructors()) { for (Constructor<?> c : clazz.getConstructors()) {
Class<?>[] types = toPrimitiveTypeArray(c.getParameterTypes()); Class<?>[] types = toPrimitiveTypeArray(c.getParameterTypes());
if (equalsTypeArray(types, t)) if (equalsTypeArray(types, t))
return c; return c;
} }
return null; return null;
} }
public static Object newInstance(Class<?> clazz, Object... args) throws Exception { public static Object newInstance(Class<?> clazz, Object... args) throws Exception {
return getConstructor(clazz, toPrimitiveTypeArray(args)).newInstance(args); return getConstructor(clazz, toPrimitiveTypeArray(args)).newInstance(args);
} }
public static Object newInstance(String name, DynamicPackage pack, String subPackage, Object... args) public static Object newInstance(String name, DynamicPackage pack, String subPackage, Object... args)
throws Exception { throws Exception {
return newInstance(getClass(name, pack, subPackage), args); return newInstance(getClass(name, pack, subPackage), args);
} }
public static Object newInstance(String name, DynamicPackage pack, Object... args) throws Exception { public static Object newInstance(String name, DynamicPackage pack, Object... args) throws Exception {
return newInstance(getClass(name, pack, null), args); return newInstance(getClass(name, pack, null), args);
} }
public static Method getMethod(String name, Class<?> clazz, Class<?>... paramTypes) { public static Method getMethod(String name, Class<?> clazz, Class<?>... paramTypes) {
Class<?>[] t = toPrimitiveTypeArray(paramTypes); Class<?>[] t = toPrimitiveTypeArray(paramTypes);
for (Method m : clazz.getMethods()) { for (Method m : clazz.getMethods()) {
Class<?>[] types = toPrimitiveTypeArray(m.getParameterTypes()); Class<?>[] types = toPrimitiveTypeArray(m.getParameterTypes());
if (m.getName().equals(name) && equalsTypeArray(types, t)) if (m.getName().equals(name) && equalsTypeArray(types, t))
return m; return m;
} }
return null; return null;
} }
public static Object invokeMethod(String name, Class<?> clazz, Object obj, Object... args) throws Exception { public static Object invokeMethod(String name, Class<?> clazz, Object obj, Object... args) throws Exception {
return getMethod(name, clazz, toPrimitiveTypeArray(args)).invoke(obj, args); return getMethod(name, clazz, toPrimitiveTypeArray(args)).invoke(obj, args);
} }
public static Field getField(String name, Class<?> clazz) throws Exception { public static Field getField(String name, Class<?> clazz) throws Exception {
return clazz.getDeclaredField(name); return clazz.getDeclaredField(name);
} }
public static Object getValue(String name, Object obj) throws Exception { public static Object getValue(String name, Object obj) throws Exception {
Field f = getField(name, obj.getClass()); Field f = getField(name, obj.getClass());
if (!f.isAccessible()) if (!f.isAccessible())
f.setAccessible(true); f.setAccessible(true);
return f.get(obj); return f.get(obj);
} }
public static Object getValueFromClass(String name, Object obj, Class<?> clazz) throws Exception { public static Object getValueFromClass(String name, Object obj, Class<?> clazz) throws Exception {
Field f = getField(name, clazz); Field f = getField(name, clazz);
if (!f.isAccessible()) if (!f.isAccessible())
f.setAccessible(true); f.setAccessible(true);
return f.get(obj); return f.get(obj);
} }
public static Object getValue(String name, Class<?> clazz) throws Exception { public static Object getValue(String name, Class<?> clazz) throws Exception {
Field f = getField(name, clazz); Field f = getField(name, clazz);
if (!f.isAccessible()) if (!f.isAccessible())
f.setAccessible(true); f.setAccessible(true);
return f.get(clazz); return f.get(clazz);
} }
public static void setValue(Object obj, FieldEntry entry) throws Exception { public static void setValue(Object obj, FieldEntry entry) throws Exception {
Field f = getField(entry.getKey(), obj.getClass()); Field f = getField(entry.getKey(), obj.getClass());
if (!f.isAccessible()) if (!f.isAccessible())
f.setAccessible(true); f.setAccessible(true);
f.set(obj, entry.getValue()); f.set(obj, entry.getValue());
} }
public static void setValue(String name, Object value, Object obj) throws Exception { public static void setValue(String name, Object value, Object obj) throws Exception {
Field f = getField(name, obj.getClass()); Field f = getField(name, obj.getClass());
if (!f.isAccessible()) if (!f.isAccessible())
f.setAccessible(true); f.setAccessible(true);
f.set(obj, value); f.set(obj, value);
} }
public static void setFinalValue(String name, Object value, Object obj) throws Exception { public static void setFinalValue(String name, Object value, Object obj) throws Exception {
Field f = obj.getClass().getDeclaredField(name); Field f = obj.getClass().getDeclaredField(name);
if (!f.isAccessible()) if (!f.isAccessible())
f.setAccessible(true); f.setAccessible(true);
f.set(obj, value); f.set(obj, value);
} }
public static void setValues(Object obj, FieldEntry... entrys) throws Exception { public static void setValues(Object obj, FieldEntry... entrys) throws Exception {
for (FieldEntry f : entrys) for (FieldEntry f : entrys)
setValue(obj, f); setValue(obj, f);
} }
public static String getVersion() { public static String getVersion() {
String name = Bukkit.getServer().getClass().getPackage().getName(); String name = Bukkit.getServer().getClass().getPackage().getName();
String version = name.substring(name.lastIndexOf('.') + 1) + "."; // Fix für 1.21+ (Paper): Paketstruktur ist flach "org.bukkit.craftbukkit"
return version; // Alte Versionen sind "org.bukkit.craftbukkit.v1_20_R3"
} if (name.equals("org.bukkit.craftbukkit")) {
return ""; // Keine Versions-Extension für 1.21+ nötig
}
String version = name.substring(name.lastIndexOf('.') + 1) + ".";
return version;
}
public static Class<?> getNMSClass(String className) { public static Class<?> getNMSClass(String className) {
String fullName = "net.minecraft.server." + getVersion() + className; // In 1.21 ist die Struktur von NMS komplett anders (Mojang Mappings),
Class<?> clazz = null; // diese Methode wird dort wahrscheinlich fehlschlagen, aber wir verhindern einen Absturz
try { // durch die falsche Versions-Logik.
clazz = Class.forName(fullName); String versionSuffix = getVersion();
} catch (Exception e) { String fullName = "net.minecraft.server." + versionSuffix + className;
e.printStackTrace(); Class<?> clazz = null;
} try {
return clazz; clazz = Class.forName(fullName);
} } catch (Exception e) {
// Ignorieren oder Loggen, wenn NMS nicht gefunden wird (Kann in 1.21+ passieren)
// e.printStackTrace();
}
return clazz;
}
public static Class<?> getOBCClass(String className) { public static Class<?> getOBCClass(String className) {
String fullName = "org.bukkit.craftbukkit." + getVersion() + className; String versionSuffix = getVersion();
Class<?> clazz = null; String fullName = "org.bukkit.craftbukkit." + versionSuffix + className;
try { Class<?> clazz = null;
clazz = Class.forName(fullName); try {
} catch (Exception e) { clazz = Class.forName(fullName);
e.printStackTrace(); } catch (Exception e) {
} e.printStackTrace();
return clazz; }
} return clazz;
}
public static Class<?> getNMSClassWithException(String className) throws Exception { public static Class<?> getNMSClassWithException(String className) throws Exception {
String fullName = "net.minecraft.server." + getVersion() + className; String versionSuffix = getVersion();
Class<?> clazz = Class.forName(fullName); String fullName = "net.minecraft.server." + versionSuffix + className;
return clazz; Class<?> clazz = Class.forName(fullName);
} return clazz;
}
public static Field getField(Class<?> clazz, String name) { public static Field getField(Class<?> clazz, String name) {
try { try {
Field field = clazz.getDeclaredField(name); Field field = clazz.getDeclaredField(name);
field.setAccessible(true); field.setAccessible(true);
return field; return field;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }
} }
public static Method getMethod(Class<?> clazz, String name, Class<?>... args) { public static Method getMethod(Class<?> clazz, String name, Class<?>... args) {
for (Method m : clazz.getMethods()) for (Method m : clazz.getMethods())
if (m.getName().equals(name) && (args.length == 0 || ClassListEqual(args, m.getParameterTypes()))) { if (m.getName().equals(name) && (args.length == 0 || ClassListEqual(args, m.getParameterTypes()))) {
m.setAccessible(true); m.setAccessible(true);
return m; return m;
} }
return null; return null;
} }
/** /**
* Set a specified Field accessible * Set a specified Field accessible
* *
* @param f * @param f
* Field set accessible * Field set accessible
*/ */
public static Field setAccessible(Field f) public static Field setAccessible(Field f)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
f.setAccessible(true); f.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers"); Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true); modifiersField.setAccessible(true);
modifiersField.setInt(f, f.getModifiers() & 0xFFFFFFEF); modifiersField.setInt(f, f.getModifiers() & 0xFFFFFFEF);
return f; return f;
} }
/** /**
* Set a specified Method accessible * Set a specified Method accessible
* *
* @param m * @param m
* Method set accessible * Method set accessible
*/ */
public static Method setAccessible(Method m) public static Method setAccessible(Method m)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
m.setAccessible(true); m.setAccessible(true);
return m; return m;
} }
public static boolean ClassListEqual(Class<?>[] l1, Class<?>[] l2) { public static boolean ClassListEqual(Class<?>[] l1, Class<?>[] l2) {
boolean equal = true; boolean equal = true;
if (l1.length != l2.length) if (l1.length != l2.length)
return false; return false;
for (int i = 0; i < l1.length; i++) for (int i = 0; i < l1.length; i++)
if (l1[i] != l2[i]) { if (l1[i] != l2[i]) {
equal = false; equal = false;
break; break;
} }
return equal; return equal;
} }
} }

View File

@@ -73,15 +73,25 @@ public class BukkitUtils {
} catch (Throwable e) { } catch (Throwable e) {
} }
} }
public static String getVersion() { public static String getVersion() {
if (Bukkit.getServer() == null) { if (Bukkit.getServer() == null) {
return ""; return "";
} }
if (version.equals("")) { if (version.equals("")) {
version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; // Korrektur: Prüfen der Länge des Paket-Namens, da 1.21+ (Paper) die Version nicht mehr im Namen trägt
String[] pkgSplit = Bukkit.getServer().getClass().getPackage().getName().split("\\.");
if (pkgSplit.length >= 4) {
// Altes Format: org.bukkit.craftbukkit.v1_20_R3
version = pkgSplit[3];
} else {
// Neues Format: org.bukkit.craftbukkit
// Wir nutzen Bukkit.getVersion() oder setzten eine Default-Version für 1.21
// Da wir für 1.21 bauen, setzen wir hier v1_21_R1, damit die weiteren Logik greift
version = "v1_21_R1";
}
String[] data = BukkitUtils.getVersion().substring(1).split("_"); String[] data = version.substring(1).split("_");
if (NumberUtils.isInteger(data[1]) && NumberUtils.isInteger(data[0])) { if (NumberUtils.isInteger(data[1]) && NumberUtils.isInteger(data[0])) {
versionMinor = Integer.parseInt(data[1]); versionMinor = Integer.parseInt(data[1]);
versionMajor = Integer.parseInt(data[0]); versionMajor = Integer.parseInt(data[0]);