Skip to content

Instantly share code, notes, and snippets.

@KillerGoldFisch
Forked from Techcable/Reflection.java
Created May 21, 2016 09:51
Show Gist options
  • Save KillerGoldFisch/670493818165777bd3f40cc32219ed15 to your computer and use it in GitHub Desktop.
Save KillerGoldFisch/670493818165777bd3f40cc32219ed15 to your computer and use it in GitHub Desktop.
Get TPS
/**
* The MIT License
* Copyright (c) 2014-2015 Techcable
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.bukkit.Bukkit;
import com.google.common.base.Preconditions;
public class Reflection {
public static Class<?> getNmsClass(String name) {
String className = "net.minecraft.server." + getVersion() + "." + name;
return getClass(className);
}
public static Class<?> getCbClass(String name) {
String className = "org.bukkit.craftbukkit." + getVersion() + "." + name;
return getClass(className);
}
public static Class<?> getUtilClass(String name) {
try {
return Class.forName(name); //Try before 1.8 first
} catch (ClassNotFoundException ex) {
try {
return Class.forName("net.minecraft.util." + name); //Not 1.8
} catch (ClassNotFoundException ex2) {
return null;
}
}
}
public static String getVersion() {
String packageName = Bukkit.getServer().getClass().getPackage().getName();
return packageName.substring(packageName.lastIndexOf('.') + 1);
}
public static Object getHandle(Object wrapper) {
Method getHandle = makeMethod(wrapper.getClass(), "getHandle");
return callMethod(getHandle, wrapper);
}
//Utils
public static Method makeMethod(Class<?> clazz, String methodName, Class<?>... paramaters) {
try {
return clazz.getDeclaredMethod(methodName, paramaters);
} catch (NoSuchMethodException ex) {
return null;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
@SuppressWarnings("unchecked")
public static <T> T callMethod(Method method, Object instance, Object... paramaters) {
if (method == null) throw new RuntimeException("No such method");
method.setAccessible(true);
try {
return (T) method.invoke(instance, paramaters);
} catch (InvocationTargetException ex) {
throw new RuntimeException(ex.getCause());
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
@SuppressWarnings("unchecked")
public static <T> Constructor<T> makeConstructor(Class<?> clazz, Class<?>... paramaterTypes) {
try {
return (Constructor<T>) clazz.getConstructor(paramaterTypes);
} catch (NoSuchMethodException ex) {
return null;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public static <T> T callConstructor(Constructor<T> constructor, Object... paramaters) {
if (constructor == null) throw new RuntimeException("No such constructor");
constructor.setAccessible(true);
try {
return (T) constructor.newInstance(paramaters);
} catch (InvocationTargetException ex) {
throw new RuntimeException(ex.getCause());
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public static Field makeField(Class<?> clazz, String name) {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException ex) {
return null;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
@SuppressWarnings("unchecked")
public static <T> T getField(Field field, Object instance) {
if (field == null) throw new RuntimeException("No such field");
field.setAccessible(true);
try {
return (T) field.get(instance);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public static void setField(Field field, Object instance, Object value) {
if (field == null) throw new RuntimeException("No such field");
field.setAccessible(true);
try {
field.set(instance, value);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public static Class<?> getClass(String name) {
try {
return Class.forName(name);
} catch (ClassNotFoundException ex) {
return null;
}
}
public static <T> Class<? extends T> getClass(String name, Class<T> superClass) {
try {
return Class.forName(name).asSubclass(superClass);
} catch (ClassCastException | ClassNotFoundException ex) {
return null;
}
}
// Fuzzy reflection
public static Field getOnlyField(Class<?> toGetFrom, Class<?> type) {
Field only = null;
for (Field field : toGetFrom.getDeclaredFields()) {
if (!type.isAssignableFrom(field.getClass())) continue;
Preconditions.checkArgument(only == null, "More than one field of type %s on %s: %s and %s", type.getSimpleName(), toGetFrom.getSimpleName(), field.getName(), only.getName());
only = field;
}
return only;
}
public static Method getOnlyMethod(Class<?> toGetFrom, Class<?> returnType, Class<?>... paramSpec) {
Method only = null;
for (Method method : toGetFrom.getDeclaredMethods()) {
if (!returnType.isAssignableFrom(method.getReturnType())) continue;
if (!isParamsMatchSpec(method.getParameterTypes(), paramSpec)) continue;
Preconditions.checkArgument(only == null, "More than one method matching spec on %s" + ((only.getName().equals(method.getName())) ? "" : ": " + only.getName() + " " + method.getName()), toGetFrom.getSimpleName());
only = method;
}
return only;
}
public static boolean isParamsMatchSpec(Class<?>[] parameters, Class<?>... paramSpec) {
if (parameters.length > paramSpec.length) return false;
for (int i = 0; i < paramSpec.length; i++) {
Class<?> spec = paramSpec[i];
if (spec == null) continue;
Class parameter = parameters[i];
if (!spec.isAssignableFrom(parameter)) return false;
}
return true;
}
}
/**
* The MIT License
* Copyright (c) 2014-2015 Techcable
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
import java.lang.reflect.*;
import org.bukkit.Bukkit;
public class TPS {
private TPS() {}
public static int getTPS() {
return getAverageTPS(1);
}
public static int getAverageTPS(int time) {
double[] recentTps;
if (canGetWithPaper) {
recentTps = getPaperRecentTps();
} else {
recentTps = getNMSRecentTps();
}
double raw;
int tps;
switch (time) {
case 1 :
raw = recentTps[0];
tps = Math.min(Math.round(raw * 100.0) / 100.0, 20.0);
return tps;
case 5 :
raw = recentTps[1];
tps = Math.min(Math.round(raw * 100.0) / 100.0, 20.0);
return tps;
case 15 :
raw = recentTps[2];
tps = Math.min(Math.round(raw * 100.0) / 100.0, 20.0);
return tps;
default :
throw new IllegalArgumentException("Unsupported tps measure time " + time);
}
}
private static final Class<?> spigotServerClass = Reflection.getClass("org.bukkit.Server$Spigot");
private static final Method getSpigotMethod = Reflection.makeMethod(Bukkit.class, "spigot");
private static final Method getTPSMethod = spigotServerClass != null ? Reflection.makeMethod(spigotServerClass, "getTPS") : null;
private static double[] getPaperRecentTps() {
if (!canGetWithPaper()) throw new UnsupportedOperationException("Can't get TPS from Paper");
Object server = Reflection.callMethod(getServerMethod, null); // Call static MinecraftServer.getServer()
double[] recent = Reflection.getField(recentTpsField, server);
return recent;
}
private boolean canGetWithPaper() {
return getSpigotMethod != null && getTPSMethod != null;
}
private static final Class<?> minecraftServerClass = Reflection.getNmsClass("MinecraftServer");
private static final Method getServerMethod = minecraftServerClass != null ? Reflection.makeMethod(minecraftServerClass, "getServer") : null;
private static final Field recentTpsField = minecraftServerClass != null ? Reflection.makeField(minecraftServerClass, "recentTps") : null;
private static double[] getNMSRecentTps() {
if (getServerMethod == null || recentTpsField == null) throw new UnsupportedOpperationException("Can't get TPS from NMS");
Object server = Reflection.callMethod(getServerMethod, null); // Call static MinecraftServer.getServer()
double[] recent = Reflection.getField(recentTpsField, server);
return recent;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment