| package us.myles.ViaVersion.boss; |
| |
| import io.netty.buffer.ByteBuf; |
| import io.netty.buffer.Unpooled; |
| import lombok.Getter; |
| import lombok.RequiredArgsConstructor; |
| import org.apache.commons.lang.Validate; |
| import org.bukkit.entity.Player; |
| import us.myles.ViaVersion.api.ViaVersion; |
| import us.myles.ViaVersion.api.boss.BossBar; |
| import us.myles.ViaVersion.api.boss.BossColor; |
| import us.myles.ViaVersion.api.boss.BossFlag; |
| import us.myles.ViaVersion.api.boss.BossStyle; |
| import us.myles.ViaVersion.packets.PacketType; |
| import us.myles.ViaVersion.transformers.OutgoingTransformer; |
| import us.myles.ViaVersion.util.PacketUtil; |
| |
| import java.util.*; |
| |
| @Getter |
| public class ViaBossBar implements BossBar { |
| private UUID uuid; |
| private String title; |
| private float health; |
| private BossColor color; |
| private BossStyle style; |
| private Set<UUID> players; |
| private boolean visible; |
| private Set<BossFlag> flags; |
| |
| public ViaBossBar(String title, float health, BossColor color, BossStyle style) { |
| Validate.notNull(title, "Title cannot be null"); |
| Validate.isTrue((health >= 0 && health <= 1), "Health must be between 0 and 1"); |
| this.uuid = UUID.randomUUID(); |
| this.title = title; |
| this.health = health; |
| this.color = color == null ? BossColor.PURPLE : color; |
| this.style = style == null ? BossStyle.SOLID : style; |
| this.players = new HashSet<>(); |
| this.flags = new HashSet<>(); |
| visible = true; |
| } |
| |
| @Override |
| public void setTitle(String title) { |
| Validate.notNull(title, "Title cannot be null"); |
| this.title = title; |
| sendPacket(UpdateAction.UPDATE_TITLE); |
| } |
| |
| @Override |
| public void setHealth(float health) { |
| Validate.isTrue((health >= 0 && health <= 1), "Health must be between 0 and 1"); |
| this.health = health; |
| sendPacket(UpdateAction.UPDATE_HEALTH); |
| } |
| |
| @Override |
| public BossColor getColor() { |
| return color; |
| } |
| |
| @Override |
| public void setColor(BossColor color) { |
| Validate.notNull(color, "Color cannot be null"); |
| this.color = color; |
| sendPacket(UpdateAction.UPDATE_STYLE); |
| } |
| |
| @Override |
| public void setStyle(BossStyle style) { |
| Validate.notNull(style, "Style cannot be null"); |
| this.style = style; |
| sendPacket(UpdateAction.UPDATE_STYLE); |
| } |
| |
| @Override |
| public void addPlayer(Player player) { |
| if (player != null && !players.contains(player.getUniqueId())) { |
| players.add(player.getUniqueId()); |
| if (visible) |
| sendPacket(player.getUniqueId(), getPacket(UpdateAction.ADD)); |
| } |
| } |
| |
| @Override |
| public void removePlayer(Player player) { |
| if (player != null && players.contains(player.getUniqueId())) { |
| players.remove(player.getUniqueId()); |
| sendPacket(player.getUniqueId(), getPacket(UpdateAction.REMOVE)); |
| } |
| } |
| |
| @Override |
| public void addFlag(BossFlag flag) { |
| if (!hasFlag(flag)) |
| flags.add(flag); |
| sendPacket(UpdateAction.UPDATE_FLAGS); |
| } |
| |
| @Override |
| public void removeFlag(BossFlag flag) { |
| if (hasFlag(flag)) |
| flags.remove(flag); |
| sendPacket(UpdateAction.UPDATE_FLAGS); |
| } |
| |
| @Override |
| public boolean hasFlag(BossFlag flag) { |
| return flags.contains(flag); |
| } |
| |
| @Override |
| public Set<UUID> getPlayers() { |
| return Collections.unmodifiableSet(players); |
| } |
| |
| @Override |
| public void show() { |
| setVisible(true); |
| } |
| |
| @Override |
| public void hide() { |
| setVisible(false); |
| } |
| |
| @Override |
| public boolean isVisible() { |
| return visible; |
| } |
| |
| private void setVisible(boolean value) { |
| if (visible != value) { |
| visible = value; |
| sendPacket(value ? UpdateAction.ADD : UpdateAction.REMOVE); |
| } |
| } |
| |
| private void sendPacket(UpdateAction action) { |
| ByteBuf buf = getPacket(action); |
| for (UUID uuid : new ArrayList<>(players)) |
| sendPacket(uuid, buf); |
| } |
| |
| private void sendPacket(UUID uuid, ByteBuf buf) { |
| if (!ViaVersion.getInstance().isPorted(uuid)) { |
| players.remove(uuid); |
| return; |
| } |
| ViaVersion.getInstance().sendRawPacket(uuid, buf); |
| } |
| |
| private ByteBuf getPacket(UpdateAction action) { |
| ByteBuf buf = Unpooled.buffer(); |
| PacketUtil.writeVarInt(PacketType.PLAY_BOSS_BAR.getNewPacketID(), buf); |
| PacketUtil.writeUUID(uuid, buf); |
| PacketUtil.writeVarInt(action.getId(), buf); |
| switch (action) { |
| case ADD: |
| PacketUtil.writeString(fixJson(title), buf); |
| buf.writeFloat(health); |
| PacketUtil.writeVarInt(color.getId(), buf); |
| PacketUtil.writeVarInt(style.getId(), buf); |
| buf.writeByte(flagToBytes()); |
| break; |
| case REMOVE: |
| break; |
| case UPDATE_HEALTH: |
| buf.writeFloat(health); |
| break; |
| case UPDATE_TITLE: |
| PacketUtil.writeString(fixJson(title), buf); |
| break; |
| case UPDATE_STYLE: |
| PacketUtil.writeVarInt(color.getId(), buf); |
| PacketUtil.writeVarInt(style.getId(), buf); |
| break; |
| case UPDATE_FLAGS: |
| buf.writeByte(flagToBytes()); |
| break; |
| } |
| |
| return buf; |
| } |
| |
| private int flagToBytes() { |
| int bitmask = 0; |
| for (BossFlag flag : flags) |
| bitmask |= flag.getId(); |
| return bitmask; |
| } |
| |
| private String fixJson(String text) { |
| return OutgoingTransformer.fixJson(text); |
| } |
| |
| @RequiredArgsConstructor |
| @Getter |
| private enum UpdateAction { |
| ADD(0), |
| REMOVE(1), |
| UPDATE_HEALTH(2), |
| UPDATE_TITLE(3), |
| UPDATE_STYLE(4), |
| UPDATE_FLAGS(5); |
| |
| private final int id; |
| } |
| } |