/*
* _____ __ _ _ _____ _
* | __|___ ___ _ _ ___ ___| | |_|___| |_| _ | |_ _ ___
* |__ | -_| _| | | -_| _| |__| |_ -| _| __| | | |_ -|
* |_____|___|_| \_/|___|_| |_____|_|___|_| |__| |_|___|___|
*
* ServerListPlus - http://git.io/slp
* Copyright (c) 2014, Minecrell <https://github.com/Minecrell>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package net.minecrell.serverlistplus.bukkit.handlers;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.comphenix.protocol.wrappers.WrappedServerPing;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import net.minecrell.serverlistplus.bukkit.BukkitPlugin;
import net.minecrell.serverlistplus.core.status.ResponseFetcher;
import net.minecrell.serverlistplus.core.status.StatusManager;
import net.minecrell.serverlistplus.core.status.StatusRequest;
import net.minecrell.serverlistplus.core.status.StatusResponse;
import net.minecrell.serverlistplus.core.util.Helper;
import java.net.InetSocketAddress;
import java.util.Collections;
public class ProtocolLibHandler extends StatusHandler {
private StatusPacketListener listener;
public ProtocolLibHandler(BukkitPlugin plugin) {
super(plugin);
}
public final class StatusPacketListener extends PacketAdapter {
public StatusPacketListener() {
super(PacketAdapter.params(bukkit, PacketType.Status.Server.OUT_SERVER_INFO,
PacketType.Handshake.Client.SET_PROTOCOL).optionAsync());
}
@Override // Handshake
public void onPacketReceiving(PacketEvent event) {
if (bukkit.getCore() == null) return; // Too early, we haven't finished initializing yet
PacketContainer packet = event.getPacket();
if (packet.getProtocols().read(0) != PacketType.Protocol.STATUS) return;
StatusRequest request = bukkit.getRequest(event.getPlayer().getAddress());
request.setProtocolVersion(packet.getIntegers().read(0));
String host = packet.getStrings().read(0);
int port = packet.getIntegers().read(1);
request.setTarget(host, port);
}
@Override // Status ping
public void onPacketSending(PacketEvent event) {
if (bukkit.getCore() == null) return; // Too early, we haven't finished initializing yet
final WrappedServerPing ping = event.getPacket().getServerPings().read(0);
// Make sure players have not been hidden when getting the player count
boolean playersVisible = ping.isPlayersVisible();
InetSocketAddress client = event.getPlayer().getAddress();
StatusRequest request = bukkit.getRequest(client);
bukkit.requestCompleted(event.getPlayer().getAddress());
StatusResponse response = request.createResponse(bukkit.getCore().getStatus(),
// Return unknown player counts if it has been hidden
new ResponseFetcher() {
@Override
public Integer getOnlinePlayers() {
return ping.getPlayersOnline();
}
@Override
public Integer getMaxPlayers() {
return ping.getPlayersMaximum();
}
@Override
public int getProtocolVersion() {
return ping.getVersionProtocol();
}
});
// Description is modified in BukkitEventHandler, but we modify it here again,
// because the BukkitEventHandler has no access to information like virtual hosts.
String message = response.getDescription();
if (message != null) ping.setMotD(message);
// Version name
message = response.getVersion();
if (message != null) ping.setVersionName(message);
// Protocol version
Integer protocol = response.getProtocolVersion();
if (protocol != null) ping.setVersionProtocol(protocol);
if (playersVisible) {
if (response.hidePlayers()) {
ping.setPlayersVisible(false);
} else {
// Online players
Integer count = response.getOnlinePlayers();
if (count != null) ping.setPlayersOnline(count);
// Max players are modified in BukkitEventHandler
count = response.getMaxPlayers();
if (count != null) ping.setPlayersMaximum(count);
// Player hover
message = response.getPlayerHover();
if (message != null) {
if (response.useMultipleSamples()) {
count = response.getDynamicSamples();
ping.setPlayers(Iterables.transform(
count != null ? Helper.splitLines(message, count) : Helper.splitLines(message),
new Function<String, WrappedGameProfile>() {
@Override
public WrappedGameProfile apply(String input) {
return new WrappedGameProfile(StatusManager.EMPTY_UUID, input);
}
}));
} else
ping.setPlayers(Collections.singleton(
new WrappedGameProfile(StatusManager.EMPTY_UUID, message)));
}
}
}
}
}
@Override
public boolean register() {
if (listener == null) {
ProtocolLibrary.getProtocolManager().addPacketListener(this.listener = new StatusPacketListener());
return true;
} else
return false;
}
@Override
public boolean unregister() {
if (listener != null) {
ProtocolLibrary.getProtocolManager().removePacketListener(listener);
this.listener = null;
return true;
} else
return false;
}
}