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. 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. I use craftbukkit as a dependency since when I use bukkit.jar most of my plugins break down.
     
  5. 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. 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. 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. 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. 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. 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. 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. 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. Just round it? or cast it back to int for display?
     

  19. Just do something like: System.out.println((int) p.getHealth());
     
  20. 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. Read the first post - use bukkit instead of craftbukkit
    or add bukkit before craftbukkit to your dependenies
     
    exiHD2k likes this.
  23. 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. bunny365
    Code:
    double health = event.getEntity().getHealth();
    double maxHealth = event.getEntity().getMaxHealth();
    remove the casts
     
  26. Do somebody know why doesnt this work? [​IMG]
     
  27. 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. scarabcoder

    easy way: cast player to Damageable

    Code:
    double health = ((Damageable)player).getHealth();
     
  29. Ahhhhhhh! Thanks @ZeusAllMighty1! :)
     
  30. 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