geforkt von SteamWar/BungeeCore
Untested full tablist
Signed-off-by: Lixfel <agga-games@gmx.de>
Dieser Commit ist enthalten in:
Ursprung
2e17c380f0
Commit
f2ed575f8c
@ -1,335 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is a part of the SteamWar software.
|
|
||||||
|
|
||||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bungeecore.listeners;
|
|
||||||
|
|
||||||
import codecrafter47.bungeetablistplus.api.bungee.BungeeTabListPlusAPI;
|
|
||||||
import codecrafter47.bungeetablistplus.api.bungee.Icon;
|
|
||||||
import codecrafter47.bungeetablistplus.tablist.DefaultCustomTablist;
|
|
||||||
import de.steamwar.bungeecore.BungeeCore;
|
|
||||||
import de.steamwar.bungeecore.Message;
|
|
||||||
import de.steamwar.bungeecore.Servertype;
|
|
||||||
import de.steamwar.bungeecore.Subserver;
|
|
||||||
import de.steamwar.bungeecore.sql.SteamwarUser;
|
|
||||||
import de.steamwar.bungeecore.sql.UserGroup;
|
|
||||||
import net.md_5.bungee.BungeeCord;
|
|
||||||
import de.steamwar.network.packets.common.FightInfoPacket;
|
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
||||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
|
||||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
|
||||||
import net.md_5.bungee.event.EventHandler;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class TablistManager extends BasicListener {
|
|
||||||
|
|
||||||
private static final Map<ProxiedPlayer, Tablist> tablists = new HashMap<>();
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public synchronized void onJoin(PostLoginEvent e){
|
|
||||||
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
|
|
||||||
if (e.getPlayer().isConnected()) {
|
|
||||||
tablists.put(e.getPlayer(), new Tablist(e.getPlayer()));
|
|
||||||
}
|
|
||||||
}, 1, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public synchronized void onLeave(PlayerDisconnectEvent e){
|
|
||||||
tablists.remove(e.getPlayer());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static final Map<ServerInfo, FightInfoPacket> fightInfos = new HashMap<>();
|
|
||||||
|
|
||||||
public static synchronized void newFightInfo(ServerInfo info, FightInfoPacket packet) {
|
|
||||||
fightInfos.put(info, packet);
|
|
||||||
fightInfos.keySet().removeIf(serverInfo -> serverInfo.getPlayers().isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static Icon darkGray;
|
|
||||||
private static Icon gray;
|
|
||||||
|
|
||||||
private int seconds = 0;
|
|
||||||
private int size;
|
|
||||||
private TablistGroup tablist;
|
|
||||||
|
|
||||||
public TablistManager(){
|
|
||||||
ProxyServer.getInstance().getScheduler().schedule(BungeeCore.get(), this::updateTablist, 1, 1, TimeUnit.SECONDS);
|
|
||||||
try{
|
|
||||||
BungeeTabListPlusAPI.createIcon(ImageIO.read(new File("/configs/BungeeTabListPlus/heads/colors/dark_gray.png")), (icon) -> darkGray = icon);
|
|
||||||
BungeeTabListPlusAPI.createIcon(ImageIO.read(new File("/configs/BungeeTabListPlus/heads/colors/gray.png")), (icon) -> gray = icon);
|
|
||||||
}catch(IOException e){
|
|
||||||
throw new SecurityException("Could not load icons", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
ProxyServer.getInstance().getPlayers().forEach(p -> tablists.put(p, new Tablist(p)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void updateTablist(){
|
|
||||||
//Calculate server-player-map
|
|
||||||
tablist = new TablistGroup(true, "");
|
|
||||||
TablistGroup bau = new TablistGroup(false, "Bau");
|
|
||||||
for (ServerInfo server : new ArrayList<>(ProxyServer.getInstance().getServers().values())){
|
|
||||||
if(server.getPlayers().isEmpty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Subserver subserver = Subserver.getSubserver(server);
|
|
||||||
if(subserver != null && subserver.getType() == Servertype.BAUSERVER)
|
|
||||||
bau.addSubTablist(new TablistServer(server));
|
|
||||||
else if(fightInfos.containsKey(server))
|
|
||||||
tablist.addSubTablist(new TablistServer(server, fightInfos.get(server)));
|
|
||||||
else
|
|
||||||
tablist.addSubTablist(new TablistServer(server));
|
|
||||||
}
|
|
||||||
if(bau.size() > 0)
|
|
||||||
tablist.addSubTablist(bau);
|
|
||||||
|
|
||||||
size = (int) Math.ceil((tablist.size() - 1) / 20.0);
|
|
||||||
tablists.values().forEach(Tablist::refresh);
|
|
||||||
seconds++;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Tablist extends DefaultCustomTablist {
|
|
||||||
private final ProxiedPlayer player;
|
|
||||||
private int pos = 0;
|
|
||||||
|
|
||||||
private Tablist(ProxiedPlayer player){
|
|
||||||
this.player = player;
|
|
||||||
BungeeTabListPlusAPI.setCustomTabList(player, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String header(){
|
|
||||||
int phase = (seconds % 16) / 3;
|
|
||||||
switch(phase){
|
|
||||||
case 0:
|
|
||||||
return Message.parse("TABLIST_PHASE_1", player);
|
|
||||||
case 1:
|
|
||||||
return Message.parse("TABLIST_PHASE_2", player);
|
|
||||||
case 2:
|
|
||||||
default:
|
|
||||||
return Message.parse("TABLIST_PHASE_DEFAULT", player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String ping(){
|
|
||||||
int ping = player.getPing();
|
|
||||||
if(ping < 50){
|
|
||||||
return "§a" + ping;
|
|
||||||
}else if(ping < 150){
|
|
||||||
return "§e" + ping;
|
|
||||||
}else{
|
|
||||||
return "§c" + ping;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refresh(){
|
|
||||||
if (player.getServer() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pos = 0;
|
|
||||||
setHeader(header());
|
|
||||||
setFooter(Message.parse("TABLIST_FOOTER", player, player.getServer().getInfo().getName(), ping(), ProxyServer.getInstance().getPlayers().size()));
|
|
||||||
int currentSize = size > 4 ? tablist.slimSize(player) : size;
|
|
||||||
setSize(currentSize, 20);
|
|
||||||
|
|
||||||
tablist.print(this, size > 4);
|
|
||||||
|
|
||||||
while (pos < currentSize*20){
|
|
||||||
setSlot(darkGray, "", 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setSlot(Icon icon, String name, int ping){
|
|
||||||
if(pos / 20 >= getColumns())
|
|
||||||
return;
|
|
||||||
|
|
||||||
setSlot(pos % 20, pos / 20, icon, name, ping);
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private interface TablistPart {
|
|
||||||
int size();
|
|
||||||
int slimSize(ProxiedPlayer viewer);
|
|
||||||
String name();
|
|
||||||
void print(Tablist viewer, boolean slim);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TablistGroup implements TablistPart {
|
|
||||||
|
|
||||||
private final boolean withHeaders;
|
|
||||||
private final String orderName;
|
|
||||||
private final List<TablistPart> subTablists = new ArrayList<>();
|
|
||||||
|
|
||||||
private TablistGroup(boolean withHeaders, String orderName) {
|
|
||||||
this.withHeaders = withHeaders;
|
|
||||||
this.orderName = orderName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addSubTablist(TablistPart tablist){
|
|
||||||
subTablists.add(tablist);
|
|
||||||
subTablists.sort((t1, t2) -> t1.name().compareToIgnoreCase(t2.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return slimSize(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int slimSize(ProxiedPlayer viewer) {
|
|
||||||
return subTablists.stream().mapToInt(tPart -> viewer == null ? tPart.size() : tPart.slimSize(viewer)).map(size -> {
|
|
||||||
size += withHeaders ? 1 : 0; // Space for header
|
|
||||||
size += withHeaders && size > 1 ? 1 : 0; // Space for footer
|
|
||||||
return size;
|
|
||||||
}).sum();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String name() {
|
|
||||||
return orderName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void print(Tablist viewer, boolean slim) {
|
|
||||||
for (int i = 0; i < subTablists.size(); i++) {
|
|
||||||
TablistPart tPart = subTablists.get(i);
|
|
||||||
String name = tPart.name();
|
|
||||||
if (name.equals("Bau")) {
|
|
||||||
name = Message.parse("TABLIST_BAU", viewer.player);
|
|
||||||
}
|
|
||||||
boolean withoutFooter = i == subTablists.size() - 1;
|
|
||||||
if (withHeaders) {
|
|
||||||
if (slim) {
|
|
||||||
int slimSize = tPart.slimSize(viewer.player);
|
|
||||||
int size = tPart.size();
|
|
||||||
if (size == slimSize) {
|
|
||||||
viewer.setSlot(gray, "§7§l" + name, 1000);
|
|
||||||
} else if (slimSize == 0) {
|
|
||||||
viewer.setSlot(gray, "§7§l" + name + " §8(§7" + size + "§8)", 1000);
|
|
||||||
withoutFooter = true;
|
|
||||||
} else {
|
|
||||||
viewer.setSlot(gray, "§7§l" + name + " §8(§7+" + (size - slimSize) + "§8)", 1000);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
viewer.setSlot(gray, "§7§l" + name, 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tPart.print(viewer, slim);
|
|
||||||
if (withHeaders && !withoutFooter) {
|
|
||||||
viewer.setSlot(darkGray, "", 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TablistServer implements TablistPart {
|
|
||||||
private static class TablistPlayer {
|
|
||||||
private final ProxiedPlayer player;
|
|
||||||
private final String defaultName;
|
|
||||||
|
|
||||||
private TablistPlayer(ProxiedPlayer player, String defaultName) {
|
|
||||||
this.player = player;
|
|
||||||
this.defaultName = defaultName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private final List<TablistPlayer> players = new ArrayList<>();
|
|
||||||
private final ServerInfo info;
|
|
||||||
private final Subserver subserver;
|
|
||||||
|
|
||||||
private TablistServer(ServerInfo info, FightInfoPacket packet){
|
|
||||||
this.info = info;
|
|
||||||
subserver = Subserver.getSubserver(info);
|
|
||||||
Collection<ProxiedPlayer> onlinePlayers = info.getPlayers();
|
|
||||||
addPlayers(packet.getBlueName().substring(0, 2), packet.getBluePlayers(), onlinePlayers);
|
|
||||||
addPlayers(packet.getRedName().substring(0, 2), packet.getRedPlayers(), onlinePlayers);
|
|
||||||
addPlayers("§7", packet.getSpectators(), onlinePlayers);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addPlayers(String prefix, List<Integer> teamPlayers, Collection<ProxiedPlayer> onlinePlayers){
|
|
||||||
teamPlayers.stream().map(SteamwarUser::get).map(
|
|
||||||
user -> onlinePlayers.stream().filter(player -> player.getUniqueId().equals(user.getUuid())).findAny()
|
|
||||||
).filter(Optional::isPresent).map(Optional::get).sorted(
|
|
||||||
(p1, p2) -> p1.getName().compareToIgnoreCase(p2.getName())
|
|
||||||
).forEachOrdered(player -> players.add(new TablistPlayer(player, prefix + player.getName())));
|
|
||||||
}
|
|
||||||
|
|
||||||
private TablistServer(ServerInfo info) {
|
|
||||||
this.info = info;
|
|
||||||
subserver = Subserver.getSubserver(info);
|
|
||||||
info.getPlayers().forEach(player -> players.add(new TablistPlayer(player, SteamwarUser.get(player.getUniqueId()).getUserGroup().getColorCode() + player.getName())));
|
|
||||||
players.sort((tp1, tp2) -> tp1.player.getName().compareToIgnoreCase(tp2.player.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean displaySlim(ProxiedPlayer viewer, ProxiedPlayer player){
|
|
||||||
if(viewer.getServer().getInfo() == info)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(subserver != null && subserver.getType() == Servertype.ARENA && info.getPlayers().size() == 1)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
SteamwarUser user = SteamwarUser.get(player);
|
|
||||||
if(user.getUserGroup() != UserGroup.Member)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return user.getTeam() != 0 && SteamwarUser.get(viewer).getTeam() == user.getTeam();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return players.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int slimSize(ProxiedPlayer viewer) {
|
|
||||||
if(viewer.getServer().getInfo() == info)
|
|
||||||
return size();
|
|
||||||
|
|
||||||
return players.stream().mapToInt(player -> displaySlim(viewer, player.player) ? 1 : 0).sum();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String name() {
|
|
||||||
return info.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void print(Tablist viewer, boolean slim) {
|
|
||||||
boolean sameServer = viewer.player.getServer().getInfo() == info;
|
|
||||||
|
|
||||||
SteamwarUser user = SteamwarUser.get(viewer.player.getUniqueId());
|
|
||||||
for(TablistPlayer player : players){
|
|
||||||
if(slim && !displaySlim(viewer.player, player.player))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int ping = sameServer ? 1 : 1000;
|
|
||||||
String name = player.defaultName.startsWith("§7") && user.getTeam() != 0 && user.getTeam() == SteamwarUser.get(player.player.getUniqueId()).getTeam() ? "§f" + player.player.getName() : player.defaultName;
|
|
||||||
viewer.setSlot(BungeeTabListPlusAPI.getIconFromPlayer(player.player), name, ping);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,10 +19,9 @@
|
|||||||
|
|
||||||
package de.steamwar.bungeecore.network.handlers;
|
package de.steamwar.bungeecore.network.handlers;
|
||||||
|
|
||||||
import de.steamwar.bungeecore.listeners.TablistManager;
|
|
||||||
import de.steamwar.bungeecore.network.NetworkReceiver;
|
|
||||||
import de.steamwar.bungeecore.network.NetworkSender;
|
import de.steamwar.bungeecore.network.NetworkSender;
|
||||||
import de.steamwar.bungeecore.network.ServerMetaInfo;
|
import de.steamwar.bungeecore.network.ServerMetaInfo;
|
||||||
|
import de.steamwar.bungeecore.tablist.TablistManager;
|
||||||
import de.steamwar.network.packets.PacketHandler;
|
import de.steamwar.network.packets.PacketHandler;
|
||||||
import de.steamwar.network.packets.common.FightInfoPacket;
|
import de.steamwar.network.packets.common.FightInfoPacket;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
|
240
src/de/steamwar/bungeecore/tablist/Tablist.java
Normale Datei
240
src/de/steamwar/bungeecore/tablist/Tablist.java
Normale Datei
@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bungeecore.tablist;
|
||||||
|
|
||||||
|
import de.steamwar.messages.ChatSender;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
import net.md_5.bungee.ServerConnection;
|
||||||
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
import net.md_5.bungee.netty.PipelineUtils;
|
||||||
|
import net.md_5.bungee.protocol.DefinedPacket;
|
||||||
|
import net.md_5.bungee.protocol.PacketWrapper;
|
||||||
|
import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter;
|
||||||
|
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
||||||
|
import net.md_5.bungee.protocol.packet.Team;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
public class Tablist extends MessageToMessageDecoder<PacketWrapper> {
|
||||||
|
|
||||||
|
private static final UUID[] uuids = IntStream.range(0, 80).mapToObj(i -> UUID.randomUUID()).toArray(UUID[]::new);
|
||||||
|
private static final String[] names = IntStream.range(0, 80).mapToObj(i -> " »SW« " + i).toArray(String[]::new);
|
||||||
|
private static final String TAB_TEAM = "»SW-Tab";
|
||||||
|
private static final Team teamPacket = new Team(TAB_TEAM, (byte) 0, ComponentSerializer.toString(TextComponent.fromLegacyText("")), ComponentSerializer.toString(TextComponent.fromLegacyText("")), ComponentSerializer.toString(TextComponent.fromLegacyText("")), "never", "never", 21, (byte)0x00, names);
|
||||||
|
|
||||||
|
private final Map<UUID, PlayerListItem.Item> directlySent = new HashMap<>(); //TODO Persist over softreload
|
||||||
|
private final Set<UUID> npcs = new HashSet<>();
|
||||||
|
private final List<PlayerListItem.Item> current = new ArrayList<>();
|
||||||
|
|
||||||
|
private final ProxiedPlayer player;
|
||||||
|
private final ChatSender viewer;
|
||||||
|
private ServerConnection connection;
|
||||||
|
|
||||||
|
public Tablist(ProxiedPlayer player) {
|
||||||
|
this.player = player;
|
||||||
|
this.viewer = ChatSender.of(player);
|
||||||
|
onServerSwitch();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(TablistPart global, int seconds) {
|
||||||
|
if (player.getServer() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
player.unsafe().sendPacket(new PlayerListHeaderFooter(
|
||||||
|
ComponentSerializer.toString(header(viewer, seconds)),
|
||||||
|
ComponentSerializer.toString(viewer.parse(false, "TABLIST_FOOTER", connection.getInfo().getName(), ping(), ProxyServer.getInstance().getPlayers().size()))
|
||||||
|
));
|
||||||
|
|
||||||
|
List<TablistPart.Item> tablist = new ArrayList<>();
|
||||||
|
List<TablistPart.Item> direct = new ArrayList<>();
|
||||||
|
global.print(viewer, player, tablist, direct);
|
||||||
|
|
||||||
|
// NPC handling
|
||||||
|
List<String> addNpc = new ArrayList<>();
|
||||||
|
List<String> removeNpc = new ArrayList<>();
|
||||||
|
for (TablistPart.Item item : direct) {
|
||||||
|
if(npcs.remove(item.getUuid()))
|
||||||
|
removeNpc.add(directlySent.get(item.getUuid()).getUsername());
|
||||||
|
|
||||||
|
if(!directlySent.containsKey(item.getUuid()))
|
||||||
|
tablist.add(0, item);
|
||||||
|
}
|
||||||
|
Set<UUID> nonNPCs = direct.stream().map(TablistPart.Item::getUuid).collect(Collectors.toSet());
|
||||||
|
for(PlayerListItem.Item item : directlySent.values()) {
|
||||||
|
if(!nonNPCs.contains(item.getUuid()) && !npcs.contains(item.getUuid()))
|
||||||
|
addNpc.add(item.getUsername());
|
||||||
|
}
|
||||||
|
sendNpcPacket(addNpc, false);
|
||||||
|
sendNpcPacket(removeNpc, true);
|
||||||
|
|
||||||
|
// Main list handling
|
||||||
|
int i = 0;
|
||||||
|
List<PlayerListItem.Item> add = new ArrayList<>();
|
||||||
|
List<PlayerListItem.Item> update = new ArrayList<>();
|
||||||
|
for (; i < tablist.size() && i < 80; i++) {
|
||||||
|
PlayerListItem.Item tabItem;
|
||||||
|
if(current.size() > i) {
|
||||||
|
tabItem = current.get(i);
|
||||||
|
} else {
|
||||||
|
tabItem = new PlayerListItem.Item();
|
||||||
|
tabItem.setUuid(uuids[i]);
|
||||||
|
tabItem.setUsername(names[i]);
|
||||||
|
tabItem.setGamemode(1);
|
||||||
|
tabItem.setPing(1000);
|
||||||
|
current.add(tabItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
TablistPart.Item item = tablist.get(i);
|
||||||
|
if(!Arrays.equals(tabItem.getProperties(), item.getProperties())) {
|
||||||
|
tabItem.setProperties(item.getProperties());
|
||||||
|
tabItem.setDisplayName(item.getDisplayName());
|
||||||
|
add.add(tabItem);
|
||||||
|
} else if(!item.getDisplayName().equals(tabItem.getDisplayName())) {
|
||||||
|
tabItem.setDisplayName(item.getDisplayName());
|
||||||
|
update.add(tabItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendTabPacket(add, PlayerListItem.Action.ADD_PLAYER);
|
||||||
|
sendTabPacket(update, PlayerListItem.Action.UPDATE_DISPLAY_NAME);
|
||||||
|
|
||||||
|
// Excess removal
|
||||||
|
List<PlayerListItem.Item> remove = new ArrayList<>();
|
||||||
|
while(i < current.size()) {
|
||||||
|
remove.add(current.remove(i));
|
||||||
|
}
|
||||||
|
sendTabPacket(remove, PlayerListItem.Action.REMOVE_PLAYER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServerSwitch() {
|
||||||
|
connection = (ServerConnection) player.getServer();
|
||||||
|
directlySent.clear();
|
||||||
|
sendNpcPacket(npcs.stream().map(npc -> directlySent.get(npc).getUsername()).collect(Collectors.toList()), true);
|
||||||
|
npcs.clear();
|
||||||
|
|
||||||
|
if(connection != null) {
|
||||||
|
connection.getCh().getHandle().pipeline().addBefore(PipelineUtils.BOSS_HANDLER, "steamwar-tablist", this);
|
||||||
|
player.unsafe().sendPacket(teamPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
sendTabPacket(current, PlayerListItem.Action.REMOVE_PLAYER);
|
||||||
|
current.clear();
|
||||||
|
sendNpcPacket(npcs.stream().map(npc -> directlySent.get(npc).getUsername()).collect(Collectors.toList()), true);
|
||||||
|
npcs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void decode(ChannelHandlerContext ctx, PacketWrapper packetWrapper, List<Object> out) {
|
||||||
|
if(!connection.isObsolete()) {
|
||||||
|
DefinedPacket packet = packetWrapper.packet;
|
||||||
|
|
||||||
|
if(packet instanceof PlayerListHeaderFooter) {
|
||||||
|
packetWrapper.trySingleRelease();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(packet instanceof PlayerListItem) {
|
||||||
|
PlayerListItem list = (PlayerListItem) packet;
|
||||||
|
PlayerListItem.Action action = list.getAction();
|
||||||
|
|
||||||
|
switch(action) {
|
||||||
|
case UPDATE_LATENCY:
|
||||||
|
case UPDATE_DISPLAY_NAME:
|
||||||
|
packetWrapper.trySingleRelease();
|
||||||
|
return;
|
||||||
|
case UPDATE_GAMEMODE:
|
||||||
|
for (PlayerListItem.Item item : list.getItems()) {
|
||||||
|
ProxiedPlayer p = ProxyServer.getInstance().getPlayer(item.getUuid());
|
||||||
|
if(p != null && p != player && item.getGamemode() == 3) {
|
||||||
|
item.setGamemode(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ADD_PLAYER:
|
||||||
|
for (PlayerListItem.Item item : list.getItems()) {
|
||||||
|
item.setPing(1);
|
||||||
|
item.setDisplayName(ComponentSerializer.toString(TextComponent.fromLegacyText("")));
|
||||||
|
if(!player.getUniqueId().equals(item.getUuid()) && item.getGamemode() == 3)
|
||||||
|
item.setGamemode(1);
|
||||||
|
|
||||||
|
directlySent.put(item.getUuid(), item);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REMOVE_PLAYER:
|
||||||
|
for(PlayerListItem.Item item : list.getItems()) {
|
||||||
|
directlySent.remove(item.getUuid());
|
||||||
|
npcs.remove(item.getUuid());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.add(packetWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendTabPacket(List<PlayerListItem.Item> items, PlayerListItem.Action action) {
|
||||||
|
if(!items.isEmpty()) {
|
||||||
|
PlayerListItem packet = new PlayerListItem();
|
||||||
|
packet.setAction(action);
|
||||||
|
packet.setItems(items.toArray(new PlayerListItem.Item[0]));
|
||||||
|
player.unsafe().sendPacket(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendNpcPacket(List<String> names, boolean remove) {
|
||||||
|
if(!names.isEmpty()) {
|
||||||
|
Team packet = new Team(TAB_TEAM);
|
||||||
|
packet.setMode((byte) (remove ? 4 : 3));
|
||||||
|
packet.setPlayers(names.toArray(new String[0]));
|
||||||
|
player.unsafe().sendPacket(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BaseComponent[] header(ChatSender p, int seconds) {
|
||||||
|
int phase = (seconds % 16) / 3;
|
||||||
|
switch (phase) {
|
||||||
|
case 0:
|
||||||
|
return p.parse(false, "TABLIST_PHASE_1");
|
||||||
|
case 1:
|
||||||
|
return p.parse(false, "TABLIST_PHASE_2");
|
||||||
|
default:
|
||||||
|
return p.parse(false, "TABLIST_PHASE_DEFAULT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String ping() {
|
||||||
|
int ping = player.getPing();
|
||||||
|
if (ping < 50) {
|
||||||
|
return "§a" + ping;
|
||||||
|
} else if (ping < 150) {
|
||||||
|
return "§e" + ping;
|
||||||
|
} else {
|
||||||
|
return "§c" + ping;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
src/de/steamwar/bungeecore/tablist/TablistGroup.java
Normale Datei
45
src/de/steamwar/bungeecore/tablist/TablistGroup.java
Normale Datei
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bungeecore.tablist;
|
||||||
|
|
||||||
|
import de.steamwar.messages.ChatSender;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TablistGroup implements TablistPart {
|
||||||
|
private final List<TablistPart> sublists;
|
||||||
|
|
||||||
|
public TablistGroup(List<TablistPart> sublists) {
|
||||||
|
this.sublists = sublists;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String sortKey() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(ChatSender viewer, ProxiedPlayer player, List<Item> tablist, List<Item> direct) {
|
||||||
|
for (TablistPart sublist : sublists) {
|
||||||
|
sublist.print(viewer, player, tablist, direct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.steamwar.bungeecore.tablist;
|
|
||||||
|
|
||||||
import de.steamwar.bungeecore.sql.SteamwarUser;
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
|
||||||
import net.md_5.bungee.ServerConnection;
|
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
||||||
import net.md_5.bungee.chat.ComponentSerializer;
|
|
||||||
import net.md_5.bungee.protocol.DefinedPacket;
|
|
||||||
import net.md_5.bungee.protocol.PacketWrapper;
|
|
||||||
import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter;
|
|
||||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
|
||||||
import net.md_5.bungee.protocol.packet.Team;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class TablistListener extends MessageToMessageDecoder<PacketWrapper> {
|
|
||||||
|
|
||||||
//private boolean teamSent = false;
|
|
||||||
private final ProxiedPlayer player;
|
|
||||||
private final ServerConnection connection;
|
|
||||||
|
|
||||||
public TablistListener(ProxiedPlayer player, ServerConnection connection) {
|
|
||||||
this.player = player;
|
|
||||||
this.connection = connection;
|
|
||||||
player.unsafe().sendPacket(TablistManager.teamPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void decode(ChannelHandlerContext ctx, PacketWrapper packetWrapper, List<Object> out) {
|
|
||||||
if(!connection.isObsolete()) {
|
|
||||||
DefinedPacket packet = packetWrapper.packet;
|
|
||||||
|
|
||||||
if(packet instanceof PlayerListHeaderFooter) {
|
|
||||||
packetWrapper.trySingleRelease();
|
|
||||||
return;
|
|
||||||
} else if(packet instanceof PlayerListItem) {
|
|
||||||
PlayerListItem list = (PlayerListItem) packet;
|
|
||||||
PlayerListItem.Action action = list.getAction();
|
|
||||||
if(action == PlayerListItem.Action.UPDATE_DISPLAY_NAME || action == PlayerListItem.Action.UPDATE_LATENCY) {
|
|
||||||
packetWrapper.trySingleRelease();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(action == PlayerListItem.Action.UPDATE_GAMEMODE) {
|
|
||||||
for (PlayerListItem.Item item : list.getItems()) {
|
|
||||||
ProxiedPlayer p = ProxyServer.getInstance().getPlayer(item.getUuid());
|
|
||||||
if(p != null && p != player && item.getGamemode() == 3) {
|
|
||||||
item.setGamemode(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else if(action != PlayerListItem.Action.REMOVE_PLAYER) {
|
|
||||||
List<String> npcs = new ArrayList<>();
|
|
||||||
for (PlayerListItem.Item item : list.getItems()) {
|
|
||||||
ProxiedPlayer p = ProxyServer.getInstance().getPlayer(item.getUuid());
|
|
||||||
if(p == null) {
|
|
||||||
item.setPing(1000);
|
|
||||||
item.setDisplayName(ComponentSerializer.toString(TextComponent.fromLegacyText("")));
|
|
||||||
npcs.add(item.getUsername());
|
|
||||||
} else {
|
|
||||||
item.setPing(1);
|
|
||||||
item.setDisplayName(ComponentSerializer.toString(TextComponent.fromLegacyText(SteamwarUser.get(p.getUniqueId()).getUserGroup().getColorCode() + p.getName())));
|
|
||||||
if(p != player && item.getGamemode() == 3) {
|
|
||||||
item.setGamemode(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!npcs.isEmpty()) {
|
|
||||||
Team teamPacket = new Team(TablistManager.TAB_TEAM);
|
|
||||||
teamPacket.setMode((byte) 3);
|
|
||||||
teamPacket.setPlayers(npcs.toArray(new String[0]));
|
|
||||||
player.unsafe().sendPacket(teamPacket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.add(packetWrapper);
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,43 +20,29 @@
|
|||||||
package de.steamwar.bungeecore.tablist;
|
package de.steamwar.bungeecore.tablist;
|
||||||
|
|
||||||
import de.steamwar.bungeecore.BungeeCore;
|
import de.steamwar.bungeecore.BungeeCore;
|
||||||
|
import de.steamwar.bungeecore.Servertype;
|
||||||
|
import de.steamwar.bungeecore.Subserver;
|
||||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||||
import de.steamwar.bungeecore.sql.SteamwarUser;
|
import de.steamwar.network.packets.common.FightInfoPacket;
|
||||||
import de.steamwar.messages.ChatSender;
|
|
||||||
import net.md_5.bungee.ServerConnection;
|
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||||
import net.md_5.bungee.chat.ComponentSerializer;
|
|
||||||
import net.md_5.bungee.connection.InitialHandler;
|
|
||||||
import net.md_5.bungee.event.EventHandler;
|
import net.md_5.bungee.event.EventHandler;
|
||||||
import net.md_5.bungee.netty.PipelineUtils;
|
|
||||||
import net.md_5.bungee.protocol.PlayerPublicKey;
|
|
||||||
import net.md_5.bungee.protocol.Property;
|
|
||||||
import net.md_5.bungee.protocol.packet.PlayerListHeaderFooter;
|
|
||||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
|
||||||
import net.md_5.bungee.protocol.packet.Team;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.IntStream;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class TablistManager extends BasicListener {
|
public class TablistManager extends BasicListener {
|
||||||
|
|
||||||
public static final String TAB_TEAM = "»SW-Tab";
|
private static final Map<ServerInfo, FightInfoPacket> fightInfos = new HashMap<>();
|
||||||
|
|
||||||
private static final Property[] GRAY = new Property[]{new Property("textures", Base64.getEncoder().encodeToString(("{\"textures\":{\"SKIN\":{\"url\":\"https://steamwar.de/gray.png\"}}}").getBytes(StandardCharsets.UTF_8)))};
|
public static synchronized void newFightInfo(ServerInfo info, FightInfoPacket packet) {
|
||||||
private static final Property[] LIGHT_GRAY = new Property[]{new Property("textures", Base64.getEncoder().encodeToString(("{\"textures\":{\"SKIN\":{\"url\":\"https://steamwar.de/lightgray.png\"}}}").getBytes(StandardCharsets.UTF_8)))};
|
fightInfos.put(info, packet);
|
||||||
|
fightInfos.keySet().removeIf(serverInfo -> serverInfo.getPlayers().isEmpty());
|
||||||
private static final UUID[] uuids = IntStream.range(0, 80).mapToObj(i -> UUID.randomUUID()).toArray(UUID[]::new);
|
}
|
||||||
private static final String[] names = IntStream.range(0, 80).mapToObj(i -> " »SW« " + i).toArray(String[]::new);
|
|
||||||
public static final Team teamPacket = new Team(TAB_TEAM, (byte) 0, ComponentSerializer.toString(TextComponent.fromLegacyText("")), ComponentSerializer.toString(TextComponent.fromLegacyText("")), ComponentSerializer.toString(TextComponent.fromLegacyText("")), "never", "never", 21, (byte)0x00, names); // new String[]{}
|
|
||||||
|
|
||||||
private final Map<ProxiedPlayer, Tablist> tablists = new HashMap<>();
|
private final Map<ProxiedPlayer, Tablist> tablists = new HashMap<>();
|
||||||
|
|
||||||
@ -76,8 +62,9 @@ public class TablistManager extends BasicListener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onServerConnection(ServerSwitchEvent event) {
|
public void onServerConnection(ServerSwitchEvent event) {
|
||||||
ServerConnection server = (ServerConnection) event.getPlayer().getServer();
|
synchronized (tablists) {
|
||||||
server.getCh().getHandle().pipeline().addBefore(PipelineUtils.BOSS_HANDLER, "steamwar-tablist", new TablistListener(event.getPlayer(), server));
|
tablists.get(event.getPlayer()).onServerSwitch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@ -95,110 +82,30 @@ public class TablistManager extends BasicListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateTablist() {
|
private void updateTablist() {
|
||||||
|
List<TablistPart.Item> buildPlayers = new ArrayList<>();
|
||||||
|
List<TablistPart> subservers = new ArrayList<>();
|
||||||
|
for (ServerInfo server : ProxyServer.getInstance().getServersCopy().values()){
|
||||||
|
if(server.getPlayers().isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Subserver subserver = Subserver.getSubserver(server);
|
||||||
|
if(subserver != null && subserver.getType() == Servertype.BAUSERVER)
|
||||||
|
server.getPlayers().forEach(player -> buildPlayers.add(new TablistPart.Item(player)));
|
||||||
|
else if(fightInfos.containsKey(server))
|
||||||
|
subservers.add(new TablistServer(server, fightInfos.get(server)));
|
||||||
|
else
|
||||||
|
subservers.add(new TablistServer(server));
|
||||||
|
}
|
||||||
|
subservers.sort((s1, s2) -> s1.sortKey().compareToIgnoreCase(s2.sortKey()));
|
||||||
|
if(!buildPlayers.isEmpty()) {
|
||||||
|
buildPlayers.sort((p1, p2) -> p1.getDisplayName().compareToIgnoreCase(p2.getDisplayName()));
|
||||||
|
subservers.add(new TablistServer(null, "Build", viewer -> viewer.parseToLegacy("TABLIST_BAU"), buildPlayers));
|
||||||
|
}
|
||||||
|
TablistPart global = new TablistGroup(subservers);
|
||||||
|
|
||||||
synchronized (tablists) {
|
synchronized (tablists) {
|
||||||
tablists.forEach((player, tablist) -> tablist.update());
|
tablists.forEach((player, tablist) -> tablist.update(global, seconds));
|
||||||
|
}
|
||||||
seconds++;
|
seconds++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private class Tablist {
|
|
||||||
private final ProxiedPlayer player;
|
|
||||||
private int shown = 0;
|
|
||||||
|
|
||||||
private Tablist(ProxiedPlayer player) {
|
|
||||||
this.player = player;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void update() {
|
|
||||||
if(player.getServer() == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
player.unsafe().sendPacket(new PlayerListHeaderFooter(
|
|
||||||
ComponentSerializer.toString(header(ChatSender.of(player))),
|
|
||||||
ComponentSerializer.toString(ChatSender.of(player).parse(false, "TABLIST_FOOTER", player.getServer().getInfo().getName(), ping(), ProxyServer.getInstance().getPlayers().size()))
|
|
||||||
));
|
|
||||||
|
|
||||||
PlayerListItem addPacket = new PlayerListItem();
|
|
||||||
addPacket.setAction(PlayerListItem.Action.ADD_PLAYER);
|
|
||||||
|
|
||||||
PlayerListItem.Item[] items = ProxyServer.getInstance().getServers().entrySet().stream().filter(entry -> entry.getValue() != player.getServer().getInfo()).sorted((e1, e2) -> e1.getKey().compareToIgnoreCase(e2.getKey())).flatMap(entry -> Stream.concat(Stream.of(construct("", false), construct("§7§l" + entry.getKey(), true)), entry.getValue().getPlayers().stream().map(this::construct))).toArray(PlayerListItem.Item[]::new);
|
|
||||||
if(items.length > 80) {
|
|
||||||
items = Arrays.copyOf(items, 80);
|
|
||||||
}
|
|
||||||
for(int i = 0; i < items.length; i++) {
|
|
||||||
items[i].setUuid(uuids[i]);
|
|
||||||
items[i].setUsername(names[i]);
|
|
||||||
}
|
|
||||||
addPacket.setItems(items);
|
|
||||||
|
|
||||||
if(shown > items.length)
|
|
||||||
player.unsafe().sendPacket(removePacket(items.length));
|
|
||||||
|
|
||||||
shown = items.length;
|
|
||||||
player.unsafe().sendPacket(addPacket);
|
|
||||||
//TODO Set direct displaynames for onserver personel (and update correctly)
|
|
||||||
//TODO Add direct onserver not shown
|
|
||||||
}
|
|
||||||
|
|
||||||
private BaseComponent[] header(ChatSender p){
|
|
||||||
int phase = (seconds % 16) / 3;
|
|
||||||
switch(phase){
|
|
||||||
case 0:
|
|
||||||
return p.parse(false, "TABLIST_PHASE_1");
|
|
||||||
case 1:
|
|
||||||
return p.parse(false, "TABLIST_PHASE_2");
|
|
||||||
default:
|
|
||||||
return p.parse(false, "TABLIST_PHASE_DEFAULT");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String ping() {
|
|
||||||
int ping = player.getPing();
|
|
||||||
if(ping < 50){
|
|
||||||
return "§a" + ping;
|
|
||||||
}else if(ping < 150){
|
|
||||||
return "§e" + ping;
|
|
||||||
}else{
|
|
||||||
return "§c" + ping;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlayerListItem.Item construct(String displayName, boolean lightgray) {
|
|
||||||
// TODO lightgray ? LIGHT_GRAY : GRAY
|
|
||||||
return construct(null, null, new Property[]{}, null, 1, 1000, displayName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlayerListItem.Item construct(ProxiedPlayer player) {
|
|
||||||
return construct(player.getUniqueId(), null, ((InitialHandler)player.getPendingConnection()).getLoginProfile().getProperties(), ((InitialHandler)player.getPendingConnection()).getLoginRequest().getPublicKey(), 1, 1000, SteamwarUser.get(player.getUniqueId()).getUserGroup().getColorCode() + player.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlayerListItem.Item construct(UUID uuid, String username, Property[] properties, PlayerPublicKey publicKey, int gamemode, int ping, String displayName) {
|
|
||||||
PlayerListItem.Item item = new PlayerListItem.Item();
|
|
||||||
item.setUuid(uuid);
|
|
||||||
item.setUsername(username);
|
|
||||||
item.setProperties(properties);
|
|
||||||
item.setPublicKey(publicKey);
|
|
||||||
item.setGamemode(gamemode);
|
|
||||||
item.setPing(ping);
|
|
||||||
item.setDisplayName(ComponentSerializer.toString(TextComponent.fromLegacyText(displayName)));
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlayerListItem.Item construct(UUID uuid) {
|
|
||||||
PlayerListItem.Item item = new PlayerListItem.Item();
|
|
||||||
item.setUuid(uuid);
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
private PlayerListItem removePacket(int newLength) {
|
|
||||||
PlayerListItem packet = new PlayerListItem();
|
|
||||||
packet.setAction(PlayerListItem.Action.REMOVE_PLAYER);
|
|
||||||
packet.setItems(IntStream.range(newLength, shown).mapToObj(i -> construct(uuids[i])).toArray(PlayerListItem.Item[]::new));
|
|
||||||
return packet;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void remove() {
|
|
||||||
player.unsafe().sendPacket(removePacket(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
75
src/de/steamwar/bungeecore/tablist/TablistPart.java
Normale Datei
75
src/de/steamwar/bungeecore/tablist/TablistPart.java
Normale Datei
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bungeecore.tablist;
|
||||||
|
|
||||||
|
import de.steamwar.bungeecore.sql.SteamwarUser;
|
||||||
|
import de.steamwar.messages.ChatSender;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
import net.md_5.bungee.connection.InitialHandler;
|
||||||
|
import net.md_5.bungee.protocol.Property;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
interface TablistPart {
|
||||||
|
String sortKey();
|
||||||
|
void print(ChatSender viewer, ProxiedPlayer player, List<Item> tablist, List<Item> direct);
|
||||||
|
|
||||||
|
class Item {
|
||||||
|
|
||||||
|
public static Property[] playerProperties(ProxiedPlayer player) {
|
||||||
|
return ((InitialHandler) player.getPendingConnection()).getLoginProfile().getProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final UUID uuid;
|
||||||
|
private final String displayName;
|
||||||
|
private final Property[] properties;
|
||||||
|
|
||||||
|
public Item(UUID uuid, String displayName, Property[] properties) {
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.displayName = reformat(displayName);
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Item(ProxiedPlayer player) {
|
||||||
|
this.uuid = player.getUniqueId();
|
||||||
|
this.displayName = reformat(SteamwarUser.get(player.getUniqueId()).getUserGroup().getColorCode() + player.getName());
|
||||||
|
this.properties = playerProperties(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property[] getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String reformat(String string) {
|
||||||
|
return ComponentSerializer.toString(TextComponent.fromLegacyText(string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
src/de/steamwar/bungeecore/tablist/TablistServer.java
Normale Datei
91
src/de/steamwar/bungeecore/tablist/TablistServer.java
Normale Datei
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.steamwar.bungeecore.tablist;
|
||||||
|
|
||||||
|
import de.steamwar.bungeecore.sql.SteamwarUser;
|
||||||
|
import de.steamwar.messages.ChatSender;
|
||||||
|
import de.steamwar.network.packets.common.FightInfoPacket;
|
||||||
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.protocol.Property;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class TablistServer implements TablistPart {
|
||||||
|
|
||||||
|
public static final Property[] GRAY = new Property[]{new Property("textures", "eyJ0aW1lc3RhbXAiOjE0NTU1NzQxMTk0MzMsInByb2ZpbGVJZCI6ImIzYjE4MzQ1MzViZjRiNzU4ZTBjZGJmMGY4MjA2NTZlIiwicHJvZmlsZU5hbWUiOiIxMDExMTEiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzZlNzJkMzE0NzczMmQ5NzFkZWZhZTIzMWIzOGQ5NDI0MTRiMDU3YTcxNTFjNTNjNWZkNjI5NmEzYjllZGEwYWIifX19", "ro/ZKHt7278yhCr+CFTcPp/q6wAUlef//85k2DzkfRaZqy0CtGgwisDs2U4pVKvQ2pfXvitzWgbJvD0bLeQ12xWi4c1Fc29LCArosVJoFmrJDHz7N2MlstHT+ynQROb9d2aiFA6uOXfLjPKb1noUZ/YQoZjqcPIvD5oFZtD5DHV5O4hYz0IvgHbIjDqjz6ITsTcKiBlbxNg2loTFxSlW1ZfnNCO+kcAmeyB5NFY3j0e+/AqVANiNoiC3OKsECM/yEx/acf+vKWcT8mQn4wRoIGtxfEU7ZjNtgdh73NvXXBygW+K9AiJ242g8Y06Xxuk8kaNEGmT6H/mM7nbwjZmQQXpi/Pao2gYqyeIofeCPfr8RsGXoDX3nXDAw8/LyhTCHgx+sp6IQYSfGcSMJtoNeTJ0liIFxqn1V9/zKmzOZAPzR6qrQPOjoRFljLAlv7rfzotaEqh/1ldd40GdS8tstczn7f29OQerNDaqvbDb00Gy0STdUr1bVyCDptA54XKjT9WFv7QpBikEculxqSppAXPxD2Fb/ZmphbZx8WEGfG6bVFhf6fQdDAUXlcv8BxjElNPwlolF86M2KJd5VquLluhrCjwID7OK/pffNultAVH+Lxw4QOAXmJqjUrA1KHgyG1S0Cwj/f4E2hdxZJBvkfVtq9qPkd9nignhEoTCTOHf0=")};
|
||||||
|
public static final Property[] LIGHT_GRAY = new Property[]{new Property("textures", "eyJ0aW1lc3RhbXAiOjE0NTU2MjU1OTM5NjIsInByb2ZpbGVJZCI6ImIzYjE4MzQ1MzViZjRiNzU4ZTBjZGJmMGY4MjA2NTZlIiwicHJvZmlsZU5hbWUiOiIxMDExMTEiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzc4Y2I3ZmMyMDhiMzM4NTUwNGE4MTQ0MjA0NDI4ZmRjZDYzMjRiZWIzMWNhMmNlODZjYzQyNGI5NjNkODVjIn19fQ==", "R/wZUZRC1dishRdM9a2SSxxW3oYa0XSb/MxHbQpEUA791HxyqjaKLDu0wFX2r2a8ZTeVjzXpNzkg3+PkrA11o8h7lt86MTD1pi/rQqj/WRuoqf2LP+ypbssKV+LU15cYez2cj3QQVcJDXgWEnfSLNuBv6NG8BDUpUAjTWldvu99NCJHUoD0jNMHxY/fu4k5vCgOjaBaKgkjVk2bmUhegusmtMwco+3pYx+y8+gUW8ptx5SnePG+dOwTqLyBFiOt2AQ+gSvbU/jP9aAXgxOwz/b1pMaBWtzVhFU865NHlIdSpIHg/sh3uNah3a7gTgtTvxPQv1OzM/KtqYKiamsrRzAQMzRcs4A7Tp0GakLuxEaz401IwvQ7UGVYLFzGUVLB2MyqtPgifiqQSQxZpiqj9sM5QadhsUw00nfX7mTdW46U0MtNIbby1rLrvgQKoj08zt6LJlhI3yjyawy4iZkgF4oc+PCNwZc93GIbVL9LJaGkXk3RVA+JpGwfMJrGVbL7hl8ibbAcUv7uCEWdkAgZCd6w75jEE4tlhDSPDD4rXbn+FeTZRg2n/PGKtnoTZRzbniiFaNoSAHDZSVRG39xvBDFvtmL3SPaKhzKaifiYrgNn453WtR3kymqdAtPf1GN9d1VltGZ/+vMPwqPJb6thcrlcU64UGHbg1olRkiyZHvY8=")};
|
||||||
|
|
||||||
|
private final ServerInfo server;
|
||||||
|
private final String sortKey;
|
||||||
|
private final Function<ChatSender, String> title;
|
||||||
|
private final List<Item> players;
|
||||||
|
|
||||||
|
public TablistServer(ServerInfo server) {
|
||||||
|
this(server, server.getName(), viewer -> server.getName(), server.getPlayers().stream().sorted((p1, p2) -> p1.getName().compareToIgnoreCase(p2.getName())).map(TablistPart.Item::new).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TablistServer(ServerInfo server, FightInfoPacket info) {
|
||||||
|
this(server, server.getName(), viewer -> server.getName(), new ArrayList<>());
|
||||||
|
|
||||||
|
Collection<ProxiedPlayer> onlinePlayers = server.getPlayers();
|
||||||
|
addPlayers(info.getBlueName().substring(0, 2), info.getBluePlayers(), onlinePlayers);
|
||||||
|
addPlayers(info.getRedName().substring(0, 2), info.getRedPlayers(), onlinePlayers);
|
||||||
|
addPlayers("§7", info.getSpectators(), onlinePlayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TablistServer(ServerInfo server, String sortKey, Function<ChatSender, String> title, List<Item> players) {
|
||||||
|
this.server = server;
|
||||||
|
this.sortKey = sortKey;
|
||||||
|
this.title = title;
|
||||||
|
this.players = players;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String sortKey() {
|
||||||
|
return sortKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(ChatSender viewer, ProxiedPlayer player, List<Item> tablist, List<Item> direct) {
|
||||||
|
boolean onServer = player.getServer().getInfo() == server;
|
||||||
|
List<Item> items = onServer ? direct : tablist;
|
||||||
|
|
||||||
|
if(!onServer && title != null) {
|
||||||
|
items.add(new Item(null, "", GRAY));
|
||||||
|
items.add(new Item(null, "§7" + title.apply(viewer), LIGHT_GRAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
items.addAll(players);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPlayers(String prefix, List<Integer> teamPlayers, Collection<ProxiedPlayer> onlinePlayers){
|
||||||
|
teamPlayers.stream().map(SteamwarUser::get).map(
|
||||||
|
user -> onlinePlayers.stream().filter(player -> player.getUniqueId().equals(user.getUuid())).findAny()
|
||||||
|
).filter(Optional::isPresent).map(Optional::get).sorted(
|
||||||
|
(p1, p2) -> p1.getName().compareToIgnoreCase(p2.getName())
|
||||||
|
).forEachOrdered(player -> players.add(new Item(player.getUniqueId(), prefix + player.getName(), Item.playerProperties(player))));
|
||||||
|
}
|
||||||
|
}
|
In neuem Issue referenzieren
Einen Benutzer sperren