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.
This commit is contained in:
LexManos 2019-02-27 23:56:31 -08:00
parent cb70702ab5
commit 58494f8878
11 changed files with 413 additions and 123 deletions

View File

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

View File

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

View File

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

View File

@ -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:<BR>
*<PRE>
* 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
*</PRE>
*/
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();
}
}
}

View File

@ -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<String> registriesToReceive;
private Map<ResourceLocation, ForgeRegistry.Snapshot> registrySnapshots;
private Set<ResourceLocation> registriesToReceive;
private Map<ResourceLocation, String> registryHashes;
private FMLHandshakeHandler(NetworkManager networkManager, NetworkDirection side)
{
@ -196,7 +199,7 @@ public class FMLHandshakeHandler {
private void handleServerModListOnClient(FMLHandshakeMessages.S2CModList serverModList, Supplier<NetworkEvent.Context> 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<NetworkEvent.Context> 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<NetworkEvent.Context> contextSupplier) {
private void handleRegistryMessage(final FMLHandshakeMessages.S2CRegistry registryPacket, final Supplier<NetworkEvent.Context> 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<NetworkEvent.Context> 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

View File

@ -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<String> registries;
private NBTTagList channels;
private List<String> modList;
private List<String> mods;
private Map<ResourceLocation, String> channels;
private List<ResourceLocation> 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<String> mods, Map<ResourceLocation, String> channels, List<ResourceLocation> 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<String> mods = new ArrayList<>();
int len = input.readVarInt();
for (int x = 0; x < len; x++)
mods.add(input.readString(0x100));
Map<ResourceLocation, String> channels = new HashMap<>();
len = input.readVarInt();
for (int x = 0; x < len; x++)
channels.put(input.readResourceLocation(), input.readString(0x100));
List<ResourceLocation> 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<String> getRegistries() {
public List<String> getModList() {
return mods;
}
public List<ResourceLocation> getRegistries() {
return this.registries;
}
NBTTagList getChannels() {
public Map<ResourceLocation, String> getChannels() {
return this.channels;
}
}
public static class C2SModListReply extends S2CModList
public static class C2SModListReply extends LoginIndexedMessage
{
public C2SModListReply() {
super();
}
private List<String> mods;
private Map<ResourceLocation, String> channels;
private Map<ResourceLocation, String> 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<String> mods, Map<ResourceLocation, String> channels, Map<ResourceLocation, String> registries)
{
super.encode(buffer);
this.mods = mods;
this.channels = channels;
this.registries = registries;
}
public static C2SModListReply decode(PacketBuffer input)
{
List<String> mods = new ArrayList<>();
int len = input.readVarInt();
for (int x = 0; x < len; x++)
mods.add(input.readString(0x100));
Map<ResourceLocation, String> channels = new HashMap<>();
len = input.readVarInt();
for (int x = 0; x < len; x++)
channels.put(input.readResourceLocation(), input.readString(0x100));
Map<ResourceLocation, String> 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<String> getModList() {
return mods;
}
public Map<ResourceLocation, String> getRegistries() {
return this.registries;
}
public Map<ResourceLocation, String> 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<? extends IForgeRegistryEntry<?>> 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;
}
}

View File

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

View File

@ -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<ResourceLocation, String> buildChannelVersions() {
return instances.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getNetworkProtocolVersion()));
}
static List<String> listRejectedVanillaMods(BiFunction<NetworkInstance, String, Boolean> 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<ResourceLocation, String> 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<ResourceLocation, String> 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<NetworkInstance, String, Boolean> testFunction) {
Map<ResourceLocation, String> 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<ResourceLocation, String> incoming, final String originName, BiFunction<NetworkInstance, String, Boolean> testFunction) {
final List<Pair<ResourceLocation, Boolean>> results = instances.values().stream().
map(ni -> {
final String incomingVersion = incoming.getOrDefault(ni.getChannelName(), ABSENT);

View File

@ -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<V extends IForgeRegistryEntry<V>> implements IForgeRe
public static class Snapshot
{
public final Map<ResourceLocation, Integer> ids = Maps.newHashMap();
public final Map<ResourceLocation, ResourceLocation> aliases = Maps.newHashMap();
public final Set<Integer> blocked = Sets.newHashSet();
public final Set<ResourceLocation> dummied = Sets.newHashSet();
public final Map<ResourceLocation, String> overrides = Maps.newHashMap();
public final Map<ResourceLocation, Integer> ids = Maps.newTreeMap();
public final Map<ResourceLocation, ResourceLocation> aliases = Maps.newTreeMap();
public final Set<Integer> blocked = Sets.newTreeSet();
public final Set<ResourceLocation> dummied = Sets.newTreeSet();
public final Map<ResourceLocation, String> 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<V extends IForgeRegistryEntry<V>> 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<V extends IForgeRegistryEntry<V>> 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<V extends IForgeRegistryEntry<V>> 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<ResourceLocation, Integer> map)

View File

@ -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<Pair<String, FMLHandshakeMessages.S2CRegistry>> generateRegistryPackets() {
return ACTIVE.registries.entrySet().stream().
map(e->Pair.of("Registry "+e.getKey(), new FMLHandshakeMessages.S2CRegistry(e.getKey(), e.getValue()))).
public static List<Pair<String, FMLHandshakeMessages.S2CRegistry>> 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<String> 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<NetworkEvent.Context> contextSupplier) {
LOGGER.debug(REGISTRIES,"Received registry packet for {}", registryUpdate.getRegistryName());
public static List<ResourceLocation> registryNames()
{
return ACTIVE.registries.entrySet().stream().map(Map.Entry::getKey).collect(Collectors.toList());
}
}

View File

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