diff --git a/common/src/main/java/us/myles/ViaVersion/ViaManager.java b/common/src/main/java/us/myles/ViaVersion/ViaManager.java index 8be60ad18..ae68810f0 100644 --- a/common/src/main/java/us/myles/ViaVersion/ViaManager.java +++ b/common/src/main/java/us/myles/ViaVersion/ViaManager.java @@ -156,6 +156,10 @@ public class ViaManager { return platform.getConnectionManager().getConnectedClients(); } + public UUID getConnectedClientId(UserConnection conn) { + return platform.getConnectionManager().getConnectedClientId(conn); + } + /** * @see ViaConnectionManager#isClientConnected(UUID) */ diff --git a/common/src/main/java/us/myles/ViaVersion/api/boss/BossBar.java b/common/src/main/java/us/myles/ViaVersion/api/boss/BossBar.java index a1aeb7b0f..91e0962fa 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/boss/BossBar.java +++ b/common/src/main/java/us/myles/ViaVersion/api/boss/BossBar.java @@ -1,6 +1,7 @@ package us.myles.ViaVersion.api.boss; import us.myles.ViaVersion.api.Via; +import us.myles.ViaVersion.api.data.UserConnection; import java.util.Set; import java.util.UUID; @@ -80,13 +81,21 @@ public abstract class BossBar { } /** - * Show the bossbar to a player (uuid) + * Show the bossbar to a player (uuid). This only works for frontend connections. Use #addConnection(UserConnection) for other types. * * @param player uuid of the player * @return The BossBar object */ public abstract BossBar addPlayer(UUID player); + /** + * Show the bossbar to a player connection. + * + * @param conn UserConnection of the connection + * @return The BossBar object + */ + public abstract BossBar addConnection(UserConnection conn); + /** * add multiple players * @@ -112,13 +121,21 @@ public abstract class BossBar { } /** - * Removes the bossbar from a player + * Removes the bossbar from a player. This only works for frontend connections. For others types, use #removeConnection(UserConnection) * - * @param uuid The platers YYUD + * @param uuid The players UUID * @return The BossBar object */ public abstract BossBar removePlayer(UUID uuid); + /** + * Removes the bossbar from a player connection. + * + * @param conn The UserConnection + * @return The BossBar object + */ + public abstract BossBar removeConnection(UserConnection conn); + /** * Add flags * @@ -142,12 +159,19 @@ public abstract class BossBar { public abstract boolean hasFlag(BossFlag flag); /** - * Get players + * Get players. Only returns UUIDs which are front-end. For all connections, use #getConnections() * * @return UUIDS from players (sorry I lied) */ public abstract Set getPlayers(); + /** + * Get UserConnections. + * + * @return UserConnection from players + */ + public abstract Set getConnections(); + /** * Show the bossbar to everyone (In the getPlayer set) * diff --git a/common/src/main/java/us/myles/ViaVersion/api/platform/ViaConnectionManager.java b/common/src/main/java/us/myles/ViaVersion/api/platform/ViaConnectionManager.java index 77607708a..d26eabff1 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/platform/ViaConnectionManager.java +++ b/common/src/main/java/us/myles/ViaVersion/api/platform/ViaConnectionManager.java @@ -2,8 +2,8 @@ package us.myles.ViaVersion.api.platform; import io.netty.channel.ChannelFutureListener; import org.jetbrains.annotations.Nullable; +import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.UserConnection; -import us.myles.ViaVersion.protocols.base.ProtocolInfo; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -17,9 +17,14 @@ public class ViaConnectionManager { public void onLoginSuccess(UserConnection connection) { Objects.requireNonNull(connection, "connection is null!"); - UUID id = connection.getProtocolInfo().getUuid(); connections.add(connection); - clients.put(id, connection); + + if (isFrontEnd(connection)) { + UUID id = connection.getProtocolInfo().getUuid(); + if (clients.put(id, connection) != null) { + Via.getPlatform().getLogger().warning("Duplicate UUID on frontend connection! ("+id+")"); + } + } if (connection.getChannel() != null) { connection.getChannel().closeFuture().addListener((ChannelFutureListener) future -> onDisconnect(connection)); @@ -28,9 +33,20 @@ public class ViaConnectionManager { public void onDisconnect(UserConnection connection) { Objects.requireNonNull(connection, "connection is null!"); - UUID id = connection.getProtocolInfo().getUuid(); connections.remove(connection); - clients.remove(id); + + if (isFrontEnd(connection)) { + UUID id = connection.getProtocolInfo().getUuid(); + clients.remove(id); + } + } + + /** + * Frontend connections will have the UUID stored. Override this if your platform isn't always frontend. + * UUIDs can't be duplicate between frontend connections. + */ + public boolean isFrontEnd(UserConnection conn) { + return true; } /** @@ -57,6 +73,27 @@ public class ViaConnectionManager { return clients.get(clientIdentifier); } + /** + * Returns the UUID from the frontend connection to this proxy server + * Returns null when there isn't a server or this connection isn't frontend or it doesn't have an id + * When ViaVersion is reloaded, this method may not return some players. + * May not return ProtocolSupport players. + *

+ * Note that connections are removed as soon as their channel is closed, + * so avoid using this method during player quits for example. + */ + @Nullable + public UUID getConnectedClientId(UserConnection conn) { + if (conn.getProtocolInfo() == null) return null; + UUID uuid = conn.getProtocolInfo().getUuid(); + UserConnection client = clients.get(uuid); + if (client != null && client.equals(conn)) { + // This is frontend + return uuid; + } + return null; + } + /** * Returns all UserConnections which are registered * May contain duplicated UUIDs on multiple ProtocolInfo. diff --git a/common/src/main/java/us/myles/ViaVersion/boss/CommonBoss.java b/common/src/main/java/us/myles/ViaVersion/boss/CommonBoss.java index 201d39f63..f3ea7c511 100644 --- a/common/src/main/java/us/myles/ViaVersion/boss/CommonBoss.java +++ b/common/src/main/java/us/myles/ViaVersion/boss/CommonBoss.java @@ -8,25 +8,21 @@ 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.api.data.UserConnection; -import us.myles.ViaVersion.api.protocol.ProtocolVersion; import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9To1_8; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; +import java.util.*; +import java.util.stream.Collectors; public abstract class CommonBoss extends BossBar { private final UUID uuid; + private final Set connections; + private final Set flags; private String title; private float health; private BossColor color; private BossStyle style; - private final Set players; private boolean visible; - private final Set flags; public CommonBoss(String title, float health, BossColor color, BossStyle style) { Preconditions.checkNotNull(title, "Title cannot be null"); @@ -37,7 +33,7 @@ public abstract class CommonBoss extends BossBar { this.health = health; this.color = color == null ? BossColor.PURPLE : color; this.style = style == null ? BossStyle.SOLID : style; - this.players = new HashSet<>(); + this.connections = Collections.newSetFromMap(new WeakHashMap<>()); this.flags = new HashSet<>(); visible = true; } @@ -81,22 +77,26 @@ public abstract class CommonBoss extends BossBar { @Override public BossBar addPlayer(UUID player) { - if (!players.contains(player)) { - players.add(player); - if (visible) { - UserConnection user = Via.getManager().getConnection(player); - sendPacket(player, getPacket(CommonBoss.UpdateAction.ADD, user)); - } + return addConnection(Via.getManager().getConnection(player)); + } + + @Override + public BossBar addConnection(UserConnection conn) { + if (connections.add(conn) && visible) { + sendPacketConnection(conn, getPacket(CommonBoss.UpdateAction.ADD, conn)); } return this; } @Override public BossBar removePlayer(UUID uuid) { - if (players.contains(uuid)) { - players.remove(uuid); - UserConnection user = Via.getManager().getConnection(uuid); - sendPacket(uuid, getPacket(UpdateAction.REMOVE, user)); + return removeConnection(Via.getManager().getConnection(uuid)); + } + + @Override + public BossBar removeConnection(UserConnection conn) { + if (connections.remove(conn)) { + sendPacketConnection(conn, getPacket(UpdateAction.REMOVE, conn)); } return this; } @@ -127,7 +127,13 @@ public abstract class CommonBoss extends BossBar { @Override public Set getPlayers() { - return Collections.unmodifiableSet(players); + return connections.stream().map(conn -> Via.getManager().getConnectedClientId(conn)).filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + @Override + public Set getConnections() { + return Collections.unmodifiableSet(connections); } @Override @@ -147,6 +153,13 @@ public abstract class CommonBoss extends BossBar { return visible; } + private void setVisible(boolean value) { + if (visible != value) { + visible = value; + sendPacket(value ? CommonBoss.UpdateAction.ADD : CommonBoss.UpdateAction.REMOVE); + } + } + @Override public UUID getId() { return uuid; @@ -175,24 +188,16 @@ public abstract class CommonBoss extends BossBar { return flags; } - private void setVisible(boolean value) { - if (visible != value) { - visible = value; - sendPacket(value ? CommonBoss.UpdateAction.ADD : CommonBoss.UpdateAction.REMOVE); - } - } - private void sendPacket(UpdateAction action) { - for (UUID uuid : new ArrayList<>(players)) { - UserConnection connection = Via.getManager().getConnection(uuid); - PacketWrapper wrapper = getPacket(action, connection); - sendPacket(uuid, wrapper); + for (UserConnection conn : new ArrayList<>(connections)) { + PacketWrapper wrapper = getPacket(action, conn); + sendPacketConnection(conn, wrapper); } } - private void sendPacket(UUID uuid, PacketWrapper wrapper) { - if (!Via.getAPI().isInjected(uuid) || !(Via.getAPI().getPlayerVersion(uuid) >= ProtocolVersion.v1_9.getId())) { - players.remove(uuid); + private void sendPacketConnection(UserConnection conn, PacketWrapper wrapper) { + if (conn.getProtocolInfo() == null || conn.getProtocolInfo().getPipeline().contains(Protocol1_9To1_8.class)) { + connections.remove(conn); return; } try { diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java index a4b21b775..a8d12f93e 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java @@ -191,7 +191,6 @@ public class EntityTracker1_9 extends EntityTracker { } } } - UUID uuid = getUser().getProtocolInfo().getUuid(); // Boss bar if (Via.getConfig().isBossbarPatch()) { if (type == EntityType.ENDER_DRAGON || type == EntityType.WITHER) { @@ -202,7 +201,7 @@ public class EntityTracker1_9 extends EntityTracker { if (bar == null) { bar = Via.getAPI().createBossBar(title, BossColor.PINK, BossStyle.SOLID); bossBarMap.put(entityId, bar); - bar.addPlayer(uuid); + bar.addConnection(getUser()); bar.show(); // Send to provider @@ -219,7 +218,7 @@ public class EntityTracker1_9 extends EntityTracker { String title = type == EntityType.ENDER_DRAGON ? "Ender Dragon" : "Wither"; bar = Via.getAPI().createBossBar(title, health, BossColor.PINK, BossStyle.SOLID); bossBarMap.put(entityId, bar); - bar.addPlayer(uuid); + bar.addConnection(getUser()); bar.show(); // Send to provider Via.getManager().getProviders().get(BossBarProvider.class).handleAdd(getUser(), bar.getId());