Preliminary network protocol re-work. vanilla clients can now connect. Further cleanup needed.

This commit is contained in:
Lex Manos 2014-09-22 19:29:40 -07:00
parent 1ac0c5d87f
commit 511c370193
15 changed files with 403 additions and 67 deletions

View File

@ -0,0 +1,11 @@
--- ../src-base/minecraft/net/minecraft/client/multiplayer/GuiConnecting.java
+++ ../src-work/minecraft/net/minecraft/client/multiplayer/GuiConnecting.java
@@ -69,7 +69,7 @@
inetaddress = InetAddress.getByName(p_146367_1_);
GuiConnecting.this.field_146371_g = NetworkManager.func_150726_a(inetaddress, p_146367_2_);
GuiConnecting.this.field_146371_g.func_150719_a(new NetHandlerLoginClient(GuiConnecting.this.field_146371_g, GuiConnecting.this.field_146297_k, GuiConnecting.this.field_146374_i));
- GuiConnecting.this.field_146371_g.func_179290_a(new C00Handshake(47, p_146367_1_, p_146367_2_, EnumConnectionState.LOGIN));
+ GuiConnecting.this.field_146371_g.func_179290_a(new C00Handshake(47, p_146367_1_, p_146367_2_, EnumConnectionState.LOGIN, true));
GuiConnecting.this.field_146371_g.func_179290_a(new C00PacketLoginStart(GuiConnecting.this.field_146297_k.func_110432_I().func_148256_e()));
}
catch (UnknownHostException unknownhostexception)

View File

@ -0,0 +1,10 @@
--- ../src-base/minecraft/net/minecraft/client/network/NetHandlerHandshakeMemory.java
+++ ../src-work/minecraft/net/minecraft/client/network/NetHandlerHandshakeMemory.java
@@ -24,6 +24,7 @@
public void func_147383_a(C00Handshake p_147383_1_)
{
+ if (!cpw.mods.fml.common.FMLCommonHandler.instance().handleServerHandshake(p_147383_1_, this.field_147384_b)) return;
this.field_147384_b.func_150723_a(p_147383_1_.func_149594_c());
this.field_147384_b.func_150719_a(new NetHandlerLoginServer(this.field_147385_a, this.field_147384_b));
}

View File

