Archiviert
13
0

Adding automatic GamePhase detection.

This should solve the infamous UNKNOWN ORIGIN problem, especially in 
MCPC++.
Dieser Commit ist enthalten in:
Kristian S. Stangeland 2013-10-31 01:55:55 +01:00
Ursprung 68c0a3c1dc
Commit 47134b43cc
6 geänderte Dateien mit 125 neuen und 11 gelöschten Zeilen

Datei anzeigen

@ -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;
}

Datei anzeigen

@ -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);
}
}
}

Datei anzeigen

@ -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

Datei anzeigen

@ -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,8 +326,7 @@ 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)
// The timeout elapsed!
reporter.reportWarning(this, Report.newBuilder(REPORT_UNKNOWN_ORIGIN_FOR_PACKET).messageParam(input, packet.getID()));
return null;
}

Datei anzeigen

@ -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;