-
-
Save chaseking/6861109 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ServerListAPI - API to modify some advanced Minecraft server list data | |
* Copyright (C) 2013 Minecrell | |
* You are not allowed to use this API to fake online players on a production server. | |
* | |
* 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/>. | |
*/ | |
import java.net.InetAddress; | |
import java.util.HashSet; | |
import java.util.Set; | |
import org.bukkit.event.EventHandler; | |
import org.bukkit.event.Listener; | |
import org.bukkit.event.server.ServerListPingEvent; | |
import org.bukkit.plugin.Plugin; | |
import com.comphenix.protocol.Packets; | |
import com.comphenix.protocol.ProtocolLibrary; | |
import com.comphenix.protocol.events.ConnectionSide; | |
import com.comphenix.protocol.events.ListenerPriority; | |
import com.comphenix.protocol.events.PacketAdapter; | |
import com.comphenix.protocol.events.PacketContainer; | |
import com.comphenix.protocol.events.PacketEvent; | |
import com.comphenix.protocol.injector.GamePhase; | |
import com.google.common.base.Joiner; | |
import com.google.common.base.Splitter; | |
import com.google.common.collect.Iterables; | |
/** | |
* API to modify some advanced Minecraft server list data. | |
* If you want to use it with ProtocolLib you have to add ProtocolLib to (soft)depend in your plugin.yml file. | |
* @author Minecrell | |
*/ | |
public class ServerListAPI { | |
private final Plugin plugin; | |
private Integer onlinePlayers, maxPlayers, snapshotVersion; | |
private String motd, serverVersion; | |
private boolean hideServerList, lockBannedIPs; | |
private final Set<InetAddress> lockedIPs = new HashSet<InetAddress>(); | |
/** | |
* Creates a new instance of the API. | |
* @param plugin Plugin instance of the Plugin using this API. | |
* @see Plugin | |
*/ | |
public ServerListAPI(final Plugin plugin) { | |
this.plugin = plugin; | |
plugin.getServer().getPluginManager().registerEvents(new ServerListListener(), plugin); | |
final Plugin pLib = plugin.getServer().getPluginManager().getPlugin("ProtocolLib"); | |
if (pLib != null && (pLib instanceof com.comphenix.protocol.ProtocolLibrary)) { | |
new ServerListPacketAdapter(); | |
} | |
} | |
/** | |
* Gets the plugin instance of this API. | |
* @return Plugin instance | |
* @see Plugin | |
*/ | |
public Plugin getPlugin() { | |
return plugin; | |
} | |
/** | |
* Resets all changed values on this API. | |
* @return This API object. | |
*/ | |
public ServerListAPI resetData() { | |
this.setOnlinePlayers(null); | |
this.setMaxPlayers(null); | |
this.setSnapshotVersion(null); | |
this.setServerVersion(null); | |
this.setMotd(null); | |
return this; | |
} | |
/** | |
* Gets the changed online player count. | |
* @return Online player count, or null if not changed. | |
*/ | |
public Integer getOnlinePlayers() { | |
return onlinePlayers; | |
} | |
/** | |
* Sets the online player count for the server. | |
* @param onlinePlayers New online player count or null to reset it. | |
* @return This API object. | |
*/ | |
public ServerListAPI setOnlinePlayers(final Integer onlinePlayers) { | |
this.onlinePlayers = onlinePlayers; | |
return this; | |
} | |
/** | |
* Gets the changed max player count. | |
* @return Max player count, or null if not changed. | |
*/ | |
public Integer getMaxPlayers() { | |
return maxPlayers; | |
} | |
/** | |
* Sets the max player count for the server. | |
* @param maxPlayers New max player count or null to reset it. | |
* @return This API object. | |
*/ | |
public ServerListAPI setMaxPlayers(final Integer maxPlayers) { | |
this.maxPlayers = maxPlayers; | |
return this; | |
} | |
/** | |
* Gets the changed snapshot version. This should only be changed if you | |
* want to display a custom server version. Remember, nobody can join the | |
* server without a mod or direct connect! | |
* @return Snapshot version or null if not changed. | |
*/ | |
public Integer getSnapshotVersion() { | |
return snapshotVersion; | |
} | |
/** | |
* Sets the snapshot version for the server. | |
* @param snapshotVersion New snapshot version or null to reset it. | |
* @see #getSnapshotVersion() | |
* @return This API object. | |
*/ | |
public ServerListAPI setSnapshotVersion(final Integer snapshotVersion) { | |
if (snapshotVersion != null && snapshotVersion < 0) | |
throw new IllegalArgumentException("Snapshot version can't be smaller than null."); | |
this.snapshotVersion = snapshotVersion; | |
return this; | |
} | |
/** | |
* Gets the changed server version string. The server version is displayed | |
* next to the server ping (or above the player count) when you look at your | |
* server list with a newer or older Minecraft version. | |
* @see #getSnapshotVersion() | |
* @return Server version or null if not changed. | |
*/ | |
public String getServerVersion() { | |
return serverVersion; | |
} | |
/** | |
* Sets the server version for the server. The server version can contain | |
* colors. | |
* @param version Server version string or null to reset it. | |
* @see #getServerVersion() | |
* @return This API object. | |
*/ | |
public ServerListAPI setServerVersion(final String version) { | |
serverVersion = version; | |
return this; | |
} | |
/** | |
* Sets the server version for the server. The server version can contain | |
* colors. | |
* @param version Server version string or null to reset it. | |
* @param changeSnapshotVersion If the snapshot version should be set automatically. | |
* @see #setServerVersion(String) | |
* @return This API object. | |
*/ | |
public ServerListAPI setServerVersion(final String version, final boolean changeSnapshotVersion) { | |
this.setServerVersion(version); | |
if (changeSnapshotVersion) | |
snapshotVersion = 255; | |
return this; | |
} | |
/** | |
* Gets the changed <i>Message of the day</i> (MOTD). | |
* @return Motd or null if not changed. | |
*/ | |
public String getMotd() { | |
return motd; | |
} | |
/** | |
* Sets the Motd for the server. | |
* @param motd Motd or null to reset it. | |
* @see #getMotd() | |
* @return This API object. | |
*/ | |
public ServerListAPI setMotd(final String motd) { | |
this.motd = motd; | |
return this; | |
} | |
/** | |
* If this is true, the server will show as <i>Communication Error</i> in the server list for everyone. | |
* @return Hide server list entry for everyone? | |
*/ | |
public boolean hideServerList() { | |
return hideServerList; | |
} | |
/** | |
* Sets whether the server should show as <i>Communication Error</i> in the server list for everyone. | |
* @param hideServerList Hide server list entry for everyone? | |
* @return This API object. | |
*/ | |
public ServerListAPI setHideServerList(final boolean hideServerList) { | |
this.hideServerList = hideServerList; | |
return this; | |
} | |
/** | |
* If this is true, the API will automatically hide the server status in the server list for every banned IP. | |
* @return Lock banned IPs? | |
*/ | |
public boolean lockBannedIPs() { | |
return lockBannedIPs; | |
} | |
/** | |
* Sets whether the API should automatically hide the server status in the server list for every banned IP. | |
* @param lockBannedIPs Hide server status for banned IPs? | |
* @return This API object. | |
*/ | |
public ServerListAPI setLockBannedIPs(final boolean lockBannedIPs) { | |
this.lockBannedIPs = lockBannedIPs; | |
return this; | |
} | |
/** | |
* Lock an IP, so it won't see the server status in the server list anymore. (Server will show as <i>Communication Error</i>) | |
* @param address IP address of the player or service | |
* @return This API object. | |
*/ | |
public ServerListAPI lockIP(final InetAddress address) { | |
lockedIPs.add(address); | |
return this; | |
} | |
/** | |
* Unlock an IP, so it will see the server status in the server list again. | |
* @param address IP address of the player or service | |
* @return This API object. | |
*/ | |
public ServerListAPI unlockIP(final InetAddress address) { | |
lockedIPs.remove(address); | |
return this; | |
} | |
/** | |
* Returns the set containing all locked IPs for the server list. | |
* @return Set with all locked IPs | |
*/ | |
public Set<InetAddress> getLockedIPs() { | |
return lockedIPs; | |
} | |
/** | |
* Resets all locked IPs. They will all see the server status in the server list again. | |
* @return This API object. | |
*/ | |
public ServerListAPI resetLockedIPs() { | |
lockedIPs.clear(); | |
return this; | |
} | |
private class ServerListListener implements Listener { | |
@EventHandler | |
public void onServerListPing(final ServerListPingEvent event) { | |
if (maxPlayers != null) event.setMaxPlayers(maxPlayers); | |
if (motd != null) event.setMotd(motd); | |
} | |
} | |
private class ServerListPacketAdapter extends PacketAdapter { | |
private static final char packetSeperator = '\0'; | |
private final Splitter packetSplitter = Splitter.on(packetSeperator); | |
private final Joiner packetJoiner = Joiner.on(packetSeperator); | |
private ServerListPacketAdapter() { | |
super(ServerListAPI.this.plugin, ConnectionSide.SERVER_SIDE, ListenerPriority.NORMAL, GamePhase.LOGIN, Packets.Server.KICK_DISCONNECT); | |
ProtocolLibrary.getProtocolManager().addPacketListener(this); | |
} | |
@Override | |
public void onPacketSending(final PacketEvent event) { | |
if (event.getPacketID() != Packets.Server.KICK_DISCONNECT) return; | |
final PacketContainer packet = event.getPacket(); | |
final String[] data = Iterables.toArray(packetSplitter.split(packet.getStrings().read(0)), String.class); | |
if (data.length != 6) return; | |
final InetAddress ip = event.getPlayer().getAddress().getAddress(); | |
if (hideServerList || (lockBannedIPs && plugin.getServer().getIPBans().contains(ip.getHostAddress())) || lockedIPs.contains(ip)) { | |
packet.getStrings().write(0, null); return; | |
} | |
if (onlinePlayers != null) data[4] = onlinePlayers.toString(); | |
if (snapshotVersion != null) data[1] = snapshotVersion.toString(); | |
if (serverVersion != null) data[2] = serverVersion; | |
packet.getStrings().write(0, packetJoiner.join(data)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment