[UTIL] HorseModifier - Spawn and modify horses!

Discussion in 'Resources' started by DarkBladee12, Jul 3, 2013.

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

    DarkBladee12

    HorseModifier v1.1:

    Hey there guys, it's me again, in a thread was asked how to change the type of a horse, so I decided to make a class which makes this possible. Besides that, there are also methods for the other specific values of a horse!

    Important: I haven't tested this class, because it's not possible atm to cast entities to horses...(EntityType of a horse entity is handled as "Unknown") Just tested all functions with the new spawn method and it works great ;)

    Usage:

    Code:java
    1. HorseModifier hm = new HorseModifier(HORSE);
    2. hm.setType(HorseType.NAME);
    3. hm.setVariant(HorseVariant.NAME);
    4. hm.setTamed(true/false);
    5. .....


    or

    Code:java
    1. HorseModifier hm = HorseModifier.spawn(LOCATION);
    2. hm.setType(HorseType.NAME);
    3. hm.setVariant(HorseVariant.NAME);
    4. hm.setTamed(true/false);
    5. .....



    HorseModifier class:

    Code:java
    1. import java.lang.reflect.Constructor;
    2. import java.lang.reflect.Method;
    3. import java.util.HashMap;
    4. import java.util.Map;
    5. import java.util.Map.Entry;
    6.  
    7. import org.bukkit.Bukkit;
    8. import org.bukkit.Location;
    9. import org.bukkit.World;
    10. import org.bukkit.entity.LivingEntity;
    11. import org.bukkit.entity.Player;
    12. import org.bukkit.inventory.ItemStack;
    13.  
    14. /**
    15. * HorseModifier v1.1
    16. *
    17. * You are free to use it, modify it and redistribute it under the condition to give credit to me
    18. *
    19. * @author DarkBlade12
    20. */
    21. public class HorseModifier {
    22. private Object entityHorse;
    23. private Object nbtTagCompound;
    24.  
    25. /**
    26.   * Creates a new instance of the HorseModifier, which allows you to change/get values of horses which aren't accessible with the bukkit api atm
    27.   */
    28. public HorseModifier(LivingEntity horse) {
    29. if (!HorseModifier.isHorse(horse)) {
    30. throw new IllegalArgumentException("Entity has to be a horse!");
    31. }
    32. try {
    33. this.entityHorse = ReflectionUtil.getMethod("getHandle", horse.getClass(), 0).invoke(horse);
    34. this.nbtTagCompound = NBTUtil.getNBTTagCompound(entityHorse);
    35. } catch (Exception e) {
    36. e.printStackTrace();
    37. }
    38. }
    39.  
    40. /**
    41.   * Creates a new instance of the HorseModifier; This constructor is only used for the static spawn method
    42.   */
    43. private HorseModifier(Object entityHorse) {
    44. this.entityHorse = entityHorse;
    45. try {
    46. this.nbtTagCompound = NBTUtil.getNBTTagCompound(entityHorse);
    47. } catch (Exception e) {
    48. e.printStackTrace();
    49. }
    50. }
    51.  
    52. /**
    53.   * Spawns a horse at a given location
    54.   */
    55. public static HorseModifier spawn(Location loc) {
    56. World w = loc.getWorld();
    57. try {
    58. Object worldServer = ReflectionUtil.getMethod("getHandle", w.getClass(), 0).invoke(w);
    59. Object entityHorse = ReflectionUtil.getClass("EntityHorse", worldServer);
    60. ReflectionUtil.getMethod("setPosition", entityHorse.getClass(), 3).invoke(entityHorse, loc.getX(), loc.getY(), loc.getZ());
    61. ReflectionUtil.getMethod("addEntity", worldServer.getClass(), 1).invoke(worldServer, entityHorse);
    62. return new HorseModifier(entityHorse);
    63. } catch (Exception e) {
    64. e.printStackTrace();
    65. return null;
    66. }
    67. }
    68.  
    69. /**
    70.   * Checks if an entity is a horse
    71.   */
    72. public static boolean isHorse(LivingEntity le) {
    73. try {
    74. Object entityLiving = ReflectionUtil.getMethod("getHandle", le.getClass(), 0).invoke(le);
    75. Object nbtTagCompound = NBTUtil.getNBTTagCompound(entityLiving);
    76. return NBTUtil.hasKeys(nbtTagCompound, new String[] { "EatingHaystack", "ChestedHorse", "HasReproduced", "Bred", "Type", "Variant", "Temper", "Tame" });
    77. } catch (Exception e) {
    78. e.printStackTrace();
    79. return false;
    80. }
    81. }
    82.  
    83. /**
    84.   * Changes the type of the horse
    85.   */
    86. public void setType(HorseType type) {
    87. setHorseValue("Type", type.getId());
    88. }
    89.  
    90. /**
    91.   * Changes whether the horse is chested or not (only for donkeys and mules)
    92.   */
    93. public void setChested(boolean chested) {
    94. setHorseValue("ChestedHorse", chested);
    95. }
    96.  
    97. /**
    98.   * Changes whether the horse is eating or not
    99.   */
    100. public void setEating(boolean eating) {
    101. setHorseValue("EatingHaystack", eating);
    102. }
    103.  
    104. /**
    105.   * Changes whether the horse was bred or not
    106.   */
    107. public void setBred(boolean bred) {
    108. setHorseValue("Bred", bred);
    109. }
    110.  
    111. /**
    112.   * Changes the color variant of the horse (only for normal horses)
    113.   */
    114. public void setVariant(HorseVariant variant) {
    115. setHorseValue("Variant", variant.getId());
    116. }
    117.  
    118. /**
    119.   * Changes the temper of the horse
    120.   */
    121. public void setTemper(int temper) {
    122. setHorseValue("Temper", temper);
    123. }
    124.  
    125. /**
    126.   * Changes whether the horse is tamed or not
    127.   */
    128. public void setTamed(boolean tamed) {
    129. setHorseValue("Tame", tamed);
    130. }
    131.  
    132. /**
    133.   * Changes whether the horse is saddled or not
    134.   */
    135. public void setSaddled(boolean saddled) {
    136. setHorseValue("Saddle", saddled);
    137. }
    138.  
    139. /**
    140.   * Sets the armor item of the horse (only for normal horses)
    141.   */
    142. public void setArmorItem(ItemStack i) {
    143. if (i != null) {
    144. try {
    145. Object itemTag = ReflectionUtil.getClass("NBTTagCompound", "ArmorItem");
    146. Object itemStack = ReflectionUtil.getMethod("asNMSCopy", Class.forName(Bukkit.getServer().getClass().getPackage().getName() + ".inventory.CraftItemStack"), 1).invoke(this, i);
    147. ReflectionUtil.getMethod("save", itemStack.getClass(), 1).invoke(itemStack, itemTag);
    148. setHorseValue("ArmorItem", itemTag);
    149. } catch (Exception e) {
    150. e.printStackTrace();
    151. }
    152. } else {
    153. setHorseValue("ArmorItem", null);
    154. }
    155. }
    156.  
    157. /**
    158.   * Returns the type of the horse
    159.   */
    160. public HorseType getType() {
    161. return HorseType.fromId((int) NBTUtil.getValue(nbtTagCompound, Integer.class, "Type"));
    162. }
    163.  
    164. /**
    165.   * Returns whether the horse is chested or not
    166.   */
    167. public boolean isChested() {
    168. return (boolean) NBTUtil.getValue(nbtTagCompound, Boolean.class, "ChestedHorse");
    169. }
    170.  
    171. /**
    172.   * Returns whether the horse is eating or not
    173.   */
    174. public boolean isEating() {
    175. return (boolean) NBTUtil.getValue(nbtTagCompound, Boolean.class, "EatingHaystack");
    176. }
    177.  
    178. /**
    179.   * Returns whether the horse was bred or not
    180.   */
    181. public boolean isBred() {
    182. return (boolean) NBTUtil.getValue(nbtTagCompound, Boolean.class, "Bred");
    183. }
    184.  
    185. /**
    186.   * Returns the variant of the horse
    187.   */
    188. public HorseVariant getVariant() {
    189. return HorseVariant.fromId((int) NBTUtil.getValue(nbtTagCompound, Integer.class, "Variant"));
    190. }
    191.  
    192. /**
    193.   * Returns the temper of the horse
    194.   */
    195. public int getTemper() {
    196. return (int) NBTUtil.getValue(nbtTagCompound, Integer.class, "Temper");
    197. }
    198.  
    199. /**
    200.   * Returns whether the horse is tamed or not
    201.   */
    202. public boolean isTamed() {
    203. return (boolean) NBTUtil.getValue(nbtTagCompound, Boolean.class, "Tame");
    204. }
    205.  
    206. /**
    207.   * Returns whether the horse is saddled or not
    208.   */
    209. public boolean isSaddled() {
    210. return (boolean) NBTUtil.getValue(nbtTagCompound, Boolean.class, "Saddle");
    211. }
    212.  
    213. /**
    214.   * Returns the armor item of the horse
    215.   */
    216. public ItemStack getArmorItem() {
    217. try {
    218. Object itemTag = NBTUtil.getValue(nbtTagCompound, nbtTagCompound.getClass(), "ArmorItem");
    219. Object itemStack = ReflectionUtil.getMethod("createStack", Class.forName(ReflectionUtil.getPackageName() + ".ItemStack"), 1).invoke(this, itemTag);
    220. return (ItemStack) ReflectionUtil.getMethod("asCraftMirror", Class.forName(Bukkit.getServer().getClass().getPackage().getName() + ".inventory.CraftItemStack"), 1).invoke(this, itemStack);
    221. } catch (Exception e) {
    222. e.printStackTrace();
    223. return null;
    224. }
    225. }
    226.  
    227. /**
    228.   * Opens the inventory of the horse for a player (only for tamed horses)
    229.   */
    230. public void openInventory(Player p) {
    231. try {
    232. Object entityPlayer = ReflectionUtil.getMethod("getHandle", p.getClass(), 0).invoke(p);
    233. ReflectionUtil.getMethod("f", entityHorse.getClass(), 1).invoke(entityHorse, entityPlayer);
    234. } catch (Exception e) {
    235. e.printStackTrace();
    236. }
    237. }
    238.  
    239. /**
    240.   * Returns the horse entity
    241.   */
    242. public LivingEntity getHorse() {
    243. try {
    244. return (LivingEntity) ReflectionUtil.getMethod("getBukkitEntity", entityHorse.getClass(), 0).invoke(entityHorse);
    245. } catch (Exception e) {
    246. e.printStackTrace();
    247. return null;
    248. }
    249. }
    250.  
    251. /**
    252.   * Changes a value in the NBTTagCompound and updates it to the horse
    253.   */
    254. private void setHorseValue(String key, Object value) {
    255. NBTUtil.setValue(nbtTagCompound, key, value);
    256. NBTUtil.updateNBTTagCompound(entityHorse, nbtTagCompound);
    257. }
    258.  
    259. public enum HorseType {
    260.  
    261. NORMAL("normal", 0), DONKEY("donkey", 1), MULE("mule", 2), UNDEAD("undead", 3), SKELETAL("skeletal", 4);
    262.  
    263. private String name;
    264. private int id;
    265.  
    266. HorseType(String name, int id) {
    267. this.name = name;
    268. this.id = id;
    269. }
    270.  
    271. public String getName() {
    272. return name;
    273. }
    274.  
    275. public int getId() {
    276. return id;
    277. }
    278.  
    279. private static final Map<String, HorseType> NAME_MAP = new HashMap<String, HorseType>();
    280. private static final Map<Integer, HorseType> ID_MAP = new HashMap<Integer, HorseType>();
    281. static {
    282. for (HorseType effect : values()) {
    283. NAME_MAP.put(effect.name, effect);
    284. ID_MAP.put(effect.id, effect);
    285. }
    286. }
    287.  
    288. public static HorseType fromName(String name) {
    289. if (name == null) {
    290. return null;
    291. }
    292. for (Entry<String, HorseType> e : NAME_MAP.entrySet()) {
    293. if (e.getKey().equalsIgnoreCase(name)) {
    294. return e.getValue();
    295. }
    296. }
    297. return null;
    298. }
    299.  
    300. public static HorseType fromId(int id) {
    301. return ID_MAP.get(id);
    302. }
    303. }
    304.  
    305. public enum HorseVariant {
    306. WHITE("white", 0), CREAMY("creamy", 1), CHESTNUT("chestnut", 2), BROWN("brown", 3), BLACK("black", 4), GRAY("gray", 5), DARK_BROWN("dark brown", 6), INVISIBLE("invisible", 7), WHITE_WHITE(
    307. "white-white", 256), CREAMY_WHITE("creamy-white", 257), CHESTNUT_WHITE("chestnut-white", 258), BROWN_WHITE("brown-white", 259), BLACK_WHITE("black-white", 260), GRAY_WHITE("gray-white", 261), DARK_BROWN_WHITE(
    308. "dark brown-white", 262), WHITE_WHITE_FIELD("white-white field", 512), CREAMY_WHITE_FIELD("creamy-white field", 513), CHESTNUT_WHITE_FIELD("chestnut-white field", 514), BROWN_WHITE_FIELD(
    309. "brown-white field", 515), BLACK_WHITE_FIELD("black-white field", 516), GRAY_WHITE_FIELD("gray-white field", 517), DARK_BROWN_WHITE_FIELD("dark brown-white field", 518), WHITE_WHITE_DOTS(
    310. "white-white dots", 768), CREAMY_WHITE_DOTS("creamy-white dots", 769), CHESTNUT_WHITE_DOTS("chestnut-white dots", 770), BROWN_WHITE_DOTS("brown-white dots", 771), BLACK_WHITE_DOTS(
    311. "black-white dots", 772), GRAY_WHITE_DOTS("gray-white dots", 773), DARK_BROWN_WHITE_DOTS("dark brown-white dots", 774), WHITE_BLACK_DOTS("white-black dots", 1024), CREAMY_BLACK_DOTS(
    312. "creamy-black dots", 1025), CHESTNUT_BLACK_DOTS("chestnut-black dots", 1026), BROWN_BLACK_DOTS("brown-black dots", 1027), BLACK_BLACK_DOTS("black-black dots", 1028), GRAY_BLACK_DOTS(
    313. "gray-black dots", 1029), DARK_BROWN_BLACK_DOTS("dark brown-black dots", 1030);
    314.  
    315. private String name;
    316. private int id;
    317.  
    318. HorseVariant(String name, int id) {
    319. this.name = name;
    320. this.id = id;
    321. }
    322.  
    323. public String getName() {
    324. return name;
    325. }
    326.  
    327. public int getId() {
    328. return id;
    329. }
    330.  
    331. private static final Map<String, HorseVariant> NAME_MAP = new HashMap<String, HorseVariant>();
    332. private static final Map<Integer, HorseVariant> ID_MAP = new HashMap<Integer, HorseVariant>();
    333. static {
    334. for (HorseVariant effect : values()) {
    335. NAME_MAP.put(effect.name, effect);
    336. ID_MAP.put(effect.id, effect);
    337. }
    338. }
    339.  
    340. public static HorseVariant fromName(String name) {
    341. if (name == null) {
    342. return null;
    343. }
    344. for (Entry<String, HorseVariant> e : NAME_MAP.entrySet()) {
    345. if (e.getKey().equalsIgnoreCase(name)) {
    346. return e.getValue();
    347. }
    348. }
    349. return null;
    350. }
    351.  
    352. public static HorseVariant fromId(int id) {
    353. return ID_MAP.get(id);
    354. }
    355. }
    356.  
    357. private static class NBTUtil {
    358. public static Object getNBTTagCompound(Object entity) {
    359. try {
    360. Object nbtTagCompound = ReflectionUtil.getClass("NBTTagCompound");
    361. for (Method m : entity.getClass().getMethods()) {
    362. Class<?>[] pt = m.getParameterTypes();
    363. if (m.getName().equals("b") && pt.length == 1 && pt[0].getName().contains("NBTTagCompound")) {
    364. m.invoke(entity, nbtTagCompound);
    365. }
    366. }
    367. return nbtTagCompound;
    368. } catch (Exception e) {
    369. e.printStackTrace();
    370. return null;
    371. }
    372. }
    373.  
    374. public static void updateNBTTagCompound(Object entity, Object nbtTagCompound) {
    375. try {
    376. for (Method m : entity.getClass().getMethods()) {
    377. Class<?>[] pt = m.getParameterTypes();
    378. if (m.getName().equals("a") && pt.length == 1 && pt[0].getName().contains("NBTTagCompound")) {
    379. m.invoke(entity, nbtTagCompound);
    380. }
    381. }
    382. } catch (Exception e) {
    383. e.printStackTrace();
    384. }
    385. }
    386.  
    387. public static void setValue(Object nbtTagCompound, String key, Object value) {
    388. try {
    389. if (value instanceof Integer) {
    390. ReflectionUtil.getMethod("setInt", nbtTagCompound.getClass(), 2).invoke(nbtTagCompound, key, (Integer) value);
    391. return;
    392. } else if (value instanceof Boolean) {
    393. ReflectionUtil.getMethod("setBoolean", nbtTagCompound.getClass(), 2).invoke(nbtTagCompound, key, (Boolean) value);
    394. return;
    395. } else {
    396. ReflectionUtil.getMethod("set", nbtTagCompound.getClass(), 2).invoke(nbtTagCompound, key, value);
    397. }
    398. } catch (Exception e) {
    399. e.printStackTrace();
    400. }
    401. }
    402.  
    403. public static Object getValue(Object nbtTagCompound, Class<?> c, String key) {
    404. try {
    405. if (c == Integer.class) {
    406. return ReflectionUtil.getMethod("getInt", nbtTagCompound.getClass(), 1).invoke(nbtTagCompound, key);
    407. } else if (c == Boolean.class) {
    408. return ReflectionUtil.getMethod("getBoolean", nbtTagCompound.getClass(), 1).invoke(nbtTagCompound, key);
    409. } else {
    410. return ReflectionUtil.getMethod("getCompound", nbtTagCompound.getClass(), 1).invoke(nbtTagCompound, key);
    411. }
    412. } catch (Exception e) {
    413. e.printStackTrace();
    414. return null;
    415. }
    416. }
    417.  
    418. public static boolean hasKey(Object nbtTagCompound, String key) {
    419. try {
    420. return (boolean) ReflectionUtil.getMethod("hasKey", nbtTagCompound.getClass(), 1).invoke(nbtTagCompound, key);
    421. } catch (Exception e) {
    422. e.printStackTrace();
    423. return false;
    424. }
    425. }
    426.  
    427. public static boolean hasKeys(Object nbtTagCompound, String[] keys) {
    428. for (String key : keys) {
    429. if (!hasKey(nbtTagCompound, key)) {
    430. return false;
    431. }
    432. }
    433. return true;
    434. }
    435. }
    436.  
    437. private static class ReflectionUtil {
    438. public static Object getClass(String name, Object... args) throws Exception {
    439. Class<?> c = Class.forName(ReflectionUtil.getPackageName() + "." + name);
    440. int params = 0;
    441. if (args != null) {
    442. params = args.length;
    443. }
    444. for (Constructor<?> co : c.getConstructors()) {
    445. if (co.getParameterTypes().length == params) {
    446. return co.newInstance(args);
    447. }
    448. }
    449. return null;
    450. }
    451.  
    452. public static Method getMethod(String name, Class<?> c, int params) {
    453. for (Method m : c.getMethods()) {
    454. if (m.getName().equals(name) && m.getParameterTypes().length == params) {
    455. return m;
    456. }
    457. }
    458. return null;
    459. }
    460.  
    461. public static String getPackageName() {
    462. return "net.minecraft.server." + Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
    463. }
    464. }
    465. }
     
  2. Offline

    TheGamersCave

    Thanks for this!
    I wonder why they don't have a native API for the Horses... hmm.
     
  3. Offline

    AstramG

    This is pretty cool, it should help us until the api gets implemented! Thanks!
    Edit:
    How can I use this to spawn a zombie horse?
     
  4. Offline

    Garris0n

    They released the dev build like the day after 1.6 came out, they need time for an API.
     
  5. Offline

    TheGamersCave


    True, true. I'm in no rush, I appreciate all the work they do already :)
     
  6. Offline

    DarkBladee12

    AstramG That's how you do it:

    Code:java
    1. HorseModifier.spawn(LOCATION).setType(HorseType.UNDEAD);
     
  7. Offline

    Omerrg

    Thank you very much. You're blessed ;)
     
  8. Offline

    Prang123

    How do I use the Horse h = ....; part? Confused.
     
  9. Offline

    DarkBladee12

    Prang123 Well there should be the part how you get it, either spawn it or cast from an entity. But there's a bug which prevents you from spawning/casting horses, maybe I'll add a method which allows you to spawn a horse via NMS through reflection ;)
     
  10. Offline

    Omerrg

    Hey DarkBladee12 , there's a way to get the horse's inventory?
     
  11. Offline

    DarkBladee12

    Omerrg Not yet, but thanks for the suggestion, I'm trying to add this ;)
     
  12. Offline

    Ba7marker

    Thanks alot for this, finaly we can spawn all the horses. Do you mind if i make a simple spawn horse plugin? i'l make sure to give full credit to you
     
  13. Offline

    DarkBladee12

    imjack16 Nope, it won't mind that ;) You're welcome to use it as long as you give credit to me.
     
    foodyling likes this.
  14. Offline

    kreashenz

    After completely reading it, it looks very, sexily helpful, and it might be very nice to have in a plugin. I am going to use this to stuff around with the obfuscated methods that EntityHorse holds :p Thanks!
     
  15. Offline

    Rockon999

  16. Offline

    DarkBladee12

    Rockon999 That's nice, I hope they'll implement your changes ;)
     
  17. Offline

    daylight95

    Ok so how do I use this?
     
  18. Offline

    DarkBladee12

    daylight95 Just read the first post, the usage is described there! You'll also have to make a new class named "HorseModifier" and copy the code from the first post in order to use it.
     
  19. Offline

    Ba7marker

    Anyway to set the horses health since it sets it currently at max?
     
  20. Offline

    DarkBladee12

    imjack16 You could try this, but I'm not sure if it works:

    Code:java
    1. MODIFIER.getHorse().setMaxHealth(AMOUNT);
     
  21. Offline

    kreashenz

    Yo, I was getting errors while using
    Code:java
    1. return (boolean) NBTTag.compound...

    But I changed it to
    Code:java
    1. return (Boolean) NBTTag.compound...

    And it worked..

    Is this a Java error, or just my stupid IDE? I'm not sure, but the primitive types didn't work, so I changed them to Boolean or Integer. Hope you can fix this, or explain why.
     
  22. Offline

    DarkBladee12

    kreashenz Could you tell me which method threw that error?
     
  23. Offline

    kreashenz

    DarkBladee12 All the boolean ones, and all the int ones. I've edited them all, gimme a moment.

    Images (open)
    [​IMG]

    [​IMG]
     
  24. Offline

    DarkBladee12

    kreashenz Well I think it's just your IDE, it doesn't show me that errors when I'm looking at the class in eclipse... But the way you solved it shouldn't change anything on the functionality ;)
     
  25. Offline

    kreashenz

  26. Offline

    VoidWhisperer

    I ended up making this with it.... (Fiery smoking skeleton horse of evil >:D)
    [​IMG]
     
  27. Offline

    DarkBladee12

  28. Offline

    MistPhizzle

    Didn't see it, but is there any way to check who is the owner of a tamed horse?
     
  29. Offline

    ShadowDog007

    MistPhizzle
    No, horses don't have owners.
    You need to store that data yourself.
     
  30. Offline

    user_43347

    What are the possible temper values?
     
Thread Status:
Not open for further replies.

Share This Page