Allow custom DataSerializers to be registered safely (#5245)
This commit is contained in:
parent
cf35019d07
commit
931105123e
5 changed files with 140 additions and 0 deletions
|
@ -0,0 +1,22 @@
|
|||
--- a/net/minecraft/network/datasync/DataSerializers.java
|
||||
+++ b/net/minecraft/network/datasync/DataSerializers.java
|
||||
@@ -320,16 +320,16 @@
|
||||
};
|
||||
|
||||
public static void func_187189_a(DataSerializer<?> p_187189_0_) {
|
||||
- field_187204_n.func_186808_c(p_187189_0_);
|
||||
+ if (field_187204_n.func_186808_c(p_187189_0_) >= 256) throw new RuntimeException("Vanilla DataSerializer ID limit exceeded");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static DataSerializer<?> func_187190_a(int p_187190_0_) {
|
||||
- return field_187204_n.func_186813_a(p_187190_0_);
|
||||
+ return net.minecraftforge.common.ForgeHooks.getSerializer(p_187190_0_, field_187204_n);
|
||||
}
|
||||
|
||||
public static int func_187188_b(DataSerializer<?> p_187188_0_) {
|
||||
- return field_187204_n.func_186815_a(p_187188_0_);
|
||||
+ return net.minecraftforge.common.ForgeHooks.getSerializerId(p_187188_0_, field_187204_n);
|
||||
}
|
||||
|
||||
static {
|
|
@ -28,6 +28,7 @@ import java.util.Collections;
|
|||
import java.util.Deque;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
@ -79,6 +80,7 @@ import net.minecraft.nbt.NBTTagCompound;
|
|||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.network.NetHandlerPlayServer;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.datasync.DataSerializer;
|
||||
import net.minecraft.network.play.server.SPacketBlockChange;
|
||||
import net.minecraft.potion.PotionType;
|
||||
import net.minecraft.potion.PotionUtils;
|
||||
|
@ -90,6 +92,7 @@ import net.minecraft.util.DamageSource;
|
|||
import net.minecraft.util.EnumActionResult;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.IntIdentityHashBiMap;
|
||||
import net.minecraft.util.JsonUtils;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.WeightedRandom;
|
||||
|
@ -141,6 +144,10 @@ import net.minecraftforge.event.world.BlockEvent;
|
|||
import net.minecraftforge.event.world.NoteBlockEvent;
|
||||
import net.minecraftforge.eventbus.api.Event.Result;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import net.minecraftforge.registries.DataSerializerEntry;
|
||||
import net.minecraftforge.registries.ForgeRegistry;
|
||||
import net.minecraftforge.registries.GameData;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
@ -1180,4 +1187,31 @@ public class ForgeHooks
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<DataSerializer<?>, DataSerializerEntry> serializerEntries = GameData.getSerializerMap();
|
||||
//private static final ForgeRegistry<DataSerializerEntry> serializerRegistry = (ForgeRegistry<DataSerializerEntry>) ForgeRegistries.DATA_SERIALIZERS;
|
||||
// Do not reimplement this ^ it introduces a chicken-egg scenario by classloading registries during bootstrap
|
||||
|
||||
@Nullable
|
||||
public static DataSerializer<?> getSerializer(int id, IntIdentityHashBiMap<DataSerializer<?>> vanilla)
|
||||
{
|
||||
DataSerializer<?> serializer = vanilla.get(id);
|
||||
if (serializer == null)
|
||||
{
|
||||
DataSerializerEntry entry = ((ForgeRegistry<DataSerializerEntry>)ForgeRegistries.DATA_SERIALIZERS).getValue(id);
|
||||
if (entry != null) serializer = entry.getSerializer();
|
||||
}
|
||||
return serializer;
|
||||
}
|
||||
|
||||
public static int getSerializerId(DataSerializer<?> serializer, IntIdentityHashBiMap<DataSerializer<?>> vanilla)
|
||||
{
|
||||
int id = vanilla.getId(serializer);
|
||||
if (id < 0)
|
||||
{
|
||||
DataSerializerEntry entry = serializerEntries.get(serializer);
|
||||
if (entry != null) id = ((ForgeRegistry<DataSerializerEntry>)ForgeRegistries.DATA_SERIALIZERS).getID(entry);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Minecraft Forge
|
||||
* Copyright (c) 2016-2018.
|
||||
*
|
||||
* 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.registries;
|
||||
|
||||
import net.minecraft.network.datasync.DataSerializer;
|
||||
|
||||
public final class DataSerializerEntry extends ForgeRegistryEntry<DataSerializerEntry>
|
||||
{
|
||||
private final DataSerializer<?> serializer;
|
||||
|
||||
public DataSerializerEntry(DataSerializer<?> serializer)
|
||||
{
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
public DataSerializer<?> getSerializer()
|
||||
{
|
||||
return serializer;
|
||||
}
|
||||
}
|
|
@ -54,6 +54,8 @@ public class ForgeRegistries
|
|||
public static final IForgeRegistry<EntityType<?>> ENTITIES = RegistryManager.ACTIVE.getRegistry(EntityType.class); //Untyped casys needed to fix javac issues.
|
||||
public static final IForgeRegistry<TileEntityType<?>> TILE_ENTITIES = RegistryManager.ACTIVE.getRegistry(TileEntityType.class);
|
||||
public static final IForgeRegistry<ModDimension> MOD_DIMENSIONS = RegistryManager.ACTIVE.getRegistry(ModDimension.class);
|
||||
public static final IForgeRegistry<DataSerializerEntry> DATA_SERIALIZERS = RegistryManager.ACTIVE.getRegistry(DataSerializerEntry.class);
|
||||
|
||||
/**
|
||||
* This function is just to make sure static inializers in other classes have run and setup their registries before we query them.
|
||||
*/
|
||||
|
|
|
@ -28,6 +28,7 @@ import net.minecraft.enchantment.Enchantment;
|
|||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import net.minecraft.network.datasync.DataSerializer;
|
||||
import net.minecraft.potion.Potion;
|
||||
import net.minecraft.potion.PotionType;
|
||||
import net.minecraft.state.StateContainer;
|
||||
|
@ -57,6 +58,7 @@ import org.apache.logging.log4j.Logger;
|
|||
import javax.annotation.Nullable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -87,6 +89,8 @@ public class GameData
|
|||
public static final ResourceLocation TILEENTITIES = new ResourceLocation("minecraft:tileentities");
|
||||
public static final ResourceLocation PROFESSIONS = new ResourceLocation("minecraft:villagerprofessions");
|
||||
public static final ResourceLocation MODDIMENSIONS = new ResourceLocation("forge:moddimensions");
|
||||
public static final ResourceLocation SERIALIZERS = new ResourceLocation("minecraft:dataserializers");
|
||||
|
||||
private static final int MAX_REGISTRY_SIZE = Integer.MAX_VALUE >> 5;
|
||||
private static final int MAX_BLOCK_ID = 4095;
|
||||
private static final int MAX_ITEM_ID = 31999;
|
||||
|
@ -98,9 +102,13 @@ public class GameData
|
|||
private static final int MAX_ENTITY_ID = MAX_REGISTRY_SIZE; // Varint (SPacketSpawnMob)
|
||||
private static final int MAX_TILE_ENTITY_ID = Integer.MAX_VALUE; //Doesnt seem to be serialized anywhere, so no max.
|
||||
private static final int MAX_PROFESSION_ID = 1024; //TODO: Is this serialized anywhere anymore?
|
||||
private static final int MIN_SERIALIZER_ID = 256; // Leave room for vanilla entries
|
||||
private static final int MAX_SERIALIZER_ID = Integer.MAX_VALUE >> 5; // Varint (EntityDataManager)
|
||||
|
||||
private static final ResourceLocation BLOCK_TO_ITEM = new ResourceLocation("minecraft:blocktoitemmap");
|
||||
private static final ResourceLocation BLOCKSTATE_TO_ID = new ResourceLocation("minecraft:blockstatetoid");
|
||||
private static final ResourceLocation SERIALIZER_TO_ENTRY = new ResourceLocation("forge:serializer_to_entry");
|
||||
|
||||
private static boolean hasInit = false;
|
||||
private static final boolean DISABLE_VANILLA_REGISTRIES = Boolean.parseBoolean(System.getProperty("forge.disableVanillaGameData", "false")); // Use for unit tests/debugging
|
||||
private static final BiConsumer<ResourceLocation, ForgeRegistry<?>> LOCK_VANILLA = (name, reg) -> reg.slaves.values().stream().filter(o -> o instanceof ILockableRegistry).forEach(o -> ((ILockableRegistry)o).lock());
|
||||
|
@ -132,12 +140,17 @@ public class GameData
|
|||
makeRegistry(ENTITIES, EntityType.class, MAX_ENTITY_ID).create();
|
||||
makeRegistry(TILEENTITIES, TileEntityType.class, MAX_TILE_ENTITY_ID).disableSaving().create();
|
||||
makeRegistry(MODDIMENSIONS, ModDimension.class, MAX_REGISTRY_SIZE).disableSaving().create();
|
||||
makeRegistry(SERIALIZERS, DataSerializerEntry.class, MIN_SERIALIZER_ID, MAX_SERIALIZER_ID).disableSaving().disableOverrides().addCallback(SerializerCallbacks.INSTANCE).create();
|
||||
}
|
||||
|
||||
private static <T extends IForgeRegistryEntry<T>> RegistryBuilder<T> makeRegistry(ResourceLocation name, Class<T> type, int max)
|
||||
{
|
||||
return new RegistryBuilder<T>().setName(name).setType(type).setMaxID(max).addCallback(new NamespacedWrapper.Factory<T>());
|
||||
}
|
||||
private static <T extends IForgeRegistryEntry<T>> RegistryBuilder<T> makeRegistry(ResourceLocation name, Class<T> type, int min, int max)
|
||||
{
|
||||
return new RegistryBuilder<T>().setName(name).setType(type).setIDRange(min, max).addCallback(new NamespacedWrapper.Factory<T>());
|
||||
}
|
||||
private static <T extends IForgeRegistryEntry<T>> RegistryBuilder<T> makeRegistry(ResourceLocation name, Class<T> type, int max, ResourceLocation _default)
|
||||
{
|
||||
return new RegistryBuilder<T>().setName(name).setType(type).setMaxID(max).addCallback(new NamespacedDefaultedWrapper.Factory<T>()).setDefaultKey(_default);
|
||||
|
@ -175,6 +188,12 @@ public class GameData
|
|||
return RegistryManager.ACTIVE.getRegistry(Block.class).getSlaveMap(BLOCKSTATE_TO_ID, ObjectIntIdentityMap.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<DataSerializer<?>, DataSerializerEntry> getSerializerMap()
|
||||
{
|
||||
return RegistryManager.ACTIVE.getRegistry(DataSerializerEntry.class).getSlaveMap(SERIALIZER_TO_ENTRY, Map.class);
|
||||
}
|
||||
|
||||
public static <K extends IForgeRegistryEntry<K>> K register_impl(K value)
|
||||
{
|
||||
Validate.notNull(value, "Attempted to register a null object");
|
||||
|
@ -539,6 +558,32 @@ public class GameData
|
|||
}
|
||||
*/
|
||||
|
||||
private static class SerializerCallbacks implements IForgeRegistry.AddCallback<DataSerializerEntry>, IForgeRegistry.ClearCallback<DataSerializerEntry>, IForgeRegistry.CreateCallback<DataSerializerEntry>
|
||||
{
|
||||
static final SerializerCallbacks INSTANCE = new SerializerCallbacks();
|
||||
|
||||
@Override
|
||||
public void onAdd(IForgeRegistryInternal<DataSerializerEntry> owner, RegistryManager stage, int id, DataSerializerEntry entry, @Nullable DataSerializerEntry oldEntry)
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<DataSerializer<?>, DataSerializerEntry> map = owner.getSlaveMap(SERIALIZER_TO_ENTRY, Map.class);
|
||||
if (oldEntry != null) map.remove(oldEntry.getSerializer());
|
||||
map.put(entry.getSerializer(), entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClear(IForgeRegistryInternal<DataSerializerEntry> owner, RegistryManager stage)
|
||||
{
|
||||
owner.getSlaveMap(SERIALIZER_TO_ENTRY, Map.class).clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(IForgeRegistryInternal<DataSerializerEntry> owner, RegistryManager stage)
|
||||
{
|
||||
owner.setSlaveMap(SERIALIZER_TO_ENTRY, new IdentityHashMap<>());
|
||||
}
|
||||
}
|
||||
|
||||
private static <T extends IForgeRegistryEntry<T>> void loadRegistry(final ResourceLocation registryName, final RegistryManager from, final RegistryManager to, final Class<T> regType, boolean freeze)
|
||||
{
|
||||
ForgeRegistry<T> fromRegistry = from.getRegistry(registryName);
|
||||
|
|
Loading…
Reference in a new issue