Add 1.7 and 1.8 boss bar support

This commit is contained in:
Electroid 2017-07-06 18:14:22 -07:00
parent 6e666e461c
commit 9612858058
7 changed files with 251 additions and 11 deletions

View File

@ -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")) {

View File

@ -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() {

View File

@ -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();
}

View File

@ -17,15 +17,24 @@ public class BossBarFactoryImpl implements BossBarFactory {
private final Server server;
private final Provider<RenderedBossBar> renderedBossBarProvider;
private final Provider<LegacyBossBar> legacyBossBarProvider;
@Inject BossBarFactoryImpl(Server server, Provider<RenderedBossBar> renderedBossBarProvider) {
@Inject BossBarFactoryImpl(Server server, Provider<RenderedBossBar> renderedBossBarProvider, Provider<LegacyBossBar> 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();
}
}

View File

@ -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<Player, NMSHacks.FakeWither> views = new HashMap<>();
private final Map<Player, Integer> 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<Player> 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<BarFlag> 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<BarFlag> 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();
}
}

View File

@ -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);
}
}

View File

@ -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<EntityWither> {
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<EntityZombie> {
public FakeZombie(World world, boolean invisible) {
super(new EntityZombie(((CraftWorld) world).getHandle()));