From 278612ad989ecf77ef6985b18ca4838546e474f7 Mon Sep 17 00:00:00 2001 From: cpw Date: Sat, 14 Mar 2015 15:32:34 -0400 Subject: [PATCH 1/9] Try and improve performance of the registry by avoiding superType.cast. --- .../FMLControlledNamespacedRegistry.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/fml/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java b/fml/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java index 49c5911dd0..7f013bd0ab 100644 --- a/fml/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java +++ b/fml/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java @@ -128,7 +128,7 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespaced { public void putObject(Object objName, Object obj) { String name = (String) objName; - I thing = superType.cast(obj); + I thing = cast(obj); if (name == null) throw new NullPointerException("Can't use a null-name for the registry."); if (name.isEmpty()) throw new IllegalArgumentException("Can't use an empty name for the registry."); @@ -224,9 +224,19 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespaced { */ 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. * @@ -235,7 +245,7 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespaced { */ public I getRaw(String name) { - I ret = superType.cast(super.getObject(name)); + I ret = cast(super.getObject(name)); if (ret == null) // no match, try aliases recursively { @@ -461,7 +471,7 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespaced { 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) { From 889c967a5bfa367f4c3f99c37148c0618f915b0b Mon Sep 17 00:00:00 2001 From: cpw Date: Fri, 20 Mar 2015 14:19:54 -0400 Subject: [PATCH 2/9] Something I meant to add a long time ago, but it got overlooked. My apologies. Presend the (int) dimension ID in the serverhello packet. This should be 100% backward compatible with existing servers but bumping a server to this version will allow clients with this version as well to now login in dimensions outside the byte range. Probably fixes a bunch of mods that add dimensions. --- .../network/NetHandlerPlayClient.java.patch | 42 +++++++++++++++++++ .../fml/common/network/NetworkRegistry.java | 4 +- .../handshake/FMLHandshakeClientState.java | 11 ++++- .../handshake/FMLHandshakeMessage.java | 21 ++++++++++ .../handshake/FMLHandshakeServerState.java | 4 +- .../network/handshake/NetworkDispatcher.java | 16 ++++++- 6 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 fml/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java.patch 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..ac402c1351 --- /dev/null +++ b/fml/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java.patch @@ -0,0 +1,42 @@ +--- ../src-base/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java ++++ ../src-work/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java +@@ -2,11 +2,14 @@ + + import com.google.common.base.Charsets; + import com.mojang.authlib.GameProfile; ++ ++import cpw.mods.fml.common.network.handshake.NetworkDispatcher; + import cpw.mods.fml.relauncher.Side; + import cpw.mods.fml.relauncher.SideOnly; + import io.netty.buffer.ByteBuf; + import io.netty.buffer.Unpooled; + import io.netty.util.concurrent.GenericFutureListener; ++ + import java.io.ByteArrayInputStream; + import java.io.DataInputStream; + import java.io.IOException; +@@ -17,6 +20,7 @@ + import java.util.Map; + import java.util.Random; + import java.util.Map.Entry; ++ + import net.minecraft.block.Block; + import net.minecraft.client.ClientBrandRetriever; + import net.minecraft.client.Minecraft; +@@ -195,6 +199,7 @@ + import net.minecraft.world.storage.ISaveHandler; + import net.minecraft.world.storage.MapData; + import net.minecraft.world.storage.MapStorage; ++ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + +@@ -232,7 +237,7 @@ + public void func_147282_a(S01PacketJoinGame p_147282_1_) + { + 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()), NetworkDispatcher.get(func_147298_b()).getOverrideDimension(p_147282_1_), p_147282_1_.func_149192_g(), this.field_147299_f.field_71424_I); + this.field_147300_g.field_72995_K = true; + 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/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java b/fml/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java index 2f8325e40a..b0ee85fa5a 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/NetworkRegistry.java @@ -63,7 +63,9 @@ public enum NetworkRegistry public static final AttributeKey MOD_CONTAINER = new AttributeKey("fml:modContainer"); public static final AttributeKey NET_HANDLER = new AttributeKey("fml:netHandler"); - 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/cpw/mods/fml/common/network/handshake/FMLHandshakeClientState.java b/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeClientState.java index 1f756f3301..7a64b7c592 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeClientState.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeClientState.java @@ -1,11 +1,13 @@ package cpw.mods.fml.common.network.handshake; import java.util.List; + import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.network.NetworkRegistry; +import cpw.mods.fml.common.network.handshake.FMLHandshakeMessage.ServerHello; import cpw.mods.fml.common.network.internal.FMLMessage; import cpw.mods.fml.common.network.internal.FMLNetworkHandler; import cpw.mods.fml.common.registry.GameData; @@ -49,7 +51,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/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java b/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java index d11933c44e..89c7f678d4 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java @@ -15,6 +15,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Maps; import com.google.common.collect.Sets; +import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.ModContainer; import cpw.mods.fml.common.network.ByteBufUtils; import cpw.mods.fml.common.network.NetworkRegistry; @@ -30,22 +31,42 @@ public abstract class FMLHandshakeMessage { } public static class ServerHello extends FMLHandshakeMessage { private byte serverProtocolVersion; + private int overrideDimension; + 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/cpw/mods/fml/common/network/handshake/FMLHandshakeServerState.java b/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeServerState.java index 766e334b33..8a61100767 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeServerState.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeServerState.java @@ -18,9 +18,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/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java b/fml/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java index 26ff077d19..9ea04faac7 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java @@ -79,6 +79,7 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple private final EmbeddedChannel handshakeChannel; private NetHandlerPlayServer serverHandler; private INetHandler netHandler; + private int overrideLoginDim; public NetworkDispatcher(NetworkManager manager) { @@ -133,7 +134,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 @@ -146,6 +147,9 @@ 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 + return player.dimension; } void clientListenForServerHandshake() @@ -480,4 +484,14 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple this.handshakeChannel.attr(FML_DISPATCHER).remove(); 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_.func_149194_f(); + } } From a8cbbfcd99e37fb1dce0b92197a6b1fa0b97d252 Mon Sep 17 00:00:00 2001 From: cpw Date: Fri, 20 Mar 2015 15:00:19 -0400 Subject: [PATCH 3/9] Clean up my patch. Terrible person I am.. --- .../network/NetHandlerPlayClient.java.patch | 27 ++----------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/fml/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java.patch b/fml/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java.patch index ac402c1351..9580eba5ea 100644 --- a/fml/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java.patch +++ b/fml/patches/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java.patch @@ -1,37 +1,14 @@ --- ../src-base/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java +++ ../src-work/minecraft/net/minecraft/client/network/NetHandlerPlayClient.java -@@ -2,11 +2,14 @@ +@@ -2,6 +2,7 @@ import com.google.common.base.Charsets; import com.mojang.authlib.GameProfile; -+ +import cpw.mods.fml.common.network.handshake.NetworkDispatcher; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; - import io.netty.buffer.Unpooled; - import io.netty.util.concurrent.GenericFutureListener; -+ - import java.io.ByteArrayInputStream; - import java.io.DataInputStream; - import java.io.IOException; -@@ -17,6 +20,7 @@ - import java.util.Map; - import java.util.Random; - import java.util.Map.Entry; -+ - import net.minecraft.block.Block; - import net.minecraft.client.ClientBrandRetriever; - import net.minecraft.client.Minecraft; -@@ -195,6 +199,7 @@ - import net.minecraft.world.storage.ISaveHandler; - import net.minecraft.world.storage.MapData; - import net.minecraft.world.storage.MapStorage; -+ - import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; - -@@ -232,7 +237,7 @@ +@@ -232,7 +233,7 @@ public void func_147282_a(S01PacketJoinGame p_147282_1_) { this.field_147299_f.field_71442_b = new PlayerControllerMP(this.field_147299_f, this); From 613c5edc7d7f7ca416978ed74a8e70498429a2bc Mon Sep 17 00:00:00 2001 From: cpw Date: Fri, 20 Mar 2015 15:11:12 -0400 Subject: [PATCH 4/9] Forgot that I need a noarg ctor. I'm so rusty. --- .../fml/common/network/handshake/FMLHandshakeMessage.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java b/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java index 89c7f678d4..7898eee234 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/handshake/FMLHandshakeMessage.java @@ -32,7 +32,12 @@ public abstract class FMLHandshakeMessage { public static class ServerHello extends FMLHandshakeMessage { private byte serverProtocolVersion; private int overrideDimension; - public ServerHello(int overrideDim) { + public ServerHello() + { + // noargs for the proto + } + public ServerHello(int overrideDim) + { this.overrideDimension = overrideDim; } From f4972b76119b6b59821dc5290c7f5f14f472f766 Mon Sep 17 00:00:00 2001 From: cpw Date: Fri, 20 Mar 2015 15:55:16 -0400 Subject: [PATCH 5/9] Need to load the dimension from disk - do it without filling out the player so that the normal player loading (including events) works properly --- .../ServerConfigurationManager.java.patch | 37 ++++++++++++---- .../world/storage/SaveHandler.java.patch | 42 ++++++++++++++++--- .../network/handshake/NetworkDispatcher.java | 15 ++++++- 3 files changed, 81 insertions(+), 13 deletions(-) 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 33ab4041f9..f0be5d4a94 100644 --- a/fml/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.java.patch +++ b/fml/patches/minecraft/net/minecraft/server/management/ServerConfigurationManager.java.patch @@ -9,7 +9,15 @@ import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import java.io.File; -@@ -98,7 +100,7 @@ +@@ -58,6 +60,7 @@ + import net.minecraft.world.WorldSettings; + import net.minecraft.world.demo.DemoWorldManager; + import net.minecraft.world.storage.IPlayerFileData; ++import net.minecraft.world.storage.SaveHandler; + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + +@@ -98,7 +101,7 @@ this.field_72405_c = 8; } @@ -18,7 +26,7 @@ { GameProfile gameprofile = p_72355_2_.func_146103_bH(); PlayerProfileCache playerprofilecache = this.field_72400_f.func_152358_ax(); -@@ -119,7 +121,7 @@ +@@ -119,7 +122,7 @@ WorldServer worldserver = this.field_72400_f.func_71218_a(p_72355_2_.field_71093_bK); ChunkCoordinates chunkcoordinates = worldserver.func_72861_E(); this.func_72381_a(p_72355_2_, (EntityPlayerMP)null, worldserver); @@ -27,7 +35,7 @@ nethandlerplayserver.func_147359_a(new S01PacketJoinGame(p_72355_2_.func_145782_y(), p_72355_2_.field_71134_c.func_73081_b(), worldserver.func_72912_H().func_76093_s(), worldserver.field_73011_w.field_76574_g, worldserver.field_73013_u, this.func_72352_l(), worldserver.func_72912_H().func_76067_t())); nethandlerplayserver.func_147359_a(new S3FPacketCustomPayload("MC|Brand", this.func_72365_p().getServerModName().getBytes(Charsets.UTF_8))); nethandlerplayserver.func_147359_a(new S05PacketSpawnPosition(chunkcoordinates.field_71574_a, chunkcoordinates.field_71572_b, chunkcoordinates.field_71573_c)); -@@ -161,6 +163,7 @@ +@@ -161,6 +164,7 @@ p_72355_2_.func_71116_b(); @@ -35,8 +43,23 @@ if (nbttagcompound != null && nbttagcompound.func_150297_b("Riding", 10)) { Entity entity = EntityList.func_75615_a(nbttagcompound.func_74775_l("Riding"), worldserver); -@@ -250,6 +253,8 @@ +@@ -248,8 +252,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 ((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; @@ -44,7 +67,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()); -@@ -281,6 +286,7 @@ +@@ -281,6 +300,7 @@ public void func_72367_e(EntityPlayerMP p_72367_1_) { @@ -52,7 +75,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(); -@@ -436,6 +442,7 @@ +@@ -436,6 +456,7 @@ this.field_72404_b.add(entityplayermp1); entityplayermp1.func_71116_b(); entityplayermp1.func_70606_j(entityplayermp1.func_110143_aJ()); @@ -60,7 +83,7 @@ return entityplayermp1; } -@@ -461,6 +468,7 @@ +@@ -461,6 +482,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 dddda84c75..48bf1c4650 100644 --- a/fml/patches/minecraft/net/minecraft/world/storage/SaveHandler.java.patch +++ b/fml/patches/minecraft/net/minecraft/world/storage/SaveHandler.java.patch @@ -1,6 +1,6 @@ --- ../src-base/minecraft/net/minecraft/world/storage/SaveHandler.java +++ ../src-work/minecraft/net/minecraft/world/storage/SaveHandler.java -@@ -6,6 +6,9 @@ +@@ -6,13 +6,18 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; @@ -8,9 +8,18 @@ +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.StartupQuery; import net.minecraft.entity.player.EntityPlayer; ++import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; -@@ -107,20 +110,29 @@ + import net.minecraft.server.MinecraftServer; + import net.minecraft.world.MinecraftException; + import net.minecraft.world.WorldProvider; + import net.minecraft.world.chunk.storage.IChunkLoader; ++ + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + +@@ -107,20 +112,29 @@ NBTTagCompound nbttagcompound; NBTTagCompound nbttagcompound1; @@ -41,7 +50,7 @@ file1 = new File(this.field_75770_b, "level.dat_old"); if (file1.exists()) -@@ -129,8 +141,14 @@ +@@ -129,8 +143,14 @@ { nbttagcompound = CompressedStreamTools.func_74796_a(new FileInputStream(file1)); nbttagcompound1 = nbttagcompound.func_74775_l("Data"); @@ -57,7 +66,7 @@ catch (Exception exception) { exception.printStackTrace(); -@@ -146,6 +164,8 @@ +@@ -146,6 +166,8 @@ NBTTagCompound nbttagcompound2 = new NBTTagCompound(); nbttagcompound2.func_74782_a("Data", nbttagcompound1); @@ -66,7 +75,7 @@ try { File file1 = new File(this.field_75770_b, "level.dat_new"); -@@ -184,6 +204,8 @@ +@@ -184,6 +206,8 @@ NBTTagCompound nbttagcompound1 = new NBTTagCompound(); nbttagcompound1.func_74782_a("Data", nbttagcompound); @@ -75,3 +84,26 @@ try { File file1 = new File(this.field_75770_b, "level.dat_new"); +@@ -296,4 +320,22 @@ + { + return this.field_75767_f; + } ++ ++ public NBTTagCompound getPlayerNBT(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/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java b/fml/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java index 9ea04faac7..628d318353 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/handshake/NetworkDispatcher.java @@ -10,14 +10,18 @@ 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.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.nbt.NBTTagCompound; import net.minecraft.network.EnumConnectionState; import net.minecraft.network.INetHandler; import net.minecraft.network.NetHandlerPlayServer; @@ -149,7 +153,16 @@ public class NetworkDispatcher extends SimpleChannelInboundHandler imple 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 - return player.dimension; + // 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() From 3df54d3d0f374ff057aafc94f75b067a3c72f5cc Mon Sep 17 00:00:00 2001 From: cpw Date: Sun, 22 Mar 2015 12:03:37 -0400 Subject: [PATCH 6/9] What a dumb oversight. One needs to copy the active substitution set to the active gamedata. Doesn't work well otherwise. Closes #616 --- .../fml/common/registry/FMLControlledNamespacedRegistry.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fml/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java b/fml/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java index 7f013bd0ab..8d2a1112eb 100644 --- a/fml/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java +++ b/fml/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java @@ -95,6 +95,8 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespaced { this.minId = registry.minId; this.aliases.clear(); this.aliases.putAll(registry.aliases); + this.activeSubstitutions.clear(); + underlyingIntegerMap = new ObjectIntIdentityMap(); registryObjects.clear(); @@ -102,6 +104,7 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespaced { { addObjectRaw(registry.getId(thing), registry.getNameForObject(thing), thing); } + this.activeSubstitutions.putAll(registry.activeSubstitutions); } // public api From 2451e49df2cbbe0f9790c7b59c805427a7085b42 Mon Sep 17 00:00:00 2001 From: cpw Date: Sun, 22 Mar 2015 12:54:05 -0400 Subject: [PATCH 7/9] Substitutions need to be activated when they're registered, otherwise they won't appear in world, ever. --- fml/src/main/java/cpw/mods/fml/common/registry/GameData.java | 1 + 1 file changed, 1 insertion(+) diff --git a/fml/src/main/java/cpw/mods/fml/common/registry/GameData.java b/fml/src/main/java/cpw/mods/fml/common/registry/GameData.java index 816ab0e490..b4c59f189f 100644 --- a/fml/src/main/java/cpw/mods/fml/common/registry/GameData.java +++ b/fml/src/main/java/cpw/mods/fml/common/registry/GameData.java @@ -1000,6 +1000,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) { From c2f11ecc35f9cc1dfea292c5ce9193e7a39599a4 Mon Sep 17 00:00:00 2001 From: cpw Date: Sun, 22 Mar 2015 12:54:34 -0400 Subject: [PATCH 8/9] Change iterator behaviour for the registry - include substitutions in the standard iterator, so that vanilla MC methods visit them (so they can get textures etc). The fml special one only visits the absolute set, used mostly for sanity checking and serialization. Closes #618 --- .../functions/GenericIterableFactory.java | 15 ++++++++++++++ .../FMLControlledNamespacedRegistry.java | 20 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/fml/src/main/java/cpw/mods/fml/common/functions/GenericIterableFactory.java b/fml/src/main/java/cpw/mods/fml/common/functions/GenericIterableFactory.java index 85be09b2eb..f956d2d3df 100644 --- a/fml/src/main/java/cpw/mods/fml/common/functions/GenericIterableFactory.java +++ b/fml/src/main/java/cpw/mods/fml/common/functions/GenericIterableFactory.java @@ -1,8 +1,23 @@ package cpw.mods.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/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java b/fml/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java index 8d2a1112eb..e94753f474 100644 --- a/fml/src/main/java/cpw/mods/fml/common/registry/FMLControlledNamespacedRegistry.java +++ b/fml/src/main/java/cpw/mods/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; @@ -16,6 +17,7 @@ import net.minecraft.util.RegistryNamespaced; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterators; import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.functions.GenericIterableFactory; @@ -311,10 +313,13 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespaced { 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 @@ -507,4 +512,15 @@ public class FMLControlledNamespacedRegistry extends RegistryNamespaced { } return persistentSubstitutions; } + + /* + * This iterator is used by some regular MC methods to visit all blocks, we need to include substitutions + * Compare #typeSafeIterable() + */ + @SuppressWarnings("unchecked") + @Override + public Iterator iterator() + { + return Iterators.concat(super.iterator(),getPersistentSubstitutions().values().iterator()); + } } From ddcc6a1aa49e0c2691f1d8785687946326f066e0 Mon Sep 17 00:00:00 2001 From: Lex Manos Date: Fri, 27 Mar 2015 01:40:23 -0700 Subject: [PATCH 9/9] Enhance output of common FML errors in crash reports and server GUI. --- ...CustomModLoadingErrorDisplayException.java | 9 +- .../common/DuplicateModsFoundException.java | 13 +++ .../fml/common/EnhancedRuntimeException.java | 92 +++++++++++++++++++ .../cpw/mods/fml/common/ILanguageAdapter.java | 4 +- .../main/java/cpw/mods/fml/common/Loader.java | 6 +- .../cpw/mods/fml/common/LoaderException.java | 10 +- .../mods/fml/common/MissingModsException.java | 13 ++- .../cpw/mods/fml/common/ProxyInjector.java | 6 +- .../network/internal/EntitySpawnHandler.java | 7 +- .../IncompatibleSubstitutionException.java | 1 + 10 files changed, 146 insertions(+), 15 deletions(-) create mode 100644 fml/src/main/java/cpw/mods/fml/common/EnhancedRuntimeException.java diff --git a/fml/src/main/java/cpw/mods/fml/client/CustomModLoadingErrorDisplayException.java b/fml/src/main/java/cpw/mods/fml/client/CustomModLoadingErrorDisplayException.java index ffba8e51a8..63f3b40929 100644 --- a/fml/src/main/java/cpw/mods/fml/client/CustomModLoadingErrorDisplayException.java +++ b/fml/src/main/java/cpw/mods/fml/client/CustomModLoadingErrorDisplayException.java @@ -14,6 +14,7 @@ package cpw.mods.fml.client; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiErrorScreen; +import cpw.mods.fml.common.EnhancedRuntimeException; import cpw.mods.fml.common.IFMLHandledException; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; @@ -29,16 +30,16 @@ import cpw.mods.fml.relauncher.SideOnly; * */ @SideOnly(Side.CLIENT) -public abstract class CustomModLoadingErrorDisplayException extends RuntimeException implements IFMLHandledException +public abstract class CustomModLoadingErrorDisplayException extends EnhancedRuntimeException implements IFMLHandledException { public CustomModLoadingErrorDisplayException() { } - + public CustomModLoadingErrorDisplayException(String message, Throwable cause) { super(message, cause); } - + private static final long serialVersionUID = 1L; /** @@ -62,4 +63,6 @@ public abstract class CustomModLoadingErrorDisplayException extends RuntimeExcep * @param tickTime tick time */ public abstract void drawScreen(GuiErrorScreen errorScreen, FontRenderer fontRenderer, int mouseRelX, int mouseRelY, float tickTime); + + @Override public void printStackTrace(EnhancedRuntimeException.WrappedPrintStream s){}; // Do Nothing unless the modder wants to. } diff --git a/fml/src/main/java/cpw/mods/fml/common/DuplicateModsFoundException.java b/fml/src/main/java/cpw/mods/fml/common/DuplicateModsFoundException.java index f067605ff8..25afefa761 100644 --- a/fml/src/main/java/cpw/mods/fml/common/DuplicateModsFoundException.java +++ b/fml/src/main/java/cpw/mods/fml/common/DuplicateModsFoundException.java @@ -13,6 +13,9 @@ package cpw.mods.fml.common; import java.io.File; +import java.util.Map.Entry; + +import cpw.mods.fml.common.EnhancedRuntimeException.WrappedPrintStream; import com.google.common.collect.SetMultimap; @@ -24,4 +27,14 @@ public class DuplicateModsFoundException extends LoaderException { this.dupes = dupes; } + @Override + protected void printStackTrace(WrappedPrintStream stream) + { + stream.println("Duplicate Mods:"); + for (Entry e : dupes.entries()) + { + stream.println(String.format("\t%s : %s", e.getKey().getModId(), e.getValue().getAbsolutePath())); + } + stream.println(""); + } } diff --git a/fml/src/main/java/cpw/mods/fml/common/EnhancedRuntimeException.java b/fml/src/main/java/cpw/mods/fml/common/EnhancedRuntimeException.java new file mode 100644 index 0000000000..d039e0e8bf --- /dev/null +++ b/fml/src/main/java/cpw/mods/fml/common/EnhancedRuntimeException.java @@ -0,0 +1,92 @@ +/* + * Forge Mod Loader + * Copyright (c) 2012-2016 Forge Dev LLC. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser Public License v2.1 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + */ +package cpw.mods.fml.common; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * RuntimeException that gives subclasses the simple opportunity to write extra data when printing the stack trace. + * Mainly a helper class as printsStackTrace has multiple signatures. + */ +public abstract class EnhancedRuntimeException extends RuntimeException +{ + private static final long serialVersionUID = 1L; + + public EnhancedRuntimeException() { super(); } + public EnhancedRuntimeException(String message) { super(message); } + public EnhancedRuntimeException(String message, Throwable cause) { super(message, cause); } + public EnhancedRuntimeException(Throwable cause) { super(cause); } + protected EnhancedRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + @Override + public String getMessage() + { + StackTraceElement[] stack = Thread.currentThread().getStackTrace(); + if (stack.length > 2 && stack[2].getClassName().startsWith("org.apache.logging.log4j.")) + { + // This is a bit of a hack to force ourselves to be able to give a extended description when log4j prints this out. + // Sadly this text is displayed AFTER the initial exception line, and before the stack trace. But as the intention + // is to print this to the end user this is what we need to do. + final StringWriter buf = new StringWriter(); + + String msg = super.getMessage(); + if (msg != null) + buf.append(msg); + + buf.append('\n'); + this.printStackTrace(new WrappedPrintStream() + { + @Override + void println(String line) + { + buf.append(line).append('\n'); + } + }); + return buf.toString(); + } + return super.getMessage(); + } + + @Override + public void printStackTrace(final PrintWriter s) + { + printStackTrace(new WrappedPrintStream() + { + @Override + void println(String line) + { + s.println(line); + } + }); + super.printStackTrace(s); + } + public void printStackTrace(final PrintStream s) + { + printStackTrace(new WrappedPrintStream() + { + @Override + void println(String line) + { + s.println(line); + } + }); + super.printStackTrace(s); + } + + protected abstract void printStackTrace(WrappedPrintStream stream); + + public static abstract class WrappedPrintStream + { + abstract void println(String line); + } +} diff --git a/fml/src/main/java/cpw/mods/fml/common/ILanguageAdapter.java b/fml/src/main/java/cpw/mods/fml/common/ILanguageAdapter.java index 11921ad6f4..f40d49a337 100644 --- a/fml/src/main/java/cpw/mods/fml/common/ILanguageAdapter.java +++ b/fml/src/main/java/cpw/mods/fml/common/ILanguageAdapter.java @@ -96,7 +96,7 @@ public interface ILanguageAdapter { // If we come here we could not find a setter for this proxy. FMLLog.severe("Failed loading proxy into %s.%s, could not find setter function. Did you declare the field with 'val' instead of 'var'?", proxyTarget.getSimpleName(), target.getName()); - throw new LoaderException(); + throw new LoaderException(String.format("Failed loading proxy into %s.%s, could not find setter function. Did you declare the field with 'val' instead of 'var'?", proxyTarget.getSimpleName(), target.getName())); } @Override @@ -141,7 +141,7 @@ public interface ILanguageAdapter { if (!target.getType().isAssignableFrom(proxy.getClass())) { FMLLog.severe("Attempted to load a proxy type %s into %s.%s, but the types don't match", targetType, proxyTarget.getSimpleName(), target.getName()); - throw new LoaderException(); + throw new LoaderException(String.format("Attempted to load a proxy type %s into %s.%s, but the types don't match", targetType, proxyTarget.getSimpleName(), target.getName())); } setProxy(target, proxyTarget, proxy); diff --git a/fml/src/main/java/cpw/mods/fml/common/Loader.java b/fml/src/main/java/cpw/mods/fml/common/Loader.java index 86c48abb79..6469c47646 100644 --- a/fml/src/main/java/cpw/mods/fml/common/Loader.java +++ b/fml/src/main/java/cpw/mods/fml/common/Loader.java @@ -182,7 +182,7 @@ public class Loader if (!mccversion.equals(MC_VERSION)) { FMLLog.severe("This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file", mccversion, MC_VERSION); - throw new LoaderException(); + throw new LoaderException(String.format("This version of FML is built for Minecraft %s, we have detected Minecraft %s in your minecraft jar file", mccversion, MC_VERSION)); } minecraft = new MinecraftDummyContainer(MC_VERSION); @@ -418,7 +418,7 @@ public class Loader if (!dirMade) { FMLLog.severe("Unable to create the mod directory %s", canonicalModsPath); - throw new LoaderException(); + throw new LoaderException(String.format("Unable to create the mod directory %s", canonicalModsPath)); } FMLLog.info("Mod directory created successfully"); } @@ -676,7 +676,7 @@ public class Loader if (parseFailure) { FMLLog.log(Level.WARN, "Unable to parse dependency string %s", dependencyString); - throw new LoaderException(); + throw new LoaderException(String.format("Unable to parse dependency string %s", dependencyString)); } } diff --git a/fml/src/main/java/cpw/mods/fml/common/LoaderException.java b/fml/src/main/java/cpw/mods/fml/common/LoaderException.java index 3a0adbf726..2d236d5a43 100644 --- a/fml/src/main/java/cpw/mods/fml/common/LoaderException.java +++ b/fml/src/main/java/cpw/mods/fml/common/LoaderException.java @@ -5,14 +5,14 @@ * are made available under the terms of the GNU Lesser Public License v2.1 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * + * * Contributors: * cpw - implementation */ package cpw.mods.fml.common; -public class LoaderException extends RuntimeException +public class LoaderException extends EnhancedRuntimeException { /** * @@ -27,4 +27,10 @@ public class LoaderException extends RuntimeException public LoaderException() { } + public LoaderException(String message) + { + super(message); + } + + @Override protected void printStackTrace(WrappedPrintStream stream){} } diff --git a/fml/src/main/java/cpw/mods/fml/common/MissingModsException.java b/fml/src/main/java/cpw/mods/fml/common/MissingModsException.java index a2b50256b2..87e4f5febe 100644 --- a/fml/src/main/java/cpw/mods/fml/common/MissingModsException.java +++ b/fml/src/main/java/cpw/mods/fml/common/MissingModsException.java @@ -16,7 +16,7 @@ import java.util.Set; import cpw.mods.fml.common.versioning.ArtifactVersion; -public class MissingModsException extends RuntimeException +public class MissingModsException extends EnhancedRuntimeException { private static final long serialVersionUID = 1L; public final Set missingMods; @@ -25,4 +25,15 @@ public class MissingModsException extends RuntimeException { this.missingMods = missingMods; } + + @Override + protected void printStackTrace(WrappedPrintStream stream) + { + stream.println("Missing Mods:"); + for (ArtifactVersion v : missingMods) + { + stream.println(String.format("\t%s : %s", v.getLabel(), v.getRangeString())); + } + stream.println(""); + } } diff --git a/fml/src/main/java/cpw/mods/fml/common/ProxyInjector.java b/fml/src/main/java/cpw/mods/fml/common/ProxyInjector.java index 473900739a..10d94335f5 100644 --- a/fml/src/main/java/cpw/mods/fml/common/ProxyInjector.java +++ b/fml/src/main/java/cpw/mods/fml/common/ProxyInjector.java @@ -45,7 +45,7 @@ public class ProxyInjector { // Impossible? FMLLog.severe("Attempted to load a proxy type into %s.%s but the field was not found", targ.getClassName(), targ.getObjectName()); - throw new LoaderException(); + throw new LoaderException(String.format("Attempted to load a proxy type into %s.%s but the field was not found", targ.getClassName(), targ.getObjectName())); } target.setAccessible(true); @@ -61,12 +61,12 @@ public class ProxyInjector if (languageAdapter.supportsStatics() && (target.getModifiers() & Modifier.STATIC) == 0 ) { FMLLog.severe("Attempted to load a proxy type %s into %s.%s, but the field is not static", targetType, targ.getClassName(), targ.getObjectName()); - throw new LoaderException(); + throw new LoaderException(String.format("Attempted to load a proxy type %s into %s.%s, but the field is not static", targetType, targ.getClassName(), targ.getObjectName())); } if (!target.getType().isAssignableFrom(proxy.getClass())) { FMLLog.severe("Attempted to load a proxy type %s into %s.%s, but the types don't match", targetType, targ.getClassName(), targ.getObjectName()); - throw new LoaderException(); + throw new LoaderException(String.format("Attempted to load a proxy type %s into %s.%s, but the types don't match", targetType, targ.getClassName(), targ.getObjectName())); } languageAdapter.setProxy(target, proxyTarget, proxy); } diff --git a/fml/src/main/java/cpw/mods/fml/common/network/internal/EntitySpawnHandler.java b/fml/src/main/java/cpw/mods/fml/common/network/internal/EntitySpawnHandler.java index 450d1cf2a4..65acc95439 100644 --- a/fml/src/main/java/cpw/mods/fml/common/network/internal/EntitySpawnHandler.java +++ b/fml/src/main/java/cpw/mods/fml/common/network/internal/EntitySpawnHandler.java @@ -59,6 +59,11 @@ public class EntitySpawnHandler extends SimpleChannelInboundHandler cls = er.getEntityClass(); try @@ -117,7 +122,7 @@ public class EntitySpawnHandler extends SimpleChannelInboundHandler