Different meta for different projectiles [NEED HELP!!!!]

Discussion in 'Plugin Development' started by Dubehh, Mar 17, 2014.

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

    Dubehh

    Hey!

    I have added a custom crafting recipe in my server, which is an Elemental bow.
    What I want:
    When the player has a ''Elemental Arrow'' (also craftable) he is able to shoot with the elemental Bow.
    I don't mind for the effects at this point, I just don't know how to check when the hitted player got hit with a NORMAL arrow or a ELEMENTAL arrow.

    And I also need to remove one arrow everytime a elemental arrow has been fired.

    Normal bows should be able to shoot elemental arrows, and the other way around, but I only want the special effect once the ELEMENTAL bow shoots the ELEMENTAL arrow. (so now normal bow with elemental arrow etc.)

    I hope you can follow me here!
    I created a different class for this:
    Code:java
    1. package me.dubehh.CoreDefense;
    2.  
    3. import org.bukkit.ChatColor;
    4. import org.bukkit.entity.Arrow;
    5. import org.bukkit.entity.Entity;
    6. import org.bukkit.entity.Player;
    7. import org.bukkit.event.EventHandler;
    8. import org.bukkit.event.Listener;
    9. import org.bukkit.event.entity.ProjectileHitEvent;
    10.  
    11. public class CraftListener implements Listener {
    12.  
    13. CoreDefense main;
    14.  
    15. public CraftListener(CoreDefense main) {
    16. this.main = main;
    17. }
    18.  
    19. @EventHandler
    20. public void onElemental(ProjectileHitEvent e) {
    21. Entity entity = e.getEntity();
    22. if(entity instanceof Arrow){
    23. Arrow arrow = (Arrow) entity;
    24. Entity shooter = arrow.getShooter();
    25. if(shooter instanceof Player) {
    26. Player player = (Player) shooter;
    27. if(player.getItemInHand().getItemMeta().equals(ChatColor.AQUA + "Elemental Bow")){
    28. arrow.setFireTicks(1000);
    29. }
    30.  
    31. }
    32. }
    33. }
    34.  
    35. }
    36.  
     
  2. Offline

    Dubehh

    dat Bump
     
  3. Offline

    AtomSponge

    You can't compare ItemMeta with a String. Use
    Code:java
    1. player.getItemInHand().getItemMeta().getDisplayName().equals(...)
     
  4. Offline

    xEpicTaco

    Personally, I would add the projectile to an ArrayList and use EntityDamageByEntityEvent to catch it. In the event, check if the Damager is instanceof Arrow and if it is, check if it in the ArrayList. To add it to the ArrayList, check the Arrow's data (and Item data) with ProjectileLaunchEvent.
     
  5. Offline

    Dubehh

    xEpicTaco

    Could u format this into a code? (a example one, not spoonfed ;P)
     
  6. Offline

    xEpicTaco

    Code:java
    1.  
    2. private ArrayList<Projectile> projectiles = new ArrayList<Projectiles>();
    3. @EventHandler
    4. public void onProjectileLaunch(ProjectileLaunchEvent ev)
    5. {
    6. if(ev.getShooter() instanceof Player)
    7. {
    8. //Check if elemental
    9. projectiles.add(ev.getProjectile());
    10. }
    11. }
    12.  
    13. @EventHandler
    14. public void onEntityHit(EntityDamageByEntityEvent ev)
    15. {
    16. if(ev.getDamager() instanceof Projectile)
    17. {
    18. Projectile p = (Projectile) ev.getDamager();
    19. if(projectiles.contains(p))
    20. {
    21. //Do Stuff
    22. }
    23. }
    24. }
     
  7. Offline

    Dubehh

    xEpicTaco
    Hey man!,
    Thanks for the reply,
    but do you know how I can keep normal arrows and 'Elemental' arrows apart?
    Since I only want the special effect when a elemental arrow is fired
     
  8. Offline

    rfsantos1996

    Put the hitted player/entity on fire instead of the arrow lol

    @EDIT: I thought you said something else, sorry...

    Well, checking the name is right like you did, just merge your code into the xEpicTaco code...
     
  9. Offline

    Loogeh

    I do arrows this way
    Code:
    arrow.setMetadata("arrow_type", new FixedMetadataValue(your_main_file, Boolean.valueOf(true)));
    Just set that on EntityShootBowEvent and check for it in EntityDamageByEntityEvent with
    Code:
    if(arrow.hasMetadata("arrow_type")) {
     
  10. Offline

    xEpicTaco

    That's for entities. He's asking how to tell if it's launching arrows that are elemental (if the ItemStack has elemental properties on it). This I do not know. Anyone have any ideas?
     
  11. Offline

    Loogeh

    xEpicTaco They were essentially doing what I did except they used they're own ArrayList. Adding MetaData makes it a whole lot easier. Also, arrows are entities.
     
  12. Offline

    xEpicTaco

    He's trying to keep track of if the ItemStack is elemental, then check if when they launched the arrow, if the one they launched was tagged as elemental. I also find it much easier to use a HashMap.
     
  13. Offline

    Loogeh

    xEpicTaco Ahh, I understand now. Also, yeah, HashMap's would be better for multiple types of arrows. Would take less memory than multiple lists anyway (i think), however, that is not likely a concern needed here Dubehh
     
  14. Offline

    Dubehh

    Loogeh xEpicTaco

    I didn't try it yet due school work,
    but I'll try it tonight and kee you updated.
    This is probably for one 'special arrow'. But it would be good to know how I could add more,
    so both, thanks for the replies. And ill share my result
    Thanks!
     
  15. Offline

    GameplayJDK

    Dubehh
    Code:java
    1. public ItemStack assignData(ItemStack i, String key, String value) {
    2. net.minecraft.server.v1_7_R1.ItemStack nms = CraftItemStack.asNMSCopy(i);
    3. NBTTagCompound tag = null;
    4. if (nms.tag != null) {
    5. tag = nms.tag;
    6. } else {
    7. nms.tag = new NBTTagCompound();
    8. nms.tag = tag;
    9. }
    10. tag.setString(key, value);
    11. ItemStack ni = CraftItemStack.asCraftMirror(nms);
    12. return ni;
    13. }
    14.  
    15. public Object readData(ItemStack i, String key) {
    16. net.minecraft.server.v1_7_R1.ItemStack nms = CraftItemStack.asNMSCopy(i);
    17. NBTTagCompound tag = null;
    18. if (nms.tag != null) {
    19. tag = nms.tag;
    20. } else {
    21. nms.tag = new NBTTagCompound();
    22. nms.tag = tag;
    23. }
    24. return tag.get(key);
    25. }

    This uses NMS classes, but if you find a simpler solution, that would be better.
    That code would store data, even if the server restarts.
    (It works with 1.7.2R0.3)
     
  16. Offline

    Dubehh

    GameplayJDK Loogeh xEpicTaco

    Hey,
    I somehow can't bind my custom ItemMeta for the 'Elemental Arrow' to a specific MetaData.
    I am stuck.
    Code:java
    1.  
    2. public class CraftListener implements Listener {
    3. private ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
    4.  
    5. CoreDefense main;
    6.  
    7. public CraftListener(CoreDefense main) {
    8. this.main = main;
    9. }
    10.  
    11. @EventHandler
    12. public void onProjectileLaunch(ProjectileLaunchEvent e) {
    13. Entity entity = e.getEntity();
    14. if (entity instanceof Arrow) {
    15. ItemStack element = new ItemStack(Material.ARROW);
    16. ItemMeta elementm = element.getItemMeta();
    17. elementm.setDisplayName(ChatColor.AQUA + "Elemental Arrow");
    18. element.setItemMeta(elementm);
    19. Arrow arrow = (Arrow) entity;
    20. arrow.setMetadata("elemental", new FixedMetadataValue(main, Boolean.valueOf(true))); // wut
    21. Entity shooter = arrow.getShooter();
    22. if (shooter instanceof Player) {
    23. Player player = (Player) shooter;
    24. if (player.getItemInHand().getItemMeta().getDisplayName()
    25. .equals(ChatColor.AQUA + "Elemental Bow")
    26. && player.getItemInHand().getItemMeta().getDisplayName() != null) {
    27. projectiles.add(arrow);
    28. } else {
    29. return;
    30. }
    31.  
    32. }
    33. }
    34. }
    35.  
    36. @EventHandler
    37. public void onEntityHit(EntityDamageByEntityEvent e) {
    38. if (e.getDamager() instanceof Projectile) {
    39. Projectile p = (Projectile) e.getDamager();
    40. if (projectiles.contains(p)) {
    41. Player player = (Player) e.getEntity();
    42. player.sendMessage(ChatColor.AQUA
    43. + "You got hit by a elemental bow!");
    44.  
    45. }else{
    46. return;
    47. }
    48.  
    49. }
    50. }
    51.  
    52. }
    53.  
     
  17. Offline

    GameplayJDK

    Dubehh
    Look fine to me, what exactly does not work? Assigning the name or something else?
     
  18. Offline

    Noxyro

    I use a very simple solution for "custom" objects which i want to be seperated from "normal" objects.
    Just apply a custom enchantment on the ItemStack - this way you also add a simple value storage for levels and such things via level of the enchantment.

    For the shooting part i would have also suggested a HashMap for tracking with the Arrow Entity as key and your custom data as values.

    Custom enchantment:

    1) Create an own class that extends the Bukkit EnchantmentWrapper like this:
    Code:java
    1. public class CustomEnchantment extends EnchantmentWrapper {
    2. private int maxLevel, startLevel;
    3. private String name;
    4.  
    5. public CustomEnchantment(int id, int maxLevel, int startLevel, String name) {
    6. super(id);
    7. this.maxLevel = maxLevel;
    8. this.startLevel = startLevel;
    9. this.name = name;
    10. }
    11.  
    12. @Override
    13. public int getMaxLevel() {
    14. return maxLevel;
    15. }
    16.  
    17. @Override
    18. public int getStartLevel() {
    19. return startLevel;
    20. }
    21.  
    22. @Override
    23. public String getName() {
    24. return name;
    25. }
    26.  
    27. @Override
    28. public boolean canEnchantItem(ItemStack item) {
    29. return true;
    30. }
    31.  
    32. @Override
    33. public boolean conflictsWith(Enchantment other) {
    34. return false;
    35. }
    36. }


    2) Don't forget to register your custom enchantments and store them in a public static variable for later access:
    (I've created an extra class for that ... some sort of manager)
    Code:java
    1. public class Enchantments {
    2. public static final CustomEnchantment GCUSTOM = new CustomEnchantment(100,5, 1, "Custom");
    3. // ... and more
    4.  
    5. private static final List<CustomEnchantment> enchantments = new ArrayList<CustomEnchantment>();
    6.  
    7. public static void init() {
    8. try {
    9. Field f = Enchantment.class.getDeclaredField("acceptingNew");
    10. f.setAccessible(true);
    11. f.set(null, true);
    12. } catch (Exception e) {
    13. e.printStackTrace();
    14. }
    15.  
    16. registerEnchantments();
    17.  
    18. for (CustomEnchantment ench : enchantments) {
    19. if (Enchantment.getByName(ench.getName()) == null) {
    20. Enchantment.registerEnchantment(ench);
    21. }
    22. }
    23. }
    24.  
    25. public static void registerEnchantments() {
    26. enchantments.add(CUSTOM);
    27. // ... and more
    28. }
    29. }



    HashMap tracking:

    1) Create the HashMap:
    (I would recommend using a new class again for HashMap and Arrow handling)
    Code:java
    1. public class ElementalArrows {
    2. private static Map<Entity, CustomData> arrowMap = new HashMap<Entity, CustomData>();
    3. // CustomData could be anything ... just create a new class CustomData with all needed variables within
    4.  
    5. public static Map<Entity, CustomData> getArrowMap() {
    6. return this.arrowMap;
    7. }
    8.  
    9. public static void setArrowMap(Map<Entity, CustomData> arrowMap) {
    10. this.arrowMap = arrowMap;
    11. }
    12. }


    2) Let your events create the entries in the HashMap:
    (best you hand them over to your new manager class for better structure)
    Code:java
    1. // Create a listener of course
    2. public class EntityListener implements Listener {
    3.  
    4. @EventHandler
    5. public void onEntityShootBow(EntityShootBowEvent e) {
    6. ElementalArrows.onEntityShootBow(e);
    7. }
    8. }
    9.  
    10. // This goes to your class with the HashMap
    11.  
    12. public static void onEntityShootBow(EntityShootBowEvent e) {
    13. if (e.getEntity() instanceof Player) {
    14. Player player = (Player) e.getEntity();
    15. CustomData customData = new CustomData(); // Create your custom data here with whatever you need
    16.  
    17. arrowMap.put(e.getProjectile(), customData);
    18. }
    19. }
    20.  
    21.  



    3) Let your events check for arrows within the HashMap:
    Code:java
    1. // This goes to your listener
    2. @EventHandler
    3. public void onEntityDamageByEntity(EntityDamageByEntityEvent e) {
    4. ElementalArrows.onEntityDamageByEntity(e);
    5. }
    6.  
    7.  
    8. // This goes to your class with the HashMap
    9.  
    10. public static void onEntityDamageByEntity(EntityDamageByEntityEvent e) {
    11. if (e.getDamager() instanceof Projectile) {
    12. Projectile projectile = (Projectile) e.getDamager();
    13. if (arrowMap.containsKey(projectile)) {
    14. CustomData customData = arrowMap.get(projectile);
    15. // do stuff
    16. }
    17. }
    18. }
     
  19. Offline

    Dubehh

    Noxyro
    'Cannot use 'this' in a static context'

    Noxyro
    And to be honest,
    I don't understand what I am doing here, I don't want to copy/paste :c.
    I have created 4 different classes and my brains hurt..
    Do you know a tutorial for this?

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

    Noxyro

    I did not actually tested the code - so yeah this.arrowMap = arrowMap should be ElementalArrows.arrowMap = arrowMap ... I'm dumb sorry ^^


    There is no tutorial on this specific topic i guess, but when you never used different classes in your projects before, you should really go through some basic Java tutorials that deal with project structures and classes with their different functions.

    Grettings - Noxyro

    PS: If demanded I could create a detailed tutorial on how to setup and use custom enchantments?
     
  21. Offline

    Dubehh

    Noxyro

    I would like it :)

    @Noxyro
    Hey, Thanks for your reply, I won't use it because I need to learn java alot better first.
    But your help shall be remembered :). Sorry if I wasted your time, but I didn't know it would be that hard (for me).

    But for the earlier code I posted:
    Code:java
    1. @EventHandler
    2. public void onProjectileLaunch(ProjectileLaunchEvent e) {
    3. Entity entity = e.getEntity();
    4. if (entity instanceof Arrow) {
    5. ItemStack element = new ItemStack(Material.ARROW);
    6. ItemMeta elementm = element.getItemMeta();
    7. elementm.setDisplayName(ChatColor.AQUA + "Elemental Arrow");
    8. element.setItemMeta(elementm);
    9. Arrow arrow = (Arrow) entity;
    10. Entity shooter = arrow.getShooter();
    11. if (shooter instanceof Player) {
    12. Player player = (Player) shooter;
    13. if (player.getItemInHand().getItemMeta().getDisplayName()
    14. .equals(ChatColor.AQUA + "Elemental Bow")
    15. && player.getItemInHand().getItemMeta().getDisplayName() != null) {
    16. projectiles.add(arrow);
    17. } else {
    18. return;
    19. }
    20.  
    21. }
    22. }
    23. }


    I got a NullPointerException on line 40.

    Which is:
    Code:java
    1. if (player.getItemInHand().getItemMeta().getDisplayName()
    2. .equals(ChatColor.AQUA + "Elemental Bow")
    3. && player.getItemInHand().getItemMeta().getDisplayName() != null) {


    Any idea?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 7, 2016
Thread Status:
Not open for further replies.

Share This Page