[Lib] Reflection Utils

Discussion in 'Resources' started by DPOH-VAR, Mar 21, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    DPOH-VAR

    This class will help you to use reflection API to access to org.bukkit.craftbukkit.* and net.minecraft.server.*
    it works with any version of bukkit

    Code:
    Code:java
    1. import org.bukkit.Bukkit;
    2. import org.bukkit.Server;
    3.  
    4. import java.lang.reflect.Constructor;
    5. import java.lang.reflect.Field;
    6. import java.lang.reflect.Method;
    7. import java.util.ArrayList;
    8. import java.util.Collections;
    9. import java.util.List;
    10.  
    11. /**
    12.  * @author DPOH-VAR
    13.  * @version 1.0
    14.  */
    15. @SuppressWarnings("UnusedDeclaration")
    16. public class ReflectionUtils {
    17.  
    18. /** prefix of bukkit classes */
    19. private static String preClassB = "org.bukkit.craftbukkit";
    20. /** prefix of minecraft classes */
    21. private static String preClassM = "net.minecraft.server";
    22. /** boolean value, TRUE if server uses forge or MCPC+ */
    23. private static boolean forge = false;
    24.  
    25. /** check server version and class names */
    26. static {
    27. if(Bukkit.getServer()!=null) {
    28. if(Bukkit.getVersion().contains("MCPC")||Bukkit.getVersion().contains("Forge")) forge = true;
    29. Server server = Bukkit.getServer();
    30. Class<?> bukkitServerClass = server.getClass();
    31. String[] pas = bukkitServerClass.getName().split("\\.");
    32. if (pas.length == 5) {
    33. String verB = pas[3];
    34. preClassB += "."+verB;
    35. }
    36. try {
    37. Method getHandle = bukkitServerClass.getDeclaredMethod("getHandle");
    38. Object handle = getHandle.invoke(server);
    39. Class handleServerClass = handle.getClass();
    40. pas = handleServerClass.getName().split("\\.");
    41. if (pas.length == 5) {
    42. String verM = pas[3];
    43. preClassM += "."+verM;
    44. }
    45. } catch (Exception ignored) {
    46. }
    47. }
    48. }
    49.  
    50. /**
    51.   * @return true if server has forge classes
    52.   */
    53. public static boolean isForge(){
    54. return forge;
    55. }
    56.  
    57. /**
    58.   * Get class for name.
    59.   * Replace {nms} to net.minecraft.server.V*.
    60.   * Replace {cb} to org.bukkit.craftbukkit.V*.
    61.   * Replace {nm} to net.minecraft
    62.   * @param classes possible class paths
    63.   * @return RefClass object
    64.   * @throws RuntimeException if no class found
    65.   */
    66. public static RefClass getRefClass(String... classes){
    67. for (String className: classes) try {
    68. className = className
    69. .replace("{cb}", preClassB)
    70. .replace("{nms}", preClassM)
    71. .replace("{nm}", "net.minecraft");
    72. return getRefClass(Class.forName(className));
    73. } catch (ClassNotFoundException ignored) {
    74. }
    75. throw new RuntimeException("no class found");
    76. }
    77.  
    78. /**
    79.   * get RefClass object by real class
    80.   * @param clazz class
    81.   * @return RefClass based on passed class
    82.   */
    83. public static RefClass getRefClass(Class clazz) {
    84. return new RefClass(clazz);
    85. }
    86.  
    87. /**
    88.   * RefClass - utility to simplify work with reflections.
    89.   */
    90. public static class RefClass {
    91. private final Class<?> clazz;
    92.  
    93. /**
    94.   * get passed class
    95.   * @return class
    96.   */
    97. public Class<?> getRealClass() {
    98. return clazz;
    99. }
    100. private RefClass(Class<?> clazz) {
    101. this.clazz = clazz;
    102. }
    103.  
    104. /**
    105.   * see {@link Class#isInstance(Object)}
    106.   * @param object the object to check
    107.   * @return true if object is an instance of this class
    108.   */
    109. public boolean isInstance(Object object){
    110. return clazz.isInstance(object);
    111. }
    112.  
    113. /**
    114.   * get existing method by name and types
    115.   * @param name name
    116.   * @param types method parameters. can be Class or RefClass
    117.   * @return RefMethod object
    118.   * @throws RuntimeException if method not found
    119.   */
    120. public RefMethod getMethod(String name, Object... types) {
    121. try {
    122. Class[] classes = new Class[types.length];
    123. int i=0; for (Object e: types) {
    124. if (e instanceof Class) classes[i++] = (Class)e;
    125. else if (e instanceof RefClass) classes[i++] = ((RefClass) e).getRealClass();
    126. else classes[i++] = e.getClass();
    127. }
    128. try {
    129. return new RefMethod(clazz.getMethod(name, classes));
    130. } catch (NoSuchMethodException ignored) {
    131. return new RefMethod(clazz.getDeclaredMethod(name, classes));
    132. }
    133. } catch (Exception e) {
    134. throw new RuntimeException(e);
    135. }
    136. }
    137.  
    138. /**
    139.   * get existing constructor by types
    140.   * @param types parameters. can be Class or RefClass
    141.   * @return RefMethod object
    142.   * @throws RuntimeException if constructor not found
    143.   */
    144. public RefConstructor getConstructor(Object... types) {
    145. try {
    146. Class[] classes = new Class[types.length];
    147. int i=0; for (Object e: types) {
    148. if (e instanceof Class) classes[i++] = (Class)e;
    149. else if (e instanceof RefClass) classes[i++] = ((RefClass) e).getRealClass();
    150. else classes[i++] = e.getClass();
    151. }
    152. try {
    153. return new RefConstructor(clazz.getConstructor(classes));
    154. } catch (NoSuchMethodException ignored) {
    155. return new RefConstructor(clazz.getDeclaredConstructor(classes));
    156. }
    157. } catch (Exception e) {
    158. throw new RuntimeException(e);
    159. }
    160. }
    161.  
    162. /**
    163.   * find method by type parameters
    164.   * @param types parameters. can be Class or RefClass
    165.   * @return RefMethod object
    166.   * @throws RuntimeException if method not found
    167.   */
    168. public RefMethod findMethod(Object... types) {
    169. Class[] classes = new Class[types.length];
    170. int t=0; for (Object e: types) {
    171. if (e instanceof Class) classes[t++] = (Class)e;
    172. else if (e instanceof RefClass) classes[t++] = ((RefClass) e).getRealClass();
    173. else classes[t++] = e.getClass();
    174. }
    175. List<Method> methods = new ArrayList<>();
    176. Collections.addAll(methods, clazz.getMethods());
    177. Collections.addAll(methods, clazz.getDeclaredMethods());
    178. findMethod: for (Method m: methods) {
    179. Class<?>[] methodTypes = m.getParameterTypes();
    180. if (methodTypes.length != classes.length) continue;
    181. for (int i=0; i<classes.length; i++) {
    182. if (!classes.equals(methodTypes)) continue findMethod;
    183. return new RefMethod(m);
    184. }
    185. }
    186. throw new RuntimeException("no such method");
    187. }
    188.  
    189. /**
    190.   * find method by name
    191.   * @param names possible names of method
    192.   * @return RefMethod object
    193.   * @throws RuntimeException if method not found
    194.   */
    195. public RefMethod findMethodByName(String... names) {
    196. List<Method> methods = new ArrayList<>();
    197. Collections.addAll(methods, clazz.getMethods());
    198. Collections.addAll(methods, clazz.getDeclaredMethods());
    199. for (Method m: methods) {
    200. for (String name: names) {
    201. if (m.getName().equals(name)) {
    202. return new RefMethod(m);
    203. }
    204. }
    205. }
    206. throw new RuntimeException("no such method");
    207. }
    208.  
    209. /**
    210.   * find method by return value
    211.   * @param type type of returned value
    212.   * @throws RuntimeException if method not found
    213.   * @return RefMethod
    214.   */
    215. public RefMethod findMethodByReturnType(RefClass type) {
    216. return findMethodByReturnType(type.clazz);
    217. }
    218.  
    219. /**
    220.   * find method by return value
    221.   * @param type type of returned value
    222.   * @return RefMethod
    223.   * @throws RuntimeException if method not found
    224.   */
    225. public RefMethod findMethodByReturnType(Class type) {
    226. if (type==null) type = void.class;
    227. List<Method> methods = new ArrayList<>();
    228. Collections.addAll(methods, clazz.getMethods());
    229. Collections.addAll(methods, clazz.getDeclaredMethods());
    230. for (Method m: methods) {
    231. if (type.equals(m.getReturnType())) {
    232. return new RefMethod(m);
    233. }
    234. }
    235. throw new RuntimeException("no such method");
    236. }
    237.  
    238. /**
    239.   * find constructor by number of arguments
    240.   * @param number number of arguments
    241.   * @return RefConstructor
    242.   * @throws RuntimeException if constructor not found
    243.   */
    244. public RefConstructor findConstructor(int number) {
    245. List<Constructor> constructors = new ArrayList<>();
    246. Collections.addAll(constructors, clazz.getConstructors());
    247. Collections.addAll(constructors, clazz.getDeclaredConstructors());
    248. for (Constructor m: constructors) {
    249. if (m.getParameterTypes().length == number) return new RefConstructor(m);
    250. }
    251. throw new RuntimeException("no such constructor");
    252. }
    253.  
    254. /**
    255.   * get field by name
    256.   * @param name field name
    257.   * @return RefField
    258.   * @throws RuntimeException if field not found
    259.   */
    260. public RefField getField(String name) {
    261. try {
    262. try {
    263. return new RefField(clazz.getField(name));
    264. } catch (NoSuchFieldException ignored) {
    265. return new RefField(clazz.getDeclaredField(name));
    266. }
    267. } catch (Exception e) {
    268. throw new RuntimeException(e);
    269. }
    270. }
    271.  
    272. /**
    273.   * find field by type
    274.   * @param type field type
    275.   * @return RefField
    276.   * @throws RuntimeException if field not found
    277.   */
    278. public RefField findField(RefClass type) {
    279. return findField(type.clazz);
    280. }
    281.  
    282. /**
    283.   * find field by type
    284.   * @param type field type
    285.   * @return RefField
    286.   * @throws RuntimeException if field not found
    287.   */
    288. public RefField findField(Class type) {
    289. if (type==null) type = void.class;
    290. List<Field> fields = new ArrayList<>();
    291. Collections.addAll(fields, clazz.getFields());
    292. Collections.addAll(fields, clazz.getDeclaredFields());
    293. for (Field f: fields) {
    294. if (type.equals(f.getType())) {
    295. return new RefField(f);
    296. }
    297. }
    298. throw new RuntimeException("no such field");
    299. }
    300. }
    301.  
    302. /**
    303.   * Method wrapper
    304.   */
    305. public static class RefMethod {
    306. private final Method method;
    307.  
    308. /**
    309.   * @return passed method
    310.   */
    311. public Method getRealMethod(){
    312. return method;
    313. }
    314. /**
    315.   * @return owner class of method
    316.   */
    317. public RefClass getRefClass(){
    318. return new RefClass(method.getDeclaringClass());
    319. }
    320. /**
    321.   * @return class of method return type
    322.   */
    323. public RefClass getReturnRefClass(){
    324. return new RefClass(method.getReturnType());
    325. }
    326. private RefMethod (Method method) {
    327. this.method = method;
    328. method.setAccessible(true);
    329. }
    330. /**
    331.   * apply method to object
    332.   * @param e object to which the method is applied
    333.   * @return RefExecutor with method call(...)
    334.   */
    335. public RefExecutor of(Object e) {
    336. return new RefExecutor(e);
    337. }
    338.  
    339. /**
    340.   * call static method
    341.   * @param params sent parameters
    342.   * @return return value
    343.   */
    344. public Object call(Object... params) {
    345. try{
    346. return method.invoke(null,params);
    347. } catch (Exception e) {
    348. throw new RuntimeException(e);
    349. }
    350. }
    351.  
    352. public class RefExecutor {
    353. Object e;
    354. public RefExecutor(Object e) {
    355. this.e = e;
    356. }
    357.  
    358. /**
    359.   * apply method for selected object
    360.   * @param params sent parameters
    361.   * @return return value
    362.   * @throws RuntimeException if something went wrong
    363.   */
    364. public Object call(Object... params) {
    365. try{
    366. return method.invoke(e,params);
    367. } catch (Exception e) {
    368. throw new RuntimeException(e);
    369. }
    370. }
    371. }
    372. }
    373.  
    374. /**
    375.   * Constructor wrapper
    376.   */
    377. public static class RefConstructor {
    378. private final Constructor constructor;
    379.  
    380. /**
    381.   * @return passed constructor
    382.   */
    383. public Constructor getRealConstructor(){
    384. return constructor;
    385. }
    386.  
    387. /**
    388.   * @return owner class of method
    389.   */
    390. public RefClass getRefClass(){
    391. return new RefClass(constructor.getDeclaringClass());
    392. }
    393. private RefConstructor (Constructor constructor) {
    394. this.constructor = constructor;
    395. constructor.setAccessible(true);
    396. }
    397.  
    398. /**
    399.   * create new instance with constructor
    400.   * @param params parameters for constructor
    401.   * @return new object
    402.   * @throws RuntimeException if something went wrong
    403.   */
    404. public Object create(Object... params) {
    405. try{
    406. return constructor.newInstance(params);
    407. } catch (Exception e) {
    408. throw new RuntimeException(e);
    409. }
    410. }
    411. }
    412.  
    413. public static class RefField {
    414. private Field field;
    415.  
    416. /**
    417.   * @return passed field
    418.   */
    419. public Field getRealField(){
    420. return field;
    421. }
    422.  
    423. /**
    424.   * @return owner class of field
    425.   */
    426. public RefClass getRefClass(){
    427. return new RefClass(field.getDeclaringClass());
    428. }
    429.  
    430. /**
    431.   * @return type of field
    432.   */
    433. public RefClass getFieldRefClass(){
    434. return new RefClass(field.getType());
    435. }
    436. private RefField (Field field) {
    437. this.field = field;
    438. field.setAccessible(true);
    439. }
    440.  
    441. /**
    442.   * apply fiend for object
    443.   * @param e applied object
    444.   * @return RefExecutor with getter and setter
    445.   */
    446. public RefExecutor of(Object e) {
    447. return new RefExecutor(e);
    448. }
    449. public class RefExecutor {
    450. Object e;
    451. public RefExecutor(Object e) {
    452. this.e = e;
    453. }
    454.  
    455. /**
    456.   * set field value for applied object
    457.   * @param param value
    458.   */
    459. public void set(Object param) {
    460. try{
    461. field.set(e,param);
    462. } catch (Exception e) {
    463. throw new RuntimeException(e);
    464. }
    465. }
    466.  
    467. /**
    468.   * get field value for applied object
    469.   * @return value of field
    470.   */
    471. public Object get() {
    472. try{
    473. return field.get(e);
    474. } catch (Exception e) {
    475. throw new RuntimeException(e);
    476. }
    477. }
    478. }
    479. }
    480.  
    481. }
    482. }

    How to use:

    1. get class

    Method getRefClass allows you to get class by name.
    RefClass classCraftPlayer = getRefClass("{cb}.entity.CraftPlayer");
    use this patterns to replace package name:
    {nms} -> net.minecraft.server.v_*
    {cb} -> org.bukkit.craftbukkit.v_*
    {nm} -> net.minecraft
    You can specify more than one name:
    private static final RefClass classParticlePacket = getRefClass(
    "{nms}.Packet63WorldParticles", // bukkit 1.6​
    "{nms}.PacketPlayOutWorldParticles", // bukkit 1.7​
    "{nm}.network.packet.Packet63WorldParticles", // forge​
    );

    method returns a wrapper over the class

    2. get method

    RefMethod methodGetHandle = classCraftPlayer.getMethod("getHandle");
    RefMethod is wrapper of method org.bukkit.craftbukkit.CraftPlayer.getHandle()
    getMethod(String, Object...) takes values:
    - method name
    - parameter types (java.lang.Class or RefClass objects)
    You can find method by name, by return value, by type parameters. See the documentation

    3. call method

    call non-static method:
    result = myRefMethod.of(object).call(parameters...)
    call static method:
    result = myRefMethod.call(parameters...)
    result = myRefMethod.of(null).call(parameters...)


    4. get field

    RefField myField = myRefClass.getField("name");
    You can find field by class:
    myRefClass.fildField(int.class); - fild field of type "int"

    5. change value of field

    Object value = myField.of(object).get();
    myField.of(object).set(value);

    use null instead of object to access static fields.
    Don't change value of final fields.

    6. use constructor

    RefConstructor myConstructor = myRefClass.getConstuctor(types...)
    You can find constructor by number of arguments: findConstructor(int)
    Create new object with this constructor:
    Object newInstance = myConstructor.create(parameters...)

    All of these methods can throw RuntimeException

    Example:

    This class allows you to play custom effects using Packet WorldParticles
    Code:java
    1. import org.bukkit.Location;
    2. import org.bukkit.entity.Player;
    3.  
    4. import static ReflectionUtils.*;
    5.  
    6. public class Particle {
    7.  
    8. private static final RefClass classParticlePacket = getRefClass(
    9. "{nms}.Packet63WorldParticles", // 1.6
    10. "{nms}.PacketPlayOutWorldParticles" // 1.7
    11. );
    12. private static final RefField fieldPacketName = classParticlePacket.getField("a");
    13. private static final RefField fieldPacketLocX = classParticlePacket.getField("b");
    14. private static final RefField fieldPacketLocY = classParticlePacket.getField("c");
    15. private static final RefField fieldPacketLocZ = classParticlePacket.getField("d");
    16. private static final RefField fieldPacketDifX = classParticlePacket.getField("e");
    17. private static final RefField fieldPacketDifY = classParticlePacket.getField("f");
    18. private static final RefField fieldPacketDifZ = classParticlePacket.getField("g");
    19. private static final RefField fieldPacketSpeed = classParticlePacket.getField("h");
    20. private static final RefField fieldPacketAmount = classParticlePacket.getField("i");
    21. private static final RefConstructor particlesConstructor = classParticlePacket.getConstructor();
    22.  
    23. private static final RefClass classPacket = getRefClass("{nms}.Packet");
    24. private static final RefClass classCraftPlayer = getRefClass("{cb}.entity.CraftPlayer");
    25. private static final RefMethod methodGetHandle = classCraftPlayer.getMethod("getHandle");
    26. private static final RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer");
    27. private static final RefField fieldPlayerConnection = classEntityPlayer.getField("playerConnection");
    28. private static final RefClass classPlayerConnection = getRefClass("{nms}.PlayerConnection");
    29. private static final RefMethod methodSendPacket = classPlayerConnection.findMethod(classPacket);
    30.  
    31. private String name;
    32.  
    33. public Particle(String name) {
    34. this.name = name;
    35. }
    36.  
    37. public float dx = 0;
    38. public float dy = 0;
    39. public float dz = 0;
    40. public float speed = 0;
    41. public int amount = 1;
    42.  
    43. public void send(Location location){
    44. Object packet = particlesConstructor.create();
    45. fieldPacketName.of(packet).set(name);
    46. fieldPacketLocX.of(packet).set((float)location.getX());
    47. fieldPacketLocY.of(packet).set((float)location.getY());
    48. fieldPacketLocZ.of(packet).set((float)location.getZ());
    49. fieldPacketDifX.of(packet).set(dx);
    50. fieldPacketDifY.of(packet).set(dy);
    51. fieldPacketDifZ.of(packet).set(dz);
    52. fieldPacketSpeed.of(packet).set(speed);
    53. fieldPacketAmount.of(packet).set(amount);
    54.  
    55. for (Player player: location.getWorld().getPlayers()) {
    56. if (player.getLocation().distance(location) > 64) continue;
    57. Object handle = methodGetHandle.of(player).call();
    58. Object connection = fieldPlayerConnection.of(handle).get();
    59. methodSendPacket.of(connection).call(packet);
    60. }
    61. }
    62.  
    63. }

    Particle particle = new Particle("witchMagic");
    particle.amount = 10;
    particle.dy = 1;
    particle.send(location); //play particle effect
     
  2. Offline

    Bammerbom

  3. Offline

    Ultimate_n00b

    Why do you use distance instead of distanceSquared?
     
  4. Offline

    DPOH-VAR

    I did it hastily
    Code:java
    1. if (player.getLocation().distanceSquared(location) > 4096) continue;
    but distanceSquared will work faster
     
  5. Offline

    Ultimate_n00b

    It does work faster, being why I corrected you.
     
    DPOH-VAR likes this.
  6. Offline

    DPOH-VAR

    The most expensive operations in the loop is
    Object handle = methodGetHandle.of(player).call();
    Object connection = fieldPlayerConnection.of(handle).get();
    methodSendPacket.of(connection).call(packet);
    because they calls Reflection API
     
  7. Offline

    Bammerbom

    I love this resource!
     
  8. Offline

    RawCode

    invalid

    version barrier exists for a reason, anything that intended to break version barrier is harmful and useless for public plugins.
     
  9. Offline

    DPOH-VAR

    This is true only if you have no experience with reflections and craftbukkit.
     
  10. Offline

    RawCode

    please explain how you going to predict what name "field a of class b" will have in next version of bukkit.
    looks like you are very very expirienced in this DPOH-VAR

    As long as you do not understand meaning of version barrier you will think that you are smarter then bukkit team and try to overcome it, this is way to disaster.
     
  11. Offline

    DPOH-VAR

    I suggest to find field by type.
    Code:groovy
    1. // Example: class in net.minectaft.server.v*.
    2. class MinecraftClass{
    3. private double value = 0;
    4. }
    5.  
    6. // Example: similar class in net.minectaft. (mcpc)
    7. class MCPCClass{
    8. private double field_1234 = 0;
    9. }
    10.  
    11. // using ReflectionUtils
    12. RefField field = myClass.findField(double.class);
    13. double value = field.of(myObject).get();
    14. // may be a problem if there are two or more fields of type double
    15. // but it happens in rare cases
    16.  

    I know why developers have separated server to bukkit API and craftbukkit.
    Bukkit API is backward compatible. Any plugin using only Bukit API will work after update the server.
    But craftbukkit does not guarantee any compatibility. And version barrier only warns about it.

    If I want to use NBT classes in my plugin (net.minecraft.server.v*.NBTBase, net.minectaft.nbt.NBTBase) >
    need to create a intermediate class for each craftbukkit version from 1.4.6 to 1.7.9?

    UPD: ReflectionUtils.java v 1.2
    What is new:
    1) public static RefClass ReflectionUtils.getRefClass(String pattern)
    pattern contains a possible classes, separated by ","
    Example:
    Code:groovy
    1. // get EntityPlayer class. If class is not found, throw exception
    2. RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer, {nm}.entity.player.EntityPlayer");
    3. // get EntityPlayer class. If class is not found, return null (last argument)
    4. RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer, {nm}.entity.player.EntityPlayer, null");

    2) public RefMethod RefClass.findMethod(MethodCondition... condition)
    find method by special conditions
    Example:
    Code:groovy
    1. // find method that takes NBTTagCompound
    2. // and method name ends with "a"
    3. RefMethod write = classTileEntity.findMethod( new MethodCondition()
    4. .withTypes("{nms}.NBTTagCompound, {nm}.nbt.NBTTagCompound, {NBTTagCompound}")
    5. .withSuffix("a")
    6. );

    class MethodCondition has methods:
    withForge(boolean forge) // check checks whether your server is forge
    withName(String name) // check full name of method
    withPrefix(String prefix) // check prefix of method name
    withSuffix(String suffix) // check suffix of method name
    withReturnType(Class returnType) // check return type of method
    withReturnType(RefClass returnType) // as previous, using RefClass
    withReturnType(String pattern) // as previous, but you can specify pattern of return type
    withTypes(Object... types) // check parameter types. "types" can be: Class, RefClass, String pattern
    withAbstract(boolean modAbstract) // check abstract modifier
    withFinal(boolean modFinal) // check final modifier
    withStatic(boolean modStatic) // check static modifier
    withIndex(int index) // use it if there is more than one method found. This check occurs in the last.

    3) ReflectionUtils.addReplacement(String key, String value)
    add new replacement for using in patterns
    Default replacements is:
    nm -> net.minectaft
    nms -> net.minecraft.server.%current_version%
    cb -> org.bukkit.craftbukkit.%current_version%
    Example:
    Code:groovy
    1. addReplacement("nbt", "net.minecraft.nbt");
    2. RefClass classNBTTagCompound = getRefClass("{nbt}.NBTTagCompound");


    4) ReflectionUtils.addReplacementsYaml(File file)
    load replacements from yaml file.
    used in PowerNBT to fix forge classes

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 7, 2016
  12. Offline

    RawCode

    I suggest to find field by type. DPOH-VAR

    public class z
    {
    boolean a
    boolean b
    boolean c
    }

    changed to by adding String field and changing type of one field from boolean to int

    public class x
    {
    String A
    boolean b
    boolean c
    int d
    boolean u
    }

    How you going to predict name of field by type in such case?

    and dont suggest magic, i already reserved that method.
     
  13. Offline

    DPOH-VAR

    If the classes are so different, the reflection API is useless.
     
  14. Offline

    desht

    Which is kind of the point. You have exactly 0% certainty that the obfuscation won't change in the next major release so that grabbing a field by name or type won't get completely the wrong field. The worst case is that you get a field of the same type which does something completely unexpected, and ends up destroying someone's world (and before you laugh at that, it has already happened).
     
  15. Offline

    bensku

    Not all NMS method are obfuscated, but they will still break every Minecraft update if developer won't use reflection. And of course, the plugin should run more version checks than just getting variable with type...
     
Thread Status:
Not open for further replies.

Share This Page