forked from cybertiger/Bukkit-LibNBT
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CBShim.java
111 lines (102 loc) · 4.25 KB
/
CBShim.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.cyberiantiger.minecraft.unsafe;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Server;
import org.bukkit.plugin.Plugin;
/**
*
* @author antony
*/
public class CBShim {
private static final String CRAFTBUKKIT_PACKAGE = "org.bukkit.craftbukkit";
private static final Map<Class, Class> PRIMITIVE_TYPES = new HashMap<Class,Class>();
static {
PRIMITIVE_TYPES.put(Boolean.TYPE, Boolean.class);
PRIMITIVE_TYPES.put(Byte.TYPE, Byte.class);
PRIMITIVE_TYPES.put(Short.TYPE, Short.class);
PRIMITIVE_TYPES.put(Integer.TYPE, Integer.class);
PRIMITIVE_TYPES.put(Long.TYPE, Long.class);
PRIMITIVE_TYPES.put(Float.TYPE, Float.class);
PRIMITIVE_TYPES.put(Double.TYPE, Double.class);
PRIMITIVE_TYPES.put(Character.TYPE, Character.class);
PRIMITIVE_TYPES.put(Void.TYPE, Void.class);
}
@SuppressWarnings("unchecked")
public static <T> T createShim(Class<T> type, Plugin plugin, Object... args) {
String version = getNmsVersion(plugin);
try {
Class<? extends T> resultType = loadShim(type, version);
T result = newInstance(resultType, args);
if (result instanceof VersionedNMS) {
String targetVersion = ((VersionedNMS) result).getTargetVersion();
if (!version.equals(targetVersion)) {
resultType = loadShim(type, targetVersion);
return newInstance(resultType, args);
}
}
return result;
} catch (ReflectiveOperationException | IllegalArgumentException ex) {
unsupportedVersion(plugin.getServer(), ex);
}
// Unreachable
return null;
}
/**
* Get the versioning on NMS.
* @param plugin A plugin loaded by the server.
* @return A string such as v1_12_R1 used in the package name of NMS.
*/
private static String getNmsVersion(Plugin plugin) {
Class<?> serverClass = plugin.getServer().getClass();
while (!serverClass.getPackage().getName().startsWith(CRAFTBUKKIT_PACKAGE) ) {
serverClass = serverClass.getSuperclass();
if (serverClass == null) {
unsupportedVersion(plugin.getServer());
}
}
String pkg = serverClass.getPackage().getName();
int i = pkg.lastIndexOf(".");
if (i == -1) {
unsupportedVersion(plugin.getServer());
}
return pkg.substring(i+1);
}
@SuppressWarnings("unchecked")
private static <T> T newInstance(Class<? extends T> type, Object[] args) throws ReflectiveOperationException {
LOOP:
for (Constructor constructor : type.getConstructors()) {
Class[] parameterTypes = constructor.getParameterTypes();
if (args.length != parameterTypes.length) {
continue LOOP;
}
for (int i = 0; i < parameterTypes.length; i++) {
Class parameterType = parameterTypes[i];
if (PRIMITIVE_TYPES.containsKey(parameterType))
parameterType = PRIMITIVE_TYPES.get(parameterType);
if (!parameterType.isInstance(args[i])) {
continue LOOP;
}
}
return (T) constructor.newInstance(args);
}
throw new IllegalArgumentException("Constructor with arguments :" + Arrays.toString(args) + " not found");
}
@SuppressWarnings("unchecked")
private static <T> Class<? extends T> loadShim(Class<T> type, String version) throws ReflectiveOperationException {
String className = type.getPackage().getName() + '.' + version + '.' + type.getSimpleName();
return (Class<? extends T>) Class.forName(className);
}
private static void unsupportedVersion(Server server) {
unsupportedVersion(server, null);
}
private static void unsupportedVersion(Server server, Exception ex) {
throw new UnsupportedOperationException("Unsupported CraftBukkit version: " + server.getBukkitVersion(), ex);
}
}