Adding automatic GamePhase detection.
This should solve the infamous UNKNOWN ORIGIN problem, especially in MCPC++.
Dieser Commit ist enthalten in:
Ursprung
68c0a3c1dc
Commit
47134b43cc
@ -1,5 +1,7 @@
|
||||
package com.comphenix.protocol.events;
|
||||
|
||||
import com.comphenix.protocol.injector.GamePhase;
|
||||
|
||||
/**
|
||||
* Represents additional options a listener may require.
|
||||
*
|
||||
@ -10,4 +12,10 @@ public enum ListenerOptions {
|
||||
* Retrieve the serialized client packet as it appears on the network stream.
|
||||
*/
|
||||
INTERCEPT_INPUT_BUFFER,
|
||||
|
||||
/**
|
||||
* Disable the automatic game phase detection that will normally force {@link GamePhase#LOGIN} when
|
||||
* a packet ID is known to be transmitted during login.
|
||||
*/
|
||||
DISABLE_GAMEPHASE_DETECTION;
|
||||
}
|
||||
|
@ -0,0 +1,71 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.comphenix.protocol.Packets;
|
||||
import com.comphenix.protocol.concurrency.IntegerSet;
|
||||
import com.comphenix.protocol.events.ConnectionSide;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
|
||||
/**
|
||||
* Packets that are known to be transmitted during login.
|
||||
* <p>
|
||||
* This may be dynamically extended later.
|
||||
* @author Kristian
|
||||
*/
|
||||
class LoginPackets {
|
||||
private IntegerSet clientSide = new IntegerSet(Packets.PACKET_COUNT);
|
||||
private IntegerSet serverSide = new IntegerSet(Packets.PACKET_COUNT);
|
||||
|
||||
public LoginPackets(MinecraftVersion version) {
|
||||
// Ordinary login
|
||||
clientSide.add(Packets.Client.HANDSHAKE);
|
||||
serverSide.add(Packets.Server.KEY_REQUEST);
|
||||
clientSide.add(Packets.Client.KEY_RESPONSE);
|
||||
serverSide.add(Packets.Server.KEY_RESPONSE);
|
||||
clientSide.add(Packets.Client.CLIENT_COMMAND);
|
||||
serverSide.add(Packets.Server.LOGIN);
|
||||
|
||||
// List ping
|
||||
clientSide.add(Packets.Client.GET_INFO);
|
||||
|
||||
// In 1.6.2, Minecraft started sending CUSTOM_PAYLOAD in the server list protocol
|
||||
if (version.compareTo(MinecraftVersion.HORSE_UPDATE) >= 0) {
|
||||
clientSide.add(Packets.Client.CUSTOM_PAYLOAD);
|
||||
}
|
||||
serverSide.add(Packets.Server.KICK_DISCONNECT);
|
||||
|
||||
// MCPC++ contains Forge, which uses packet 250 during login
|
||||
if (isMCPC()) {
|
||||
clientSide.add(Packets.Client.CUSTOM_PAYLOAD);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we are runnign MCPC.
|
||||
* @return TRUE if we are, FALSE otherwise.
|
||||
*/
|
||||
private static boolean isMCPC() {
|
||||
return Bukkit.getServer().getVersion().contains("MCPC-Plus");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a packet may be sent during login from a given direction.
|
||||
* @param packetId - the ID of the packet.
|
||||
* @param side - the direction.
|
||||
* @return TRUE if it may, FALSE otherwise.
|
||||
*/
|
||||
public boolean isLoginPacket(int packetId, ConnectionSide side) {
|
||||
switch (side) {
|
||||
case CLIENT_SIDE:
|
||||
return clientSide.contains(packetId);
|
||||
case SERVER_SIDE:
|
||||
return serverSide.contains(packetId);
|
||||
case BOTH:
|
||||
return clientSide.contains(packetId) ||
|
||||
serverSide.contains(packetId);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown connection side: " + side);
|
||||
}
|
||||
}
|
||||
}
|
@ -190,6 +190,9 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
// The current Minecraft version
|
||||
private MinecraftVersion minecraftVersion;
|
||||
|
||||
// Login packets
|
||||
private LoginPackets loginPackets;
|
||||
|
||||
/**
|
||||
* Only create instances of this class if protocol lib is disabled.
|
||||
*/
|
||||
@ -222,6 +225,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
// The plugin verifier
|
||||
this.pluginVerifier = new PluginVerifier(builder.getLibrary());
|
||||
this.minecraftVersion = builder.getMinecraftVersion();
|
||||
this.loginPackets = new LoginPackets(minecraftVersion);
|
||||
|
||||
// The write packet interceptor
|
||||
this.interceptWritePacket = new InterceptWritePacket(classLoader, reporter);
|
||||
@ -367,7 +371,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
playerInjection.checkListener(listener);
|
||||
}
|
||||
if (hasSending)
|
||||
incrementPhases(sending.getGamePhase());
|
||||
incrementPhases(processPhase(sending, ConnectionSide.SERVER_SIDE));
|
||||
|
||||
// Handle receivers after senders
|
||||
if (hasReceiving) {
|
||||
@ -376,7 +380,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
enablePacketFilters(listener, ConnectionSide.CLIENT_SIDE, receiving.getWhitelist());
|
||||
}
|
||||
if (hasReceiving)
|
||||
incrementPhases(receiving.getGamePhase());
|
||||
incrementPhases(processPhase(receiving, ConnectionSide.CLIENT_SIDE));
|
||||
|
||||
// Inform our injected hooks
|
||||
packetListeners.add(listener);
|
||||
@ -384,6 +388,20 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
}
|
||||
}
|
||||
|
||||
private GamePhase processPhase(ListeningWhitelist whitelist, ConnectionSide side) {
|
||||
// Determine if this is a login packet, ensuring that gamephase detection is enabled
|
||||
if (!whitelist.getGamePhase().hasLogin() &&
|
||||
!whitelist.getOptions().contains(ListenerOptions.DISABLE_GAMEPHASE_DETECTION)) {
|
||||
|
||||
for (int id : whitelist.getWhitelist()) {
|
||||
if (loginPackets.isLoginPacket(id, side)) {
|
||||
return GamePhase.BOTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
return whitelist.getGamePhase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when we need to update the input buffer set.
|
||||
*/
|
||||
@ -483,11 +501,11 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
// Remove listeners and phases
|
||||
if (sending != null && sending.isEnabled()) {
|
||||
sendingRemoved = sendingListeners.removeListener(listener, sending);
|
||||
decrementPhases(sending.getGamePhase());
|
||||
decrementPhases(processPhase(sending, ConnectionSide.SERVER_SIDE));
|
||||
}
|
||||
if (receiving != null && receiving.isEnabled()) {
|
||||
receivingRemoved = recievedListeners.removeListener(listener, receiving);
|
||||
decrementPhases(receiving.getGamePhase());
|
||||
decrementPhases(processPhase(receiving, ConnectionSide.CLIENT_SIDE));
|
||||
}
|
||||
|
||||
// Remove hooks, if needed
|
||||
@ -500,7 +518,6 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
||||
|
||||
@Override
|
||||
public void removePacketListeners(Plugin plugin) {
|
||||
|
||||
// Iterate through every packet listener
|
||||
for (PacketListener listener : packetListeners) {
|
||||
// Remove the listener
|
||||
|
@ -32,7 +32,6 @@ import net.sf.cglib.proxy.Factory;
|
||||
import net.sf.cglib.proxy.CallbackFilter;
|
||||
import net.sf.cglib.proxy.NoOp;
|
||||
|
||||
import com.comphenix.protocol.Packets;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
@ -57,7 +56,7 @@ import com.comphenix.protocol.wrappers.WrappedIntHashMap;
|
||||
*/
|
||||
class ProxyPacketInjector implements PacketInjector {
|
||||
public static final ReportType REPORT_CANNOT_FIND_READ_PACKET_METHOD = new ReportType("Cannot find read packet method for ID %s.");
|
||||
public static final ReportType REPORT_UNKNOWN_ORIGIN_FOR_PACKET = new ReportType("Unknown origin %s for packet %s. Are you using GamePhase.LOGIN?");
|
||||
public static final ReportType REPORT_UNKNOWN_ORIGIN_FOR_PACKET = new ReportType("Timeout: Unknown origin %s for packet %s. Are you using GamePhase.LOGIN?");
|
||||
|
||||
/**
|
||||
* Represents a way to update the packet ID to class lookup table.
|
||||
@ -327,9 +326,8 @@ class ProxyPacketInjector implements PacketInjector {
|
||||
if (client != null) {
|
||||
return packetRecieved(packet, client, buffered);
|
||||
} else {
|
||||
// Hack #2 - Caused by our server socket injector
|
||||
if (packet.getID() != Packets.Client.GET_INFO)
|
||||
reporter.reportWarning(this, Report.newBuilder(REPORT_UNKNOWN_ORIGIN_FOR_PACKET).messageParam(input, packet.getID()));
|
||||
// The timeout elapsed!
|
||||
reporter.reportWarning(this, Report.newBuilder(REPORT_UNKNOWN_ORIGIN_FOR_PACKET).messageParam(input, packet.getID()));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,26 @@ public class MinecraftVersion implements Comparable<MinecraftVersion> {
|
||||
*/
|
||||
private static final String VERSION_PATTERN = ".*\\(.*MC.\\s*([a-zA-z0-9\\-\\.]+)\\s*\\)";
|
||||
|
||||
/**
|
||||
* Version 1.7.2 - the update that changed the world.
|
||||
*/
|
||||
public static final MinecraftVersion WORLD_UPDATE = new MinecraftVersion("1.7.2");
|
||||
|
||||
/**
|
||||
* Version 1.6.1 - the horse update.
|
||||
*/
|
||||
public static final MinecraftVersion HORSE_UPDATE = new MinecraftVersion("1.6.1");
|
||||
|
||||
/**
|
||||
* Version 1.5.0 - the redstone update.
|
||||
*/
|
||||
public static final MinecraftVersion REDSTONE_UPDATE = new MinecraftVersion("1.5.0");
|
||||
|
||||
/**
|
||||
* Version 1.4.2 - the scary update (Wither Boss).
|
||||
*/
|
||||
public static final MinecraftVersion SCARY_UPDATE = new MinecraftVersion("1.4.2");
|
||||
|
||||
private final int major;
|
||||
private final int minor;
|
||||
private final int build;
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren