diff --git a/fml/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java.patch b/fml/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java.patch new file mode 100644 index 0000000000..f92bdb01ba --- /dev/null +++ b/fml/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java.patch @@ -0,0 +1,11 @@ +--- ../src-base/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java ++++ ../src-work/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java +@@ -247,7 +247,7 @@ + { + PacketThreadUtil.func_180031_a(p_147282_1_, this, this.field_147299_f); + this.field_147299_f.field_71442_b = new PlayerControllerMP(this.field_147299_f, this); +- this.field_147300_g = new WorldClient(this, new WorldSettings(0L, p_147282_1_.func_149198_e(), false, p_147282_1_.func_149195_d(), p_147282_1_.func_149196_i()), p_147282_1_.func_149194_f(), p_147282_1_.func_149192_g(), this.field_147299_f.field_71424_I); ++ this.field_147300_g = new WorldClient(this, new WorldSettings(0L, p_147282_1_.func_149198_e(), false, p_147282_1_.func_149195_d(), p_147282_1_.func_149196_i()), net.minecraftforge.fml.common.network.handshake.NetworkDispatcher.get(func_147298_b()).getOverrideDimension(p_147282_1_), p_147282_1_.func_149192_g(), this.field_147299_f.field_71424_I); + this.field_147299_f.field_71474_y.field_74318_M = p_147282_1_.func_149192_g(); + this.field_147299_f.func_71403_a(this.field_147300_g); + this.field_147299_f.field_71439_g.field_71093_bK = p_147282_1_.func_149194_f(); diff --git a/fml/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.java.patch b/fml/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.java.patch index 6c80950f95..259097c601 100644 --- a/fml/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.java.patch +++ b/fml/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.java.patch @@ -26,8 +26,23 @@ if (nbttagcompound != null && nbttagcompound.func_150297_b("Riding", 10)) { Entity entity = EntityList.func_75615_a(nbttagcompound.func_74775_l("Riding"), worldserver); -@@ -283,6 +284,8 @@ +@@ -281,8 +282,23 @@ + return nbttagcompound1; + } ++ public NBTTagCompound getPlayerNBT(EntityPlayerMP player) ++ { ++ // Hacky method to allow loading the NBT for a player prior to login ++ NBTTagCompound nbttagcompound = this.field_72400_f.field_71305_c[0].func_72912_H().func_76072_h(); ++ if (player.func_70005_c_().equals(this.field_72400_f.func_71214_G()) && nbttagcompound != null) ++ { ++ return nbttagcompound; ++ } ++ else ++ { ++ return ((net.minecraft.world.storage.SaveHandler)this.field_72412_k).getPlayerNBT(player); ++ } ++ } protected void func_72391_b(EntityPlayerMP p_72391_1_) { + if (p_72391_1_.field_71135_a == null) return; @@ -35,7 +50,7 @@ this.field_72412_k.func_75753_a(p_72391_1_); StatisticsFile statisticsfile = (StatisticsFile)this.field_148547_k.get(p_72391_1_.func_110124_au()); -@@ -315,6 +318,7 @@ +@@ -315,6 +331,7 @@ public void func_72367_e(EntityPlayerMP p_72367_1_) { @@ -43,7 +58,7 @@ p_72367_1_.func_71029_a(StatList.field_75947_j); this.func_72391_b(p_72367_1_); WorldServer worldserver = p_72367_1_.func_71121_q(); -@@ -473,6 +477,7 @@ +@@ -473,6 +490,7 @@ this.field_177454_f.put(entityplayermp1.func_110124_au(), entityplayermp1); entityplayermp1.func_71116_b(); entityplayermp1.func_70606_j(entityplayermp1.func_110143_aJ()); @@ -51,7 +66,7 @@ return entityplayermp1; } -@@ -498,6 +503,7 @@ +@@ -498,6 +516,7 @@ PotionEffect potioneffect = (PotionEffect)iterator.next(); p_72356_1_.field_71135_a.func_147359_a(new S1DPacketEntityEffect(p_72356_1_.func_145782_y(), potioneffect)); } diff --git a/fml/patches/minecraft/net/minecraft/world/storage/SaveHandler.java.patch b/fml/patches/minecraft/net/minecraft/world/storage/SaveHandler.java.patch index 72a4b5be63..6b8e86b5c0 100644 --- a/fml/patches/minecraft/net/minecraft/world/storage/SaveHandler.java.patch +++ b/fml/patches/minecraft/net/minecraft/world/storage/SaveHandler.java.patch @@ -64,3 +64,26 @@ try { File file1 = new File(this.field_75770_b, "level.dat_new"); +@@ -301,4 +320,22 @@ + { + return this.field_75767_f; + } ++ ++ public NBTTagCompound getPlayerNBT(net.minecraft.entity.player.EntityPlayerMP player) ++ { ++ try ++ { ++ File file1 = new File(this.field_75771_c, player.func_110124_au().toString() + ".dat"); ++ ++ if (file1.exists() && file1.isFile()) ++ { ++ return CompressedStreamTools.func_74796_a(new FileInputStream(file1)); ++ } ++ } ++ catch (Exception exception) ++ { ++ field_151478_a.warn("Failed to load player data for " + player.func_70005_c_()); ++ } ++ return null; ++ } + } diff --git a/fml/src/main/java/net/minecraftforge/fml/common/functions/GenericIterableFactory.java b/fml/src/main/java/net/minecraftforge/fml/common/functions/GenericIterableFactory.java index 83534b3def..9d570a16d2 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/functions/GenericIterableFactory.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/functions/GenericIterableFactory.java @@ -1,8 +1,23 @@ package net.minecraftforge.fml.common.functions; +import java.util.Iterator; + import com.google.common.collect.Iterables; +import com.google.common.collect.Iterators; public class GenericIterableFactory { + public static Iterable newCastingIterable(final Iterator input, final Class type) + { + return new Iterable() + { + @Override + public Iterator iterator() + { + return Iterators.transform(input, new TypeCastFunction(type)); + } + }; + } + public static Iterable newCastingIterable(Iterable input, Class type) { return Iterables.transform(input, new TypeCastFunction(type)); diff --git a/fml/src/main/java/net/minecraftforge/fml/common/network/NetworkRegistry.java b/fml/src/main/java/net/minecraftforge/fml/common/network/NetworkRegistry.java index e088250a68..66ed284b2a 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/network/NetworkRegistry.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/network/NetworkRegistry.java @@ -64,7 +64,9 @@ public enum NetworkRegistry public static final AttributeKey NET_HANDLER = AttributeKey.valueOf("fml:netHandler"); public static final AttributeKey FML_MARKER = AttributeKey.valueOf("fml:hasMarker"); - public static final byte FML_PROTOCOL = 1; + // Version 1: ServerHello only contains this value as a byte + // Version 2: ServerHello additionally contains a 4 byte (int) dimension for the logging in client + public static final byte FML_PROTOCOL = 2; private NetworkRegistry() { diff --git a/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeClientState.java b/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeClientState.java index d28a6d5b87..15324aa233 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeClientState.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeClientState.java @@ -6,6 +6,7 @@ import java.util.List; import net.minecraftforge.fml.common.FMLLog; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.network.NetworkRegistry; +import net.minecraftforge.fml.common.network.handshake.FMLHandshakeMessage.ServerHello; import net.minecraftforge.fml.common.network.internal.FMLMessage; import net.minecraftforge.fml.common.network.internal.FMLNetworkHandler; import net.minecraftforge.fml.common.registry.GameData; @@ -51,7 +52,14 @@ enum FMLHandshakeClientState implements IHandshakeState return DONE; } - FMLLog.info("Server protocol version %x", ((FMLHandshakeMessage.ServerHello)msg).protocolVersion()); + ServerHello serverHelloPacket = (FMLHandshakeMessage.ServerHello)msg; + FMLLog.info("Server protocol version %x", serverHelloPacket.protocolVersion()); + if (serverHelloPacket.protocolVersion() > 1) + { + // Server sent us an extra dimension for the logging in player - stash it for retrieval later + NetworkDispatcher dispatcher = ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(); + dispatcher.setOverrideDimension(serverHelloPacket.overrideDim()); + } ctx.writeAndFlush(new FMLHandshakeMessage.ClientHello()).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); ctx.writeAndFlush(new FMLHandshakeMessage.ModList(Loader.instance().getActiveModList())).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); return WAITINGSERVERDATA; diff --git a/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeMessage.java b/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeMessage.java index 1ff2c0a12e..984f600ff2 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeMessage.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeMessage.java @@ -10,6 +10,7 @@ import java.util.Map.Entry; import java.util.Set; import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.common.FMLLog; import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.common.network.NetworkRegistry; @@ -31,22 +32,47 @@ public abstract class FMLHandshakeMessage { } public static class ServerHello extends FMLHandshakeMessage { private byte serverProtocolVersion; + private int overrideDimension; + public ServerHello() + { + // noargs for the proto + } + public ServerHello(int overrideDim) + { + this.overrideDimension = overrideDim; + } + @Override public void toBytes(ByteBuf buffer) { buffer.writeByte(NetworkRegistry.FML_PROTOCOL); + buffer.writeInt(overrideDimension); } @Override public void fromBytes(ByteBuf buffer) { serverProtocolVersion = buffer.readByte(); + // Extended dimension support during login + if (serverProtocolVersion > 1) + { + overrideDimension = buffer.readInt(); + FMLLog.fine("Server FML protocol version %d, 4 byte dimension received %d", serverProtocolVersion, overrideDimension); + } + else + { + FMLLog.info("Server FML protocol version %d, no additional data received", serverProtocolVersion); + } } public byte protocolVersion() { return serverProtocolVersion; } + + public int overrideDim() { + return overrideDimension; + } } public static class ClientHello extends FMLHandshakeMessage { private byte serverProtocolVersion; diff --git a/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeServerState.java b/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeServerState.java index b800429f9d..f2683b8e04 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeServerState.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/FMLHandshakeServerState.java @@ -22,9 +22,9 @@ enum FMLHandshakeServerState implements IHandshakeState public FMLHandshakeServerState accept(ChannelHandlerContext ctx, FMLHandshakeMessage msg) { NetworkDispatcher dispatcher = ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get(); - dispatcher.serverInitiateHandshake(); + int overrideDim = dispatcher.serverInitiateHandshake(); ctx.writeAndFlush(FMLHandshakeMessage.makeCustomChannelRegistration(NetworkRegistry.INSTANCE.channelNamesFor(Side.SERVER))).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); - ctx.writeAndFlush(new FMLHandshakeMessage.ServerHello()).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + ctx.writeAndFlush(new FMLHandshakeMessage.ServerHello(overrideDim)).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); return HELLO; } }, diff --git a/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/NetworkDispatcher.java b/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/NetworkDispatcher.java index 1be6617d88..1d60503b71 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/NetworkDispatcher.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/network/handshake/NetworkDispatcher.java @@ -21,6 +21,7 @@ import java.util.Map; import org.apache.logging.log4j.Level; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.EnumConnectionState; import net.minecraft.network.INetHandler; import net.minecraft.network.NetHandlerPlayServer; @@ -88,6 +89,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple private NetHandlerPlayServer serverHandler; private INetHandler netHandler; private Map modList; + private int overrideLoginDim; public NetworkDispatcher(NetworkManager manager) { @@ -136,7 +138,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple this.completeServerSideConnection(ConnectionType.VANILLA); } } - + protected void setModList(Map modList) { this.modList = modList; @@ -163,7 +165,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple this.manager.channel().config().setAutoRead(true); } - void serverInitiateHandshake() + int serverInitiateHandshake() { // Send mod salutation to the client // This will be ignored by vanilla clients @@ -186,6 +188,18 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple player.playerNetServerHandler = null; // manually for the manager into the PLAY state, so we can send packets later this.manager.setConnectionState(EnumConnectionState.PLAY); + + // Return the dimension the player is in, so it can be pre-sent to the client in the ServerHello v2 packet + // Requires some hackery to the serverconfigmanager and stuff for this to work + NBTTagCompound playerNBT = scm.getPlayerNBT(player); + if (playerNBT!=null) + { + return playerNBT.getInteger("Dimension"); + } + else + { + return 0; + } } void clientListenForServerHandshake() @@ -253,10 +267,10 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple { return netHandler; } - + /** * The mod list returned by this method is in no way reliable because it is provided by the client - * + * * @return a map that will contain String keys and values listing all mods and their versions */ public Map getModList() @@ -545,6 +559,16 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple this.manager.channel().attr(FML_DISPATCHER).remove(); } + public void setOverrideDimension(int overrideDim) { + this.overrideLoginDim = overrideDim; + FMLLog.fine("Received override dimension %d", overrideDim); + } + + public int getOverrideDimension(S01PacketJoinGame p_147282_1_) { + FMLLog.fine("Overriding dimension: using %d", this.overrideLoginDim); + return this.overrideLoginDim != 0 ? this.overrideLoginDim : p_147282_1_.getDimension(); + } + private class MultiPartCustomPayload extends S3FPacketCustomPayload { private String channel; diff --git a/fml/src/main/java/net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry.java b/fml/src/main/java/net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry.java index 6c9994fd33..b558c14888 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/registry/FMLControlledNamespacedRegistry.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -23,6 +24,7 @@ import net.minecraftforge.fml.common.functions.GenericIterableFactory; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterators; public class FMLControlledNamespacedRegistry extends RegistryNamespacedDefaultedByKey { private final Class superType; @@ -107,6 +109,8 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespacedDefaul this.minId = registry.minId; this.aliases.clear(); this.aliases.putAll(registry.aliases); + this.activeSubstitutions.clear(); + underlyingIntegerMap = new ObjectIntIdentityMap(); registryObjects.clear(); @@ -114,6 +118,7 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespacedDefaul { addObjectRaw(registry.getId(thing), registry.getNameForObject(thing), thing); } + this.activeSubstitutions.putAll(registry.activeSubstitutions); } // public api @@ -239,9 +244,19 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespacedDefaul */ public I getRaw(int id) { - return superType.cast(super.getObjectById(id)); + return cast(super.getObjectById(id)); } + /** + * superType.cast appears to be expensive. Skip it for speed? + * @param obj + * @return + */ + @SuppressWarnings("unchecked") + private I cast(Object obj) + { + return (I)(obj); + } /** * Get the object identified by the specified name. * @@ -324,10 +339,13 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespacedDefaul return containsKey(itemName); } + /* + * This iterator is used by FML to visit the actual block sets, it should use the super.iterator method instead + * Compare #iterator() + */ public Iterable typeSafeIterable() { - Iterable self = this; - return GenericIterableFactory.newCastingIterable(self, superType); + return GenericIterableFactory.newCastingIterable(super.iterator(), superType); } // internal @@ -496,7 +514,7 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespacedDefaul FMLLog.severe("The substitution of %s has already occured. You cannot duplicate substitutions", nameToReplace); throw new ExistingSubstitutionException(nameToReplace, toReplace); } - I replacement = superType.cast(toReplace); + I replacement = cast(toReplace); I original = getRaw(nameToReplace); if (original == null) { diff --git a/fml/src/main/java/net/minecraftforge/fml/common/registry/GameData.java b/fml/src/main/java/net/minecraftforge/fml/common/registry/GameData.java index 7fd1bca226..a08c114c1d 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/registry/GameData.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/registry/GameData.java @@ -946,6 +946,7 @@ public class GameData { void registerSubstitutionAlias(String nameToSubstitute, Type type, Object toReplace) throws ExistingSubstitutionException { type.getRegistry().addSubstitutionAlias(Loader.instance().activeModContainer().getModId(),nameToSubstitute, toReplace); + type.getRegistry().activateSubstitution(nameToSubstitute); } static RegistryDelegate buildDelegate(T referant, Class type) {