mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-24 00:51:34 +01:00
Rework boss bar system
This commit is contained in:
parent
aa2d1f6397
commit
3628c42ef2
@ -2,17 +2,16 @@ package net.minestom.server.adventure.bossbar;
|
||||
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.Viewable;
|
||||
import net.minestom.server.adventure.AdventurePacketConvertor;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.packet.server.play.BossBarPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static net.minestom.server.network.packet.server.play.BossBarPacket.Action.*;
|
||||
@ -24,13 +23,13 @@ import static net.minestom.server.network.packet.server.play.BossBarPacket.Actio
|
||||
final class BossBarHolder implements Viewable {
|
||||
final UUID uuid;
|
||||
final BossBar bar;
|
||||
final Set<UUID> players;
|
||||
final Set<Player> players;
|
||||
boolean registered;
|
||||
|
||||
BossBarHolder(@NotNull BossBar bar) {
|
||||
this.uuid = UUID.randomUUID();
|
||||
this.bar = bar;
|
||||
this.players = ConcurrentHashMap.newKeySet();
|
||||
this.players = new CopyOnWriteArraySet<>();
|
||||
this.registered = false;
|
||||
}
|
||||
|
||||
@ -88,26 +87,16 @@ final class BossBarHolder implements Viewable {
|
||||
|
||||
@Override
|
||||
public boolean addViewer(@NotNull Player player) {
|
||||
return this.players.add(player.getUuid());
|
||||
return this.players.add(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeViewer(@NotNull Player player) {
|
||||
return this.players.remove(player.getUuid());
|
||||
return this.players.remove(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Set<Player> getViewers() {
|
||||
Set<Player> playerList = new HashSet<>();
|
||||
|
||||
for (UUID uuid : this.players) {
|
||||
Player player = MinecraftServer.getConnectionManager().getPlayer(uuid);
|
||||
|
||||
if (player != null) {
|
||||
playerList.add(player);
|
||||
}
|
||||
}
|
||||
|
||||
return playerList;
|
||||
return Collections.unmodifiableSet(this.players);
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,11 @@ package net.minestom.server.adventure.bossbar;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.bossbar.BossBar;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.utils.PacketUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A listener for boss bar updates. This class is not intended for public use and it is
|
||||
@ -26,31 +28,35 @@ class BossBarListener implements BossBar.Listener {
|
||||
|
||||
@Override
|
||||
public void bossBarNameChanged(@NotNull BossBar bar, @NotNull Component oldName, @NotNull Component newName) {
|
||||
BossBarHolder holder = this.manager.bars.get(bar);
|
||||
this.manager.updatePlayers(holder.createTitleUpdate(newName), holder.players);
|
||||
this.doIfRegistered(bar, holder -> PacketUtils.sendGroupedPacket(holder.players, holder.createTitleUpdate(newName)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bossBarProgressChanged(@NotNull BossBar bar, float oldProgress, float newProgress) {
|
||||
BossBarHolder holder = this.manager.bars.get(bar);
|
||||
this.manager.updatePlayers(holder.createPercentUpdate(newProgress), holder.players);
|
||||
this.doIfRegistered(bar, holder -> PacketUtils.sendGroupedPacket(holder.players, holder.createPercentUpdate(newProgress)));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bossBarColorChanged(@NotNull BossBar bar, @NotNull BossBar.Color oldColor, @NotNull BossBar.Color newColor) {
|
||||
BossBarHolder holder = this.manager.bars.get(bar);
|
||||
this.manager.updatePlayers(holder.createColorUpdate(newColor), holder.players);
|
||||
this.doIfRegistered(bar, holder -> PacketUtils.sendGroupedPacket(holder.players, holder.createColorUpdate(newColor)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bossBarOverlayChanged(@NotNull BossBar bar, BossBar.@NotNull Overlay oldOverlay, BossBar.@NotNull Overlay newOverlay) {
|
||||
BossBarHolder holder = this.manager.bars.get(bar);
|
||||
this.manager.updatePlayers(holder.createOverlayUpdate(newOverlay), holder.players);
|
||||
this.doIfRegistered(bar, holder -> PacketUtils.sendGroupedPacket(holder.players, holder.createOverlayUpdate(newOverlay)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bossBarFlagsChanged(@NotNull BossBar bar, @NotNull Set<BossBar.Flag> flagsAdded, @NotNull Set<BossBar.Flag> flagsRemoved) {
|
||||
this.doIfRegistered(bar, holder -> PacketUtils.sendGroupedPacket(holder.players, holder.createFlagsUpdate()));
|
||||
}
|
||||
|
||||
private void doIfRegistered(@NotNull BossBar bar, @NotNull Consumer<BossBarHolder> consumer) {
|
||||
BossBarHolder holder = this.manager.bars.get(bar);
|
||||
this.manager.updatePlayers(holder.createFlagsUpdate(), holder.players);
|
||||
|
||||
if (holder != null && holder.registered) {
|
||||
consumer.accept(holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ import net.minestom.server.utils.PacketUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* Manages all boss bars known to this Minestom instance. Although this class can be used
|
||||
@ -27,9 +29,8 @@ import java.util.*;
|
||||
* @see Audience#hideBossBar(BossBar)
|
||||
*/
|
||||
public class BossBarManager {
|
||||
private static final int CONCURRENCY_LEVEL = 4;
|
||||
|
||||
private final BossBarListener listener;
|
||||
private final Map<UUID, Set<BossBarHolder>> playerBars;
|
||||
final Map<BossBar, BossBarHolder> bars;
|
||||
|
||||
/**
|
||||
@ -37,9 +38,8 @@ public class BossBarManager {
|
||||
*/
|
||||
public BossBarManager() {
|
||||
this.listener = new BossBarListener(this);
|
||||
this.bars = new MapMaker().concurrencyLevel(CONCURRENCY_LEVEL).weakKeys().makeMap();
|
||||
|
||||
MinecraftServer.getGlobalEventHandler().addEventCallback(PlayerDisconnectEvent.class, this::onDisconnect);
|
||||
this.playerBars = new ConcurrentHashMap<>();
|
||||
this.bars = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,6 +54,7 @@ public class BossBarManager {
|
||||
|
||||
if (holder.addViewer(player)) {
|
||||
player.getPlayerConnection().sendPacket(holder.createAddPacket());
|
||||
this.playerBars.computeIfAbsent(player.getUuid(), uuid -> new HashSet<>()).add(holder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,6 +69,7 @@ public class BossBarManager {
|
||||
|
||||
if (holder.removeViewer(player)) {
|
||||
player.getPlayerConnection().sendPacket(holder.createRemovePacket());
|
||||
this.removePlayer(player, holder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,6 +87,7 @@ public class BossBarManager {
|
||||
for (Player player : players) {
|
||||
if (holder.addViewer(player)) {
|
||||
addedPlayers.add(player);
|
||||
this.playerBars.computeIfAbsent(player.getUuid(), uuid -> new HashSet<>()).add(holder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,6 +109,7 @@ public class BossBarManager {
|
||||
for (Player player : players) {
|
||||
if (holder.removeViewer(player)) {
|
||||
removedPlayers.add(player);
|
||||
this.removePlayer(player, holder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,27 +119,37 @@ public class BossBarManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the packet to all players in the set, removing them if they no longer exist
|
||||
* in the connection manager.
|
||||
* Completely destroys a boss bar, removing it from all players.
|
||||
*
|
||||
* @param packet the packet
|
||||
* @param uuids the players
|
||||
* @param bossBar the boss bar
|
||||
*/
|
||||
void updatePlayers(BossBarPacket packet, Set<UUID> uuids) {
|
||||
Iterator<UUID> iterator = uuids.iterator();
|
||||
Collection<Player> players = new ArrayList<>();
|
||||
public void destroyBossBar(@NotNull BossBar bossBar) {
|
||||
BossBarHolder holder = this.bars.remove(bossBar);
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
Player player = MinecraftServer.getConnectionManager().getPlayer(iterator.next());
|
||||
if (holder != null) {
|
||||
PacketUtils.sendGroupedPacket(holder.players, holder.createRemovePacket());
|
||||
|
||||
if (player == null) {
|
||||
iterator.remove();
|
||||
} else {
|
||||
players.add(player);
|
||||
for (Player player : holder.players) {
|
||||
this.removePlayer(player, holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PacketUtils.sendGroupedPacket(players, packet);
|
||||
/**
|
||||
* Removes a player from all of their boss bars. Note that this method does not
|
||||
* send any removal packets to the player. It is meant to be used when a player is
|
||||
* disconnecting from the server.
|
||||
*
|
||||
* @param player the player
|
||||
*/
|
||||
public void removeAllBossBars(@NotNull Player player) {
|
||||
Set<BossBarHolder> holders = this.playerBars.remove(player.getUuid());
|
||||
|
||||
if (holders != null) {
|
||||
for (BossBarHolder holder : holders) {
|
||||
holder.removeViewer(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,25 +160,22 @@ public class BossBarManager {
|
||||
* @return the handler
|
||||
*/
|
||||
private @NotNull BossBarHolder getOrCreateHandler(@NotNull BossBar bar) {
|
||||
BossBarHolder holder = this.bars.computeIfAbsent(bar, BossBarHolder::new);
|
||||
|
||||
if (!holder.registered) {
|
||||
return this.bars.computeIfAbsent(bar, key -> {
|
||||
BossBarHolder holder = new BossBarHolder(key);
|
||||
bar.addListener(this.listener);
|
||||
holder.registered = true;
|
||||
}
|
||||
|
||||
return holder;
|
||||
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 (BossBarHolder holder : this.bars.values()) {
|
||||
holder.players.remove(event.getPlayer().getUuid());
|
||||
private void removePlayer(Player player, BossBarHolder holder) {
|
||||
Set<BossBarHolder> holders = this.playerBars.get(player.getUuid());
|
||||
|
||||
if (holders != null) {
|
||||
holders.remove(holder);
|
||||
|
||||
if (holders.isEmpty()) {
|
||||
this.playerBars.remove(player.getUuid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,6 @@ import net.minestom.server.network.player.NettyPlayerConnection;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.recipe.Recipe;
|
||||
import net.minestom.server.recipe.RecipeManager;
|
||||
import net.minestom.server.registry.Registries;
|
||||
import net.minestom.server.resourcepack.ResourcePack;
|
||||
import net.minestom.server.scoreboard.BelowNameTag;
|
||||
import net.minestom.server.scoreboard.Team;
|
||||
@ -579,6 +578,8 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
|
||||
}
|
||||
}
|
||||
|
||||
MinecraftServer.getBossBarManager().removeAllBossBars(this);
|
||||
|
||||
// Advancement tabs cache
|
||||
{
|
||||
Set<AdvancementTab> advancementTabs = AdvancementTab.getTabs(this);
|
||||
|
Loading…
Reference in New Issue
Block a user