@ -1,6 +1,18 @@
--- ../src-base/minecraft/net/minecraft/network/NetworkManager.java
+++ ../src-work/minecraft/net/minecraft/network/NetworkManager.java
@@ -175,7 +175,7 @@
@@ -88,6 +88,11 @@
this.field_179294_g = p_i46004_1_;
}
+ public EnumPacketDirection getDirection()
+ {
+ return this.field_179294_g;
+ }
+
public void channelActive(ChannelHandlerContext p_channelActive_1_) throws Exception
{
super.channelActive(p_channelActive_1_);
@@ -175,7 +180,7 @@
final EnumConnectionState enumconnectionstate = EnumConnectionState.func_150752_a(p_150732_1_);
final EnumConnectionState enumconnectionstate1 = (EnumConnectionState)this.field_150746_k.attr(field_150739_c).get();
@ -9,7 +21,7 @@
{
field_150735_g.debug("Disabled auto read");
this.field_150746_k.config().setAutoRead(false);
@@ -183,7 +183,7 @@
@@ -183,7 +188,7 @@
if (this.field_150746_k.eventLoop().inEventLoop())
{
@ -18,7 +30,7 @@
{
this.func_150723_a(enumconnectionstate);
}
@@ -204,7 +204,7 @@
@@ -204,7 +209,7 @@
private static final String __OBFID = "CL_00001243";
public void run()
{
@ -27,7 +39,7 @@
{
NetworkManager.this.func_150723_a(enumconnectionstate);
}
@@ -409,6 +409,11 @@
@@ -409,6 +414,11 @@
this.channelRead0(p_channelRead0_1_, (Packet)p_channelRead0_2_);
}

View File

@ -0,0 +1,48 @@
--- ../src-base/minecraft/net/minecraft/network/handshake/client/C00Handshake.java
+++ ../src-work/minecraft/net/minecraft/network/handshake/client/C00Handshake.java
@@ -16,6 +16,7 @@
private int field_149599_c;
private EnumConnectionState field_149597_d;
private static final String __OBFID = "CL_00001372";
+ private boolean hasFMLMarker = false;
public C00Handshake() {}
@@ -28,18 +29,26 @@
this.field_149597_d = p_i45266_4_;
}
+ public C00Handshake(int protocol, String address, int port, EnumConnectionState state, boolean addFMLMarker)
+ {
+ this(protocol, address, port, state);
+ this.hasFMLMarker = addFMLMarker;
+ }
+
public void func_148837_a(PacketBuffer p_148837_1_) throws IOException
{
this.field_149600_a = p_148837_1_.func_150792_a();
this.field_149598_b = p_148837_1_.func_150789_c(255);
this.field_149599_c = p_148837_1_.readUnsignedShort();
this.field_149597_d = EnumConnectionState.func_150760_a(p_148837_1_.func_150792_a());
+ this.hasFMLMarker = this.field_149598_b.contains("\0FML\0");
+ this.field_149598_b = this.field_149598_b.split("\0")[0];
}
public void func_148840_b(PacketBuffer p_148840_1_) throws IOException
{
p_148840_1_.func_150787_b(this.field_149600_a);
- p_148840_1_.func_180714_a(this.field_149598_b);
+ p_148840_1_.func_180714_a(this.field_149598_b + "\0FML\0");
p_148840_1_.writeShort(this.field_149599_c);
p_148840_1_.func_150787_b(this.field_149597_d.func_150759_c());
}
@@ -63,4 +72,9 @@
{
this.func_180770_a((INetHandlerHandshakeServer)p_148833_1_);
}
+
+ public boolean hasFMLMarker()
+ {
+ return this.hasFMLMarker;
+ }
}

View File

@ -1,16 +1,10 @@
--- ../src-base/minecraft/net/minecraft/server/network/NetHandlerHandshakeTCP.java
+++ ../src-work/minecraft/net/minecraft/server/network/NetHandlerHandshakeTCP.java
@@ -23,6 +23,14 @@
@@ -23,6 +23,8 @@
public void func_147383_a(C00Handshake p_147383_1_)
{
+ if (!cpw.mods.fml.common.FMLCommonHandler.instance().shouldAllowPlayerLogins())
+ {
+ ChatComponentText chatcomponenttext = new ChatComponentText("Server is still starting! Please wait before reconnecting.");
+ this.field_147386_b.func_179290_a(new S00PacketDisconnect(chatcomponenttext));
+ this.field_147386_b.func_150718_a(chatcomponenttext);
+ return;
+ }
+ if (!cpw.mods.fml.common.FMLCommonHandler.instance().handleServerHandshake(p_147383_1_, this.field_147386_b)) return;
+
switch (NetHandlerHandshakeTCP.SwitchEnumConnectionState.field_151291_a[p_147383_1_.func_149594_c().ordinal()])
{

View File

@ -28,9 +28,13 @@ import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.EnumConnectionState;
import net.minecraft.network.INetHandler;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.handshake.client.C00Handshake;
import net.minecraft.network.login.server.S00PacketDisconnect;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ChatComponentText;
import net.minecraft.world.World;
import net.minecraft.world.storage.SaveHandler;
import net.minecraft.world.storage.WorldInfo;
@ -40,6 +44,7 @@ import org.apache.logging.log4j.Logger;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.Lists;
@ -52,6 +57,7 @@ import cpw.mods.fml.common.gameevent.InputEvent;
import cpw.mods.fml.common.gameevent.PlayerEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.server.FMLServerHandler;
@ -590,6 +596,39 @@ public class FMLCommonHandler
return sidedDelegate.shouldAllowPlayerLogins();
}
/**
* Process initial Handshake packet, kicks players from the server if they are connecting while we are starting up.
* Also verifies the client has the FML marker.
*
* @param packet Handshake Packet
* @param manager Network connection
* @return True to allow connection, otherwise False.
*/
public boolean handleServerHandshake(C00Handshake packet, NetworkManager manager)
{
if (!shouldAllowPlayerLogins())
{
ChatComponentText text = new ChatComponentText("Server is still starting! Please wait before reconnecting.");
FMLLog.info("Disconnecting Player: " + text.getUnformattedText());
manager.func_179290_a(new S00PacketDisconnect(text));
manager.closeChannel(text);
return false;
}
if (packet.func_149594_c() == EnumConnectionState.LOGIN && (!NetworkRegistry.INSTANCE.isVanillaAccepted(Side.CLIENT) && !packet.hasFMLMarker()))
{
manager.setConnectionState(EnumConnectionState.LOGIN);
ChatComponentText text = new ChatComponentText("This server requires FML/Forge to be installed. Contact your server admin for more details.");
FMLLog.info("Disconnecting Player: " + text.getUnformattedText());
manager.func_179290_a(new S00PacketDisconnect(text));
manager.closeChannel(text);
return false;
}
manager.channel().attr(NetworkRegistry.FML_MARKER).set(packet.hasFMLMarker());
return true;
}
/**
* Used to exit from java, with system exit preventions in place. Will be tidy about it and just log a message,

View File

@ -857,7 +857,8 @@ public class Loader
}
}
FMLLog.info("Attempting connection with missing mods %s at %s", difference, side);
if (difference.size() > 0)
FMLLog.info("Attempting connection with missing mods %s at %s", difference, side);
return true;
}

View File

@ -44,9 +44,12 @@ public class TerminalTransformer implements IClassTransformer
{
final boolean warn = !(clsName.equals("net/minecraft/client/Minecraft") ||
clsName.equals("net/minecraft/server/dedicated/DedicatedServer") ||
clsName.equals("net/minecraft/server/dedicated/ServerHangWatchdog") ||
clsName.equals("net/minecraft/server/dedicated/ServerHangWatchdog$1") ||
clsName.equals("cpw/mods/fml/common/FMLCommonHandler") ||
clsName.startsWith("com/jcraft/jogg/") ||
clsName.startsWith("scala/sys/")
clsName.startsWith("scala/sys/") ||
clsName.startsWith("net/minecraft/server/gui/MinecraftServerGui")
);
return new MethodVisitor(Opcodes.ASM4, super.visitMethod(mAccess, mName, mDesc, mSignature, mExceptions))
@ -132,6 +135,7 @@ public class TerminalTransformer implements IClassTransformer
// FML is allowed to call system exit and the Minecraft applet (from the quit button), and the dedicated server (from itself)
if (!(callingClass.startsWith("cpw.mods.fml.") ||
("net.minecraft.client.Minecraft".equals(callingClass) && "net.minecraft.client.Minecraft".equals(callingParent)) ||
("net.minecraft.server.gui.MinecraftServerGui$1".equals(callingClass) && "java.awt.AWTEventMulticaster".equals(callingParent)) ||
("net.minecraft.server.dedicated.DedicatedServer".equals(callingClass) && "net.minecraft.server.MinecraftServer".equals(callingParent)))
)
{

View File

@ -58,10 +58,11 @@ public enum NetworkRegistry
/**
* Set in the {@link ChannelHandlerContext}
*/
public static final AttributeKey<String> FML_CHANNEL = new AttributeKey<String>("fml:channelName");
public static final AttributeKey<Side> CHANNEL_SOURCE = new AttributeKey<Side>("fml:channelSource");
public static final AttributeKey<ModContainer> MOD_CONTAINER = new AttributeKey<ModContainer>("fml:modContainer");
public static final AttributeKey<INetHandler> NET_HANDLER = new AttributeKey<INetHandler>("fml:netHandler");
public static final AttributeKey<String> FML_CHANNEL = AttributeKey.valueOf("fml:channelName");
public static final AttributeKey<Side> CHANNEL_SOURCE = AttributeKey.valueOf("fml:channelSource");
public static final AttributeKey<ModContainer> MOD_CONTAINER = AttributeKey.valueOf("fml:modContainer");
public static final AttributeKey<INetHandler> NET_HANDLER = AttributeKey.valueOf("fml:netHandler");
public static final AttributeKey<Boolean> FML_MARKER = AttributeKey.valueOf("fml:hasMarker");
public static final byte FML_PROTOCOL = 1;

View File

@ -0,0 +1,88 @@
package cpw.mods.fml.common.network;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.SimpleChannelInboundHandler;
import java.util.List;
import org.apache.logging.log4j.Level;
import cpw.mods.fml.common.FMLLog;
import net.minecraft.network.EnumPacketDirection;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.MessageDeserializer2;
import net.minecraft.util.MessageSerializer2;
public class PacketLoggingHandler
{
public static void register(NetworkManager manager)
{
ChannelPipeline pipeline = manager.channel().pipeline();
final EnumPacketDirection direction = manager.getDirection();
if (manager.isLocalChannel())
{
pipeline.addBefore("packet_handler", "splitter", new SimpleChannelInboundHandler<Packet>()
{
@Override
protected void channelRead0(ChannelHandlerContext ctx, Packet msg) throws Exception
{
PacketBuffer buf = new PacketBuffer(Unpooled.buffer());
msg.writePacketData(buf);
FMLLog.log(Level.DEBUG, "$s $s:\n%s", msg.getClass().getSimpleName(), ByteBufUtils.getContentDump(buf));
ctx.fireChannelRead(msg);
}
});
pipeline.addBefore("splitter", "prepender", new ChannelOutboundHandlerAdapter()
{
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception
{
if (msg instanceof Packet)
{
PacketBuffer buf = new PacketBuffer(Unpooled.buffer());
((Packet)msg).writePacketData(buf);
FMLLog.log(Level.DEBUG, "$s $s:\n%s", msg.getClass().getSimpleName(), ByteBufUtils.getContentDump(buf));
}
ctx.write(msg, promise);
}
});
}
else
{
pipeline.replace("splitter", "splitter", new MessageDeserializer2()
{
String prefix = (direction == EnumPacketDirection.SERVERBOUND ? "SERVER: C->S" : "CLIENT: S->C");
@Override
protected void decode(ChannelHandlerContext context, ByteBuf input, List output)
{
super.decode(context, input, output);
for (ByteBuf pkt : (List<ByteBuf>)output)
{
pkt.markReaderIndex();
FMLLog.log(Level.DEBUG, "%s:\n%s", prefix, ByteBufUtils.getContentDump(pkt));
pkt.resetReaderIndex();
}
}
});
pipeline.replace("prepender", "prepender", new MessageSerializer2()
{
String prefix = (direction == EnumPacketDirection.SERVERBOUND ? "SERVER: S->C" : "CLIENT: C->S");
@Override
protected void encode(ChannelHandlerContext context, ByteBuf input, ByteBuf output)
{
input.markReaderIndex();
FMLLog.log(Level.DEBUG, "%s:\n%s", prefix, ByteBufUtils.getContentDump(input));
input.resetReaderIndex();
super.encode(context, input, output);
}
});
}
}
}

View File

@ -26,7 +26,7 @@ import cpw.mods.fml.common.registry.GameData;
public abstract class FMLHandshakeMessage {
public static FMLProxyPacket makeCustomChannelRegistration(Set<String> channels)
{
String salutation = Joiner.on('\0').join(Iterables.concat(Arrays.asList("FML|HS","FML"),channels));
String salutation = Joiner.on('\0').join(Iterables.concat(Arrays.asList("FML|HS","FML", "FML|MP"),channels));
FMLProxyPacket proxy = new FMLProxyPacket(new PacketBuffer(Unpooled.wrappedBuffer(salutation.getBytes(Charsets.UTF_8))), "REGISTER");
return proxy;
}

View File

@ -7,7 +7,7 @@ import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.AttributeKey;
public class HandshakeMessageHandler<S extends Enum<S> & IHandshakeState<S>> extends SimpleChannelInboundHandler<FMLHandshakeMessage> {
private static final AttributeKey<IHandshakeState<?>> STATE = new AttributeKey<IHandshakeState<?>>("fml:handshake-state");
private static final AttributeKey<IHandshakeState<?>> STATE = AttributeKey.valueOf("fml:handshake-state");
private final AttributeKey<S> fmlHandshakeState;
private S initialState;
private Class<S> stateType;
@ -23,8 +23,9 @@ public class HandshakeMessageHandler<S extends Enum<S> & IHandshakeState<S>> ext
protected void channelRead0(ChannelHandlerContext ctx, FMLHandshakeMessage msg) throws Exception
{
S state = ctx.attr(fmlHandshakeState).get();
FMLLog.finer(msg.toString(stateType) + "->" + state.getClass().getName().substring(state.getClass().getName().lastIndexOf('.')+1)+":"+state);
FMLLog.fine(stateType.getSimpleName() + ": " + msg.toString(stateType) + "->" + state.getClass().getName().substring(state.getClass().getName().lastIndexOf('.')+1)+":"+state);
S newState = state.accept(ctx, msg);
FMLLog.fine(" Next: " + newState.name());
ctx.attr(fmlHandshakeState).set(newState);
}
@ -37,7 +38,9 @@ public class HandshakeMessageHandler<S extends Enum<S> & IHandshakeState<S>> ext
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception
{
S state = ctx.attr(fmlHandshakeState).get();
FMLLog.fine(stateType.getSimpleName() + ": null->" + state.getClass().getName().substring(state.getClass().getName().lastIndexOf('.')+1)+":"+state);
S newState = state.accept(ctx, null);
FMLLog.fine(" Next: " + newState.name());
ctx.attr(fmlHandshakeState).set(newState);
}

View File

@ -1,5 +1,6 @@
package cpw.mods.fml.common.network.handshake;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOutboundHandler;
@ -10,19 +11,24 @@ import io.netty.util.AttributeKey;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.ScheduledFuture;
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.channels.ClosedChannelException;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.Level;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.EnumConnectionState;
import net.minecraft.network.INetHandler;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.play.client.C17PacketCustomPayload;
import net.minecraft.network.play.server.S01PacketJoinGame;
import net.minecraft.network.play.server.S3FPacketCustomPayload;
@ -35,12 +41,14 @@ import cpw.mods.fml.common.network.FMLNetworkEvent;
import cpw.mods.fml.common.network.FMLNetworkException;
import cpw.mods.fml.common.network.FMLOutboundHandler;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.PacketLoggingHandler;
import cpw.mods.fml.common.network.internal.FMLMessage;
import cpw.mods.fml.common.network.internal.FMLNetworkHandler;
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
import cpw.mods.fml.relauncher.Side;
public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> implements ChannelOutboundHandler {
private static boolean DEBUG_HANDSHAKE = Boolean.parseBoolean(System.getProperty("fml.debugNetworkHandshake", "false"));
private static enum ConnectionState {
OPENING, AWAITING_HANDSHAKE, HANDSHAKING, HANDSHAKECOMPLETE, CONNECTED;
}
@ -68,8 +76,8 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> imple
return net;
}
public static final AttributeKey<NetworkDispatcher> FML_DISPATCHER = new AttributeKey<NetworkDispatcher>("fml:dispatcher");
public static final AttributeKey<Boolean> IS_LOCAL = new AttributeKey<Boolean>("fml:isLocal");
public static final AttributeKey<NetworkDispatcher> FML_DISPATCHER = AttributeKey.valueOf("fml:dispatcher");
public static final AttributeKey<Boolean> IS_LOCAL = AttributeKey.valueOf("fml:isLocal");
public final NetworkManager manager;
private final ServerConfigurationManager scm;
private EntityPlayerMP player;
@ -91,6 +99,8 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> imple
this.handshakeChannel.attr(NetworkRegistry.CHANNEL_SOURCE).set(Side.SERVER);
this.handshakeChannel.attr(NetworkRegistry.FML_CHANNEL).set("FML|HS");
this.handshakeChannel.attr(IS_LOCAL).set(manager.isLocalChannel());
if (DEBUG_HANDSHAKE)
PacketLoggingHandler.register(manager);
}
public NetworkDispatcher(NetworkManager manager, ServerConfigurationManager scm)
@ -104,12 +114,26 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> imple
this.handshakeChannel.attr(NetworkRegistry.CHANNEL_SOURCE).set(Side.CLIENT);
this.handshakeChannel.attr(NetworkRegistry.FML_CHANNEL).set("FML|HS");
this.handshakeChannel.attr(IS_LOCAL).set(manager.isLocalChannel());
if (DEBUG_HANDSHAKE)
PacketLoggingHandler.register(manager);
}
public void serverToClientHandshake(EntityPlayerMP player)
{
this.player = player;
insertIntoChannel();
Boolean fml = this.manager.channel().attr(NetworkRegistry.FML_MARKER).get();
if (fml != null && fml.booleanValue())
{
//FML on client, send server hello
//TODO: Make this cleaner as it uses netty magic 0.o
}
else
{
serverInitiateHandshake();
FMLLog.info("Connection received without FML marker, assuming vanilla.");
this.completeServerSideConnection(ConnectionType.VANILLA);
}
}
private void insertIntoChannel()
@ -138,7 +162,6 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> imple
// Send mod salutation to the client
// This will be ignored by vanilla clients
this.state = ConnectionState.AWAITING_HANDSHAKE;
this.manager.channel().pipeline().addFirst("fml:vanilla_detector", new VanillaTimeoutWaiter());
// Need to start the handler here, so we can send custompayload packets
serverHandler = new NetHandlerPlayServer(scm.getServerInstance(), manager, player);
this.netHandler = serverHandler;
@ -170,6 +193,8 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> imple
FMLLog.info("[%s] Server side %s connection established", Thread.currentThread().getName(), this.connectionType.name().toLowerCase(Locale.ENGLISH));
this.state = ConnectionState.CONNECTED;
FMLCommonHandler.instance().bus().post(new FMLNetworkEvent.ServerConnectionFromClientEvent(manager));
if (DEBUG_HANDSHAKE)
manager.closeChannel(new ChatComponentText("Handshake Complete review log file for details."));
scm.initializeConnectionToPlayer(manager, player, serverHandler);
}
@Override
@ -247,9 +272,41 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> imple
manager.channel().config().setAutoRead(false);
}
private MultiPartCustomPayload multipart = null;
private boolean handleClientSideCustomPacket(S3FPacketCustomPayload msg, ChannelHandlerContext context)
{
String channelName = msg.func_149169_c();
if ("FML|MP".equals(channelName))
{
try
{
if (multipart == null)
{
multipart = new MultiPartCustomPayload(msg.func_180735_b());
}
else
{
multipart.processPart(msg.func_180735_b());
}
}
catch (IOException e)
{
this.kickWithMessage(e.getMessage());
multipart = null;
return true;
}
if (multipart.isComplete())
{
msg = multipart;
channelName = msg.func_149169_c();
multipart = null;
}
else
{
return true; // Haven't received all so return till we have.
}
}
if ("FML|HS".equals(channelName) || "REGISTER".equals(channelName) || "UNREGISTER".equals(channelName))
{
FMLProxyPacket proxy = new FMLProxyPacket(msg);
@ -283,7 +340,6 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> imple
{
if (state == ConnectionState.AWAITING_HANDSHAKE)
{
this.manager.channel().pipeline().remove("fml:vanilla_detector");
state = ConnectionState.HANDSHAKING;
}
String channelName = msg.func_149559_c();
@ -315,34 +371,6 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> imple
return false;
}
private class VanillaTimeoutWaiter extends ChannelInboundHandlerAdapter
{
private ScheduledFuture<Void> future;
@Override
public void handlerAdded(final ChannelHandlerContext ctx) throws Exception
{
future = ctx.executor().schedule(new Callable<Void>() {
@Override
public Void call() throws Exception
{
if (state != ConnectionState.CONNECTED)
{
FMLLog.info("Timeout occurred waiting for response, assuming vanilla connection");
ctx.fireUserEventTriggered(ConnectionType.VANILLA);
}
return null;
}
}, 10, TimeUnit.HOURS);
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception
{
future.cancel(true);
}
}
public void sendProxy(FMLProxyPacket msg)
{
manager.func_179290_a(msg);
@ -414,9 +442,18 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> imple
if (msg instanceof FMLProxyPacket)
{
if (side == Side.CLIENT)
{
//Client to server large packets are not supported to prevent client being bad.
ctx.write(((FMLProxyPacket) msg).toC17Packet(), promise);
}
else
ctx.write(((FMLProxyPacket) msg).toS3FPacket(), promise);
{
List<Packet> parts = ((FMLProxyPacket)msg).toS3FPackets();
for (Packet pkt : parts)
{
ctx.write(pkt, promise);
}
}
}
else
{
@ -480,4 +517,57 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler<Packet> imple
this.handshakeChannel.attr(FML_DISPATCHER).remove();
this.manager.channel().attr(FML_DISPATCHER).remove();
}
private class MultiPartCustomPayload extends S3FPacketCustomPayload
{
private String channel;
private byte[] data;
private PacketBuffer data_buf = null;
private int part_count = 0;
private int part_expected = 0;
private int offset = 0;
private MultiPartCustomPayload(PacketBuffer preamble) throws IOException
{
channel = preamble.readStringFromBuffer(20);
part_count = preamble.readUnsignedByte();
int length = preamble.readInt();
if (length <= 0 || length >= FMLProxyPacket.MAX_LENGTH)
{
throw new IOException("The received FML MultiPart packet outside of valid length bounds, Max: " + FMLProxyPacket.MAX_LENGTH + ", Received: " + length);
}
data = new byte[length];
data_buf = new PacketBuffer(Unpooled.wrappedBuffer(data));
}
public void processPart(PacketBuffer input) throws IOException
{
int part = (int)(input.readByte() & 0xFF);
if (part != part_expected)
{
throw new IOException("Received FML MultiPart packet out of order, Expected " + part_expected + " Got " + part);
}
int len = input.readableBytes() - 1;
input.readBytes(data, offset, len);
part_expected++;
offset += len;
}
public boolean isComplete()
{
return part_expected == part_count;
}
@Override
public String func_149169_c() // getChannel
{
return this.channel;
}
@Override
public PacketBuffer func_180735_b() // getData
{
return this.data_buf;
}
}
}

View File

@ -3,19 +3,26 @@ package cpw.mods.fml.common.network.internal;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.embedded.EmbeddedChannel;
import java.io.IOException;
import java.util.List;
import net.minecraft.network.INetHandler;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.play.client.C17PacketCustomPayload;
import net.minecraft.network.play.server.S3FPacketCustomPayload;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.helpers.Integers;
import com.google.common.collect.ConcurrentHashMultiset;
import com.google.common.collect.Lists;
import com.google.common.collect.Multiset;
import com.google.common.collect.Multiset.Entry;
import com.google.common.collect.Multisets;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.network.FMLNetworkException;
import cpw.mods.fml.common.network.NetworkRegistry;
@ -116,9 +123,42 @@ public class FMLProxyPacket implements Packet {
return new C17PacketCustomPayload(channel, payload);
}
public Packet toS3FPacket()
static final int PART_SIZE = 0x1000000 - 0x50; // Make it a constant so that it gets inlined below.
public static final int MAX_LENGTH = PART_SIZE * 255;
public List<Packet> toS3FPackets() throws IOException
{
return new S3FPacketCustomPayload(channel, payload);
List<Packet> ret = Lists.newArrayList();
byte[] data = payload.array();
if (data.length < PART_SIZE)
{
ret.add(new S3FPacketCustomPayload(channel, payload));
}
else
{
int parts = (int)Math.ceil(data.length / (double)(PART_SIZE - 1)); //We add a byte header so -1
if (parts > 255)
{
throw new IllegalArgumentException("Payload may not be larger than " + MAX_LENGTH + " bytes");
}
PacketBuffer preamble = new PacketBuffer(Unpooled.buffer());
preamble.func_180714_a(channel);
preamble.writeByte(parts);
preamble.writeInt(data.length);
ret.add(new S3FPacketCustomPayload("FML|MP", preamble));
int offset = 0;
for (int x = 0; x < parts; x++)
{
int length = Math.min(PART_SIZE, data.length - offset + 1);
byte[] tmp = new byte[length];
tmp[0] = (byte)(x & 0xFF);
System.arraycopy(data, offset, tmp, 1, tmp.length - 1);
offset += tmp.length - 1;
ret.add(new S3FPacketCustomPayload("FML|MP", new PacketBuffer(Unpooled.wrappedBuffer(tmp))));
}
}
return ret;
}
public void setTarget(Side target)

View File

@ -65,16 +65,8 @@ public class GameData {
private static final GameData mainData = new GameData();
/**
* @deprecated use {@link #getBlockRegistry()} instead.
*/
@Deprecated
public static final FMLControlledNamespacedRegistry<Block> blockRegistry = getBlockRegistry();
/**
* @deprecated use {@link #getItemRegistry()} instead.
*/
@Deprecated
public static final FMLControlledNamespacedRegistry<Item> itemRegistry = getItemRegistry();
private static final FMLControlledNamespacedRegistry<Block> blockRegistry = getBlockRegistry();
private static final FMLControlledNamespacedRegistry<Item> itemRegistry = getItemRegistry();
private static Table<String, String, ItemStack> customItemStacks = HashBasedTable.create();
private static Map<UniqueIdentifier, ModContainer> customOwners = Maps.newHashMap();
@ -970,7 +962,10 @@ public class GameData {
Object blockName = iBlockRegistry.func_177774_c(item.blockInstance);
Object itemName = iItemRegistry.func_177774_c(item);
if (blockName != null && !blockName.equals(itemName))
//Vanilla has a mismatch:
//Block <-> ItemBlock name mismatch, block name minecraft:standing_banner, item name minecraft:banner
//TODO: Untie these in the rest of the registry
if (blockName != null && !blockName.equals(itemName) && !"minecraft:standing_banner".equals(blockName.toString()))
{
FMLLog.bigWarning("Block <-> ItemBlock name mismatch, block name %s, item name %s", blockName, itemName);
}