Oops, I didn't break your plugins - ambiguous getHealth()

Discussion in 'Plugin Development' started by EvilSeph, Jul 1, 2013.

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

    EvilSeph Retired Staff

    With the release of Minecraft 1.6(.1), Mojang has made a big change to the way entity health is handled and stored. Prior to Minecraft 1.6.x, Minecraft used integers for health values which many plugins have grown to rely on. From Minecraft 1.6.x onward, Mojang have switched health over to using floats instead, leaving us in a tough position: we would have to break all plugins expecting integer health.

    Fortunately, as the name of this thread suggests, we put in many hours trying to figure out a way to avoid just flat out breaking plugins and managed to come up with a solution we think everyone will be really happy with. Through the use of a cool new Maven plugin Wolvereness developed, we are now able to provide a backwards-compatibility layer for this change for plugins. This means that plugins that rely on health being integers will still work until we remove the temporary compatibility mechanism.

    As a result, all plugins will still function, giving you time to work on a solid update to your plugin instead of having to rush a fix out to your users. We will eventually remove the compatibility layer so you'll still want to update your plugins to use the new double methods as soon as you can.

    What's going on?
    Minecraft 1.6.x uses floats for health instead of integers, which means all plugins expecting integer health need to be updated. Luckily, we've managed to come up with a way to support both old (integer) and new (double) health formats until plugin developers are able to update their plugins accordingly.

    Wait, why doubles and not floats?
    We've decided to go with double health to provide us with future-proofing against the possibility of a similar change from taking place in the future (from floats to doubles).

    Although our handling of this problem meant extra work on our part and added complexity within the project's compile process, we still believe that this is the best solution for everyone and are confident you'll feel the same way. We hope that the extra effort we've put into this update makes dealing with Minecraft 1.6.1 easier for you guys, removing the stress of needing to immediately update your plugin to support the change to health.
     
  2. Offline

    mbaxter ʇıʞʞnq ɐ sɐɥ ı Retired Staff

    The method now takes a double :)
     
  3. Offline

    FireBreath14

    I found a way to fix this. I was just coding and I came across a 2-line fix for this.

    Code:
    Damageable damag = player;
    if(damag.getHealth() >= 3){
      //code here
    }
    Not sure exactly what its doing on the technical side but it works for my plugins. I pulled this code from my pvp minigame Backbone
     
    Rainy37 likes this.
  4. Offline

    XKnucklesX

    I use craftbukkit as a dependency since when I use bukkit.jar most of my plugins break down.
     
  5. Offline

    LegendaryViper

    So does it add health to the player or set it? I kind of don't understand how that could work, since Im not a much of a pro coder. Also, this is would part of my code was oringally before the 1.6 update
    Code:
        public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String []args){
            Player player = (Player) sender;
            if(commandLabel.equalsIgnoreCase("heal")){
                if(args.length == 0){
                    //heal = 0 args / heal QueenViper21 = 1 args
                    player.setHealth(20);
                    player.setFireTicks(0);
                }else if(args.length == 1){
                    if(player.getServer().getPlayer(args[0]) != null){
                    Player targetPlayer = player.getServer().getPlayer(args [0]);
                    targetPlayer.setHealth(20);
                    targetPlayer.setFireTicks(0);
     
  6. Offline

    Janmm14

    LegendaryViper
    Code:java
    1. //use
    2. player.setHealth(20d);
    3. //or
    4. player.setHealth(20.0);
    5. //to heal a player fully, you should do this:
    6. player.setHealth(player.getMaxHealth());
     
  7. Offline

    LegendaryViper

    Thanks! Just what I needed.
     
  8. Offline

    Zelnehlun

    Good evening,

    I really, really like the change to doubles (I like doubles :)). Can someone maybe help me with the setScaleHealth() command?
    I set my max health to 100 or 1000 and of course many hearts appear, but it works. Now I want to increase max health but only display 1 bar of hearts. Thought using setScaleHealth() will solve the problem and yes it does! It uses the first row of hearts the others are greyed out which I find horrible.

    Is there a way to setMaxHealth and only display 1 row of hearts?

    (Currently I have a work-around where my plugin stores and handles the health of the player and scales the health bar accordingly)

    Thanks in advance.
     
  9. Offline

    fireblast709

    Why does Java not handle this like in C(++), where an int is just casted to a float D:
     
  10. Offline

    Zelnehlun


    It does, you can cast int to float, smaller types always fit into bigger types. ;)
     
  11. Offline

    Wolvereness Bukkit Team Member

    That's syntactic (source-level), not post-compile. We solved an issue involving plugins that were already compiled.
     
  12. Offline

    desht

    The only source modification needed is for cases like this:
    PHP:
    int health player.getHealth();
    since double can't be implicitly converted to int (that involves loss of information).
     
    Zelnehlun likes this.
  13. Offline

    matejdro

    After some quick tests this works for me:
    (Of course you set different setMaxHealth value)

    Code:
    		event.getPlayer().setMaxHealth(100);
    		event.getPlayer().setHealthScale(20);
    		event.getPlayer().setHealthScaled(true);
    
    Apparently, setHealthScale sets amount of health actually displayed (so setting it to 2 will display only 1 hearth).

    And yeah doubles change is great. Previously you couldn't do small damage easily. Like you could do 0 damage or 1 damage which is already 5% of player's health. Of course you could fiddle with maximum health but that was complicated.
     
    TheGreenGamerHD and Zelnehlun like this.
  14. Offline

    Zelnehlun

    Thank you very much matejdro =)
     
  15. Offline

    The_Doctor_123

    How stupid, integers worked just fine. And if they were going to change that, they should've done a LONG time ago, like in Beta.
     
  16. Offline

    kreashenz

    I don't see what's so bad about add 'D' on the end of your number. Even casting (double) doesn't annoy me at all.
     
  17. Offline

    The_Doctor_123

    It's not really that I have a problem adding a ".0", it's that now the health is a really long and complex number. Have you ever tried printing out damage dealt to other mobs or the player's health? It's insane!
     
  18. Offline

    toothplck1 Retired Staff

    Just round it? or cast it back to int for display?
     
  19. Offline

    bobacadodl


    Just do something like: System.out.println((int) p.getHealth());
     
  20. Offline

    Ultimate_n00b

    Code:java
    1. Math.ceil(p.getHealth());
    ?
     
  21. Offline

    exiHD2k

    How can I ask the Health of the player?

    double heath = player.getHealth();

    don't work.
    After that I like to damage the player but the damage command don't work too.
    The only command who works is the

    player.setHealth(2.0);

    So the player has always 2 Hearts but I like to damage him everytime 2 Hearts.
     
  22. Offline

    Janmm14

    Read the first post - use bukkit instead of craftbukkit
    or add bukkit before craftbukkit to your dependenies
     
    exiHD2k likes this.
  23. Offline

    bunny365

    Actually, you broke the plugin I'm developing:
    Code:
    18:33:40 [SEVERE] Could not pass event CreatureSpawnEvent to ScoreBoard HealthBar v1.0.0
    org.bukkit.event.EventException
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:427)
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62)
            at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:477)
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:462)
            at org.bukkit.craftbukkit.v1_6_R2.event.CraftEventFactory.callCreatureSpawnEvent(CraftEventFactory.java:239)
            at net.minecraft.server.v1_6_R2.World.addEntity(World.java:923)
            at net.minecraft.server.v1_6_R2.ItemMonsterEgg.a(ItemMonsterEgg.java:110)
            at net.minecraft.server.v1_6_R2.ItemMonsterEgg.interactWith(ItemMonsterEgg.java:37)
            at net.minecraft.server.v1_6_R2.ItemStack.placeItem(ItemStack.java:79)
            at net.minecraft.server.v1_6_R2.PlayerInteractManager.interact(PlayerInteractManager.java:389)
            at net.minecraft.server.v1_6_R2.PlayerConnection.a(PlayerConnection.java:628)
            at net.minecraft.server.v1_6_R2.Packet15Place.handle(SourceFile:58)
            at net.minecraft.server.v1_6_R2.NetworkManager.b(NetworkManager.java:296)
            at net.minecraft.server.v1_6_R2.PlayerConnection.e(PlayerConnection.java:116)
            at net.minecraft.server.v1_6_R2.ServerConnection.b(SourceFile:37)
            at net.minecraft.server.v1_6_R2.DedicatedServerConnection.b(SourceFile:30)
            at net.minecraft.server.v1_6_R2.MinecraftServer.t(MinecraftServer.java:590)
            at net.minecraft.server.v1_6_R2.DedicatedServer.t(DedicatedServer.java:226)
            at net.minecraft.server.v1_6_R2.MinecraftServer.s(MinecraftServer.java:486)
            at net.minecraft.server.v1_6_R2.MinecraftServer.run(MinecraftServer.java:419)
            at net.minecraft.server.v1_6_R2.ThreadServerApplication.run(SourceFile:582)
    Caused by: java.lang.Error: Unresolved compilation problems:
            The method getHealth() is ambiguous for the type LivingEntity
            The method getMaxHealth() is ambiguous for the type LivingEntity
     
            at com.gmail.ethanshnesy.healthbar.HealthBar.onMobSpawn(HealthBar.java:29)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
            at java.lang.reflect.Method.invoke(Unknown Source)
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:425)
            ... 20 more
    Here's my main class:
    Code:java
    1. package com.gmail.ethanshnesy.healthbar;
    2.  
    3. import org.bukkit.entity.Player;
    4. import org.bukkit.event.EventHandler;
    5. import org.bukkit.event.Listener;
    6. import org.bukkit.event.entity.CreatureSpawnEvent;
    7. import org.bukkit.event.entity.EntityDamageEvent;
    8. import org.bukkit.event.player.PlayerJoinEvent;
    9. import org.bukkit.scoreboard.DisplaySlot;
    10. import org.bukkit.scoreboard.Objective;
    11. import org.bukkit.scoreboard.Scoreboard;
    12. import org.bukkit.scoreboard.ScoreboardManager;
    13.  
    14. import com.massivecraft.mcore.MPlugin;
    15. import com.massivecraft.mcore.Progressbar;
    16.  
    17. public class HealthBar extends MPlugin implements Listener
    18. {
    19. @EventHandler
    20. public void onLogin(PlayerJoinEvent event)
    21. {
    22. update();
    23. }
    24.  
    25. @EventHandler
    26. public void onMobSpawn(CreatureSpawnEvent event) {
    27. // "Oops, I didn't break your plugins - ambiguous getHealth()" doesn't apply here... :/
    28. double health = (double)event.getEntity().getHealth();
    29. double maxHealth = (double)event.getEntity().getMaxHealth();
    30. event.getEntity().setCustomName(bar(health,maxHealth));
    31. event.getEntity().setCustomNameVisible(true);
    32. }
    33.  
    34. @EventHandler
    35. public void onMobHurt(EntityDamageEvent event) {
    36.  
    37. }
    38.  
    39. public void onEnable()
    40. {
    41. getServer().getPluginManager().registerEvents(this, this);
    42. update();
    43. }
    44.  
    45. public void onDisable() {
    46. update();
    47. }
    48.  
    49. private String bar(double health, double maxHealth) {
    50. return Progressbar.HEALTHBAR_CLASSIC.withQuota(1D/maxHealth*health).render();
    51. }
    52.  
    53. private void update()
    54. {
    55. ScoreboardManager manager = getServer().getScoreboardManager();
    56. Scoreboard board = manager.getNewScoreboard();
    57. Objective objective = board
    58. .registerNewObjective("showhealth", "health");
    59. objective.setDisplaySlot(DisplaySlot.BELOW_NAME);
    60. objective.setDisplayName("Health");
    61. for (Player online : getServer().getOnlinePlayers())
    62. {
    63. online.setScoreboard(board);
    64. }
    65. }
    66. }
    67.  

    Just so you know, I am using MCore as a dependency. My plugin extends MPlugin which extends JavaPlugin: Source Code of MPlugin
     
  24. Offline

    mbaxter ʇıʞʞnq ɐ sɐɥ ı Retired Staff

    glen3b and Janmm14 like this.
  25. Offline

    Conarnar

    bunny365
    Code:
    double health = event.getEntity().getHealth();
    double maxHealth = event.getEntity().getMaxHealth();
    remove the casts
     
  26. Offline

    DreTaX

    Do somebody know why doesnt this work? [​IMG]
     
  27. Offline

    scarabcoder

    Yes yes, but HOW DO WE GET HEALTH? It won't work at all anymore. And I only use one library, and that's Bukkit. I don't import anything else (like org.craftbukkit.etc).
     
  28. Offline

    ZeusAllMighty11 Retired Staff

    scarabcoder

    easy way: cast player to Damageable

    Code:
    double health = ((Damageable)player).getHealth();
     
  29. Offline

    scarabcoder

    Ahhhhhhh! Thanks @ZeusAllMighty1! :)
     
  30. Offline

    ChipDev

    Set the max health and set it to 20.0, fill the max health...
    then set it back to watevz.
     
Thread Status:
Not open for further replies.

Share This Page