forked from Upstream/Velocitab
Added PlayerAddedToTabEvent, improved PlayerTabList performance and more (#114)
Added PlayerAddedToTabEvent, improved PlayerTabList performance and added the possibility to reload the plugin without breaking the tab list. This is only for dev purposes. Bumped version to 1.5.2 Fixed a few problems.
This commit is contained in:
parent
c82a0c75d8
commit
c36e17b75e
@ -59,4 +59,20 @@ You can also use `VelocitabAPI#getCustomPlayerName` which accepts a Velocity `Pl
|
||||
// Getting a player's custom name
|
||||
Optional<String> customName = velocitabAPI.getCustomPlayerName(player);
|
||||
```
|
||||
</details>
|
||||
|
||||
## 3. Listening to PlayerAddedToTabEvent
|
||||
You can listen to `PlayerAddedToTabEvent` to get notified when a player is added to a group TabList.
|
||||
|
||||
<details>
|
||||
<summary>Example — Listening to PlayerAddToTabEvent</summary>
|
||||
|
||||
```java
|
||||
@Subscribe
|
||||
public void onPlayerAddToTab(PlayerAddToTabEvent event) {
|
||||
VelocitabAPI velocitabAPI = VelocitabAPI.getInstance();
|
||||
velocitabAPI.setCustomPlayerName(event.getPlayer().getPlayer(), "CustomName");
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
@ -9,7 +9,7 @@ The Velocitab API shares version numbering with the plugin itself for consistenc
|
||||
|
||||
| API Version | Velocitab Versions | Supported |
|
||||
|:-----------:|:----------------------:|:---------:|
|
||||
| v1.x | _v1.5.1—Current_ | ✅ |
|
||||
| v1.x | _v1.5.2—Current_ | ✅ |
|
||||
|
||||
## Table of contents
|
||||
1. Adding the API to your project
|
||||
|
@ -3,6 +3,6 @@ javaVersion=16
|
||||
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
|
||||
org.gradle.daemon=true
|
||||
|
||||
plugin_version=1.5.1
|
||||
plugin_version=1.5.2
|
||||
plugin_archive=velocitab
|
||||
plugin_description=A beautiful and versatile TAB list plugin for Velocity proxies
|
||||
|
@ -59,6 +59,7 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Plugin(id = "velocitab")
|
||||
public class Velocitab {
|
||||
@ -89,10 +90,10 @@ public class Velocitab {
|
||||
public void onProxyInitialization(@NotNull ProxyInitializeEvent event) {
|
||||
loadSettings();
|
||||
loadHooks();
|
||||
prepareVanishManager();
|
||||
prepareScoreboardManager();
|
||||
prepareTabList();
|
||||
prepareSortingManager();
|
||||
prepareVanishManager();
|
||||
registerCommands();
|
||||
registerMetrics();
|
||||
checkForUpdates();
|
||||
@ -104,6 +105,7 @@ public class Velocitab {
|
||||
public void onProxyShutdown(@NotNull ProxyShutdownEvent event) {
|
||||
server.getScheduler().tasksByPlugin(this).forEach(ScheduledTask::cancel);
|
||||
disableScoreboardManager();
|
||||
disableTabList();
|
||||
getLuckPermsHook().ifPresent(LuckPermsHook::close);
|
||||
VelocitabAPI.unregister();
|
||||
logger.info("Successfully disabled Velocitab");
|
||||
@ -174,10 +176,17 @@ public class Velocitab {
|
||||
|
||||
private void disableScoreboardManager() {
|
||||
if (scoreboardManager != null && settings.isSendScoreboardPackets()) {
|
||||
scoreboardManager.close();
|
||||
scoreboardManager.unregisterPacket();
|
||||
}
|
||||
}
|
||||
|
||||
private void disableTabList() {
|
||||
if (tabList != null) {
|
||||
tabList.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareVanishManager() {
|
||||
this.vanishManager = new VanishManager(this);
|
||||
}
|
||||
@ -204,10 +213,12 @@ public class Velocitab {
|
||||
private void prepareTabList() {
|
||||
this.tabList = new PlayerTabList(this);
|
||||
server.getEventManager().register(this, tabList);
|
||||
|
||||
server.getScheduler().buildTask(this, tabList::load).delay(1, TimeUnit.SECONDS).schedule();
|
||||
}
|
||||
|
||||
private void prepareAPI() {
|
||||
VelocitabAPI.register(this);
|
||||
VelocitabAPI.register(this);
|
||||
}
|
||||
|
||||
private void registerCommands() {
|
||||
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of Velocitab, licensed under the Apache License 2.0.
|
||||
*
|
||||
* Copyright (c) William278 <will27528@gmail.com>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.william278.velocitab.api;
|
||||
|
||||
import net.william278.velocitab.player.TabPlayer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public record PlayerAddedToTabEvent(TabPlayer player, String group, List<String> groupServers) {
|
||||
|
||||
}
|
@ -43,7 +43,7 @@ public enum Placeholder {
|
||||
.orElse("")),
|
||||
CURRENT_DATE((plugin, player) -> DateTimeFormatter.ofPattern("dd MMM yyyy").format(LocalDateTime.now())),
|
||||
CURRENT_TIME((plugin, player) -> DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now())),
|
||||
USERNAME((plugin, player) -> plugin.getFormatter().escape(player.getCustomName().orElse(player.getPlayer().getUsername()))),
|
||||
USERNAME((plugin, player) -> player.getCustomName().orElse(player.getPlayer().getUsername())),
|
||||
SERVER((plugin, player) -> player.getServerDisplayName(plugin)),
|
||||
PING((plugin, player) -> Long.toString(player.getPlayer().getPing())),
|
||||
PREFIX((plugin, player) -> player.getRole().getPrefix().orElse("")),
|
||||
|
@ -67,6 +67,10 @@ public class ScoreboardManager {
|
||||
.orElseThrow(() -> new IllegalArgumentException("No adapter found for protocol version " + version));
|
||||
}
|
||||
|
||||
public void close() {
|
||||
plugin.getServer().getAllPlayers().forEach(this::resetCache);
|
||||
}
|
||||
|
||||
public void resetCache(@NotNull Player player) {
|
||||
final String team = createdTeams.remove(player.getUniqueId());
|
||||
if (team != null) {
|
||||
@ -92,10 +96,10 @@ public class ScoreboardManager {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateTeamsPacket packet = UpdateTeamsPacket.removeTeam(plugin, createdTeams.get(player.getUniqueId()));
|
||||
final UpdateTeamsPacket packet = UpdateTeamsPacket.removeTeam(plugin, teamName);
|
||||
|
||||
siblings.forEach(server -> server.getPlayersConnected().forEach(connected -> {
|
||||
boolean canSee = !plugin.getVanishManager().isVanished(connected.getUsername())
|
||||
final boolean canSee = !plugin.getVanishManager().isVanished(connected.getUsername())
|
||||
|| plugin.getVanishManager().canSee(player.getUsername(), player.getUsername());
|
||||
|
||||
if (!canSee) {
|
||||
@ -145,6 +149,7 @@ public class ScoreboardManager {
|
||||
|
||||
final String name = player.getUsername();
|
||||
final TabPlayer tabPlayer = plugin.getTabList().getTabPlayer(player).orElseThrow();
|
||||
|
||||
tabPlayer.getNametag(plugin).thenAccept(nametag -> {
|
||||
final String[] split = nametag.split(player.getUsername(), 2);
|
||||
final String prefix = split[0];
|
||||
|
@ -32,15 +32,18 @@ import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||
import com.velocitypowered.api.scheduler.ScheduledTask;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.william278.velocitab.Velocitab;
|
||||
import net.william278.velocitab.api.PlayerAddedToTabEvent;
|
||||
import net.william278.velocitab.config.Placeholder;
|
||||
import net.william278.velocitab.player.Role;
|
||||
import net.william278.velocitab.player.TabPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -49,13 +52,13 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public class PlayerTabList {
|
||||
private final Velocitab plugin;
|
||||
private final ConcurrentLinkedQueue<TabPlayer> players;
|
||||
private final ConcurrentHashMap<UUID, TabPlayer> players;
|
||||
private final ConcurrentLinkedQueue<String> fallbackServers;
|
||||
private ScheduledTask updateTask;
|
||||
|
||||
public PlayerTabList(@NotNull Velocitab plugin) {
|
||||
this.plugin = plugin;
|
||||
this.players = new ConcurrentLinkedQueue<>();
|
||||
this.players = new ConcurrentHashMap<>();
|
||||
this.fallbackServers = new ConcurrentLinkedQueue<>();
|
||||
|
||||
// If the update time is set to 0 do not schedule the updater
|
||||
@ -64,8 +67,51 @@ public class PlayerTabList {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a TabPlayer object corresponding to the given Player object.
|
||||
*
|
||||
* @param player The Player object for which to retrieve the corresponding TabPlayer.
|
||||
* @return An Optional object containing the TabPlayer if found, or an empty Optional if not found.
|
||||
*/
|
||||
public Optional<TabPlayer> getTabPlayer(@NotNull Player player) {
|
||||
return players.stream().filter(tabPlayer -> tabPlayer.getPlayer().getUniqueId().equals(player.getUniqueId())).findFirst();
|
||||
return Optional.ofNullable(players.get(player.getUniqueId()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads the tab list for all players connected to the server.
|
||||
* Removes the player's entry from the tab list of all other players on the same group servers.
|
||||
*/
|
||||
public void load() {
|
||||
plugin.getServer().getAllPlayers().forEach(p -> {
|
||||
final Optional<ServerConnection> server = p.getCurrentServer();
|
||||
if (server.isEmpty()) return;
|
||||
|
||||
final List<RegisteredServer> serversInGroup = new ArrayList<>(getGroupServers(server.get().getServerInfo().getName()));
|
||||
if (serversInGroup.isEmpty()) return;
|
||||
|
||||
serversInGroup.remove(server.get().getServer());
|
||||
|
||||
joinPlayer(p, serversInGroup.stream().map(s -> s.getServerInfo().getName()).toList());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the tab list for all players connected to the server.
|
||||
* Removes the player's entry from the tab list of all other players on the same group servers.
|
||||
*/
|
||||
public void close() {
|
||||
plugin.getServer().getAllPlayers().forEach(p -> {
|
||||
final Optional<ServerConnection> server = p.getCurrentServer();
|
||||
if (server.isEmpty()) return;
|
||||
|
||||
final List<RegisteredServer> serversInGroup = new ArrayList<>(getGroupServers(server.get().getServerInfo().getName()));
|
||||
if (serversInGroup.isEmpty()) return;
|
||||
|
||||
serversInGroup.remove(server.get().getServer());
|
||||
|
||||
serversInGroup.forEach(s -> s.getPlayersConnected().forEach(t -> t.getTabList().removeEntry(p.getUniqueId())));
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
@ -88,22 +134,27 @@ public class PlayerTabList {
|
||||
if (serversInGroup.isEmpty() &&
|
||||
(previousServer != null && !this.fallbackServers.contains(previousServer.getServerInfo().getName()))) {
|
||||
event.getPlayer().sendPlayerListHeaderAndFooter(Component.empty(), Component.empty());
|
||||
players.remove(event.getPlayer().getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
joinPlayer(joined, serversInGroup.orElseGet(ArrayList::new));
|
||||
}
|
||||
|
||||
private void joinPlayer(@NotNull Player joined, @NotNull List<String> serversInGroup) {
|
||||
// Add the player to the tracking list if they are not already listed
|
||||
final TabPlayer tabPlayer = getTabPlayer(joined).orElseGet(() -> createTabPlayer(joined));
|
||||
players.add(tabPlayer);
|
||||
players.putIfAbsent(joined.getUniqueId(), tabPlayer);
|
||||
|
||||
final boolean isVanished = plugin.getVanishManager().isVanished(joined.getUsername());
|
||||
// Update lists
|
||||
plugin.getServer().getScheduler()
|
||||
.buildTask(plugin, () -> {
|
||||
final TabList tabList = joined.getTabList();
|
||||
for (TabPlayer player : players) {
|
||||
for (final TabPlayer player : players.values()) {
|
||||
// Skip players on other servers if the setting is enabled
|
||||
if (plugin.getSettings().isOnlyListPlayersInSameGroup() && serversInGroup.isPresent()
|
||||
&& !serversInGroup.get().contains(player.getServerName())) {
|
||||
if (plugin.getSettings().isOnlyListPlayersInSameGroup()
|
||||
&& !serversInGroup.contains(player.getServerName())) {
|
||||
continue;
|
||||
}
|
||||
// check if current player can see the joined player
|
||||
@ -117,12 +168,10 @@ public class PlayerTabList {
|
||||
!plugin.getVanishManager().canSee(joined.getUsername(), player.getPlayer().getUsername())) && player.getPlayer() != joined) {
|
||||
tabList.removeEntry(player.getPlayer().getUniqueId());
|
||||
} else {
|
||||
tabList.getEntries().stream()
|
||||
.filter(e -> e.getProfile().getId().equals(player.getPlayer().getUniqueId())).findFirst()
|
||||
.ifPresentOrElse(
|
||||
entry -> player.getDisplayName(plugin).thenAccept(entry::setDisplayName),
|
||||
() -> createEntry(player, tabList).thenAccept(tabList::addEntry)
|
||||
);
|
||||
tabList.getEntry(player.getPlayer().getUniqueId()).ifPresentOrElse(
|
||||
entry -> player.getDisplayName(plugin).thenAccept(entry::setDisplayName),
|
||||
() -> createEntry(player, tabList).thenAccept(tabList::addEntry)
|
||||
);
|
||||
}
|
||||
|
||||
player.sendHeaderAndFooter(this);
|
||||
@ -132,6 +181,9 @@ public class PlayerTabList {
|
||||
s.resendAllTeams(joined);
|
||||
tabPlayer.getTeamName(plugin).thenAccept(t -> s.updateRole(joined, t));
|
||||
});
|
||||
|
||||
// Fire event without listening for result
|
||||
plugin.getServer().getEventManager().fireAndForget(new PlayerAddedToTabEvent(tabPlayer, tabPlayer.getServerGroup(plugin), serversInGroup));
|
||||
})
|
||||
.delay(500, TimeUnit.MILLISECONDS)
|
||||
.schedule();
|
||||
@ -147,9 +199,8 @@ public class PlayerTabList {
|
||||
.build());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private TabListEntry createEntry(@NotNull TabPlayer player, @NotNull TabList tabList, Component displayName) {
|
||||
return TabListEntry.builder()
|
||||
private void addEntry(@NotNull TabPlayer player, @NotNull TabList tabList, @NotNull Component displayName) {
|
||||
TabListEntry.builder()
|
||||
.profile(player.getPlayer().getGameProfile())
|
||||
.displayName(displayName)
|
||||
.latency(0)
|
||||
@ -173,20 +224,6 @@ public class PlayerTabList {
|
||||
|
||||
}
|
||||
|
||||
private void addPlayerToTabList(@NotNull TabPlayer player, @NotNull TabPlayer newPlayer, TabListEntry entry) {
|
||||
if (newPlayer.getPlayer().getUniqueId().equals(player.getPlayer().getUniqueId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isPresent = player.getPlayer()
|
||||
.getTabList().getEntries().stream()
|
||||
.noneMatch(e -> e.getProfile().getId().equals(newPlayer.getPlayer().getUniqueId()));
|
||||
|
||||
if (isPresent) {
|
||||
player.getPlayer().getTabList().addEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPlayerQuit(@NotNull DisconnectEvent event) {
|
||||
if (event.getLoginStatus() != DisconnectEvent.LoginStatus.SUCCESSFUL_LOGIN) {
|
||||
@ -195,9 +232,9 @@ public class PlayerTabList {
|
||||
|
||||
// Remove the player from the tracking list, Print warning if player was not removed
|
||||
final UUID uuid = event.getPlayer().getUniqueId();
|
||||
if (!players.removeIf(listed -> listed.getPlayer().getUniqueId().equals(uuid))) {
|
||||
if (players.remove(uuid) == null) {
|
||||
plugin.log(String.format("Failed to remove disconnecting player %s (UUID: %s)",
|
||||
event.getPlayer().getUsername(), uuid.toString()));
|
||||
event.getPlayer().getUsername(), uuid));
|
||||
}
|
||||
|
||||
// Remove the player from the tab list of all other players
|
||||
@ -205,7 +242,7 @@ public class PlayerTabList {
|
||||
|
||||
// Update the tab list of all players
|
||||
plugin.getServer().getScheduler()
|
||||
.buildTask(plugin, () -> players.forEach(player -> {
|
||||
.buildTask(plugin, () -> players.values().forEach(player -> {
|
||||
player.getPlayer().getTabList().removeEntry(uuid);
|
||||
player.sendHeaderAndFooter(this);
|
||||
}))
|
||||
@ -247,9 +284,9 @@ public class PlayerTabList {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isVanished = plugin.getVanishManager().isVanished(tabPlayer.getPlayer().getUsername());
|
||||
final boolean isVanished = plugin.getVanishManager().isVanished(tabPlayer.getPlayer().getUsername());
|
||||
|
||||
players.forEach(player -> {
|
||||
players.values().forEach(player -> {
|
||||
if (isVanished && !plugin.getVanishManager().canSee(player.getPlayer().getUsername(), tabPlayer.getPlayer().getUsername())) {
|
||||
return;
|
||||
}
|
||||
@ -263,7 +300,7 @@ public class PlayerTabList {
|
||||
|
||||
// Update the display names of all listed players
|
||||
public void updateDisplayNames() {
|
||||
players.forEach(this::updatePlayerDisplayName);
|
||||
players.values().forEach(this::updatePlayerDisplayName);
|
||||
}
|
||||
|
||||
// Get the component for the TAB list header
|
||||
@ -291,7 +328,7 @@ public class PlayerTabList {
|
||||
if (players.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
players.forEach(player -> {
|
||||
players.values().forEach(player -> {
|
||||
this.updatePlayer(player);
|
||||
player.sendHeaderAndFooter(this);
|
||||
});
|
||||
@ -316,7 +353,7 @@ public class PlayerTabList {
|
||||
if (plugin.getSettings().getUpdateRate() > 0) {
|
||||
this.updatePeriodically(plugin.getSettings().getUpdateRate());
|
||||
} else {
|
||||
players.forEach(player -> {
|
||||
players.values().forEach(player -> {
|
||||
this.updatePlayer(player);
|
||||
player.sendHeaderAndFooter(this);
|
||||
});
|
||||
@ -382,11 +419,11 @@ public class PlayerTabList {
|
||||
* @param player The player to remove
|
||||
*/
|
||||
public void removeOfflinePlayer(@NotNull Player player) {
|
||||
players.removeIf(tabPlayer -> tabPlayer.getPlayer().getUniqueId().equals(player.getUniqueId()));
|
||||
players.remove(player.getUniqueId());
|
||||
}
|
||||
|
||||
public void vanishPlayer(@NotNull TabPlayer tabPlayer) {
|
||||
players.forEach(p -> {
|
||||
players.values().forEach(p -> {
|
||||
if (p.getPlayer().equals(tabPlayer.getPlayer())) {
|
||||
return;
|
||||
}
|
||||
@ -401,13 +438,13 @@ public class PlayerTabList {
|
||||
final UUID uuid = tabPlayer.getPlayer().getUniqueId();
|
||||
|
||||
tabPlayer.getDisplayName(plugin).thenAccept(c -> {
|
||||
players.forEach(p -> {
|
||||
players.values().forEach(p -> {
|
||||
if (p.getPlayer().equals(tabPlayer.getPlayer())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!p.getPlayer().getTabList().containsEntry(uuid)) {
|
||||
createEntry(tabPlayer, p.getPlayer().getTabList(), c);
|
||||
addEntry(tabPlayer, p.getPlayer().getTabList(), c);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user