From 961285805890e5f74e21dedc64421f4f6e9c2270 Mon Sep 17 00:00:00 2001 From: Electroid Date: Thu, 6 Jul 2017 18:14:22 -0700 Subject: [PATCH] Add 1.7 and 1.8 boss bar support --- .../bukkit/listeners/PlayerListener.java | 5 +- .../tc/oc/pgm/bossbar/BossBarMatchModule.java | 3 +- .../bukkit/bossbar/BossBarFactory.java | 19 +- .../bukkit/bossbar/BossBarFactoryImpl.java | 20 +- .../commons/bukkit/bossbar/LegacyBossBar.java | 176 ++++++++++++++++++ .../bukkit/bossbar/RenderedBossBar.java | 3 +- .../tc/oc/commons/bukkit/util/NMSHacks.java | 36 ++++ 7 files changed, 251 insertions(+), 11 deletions(-) create mode 100644 Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/LegacyBossBar.java diff --git a/Lobby/src/main/java/tc/oc/lobby/bukkit/listeners/PlayerListener.java b/Lobby/src/main/java/tc/oc/lobby/bukkit/listeners/PlayerListener.java index f619114..cd71d98 100644 --- a/Lobby/src/main/java/tc/oc/lobby/bukkit/listeners/PlayerListener.java +++ b/Lobby/src/main/java/tc/oc/lobby/bukkit/listeners/PlayerListener.java @@ -147,10 +147,9 @@ public class PlayerListener implements PluginFacet, Listener { new Component(ChatColor.GOLD, ChatColor.BOLD).extra(generalFormatter.publicHostname()) )); - final BossBar bar = bossBarFactory.createBossBar(renderer.render(news, player), BarColor.BLUE, BarStyle.SOLID); + final BossBar bar = bossBarFactory.createBossBar(player, renderer.render(news, player), BarColor.BLUE, BarStyle.SOLID); bar.setProgress(1); - bar.addPlayer(player); - bar.show(); + bar.setVisible(true); } if(!player.hasPermission("lobby.disabled-permissions-exempt")) { diff --git a/PGM/src/main/java/tc/oc/pgm/bossbar/BossBarMatchModule.java b/PGM/src/main/java/tc/oc/pgm/bossbar/BossBarMatchModule.java index 53e79dc..29ce62b 100644 --- a/PGM/src/main/java/tc/oc/pgm/bossbar/BossBarMatchModule.java +++ b/PGM/src/main/java/tc/oc/pgm/bossbar/BossBarMatchModule.java @@ -113,9 +113,8 @@ public class BossBarMatchModule extends MatchModule implements Listener { View(BossBarSource source, Player viewer) { this.source = source; this.viewer = viewer; - this.bar = bossBarFactory.createBossBar(Components.blank(), BarColor.WHITE, BarStyle.SOLID); + this.bar = bossBarFactory.createBossBar(viewer, Components.blank(), BarColor.WHITE, BarStyle.SOLID); render(); - bar.addPlayer(viewer); } void destroy() { diff --git a/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/BossBarFactory.java b/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/BossBarFactory.java index b507b7a..d06b557 100644 --- a/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/BossBarFactory.java +++ b/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/BossBarFactory.java @@ -5,11 +5,28 @@ import org.bukkit.boss.BarColor; import org.bukkit.boss.BarFlag; import org.bukkit.boss.BarStyle; import org.bukkit.boss.BossBar; +import org.bukkit.entity.Player; +import tc.oc.minecraft.protocol.MinecraftVersion; + +import static tc.oc.minecraft.protocol.MinecraftVersion.MINECRAFT_1_9; + public interface BossBarFactory { BossBar createBossBar(); - BossBar createBossBar(BaseComponent title, BarColor color, BarStyle style, BarFlag...flags); + BossBar createBossBar(BaseComponent title, BarColor color, BarStyle style, boolean legacy, BarFlag...flags); + + default BossBar createBossBar(Player player, BaseComponent title, BarColor color, BarStyle style, BarFlag...flags) { + BossBar bar = createBossBar(title, color, style, MinecraftVersion.lessThan(MINECRAFT_1_9, player.getProtocolVersion()), flags); + bar.addPlayer(player); + return bar; + } + + default BossBar createBossBar(BaseComponent title, BarColor color, BarStyle style, BarFlag...flags) { + return createBossBar(title, color, style, false, flags); + } BossBar createRenderedBossBar(); + + BossBar createLegacyBossBar(); } diff --git a/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/BossBarFactoryImpl.java b/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/BossBarFactoryImpl.java index 8e790f2..f4dce9f 100644 --- a/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/BossBarFactoryImpl.java +++ b/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/BossBarFactoryImpl.java @@ -17,15 +17,24 @@ public class BossBarFactoryImpl implements BossBarFactory { private final Server server; private final Provider renderedBossBarProvider; + private final Provider legacyBossBarProvider; - @Inject BossBarFactoryImpl(Server server, Provider renderedBossBarProvider) { + @Inject BossBarFactoryImpl(Server server, Provider renderedBossBarProvider, Provider legacyBossBarProvider) { this.server = server; this.renderedBossBarProvider = renderedBossBarProvider; + this.legacyBossBarProvider = legacyBossBarProvider; } @Override - public BossBar createBossBar(BaseComponent title, BarColor color, BarStyle style, BarFlag... flags) { - return server.createBossBar(title, color, style, flags); + public BossBar createBossBar(BaseComponent title, BarColor color, BarStyle style, boolean legacy, BarFlag... flags) { + BossBar bar; + if(legacy) { + bar = createLegacyBossBar(); + bar.setTitle(title); + } else { + bar = server.createBossBar(title, color, style, flags); + } + return bar; } @Override @@ -37,4 +46,9 @@ public class BossBarFactoryImpl implements BossBarFactory { public BossBar createRenderedBossBar() { return renderedBossBarProvider.get(); } + + @Override + public BossBar createLegacyBossBar() { + return legacyBossBarProvider.get(); + } } diff --git a/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/LegacyBossBar.java b/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/LegacyBossBar.java new file mode 100644 index 0000000..f68446c --- /dev/null +++ b/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/LegacyBossBar.java @@ -0,0 +1,176 @@ +package tc.oc.commons.bukkit.bossbar; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import net.md_5.bungee.api.chat.BaseComponent; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarFlag; +import org.bukkit.boss.BarStyle; +import org.bukkit.boss.BossBar; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitScheduler; +import tc.oc.commons.bukkit.chat.ComponentRenderContext; +import tc.oc.commons.bukkit.util.NMSHacks; +import tc.oc.commons.core.chat.Components; + +import javax.inject.Inject; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class LegacyBossBar implements BossBar { + + private final ComponentRenderContext renderer; + private final Map views = new HashMap<>(); + private final Map tasks = new HashMap<>(); + + private BaseComponent title = Components.blank(); + private double progress = 1; + private boolean visible = true; + + @Inject LegacyBossBar(ComponentRenderContext renderer) { + this.renderer = renderer; + } + + @Override + public BaseComponent getTitle() { + return title; + } + + @Override + public BarColor getColor() { + return BarColor.PURPLE; + } + + @Override + public BarStyle getStyle() { + return BarStyle.SOLID; + } + + @Override + public double getProgress() { + return progress; + } + + @Override + public boolean isVisible() { + return visible; + } + + @Override + public List getPlayers() { + return ImmutableList.copyOf(views.keySet()); + } + + @Override + public void setTitle(BaseComponent title) { + this.title = title; + views.forEach((player, wither) -> wither.name(player, renderer.renderLegacy(title, player), isVisible())); + } + + @Override + public void setProgress(double progress) { + this.progress = progress; + views.forEach((player, wither) -> wither.health(player, progress, isVisible())); + } + + @Override + public void addPlayer(Player player) { + if(!views.containsKey(player)) { + NMSHacks.FakeWither view = new NMSHacks.FakeWither(player.getWorld(), renderer.renderLegacy(title, player)); + views.put(player, view); + int task = scheduler().scheduleSyncRepeatingTask(plugin(), () -> { if(isVisible()) view.teleport(player, witherLocation(player)); }, 0, 1); + tasks.put(player, task); + if(isVisible()) { + view.spawn(player, witherLocation(player)); + } + } + } + + @Override + public void removePlayer(Player player) { + int task = tasks.remove(player); + if(task != -1) { + scheduler().cancelTask(task); + } + NMSHacks.FakeWither view = views.remove(player); + if(view != null) { + view.destroy(player); + } + } + + @Override + public void removeAll() { + ImmutableSet.copyOf(views.keySet()).forEach(this::removePlayer); + views.clear(); + } + + @Override + public void setVisible(boolean visible) { + boolean previous = isVisible(); + this.visible = visible; + if(previous && !visible) { + views.forEach((player, wither) -> wither.destroy(player)); + } else if(!previous && visible) { + views.forEach((player, wither) -> wither.spawn(player, witherLocation(player))); + } + } + + @Override + public void update(BaseComponent title, double progress, BarColor color, BarStyle style, Set flags) { + this.title = title; + this.progress = progress; + views.forEach((player, wither) -> wither.update(player, renderer.renderLegacy(title, player), progress, isVisible())); + } + + @Override + public void show() { + setVisible(true); + } + + @Override + public void hide() { + setVisible(false); + } + + @Override + public void setColor(BarColor color) {} + + @Override + public void setStyle(BarStyle style) {} + + @Override + public void setFlags(Set flags) {} + + @Override + public void removeFlag(BarFlag flag) {} + + @Override + public void addFlag(BarFlag flag) {} + + @Override + public boolean hasFlag(BarFlag flag) { + return false; + } + + protected Location witherLocation(Player player) { + Location eye = player.getEyeLocation().clone(); + eye.setPitch(eye.getPitch() - 20); + return player.getEyeLocation().add(eye.getDirection().multiply(32)); + } + + // HACK + + protected Plugin plugin() { + return Bukkit.getPluginManager().getPlugin("Commons"); + } + + protected BukkitScheduler scheduler() { + return Bukkit.getScheduler(); + } + +} diff --git a/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/RenderedBossBar.java b/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/RenderedBossBar.java index da3850c..e77756d 100644 --- a/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/RenderedBossBar.java +++ b/Util/bukkit/src/main/java/tc/oc/commons/bukkit/bossbar/RenderedBossBar.java @@ -117,9 +117,8 @@ public class RenderedBossBar implements BossBar { @Override public void addPlayer(Player player) { if(!views.containsKey(player)) { - final BossBar view = bossBarFactory.createBossBar(renderer.render(title, player), color, style, flags.toArray(new BarFlag[flags.size()])); + final BossBar view = bossBarFactory.createBossBar(player, renderer.render(title, player), color, style, flags.toArray(new BarFlag[flags.size()])); view.setVisible(visibile); - view.addPlayer(player); views.put(player, view); } } diff --git a/Util/bukkit/src/main/java/tc/oc/commons/bukkit/util/NMSHacks.java b/Util/bukkit/src/main/java/tc/oc/commons/bukkit/util/NMSHacks.java index 6891147..38a857d 100644 --- a/Util/bukkit/src/main/java/tc/oc/commons/bukkit/util/NMSHacks.java +++ b/Util/bukkit/src/main/java/tc/oc/commons/bukkit/util/NMSHacks.java @@ -28,6 +28,7 @@ import net.minecraft.server.EntityLiving; import net.minecraft.server.EntityPlayer; import net.minecraft.server.EntityTrackerEntry; import net.minecraft.server.EntityTypes; +import net.minecraft.server.EntityWither; import net.minecraft.server.EntityZombie; import net.minecraft.server.EnumGamemode; import net.minecraft.server.EnumHand; @@ -92,6 +93,7 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Firework; import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; +import org.bukkit.entity.Wither; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.material.MaterialData; import org.bukkit.plugin.Plugin; @@ -403,6 +405,40 @@ public class NMSHacks { } } + public static class FakeWither extends FakeLivingEntity { + + public FakeWither(World world, @Nullable String name) { + super(new EntityWither(((CraftWorld) world).getHandle())); + + entity.setNoAI(true); + entity.setNoGravity(true); + entity.setSilent(true); + entity.setInvulnerable(true); + entity.setInvisible(true); + entity.setCustomNameVisible(true); + entity.g(890); // Required to make the wither extremely small + + if(name != null) { + entity.setCustomName(name); + } + } + + public void update(Player viewer, @Nullable String name, @Nullable Double percent, boolean send) { + if(name != null) entity.setCustomName(name); + if(percent != null) entity.setHealth(percent.floatValue() * entity.getMaxHealth()); + if(send) sendPacket(viewer, entityMetadataPacket(entity, true)); + } + + public void name(Player viewer, String name, boolean update) { + update(viewer, name, null, update); + } + + public void health(Player viewer, double percent, boolean update) { + update(viewer, null, percent, update); + } + + } + public static class FakeZombie extends FakeLivingEntity { public FakeZombie(World world, boolean invisible) { super(new EntityZombie(((CraftWorld) world).getHandle()));