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:
parent
cb70702ab5
commit
58494f8878
11 changed files with 413 additions and 123 deletions
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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_);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
129
src/main/java/net/minecraftforge/common/util/HexDumper.java
Normal file
129
src/main/java/net/minecraftforge/common/util/HexDumper.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue