├── .github\FUNDING.yml ├── .github\stale.yml ├── .settings └── org.eclipse.jdt.core.prefs ├── .travis.yml ├── LICENSE ├── pom.xml ├── renovate.json ├── resources └── plugin.yml ├── settings.xml └── src └── org └── inventivetalent └── bossbar ├── BossBar.java ├── BossBarAPI.java ├── BossBarPlugin.java ├── BossBarTimer.java ├── EntityBossBar.java ├── PacketBossBar.java └── reflection ├── AccessUtil.java ├── ClassBuilder.java ├── MathUtil.java ├── NMSClass.java ├── NMUClass.java └── Reflection.java /.github\FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: InventivetalentDev 2 | patreon: inventivetalent 3 | custom: ["https://www.paypal.me/inventivetalent", "https://donation.inventivetalent.org"] 4 | -------------------------------------------------------------------------------- /.github\stale.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InventivetalentDev/BossBarAPI/adc132a0cad8fb89b26893b139a2926c0b52ce3c/.github\stale.yml -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 4 | org.eclipse.jdt.core.compiler.compliance=1.7 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 8 | org.eclipse.jdt.core.compiler.source=1.7 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | 5 | script: "mvn deploy --settings settings.xml" 6 | env: 7 | global: 8 | - secure: "FBEvL2TOKKQTWWkGf6yyW049I4F9U3EPbYGavPZY6YxuRHlZEP9livGC2YjFgZrNqdw/iPXaRS9i7j7Gi/Y0BdWYljtAL2RFAP7XqUo2D6VgtLeopShNu3K8KUQxQCwP+ESxgfNoEKXrEd1CGXPhjHT7dr0JquiySgdg+rAs9YVVs7QjrcLGXBB4I9h1vuzB/dxFbaWb16/tFdBJU3WGDoiQsDFfU7YZ2EnBDDJRTSgAw5SpeApE0XQgH+pFuj0vffoUftjqiVv8YJgCgDdIxeie2zrzWA9vPjnagH7kM9/0yS8IrH13/63Qwx4vOYGi9B8NfRpy3Qh8j/vojuGl0qOYOMh016AG+I6YacFemIC3WTVRH9XXq7WTdIoABa5Q3VQadlakuGusF2ydQjI49iHTpHieycDv0DMWBJFZfMXnHW4TXZENQbcVc43LFSx93UoEft7vi3phhZbp64nR79bw8oth/wJPFwND+0LayOqmWZ3i43YvI990aRBkFcJJaaKBL/sEMTn4IN9DBaqkdXNOOR4sP8TTTHBkjI7GOFOIOO/tpWTNeZbCD59YIjv2AIZ068CE9suWO94LvjHEwENuH+gDwUUL8Ogieh4/CmvUb5NVOMBkAIfr8KRP2F0lI0Yl2BuYmo15eWhts3X0GBvX5uGcKVR5L5PjHFwqLHI=" 9 | - secure: "U1UDF/PR8lSfhAo6iQtmSdZ0ZDdQ59nNyT3GvbPFmiHNFyVu5WQgj7SzBu9PhtQjxH0bixIeoBnkM6LI8yTkQd2U9bHBXz0nwGaMouke+WXBirIXaYFUI2KvQBL5lqSjYBu/DlgXWqkyyRE/+idWoBPxXuBCMOwrXmh+RwWQGzIIsW8k4L1DssNIBIhz9Y66nIKGhVMcy7leJMvaEdsSRanlKf5gNSoM0AVccfE2MycSusJr+JcIeAF+zRkW0z2s8Gfx55II4bcTsef03mOofZD2LGX4w6ZX4AqGZg6q0owZfL5mXCTLsHzKA1El2wiSDo67YIv9xUVg1B41LnSel5G4d3zKlJFwkHp+3zWqJd++J5IsUzfOVRgc1PImFIfYRCOhAhmfKosAO1huSRrzPCDNICvHOuhOP7ssIqVDv3QWK3ezxYDjX09KA1FSm8uzaQdxBFnBrGITM2bK5nvEmvdgd2huwrA7gjtkvOvOHI1GaglLbBPH7dC+7jhGPY8WooWDNA/wQ8+C90mlOigCyxki9NOhBU2BcWUOhoO6M68YAlQX0wrJ4SQqZvIE8PSoO3V2ZdOd0uBFdcpX+u/8toH8b0RvB8mh9a+X+me+QOza3X7e/FiVnXCRCd46ShkTmb5pzdpy3QQtsIl+4ZAZZI6K7+qsDIsXWImMNn2m4og=" 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Haylee Schäfer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 28 | 29 | 30 | 4.0.0 31 | org.inventivetalent 32 | bossbarapi 33 | 2.4.3-SNAPSHOT 34 | BossBarAPI 35 | 36 | BossBarAPI_v${project.version} 37 | src 38 | 39 | 40 | src 41 | 42 | **/*.java 43 | 44 | 45 | 46 | resources 47 | true 48 | 49 | plugin.yml 50 | config.yml 51 | 52 | 53 | 54 | 55 | 56 | maven-compiler-plugin 57 | 3.3 58 | 59 | 1.7 60 | 1.7 61 | 62 | 63 | 64 | org.apache.maven.plugins 65 | maven-shade-plugin 66 | 2.4 67 | 68 | 69 | package 70 | 71 | shade 72 | 73 | 74 | 75 | 76 | org.inventivetalent:bossbarapi** 77 | org.inventivetalent:reflectionhelper** 78 | org.inventivetalent:apimanager** 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | inventive-repo 91 | https://repo.inventivetalent.org/content/groups/public/ 92 | 93 | 94 | md_5-repo 95 | http://repo.md-5.net/content/repositories/public/ 96 | 97 | 98 | spigot-repo 99 | https://hub.spigotmc.org/nexus/content/groups/public/ 100 | 101 | 102 | techcable-repo 103 | https://repo.techcable.net/content/groups/public/ 104 | 105 | 106 | 107 | 108 | org.spigotmc 109 | spigot-api 110 | 1.12.2-R0.1-SNAPSHOT 111 | provided 112 | 113 | 114 | org.bukkit 115 | bukkit 116 | 1.12.2-R0.1-SNAPSHOT 117 | 118 | 119 | org.inventivetalent 120 | reflectionhelper 121 | 1.14.3-SNAPSHOT 122 | 123 | 124 | org.inventivetalent 125 | apimanager 126 | 1.0.3-SNAPSHOT 127 | 128 | 129 | 130 | 131 | 132 | sonatype-nexus-releases 133 | https://repo.inventivetalent.org/content/repositories/releases/ 134 | 135 | 136 | sonatype-nexus-snapshots 137 | https://repo.inventivetalent.org/content/repositories/snapshots/ 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "maven": { 6 | "enabled": true 7 | }, 8 | "ignoreUnstable": false, 9 | "hostRules": [{ 10 | "hostType": "maven", 11 | "endpoint": "https://repo.inventivetalent.org/content/groups/public/" 12 | }] 13 | } 14 | -------------------------------------------------------------------------------- /resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: BossBarAPI 2 | main: org.inventivetalent.bossbar.BossBarPlugin 3 | author: inventivetalent 4 | version: ${project.version} 5 | 6 | loadbefore: [BarAPI] -------------------------------------------------------------------------------- /settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | sonatype-nexus-releases 5 | ${env.CI_DEPLOY_USERNAME} 6 | ${env.CI_DEPLOY_PASSWORD} 7 | 8 | 9 | sonatype-nexus-snapshots 10 | ${env.CI_DEPLOY_USERNAME} 11 | ${env.CI_DEPLOY_PASSWORD} 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/BossBar.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.entity.Player; 5 | 6 | import java.util.Collection; 7 | 8 | public interface BossBar { 9 | 10 | /** 11 | * @return The players which can see the BossBar 12 | */ 13 | Collection getPlayers(); 14 | 15 | /** 16 | * Add a player to this BossBar 17 | * 18 | * @param player {@link Player} to add 19 | */ 20 | void addPlayer(Player player); 21 | 22 | /** 23 | * Remove a player from this BossBar 24 | * 25 | * @param player {@link Player} to remove 26 | */ 27 | void removePlayer(Player player); 28 | 29 | /** 30 | * @return the {@link org.inventivetalent.bossbar.BossBarAPI.Color} 31 | */ 32 | BossBarAPI.Color getColor(); 33 | 34 | /** 35 | * @param color the new {@link org.inventivetalent.bossbar.BossBarAPI.Color} 36 | */ 37 | void setColor(BossBarAPI.Color color); 38 | 39 | /** 40 | * @return the {@link org.inventivetalent.bossbar.BossBarAPI.Style} 41 | */ 42 | BossBarAPI.Style getStyle(); 43 | 44 | /** 45 | * @param style the new {@link org.inventivetalent.bossbar.BossBarAPI.Style} 46 | */ 47 | void setStyle(BossBarAPI.Style style); 48 | 49 | /** 50 | * Modify a property 51 | * 52 | * @param property {@link org.inventivetalent.bossbar.BossBarAPI.Property} 53 | * @param flag whether to enable the property 54 | */ 55 | void setProperty(BossBarAPI.Property property, boolean flag); 56 | 57 | /** 58 | * @return the message 59 | */ 60 | String getMessage(); 61 | 62 | /** 63 | * @param flag whether the BossBar is visible 64 | */ 65 | void setVisible(boolean flag); 66 | 67 | /** 68 | * @return whether the BossBar is visible 69 | */ 70 | boolean isVisible(); 71 | 72 | /** 73 | * @return the progress (0.0 - 1.0) 74 | */ 75 | float getProgress(); 76 | 77 | /** 78 | * @param progress the new progress (0.0 - 1.0) 79 | */ 80 | void setProgress(float progress); 81 | 82 | @Deprecated 83 | float getMaxHealth(); 84 | 85 | @Deprecated 86 | void setHealth(float percentage); 87 | 88 | @Deprecated 89 | float getHealth(); 90 | 91 | @Deprecated 92 | void setMessage(String message); 93 | 94 | @Deprecated 95 | Player getReceiver(); 96 | 97 | @Deprecated 98 | Location getLocation(); 99 | 100 | @Deprecated 101 | void updateMovement(); 102 | } 103 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/BossBarAPI.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar; 2 | 3 | import net.md_5.bungee.api.chat.BaseComponent; 4 | import net.md_5.bungee.api.chat.TextComponent; 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.Location; 7 | import org.bukkit.entity.Player; 8 | import org.bukkit.event.EventHandler; 9 | import org.bukkit.event.EventPriority; 10 | import org.bukkit.event.Listener; 11 | import org.bukkit.event.player.*; 12 | import org.bukkit.event.server.PluginEnableEvent; 13 | import org.bukkit.plugin.Plugin; 14 | import org.bukkit.scheduler.BukkitRunnable; 15 | import org.inventivetalent.apihelper.API; 16 | import org.inventivetalent.apihelper.APIManager; 17 | import org.inventivetalent.bossbar.reflection.Reflection; 18 | import org.inventivetalent.reflection.minecraft.Minecraft; 19 | 20 | import java.lang.reflect.Method; 21 | import java.util.*; 22 | import java.util.concurrent.ConcurrentHashMap; 23 | import java.util.logging.Logger; 24 | 25 | public class BossBarAPI implements API, Listener { 26 | 27 | protected static final Map> barMap = new ConcurrentHashMap<>(); 28 | 29 | public static boolean is1_9 = Minecraft.VERSION.newerThan(Minecraft.Version.v1_9_R1); 30 | 31 | public enum Color { 32 | PINK, 33 | BLUE, 34 | RED, 35 | GREEN, 36 | YELLOW, 37 | PURPLE, 38 | WHITE; 39 | } 40 | 41 | public enum Style { 42 | PROGRESS, 43 | NOTCHED_6, 44 | NOTCHED_10, 45 | NOTCHED_12, 46 | NOTCHED_20; 47 | } 48 | 49 | public enum Property { 50 | DARKEN_SKY, 51 | PLAY_MUSIC, 52 | //This seems to be the only property implemented client-side currently 53 | CREATE_FOG; 54 | } 55 | 56 | /** 57 | * Not compatible with 1.8! 58 | * 59 | * @param players Receivers of the BossBar 60 | * @param message Message of the BossBar (JSON) 61 | * @param color {@link org.inventivetalent.bossbar.BossBarAPI.Color} 62 | * @param style {@link org.inventivetalent.bossbar.BossBarAPI.Style} 63 | * @param progress progress (0.0 - 1.0) 64 | * @param properties {@link org.inventivetalent.bossbar.BossBarAPI.Property} 65 | * @return the new {@link BossBar} instance 66 | */ 67 | public static BossBar addBar(Collection players, String message, Color color, Style style, float progress, Property... properties) { 68 | validate1_9(); 69 | BossBar bossBar = new PacketBossBar(message, color, style, progress, properties); 70 | for (Player player : players) { 71 | addBarForPlayer(player, bossBar); 72 | } 73 | return bossBar; 74 | } 75 | 76 | /** 77 | * Not compatible with 1.8! 78 | * 79 | * @param players Receivers of the BossBar 80 | * @param component displayed message 81 | * @param color {@link org.inventivetalent.bossbar.BossBarAPI.Color} 82 | * @param style {@link org.inventivetalent.bossbar.BossBarAPI.Style} 83 | * @param progress progress (0.0 - 1.0) 84 | * @param properties {@link org.inventivetalent.bossbar.BossBarAPI.Property} 85 | * @return the new {@link BossBar} instance 86 | */ 87 | public static BossBar addBar(Collection players, BaseComponent component, Color color, Style style, float progress, Property... properties) { 88 | validate1_9(); 89 | BossBar bossBar = new PacketBossBar(component, color, style, progress, properties); 90 | for (Player player : players) { 91 | addBarForPlayer(player, bossBar); 92 | } 93 | return bossBar; 94 | } 95 | 96 | /** 97 | * Not compatible with 1.8! 98 | * 99 | * @param players Receivers of the BossBar 100 | * @param component displayed message 101 | * @param color {@link org.inventivetalent.bossbar.BossBarAPI.Color} 102 | * @param style {@link org.inventivetalent.bossbar.BossBarAPI.Style} 103 | * @param progress progress (0.0 - 1.0) 104 | * @param timeout time until the bar disappears 105 | * @param interval interval of the "countdown" 106 | * @param properties {@link org.inventivetalent.bossbar.BossBarAPI.Property} 107 | * @return the new {@link BossBar} instance 108 | */ 109 | public static BossBar addBar(Collection players, BaseComponent component, Color color, Style style, float progress, int timeout, long interval, Property... properties) { 110 | validate1_9(); 111 | final BossBar bossBar = addBar(players, component, color, style, progress, properties); 112 | new BossBarTimer((PacketBossBar) bossBar, progress, timeout).runTaskTimer(BossBarPlugin.instance, interval, interval); 113 | return bossBar; 114 | } 115 | 116 | /** 117 | * Compatible with 1.8 118 | * 119 | * @param player Receiver of the BossBar 120 | * @param component displayed message 121 | * @param color {@link org.inventivetalent.bossbar.BossBarAPI.Color} (1.9-only) 122 | * @param style {@link org.inventivetalent.bossbar.BossBarAPI.Style} (1.9-only) 123 | * @param progress progress (0.0 - 1.0) 124 | * @param properties {@link org.inventivetalent.bossbar.BossBarAPI.Property} (1.9-only) 125 | * @return the new {@link BossBar} instance 126 | * @see #setMessage(Player, String, float) 127 | */ 128 | public static BossBar addBar(Player player, BaseComponent component, Color color, Style style, float progress, Property... properties) { 129 | if (is1_9) { 130 | BossBar bossBar = new PacketBossBar(component, color, style, progress, properties); 131 | addBarForPlayer(player, bossBar); 132 | return bossBar; 133 | } else { 134 | setMessage(player, component.toLegacyText(), progress * 100); 135 | return getBossBar(player); 136 | } 137 | } 138 | 139 | /** 140 | * Compatible with 1.8 141 | * 142 | * @param player Receiver of the BossBar 143 | * @param component displayed message 144 | * @param color {@link org.inventivetalent.bossbar.BossBarAPI.Color} (1.9-only) 145 | * @param style {@link org.inventivetalent.bossbar.BossBarAPI.Style} (1.9-only) 146 | * @param progress progress (0.0-1.0) 147 | * @param timeout time until the bar disappears 148 | * @param interval interval of the "countdown" 149 | * @param properties {@link org.inventivetalent.bossbar.BossBarAPI.Property} (1.9-only) 150 | * @return the new {@link BossBar} instance 151 | */ 152 | public static BossBar addBar(Player player, BaseComponent component, Color color, Style style, float progress, int timeout, long interval, Property... properties) { 153 | if (is1_9) { 154 | final BossBar bossBar = addBar(player, component, color, style, progress, properties); 155 | new BossBarTimer((PacketBossBar) bossBar, progress, timeout).runTaskTimer(BossBarPlugin.instance, interval, interval); 156 | return bossBar; 157 | } else { 158 | setMessage(player, component.toLegacyText(), progress * 100, timeout); 159 | return getBossBar(player); 160 | } 161 | } 162 | 163 | /** 164 | * Not compatible with 1.8! Adds a BossBar without displaying it to a player 165 | * 166 | * @param component displayed message 167 | * @param color {@link org.inventivetalent.bossbar.BossBarAPI.Color} 168 | * @param style {@link org.inventivetalent.bossbar.BossBarAPI.Style} 169 | * @param progress progress (0.0 - 1.0) 170 | * @param properties {@link org.inventivetalent.bossbar.BossBarAPI.Property} 171 | * @return the new {@link BossBar} instance 172 | */ 173 | public static BossBar addBar(BaseComponent component, Color color, Style style, float progress, Property... properties) { 174 | validate1_9(); 175 | return new PacketBossBar(component, color, style, progress, properties); 176 | } 177 | 178 | public static Collection getBossBars(Player player) { 179 | if (!barMap.containsKey(player.getUniqueId())) { return new ArrayList<>(); } 180 | return new ArrayList<>(barMap.get(player.getUniqueId())); 181 | } 182 | 183 | protected static void addBarForPlayer(Player player, BossBar bossBar) { 184 | bossBar.addPlayer(player); 185 | 186 | Collection collection = barMap.get(player.getUniqueId()); 187 | if (collection == null) { collection = new ArrayList<>(); } 188 | collection.add(bossBar); 189 | barMap.put(player.getUniqueId(), collection); 190 | } 191 | 192 | protected static void removeBarForPlayer(Player player, BossBar bossBar) { 193 | bossBar.removePlayer(player); 194 | 195 | Collection collection = barMap.get(player.getUniqueId()); 196 | if (collection != null) { 197 | collection.remove(bossBar); 198 | if (!collection.isEmpty()) { 199 | barMap.put(player.getUniqueId(), collection); 200 | } else { 201 | barMap.remove(player.getUniqueId()); 202 | } 203 | } 204 | } 205 | 206 | public static void removeAllBars(Player player) { 207 | for (BossBar bossBar : getBossBars(player)) { 208 | removeBarForPlayer(player, bossBar); 209 | } 210 | } 211 | 212 | //// Deprecated (< 1.9) methods 213 | 214 | /** 215 | * Sets the boss-bar message for the specified player 216 | * 217 | * @param player Receiver of the message 218 | * @param message Message content 219 | */ 220 | @Deprecated 221 | public static void setMessage(Player player, String message) { 222 | setMessage(player, message, 100); 223 | } 224 | 225 | /** 226 | * Sets the boss-bar message for the specified player 227 | * 228 | * @param player Receiver of the message 229 | * @param message Message content 230 | * @param percentage Health percentage 231 | */ 232 | @Deprecated 233 | public static void setMessage(Player player, String message, float percentage) { 234 | setMessage(player, message, percentage, 0); 235 | } 236 | 237 | /** 238 | * Sets the boss-bar message for the specified player 239 | * 240 | * @param player Receiver of the message 241 | * @param message Message content 242 | * @param percentage Health percentage 243 | * @param timeout Amount of seconds until the bar is removed 244 | */ 245 | @Deprecated 246 | public static void setMessage(Player player, String message, float percentage, int timeout) { 247 | setMessage(player, message, percentage, timeout, 100); 248 | } 249 | 250 | /** 251 | * Sets the boss-bar message for the specified player 252 | * 253 | * @param player Receiver of the message 254 | * @param message Message content 255 | * @param percentage Health percentage 256 | * @param timeout Amount of seconds until the bar is removed 257 | * @param minHealth minimum health (100 by default) 258 | */ 259 | @Deprecated 260 | public static void setMessage(Player player, String message, float percentage, int timeout, float minHealth) { 261 | if (is1_9) { 262 | removeAllBars(player); 263 | addBar(player, new TextComponent(message), Color.PURPLE, Style.PROGRESS, percentage / 100); 264 | } else { 265 | if (!barMap.containsKey(player.getUniqueId())) { 266 | ArrayList list = new ArrayList<>(); 267 | list.add(new EntityBossBar(player, message, percentage, timeout, minHealth)); 268 | barMap.put(player.getUniqueId(), list); 269 | } 270 | BossBar bar = ((List) barMap.get(player.getUniqueId())).get(0); 271 | if (!bar.getMessage().equals(message)) { 272 | bar.setMessage(message); 273 | } 274 | float newHealth = percentage / 100F * bar.getMaxHealth(); 275 | if (bar.getHealth() != newHealth) { 276 | bar.setHealth(percentage); 277 | } 278 | if (!bar.isVisible()) { 279 | bar.setVisible(true); 280 | } 281 | } 282 | } 283 | 284 | /** 285 | * @param player {@link Player} 286 | * @return The current message of the player's bar 287 | */ 288 | @Deprecated 289 | public static String getMessage(Player player) { 290 | BossBar bar = getBossBar(player); 291 | if (bar == null) { return null; } 292 | return bar.getMessage(); 293 | } 294 | 295 | /** 296 | * @param player {@link Player} to check 297 | * @return true if the player has a bar 298 | */ 299 | @Deprecated 300 | public static boolean hasBar( Player player) { 301 | return barMap.containsKey(player.getUniqueId()); 302 | } 303 | 304 | /** 305 | * Removes the bar of a player 306 | * 307 | * @param player Player to remove 308 | */ 309 | @Deprecated 310 | public static void removeBar( Player player) { 311 | BossBar bar = getBossBar(player); 312 | if (bar != null) { bar.setVisible(false); } 313 | removeAllBars(player); 314 | } 315 | 316 | /** 317 | * Changes the displayed health of the bar 318 | * 319 | * @param player {@link Player} 320 | * @param percentage Health percentage 321 | */ 322 | @Deprecated 323 | public static void setHealth(Player player, float percentage) { 324 | BossBar bar = getBossBar(player); 325 | if (bar == null) { return; } 326 | bar.setHealth(percentage); 327 | } 328 | 329 | /** 330 | * @param player {@link Player} 331 | * @return The health of the player's bar 332 | */ 333 | @Deprecated 334 | public static float getHealth(Player player) { 335 | BossBar bar = getBossBar(player); 336 | if (bar == null) { return -1; } 337 | return bar.getHealth(); 338 | } 339 | 340 | /** 341 | * Get the bar for the specified player 342 | * 343 | * @param player {@link Player} 344 | * @return a {@link EntityBossBar} instance if the player has a bar, null otherwise 345 | */ 346 | @Deprecated 347 | public static BossBar getBossBar(Player player) { 348 | if (player == null) { return null; } 349 | List list = ((List) barMap.get(player.getUniqueId())); 350 | 351 | if (list != null && list.size() > 0) { 352 | return list.get(0); 353 | } 354 | return null; 355 | } 356 | 357 | /** 358 | * @return A {@link Collection} of all registered bars 359 | */ 360 | @Deprecated 361 | public static Collection getBossBars() { 362 | List list = new ArrayList<>(); 363 | for (Collection collection : barMap.values()) { 364 | list.add(((List) collection).get(0)); 365 | } 366 | return list; 367 | } 368 | 369 | protected static void sendPacket(Player p, Object packet) { 370 | if (p == null || packet == null) { throw new IllegalArgumentException("player and packet cannot be null"); } 371 | try { 372 | Object handle = Reflection.getHandle(p); 373 | Object connection = Reflection.getField(handle.getClass(), "playerConnection").get(handle); 374 | Reflection.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet")).invoke(connection, new Object[] { packet }); 375 | } catch (Exception e) { 376 | } 377 | } 378 | 379 | static void validate1_9() { 380 | if (!is1_9) { 381 | throw new RuntimeException(new UnsupportedOperationException("This method is not compatible with versions < 1.9")); 382 | } 383 | } 384 | 385 | Logger logger = Logger.getLogger("BossBarAPI"); 386 | 387 | @Override 388 | public void load() { 389 | } 390 | 391 | @Override 392 | public void init(Plugin plugin) { 393 | APIManager.registerEvents(this, this); 394 | BossBarPlugin.instance = APIManager.getAPIHost(this); 395 | for (Player player : Bukkit.getOnlinePlayers()) { 396 | BossBarAPI.removeAllBars(player); 397 | } 398 | } 399 | 400 | @Override 401 | public void disable(Plugin plugin) { 402 | } 403 | 404 | @EventHandler 405 | public void onPluginEnable(PluginEnableEvent e) { 406 | if ("BarAPI".equals(e.getPlugin().getName()) && Bukkit.getPluginManager().isPluginEnabled("BarAPI")) { 407 | try { 408 | Class barAPI = Class.forName("me.confuser.barapi.BarAPI"); 409 | 410 | Method method = barAPI.getDeclaredMethod("enabled"); 411 | method.setAccessible(true); 412 | if ((boolean) method.invoke(null)) { 413 | logger.info("Successfully replaced BarAPI."); 414 | return; 415 | } 416 | } catch (Exception ex) { 417 | } 418 | logger.warning("Failed to replace BarAPI."); 419 | } 420 | } 421 | 422 | @EventHandler(priority = EventPriority.MONITOR) 423 | public void onQuit(PlayerQuitEvent e) { 424 | BossBarAPI.removeBar(e.getPlayer()); 425 | } 426 | 427 | @EventHandler(priority = EventPriority.MONITOR) 428 | public void onKick(PlayerKickEvent e) { 429 | BossBarAPI.removeBar(e.getPlayer()); 430 | } 431 | 432 | @EventHandler(priority = EventPriority.MONITOR) 433 | public void onTeleport(PlayerTeleportEvent e) { 434 | if (Minecraft.VERSION.olderThan(Minecraft.Version.v1_9_R1)) { 435 | this.handlePlayerTeleport(e.getPlayer(), e.getFrom(), e.getTo()); 436 | } 437 | } 438 | 439 | @EventHandler(priority = EventPriority.MONITOR) 440 | public void onRespawn(PlayerRespawnEvent e) { 441 | if (Minecraft.VERSION.olderThan(Minecraft.Version.v1_9_R1)) { 442 | this.handlePlayerTeleport(e.getPlayer(), e.getPlayer().getLocation(), e.getRespawnLocation()); 443 | } 444 | } 445 | 446 | protected void handlePlayerTeleport(Player player, Location from, Location to) { 447 | if (!BossBarAPI.hasBar(player)) { return; } 448 | final BossBar bar = BossBarAPI.getBossBar(player); 449 | bar.setVisible(false); 450 | new BukkitRunnable() { 451 | 452 | @Override 453 | public void run() { 454 | bar.setVisible(true); 455 | } 456 | }.runTaskLater(APIManager.getAPIHost(this), 2); 457 | } 458 | 459 | @EventHandler 460 | public void onMove(final PlayerMoveEvent e) { 461 | if (Minecraft.VERSION.olderThan(Minecraft.Version.v1_9_R1)) { 462 | final BossBar bar = BossBarAPI.getBossBar(e.getPlayer()); 463 | if (bar != null) { 464 | new BukkitRunnable() { 465 | 466 | @SuppressWarnings("deprecation") 467 | @Override 468 | public void run() { 469 | if (!e.getPlayer().isOnline()) { return; } 470 | bar.updateMovement(); 471 | } 472 | }.runTaskLater(APIManager.getAPIHost(this), 0); 473 | } 474 | } 475 | } 476 | 477 | public BossBarAPI() { 478 | } 479 | 480 | } 481 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/BossBarPlugin.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar; 2 | 3 | import org.bukkit.plugin.Plugin; 4 | import org.bukkit.plugin.java.JavaPlugin; 5 | import org.inventivetalent.apihelper.APIManager; 6 | 7 | public class BossBarPlugin extends JavaPlugin { 8 | 9 | protected static Plugin instance; 10 | BossBarAPI apiInstance = new BossBarAPI(); 11 | 12 | @Override 13 | public void onLoad() { 14 | APIManager.registerAPI(apiInstance, this); 15 | } 16 | 17 | @Override 18 | public void onEnable() { 19 | instance = this; 20 | 21 | APIManager.initAPI(BossBarAPI.class); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/BossBarTimer.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.scheduler.BukkitRunnable; 5 | 6 | public class BossBarTimer extends BukkitRunnable { 7 | 8 | private PacketBossBar bossBar; 9 | final float progressMinus; 10 | 11 | public BossBarTimer(PacketBossBar packetBossBar, float progress, int timeout) { 12 | this.bossBar = packetBossBar; 13 | this.progressMinus = progress / timeout; 14 | } 15 | 16 | @Override 17 | public void run() { 18 | float newProgress = bossBar.getProgress() - progressMinus; 19 | if (newProgress <= 0) { 20 | for (Player player : bossBar.getPlayers()) { 21 | bossBar.removePlayer(player); 22 | } 23 | } else { 24 | bossBar.setProgress(newProgress); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/EntityBossBar.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.World; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.scheduler.BukkitRunnable; 7 | import org.inventivetalent.bossbar.reflection.ClassBuilder; 8 | import org.inventivetalent.bossbar.reflection.NMSClass; 9 | import org.inventivetalent.reflection.minecraft.DataWatcher; 10 | 11 | import java.util.Collection; 12 | import java.util.Collections; 13 | import java.util.Random; 14 | import java.util.UUID; 15 | 16 | import static org.inventivetalent.reflection.minecraft.DataWatcher.V1_9.ValueType.*; 17 | 18 | public class EntityBossBar extends BukkitRunnable implements BossBar { 19 | 20 | protected static int ENTITY_DISTANCE = 32; 21 | 22 | protected final int ID; 23 | protected final UUID uuid; 24 | 25 | protected final Player receiver; 26 | protected String message; 27 | protected float health; 28 | protected float healthMinus; 29 | protected float minHealth = 1; 30 | 31 | protected Location location; 32 | protected World world; 33 | protected boolean visible = false; 34 | protected Object dataWatcher; 35 | 36 | @SuppressWarnings("deprecation") 37 | protected EntityBossBar(Player player, String message, float percentage, int timeout, float minHealth) { 38 | this.ID = new Random().nextInt(); 39 | this.uuid = UUID.randomUUID(); 40 | 41 | this.receiver = player; 42 | this.message = message; 43 | this.health = percentage / 100F * this.getMaxHealth(); 44 | this.minHealth = minHealth; 45 | this.world = player.getWorld(); 46 | this.location = this.makeLocation(player.getLocation()); 47 | 48 | if (percentage <= minHealth) { 49 | BossBarAPI.removeBar(player); 50 | } 51 | 52 | if (timeout > 0) { 53 | this.healthMinus = this.getMaxHealth() / timeout; 54 | this.runTaskTimer(BossBarPlugin.instance, 20, 20); 55 | } 56 | } 57 | 58 | protected Location makeLocation(Location base) { 59 | return base.getDirection().multiply(ENTITY_DISTANCE).add(base.toVector()).toLocation(this.world); 60 | } 61 | 62 | @Override 63 | public Player getReceiver() { 64 | return receiver; 65 | } 66 | 67 | @Override 68 | public float getMaxHealth() { 69 | return 300; 70 | } 71 | 72 | @SuppressWarnings("deprecation") 73 | @Override 74 | public void setHealth(float percentage) { 75 | this.health = percentage / 100F * this.getMaxHealth(); 76 | if (this.health <= this.minHealth) { 77 | BossBarAPI.removeBar(this.receiver); 78 | } else { 79 | this.sendMetadata(); 80 | } 81 | } 82 | 83 | @Override 84 | public float getHealth() { 85 | return health; 86 | } 87 | 88 | @Override 89 | public void setMessage(String message) { 90 | this.message = message; 91 | if (this.isVisible()) { 92 | this.sendMetadata(); 93 | } 94 | } 95 | 96 | @Override 97 | public Collection getPlayers() { 98 | return Collections.singletonList(getReceiver()); 99 | } 100 | 101 | @Override 102 | public void addPlayer(Player player) { 103 | } 104 | 105 | @Override 106 | public void removePlayer(Player player) { 107 | setVisible(false); 108 | } 109 | 110 | @Override 111 | public BossBarAPI.Color getColor() { 112 | return null; 113 | } 114 | 115 | @Override 116 | public void setColor(BossBarAPI.Color color) { 117 | } 118 | 119 | @Override 120 | public BossBarAPI.Style getStyle() { 121 | return null; 122 | } 123 | 124 | @Override 125 | public void setStyle(BossBarAPI.Style style) { 126 | } 127 | 128 | @Override 129 | public void setProperty(BossBarAPI.Property property, boolean flag) { 130 | } 131 | 132 | @Override 133 | public String getMessage() { 134 | return message; 135 | } 136 | 137 | @Override 138 | public Location getLocation() { 139 | return this.location; 140 | } 141 | 142 | @SuppressWarnings("deprecation") 143 | @Override 144 | public void run() { 145 | this.health -= this.healthMinus; 146 | if (this.health <= this.minHealth) { 147 | BossBarAPI.removeBar(this.receiver); 148 | } else { 149 | this.sendMetadata(); 150 | } 151 | } 152 | 153 | @Override 154 | public void setVisible(boolean flag) { 155 | if (flag == this.visible) { return; } 156 | if (flag) { 157 | this.spawn(); 158 | } else { 159 | this.destroy(); 160 | } 161 | } 162 | 163 | @Override 164 | public boolean isVisible() { 165 | return this.visible; 166 | } 167 | 168 | @Override 169 | public void setProgress(float progress) { 170 | setHealth(progress * 100); 171 | } 172 | 173 | @Override 174 | public float getProgress() { 175 | return getHealth() / 100; 176 | } 177 | 178 | @Override 179 | public void updateMovement() { 180 | if (!this.visible) { return; } 181 | this.location = this.makeLocation(this.receiver.getLocation()); 182 | try { 183 | Object packet = ClassBuilder.buildTeleportPacket(this.ID, this.getLocation(), false, false); 184 | BossBarAPI.sendPacket(this.receiver, packet); 185 | } catch (Exception e) { 186 | e.printStackTrace(); 187 | } 188 | } 189 | 190 | protected void updateDataWatcher() { 191 | if (this.dataWatcher == null) { 192 | try { 193 | this.dataWatcher = DataWatcher.newDataWatcher(null); 194 | DataWatcher.setValue(this.dataWatcher, 17, ENTITY_WITHER_a, new Integer(0)); 195 | DataWatcher.setValue(this.dataWatcher, 18, ENTITY_WIHER_b, new Integer(0)); 196 | DataWatcher.setValue(this.dataWatcher, 19, ENTITY_WITHER_c, new Integer(0)); 197 | 198 | DataWatcher.setValue(this.dataWatcher, 20, ENTITY_WITHER_bw, new Integer(1000));// Invulnerable time (1000 = very small) 199 | DataWatcher.setValue(this.dataWatcher, 0, ENTITY_FLAG, Byte.valueOf((byte) (0 | 1 << 5))); 200 | } catch (Exception e) { 201 | throw new RuntimeException(e); 202 | } 203 | } 204 | try { 205 | DataWatcher.setValue(this.dataWatcher, 6, ENTITY_LIVING_HEALTH, this.health); 206 | 207 | DataWatcher.setValue(this.dataWatcher, 10, ENTITY_NAME, this.message); 208 | DataWatcher.setValue(this.dataWatcher, 2, ENTITY_NAME, this.message); 209 | 210 | DataWatcher.setValue(this.dataWatcher, 11, ENTITY_NAME_VISIBLE, (byte) 1); 211 | DataWatcher.setValue(this.dataWatcher, 3, ENTITY_NAME_VISIBLE, (byte) 1); 212 | } catch (Exception e) { 213 | e.printStackTrace(); 214 | } 215 | } 216 | 217 | protected void sendMetadata() { 218 | this.updateDataWatcher(); 219 | try { 220 | Object metaPacket = ClassBuilder.buildNameMetadataPacket(this.ID, this.dataWatcher, 2, 3, this.message); 221 | BossBarAPI.sendPacket(this.receiver, metaPacket); 222 | } catch (Exception e) { 223 | e.printStackTrace(); 224 | } 225 | } 226 | 227 | protected void spawn() { 228 | try { 229 | this.updateMovement(); 230 | this.updateDataWatcher(); 231 | Object packet = ClassBuilder.buildWitherSpawnPacket(this.ID, this.uuid, this.getLocation(), this.dataWatcher); 232 | BossBarAPI.sendPacket(this.receiver, packet); 233 | this.visible = true; 234 | this.sendMetadata(); 235 | this.updateMovement(); 236 | } catch (Exception e) { 237 | e.printStackTrace(); 238 | } 239 | } 240 | 241 | protected void destroy() { 242 | try { 243 | this.cancel(); 244 | } catch (IllegalStateException e) { 245 | } 246 | try { 247 | Object packet = NMSClass.PacketPlayOutEntityDestroy.getConstructor(int[].class).newInstance(new int[] { this.ID }); 248 | BossBarAPI.sendPacket(this.receiver, packet); 249 | this.visible = false; 250 | } catch (Exception e) { 251 | e.printStackTrace(); 252 | } 253 | } 254 | 255 | } 256 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/PacketBossBar.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar; 2 | 3 | import net.md_5.bungee.api.chat.BaseComponent; 4 | import net.md_5.bungee.chat.ComponentSerializer; 5 | import org.bukkit.Location; 6 | import org.bukkit.entity.Player; 7 | import org.inventivetalent.reflection.resolver.FieldResolver; 8 | import org.inventivetalent.reflection.resolver.MethodResolver; 9 | import org.inventivetalent.reflection.resolver.ResolverQuery; 10 | import org.inventivetalent.reflection.resolver.minecraft.NMSClassResolver; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Collection; 14 | import java.util.UUID; 15 | 16 | public class PacketBossBar implements BossBar { 17 | 18 | static NMSClassResolver nmsClassResolver = new NMSClassResolver(); 19 | 20 | static Class PacketPlayOutBoss = nmsClassResolver.resolveSilent("PacketPlayOutBoss"); 21 | static Class PacketPlayOutBossAction = nmsClassResolver.resolveSilent("PacketPlayOutBoss$Action"); 22 | static Class ChatSerializer = nmsClassResolver.resolveSilent("ChatSerializer", "IChatBaseComponent$ChatSerializer"); 23 | static Class BossBattleBarColor = nmsClassResolver.resolveSilent("BossBattle$BarColor"); 24 | static Class BossBattleBarStyle = nmsClassResolver.resolveSilent("BossBattle$BarStyle"); 25 | 26 | static FieldResolver PacketPlayOutBossFieldResolver = new FieldResolver(PacketPlayOutBoss); 27 | 28 | static MethodResolver ChatSerializerMethodResolver = new MethodResolver(ChatSerializer); 29 | 30 | private final UUID uuid; 31 | private Collection receivers = new ArrayList<>(); 32 | private float progress; 33 | private String message; 34 | private BossBarAPI.Color color; 35 | private BossBarAPI.Style style; 36 | private boolean visible; 37 | 38 | private boolean darkenSky; 39 | private boolean playMusic; 40 | private boolean createFog; 41 | 42 | protected PacketBossBar(String message, BossBarAPI.Color color, BossBarAPI.Style style, float progress, BossBarAPI.Property... properties) { 43 | this.uuid = UUID.randomUUID(); 44 | 45 | this.color = color != null ? color : BossBarAPI.Color.PURPLE; 46 | this.style = style != null ? style : BossBarAPI.Style.PROGRESS; 47 | setMessage(message); 48 | setProgress(progress); 49 | 50 | for (BossBarAPI.Property property : properties) { 51 | setProperty(property, true); 52 | } 53 | } 54 | 55 | protected PacketBossBar(BaseComponent message, BossBarAPI.Color color, BossBarAPI.Style style, float progress, BossBarAPI.Property... properties) { 56 | this(ComponentSerializer.toString(message), color, style, progress, properties); 57 | } 58 | 59 | @Override 60 | public Collection getPlayers() { 61 | return new ArrayList<>(this.receivers); 62 | } 63 | 64 | @Override 65 | public void addPlayer(Player player) { 66 | if (!this.receivers.contains(player)) { 67 | this.receivers.add(player); 68 | sendPacket(0, player); 69 | BossBarAPI.addBarForPlayer(player, this); 70 | } 71 | } 72 | 73 | @Override 74 | public void removePlayer(Player player) { 75 | if (this.receivers.contains(player)) { 76 | this.receivers.remove(player); 77 | sendPacket(1, player); 78 | BossBarAPI.removeBarForPlayer(player, this); 79 | } 80 | } 81 | 82 | @Override 83 | public BossBarAPI.Color getColor() { 84 | return this.color; 85 | } 86 | 87 | @Override 88 | public void setColor(BossBarAPI.Color color) { 89 | if (color == null) { throw new IllegalArgumentException("color cannot be null"); } 90 | if (color != this.color) { 91 | this.color = color; 92 | sendPacket(4, null); 93 | } 94 | } 95 | 96 | @Override 97 | public BossBarAPI.Style getStyle() { 98 | return this.style; 99 | } 100 | 101 | @Override 102 | public void setStyle(BossBarAPI.Style style) { 103 | if (style == null) { throw new IllegalArgumentException("style cannot be null"); } 104 | if (style != this.style) { 105 | this.style = style; 106 | sendPacket(4, null); 107 | } 108 | } 109 | 110 | @Override 111 | public void setProperty(BossBarAPI.Property property, boolean flag) { 112 | switch (property) { 113 | case DARKEN_SKY: 114 | darkenSky = flag; 115 | break; 116 | case PLAY_MUSIC: 117 | playMusic = flag; 118 | break; 119 | case CREATE_FOG: 120 | createFog = flag; 121 | break; 122 | default: 123 | break; 124 | } 125 | sendPacket(5, null); 126 | } 127 | 128 | @Override 129 | public String getMessage() { 130 | return this.message; 131 | } 132 | 133 | @Override 134 | public void setMessage(String message) { 135 | if (message == null) { throw new IllegalArgumentException("message cannot be null"); } 136 | if (!message.startsWith("{") || !message.endsWith("}")) { 137 | throw new IllegalArgumentException("Invalid JSON"); 138 | } 139 | if (!message.equals(this.message)) { 140 | this.message = message; 141 | sendPacket(3, null); 142 | } 143 | } 144 | 145 | @Override 146 | public float getProgress() { 147 | return progress; 148 | } 149 | 150 | @Override 151 | public void setProgress(float progress) { 152 | if (progress > 1) { 153 | progress = progress / 100F; 154 | } 155 | if (progress != this.progress) { 156 | this.progress = progress; 157 | sendPacket(2, null); 158 | } 159 | } 160 | 161 | @Override 162 | public boolean isVisible() { 163 | return this.visible; 164 | } 165 | 166 | @Override 167 | public void setVisible(boolean flag) { 168 | if (flag != this.visible) { 169 | this.visible = flag; 170 | sendPacket(flag ? 0 : 1, null); 171 | } 172 | } 173 | 174 | void sendPacket(int action, Player player) { 175 | try { 176 | Object packet = PacketPlayOutBoss.newInstance(); 177 | PacketPlayOutBossFieldResolver.resolve("a").set(packet, this.uuid); 178 | PacketPlayOutBossFieldResolver.resolve("b").set(packet, PacketPlayOutBossAction.getEnumConstants()[action]); 179 | PacketPlayOutBossFieldResolver.resolve("c").set(packet, serialize(this.message)); 180 | PacketPlayOutBossFieldResolver.resolve("d").set(packet, this.progress); 181 | PacketPlayOutBossFieldResolver.resolve("e").set(packet, BossBattleBarColor.getEnumConstants()[this.color.ordinal()]); 182 | PacketPlayOutBossFieldResolver.resolve("f").set(packet, BossBattleBarStyle.getEnumConstants()[this.style.ordinal()]); 183 | PacketPlayOutBossFieldResolver.resolve("g").set(packet, this.darkenSky); 184 | PacketPlayOutBossFieldResolver.resolve("h").set(packet, this.playMusic); 185 | PacketPlayOutBossFieldResolver.resolve("i").set(packet, this.createFog); 186 | 187 | if (player != null) { 188 | BossBarAPI.sendPacket(player, packet); 189 | } else { 190 | for (Player player1 : this.getPlayers()) { 191 | BossBarAPI.sendPacket(player1, packet); 192 | } 193 | } 194 | } catch (ReflectiveOperationException e) { 195 | throw new RuntimeException(e); 196 | } 197 | } 198 | 199 | //Deprecated methods 200 | 201 | @Override 202 | public float getMaxHealth() { 203 | return 100F; 204 | } 205 | 206 | @Override 207 | public void setHealth(float percentage) { 208 | setProgress(percentage / 100F); 209 | } 210 | 211 | @Override 212 | public float getHealth() { 213 | return getProgress() * 100F; 214 | } 215 | 216 | @Override 217 | public Player getReceiver() { 218 | return null; 219 | } 220 | 221 | @Override 222 | public Location getLocation() { 223 | return null; 224 | } 225 | 226 | @Override 227 | public void updateMovement() { 228 | } 229 | 230 | static Object serialize(String json) throws ReflectiveOperationException { 231 | return ChatSerializerMethodResolver.resolve(new ResolverQuery("a", String.class)).invoke(null, json); 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/reflection/AccessUtil.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar.reflection; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Method; 5 | 6 | public abstract class AccessUtil { 7 | 8 | /** 9 | * Set a specified Field accessible 10 | * 11 | * @param f Field set accessible 12 | */ 13 | public static Field setAccessible(Field f) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { 14 | f.setAccessible(true); 15 | Field modifiersField = Field.class.getDeclaredField("modifiers"); 16 | modifiersField.setAccessible(true); 17 | modifiersField.setInt(f, f.getModifiers() & 0xFFFFFFEF); 18 | return f; 19 | } 20 | 21 | /** 22 | * Set a specified Method accessible 23 | * 24 | * @param m Method set accessible 25 | */ 26 | public static Method setAccessible(Method m) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { 27 | m.setAccessible(true); 28 | return m; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/reflection/ClassBuilder.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar.reflection; 2 | 3 | import org.bukkit.Location; 4 | import org.inventivetalent.reflection.minecraft.DataWatcher; 5 | import org.inventivetalent.reflection.minecraft.Minecraft; 6 | 7 | import java.util.UUID; 8 | 9 | import static org.inventivetalent.reflection.minecraft.DataWatcher.V1_9.ValueType.ENTITY_NAME; 10 | import static org.inventivetalent.reflection.minecraft.DataWatcher.V1_9.ValueType.ENTITY_NAME_VISIBLE; 11 | 12 | public abstract class ClassBuilder { 13 | 14 | public static Object buildWitherSpawnPacket(int id, UUID uuid/*UUID*/, Location loc, Object dataWatcher) throws Exception { 15 | Object packet = NMSClass.PacketPlayOutSpawnEntityLiving.newInstance(); 16 | if (Minecraft.VERSION.olderThan(Minecraft.Version.v1_9_R1)) { 17 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("a")).set(packet, id); 18 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("b")).set(packet, 64);// TODO: Find correct entity type id 19 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("c")).set(packet, (int) loc.getX()); 20 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("d")).set(packet, MathUtil.floor(loc.getY() * 32D)); 21 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("e")).set(packet, (int) loc.getZ()); 22 | 23 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("i")).set(packet, (byte) MathUtil.d(loc.getYaw() * 256F / 360F)); 24 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("j")).set(packet, (byte) MathUtil.d(loc.getPitch() * 256F / 360F)); 25 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("k")).set(packet, (byte) MathUtil.d(loc.getPitch() * 256F / 360F)); 26 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("l")).set(packet, dataWatcher); 27 | } else { 28 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("a")).set(packet, id); 29 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("b")).set(packet, uuid); 30 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("c")).set(packet, 64); 31 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("d")).set(packet, loc.getX()); 32 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("e")).set(packet, loc.getY()); 33 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("f")).set(packet, loc.getZ()); 34 | 35 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("j")).set(packet, (byte) MathUtil.d(loc.getYaw() * 256F / 360F)); 36 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("k")).set(packet, (byte) MathUtil.d(loc.getPitch() * 256F / 360F)); 37 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("l")).set(packet, (byte) MathUtil.d(loc.getPitch() * 256F / 360F)); 38 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("m")).set(packet, dataWatcher); 39 | } 40 | 41 | return packet; 42 | } 43 | 44 | public static Object buildNameMetadataPacket(int id, Object dataWatcher, int nameIndex, int visibilityIndex, String name) throws Exception { 45 | // dataWatcher = setDataWatcherValue(dataWatcher, nameIndex, name != null ? name : "");// Pass an empty string to avoid exceptions 46 | // dataWatcher = setDataWatcherValue(dataWatcher, visibilityIndex, (byte) (name != null && !name.isEmpty() ? 1 : 0)); 47 | DataWatcher.setValue(dataWatcher, nameIndex, ENTITY_NAME, name != null ? name : "");// Pass an empty string to avoid exceptions 48 | DataWatcher.setValue(dataWatcher, visibilityIndex, ENTITY_NAME_VISIBLE, Minecraft.VERSION.olderThan(Minecraft.Version.v1_9_R1) ? (byte) (name != null && !name.isEmpty() ? 1 : 0) : (name != null && !name.isEmpty()));//Byte < 1.9, Boolean >= 1.9 49 | Object metaPacket = NMSClass.PacketPlayOutEntityMetadata.getConstructor(int.class, NMSClass.DataWatcher, boolean.class).newInstance(id, dataWatcher, true); 50 | 51 | return metaPacket; 52 | } 53 | 54 | public static Object updateEntityLocation(Object entity, Location loc) throws Exception { 55 | NMSClass.Entity.getDeclaredField("locX").set(entity, loc.getX()); 56 | NMSClass.Entity.getDeclaredField("locY").set(entity, loc.getY()); 57 | NMSClass.Entity.getDeclaredField("locZ").set(entity, loc.getZ()); 58 | return entity; 59 | } 60 | 61 | // public static Object buildDataWatcher(@Nullable Object entity) throws Exception { 62 | // Object dataWatcher = NMSClass.DataWatcher.getConstructor(NMSClass.Entity).newInstance(entity); 63 | // return dataWatcher; 64 | // } 65 | // 66 | // public static Object buildWatchableObject(int index, Object value) throws Exception { 67 | // return buildWatchableObject(getDataWatcherValueType(value), index, value); 68 | // } 69 | // 70 | // public static Object buildWatchableObject(int type, int index, Object value) throws Exception { 71 | // return NMSClass.WatchableObject.getConstructor(int.class, int.class, Object.class).newInstance(type, index, value); 72 | // } 73 | // 74 | // public static Object setDataWatcherValue(Object dataWatcher, int index, Object value) throws Exception { 75 | // Object type = getDataWatcherValueType(value); 76 | // 77 | // Object map = AccessUtil.setAccessible(NMSClass.DataWatcher.getDeclaredField("dataValues")).get(dataWatcher); 78 | // NMUClass.gnu_trove_map_hash_TIntObjectHashMap.getDeclaredMethod("put", int.class, Object.class).invoke(map, index, buildWatchableObject(type, index, value)); 79 | // 80 | // return dataWatcher; 81 | // } 82 | // 83 | // public static Object getDataWatcherValue(Object dataWatcher, int index) throws Exception { 84 | // Object map = AccessUtil.setAccessible(NMSClass.DataWatcher.getDeclaredField("dataValues")).get(dataWatcher); 85 | // Object value = NMUClass.gnu_trove_map_hash_TIntObjectHashMap.getDeclaredMethod("get", int.class).invoke(map, index); 86 | // 87 | // return value; 88 | // } 89 | // 90 | // public static int getWatchableObjectIndex(Object object) throws Exception { 91 | // int index = AccessUtil.setAccessible(NMSClass.WatchableObject.getDeclaredField("b")).getInt(object); 92 | // return index; 93 | // } 94 | // 95 | // public static int getWatchableObjectType(Object object) throws Exception { 96 | // int type = AccessUtil.setAccessible(NMSClass.WatchableObject.getDeclaredField("a")).getInt(object); 97 | // return type; 98 | // } 99 | // 100 | // public static Object getWatchableObjectValue(Object object) throws Exception { 101 | // Object value = AccessUtil.setAccessible(NMSClass.WatchableObject.getDeclaredField("c")).get(object); 102 | // return value; 103 | // } 104 | // 105 | // public static Object getDataWatcherValueType(Object value) { 106 | // int type = 0; 107 | // if (value instanceof Number) { 108 | // if (value instanceof Byte) { 109 | // type = 0; 110 | // } else if (value instanceof Short) { 111 | // type = 1; 112 | // } else if (value instanceof Integer) { 113 | // type = 2; 114 | // } else if (value instanceof Float) { 115 | // type = 3; 116 | // } 117 | // } else if (value instanceof String) { 118 | // type = 4; 119 | // } else if (value != null && value.getClass().equals(NMSClass.ItemStack)) { 120 | // type = 5; 121 | // } else if (value != null && (value.getClass().equals(NMSClass.ChunkCoordinates) || value.getClass().equals(NMSClass.BlockPosition))) { 122 | // type = 6; 123 | // } else if (value != null && value.getClass().equals(NMSClass.Vector3f)) { 124 | // type = 7; 125 | // } 126 | // 127 | // return type; 128 | // } 129 | 130 | public static Object buildArmorStandSpawnPacket(Object armorStand) throws Exception { 131 | Object spawnPacket = NMSClass.PacketPlayOutSpawnEntityLiving.getConstructor(NMSClass.EntityLiving).newInstance(armorStand); 132 | AccessUtil.setAccessible(NMSClass.PacketPlayOutSpawnEntityLiving.getDeclaredField("b")).setInt(spawnPacket, 30); 133 | 134 | return spawnPacket; 135 | } 136 | 137 | public static Object buildTeleportPacket(int id, Location loc, boolean onGround, boolean heightCorrection) throws Exception { 138 | Object packet = NMSClass.PacketPlayOutEntityTeleport.newInstance(); 139 | AccessUtil.setAccessible(NMSClass.PacketPlayOutEntityTeleport.getDeclaredField("a")).set(packet, id); 140 | AccessUtil.setAccessible(NMSClass.PacketPlayOutEntityTeleport.getDeclaredField("b")).set(packet, (int) (loc.getX() * 32D)); 141 | AccessUtil.setAccessible(NMSClass.PacketPlayOutEntityTeleport.getDeclaredField("c")).set(packet, (int) (loc.getY() * 32D)); 142 | AccessUtil.setAccessible(NMSClass.PacketPlayOutEntityTeleport.getDeclaredField("d")).set(packet, (int) (loc.getZ() * 32D)); 143 | AccessUtil.setAccessible(NMSClass.PacketPlayOutEntityTeleport.getDeclaredField("e")).set(packet, (byte) (int) (loc.getYaw() * 256F / 360F)); 144 | AccessUtil.setAccessible(NMSClass.PacketPlayOutEntityTeleport.getDeclaredField("f")).set(packet, (byte) (int) (loc.getPitch() * 256F / 360F)); 145 | 146 | return packet; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/reflection/MathUtil.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar.reflection; 2 | 3 | public abstract class MathUtil { 4 | 5 | public static int floor(double d1) { 6 | int i = (int) d1; 7 | return d1 >= i ? i : i - 1; 8 | } 9 | 10 | public static int d(float f1) { 11 | int i = (int) f1; 12 | return f1 >= i ? i : i - 1; 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/reflection/NMSClass.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar.reflection; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | public abstract class NMSClass { 6 | 7 | private static boolean initialized; 8 | 9 | public static Class Entity; 10 | public static Class EntityLiving; 11 | public static Class EntityInsentient; 12 | public static Class EntityAgeable; 13 | public static Class EntityHorse; 14 | public static Class EntityArmorStand; 15 | public static Class EntityWither; 16 | public static Class EntityWitherSkull; 17 | public static Class EntitySlime; 18 | public static Class World; 19 | public static Class PacketPlayOutSpawnEntityLiving; 20 | public static Class PacketPlayOutSpawnEntity; 21 | public static Class PacketPlayOutEntityDestroy; 22 | public static Class PacketPlayOutAttachEntity; 23 | public static Class PacketPlayOutEntityTeleport; 24 | public static Class PacketPlayOutEntityMetadata; 25 | public static Class DataWatcher; 26 | public static Class WatchableObject; 27 | public static Class ItemStack; 28 | public static Class ChunkCoordinates; 29 | public static Class BlockPosition; 30 | public static Class Vector3f; 31 | public static Class EnumEntityUseAction; 32 | 33 | static { 34 | if (!initialized) { 35 | for (Field f : NMSClass.class.getDeclaredFields()) { 36 | if (f.getType().equals(Class.class)) { 37 | try { 38 | f.set(null, Reflection.getNMSClassWithException(f.getName())); 39 | } catch (Exception e) { 40 | if (f.getName().equals("WatchableObject")) { 41 | try { 42 | f.set(null, Reflection.getNMSClassWithException("DataWatcher$WatchableObject")); 43 | } catch (Exception e1) { 44 | e1.printStackTrace(); 45 | } 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/reflection/NMUClass.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar.reflection; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | public abstract class NMUClass { 6 | 7 | private static boolean initialized; 8 | 9 | public static Class gnu_trove_map_TIntObjectMap; 10 | public static Class gnu_trove_map_hash_TIntObjectHashMap; 11 | public static Class gnu_trove_impl_hash_THash; 12 | public static Class io_netty_channel_Channel; 13 | 14 | static { 15 | if (!initialized) { 16 | for (Field f : NMUClass.class.getDeclaredFields()) { 17 | if (f.getType().equals(Class.class)) { 18 | try { 19 | String name = f.getName().replace("_", "."); 20 | if (Reflection.getVersion().contains("1_8")) { 21 | f.set(null, Class.forName(name)); 22 | } else { 23 | f.set(null, Class.forName("net.minecraft.util." + name)); 24 | } 25 | } catch (Exception e) { 26 | e.printStackTrace(); 27 | } 28 | } 29 | } 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/org/inventivetalent/bossbar/reflection/Reflection.java: -------------------------------------------------------------------------------- 1 | package org.inventivetalent.bossbar.reflection; 2 | 3 | import org.bukkit.Bukkit; 4 | 5 | import java.lang.reflect.Field; 6 | import java.lang.reflect.Method; 7 | 8 | public abstract class Reflection { 9 | 10 | public static String getVersion() { 11 | String name = Bukkit.getServer().getClass().getPackage().getName(); 12 | String version = name.substring(name.lastIndexOf('.') + 1) + "."; 13 | return version; 14 | } 15 | 16 | public static Class getNMSClass(String className) { 17 | String fullName = "net.minecraft.server." + getVersion() + className; 18 | Class clazz = null; 19 | try { 20 | clazz = Class.forName(fullName); 21 | } catch (Exception e) { 22 | e.printStackTrace(); 23 | } 24 | return clazz; 25 | } 26 | 27 | public static Class getNMSClassWithException(String className) throws Exception { 28 | String fullName = "net.minecraft.server." + getVersion() + className; 29 | Class clazz = Class.forName(fullName); 30 | return clazz; 31 | } 32 | 33 | public static Class getOBCClass(String className) { 34 | String fullName = "org.bukkit.craftbukkit." + getVersion() + className; 35 | Class clazz = null; 36 | try { 37 | clazz = Class.forName(fullName); 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } 41 | return clazz; 42 | } 43 | 44 | public static Object getHandle(Object obj) { 45 | try { 46 | return getMethod(obj.getClass(), "getHandle", new Class[0]).invoke(obj, new Object[0]); 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | } 50 | return null; 51 | } 52 | 53 | public static Field getField(Class clazz, String name) { 54 | try { 55 | Field field = clazz.getDeclaredField(name); 56 | field.setAccessible(true); 57 | return field; 58 | } catch (Exception e) { 59 | e.printStackTrace(); 60 | } 61 | return null; 62 | } 63 | 64 | public static Method getMethod(Class clazz, String name, Class... args) { 65 | for (Method m : clazz.getMethods()) { 66 | if (m.getName().equals(name) && (args.length == 0 || ClassListEqual(args, m.getParameterTypes()))) { 67 | m.setAccessible(true); 68 | return m; 69 | } 70 | } 71 | return null; 72 | } 73 | 74 | public static boolean ClassListEqual(Class[] l1, Class[] l2) { 75 | boolean equal = true; 76 | if (l1.length != l2.length) { return false; } 77 | for (int i = 0; i < l1.length; i++) { 78 | if (l1[i] != l2[i]) { 79 | equal = false; 80 | break; 81 | } 82 | } 83 | return equal; 84 | } 85 | } 86 | --------------------------------------------------------------------------------