mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-08 09:27:58 +01:00
Add boss bar implementations
This commit is contained in:
parent
cfa9cffe87
commit
aff04c0e0d
@ -1,6 +1,7 @@
|
||||
package net.minestom.server;
|
||||
|
||||
import net.minestom.server.advancements.AdvancementManager;
|
||||
import net.minestom.server.adventure.BossBarManager;
|
||||
import net.minestom.server.benchmark.BenchmarkManager;
|
||||
import net.minestom.server.command.CommandManager;
|
||||
import net.minestom.server.data.DataManager;
|
||||
@ -115,6 +116,7 @@ public final class MinecraftServer {
|
||||
private static DimensionTypeManager dimensionTypeManager;
|
||||
private static BiomeManager biomeManager;
|
||||
private static AdvancementManager advancementManager;
|
||||
private static BossBarManager bossBarManager;
|
||||
|
||||
private static ExtensionManager extensionManager;
|
||||
|
||||
@ -180,6 +182,7 @@ public final class MinecraftServer {
|
||||
dimensionTypeManager = new DimensionTypeManager();
|
||||
biomeManager = new BiomeManager();
|
||||
advancementManager = new AdvancementManager();
|
||||
bossBarManager = new BossBarManager();
|
||||
|
||||
updateManager = new UpdateManager();
|
||||
|
||||
@ -427,6 +430,16 @@ public final class MinecraftServer {
|
||||
return connectionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the boss bar manager.
|
||||
*
|
||||
* @return the boss bar manager
|
||||
*/
|
||||
public static BossBarManager getBossBarManager() {
|
||||
checkInitStatus(bossBarManager);
|
||||
return bossBarManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object handling the client packets processing.
|
||||
* <p>
|
||||
|
223
src/main/java/net/minestom/server/adventure/BossBarManager.java
Normal file
223
src/main/java/net/minestom/server/adventure/BossBarManager.java
Normal file
@ -0,0 +1,223 @@
|
||||
package net.minestom.server.adventure;
|
||||
|
||||
import com.google.common.collect.MapMaker;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.bossbar.BossBar.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.GlobalEventHandler;
|
||||
import net.minestom.server.event.player.PlayerDisconnectEvent;
|
||||
import net.minestom.server.network.packet.server.play.BossBarPacket;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Handler;
|
||||
|
||||
import static net.minestom.server.network.packet.server.play.BossBarPacket.Action.*;
|
||||
|
||||
/**
|
||||
* Manages all boss bars known to this Minestom instance. This implementation is heavily
|
||||
* based on <a href="https://github.com/VelocityPowered/Velocity">Velocity</a>'s
|
||||
* boss bar management system.
|
||||
*/
|
||||
public class BossBarManager implements BossBar.Listener {
|
||||
private final Map<BossBar, Holder> bars;
|
||||
|
||||
/**
|
||||
* Creates a new boss bar manager.
|
||||
*/
|
||||
public BossBarManager() {
|
||||
this.bars = new MapMaker().weakKeys().makeMap();
|
||||
|
||||
MinecraftServer.getGlobalEventHandler().addEventCallback(PlayerDisconnectEvent.class, this::onDisconnect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified player to the boss bar's viewers and spawns the boss bar, registering the
|
||||
* boss bar if needed.
|
||||
*
|
||||
* @param player the intended viewer
|
||||
* @param bar the boss bar to show
|
||||
*/
|
||||
public void addBossBar(@NotNull Player player, @NotNull BossBar bar) {
|
||||
Holder holder = this.getOrCreateHandler(bar);
|
||||
|
||||
if (holder.players.add(player.getUuid())) {
|
||||
player.getPlayerConnection().sendPacket(holder.createAddPacket());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Removes the specified player from the boss bar's viewers and despawns the boss bar.
|
||||
*
|
||||
* @param player the intended viewer
|
||||
* @param bar the boss bar to hide
|
||||
*/
|
||||
|
||||
public void removeBossBar(@NotNull Player player, @NotNull BossBar bar) {
|
||||
Holder holder = this.getOrCreateHandler(bar);
|
||||
|
||||
if (holder.players.remove(player.getUuid())) {
|
||||
player.getPlayerConnection().sendPacket(holder.createRemovePacket());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bossBarNameChanged(@NonNull BossBar bar, @NonNull Component oldName, @NonNull Component newName) {
|
||||
Holder holder = this.bars.get(bar);
|
||||
this.updatePlayers(holder.createTitleUpdate(newName), holder.players);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bossBarProgressChanged(@NonNull BossBar bar, float oldProgress, float newProgress) {
|
||||
Holder holder = this.bars.get(bar);
|
||||
this.updatePlayers(holder.createPercentUpdate(newProgress), holder.players);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bossBarColorChanged(@NonNull BossBar bar, @NonNull Color oldColor, @NonNull Color newColor) {
|
||||
Holder holder = this.bars.get(bar);
|
||||
this.updatePlayers(holder.createColorUpdate(newColor), holder.players);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bossBarOverlayChanged(@NonNull BossBar bar, BossBar.@NonNull Overlay oldOverlay, BossBar.@NonNull Overlay newOverlay) {
|
||||
Holder holder = this.bars.get(bar);
|
||||
this.updatePlayers(holder.createOverlayUpdate(newOverlay), holder.players);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bossBarFlagsChanged(@NonNull BossBar bar, @NonNull Set<BossBar.Flag> flagsAdded, @NonNull Set<BossBar.Flag> flagsRemoved) {
|
||||
Holder holder = this.bars.get(bar);
|
||||
this.updatePlayers(holder.createFlagsUpdate(), holder.players);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the packet to all players in the set, removing them if they no longer exist
|
||||
* in the connection manager.
|
||||
*
|
||||
* @param packet the packet
|
||||
* @param players the players
|
||||
*/
|
||||
private void updatePlayers(BossBarPacket packet, Set<UUID> players) {
|
||||
Iterator<UUID> iterator = players.iterator();
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Player player = MinecraftServer.getConnectionManager().getPlayer(iterator.next());
|
||||
|
||||
if (player == null) {
|
||||
iterator.remove();
|
||||
} else {
|
||||
player.getPlayerConnection().sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or creates a handler for this bar.
|
||||
*
|
||||
* @param bar the bar
|
||||
*
|
||||
* @return the handler
|
||||
*/
|
||||
private @NotNull Holder getOrCreateHandler(@NotNull BossBar bar) {
|
||||
Holder holder = this.bars.computeIfAbsent(bar, Holder::new);
|
||||
|
||||
if (!holder.registered) {
|
||||
bar.addListener(this);
|
||||
holder.registered = true;
|
||||
}
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player disconnects. This removes the player from any boss bars they
|
||||
* may be subscribed to.
|
||||
*
|
||||
* @param event the event
|
||||
*/
|
||||
private void onDisconnect(@NotNull PlayerDisconnectEvent event) {
|
||||
for (Holder holder : this.bars.values()) {
|
||||
holder.players.remove(event.getPlayer().getUuid());
|
||||
}
|
||||
}
|
||||
|
||||
private static class Holder {
|
||||
protected final UUID uuid;
|
||||
protected final BossBar bar;
|
||||
protected final Set<UUID> players;
|
||||
protected boolean registered;
|
||||
|
||||
Holder(@NotNull BossBar bar) {
|
||||
this.uuid = UUID.randomUUID();
|
||||
this.bar = bar;
|
||||
this.players = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap());
|
||||
this.registered = false;
|
||||
}
|
||||
|
||||
BossBarPacket createRemovePacket() {
|
||||
return this.createGenericPacket(REMOVE, packet -> {});
|
||||
}
|
||||
|
||||
BossBarPacket createAddPacket() {
|
||||
return this.createGenericPacket(ADD, packet -> {
|
||||
packet.title = GsonComponentSerializer.gson().serialize(bar.name());
|
||||
packet.color = bar.color().ordinal();
|
||||
packet.division = bar.overlay().ordinal();
|
||||
packet.health = bar.progress();
|
||||
packet.flags = serializeFlags(bar.flags());
|
||||
});
|
||||
}
|
||||
|
||||
BossBarPacket createPercentUpdate(float newPercent) {
|
||||
return this.createGenericPacket(UPDATE_HEALTH, packet -> packet.health = newPercent);
|
||||
}
|
||||
|
||||
BossBarPacket createColorUpdate(@NotNull Color color) {
|
||||
return this.createGenericPacket(UPDATE_STYLE, packet -> {
|
||||
packet.color = color.ordinal();
|
||||
packet.division = bar.overlay().ordinal();
|
||||
});
|
||||
}
|
||||
|
||||
BossBarPacket createTitleUpdate(@NotNull Component title) {
|
||||
return this.createGenericPacket(UPDATE_TITLE, packet -> packet.title = GsonComponentSerializer.gson().serialize(title));
|
||||
}
|
||||
|
||||
BossBarPacket createFlagsUpdate() {
|
||||
return createFlagsUpdate(bar.flags());
|
||||
}
|
||||
|
||||
BossBarPacket createFlagsUpdate(@NotNull Set<Flag> newFlags) {
|
||||
return this.createGenericPacket(UPDATE_FLAGS, packet -> packet.flags = serializeFlags(bar.flags()));
|
||||
}
|
||||
|
||||
BossBarPacket createOverlayUpdate(@NotNull Overlay overlay) {
|
||||
return this.createGenericPacket(UPDATE_STYLE, packet -> {
|
||||
packet.division = overlay.ordinal();
|
||||
packet.color = bar.color().ordinal();
|
||||
});
|
||||
}
|
||||
|
||||
BossBarPacket createGenericPacket(@NotNull BossBarPacket.Action action, @NotNull Consumer<BossBarPacket> consumer) {
|
||||
BossBarPacket packet = new BossBarPacket();
|
||||
packet.uuid = this.uuid;
|
||||
packet.action = action;
|
||||
consumer.accept(packet);
|
||||
return packet;
|
||||
}
|
||||
|
||||
private static byte serializeFlags(@NotNull Set<Flag> flags) {
|
||||
byte val = 0x0;
|
||||
for (Flag flag : flags) {
|
||||
val |= flag.ordinal();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,9 @@ package net.minestom.server.bossbar;
|
||||
|
||||
/**
|
||||
* Represents the displayed color of a {@link BossBar}.
|
||||
* @deprecated Use {@link net.kyori.adventure.bossbar.BossBar}
|
||||
*/
|
||||
@Deprecated
|
||||
public enum BarColor {
|
||||
PINK,
|
||||
BLUE,
|
||||
|
@ -2,7 +2,10 @@ package net.minestom.server.bossbar;
|
||||
|
||||
/**
|
||||
* Used to define the number of segments on a {@link BossBar}.
|
||||
*
|
||||
* @deprecated Use {@link net.kyori.adventure.bossbar.BossBar}
|
||||
*/
|
||||
@Deprecated
|
||||
public enum BarDivision {
|
||||
SOLID,
|
||||
SEGMENT_6,
|
||||
|
@ -19,7 +19,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
* and add the {@link Player} you want using {@link #addViewer(Player)} and remove them using {@link #removeViewer(Player)}.
|
||||
* <p>
|
||||
* You can retrieve all the boss bars of a {@link Player} with {@link #getBossBars(Player)}.
|
||||
*
|
||||
* @deprecated Use {@link net.kyori.adventure.audience.Audience#showBossBar(net.kyori.adventure.bossbar.BossBar)}
|
||||
*/
|
||||
@Deprecated
|
||||
public class BossBar implements Viewable {
|
||||
|
||||
private static final int MAX_BOSSBAR = 7;
|
||||
@ -249,10 +252,10 @@ public class BossBar implements Viewable {
|
||||
BossBarPacket bossBarPacket = new BossBarPacket();
|
||||
bossBarPacket.uuid = uuid;
|
||||
bossBarPacket.action = BossBarPacket.Action.ADD;
|
||||
bossBarPacket.title = title;
|
||||
bossBarPacket.title = title.toString();
|
||||
bossBarPacket.health = progress;
|
||||
bossBarPacket.color = color;
|
||||
bossBarPacket.division = division;
|
||||
bossBarPacket.color = color.ordinal();
|
||||
bossBarPacket.division = division.ordinal();
|
||||
bossBarPacket.flags = flags;
|
||||
player.getPlayerConnection().sendPacket(bossBarPacket);
|
||||
}
|
||||
@ -275,7 +278,7 @@ public class BossBar implements Viewable {
|
||||
BossBarPacket bossBarPacket = new BossBarPacket();
|
||||
bossBarPacket.uuid = uuid;
|
||||
bossBarPacket.action = BossBarPacket.Action.UPDATE_TITLE;
|
||||
bossBarPacket.title = title;
|
||||
bossBarPacket.title = title.toString();
|
||||
sendPacketToViewers(bossBarPacket);
|
||||
}
|
||||
|
||||
@ -291,7 +294,7 @@ public class BossBar implements Viewable {
|
||||
BossBarPacket bossBarPacket = new BossBarPacket();
|
||||
bossBarPacket.uuid = uuid;
|
||||
bossBarPacket.action = BossBarPacket.Action.UPDATE_STYLE;
|
||||
bossBarPacket.color = color;
|
||||
bossBarPacket.color = color.ordinal();
|
||||
sendPacketToViewers(bossBarPacket);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package net.minestom.server.entity;
|
||||
|
||||
import com.google.common.collect.Queues;
|
||||
import net.kyori.adventure.audience.MessageType;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
import net.kyori.adventure.inventory.Book;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@ -12,8 +13,10 @@ import net.kyori.adventure.title.Title;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.advancements.AdvancementTab;
|
||||
import net.minestom.server.attribute.Attribute;
|
||||
import net.minestom.server.attribute.AttributeInstance;
|
||||
import net.minestom.server.bossbar.BossBar;
|
||||
import net.minestom.server.chat.ChatParser;
|
||||
import net.minestom.server.attribute.Attributes;
|
||||
import net.minestom.server.chat.ColoredText;
|
||||
import net.minestom.server.chat.JsonMessage;
|
||||
import net.minestom.server.chat.RichMessage;
|
||||
@ -561,9 +564,9 @@ public class Player extends LivingEntity implements CommandSender {
|
||||
|
||||
// Boss bars cache
|
||||
{
|
||||
Set<BossBar> bossBars = BossBar.getBossBars(this);
|
||||
Set<net.minestom.server.bossbar.BossBar> bossBars = net.minestom.server.bossbar.BossBar.getBossBars(this);
|
||||
if (bossBars != null) {
|
||||
for (BossBar bossBar : bossBars) {
|
||||
for (net.minestom.server.bossbar.BossBar bossBar : bossBars) {
|
||||
bossBar.removeViewer(this);
|
||||
}
|
||||
}
|
||||
@ -1091,6 +1094,16 @@ public class Player extends LivingEntity implements CommandSender {
|
||||
playerConnection.sendPacket(titlePacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBossBar(@NonNull BossBar bar) {
|
||||
MinecraftServer.getBossBarManager().addBossBar(this, bar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideBossBar(@NonNull BossBar bar) {
|
||||
MinecraftServer.getBossBarManager().removeBossBar(this, bar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a book ui for the player with the given book metadata.
|
||||
*
|
||||
|
@ -15,10 +15,10 @@ public class BossBarPacket implements ServerPacket {
|
||||
public UUID uuid;
|
||||
public Action action;
|
||||
|
||||
public JsonMessage title; // Only text
|
||||
public String title;
|
||||
public float health;
|
||||
public BarColor color;
|
||||
public BarDivision division;
|
||||
public int color;
|
||||
public int division;
|
||||
public byte flags;
|
||||
|
||||
|
||||
@ -29,10 +29,10 @@ public class BossBarPacket implements ServerPacket {
|
||||
|
||||
switch (action) {
|
||||
case ADD:
|
||||
writer.writeSizedString(title.toString());
|
||||
writer.writeSizedString(title);
|
||||
writer.writeFloat(health);
|
||||
writer.writeVarInt(color.ordinal());
|
||||
writer.writeVarInt(division.ordinal());
|
||||
writer.writeVarInt(color);
|
||||
writer.writeVarInt(division);
|
||||
writer.writeByte(flags);
|
||||
break;
|
||||
case REMOVE:
|
||||
@ -42,11 +42,11 @@ public class BossBarPacket implements ServerPacket {
|
||||
writer.writeFloat(health);
|
||||
break;
|
||||
case UPDATE_TITLE:
|
||||
writer.writeSizedString(title.toString());
|
||||
writer.writeSizedString(title);
|
||||
break;
|
||||
case UPDATE_STYLE:
|
||||
writer.writeVarInt(color.ordinal());
|
||||
writer.writeVarInt(division.ordinal());
|
||||
writer.writeVarInt(color);
|
||||
writer.writeVarInt(division);
|
||||
break;
|
||||
case UPDATE_FLAGS:
|
||||
writer.writeByte(flags);
|
||||
|
Loading…
Reference in New Issue
Block a user