Skip to content

Commit

Permalink
Allow custom DataSerializers to be registered safely (MinecraftForge#…
Browse files Browse the repository at this point in the history
  • Loading branch information
bs2609 authored and tterrag1098 committed Apr 11, 2019
1 parent 1f12642 commit 208ed99
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--- ../src-base/minecraft/net/minecraft/network/datasync/DataSerializers.java
+++ ../src-work/minecraft/net/minecraft/network/datasync/DataSerializers.java
@@ -305,20 +305,21 @@
}
};

+ @Deprecated // Forge: ONLY FOR VANILLA - mods should use the Forge registry
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 (DataSerializer)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
30 changes: 30 additions & 0 deletions src/main/java/net/minecraftforge/common/ForgeHooks.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
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.network.play.server.SPacketRecipeBook;
import net.minecraft.network.play.server.SPacketRecipeBook.State;
Expand All @@ -93,6 +94,7 @@
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.NonNullList;
import net.minecraft.util.ResourceLocation;
Expand Down Expand Up @@ -151,6 +153,9 @@
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher.ConnectionType;
import net.minecraftforge.fml.common.registry.ForgeRegistries;
import net.minecraftforge.registries.DataSerializerEntry;
import net.minecraftforge.registries.ForgeRegistry;
import net.minecraftforge.registries.GameData;
import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.RegistryManager;

Expand Down Expand Up @@ -1470,4 +1475,29 @@ public static boolean onFarmlandTrample(World world, BlockPos pos, IBlockState s
return false;
}

private static final Map<DataSerializer<?>, DataSerializerEntry> serializerEntries = GameData.getSerializerMap();
private static final ForgeRegistry<DataSerializerEntry> serializerRegistry = (ForgeRegistry<DataSerializerEntry>) ForgeRegistries.DATA_SERIALIZERS;

@Nullable
public static DataSerializer<?> getSerializer(int id, IntIdentityHashBiMap<DataSerializer<?>> vanilla)
{
DataSerializer<?> serializer = vanilla.get(id);
if (serializer == null)
{
DataSerializerEntry entry = serializerRegistry.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 = serializerRegistry.getID(entry);
}
return id;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import net.minecraft.util.SoundEvent;
import net.minecraft.world.biome.Biome;
import net.minecraftforge.fml.common.registry.VillagerRegistry.VillagerProfession;
import net.minecraftforge.registries.DataSerializerEntry;
import net.minecraftforge.registries.GameData;
import net.minecraftforge.registries.IForgeRegistry;

Expand All @@ -51,6 +52,7 @@ public class ForgeRegistries
public static final IForgeRegistry<VillagerProfession> VILLAGER_PROFESSIONS = GameRegistry.findRegistry(VillagerProfession.class);
public static final IForgeRegistry<EntityEntry> ENTITIES = GameRegistry.findRegistry(EntityEntry.class);
public static final IForgeRegistry<IRecipe> RECIPES = GameRegistry.findRegistry(IRecipe.class);
public static final IForgeRegistry<DataSerializerEntry> DATA_SERIALIZERS = GameRegistry.findRegistry(DataSerializerEntry.class);


/**
Expand Down
Original file line number Diff line number Diff line change
@@ -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 IForgeRegistryEntry.Impl<DataSerializerEntry>
{
private final DataSerializer<?> serializer;

public DataSerializerEntry(DataSerializer<?> serializer)
{
this.serializer = serializer;
}

public DataSerializer<?> getSerializer()
{
return serializer;
}
}
40 changes: 40 additions & 0 deletions src/main/java/net/minecraftforge/registries/GameData.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.network.datasync.DataSerializer;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionType;
import net.minecraft.util.ObjectIntIdentityMap;
Expand Down Expand Up @@ -100,6 +101,8 @@ public class GameData
public static final ResourceLocation ENTITIES = new ResourceLocation("minecraft:entities");
public static final ResourceLocation RECIPES = new ResourceLocation("minecraft:recipes");
public static final ResourceLocation PROFESSIONS = new ResourceLocation("minecraft:villagerprofessions");
public static final ResourceLocation SERIALIZERS = new ResourceLocation("minecraft:dataserializers");

private static final int MAX_BLOCK_ID = 4095;
private static final int MIN_ITEM_ID = MAX_BLOCK_ID + 1;
private static final int MAX_ITEM_ID = 31999;
Expand All @@ -111,10 +114,14 @@ public class GameData
private static final int MAX_ENTITY_ID = Integer.MAX_VALUE >> 5; // Varint (SPacketSpawnMob)
private static final int MAX_RECIPE_ID = Integer.MAX_VALUE >> 5; // Varint CPacketRecipeInfo/SPacketRecipeBook
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 ENTITY_CLASS_TO_ENTRY = new ResourceLocation("forge:entity_class_to_entry");
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());
Expand Down Expand Up @@ -142,6 +149,7 @@ public static void init()
makeRegistry(ENCHANTMENTS, Enchantment.class, MAX_ENCHANTMENT_ID).create();
makeRegistry(RECIPES, IRecipe.class, MAX_RECIPE_ID).disableSaving().allowModification().addCallback(RecipeCallbacks.INSTANCE).create();
makeRegistry(PROFESSIONS, VillagerProfession.class, MAX_PROFESSION_ID).create();
makeRegistry(SERIALIZERS, DataSerializerEntry.class, MIN_SERIALIZER_ID, MAX_SERIALIZER_ID).disableSaving().disableOverrides().addCallback(SerializerCallbacks.INSTANCE).create();
entityRegistry = (ForgeRegistry<EntityEntry>)makeRegistry(ENTITIES, EntityEntry.class, MAX_ENTITY_ID).addCallback(EntityCallbacks.INSTANCE).create();
}

Expand Down Expand Up @@ -196,6 +204,12 @@ public static Map<Class<? extends Entity>, EntityEntry> getEntityClassMap()
return GameRegistry.findRegistry(EntityEntry.class).getSlaveMap(ENTITY_CLASS_TO_ENTRY, Map.class);
}

@SuppressWarnings("unchecked")
public static Map<DataSerializer<?>, DataSerializerEntry> getSerializerMap()
{
return GameRegistry.findRegistry(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");
Expand Down Expand Up @@ -520,6 +534,32 @@ public void onCreate(IForgeRegistryInternal<EntityEntry> owner, RegistryManager
}
}

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);
Expand Down

0 comments on commit 208ed99

Please sign in to comment.