From 58494f88788b9a298ffe3b5112875c873ebc2150 Mon Sep 17 00:00:00 2001 From: LexManos Date: Wed, 27 Feb 2019 23:56:31 -0800 Subject: [PATCH] Rewrite the FML Handshake packet formats to include actually syncing the registry data and introduce the concept of caching it locally. Snapshots are not injected yet due top threading issues. --- .../client/CPacketHandshake.java.patch | 4 +- .../minecraft/world/biome/Biome.java.patch | 2 +- .../common/util/DummyWorldSaveData.java | 19 ++ .../minecraftforge/common/util/HexDumper.java | 129 ++++++++++++ .../fml/network/FMLHandshakeHandler.java | 37 ++-- .../fml/network/FMLHandshakeMessages.java | 195 +++++++++++++----- .../fml/network/FMLNetworkConstants.java | 2 +- .../fml/network/NetworkRegistry.java | 29 +-- .../registries/ForgeRegistry.java | 89 ++++++-- .../registries/RegistryManager.java | 20 +- .../resources/META-INF/accesstransformer.cfg | 10 - 11 files changed, 413 insertions(+), 123 deletions(-) create mode 100644 src/main/java/net/minecraftforge/common/util/HexDumper.java diff --git a/patches/minecraft/net/minecraft/network/handshake/client/CPacketHandshake.java.patch b/patches/minecraft/net/minecraft/network/handshake/client/CPacketHandshake.java.patch index 5b268170a..918d8b616 100644 --- a/patches/minecraft/net/minecraft/network/handshake/client/CPacketHandshake.java.patch +++ b/patches/minecraft/net/minecraft/network/handshake/client/CPacketHandshake.java.patch @@ -4,7 +4,7 @@ private String field_149598_b; private int field_149599_c; private EnumConnectionState field_149597_d; -+ private String fmlVersion = net.minecraftforge.fml.network.NetworkHooks.NETVERSION; ++ private String fmlVersion = net.minecraftforge.fml.network.FMLNetworkConstants.NETVERSION; public CPacketHandshake() { } @@ -19,7 +19,7 @@ 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 + "\0"+net.minecraftforge.fml.network.NetworkHooks.NETVERSION+"\0"); ++ p_148840_1_.func_180714_a(this.field_149598_b + "\0"+net.minecraftforge.fml.network.FMLNetworkConstants.NETVERSION+"\0"); p_148840_1_.writeShort(this.field_149599_c); p_148840_1_.func_150787_b(this.field_149597_d.func_150759_c()); } diff --git a/patches/minecraft/net/minecraft/world/biome/Biome.java.patch b/patches/minecraft/net/minecraft/world/biome/Biome.java.patch index 97c36a7b2..5ce3aa3e1 100644 --- a/patches/minecraft/net/minecraft/world/biome/Biome.java.patch +++ b/patches/minecraft/net/minecraft/world/biome/Biome.java.patch @@ -12,7 +12,7 @@ @@ -322,11 +322,11 @@ } - public void func_201866_a(EnumCreatureType p_201866_1_, Biome.SpawnListEntry p_201866_2_) { + protected void func_201866_a(EnumCreatureType p_201866_1_, Biome.SpawnListEntry p_201866_2_) { - this.field_201880_ax.get(p_201866_1_).add(p_201866_2_); + this.field_201880_ax.computeIfAbsent(p_201866_1_, k -> Lists.newArrayList()).add(p_201866_2_); } diff --git a/src/main/java/net/minecraftforge/common/util/DummyWorldSaveData.java b/src/main/java/net/minecraftforge/common/util/DummyWorldSaveData.java index 45bcff7fe..9d0777067 100644 --- a/src/main/java/net/minecraftforge/common/util/DummyWorldSaveData.java +++ b/src/main/java/net/minecraftforge/common/util/DummyWorldSaveData.java @@ -1,3 +1,22 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + package net.minecraftforge.common.util; import net.minecraft.nbt.NBTTagCompound; diff --git a/src/main/java/net/minecraftforge/common/util/HexDumper.java b/src/main/java/net/minecraftforge/common/util/HexDumper.java new file mode 100644 index 000000000..1aeaa1f3c --- /dev/null +++ b/src/main/java/net/minecraftforge/common/util/HexDumper.java @@ -0,0 +1,129 @@ +/* + * Minecraft Forge + * Copyright (c) 2016-2019. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package net.minecraftforge.common.util; + +import io.netty.buffer.ByteBuf; + +/** + * Utility class for creating a nice human readable dump of binary data. + * + * It might look something like this:
+ *
+ *      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F    ................
+ *      69 68 67 66 65 64 63 62 61 61 6A 6B 6C 6D 6E 00    ihgfedcbaajklmn.
+ *      41 00                                              A.
+ *      Length: 34
+ *
+ */ +public class HexDumper +{ + + public static String dump(ByteBuf data) + { + int current = data.readerIndex(); + data.readerIndex(0); + Instance inst = new Instance(current, data.readableBytes()); + data.forEachByte(b -> { + inst.add(b); + return true; + }); + data.readerIndex(current); + return inst.finish(); + } + + public static String dump(byte[] data) + { + return dump(data, -1); + } + + public static String dump(byte[] data, int marker) + { + Instance inst = new Instance(marker, data.length); + for (int x = 0; x < data.length; x++) + inst.add(data[x]); + return inst.finish(); + } + + private static class Instance + { + private static final String HEX = "0123456789ABCDEF"; + private final int marked; + private final StringBuilder buf; + private char[] ascii = new char[16]; + private int index = 0; + + private Instance(int marked, int size) + { + this.marked = marked; + int lines = ((size + 15) / 16); + this.buf = new StringBuilder((size * 3) //Hex + + size // ASCII + + (lines * 2) // \t and \n per line + + (marked == -1 ? 0 : lines)); // ' ' or < at the start of each line + + for (int x = 0; x < ascii.length; x++) + ascii[x] = ' '; + } + + public void add(byte data) + { + if (index == 0 && marked != -1) + buf.append(index == marked ? '<' : ' '); + + if (index != 0 && index % 16 == 0) + { + buf.append('\t'); + for (int x = 0; x < 16; x++) + { + buf.append(ascii[x]); + ascii[x] = ' '; + } + buf.append('\n'); + if (marked != -1) + buf.append(index == marked ? '<' : ' '); + } + ascii[index % 16] = data < ' ' || data > '~' ? '.' : (char)data; + buf.append(HEX.charAt((data & 0xF0) >> 4)); + buf.append(HEX.charAt((data & 0x0F) )); + if (index + 1 == marked) + buf.append(marked % 16 == 0 ? ' ' : '<'); + else + buf.append(marked == index ? '>' : ' '); + + index++; + } + + public String finish() + { + int padding = 16 - (index % 16); + if (padding > 0) + { + for (int x = 0; x < padding * 3; x++) + buf.append(' '); + buf.append('\t'); + buf.append(ascii); + } + buf.append('\n'); + buf.append("Length: ").append(index); + if (marked != -1) + buf.append(" Mark: ").append(marked); + return buf.toString(); + } + } +} diff --git a/src/main/java/net/minecraftforge/fml/network/FMLHandshakeHandler.java b/src/main/java/net/minecraftforge/fml/network/FMLHandshakeHandler.java index a5456fe7d..1e9a7fdc7 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLHandshakeHandler.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLHandshakeHandler.java @@ -35,6 +35,8 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Marker; import org.apache.logging.log4j.MarkerManager; +import com.google.common.collect.Maps; + import java.util.*; import java.util.function.BiConsumer; import java.util.function.Supplier; @@ -108,7 +110,7 @@ public class FMLHandshakeHandler { loginIndex(FMLHandshakeMessages.LoginIndexedMessage::getLoginIndex, FMLHandshakeMessages.LoginIndexedMessage::setLoginIndex). decoder(FMLHandshakeMessages.S2CRegistry::decode). encoder(FMLHandshakeMessages.S2CRegistry::encode). - buildLoginPacketList(RegistryManager::generateRegistryPackets). + buildLoginPacketList(RegistryManager::generateRegistryPackets). //TODO: Make this non-static, and store a cache on the client. consumer(biConsumerFor(FMLHandshakeHandler::handleRegistryMessage)). add(); channel.messageBuilder(FMLHandshakeMessages.S2CConfigData.class, 4). @@ -178,8 +180,9 @@ public class FMLHandshakeHandler { private final NetworkDirection direction; private final NetworkManager manager; private int packetPosition; - private ForgeRegistry.Snapshot registrySnapshot; - private Set registriesToReceive; + private Map registrySnapshots; + private Set registriesToReceive; + private Map registryHashes; private FMLHandshakeHandler(NetworkManager networkManager, NetworkDirection side) { @@ -196,7 +199,7 @@ public class FMLHandshakeHandler { private void handleServerModListOnClient(FMLHandshakeMessages.S2CModList serverModList, Supplier c) { - LOGGER.debug(FMLHSMARKER, "Logging into server with mod list [{}]", serverModList.getModList()); + LOGGER.debug(FMLHSMARKER, "Logging into server with mod list [{}]", String.join(", ", serverModList.getModList())); boolean accepted = NetworkRegistry.validateClientChannels(serverModList.getChannels()); c.get().setPacketHandled(true); if (!accepted) { @@ -204,12 +207,14 @@ public class FMLHandshakeHandler { c.get().getNetworkManager().closeChannel(new TextComponentString("Connection closed - mismatched mod channel list")); return; } - final FMLHandshakeMessages.C2SModListReply reply = new FMLHandshakeMessages.C2SModListReply(); - channel.reply(reply, c.get()); + channel.reply(new FMLHandshakeMessages.C2SModListReply(), c.get()); + LOGGER.debug(FMLHSMARKER, "Accepted server connection"); // Set the modded marker on the channel so we know we got packets c.get().getNetworkManager().channel().attr(FMLNetworkConstants.FML_MARKER).set(FMLNetworkConstants.NETVERSION); + this.registriesToReceive = new HashSet<>(serverModList.getRegistries()); + this.registrySnapshots = Maps.newHashMap(); LOGGER.debug(REGISTRIES, "Expecting {} registries: {}", ()->this.registriesToReceive.size(), ()->this.registriesToReceive); } @@ -224,7 +229,7 @@ public class FMLHandshakeHandler { private void handleClientModListOnServer(FMLHandshakeMessages.C2SModListReply clientModList, Supplier c) { - LOGGER.debug(FMLHSMARKER, "Received client connection with modlist [{}]", clientModList.getModList()); + LOGGER.debug(FMLHSMARKER, "Received client connection with modlist [{}]", String.join(", ", clientModList.getModList())); boolean accepted = NetworkRegistry.validateServerChannels(clientModList.getChannels()); c.get().setPacketHandled(true); if (!accepted) { @@ -234,13 +239,18 @@ public class FMLHandshakeHandler { } LOGGER.debug(FMLHSMARKER, "Accepted client connection mod list"); } - private void handleRegistryMessage(final FMLHandshakeMessages.S2CRegistry registryPacket, final Supplier contextSupplier) { + + private void handleRegistryMessage(final FMLHandshakeMessages.S2CRegistry registryPacket, final Supplier contextSupplier){ + LOGGER.debug(FMLHSMARKER,"Received registry packet for {}", registryPacket.getRegistryName()); this.registriesToReceive.remove(registryPacket.getRegistryName()); - RegistryManager.acceptRegistry(registryPacket, contextSupplier); + this.registrySnapshots.put(registryPacket.getRegistryName(), registryPacket.getSnapshot()); contextSupplier.get().setPacketHandled(true); - final FMLHandshakeMessages.C2SAcknowledge reply = new FMLHandshakeMessages.C2SAcknowledge(); - channel.reply(reply, contextSupplier.get()); - if (this.registriesToReceive.isEmpty()) {}//injectSnapshot + channel.reply(new FMLHandshakeMessages.C2SAcknowledge(), contextSupplier.get()); + + if (this.registriesToReceive.isEmpty()) { + //TODO: @cpw injectSnapshot Needs to be on the world thread. And maybe block the network/login so we don't get world data before we finish? + registrySnapshots = null; + } } private void handleClientAck(final FMLHandshakeMessages.C2SAcknowledge msg, final Supplier contextSupplier) { @@ -252,8 +262,7 @@ public class FMLHandshakeHandler { LOGGER.debug(FMLHSMARKER, "Received config sync from server"); ConfigTracker.INSTANCE.receiveSyncedConfig(msg, contextSupplier); contextSupplier.get().setPacketHandled(true); - final FMLHandshakeMessages.C2SAcknowledge reply = new FMLHandshakeMessages.C2SAcknowledge(); - channel.reply(reply, contextSupplier.get()); + channel.reply(new FMLHandshakeMessages.C2SAcknowledge(), contextSupplier.get()); } /** * FML will send packets, from Server to Client, from the messages queue until the queue is drained. Each message diff --git a/src/main/java/net/minecraftforge/fml/network/FMLHandshakeMessages.java b/src/main/java/net/minecraftforge/fml/network/FMLHandshakeMessages.java index 3a1a4b79a..de4cc93fc 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLHandshakeMessages.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLHandshakeMessages.java @@ -19,21 +19,24 @@ package net.minecraftforge.fml.network; -import net.minecraft.nbt.INBTBase; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; -import net.minecraft.nbt.NBTTagString; import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.util.HexDumper; import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.loading.moddiscovery.ModInfo; import net.minecraftforge.registries.ForgeRegistry; -import net.minecraftforge.registries.IForgeRegistryEntry; import net.minecraftforge.registries.RegistryManager; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; +import javax.annotation.Nullable; + +import com.google.common.collect.Maps; + public class FMLHandshakeMessages { static class LoginIndexedMessage { @@ -52,66 +55,140 @@ public class FMLHandshakeMessages */ public static class S2CModList extends LoginIndexedMessage { - private List registries; - private NBTTagList channels; - private List modList; + private List mods; + private Map channels; + private List registries; - public S2CModList() { - this.modList = ModList.get().getMods().stream().map(ModInfo::getModId).collect(Collectors.toList()); - } - - S2CModList(NBTTagCompound nbtTagCompound) + public S2CModList() { - this.modList = nbtTagCompound.getList("modlist", 8).stream().map(INBTBase::getString).collect(Collectors.toList()); - this.channels = nbtTagCompound.getList("channels", 10); - this.registries = nbtTagCompound.getList("registries", 8).stream().map(INBTBase::getString).collect(Collectors.toList()); + this.mods = ModList.get().getMods().stream().map(ModInfo::getModId).collect(Collectors.toList()); + this.channels = NetworkRegistry.buildChannelVersions(); + this.registries = RegistryManager.registryNames(); } - public static S2CModList decode(PacketBuffer packetBuffer) + private S2CModList(List mods, Map channels, List registries) { - final NBTTagCompound nbtTagCompound = packetBuffer.readCompoundTag(); - return new S2CModList(nbtTagCompound); + this.mods = mods; + this.channels = channels; + this.registries = registries; } - public void encode(PacketBuffer packetBuffer) + public static S2CModList decode(PacketBuffer input) { - NBTTagCompound tag = new NBTTagCompound(); - tag.setTag("modlist",modList.stream().map(NBTTagString::new).collect(Collectors.toCollection(NBTTagList::new))); - tag.setTag("channels", NetworkRegistry.buildChannelVersions()); - tag.setTag("registries", RegistryManager.registryNames().stream().map(NBTTagString::new).collect(Collectors.toCollection(NBTTagList::new))); - packetBuffer.writeCompoundTag(tag); + List mods = new ArrayList<>(); + int len = input.readVarInt(); + for (int x = 0; x < len; x++) + mods.add(input.readString(0x100)); + + Map channels = new HashMap<>(); + len = input.readVarInt(); + for (int x = 0; x < len; x++) + channels.put(input.readResourceLocation(), input.readString(0x100)); + + List registries = new ArrayList<>(); + len = input.readVarInt(); + for (int x = 0; x < len; x++) + registries.add(input.readResourceLocation()); + + return new S2CModList(mods, channels, registries); } - String getModList() { - return String.join(",", modList); + public void encode(PacketBuffer output) + { + output.writeVarInt(mods.size()); + mods.forEach(m -> output.writeString(m, 0x100)); + + output.writeVarInt(channels.size()); + channels.forEach((k, v) -> { + output.writeResourceLocation(k); + output.writeString(v, 0x100); + }); + + output.writeVarInt(registries.size()); + registries.forEach(output::writeResourceLocation); } - List getRegistries() { + public List getModList() { + return mods; + } + + public List getRegistries() { return this.registries; } - NBTTagList getChannels() { + + public Map getChannels() { return this.channels; } } - public static class C2SModListReply extends S2CModList + public static class C2SModListReply extends LoginIndexedMessage { - public C2SModListReply() { - super(); - } + private List mods; + private Map channels; + private Map registries; - C2SModListReply(final NBTTagCompound buffer) { - super(buffer); - } - - public static C2SModListReply decode(PacketBuffer buffer) + public C2SModListReply() { - return new C2SModListReply(buffer.readCompoundTag()); + this.mods = ModList.get().getMods().stream().map(ModInfo::getModId).collect(Collectors.toList()); + this.channels = NetworkRegistry.buildChannelVersions(); + this.registries = Maps.newHashMap(); //TODO: Fill with known hashes, which requires keeping a file cache } - public void encode(PacketBuffer buffer) + private C2SModListReply(List mods, Map channels, Map registries) { - super.encode(buffer); + this.mods = mods; + this.channels = channels; + this.registries = registries; + } + + public static C2SModListReply decode(PacketBuffer input) + { + List mods = new ArrayList<>(); + int len = input.readVarInt(); + for (int x = 0; x < len; x++) + mods.add(input.readString(0x100)); + + Map channels = new HashMap<>(); + len = input.readVarInt(); + for (int x = 0; x < len; x++) + channels.put(input.readResourceLocation(), input.readString(0x100)); + + Map registries = new HashMap<>(); + len = input.readVarInt(); + for (int x = 0; x < len; x++) + registries.put(input.readResourceLocation(), input.readString(0x100)); + + return new C2SModListReply(mods, channels, registries); + } + + public void encode(PacketBuffer output) + { + output.writeVarInt(mods.size()); + mods.forEach(m -> output.writeString(m, 0x100)); + + output.writeVarInt(channels.size()); + channels.forEach((k, v) -> { + output.writeResourceLocation(k); + output.writeString(v, 0x100); + }); + + output.writeVarInt(registries.size()); + registries.forEach((k, v) -> { + output.writeResourceLocation(k); + output.writeString(v, 0x100); + }); + } + + public List getModList() { + return mods; + } + + public Map getRegistries() { + return this.registries; + } + + public Map getChannels() { + return this.channels; } } @@ -126,27 +203,43 @@ public class FMLHandshakeMessages } public static class S2CRegistry extends LoginIndexedMessage { - private String registryName; + private ResourceLocation registryName; + @Nullable + private ForgeRegistry.Snapshot snapshot; - public S2CRegistry(final ResourceLocation key, final ForgeRegistry> registry) { - registryName = key.toString(); - } - - private S2CRegistry(final String registryName) { - this.registryName = registryName; + public S2CRegistry(final ResourceLocation name, @Nullable ForgeRegistry.Snapshot snapshot) { + this.registryName = name; + this.snapshot = snapshot; } void encode(final PacketBuffer buffer) { - buffer.writeString(registryName, 128); + buffer.writeResourceLocation(registryName); + buffer.writeBoolean(hasSnapshot()); + if (hasSnapshot()) + buffer.writeBytes(snapshot.getPacketData()); } public static S2CRegistry decode(final PacketBuffer buffer) { - return new S2CRegistry(buffer.readString(128)); +System.out.println("Readable: " + buffer.readableBytes()); + ResourceLocation name = buffer.readResourceLocation(); + ForgeRegistry.Snapshot snapshot = null; + if (buffer.readBoolean()) + snapshot = ForgeRegistry.Snapshot.read(buffer); + return new S2CRegistry(name, snapshot); } - public String getRegistryName() { + public ResourceLocation getRegistryName() { return registryName; } + + public boolean hasSnapshot() { + return snapshot != null; + } + + @Nullable + public ForgeRegistry.Snapshot getSnapshot() { + return snapshot; + } } diff --git a/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java b/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java index e1ccc1c26..9c02758d2 100644 --- a/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java +++ b/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java @@ -29,7 +29,7 @@ import org.apache.logging.log4j.MarkerManager; public class FMLNetworkConstants { public static final String FMLNETMARKER = "FML"; - public static final int FMLNETVERSION = 1; + public static final int FMLNETVERSION = 2; public static final String NETVERSION = FMLNETMARKER + FMLNETVERSION; public static final String NOVERSION = "NONE"; static final Marker NETWORK = MarkerManager.getMarker("FMLNETWORK"); diff --git a/src/main/java/net/minecraftforge/fml/network/NetworkRegistry.java b/src/main/java/net/minecraftforge/fml/network/NetworkRegistry.java index 1ec269920..bec35da36 100644 --- a/src/main/java/net/minecraftforge/fml/network/NetworkRegistry.java +++ b/src/main/java/net/minecraftforge/fml/network/NetworkRegistry.java @@ -137,20 +137,13 @@ public class NetworkRegistry } /** - * Construct the NBT representation of the channel list, for use during login handshaking + * Construct the Map representation of the channel list, for use during login handshaking * * @see FMLHandshakeMessages.S2CModList * @see FMLHandshakeMessages.C2SModListReply - * - * @return An nbt tag list */ - static NBTTagList buildChannelVersions() { - return instances.entrySet().stream().map(e-> { - final NBTTagCompound tag = new NBTTagCompound(); - tag.setString("name", e.getKey().toString()); - tag.setString("version", e.getValue().getNetworkProtocolVersion()); - return tag; - }).collect(Collectors.toCollection(NBTTagList::new)); + static Map buildChannelVersions() { + return instances.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getNetworkProtocolVersion())); } static List listRejectedVanillaMods(BiFunction testFunction) { @@ -174,34 +167,32 @@ public class NetworkRegistry * Validate the channels from the server on the client. Tests the client predicates against the server * supplied network protocol version. * - * @param channels An @{@link NBTTagList} of name->version pairs for testing + * @param channels An @{@link Map} of name->version pairs for testing * @return true if all channels accept themselves */ - static boolean validateClientChannels(final NBTTagList channels) { + static boolean validateClientChannels(final Map channels) { return validateChannels(channels, "server", NetworkInstance::tryServerVersionOnClient); } /** * Validate the channels from the client on the server. Tests the server predicates against the client * supplied network protocol version. - * @param channels An @{@link NBTTagList} of name->version pairs for testing + * @param channels An @{@link Map} of name->version pairs for testing * @return true if all channels accept themselves */ - static boolean validateServerChannels(final NBTTagList channels) { + static boolean validateServerChannels(final Map channels) { return validateChannels(channels, "client", NetworkInstance::tryClientVersionOnServer); } /** - * Tests if the nbt list matches with the supplied predicate tester + * Tests if the map matches with the supplied predicate tester * - * @param channels An @{@link NBTTagList} of name->version pairs for testing + * @param channels An @{@link Map} of name->version pairs for testing * @param originName A label for use in logging (where the version pairs came from) * @param testFunction The test function to use for testing * @return true if all channels accept themselves */ - private static boolean validateChannels(final NBTTagList channels, final String originName, BiFunction testFunction) { - Map incoming = channels.stream().map(NBTTagCompound.class::cast).collect(Collectors.toMap(tag->new ResourceLocation(tag.getString("name")),tag->tag.getString("version"))); - + private static boolean validateChannels(final Map incoming, final String originName, BiFunction testFunction) { final List> results = instances.values().stream(). map(ni -> { final String incomingVersion = incoming.getOrDefault(ni.getChannelName(), ABSENT); diff --git a/src/main/java/net/minecraftforge/registries/ForgeRegistry.java b/src/main/java/net/minecraftforge/registries/ForgeRegistry.java index c78fab53f..5842be22f 100644 --- a/src/main/java/net/minecraftforge/registries/ForgeRegistry.java +++ b/src/main/java/net/minecraftforge/registries/ForgeRegistry.java @@ -46,9 +46,11 @@ import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; +import io.netty.buffer.Unpooled; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; +import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.event.RegistryEvent.MissingMappings; @@ -793,18 +795,19 @@ public class ForgeRegistry> implements IForgeRe public static class Snapshot { - public final Map ids = Maps.newHashMap(); - public final Map aliases = Maps.newHashMap(); - public final Set blocked = Sets.newHashSet(); - public final Set dummied = Sets.newHashSet(); - public final Map overrides = Maps.newHashMap(); + public final Map ids = Maps.newTreeMap(); + public final Map aliases = Maps.newTreeMap(); + public final Set blocked = Sets.newTreeSet(); + public final Set dummied = Sets.newTreeSet(); + public final Map overrides = Maps.newTreeMap(); + private PacketBuffer binary = null; public NBTTagCompound write() { NBTTagCompound data = new NBTTagCompound(); NBTTagList ids = new NBTTagList(); - this.ids.entrySet().stream().sorted((o1, o2) -> o1.getKey().compareTo(o2.getKey())).forEach(e -> + this.ids.entrySet().stream().forEach(e -> { NBTTagCompound tag = new NBTTagCompound(); tag.setString("K", e.getKey().toString()); @@ -814,7 +817,7 @@ public class ForgeRegistry> implements IForgeRe data.setTag("ids", ids); NBTTagList aliases = new NBTTagList(); - this.aliases.entrySet().stream().sorted((o1, o2) -> o1.getKey().compareTo(o2.getKey())).forEach(e -> + this.aliases.entrySet().stream().forEach(e -> { NBTTagCompound tag = new NBTTagCompound(); tag.setString("K", e.getKey().toString()); @@ -824,7 +827,7 @@ public class ForgeRegistry> implements IForgeRe data.setTag("aliases", aliases); NBTTagList overrides = new NBTTagList(); - this.overrides.entrySet().stream().sorted((o1, o2) -> o1.getKey().compareTo(o2.getKey())).forEach(e -> + this.overrides.entrySet().stream().forEach(e -> { NBTTagCompound tag = new NBTTagCompound(); tag.setString("K", e.getKey().toString()); @@ -878,14 +881,76 @@ public class ForgeRegistry> implements IForgeRe ret.blocked.add(i); } - list = nbt.getList("dummied", 10); //10 - NBTTagCompound, Old format. New format is String list. For now we will just merge the old and new. TODO: Remove in 1.13 - list.forEach(e -> ret.dummied.add(new ResourceLocation(((NBTTagCompound)e).getString("K")))); - - list = nbt.getList("dummied", 8); //8 - NBTTagString, New format, less redundant/verbose + list = nbt.getList("dummied", 8); list.forEach(e -> ret.dummied.add(new ResourceLocation(((NBTTagString)e).getString()))); return ret; } + + public synchronized PacketBuffer getPacketData() + { + if (binary == null) { + PacketBuffer pkt = new PacketBuffer(Unpooled.buffer()); + + pkt.writeVarInt(this.ids.size()); + this.ids.forEach((k,v) -> { + pkt.writeResourceLocation(k); + pkt.writeVarInt(v); + }); + + pkt.writeVarInt(this.aliases.size()); + this.aliases.forEach((k, v) -> { + pkt.writeResourceLocation(k); + pkt.writeResourceLocation(v); + }); + + pkt.writeVarInt(this.overrides.size()); + this.overrides.forEach((k, v) -> { + pkt.writeResourceLocation(k); + pkt.writeString(v, 0x100); + }); + + pkt.writeVarInt(this.blocked.size()); + this.blocked.forEach(pkt::writeVarInt); + + pkt.writeVarInt(this.dummied.size()); + this.dummied.forEach(pkt::writeResourceLocation); + + this.binary = pkt; + } + + return new PacketBuffer(binary.slice()); + } + + public static Snapshot read(PacketBuffer buff) + { + if (buff == null) + return new Snapshot(); + + Snapshot ret = new Snapshot(); + + int len = buff.readVarInt(); + for (int x = 0; x < len; x++) + ret.ids.put(buff.readResourceLocation(), buff.readVarInt()); + + len = buff.readVarInt(); + for (int x = 0; x < len; x++) + ret.aliases.put(buff.readResourceLocation(), buff.readResourceLocation()); + + len = buff.readVarInt(); + for (int x = 0; x < len; x++) + ret.overrides.put(buff.readResourceLocation(), buff.readString(0x100)); + + len = buff.readVarInt(); + for (int x = 0; x < len; x++) + ret.blocked.add(buff.readVarInt()); + + len = buff.readVarInt(); + for (int x = 0; x < len; x++) + ret.dummied.add(buff.readResourceLocation()); + + return ret; + } } public MissingMappings getMissingEvent(ResourceLocation name, Map map) diff --git a/src/main/java/net/minecraftforge/registries/RegistryManager.java b/src/main/java/net/minecraftforge/registries/RegistryManager.java index f1e336dbf..cab6b6706 100644 --- a/src/main/java/net/minecraftforge/registries/RegistryManager.java +++ b/src/main/java/net/minecraftforge/registries/RegistryManager.java @@ -22,7 +22,6 @@ package net.minecraftforge.registries; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Supplier; import java.util.stream.Collectors; import com.google.common.collect.BiMap; @@ -33,14 +32,11 @@ import com.google.common.collect.Sets.SetView; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.network.FMLHandshakeMessages; -import net.minecraftforge.fml.network.NetworkEvent; import net.minecraftforge.registries.ForgeRegistry.Snapshot; import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import static net.minecraftforge.registries.ForgeRegistry.REGISTRIES; - public class RegistryManager { private static final Logger LOGGER = LogManager.getLogger(); @@ -150,17 +146,15 @@ public class RegistryManager this.superTypes.clear(); } - public static List> generateRegistryPackets() { - return ACTIVE.registries.entrySet().stream(). - map(e->Pair.of("Registry "+e.getKey(), new FMLHandshakeMessages.S2CRegistry(e.getKey(), e.getValue()))). + public static List> generateRegistryPackets() + { + return ACTIVE.takeSnapshot(false).entrySet().stream(). + map(e->Pair.of("Registry " + e.getKey(), new FMLHandshakeMessages.S2CRegistry(e.getKey(), e.getValue()))). collect(Collectors.toList()); } - public static List registryNames() { - return ACTIVE.registries.entrySet().stream().map(Map.Entry::getKey).map(Object::toString).collect(Collectors.toList()); - } - - public static void acceptRegistry(final FMLHandshakeMessages.S2CRegistry registryUpdate, final Supplier contextSupplier) { - LOGGER.debug(REGISTRIES,"Received registry packet for {}", registryUpdate.getRegistryName()); + public static List registryNames() + { + return ACTIVE.registries.entrySet().stream().map(Map.Entry::getKey).collect(Collectors.toList()); } } diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index d1f8b61a9..c6f077f77 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -30,16 +30,6 @@ public net.minecraft.world.chunk.storage.AnvilChunkLoader field_75825_d # chunkS public net.minecraft.world.gen.ChunkProviderServer field_73247_e # currentChunkLoader # World public-f net.minecraft.world.World field_72982_D #villageCollectionObj -# Biome -public net.minecraft.world.biome.Biome *() #Everything protected->public -public net.minecraft.world.biome.BiomeForest *() -public net.minecraft.world.biome.BiomeHills *() -public net.minecraft.world.biome.BiomeMesa *() -public net.minecraft.world.biome.BiomePlains *() -public net.minecraft.world.biome.BiomeSavanna *() -public net.minecraft.world.biome.BiomeSnow *() -public net.minecraft.world.biome.BiomeTaiga *() -public net.minecraft.world.biome.Biome$BiomeProperties *() # Map Gen Biome Lists public+f net.minecraft.world.gen.structure.MapGenStronghold field_151546_e # MapGenVillage