Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-12-24 23:30:26 +01:00
add event to modify and/or block specific updates to the tablist of a player
Inspired by https://github.com/PaperMC/Velocity/pull/874
Dieser Commit ist enthalten in:
Ursprung
78f6cfc26c
Commit
ce18534ce2
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) 2019-2024 Velocity Contributors
|
||||
*
|
||||
* The Velocity API is licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in the api top-level directory.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.api.event.player;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.event.ResultedEvent;
|
||||
import com.velocitypowered.api.event.annotation.AwaitingEvent;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* This event is fired, when a {@link com.velocitypowered.api.proxy.player.TabList Tablist} is updated.
|
||||
* It can be used to override or cancel updates for {@link TabListEntry}s.
|
||||
* Velocity will wait for this event to finish firing before forwarding it to the server.
|
||||
*
|
||||
* <p>Note: If the {@code actions} contain {@link Action#REMOVE_PLAYER Action.REMOVE_PLAYER}, that may be the only action.
|
||||
*
|
||||
* <p><b>Version-specific behavior:</b>
|
||||
* <li>For versions below 1.19.3, {@code actions} may only contain one action, and if that action
|
||||
* is {@link Action#ADD_PLAYER Action.ADD_PLAYER}, the values normally set by other actions
|
||||
* (e.g., {@link Action#UPDATE_GAME_MODE Action.UPDATE_GAME_MODE}) may still be set.
|
||||
* <li>For versions below 1.8, {@code actions} may only contain {@link Action#ADD_PLAYER Action.ADD_PLAYER}
|
||||
* or {@link Action#REMOVE_PLAYER Action.REMOVE_PLAYER}. {@link Action#ADD_PLAYER Action.ADD_PLAYER} may also act as a replacement
|
||||
* for actions like {@link Action#UPDATE_LATENCY Action.UPDATE_LATENCY}}.
|
||||
*/
|
||||
@AwaitingEvent
|
||||
public class ServerUpdateTabListEvent implements ResultedEvent<ServerUpdateTabListEvent.TabListUpdateResult> {
|
||||
|
||||
private final Player player;
|
||||
private final Set<Action> actions;
|
||||
private final List<TabListEntry> entries;
|
||||
private TabListUpdateResult result;
|
||||
|
||||
/**
|
||||
* Constructs a {@link ServerUpdateTabListEvent} instance.
|
||||
*
|
||||
* @param player the player for whom the tab list is being updated
|
||||
* @param actions the {@link Action Action}s from the server for this tab list update
|
||||
* @param entries the {@link TabListEntry}s in their updated form
|
||||
*/
|
||||
public ServerUpdateTabListEvent(Player player, Set<Action> actions, List<TabListEntry> entries) {
|
||||
this.player = Preconditions.checkNotNull(player, "player");
|
||||
this.actions = Preconditions.checkNotNull(actions, "actions");
|
||||
this.entries = Preconditions.checkNotNull(entries, "entries");
|
||||
this.result = TabListUpdateResult.allowed();
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public Set<Action> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* The updated {@link TabListEntry}s that will be applied to the {@link com.velocitypowered.api.proxy.player.TabList Tablist}
|
||||
* of the {@code player} (or in the case of {@link Action#REMOVE_PLAYER Action.REMOVE_PLAYER} removed).
|
||||
*
|
||||
* @return the updated entries, normally immutable
|
||||
*/
|
||||
public List<TabListEntry> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabListUpdateResult getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResult(TabListUpdateResult result) {
|
||||
this.result = Preconditions.checkNotNull(result, "result");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServerUpdateTabListEvent{"
|
||||
+ "player=" + player
|
||||
+ ", actions=" + actions
|
||||
+ ", entries=" + entries
|
||||
+ '}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an action of the {@link ServerUpdateTabListEvent}.
|
||||
*/
|
||||
public enum Action {
|
||||
/**
|
||||
* Add new players to the player list.
|
||||
*/
|
||||
ADD_PLAYER,
|
||||
/**
|
||||
* Initialize the chat session for the entries.
|
||||
*/
|
||||
INITIALIZE_CHAT,
|
||||
/**
|
||||
* Update the gamemode for the entries.
|
||||
*/
|
||||
UPDATE_GAME_MODE,
|
||||
/**
|
||||
* Update the latency for the entries.
|
||||
*/
|
||||
UPDATE_LISTED,
|
||||
/**
|
||||
* Update the latency for the entries.
|
||||
*/
|
||||
UPDATE_LATENCY,
|
||||
/**
|
||||
* Update the display name for the specific entries.
|
||||
*/
|
||||
UPDATE_DISPLAY_NAME,
|
||||
/**
|
||||
* Remove players from the player list.
|
||||
*/
|
||||
REMOVE_PLAYER
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the result of the {@link ServerUpdateTabListEvent}.
|
||||
*/
|
||||
public static final class TabListUpdateResult implements ResultedEvent.Result {
|
||||
|
||||
private static final TabListUpdateResult ALLOWED = new TabListUpdateResult(true);
|
||||
private static final TabListUpdateResult DENIED = new TabListUpdateResult(false);
|
||||
|
||||
private final boolean status;
|
||||
private final Set<UUID> ids;
|
||||
|
||||
public TabListUpdateResult(boolean status) {
|
||||
this.status = status;
|
||||
ids = Collections.emptySet();
|
||||
}
|
||||
|
||||
public TabListUpdateResult(boolean status, Set<UUID> ids) {
|
||||
this.status = status;
|
||||
this.ids = ids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowed() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public Set<UUID> getIds() {
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the {@link TabListEntry}s to be updated, with or without modification.
|
||||
*
|
||||
* @return the allowed result
|
||||
*/
|
||||
public static TabListUpdateResult allowed() {
|
||||
return ALLOWED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents the {@link TabListEntry}s from being updated.
|
||||
*
|
||||
* @return the denied result
|
||||
*/
|
||||
public static TabListUpdateResult denied() {
|
||||
return DENIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only allows specific {@link TabListEntry}s to be updated.
|
||||
* The updates for the remaining entries will be dropped.
|
||||
*
|
||||
* <p>Note: You can get the id of an entry with {@link TabListEntry#getProfile()}{@link com.velocitypowered.api.util.GameProfile#getId() .getId()}
|
||||
*
|
||||
* @param allowedOnly A non-empty set of ids of the entries that should be updated
|
||||
* @return a result with the specified entries to be updated
|
||||
*/
|
||||
public static TabListUpdateResult allowedSpecific(final Set<UUID> allowedOnly) {
|
||||
Preconditions.checkNotNull(allowedOnly, "allowedOnly");
|
||||
Preconditions.checkArgument(!allowedOnly.isEmpty(), "allowedOnly empty");
|
||||
return new TabListUpdateResult(true, allowedOnly);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -334,20 +334,20 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
|
||||
|
||||
@Override
|
||||
public boolean handle(LegacyPlayerListItemPacket packet) {
|
||||
serverConn.getPlayer().getTabList().processLegacy(packet);
|
||||
return false;
|
||||
serverConn.getPlayer().getTabList().processLegacyUpdate(packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(UpsertPlayerInfoPacket packet) {
|
||||
serverConn.getPlayer().getTabList().processUpdate(packet);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(RemovePlayerInfoPacket packet) {
|
||||
serverConn.getPlayer().getTabList().processRemove(packet);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -202,7 +202,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
|
||||
this.onlineMode = onlineMode;
|
||||
|
||||
if (connection.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_19_3)) {
|
||||
this.tabList = new VelocityTabList(this);
|
||||
this.tabList = new VelocityTabList(this, server);
|
||||
} else if (connection.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_8)) {
|
||||
this.tabList = new KeyedVelocityTabList(this, server);
|
||||
} else {
|
||||
|
@ -30,7 +30,7 @@ public interface InternalTabList extends TabList {
|
||||
|
||||
Player getPlayer();
|
||||
|
||||
default void processLegacy(LegacyPlayerListItemPacket packet) {
|
||||
default void processLegacyUpdate(LegacyPlayerListItemPacket packet) {
|
||||
}
|
||||
|
||||
default void processUpdate(UpsertPlayerInfoPacket infoPacket) {
|
||||
|
@ -18,6 +18,7 @@
|
||||
package com.velocitypowered.proxy.tablist;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.event.player.ServerUpdateTabListEvent;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.proxy.crypto.IdentifiedKey;
|
||||
@ -35,6 +36,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@ -78,20 +80,27 @@ public class KeyedVelocityTabList implements InternalTabList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntry(TabListEntry entry) {
|
||||
public void addEntry(TabListEntry entry1) {
|
||||
KeyedVelocityTabListEntry entry;
|
||||
if (entry1 instanceof KeyedVelocityTabListEntry) {
|
||||
entry = (KeyedVelocityTabListEntry) entry1;
|
||||
} else {
|
||||
entry = new KeyedVelocityTabListEntry(this, entry1.getProfile(),
|
||||
entry1.getDisplayNameComponent().orElse(null),
|
||||
entry1.getLatency(), entry1.getGameMode(), entry1.getIdentifiedKey());
|
||||
}
|
||||
|
||||
Preconditions.checkNotNull(entry, "entry");
|
||||
Preconditions.checkArgument(entry.getTabList().equals(this),
|
||||
"The provided entry was not created by this tab list");
|
||||
Preconditions.checkArgument(!entries.containsKey(entry.getProfile().getId()),
|
||||
"this TabList already contains an entry with the same uuid");
|
||||
Preconditions.checkArgument(entry instanceof KeyedVelocityTabListEntry,
|
||||
"Not a Velocity tab list entry");
|
||||
|
||||
LegacyPlayerListItemPacket.Item packetItem = LegacyPlayerListItemPacket.Item.from(entry);
|
||||
connection.write(
|
||||
new LegacyPlayerListItemPacket(LegacyPlayerListItemPacket.ADD_PLAYER,
|
||||
Collections.singletonList(packetItem)));
|
||||
entries.put(entry.getProfile().getId(), (KeyedVelocityTabListEntry) entry);
|
||||
entries.put(entry.getProfile().getId(), entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -166,20 +175,117 @@ public class KeyedVelocityTabList implements InternalTabList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processLegacy(LegacyPlayerListItemPacket packet) {
|
||||
// Packets are already forwarded on, so no need to do that here
|
||||
for (LegacyPlayerListItemPacket.Item item : packet.getItems()) {
|
||||
UUID uuid = item.getUuid();
|
||||
assert uuid != null : "1.7 tab list entry given to modern tab list handler!";
|
||||
public void processLegacyUpdate(LegacyPlayerListItemPacket packet) {
|
||||
ServerUpdateTabListEvent.Action action = mapToEventAction(packet.getAction());
|
||||
Preconditions.checkNotNull(action, "action");
|
||||
|
||||
if (packet.getAction() != LegacyPlayerListItemPacket.ADD_PLAYER
|
||||
&& !entries.containsKey(uuid)) {
|
||||
List<UpdateEventTabListEntry> entries = mapToEventEntries(packet.getAction(), packet.getItems());
|
||||
|
||||
proxyServer.getEventManager().fire(
|
||||
new ServerUpdateTabListEvent(
|
||||
player,
|
||||
Set.of(action),
|
||||
Collections.unmodifiableList(entries)
|
||||
)
|
||||
).thenAcceptAsync(event -> {
|
||||
if (event.getResult().isAllowed()) {
|
||||
if (event.getResult().getIds().isEmpty()) {
|
||||
boolean rewrite = false;
|
||||
for (UpdateEventTabListEntry entry : entries) {
|
||||
if (entry.isRewrite()) {
|
||||
rewrite = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rewrite) {
|
||||
//listeners have modified entries, requires manual processing
|
||||
if (action != ServerUpdateTabListEvent.Action.REMOVE_PLAYER) {
|
||||
for (UpdateEventTabListEntry entry : entries) {
|
||||
if (this.entries.containsKey(entry.getProfile().getId())) {
|
||||
removeEntry(entry.getProfile().getId());
|
||||
}
|
||||
|
||||
addEntry(entry);
|
||||
}
|
||||
} else {
|
||||
for (UpdateEventTabListEntry entry : entries) {
|
||||
removeEntry(entry.getProfile().getId());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//listeners haven't modified entries
|
||||
for (LegacyPlayerListItemPacket.Item item : packet.getItems()) {
|
||||
processLegacy(packet.getAction(), item);
|
||||
}
|
||||
|
||||
connection.write(packet);
|
||||
}
|
||||
} else {
|
||||
//listeners have denied entries (and may have modified others), requires manual processing
|
||||
if (action != ServerUpdateTabListEvent.Action.REMOVE_PLAYER) {
|
||||
for (UpdateEventTabListEntry entry : entries) {
|
||||
if (event.getResult().getIds().contains(entry.getProfile().getId())) {
|
||||
if (this.entries.containsKey(entry.getProfile().getId())) {
|
||||
removeEntry(entry.getProfile().getId());
|
||||
}
|
||||
|
||||
addEntry(entry);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (UpdateEventTabListEntry entry : entries) {
|
||||
if (event.getResult().getIds().contains(entry.getProfile().getId())) {
|
||||
removeEntry(entry.getProfile().getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected ServerUpdateTabListEvent.@Nullable Action mapToEventAction(int action) {
|
||||
return switch (action) {
|
||||
case LegacyPlayerListItemPacket.ADD_PLAYER -> ServerUpdateTabListEvent.Action.ADD_PLAYER;
|
||||
case LegacyPlayerListItemPacket.REMOVE_PLAYER -> ServerUpdateTabListEvent.Action.REMOVE_PLAYER;
|
||||
case LegacyPlayerListItemPacket.UPDATE_GAMEMODE -> ServerUpdateTabListEvent.Action.UPDATE_GAME_MODE;
|
||||
case LegacyPlayerListItemPacket.UPDATE_LATENCY -> ServerUpdateTabListEvent.Action.UPDATE_LATENCY;
|
||||
case LegacyPlayerListItemPacket.UPDATE_DISPLAY_NAME -> ServerUpdateTabListEvent.Action.UPDATE_DISPLAY_NAME;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private List<UpdateEventTabListEntry> mapToEventEntries(int action, List<LegacyPlayerListItemPacket.Item> packetItems) {
|
||||
List<UpdateEventTabListEntry> entries = new ArrayList<>(packetItems.size());
|
||||
|
||||
for (LegacyPlayerListItemPacket.Item item : packetItems) {
|
||||
UUID uuid = item.getUuid();
|
||||
Preconditions.checkNotNull(uuid, "1.7 tab list entry given to modern tab list handler!");
|
||||
|
||||
if (action != LegacyPlayerListItemPacket.ADD_PLAYER
|
||||
&& !this.entries.containsKey(uuid)) {
|
||||
// Sometimes UPDATE_GAMEMODE is sent before ADD_PLAYER so don't want to warn here
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case LegacyPlayerListItemPacket.ADD_PLAYER: {
|
||||
UpdateEventTabListEntry currentEntry = null;
|
||||
KeyedVelocityTabListEntry oldCurrentEntry = this.entries.get(uuid);
|
||||
|
||||
if (oldCurrentEntry != null) {
|
||||
currentEntry = new UpdateEventTabListEntry(
|
||||
this,
|
||||
oldCurrentEntry.getProfile(),
|
||||
oldCurrentEntry.getDisplayNameComponent().orElse(null),
|
||||
oldCurrentEntry.getLatency(),
|
||||
oldCurrentEntry.getGameMode(),
|
||||
oldCurrentEntry.getChatSession(),
|
||||
oldCurrentEntry.isListed()
|
||||
);
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case LegacyPlayerListItemPacket.ADD_PLAYER -> {
|
||||
// ensure that name and properties are available
|
||||
String name = item.getName();
|
||||
List<GameProfile.Property> properties = item.getProperties();
|
||||
@ -187,43 +293,97 @@ public class KeyedVelocityTabList implements InternalTabList {
|
||||
throw new IllegalStateException("Got null game profile for ADD_PLAYER");
|
||||
}
|
||||
|
||||
entries.putIfAbsent(item.getUuid(), (KeyedVelocityTabListEntry) TabListEntry.builder()
|
||||
.tabList(this)
|
||||
.profile(new GameProfile(uuid, name, properties))
|
||||
.displayName(item.getDisplayName())
|
||||
.latency(item.getLatency())
|
||||
.chatSession(new RemoteChatSession(null, item.getPlayerKey()))
|
||||
.gameMode(item.getGameMode())
|
||||
.build());
|
||||
break;
|
||||
currentEntry = new UpdateEventTabListEntry(
|
||||
this,
|
||||
new GameProfile(uuid, name, properties),
|
||||
item.getDisplayName(),
|
||||
item.getLatency(),
|
||||
item.getGameMode(),
|
||||
new RemoteChatSession(null, item.getPlayerKey()),
|
||||
true
|
||||
);
|
||||
}
|
||||
case LegacyPlayerListItemPacket.REMOVE_PLAYER:
|
||||
entries.remove(uuid);
|
||||
break;
|
||||
case LegacyPlayerListItemPacket.UPDATE_DISPLAY_NAME: {
|
||||
KeyedVelocityTabListEntry entry = entries.get(uuid);
|
||||
if (entry != null) {
|
||||
entry.setDisplayNameInternal(item.getDisplayName());
|
||||
case LegacyPlayerListItemPacket.REMOVE_PLAYER -> {
|
||||
//Nothing should be done here, as all entries which are not allowed are removed
|
||||
// if the action is ServerUpdateTabListEvent.Action.REMOVE_PLAYER
|
||||
}
|
||||
case LegacyPlayerListItemPacket.UPDATE_DISPLAY_NAME -> {
|
||||
if (currentEntry != null) {
|
||||
currentEntry.setDisplayNameWithoutRewrite(item.getDisplayName());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LegacyPlayerListItemPacket.UPDATE_LATENCY: {
|
||||
KeyedVelocityTabListEntry entry = entries.get(uuid);
|
||||
if (entry != null) {
|
||||
entry.setLatencyInternal(item.getLatency());
|
||||
case LegacyPlayerListItemPacket.UPDATE_LATENCY -> {
|
||||
if (currentEntry != null) {
|
||||
currentEntry.setLatencyWithoutRewrite(item.getLatency());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LegacyPlayerListItemPacket.UPDATE_GAMEMODE: {
|
||||
KeyedVelocityTabListEntry entry = entries.get(uuid);
|
||||
if (entry != null) {
|
||||
entry.setGameModeInternal(item.getGameMode());
|
||||
case LegacyPlayerListItemPacket.UPDATE_GAMEMODE -> {
|
||||
if (currentEntry != null) {
|
||||
currentEntry.setGameModeWithoutRewrite(item.getGameMode());
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
default -> {
|
||||
// Nothing we can do here
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentEntry != null) {
|
||||
entries.add(currentEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private void processLegacy(int action, LegacyPlayerListItemPacket.Item item) {
|
||||
UUID uuid = item.getUuid();
|
||||
assert uuid != null : "1.7 tab list entry given to modern tab list handler!";
|
||||
|
||||
if (action != LegacyPlayerListItemPacket.ADD_PLAYER
|
||||
&& !entries.containsKey(uuid)) {
|
||||
// Sometimes UPDATE_GAMEMODE is sent before ADD_PLAYER so don't want to warn here
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case LegacyPlayerListItemPacket.ADD_PLAYER -> {
|
||||
// ensure that name and properties are available
|
||||
String name = item.getName();
|
||||
List<GameProfile.Property> properties = item.getProperties();
|
||||
if (name == null || properties == null) {
|
||||
throw new IllegalStateException("Got null game profile for ADD_PLAYER");
|
||||
}
|
||||
|
||||
entries.putIfAbsent(item.getUuid(), (KeyedVelocityTabListEntry) TabListEntry.builder()
|
||||
.tabList(this)
|
||||
.profile(new GameProfile(uuid, name, properties))
|
||||
.displayName(item.getDisplayName())
|
||||
.latency(item.getLatency())
|
||||
.chatSession(new RemoteChatSession(null, item.getPlayerKey()))
|
||||
.gameMode(item.getGameMode())
|
||||
.build());
|
||||
}
|
||||
case LegacyPlayerListItemPacket.REMOVE_PLAYER -> entries.remove(uuid);
|
||||
case LegacyPlayerListItemPacket.UPDATE_DISPLAY_NAME -> {
|
||||
KeyedVelocityTabListEntry entry = entries.get(uuid);
|
||||
if (entry != null) {
|
||||
entry.setDisplayNameInternal(item.getDisplayName());
|
||||
}
|
||||
}
|
||||
case LegacyPlayerListItemPacket.UPDATE_LATENCY -> {
|
||||
KeyedVelocityTabListEntry entry = entries.get(uuid);
|
||||
if (entry != null) {
|
||||
entry.setLatencyInternal(item.getLatency());
|
||||
}
|
||||
}
|
||||
case LegacyPlayerListItemPacket.UPDATE_GAMEMODE -> {
|
||||
KeyedVelocityTabListEntry entry = entries.get(uuid);
|
||||
if (entry != null) {
|
||||
entry.setGameModeInternal(item.getGameMode());
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
// Nothing we can do here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2024 Velocity Contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.velocitypowered.proxy.tablist;
|
||||
|
||||
import com.velocitypowered.api.event.player.ServerUpdateTabListEvent;
|
||||
import com.velocitypowered.api.proxy.player.ChatSession;
|
||||
import com.velocitypowered.api.proxy.player.TabList;
|
||||
import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import java.util.Optional;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents a {@link TabListEntry} of the {@link ServerUpdateTabListEvent}.
|
||||
*/
|
||||
public class UpdateEventTabListEntry implements TabListEntry {
|
||||
|
||||
private final TabList tabList;
|
||||
private final GameProfile profile;
|
||||
private @Nullable Component displayName;
|
||||
private int latency;
|
||||
private int gameMode;
|
||||
private boolean listed;
|
||||
private @Nullable ChatSession session;
|
||||
private boolean rewrite = false;
|
||||
|
||||
/**
|
||||
* Constructs an instance.
|
||||
*/
|
||||
public UpdateEventTabListEntry(TabList tabList, GameProfile profile, @Nullable Component displayName,
|
||||
int latency,
|
||||
int gameMode, @Nullable ChatSession session, boolean listed) {
|
||||
this.tabList = tabList;
|
||||
this.profile = profile;
|
||||
this.displayName = displayName;
|
||||
this.latency = latency;
|
||||
this.gameMode = gameMode;
|
||||
this.session = session;
|
||||
this.listed = listed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ChatSession getChatSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabList getTabList() {
|
||||
return this.tabList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameProfile getProfile() {
|
||||
return this.profile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Component> getDisplayNameComponent() {
|
||||
return Optional.ofNullable(displayName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabListEntry setDisplayName(@Nullable Component displayName) {
|
||||
this.displayName = displayName;
|
||||
rewrite = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
void setDisplayNameWithoutRewrite(@Nullable Component displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLatency() {
|
||||
return this.latency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabListEntry setLatency(int latency) {
|
||||
this.latency = latency;
|
||||
rewrite = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
void setLatencyWithoutRewrite(int latency) {
|
||||
this.latency = latency;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGameMode() {
|
||||
return this.gameMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabListEntry setGameMode(int gameMode) {
|
||||
this.gameMode = gameMode;
|
||||
rewrite = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
void setGameModeWithoutRewrite(int gameMode) {
|
||||
this.gameMode = gameMode;
|
||||
}
|
||||
|
||||
void setChatSessionWithoutRewrite(@Nullable ChatSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isListed() {
|
||||
return listed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabListEntry setListed(boolean listed) {
|
||||
this.listed = listed;
|
||||
rewrite = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
void setListedWithoutRewrite(boolean listed) {
|
||||
this.listed = listed;
|
||||
}
|
||||
|
||||
boolean isRewrite() {
|
||||
return rewrite;
|
||||
}
|
||||
|
||||
}
|
@ -19,7 +19,9 @@ package com.velocitypowered.proxy.tablist;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.velocitypowered.api.event.player.ServerUpdateTabListEvent;
|
||||
import com.velocitypowered.api.proxy.Player;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.proxy.player.ChatSession;
|
||||
import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
@ -32,11 +34,13 @@ import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder;
|
||||
import com.velocitypowered.proxy.protocol.packet.chat.RemoteChatSession;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@ -51,6 +55,7 @@ public class VelocityTabList implements InternalTabList {
|
||||
private static final Logger logger = LogManager.getLogger(VelocityConsole.class);
|
||||
private final ConnectedPlayer player;
|
||||
private final MinecraftConnection connection;
|
||||
protected final ProxyServer proxyServer;
|
||||
private final Map<UUID, VelocityTabListEntry> entries;
|
||||
|
||||
/**
|
||||
@ -58,8 +63,9 @@ public class VelocityTabList implements InternalTabList {
|
||||
*
|
||||
* @param player player associated with this tab list
|
||||
*/
|
||||
public VelocityTabList(ConnectedPlayer player) {
|
||||
public VelocityTabList(ConnectedPlayer player, final ProxyServer proxyServer) {
|
||||
this.player = player;
|
||||
this.proxyServer = proxyServer;
|
||||
this.connection = player.getConnection();
|
||||
this.entries = Maps.newConcurrentMap();
|
||||
}
|
||||
@ -214,9 +220,45 @@ public class VelocityTabList implements InternalTabList {
|
||||
|
||||
@Override
|
||||
public void processUpdate(UpsertPlayerInfoPacket infoPacket) {
|
||||
for (UpsertPlayerInfoPacket.Entry entry : infoPacket.getEntries()) {
|
||||
processUpsert(infoPacket.getActions(), entry);
|
||||
}
|
||||
List<UpdateEventTabListEntry> entries = mapToEventEntries(infoPacket.getActions(), infoPacket.getEntries());
|
||||
|
||||
proxyServer.getEventManager().fire(new ServerUpdateTabListEvent(player,
|
||||
Collections.unmodifiableSet(mapToEventActions(infoPacket.getActions())),
|
||||
Collections.unmodifiableList(entries))
|
||||
).thenAcceptAsync(event -> {
|
||||
if (event.getResult().isAllowed()) {
|
||||
if (event.getResult().getIds().isEmpty()) {
|
||||
boolean rewrite = false;
|
||||
for (UpdateEventTabListEntry entry : entries) {
|
||||
if (entry.isRewrite()) {
|
||||
rewrite = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rewrite) {
|
||||
//listeners have modified entries, requires manual processing
|
||||
for (UpdateEventTabListEntry entry : entries) {
|
||||
addEntry(entry);
|
||||
}
|
||||
} else {
|
||||
//listeners haven't modified entries
|
||||
for (UpsertPlayerInfoPacket.Entry entry : infoPacket.getEntries()) {
|
||||
processUpsert(infoPacket.getActions(), entry);
|
||||
}
|
||||
|
||||
connection.write(infoPacket);
|
||||
}
|
||||
} else {
|
||||
//listeners have denied entries (and may have modified others), requires manual processing
|
||||
for (UpdateEventTabListEntry entry : entries) {
|
||||
if (event.getResult().getIds().contains(entry.getProfile().getId())) {
|
||||
addEntry(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected UpsertPlayerInfoPacket.Entry createRawEntry(VelocityTabListEntry entry) {
|
||||
@ -231,6 +273,134 @@ public class VelocityTabList implements InternalTabList {
|
||||
this.connection.write(new UpsertPlayerInfoPacket(EnumSet.of(action), List.of(entry)));
|
||||
}
|
||||
|
||||
private EnumSet<ServerUpdateTabListEvent.Action> mapToEventActions(EnumSet<UpsertPlayerInfoPacket.Action> packetActions) {
|
||||
EnumSet<ServerUpdateTabListEvent.Action> actions = EnumSet.noneOf(ServerUpdateTabListEvent.Action.class);
|
||||
|
||||
for (UpsertPlayerInfoPacket.Action packetAction : packetActions) {
|
||||
switch (packetAction) {
|
||||
case ADD_PLAYER -> {
|
||||
actions.add(ServerUpdateTabListEvent.Action.ADD_PLAYER);
|
||||
}
|
||||
case INITIALIZE_CHAT -> {
|
||||
actions.add(ServerUpdateTabListEvent.Action.INITIALIZE_CHAT);
|
||||
}
|
||||
case UPDATE_GAME_MODE -> {
|
||||
actions.add(ServerUpdateTabListEvent.Action.UPDATE_GAME_MODE);
|
||||
}
|
||||
case UPDATE_LISTED -> {
|
||||
actions.add(ServerUpdateTabListEvent.Action.UPDATE_LISTED);
|
||||
}
|
||||
case UPDATE_LATENCY -> {
|
||||
actions.add(ServerUpdateTabListEvent.Action.UPDATE_LATENCY);
|
||||
}
|
||||
case UPDATE_DISPLAY_NAME -> {
|
||||
actions.add(ServerUpdateTabListEvent.Action.UPDATE_DISPLAY_NAME);
|
||||
}
|
||||
default -> {
|
||||
// Nothing we can do here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
private List<UpdateEventTabListEntry> mapToEventEntries(EnumSet<UpsertPlayerInfoPacket.Action> actions,
|
||||
List<UpsertPlayerInfoPacket.Entry> packetEntries) {
|
||||
List<UpdateEventTabListEntry> entries = new ArrayList<>(packetEntries.size());
|
||||
|
||||
for (UpsertPlayerInfoPacket.Entry rawEntry : packetEntries) {
|
||||
Preconditions.checkNotNull(rawEntry.getProfileId(), "Profile ID cannot be null");
|
||||
UUID profileId = rawEntry.getProfileId();
|
||||
UpdateEventTabListEntry currentEntry = null;
|
||||
VelocityTabListEntry oldCurrentEntry = this.entries.get(profileId);
|
||||
|
||||
if (oldCurrentEntry != null) {
|
||||
currentEntry = new UpdateEventTabListEntry(
|
||||
this,
|
||||
oldCurrentEntry.getProfile(),
|
||||
oldCurrentEntry.getDisplayNameComponent().orElse(null),
|
||||
oldCurrentEntry.getLatency(),
|
||||
oldCurrentEntry.getGameMode(),
|
||||
oldCurrentEntry.getChatSession(),
|
||||
oldCurrentEntry.isListed()
|
||||
);
|
||||
}
|
||||
|
||||
if (actions.contains(UpsertPlayerInfoPacket.Action.ADD_PLAYER)) {
|
||||
if (currentEntry == null) {
|
||||
currentEntry = new UpdateEventTabListEntry(
|
||||
this,
|
||||
rawEntry.getProfile(),
|
||||
null,
|
||||
0,
|
||||
-1,
|
||||
null,
|
||||
false
|
||||
);
|
||||
} else {
|
||||
logger.debug("Received an add player packet for an existing entry; this does nothing.");
|
||||
}
|
||||
} else if (currentEntry == null) {
|
||||
logger.debug(
|
||||
"Received a partial player before an ADD_PLAYER action; profile could not be built. {}",
|
||||
rawEntry);
|
||||
continue;
|
||||
} else {
|
||||
currentEntry = new UpdateEventTabListEntry(
|
||||
this,
|
||||
currentEntry.getProfile(),
|
||||
currentEntry.getDisplayNameComponent().orElse(null),
|
||||
currentEntry.getLatency(),
|
||||
currentEntry.getGameMode(),
|
||||
currentEntry.getChatSession(),
|
||||
currentEntry.isListed()
|
||||
);
|
||||
}
|
||||
if (actions.contains(UpsertPlayerInfoPacket.Action.UPDATE_GAME_MODE)) {
|
||||
currentEntry.setGameModeWithoutRewrite(rawEntry.getGameMode());
|
||||
}
|
||||
if (actions.contains(UpsertPlayerInfoPacket.Action.UPDATE_LATENCY)) {
|
||||
currentEntry.setLatencyWithoutRewrite(rawEntry.getLatency());
|
||||
}
|
||||
if (actions.contains(UpsertPlayerInfoPacket.Action.UPDATE_DISPLAY_NAME)) {
|
||||
currentEntry.setDisplayNameWithoutRewrite(rawEntry.getDisplayName() != null
|
||||
? rawEntry.getDisplayName().getComponent() : null);
|
||||
}
|
||||
if (actions.contains(UpsertPlayerInfoPacket.Action.INITIALIZE_CHAT)) {
|
||||
currentEntry.setChatSessionWithoutRewrite(rawEntry.getChatSession());
|
||||
}
|
||||
if (actions.contains(UpsertPlayerInfoPacket.Action.UPDATE_LISTED)) {
|
||||
currentEntry.setListedWithoutRewrite(rawEntry.isListed());
|
||||
}
|
||||
entries.add(currentEntry);
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private List<UpdateEventTabListEntry> mapToEventEntries(Collection<UUID> uuids) {
|
||||
List<UpdateEventTabListEntry> entries = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<UUID, VelocityTabListEntry> entry : this.entries.entrySet()) {
|
||||
if (uuids.contains(entry.getKey())) {
|
||||
entries.add(
|
||||
new UpdateEventTabListEntry(
|
||||
this,
|
||||
entry.getValue().getProfile(),
|
||||
entry.getValue().getDisplayNameComponent().orElse(null),
|
||||
entry.getValue().getLatency(),
|
||||
entry.getValue().getGameMode(),
|
||||
entry.getValue().getChatSession(),
|
||||
entry.getValue().isListed()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private void processUpsert(EnumSet<UpsertPlayerInfoPacket.Action> actions,
|
||||
UpsertPlayerInfoPacket.Entry entry) {
|
||||
Preconditions.checkNotNull(entry.getProfileId(), "Profile ID cannot be null");
|
||||
@ -278,8 +448,34 @@ public class VelocityTabList implements InternalTabList {
|
||||
|
||||
@Override
|
||||
public void processRemove(RemovePlayerInfoPacket infoPacket) {
|
||||
for (UUID uuid : infoPacket.getProfilesToRemove()) {
|
||||
this.entries.remove(uuid);
|
||||
}
|
||||
List<UpdateEventTabListEntry> entries = mapToEventEntries(infoPacket.getProfilesToRemove());
|
||||
|
||||
proxyServer.getEventManager().fire(
|
||||
new ServerUpdateTabListEvent(
|
||||
player,
|
||||
Set.of(ServerUpdateTabListEvent.Action.REMOVE_PLAYER),
|
||||
Collections.unmodifiableList(entries)
|
||||
)
|
||||
).thenAcceptAsync(event -> { //not sure what should be used here!
|
||||
if (event.getResult().isAllowed()) {
|
||||
if (event.getResult().getIds().isEmpty()) {
|
||||
for (UUID uuid : infoPacket.getProfilesToRemove()) {
|
||||
this.entries.remove(uuid);
|
||||
}
|
||||
|
||||
connection.write(infoPacket);
|
||||
} else {
|
||||
List<UUID> uuids = new ArrayList<>();
|
||||
for (UUID uuid : infoPacket.getProfilesToRemove()) {
|
||||
if (event.getResult().getIds().contains(uuid)) {
|
||||
this.entries.remove(uuid);
|
||||
uuids.add(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
this.connection.write(new RemovePlayerInfoPacket(uuids));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ public class VelocityTabListEntry implements TabListEntry {
|
||||
|
||||
private final VelocityTabList tabList;
|
||||
private final GameProfile profile;
|
||||
private Component displayName;
|
||||
private @Nullable Component displayName;
|
||||
private int latency;
|
||||
private int gameMode;
|
||||
private boolean listed;
|
||||
@ -43,7 +43,7 @@ public class VelocityTabListEntry implements TabListEntry {
|
||||
/**
|
||||
* Constructs the instance.
|
||||
*/
|
||||
public VelocityTabListEntry(VelocityTabList tabList, GameProfile profile, Component displayName,
|
||||
public VelocityTabListEntry(VelocityTabList tabList, GameProfile profile, @Nullable Component displayName,
|
||||
int latency,
|
||||
int gameMode, @Nullable ChatSession session, boolean listed) {
|
||||
this.tabList = tabList;
|
||||
|
@ -17,16 +17,18 @@
|
||||
|
||||
package com.velocitypowered.proxy.tablist;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.velocitypowered.api.event.player.ServerUpdateTabListEvent;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||
import com.velocitypowered.api.util.GameProfile;
|
||||
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
|
||||
import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItemPacket;
|
||||
import com.velocitypowered.proxy.protocol.packet.LegacyPlayerListItemPacket.Item;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import net.kyori.adventure.text.Component;
|
||||
@ -82,11 +84,111 @@ public class VelocityTabListLegacy extends KeyedVelocityTabList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processLegacy(LegacyPlayerListItemPacket packet) {
|
||||
Item item = packet.getItems().get(0); // Only one item per packet in 1.7
|
||||
public void processLegacyUpdate(LegacyPlayerListItemPacket packet) {
|
||||
ServerUpdateTabListEvent.Action action = mapToEventAction(packet.getAction());
|
||||
Preconditions.checkNotNull(action, "action");
|
||||
|
||||
switch (packet.getAction()) {
|
||||
case LegacyPlayerListItemPacket.ADD_PLAYER:
|
||||
UpdateEventTabListEntry entry = mapToEventEntry(packet.getAction(), packet.getItems().get(0)); // Only one item per packet in 1.7
|
||||
|
||||
proxyServer.getEventManager().fire(
|
||||
new ServerUpdateTabListEvent(
|
||||
player,
|
||||
Set.of(action),
|
||||
Collections.singletonList(entry)
|
||||
)
|
||||
).thenAcceptAsync(event -> {
|
||||
if (event.getResult().isAllowed()) {
|
||||
if (event.getResult().getIds().isEmpty()) {
|
||||
if (entry.isRewrite()) {
|
||||
//listeners have modified the entry, requires manual processing
|
||||
if (action != ServerUpdateTabListEvent.Action.REMOVE_PLAYER) {
|
||||
if (this.entries.containsKey(entry.getProfile().getId())) {
|
||||
removeEntry(entry.getProfile().getId());
|
||||
}
|
||||
|
||||
addEntry(entry);
|
||||
} else {
|
||||
removeEntry(entry.getProfile().getId());
|
||||
}
|
||||
} else {
|
||||
//listeners haven't modified the entry
|
||||
processLegacy(packet.getAction(), packet.getItems().get(0));
|
||||
|
||||
connection.write(packet);
|
||||
}
|
||||
} else {
|
||||
//listeners have denied entries (and may have modified others), requires manual processing
|
||||
// (doesn't make much sense as there can only be one entry)
|
||||
if (action != ServerUpdateTabListEvent.Action.REMOVE_PLAYER) {
|
||||
if (event.getResult().getIds().contains(entry.getProfile().getId())) {
|
||||
if (this.entries.containsKey(entry.getProfile().getId())) {
|
||||
removeEntry(entry.getProfile().getId());
|
||||
}
|
||||
|
||||
addEntry(entry);
|
||||
}
|
||||
} else {
|
||||
if (event.getResult().getIds().contains(entry.getProfile().getId())) {
|
||||
removeEntry(entry.getProfile().getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private UpdateEventTabListEntry mapToEventEntry(int action, LegacyPlayerListItemPacket.Item packetItem) {
|
||||
UpdateEventTabListEntry currentEntry = null;
|
||||
|
||||
switch (action) {
|
||||
case LegacyPlayerListItemPacket.ADD_PLAYER -> {
|
||||
if (nameMapping.containsKey(packetItem.getName())) { // ADD_PLAYER also used for updating ping
|
||||
KeyedVelocityTabListEntry oldCurrentEntry = this.entries.get(nameMapping.get(packetItem.getName()));
|
||||
|
||||
if (oldCurrentEntry != null) {
|
||||
currentEntry = new UpdateEventTabListEntry(
|
||||
this,
|
||||
oldCurrentEntry.getProfile(),
|
||||
oldCurrentEntry.getDisplayNameComponent().orElse(null),
|
||||
oldCurrentEntry.getLatency(),
|
||||
oldCurrentEntry.getGameMode(),
|
||||
oldCurrentEntry.getChatSession(),
|
||||
oldCurrentEntry.isListed()
|
||||
);
|
||||
}
|
||||
|
||||
if (currentEntry != null) {
|
||||
currentEntry.setLatencyWithoutRewrite(packetItem.getLatency());
|
||||
}
|
||||
} else {
|
||||
UUID uuid = UUID.randomUUID(); // Use a fake uuid to preserve function of custom entries
|
||||
|
||||
nameMapping.put(packetItem.getName(), uuid);
|
||||
currentEntry = new UpdateEventTabListEntry(
|
||||
this,
|
||||
new GameProfile(uuid, packetItem.getName(), ImmutableList.of()),
|
||||
null,
|
||||
packetItem.getLatency(),
|
||||
0,
|
||||
null,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
case LegacyPlayerListItemPacket.REMOVE_PLAYER -> {
|
||||
//Nothing should be done here as all entries which are not allowed are removed if the action is ServerUpdateTabListEvent.Action.REMOVE_PLAYER
|
||||
}
|
||||
default -> {
|
||||
// For 1.7 there is only add and remove
|
||||
}
|
||||
}
|
||||
|
||||
return currentEntry;
|
||||
}
|
||||
|
||||
private void processLegacy(int action, LegacyPlayerListItemPacket.Item item) {
|
||||
switch (action) {
|
||||
case LegacyPlayerListItemPacket.ADD_PLAYER -> {
|
||||
if (nameMapping.containsKey(item.getName())) { // ADD_PLAYER also used for updating ping
|
||||
KeyedVelocityTabListEntry entry = entries.get(nameMapping.get(item.getName()));
|
||||
if (entry != null) {
|
||||
@ -101,16 +203,16 @@ public class VelocityTabListLegacy extends KeyedVelocityTabList {
|
||||
.latency(item.getLatency())
|
||||
.build());
|
||||
}
|
||||
break;
|
||||
case LegacyPlayerListItemPacket.REMOVE_PLAYER:
|
||||
}
|
||||
case LegacyPlayerListItemPacket.REMOVE_PLAYER -> {
|
||||
UUID removedUuid = nameMapping.remove(item.getName());
|
||||
if (removedUuid != null) {
|
||||
entries.remove(removedUuid);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default -> {
|
||||
// For 1.7 there is only add and remove
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren