Backport of Registries optimization, now uses fastutils collections to minimize boxing

This commit is contained in:
J-RAP authored and GitHub committed 2023-11-29 11:11:55 -08:00
1 parent 6821d7b1cc
commit cdba403ab6
4 files changed
+271 -446

No files matched your search

@@ -138,7 +138,7 @@ public class ForgeRegistries
* Calling {@link Supplier#get()} before {@link NewRegistryEvent} is fired will result in a null registry returned.
* Use {@link Keys#HOLDER_SET_TYPES} to create a {@link DeferredRegister}.
*/
public static final Supplier<IForgeRegistry<HolderSetType>> HOLDER_SET_TYPES = DEFERRED_HOLDER_SET_TYPES.makeRegistry(GameData::getHolderSetTypeRegistryBuilder);
public static final Supplier<IForgeRegistry<HolderSetType>> HOLDER_SET_TYPES = DEFERRED_HOLDER_SET_TYPES.makeRegistry(GameData::makeUnsavedAndUnsynced);
static final DeferredRegister<ItemDisplayContext> DEFERRED_DISPLAY_CONTEXTS = DeferredRegister.create(Keys.DISPLAY_CONTEXTS, "forge");
/**
File diff suppressed because it is too large. Load diff
@@ -7,7 +7,6 @@ package net.minecraftforge.registries;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.mojang.serialization.Codec;
import com.mojang.serialization.Lifecycle;
@@ -23,6 +22,9 @@ import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.core.IdMapper;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
@@ -30,6 +32,7 @@ import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.syncher.EntityDataSerializer;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.effect.MobEffect;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.SpawnPlacements;
import net.minecraft.world.entity.ai.attributes.Attribute;
@@ -38,7 +41,10 @@ import net.minecraft.world.entity.ai.village.poi.PoiType;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.alchemy.Potion;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.levelgen.DebugLevelSource;
@@ -57,7 +63,6 @@ import net.minecraftforge.fml.StartupMessageManager;
import net.minecraftforge.fml.util.EnhancedRuntimeException;
import net.minecraftforge.fml.util.thread.EffectiveSide;
import net.minecraftforge.registries.ForgeRegistries.Keys;
import net.minecraftforge.registries.holdersets.HolderSetType;
import org.apache.commons.lang3.Validate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -68,12 +73,12 @@ import org.jetbrains.annotations.Nullable;
/**
* INTERNAL ONLY
* MODDERS SHOULD HAVE NO REASON TO USE THIS CLASS
* <p>Use the public {@link IForgeRegistry} and {@link ForgeRegistries} APIs to get the data</p>
*/
@ApiStatus.Internal
public class GameData
{
public class GameData {
private static final Logger LOGGER = LogManager.getLogger();
private static Marker REGISTRIES = ForgeRegistry.REGISTRIES;
private static final Marker REGISTRIES = ForgeRegistry.REGISTRIES;
private static final int MAX_VARINT = Integer.MAX_VALUE - 1; //We were told it is their intention to have everything in a reg be unlimited, so assume that until we find cases where it isnt.
private static final ResourceLocation BLOCK_TO_ITEM = new ResourceLocation("minecraft:blocktoitemmap");
@@ -82,16 +87,15 @@ public class GameData
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());
private static final BiConsumer<ResourceLocation, ForgeRegistry<?>> LOCK_VANILLA = (name, reg) -> reg.slaves.values().stream().filter(o -> o instanceof ILockableRegistry).forEach(o -> ((ILockableRegistry) o).lock());
static {
init();
}
public static void init()
{
if (DISABLE_VANILLA_REGISTRIES)
{
@SuppressWarnings("deprecation")
public static void init() {
if (DISABLE_VANILLA_REGISTRIES) {
LOGGER.warn(REGISTRIES, "DISABLING VANILLA REGISTRY CREATION AS PER SYSTEM VARIABLE SETTING! forge.disableVanillaGameData");
return;
}
@@ -138,59 +142,50 @@ public class GameData
makeRegistry(Keys.BIOMES).disableSync().create();
}
static RegistryBuilder<EntityDataSerializer<?>> getDataSerializersRegistryBuilder()
{
static RegistryBuilder<EntityDataSerializer<?>> getDataSerializersRegistryBuilder() {
return makeRegistry(Keys.ENTITY_DATA_SERIALIZERS, 256 /*vanilla space*/, MAX_VARINT).disableSaving().disableOverrides();
}
static RegistryBuilder<Codec<? extends IGlobalLootModifier>> getGLMSerializersRegistryBuilder()
{
static RegistryBuilder<Codec<? extends IGlobalLootModifier>> getGLMSerializersRegistryBuilder() {
return makeRegistry(Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS).disableSaving().disableSync();
}
static RegistryBuilder<Codec<? extends BiomeModifier>> getBiomeModifierSerializersRegistryBuilder()
{
static RegistryBuilder<Codec<? extends BiomeModifier>> getBiomeModifierSerializersRegistryBuilder() {
return new RegistryBuilder<Codec<? extends BiomeModifier>>().disableSaving().disableSync();
}
static RegistryBuilder<Codec<? extends StructureModifier>> getStructureModifierSerializersRegistryBuilder()
{
static RegistryBuilder<Codec<? extends StructureModifier>> getStructureModifierSerializersRegistryBuilder() {
return new RegistryBuilder<Codec<? extends StructureModifier>>().disableSaving().disableSync();
}
static RegistryBuilder<FluidType> getFluidTypeRegistryBuilder()
{
static RegistryBuilder<FluidType> getFluidTypeRegistryBuilder() {
return makeRegistry(Keys.FLUID_TYPES).disableSaving();
}
static RegistryBuilder<HolderSetType> getHolderSetTypeRegistryBuilder()
{
return new RegistryBuilder<HolderSetType>().disableSaving().disableSync();
static <T> RegistryBuilder<T> makeUnsavedAndUnsynced() {
return RegistryBuilder.<T>of().disableSaving().disableSync();
}
static RegistryBuilder<ItemDisplayContext> getItemDisplayContextRegistryBuilder()
{
static RegistryBuilder<ItemDisplayContext> getItemDisplayContextRegistryBuilder() {
return new RegistryBuilder<ItemDisplayContext>()
.setMaxID(128 * 2) /* 0 -> 127 gets positive ID, 128 -> 256 gets negative ID */.disableOverrides().disableSaving()
.setDefaultKey(new ResourceLocation("minecraft:none"))
.onAdd(ItemDisplayContext.ADD_CALLBACK);
.setMaxID(128 * 2) /* 0 -> 127 gets positive ID, 128 -> 256 gets negative ID */.disableOverrides().disableSaving()
.setDefaultKey(new ResourceLocation("minecraft:none"))
.onAdd(ItemDisplayContext.ADD_CALLBACK);
}
private static <T> RegistryBuilder<T> makeRegistry(ResourceKey<? extends Registry<T>> key)
{
private static <T> RegistryBuilder<T> makeRegistry(ResourceKey<? extends Registry<T>> key) {
return new RegistryBuilder<T>().setName(key.location()).setMaxID(MAX_VARINT).hasWrapper();
}
private static <T> RegistryBuilder<T> makeRegistry(ResourceKey<? extends Registry<T>> key, int min, int max)
{
private static <T> RegistryBuilder<T> makeRegistry(ResourceKey<? extends Registry<T>> key, int min, int max) {
return new RegistryBuilder<T>().setName(key.location()).setIDRange(min, max).hasWrapper();
}
private static <T> RegistryBuilder<T> makeRegistry(ResourceKey<? extends Registry<T>> key, String _default)
{
private static <T> RegistryBuilder<T> makeRegistry(ResourceKey<? extends Registry<T>> key, String _default) {
return new RegistryBuilder<T>().setName(key.location()).setMaxID(MAX_VARINT).hasWrapper().setDefaultKey(new ResourceLocation(_default));
}
public static <T> MappedRegistry<T> getWrapper(ResourceKey<? extends Registry<T>> key, Lifecycle lifecycle)
{
public static <T> MappedRegistry<T> getWrapper(ResourceKey<? extends Registry<T>> key, Lifecycle lifecycle) {
IForgeRegistry<T> reg = RegistryManager.ACTIVE.getRegistry(key);
Validate.notNull(reg, "Attempted to get vanilla wrapper for unknown registry: " + key.toString());
@SuppressWarnings("unchecked")
@@ -199,8 +194,7 @@ public class GameData
return ret;
}
public static <T> MappedRegistry<T> getWrapper(ResourceKey<? extends Registry<T>> key, Lifecycle lifecycle, String defKey)
{
public static <T> MappedRegistry<T> getWrapper(ResourceKey<? extends Registry<T>> key, Lifecycle lifecycle, String defKey) {
IForgeRegistry<T> reg = RegistryManager.ACTIVE.getRegistry(key);
Validate.notNull(reg, "Attempted to get vanilla wrapper for unknown registry: " + key.toString());
@SuppressWarnings("unchecked")
@@ -210,26 +204,21 @@ public class GameData
}
@SuppressWarnings("unchecked")
public static Map<Block,Item> getBlockItemMap()
{
public static Map<Block, Item> getBlockItemMap() {
return RegistryManager.ACTIVE.getRegistry(Keys.ITEMS).getSlaveMap(BLOCK_TO_ITEM, Map.class);
}
@SuppressWarnings("unchecked")
public static IdMapper<BlockState> getBlockStateIDMap()
{
public static IdMapper<BlockState> getBlockStateIDMap() {
return RegistryManager.ACTIVE.getRegistry(Keys.BLOCKS).getSlaveMap(BLOCKSTATE_TO_ID, IdMapper.class);
}
@SuppressWarnings("unchecked")
public static Map<BlockState, PoiType> getBlockStatePointOfInterestTypeMap()
{
public static Map<BlockState, PoiType> getBlockStatePointOfInterestTypeMap() {
return RegistryManager.ACTIVE.getRegistry(Keys.POI_TYPES).getSlaveMap(BLOCKSTATE_TO_POINT_OF_INTEREST_TYPE, Map.class);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void vanillaSnapshot()
{
public static void vanillaSnapshot() {
LOGGER.debug(REGISTRIES, "Creating vanilla freeze snapshot");
for (Map.Entry<ResourceLocation, ForgeRegistry<?>> r : RegistryManager.ACTIVE.registries.entrySet())
{
@@ -245,13 +234,12 @@ public class GameData
LOGGER.debug(REGISTRIES, "Vanilla freeze snapshot created");
}
public static void unfreezeData()
{
@SuppressWarnings("deprecation")
public static void unfreezeData() {
LOGGER.debug(REGISTRIES, "Unfreezing vanilla registries");
BuiltInRegistries.REGISTRY.stream().filter(r -> r instanceof MappedRegistry).forEach(r -> ((MappedRegistry<?>)r).unfreeze());
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void freezeData()
{
LOGGER.debug(REGISTRIES, "Freezing registries");
@@ -281,7 +269,7 @@ public class GameData
public static void revertToFrozen() {
revertTo(RegistryManager.FROZEN, true);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void revertTo(final RegistryManager target, boolean fireEvents)
{
if (target.registries.isEmpty())
@@ -307,7 +295,6 @@ public class GameData
LOGGER.debug(REGISTRIES, "{} state restored.", target.getName());
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void revert(RegistryManager state, ResourceLocation registry, boolean lock)
{
LOGGER.debug(REGISTRIES, "Reverting {} to {}", registry, state.getName());
@@ -376,11 +363,12 @@ public class GameData
this.nextId = 0;
}
@SuppressWarnings("unused")
void remove(I key)
{
Integer prev = this.tToId.remove(key);
if (prev != null)
{
boolean hadId = this.tToId.containsKey(key);
int prev = this.tToId.removeInt(key);
if (hadId) {
this.idToT.set(prev, null);
}
}
@@ -430,21 +418,17 @@ public class GameData
@Override
public void onCreate(IForgeRegistryInternal<Block> owner, RegistryManager stage)
{
final ClearableObjectIntIdentityMap<BlockState> idMap = new ClearableObjectIntIdentityMap<BlockState>()
final ClearableObjectIntIdentityMap<BlockState> idMap = new ClearableObjectIntIdentityMap<>()
{
@SuppressWarnings("deprecation")
@Override
public int getId(BlockState key)
{
Integer integer = (Integer)this.tToId.get(key);
// There are some cases where this map is queried to serialize a state that is valid,
//but somehow not in this list, so attempt to get real metadata. Doing this hear saves us 7 patches
//if (integer == null && key != null)
// integer = this.identityMap.get(key.getBlock().getStateFromMeta(key.getBlock().getMetaFromState(key)));
return integer == null ? -1 : integer.intValue();
return this.tToId.containsKey(key) ? this.tToId.getInt(key) : -1;
}
};
owner.setSlaveMap(BLOCKSTATE_TO_ID, idMap);
owner.setSlaveMap(BLOCK_TO_ITEM, Maps.newHashMap());
owner.setSlaveMap(BLOCK_TO_ITEM, new HashMap<>());
}
@Override
@@ -522,6 +506,7 @@ public class GameData
@Override
public void onAdd(IForgeRegistryInternal<PoiType> owner, RegistryManager stage, int id, ResourceKey<PoiType> key, PoiType obj, @Nullable PoiType oldObj)
{
@SuppressWarnings("unchecked")
Map<BlockState, PoiType> map = owner.getSlaveMap(BLOCKSTATE_TO_POINT_OF_INTEREST_TYPE, Map.class);
if (oldObj != null)
{
@@ -590,7 +575,6 @@ public class GameData
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static Multimap<ResourceLocation, ResourceLocation> injectSnapshot(Map<ResourceLocation, ForgeRegistry.Snapshot> snapshot, boolean injectFrozenData, boolean isLocalWorld)
{
LOGGER.info(REGISTRIES, "Injecting existing registry data into this {} instance", EffectiveSide.get());
@@ -605,11 +589,11 @@ public class GameData
if (isLocalWorld)
{
List<ResourceLocation> missingRegs = snapshot.keySet().stream().filter(name -> !RegistryManager.ACTIVE.registries.containsKey(name)).collect(Collectors.toList());
if (missingRegs.size() > 0)
ResourceLocation[] missingRegs = snapshot.keySet().stream().filter(name -> !RegistryManager.ACTIVE.registries.containsKey(name)).toArray(ResourceLocation[]::new);
if (missingRegs.length > 0)
{
String header = "Forge Mod Loader detected missing/unknown registrie(s).\n\n" +
"There are " + missingRegs.size() + " missing registries in this save.\n" +
"There are " + missingRegs.length + " missing registries in this save.\n" +
"If you continue the missing registries will get removed.\n" +
"This may cause issues, it is advised that you create a world backup before continuing.\n\n";
@@ -625,13 +609,13 @@ public class GameData
RegistryManager STAGING = new RegistryManager();
final Map<ResourceLocation, Map<ResourceLocation, IdMappingEvent.IdRemapping>> remaps = Maps.newHashMap();
final LinkedHashMap<ResourceLocation, Map<ResourceLocation, Integer>> missing = Maps.newLinkedHashMap();
final Map<ResourceLocation, Map<ResourceLocation, IdMappingEvent.IdRemapping>> remaps = new HashMap<>();
final LinkedHashMap<ResourceLocation, Object2IntMap<ResourceLocation>> missing = new LinkedHashMap<>();
// Load the snapshot into the "STAGING" registry
snapshot.forEach((key, value) ->
{
remaps.put(key, Maps.newLinkedHashMap());
missing.put(key, Maps.newLinkedHashMap());
remaps.put(key, new LinkedHashMap<>());
missing.put(key, new Object2IntLinkedOpenHashMap<>());
loadPersistentDataToStagingRegistry(RegistryManager.ACTIVE, STAGING, remaps.get(key), missing.get(key), key, value);
});
@@ -642,11 +626,12 @@ public class GameData
Multimap<ResourceLocation, ResourceLocation> defaulted = ArrayListMultimap.create();
Multimap<ResourceLocation, ResourceLocation> failed = ArrayListMultimap.create();
missing.entrySet().stream().filter(e -> e.getValue().size() > 0).forEach(m ->
missing.entrySet().stream().filter(e -> !e.getValue().isEmpty()).forEach(m ->
{
ResourceLocation name = m.getKey();
ForgeRegistry<?> reg = STAGING.getRegistry(name);
MissingMappingsEvent event = reg.getMissingEvent(name, m.getValue());
Object2IntMap<ResourceLocation> missingIds = m.getValue();
MissingMappingsEvent event = reg.getMissingEvent(name, missingIds);
MinecraftForge.EVENT_BUS.post(event);
List<MissingMappingsEvent.Mapping<?>> lst = event.getAllMappings(reg.getRegistryKey()).stream()
@@ -664,7 +649,7 @@ public class GameData
.filter(e -> e.action == MissingMappingsEvent.Action.FAIL)
.forEach(fail -> failed.put(name, fail.key));
processMissing(name, STAGING, event, m.getValue(), remaps.get(name), defaulted.get(name), failed.get(name), !isLocalWorld);
processMissing(name, STAGING, event, missingIds, remaps.get(name), defaulted.get(name), failed.get(name), !isLocalWorld);
});
if (!defaulted.isEmpty() && !isLocalWorld)
@@ -681,7 +666,7 @@ public class GameData
defaulted.asMap().forEach((name, entries) ->
{
buf.append("Missing ").append(name).append(":\n");
entries.stream().sorted((o1, o2) -> o1.compareNamespaced(o2)).forEach(rl -> buf.append(" ").append(rl).append("\n"));
entries.stream().sorted(ResourceLocation::compareNamespaced).forEach(rl -> buf.append(" ").append(rl).append("\n"));
buf.append("\n");
});
@@ -739,7 +724,7 @@ public class GameData
}
//Has to be split because of generics, Yay!
private static <T> void loadPersistentDataToStagingRegistry(RegistryManager pool, RegistryManager to, Map<ResourceLocation, IdMappingEvent.IdRemapping> remaps, Map<ResourceLocation, Integer> missing, ResourceLocation name, ForgeRegistry.Snapshot snap)
private static <T> void loadPersistentDataToStagingRegistry(RegistryManager pool, RegistryManager to, Map<ResourceLocation, IdMappingEvent.IdRemapping> remaps, Object2IntMap<ResourceLocation> missing, ResourceLocation name, ForgeRegistry.Snapshot snap)
{
ForgeRegistry<T> active = pool.getRegistry(name);
if (active == null)
@@ -751,8 +736,7 @@ public class GameData
}
//Another bouncer for generic reasons
@SuppressWarnings("unchecked")
private static <T> void processMissing(ResourceLocation name, RegistryManager STAGING, MissingMappingsEvent e, Map<ResourceLocation, Integer> missing, Map<ResourceLocation, IdMappingEvent.IdRemapping> remaps, Collection<ResourceLocation> defaulted, Collection<ResourceLocation> failed, boolean injectNetworkDummies)
private static <T> void processMissing(ResourceLocation name, RegistryManager STAGING, MissingMappingsEvent e, Object2IntMap<ResourceLocation> missing, Map<ResourceLocation, IdMappingEvent.IdRemapping> remaps, Collection<ResourceLocation> defaulted, Collection<ResourceLocation> failed, boolean injectNetworkDummies)
{
List<MissingMappingsEvent.Mapping<T>> mappings = e.getAllMappings(ResourceKey.createRegistryKey(name));
ForgeRegistry<T> active = RegistryManager.ACTIVE.getRegistry(name);
@@ -764,9 +748,9 @@ public class GameData
{
ForgeRegistry<T> frozen = RegistryManager.FROZEN.getRegistry(name);
ForgeRegistry<T> newRegistry = STAGING.getRegistry(name, RegistryManager.FROZEN);
Map<ResourceLocation, Integer> _new = Maps.newLinkedHashMap();
Object2IntMap<ResourceLocation> _new = new Object2IntLinkedOpenHashMap<>();
frozen.getKeys().stream().filter(key -> !newRegistry.containsKey(key)).forEach(key -> _new.put(key, frozen.getID(key)));
newRegistry.loadIds(_new, frozen.getOverrideOwners(), Maps.newLinkedHashMap(), remaps, frozen, name);
newRegistry.loadIds(_new, frozen.getOverrideOwners(), new Object2IntLinkedOpenHashMap<>(), remaps, frozen, name);
}
/**
@@ -785,11 +769,11 @@ public class GameData
String oldPrefix = index == -1 ? "" : name.substring(0, index).toLowerCase(Locale.ROOT);
name = index == -1 ? name : name.substring(index + 1);
String prefix = ModLoadingContext.get().getActiveNamespace();
if (warnOverrides && !oldPrefix.equals(prefix) && oldPrefix.length() > 0)
if (warnOverrides && !oldPrefix.equals(prefix) && !oldPrefix.isEmpty())
{
LogManager.getLogger().debug("Mod `{}` attempting to register `{}` to the namespace `{}`. This could be intended, but likely means an EventBusSubscriber without a modid.", prefix, name, oldPrefix);
prefix = oldPrefix;
}
return new ResourceLocation(prefix, name);
}
}
}
@@ -20,8 +20,19 @@ import java.util.List;
import java.util.Set;
import java.util.function.Function;
public class RegistryBuilder<T>
{
public class RegistryBuilder<T> {
public static <T> RegistryBuilder<T> of() {
return new RegistryBuilder<T>();
}
public static <T> RegistryBuilder<T> of(String name) {
return of(new ResourceLocation(name));
}
public static <T> RegistryBuilder<T> of(ResourceLocation name) {
return new RegistryBuilder<T>().setName(name);
}
private static final int MAX_ID = Integer.MAX_VALUE - 1;
private ResourceLocation registryName;