2017-06-19 15:02:18 -07:00
/*
2022-04-14 03:42:00 +00:00
* Copyright (c) Forge Development LLC and contributors
2022-02-28 13:41:23 -08:00
* SPDX-License-Identifier: LGPL-2.1-only
2017-06-19 15:02:18 -07:00
*/
package net.minecraftforge.registries ;
2019-01-11 23:52:30 +01:00
import com.google.common.collect.* ;
2020-08-13 00:13:48 -07:00
import com.mojang.serialization.Lifecycle ;
2019-09-06 23:39:14 -04:00
2020-10-04 15:50:15 -04:00
import java.util.* ;
2022-04-01 15:49:46 -05:00
import net.minecraft.data.BuiltinRegistries ;
2021-07-17 00:08:49 -05:00
import net.minecraft.world.level.block.AirBlock ;
import net.minecraft.world.level.block.Block ;
import net.minecraft.world.level.block.state.BlockState ;
import net.minecraft.world.level.material.Material ;
import net.minecraft.world.item.enchantment.Enchantment ;
import net.minecraft.world.entity.EntityType ;
import net.minecraft.world.entity.ai.attributes.Attribute ;
import net.minecraft.world.entity.ai.attributes.DefaultAttributes ;
import net.minecraft.world.entity.ai.memory.MemoryModuleType ;
import net.minecraft.world.entity.schedule.Activity ;
import net.minecraft.world.entity.schedule.Schedule ;
import net.minecraft.world.entity.ai.sensing.SensorType ;
import net.minecraft.world.entity.decoration.Motive ;
import net.minecraft.world.entity.npc.VillagerProfession ;
import net.minecraft.world.level.material.Fluid ;
import net.minecraft.world.inventory.MenuType ;
import net.minecraft.world.item.BlockItem ;
import net.minecraft.world.item.Item ;
import net.minecraft.world.item.crafting.RecipeSerializer ;
import net.minecraft.network.syncher.EntityDataSerializer ;
import net.minecraft.core.particles.ParticleType ;
import net.minecraft.world.effect.MobEffect ;
import net.minecraft.world.item.alchemy.Potion ;
import net.minecraft.world.level.block.state.StateDefinition ;
2019-06-09 03:23:00 -04:00
import net.minecraft.stats.StatType ;
2021-07-17 00:08:49 -05:00
import net.minecraft.world.level.block.entity.BlockEntityType ;
import net.minecraft.core.DefaultedRegistry ;
import net.minecraft.core.Registry ;
import net.minecraft.core.MappedRegistry ;
import net.minecraft.world.entity.ai.village.poi.PoiType ;
import net.minecraft.world.level.biome.Biome ;
import net.minecraft.world.level.chunk.ChunkStatus ;
import net.minecraft.world.level.levelgen.DebugLevelSource ;
import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProviderType ;
import net.minecraft.world.level.levelgen.carver.WorldCarver ;
import net.minecraft.world.level.levelgen.feature.Feature ;
import net.minecraft.world.level.levelgen.feature.StructureFeature ;
import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacerType ;
import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecoratorType ;
2017-06-19 15:02:18 -07:00
import net.minecraftforge.common.MinecraftForge ;
2020-02-27 00:13:36 -06:00
import net.minecraftforge.common.loot.GlobalLootModifierSerializer ;
2021-07-17 00:08:49 -05:00
import net.minecraftforge.common.util.LogMessageAdapter ;
2021-11-26 18:57:41 +00:00
import net.minecraftforge.common.world.ForgeWorldPreset ;
2017-06-19 15:02:18 -07:00
import net.minecraftforge.event.RegistryEvent ;
import net.minecraftforge.event.RegistryEvent.MissingMappings ;
2022-04-01 15:49:46 -05:00
import net.minecraftforge.fml.ModLoader ;
2019-02-13 21:06:39 -05:00
import net.minecraftforge.fml.ModLoadingContext ;
2021-07-17 00:08:49 -05:00
import net.minecraftforge.fml.IModStateTransition ;
import net.minecraftforge.fml.StartupMessageManager ;
import net.minecraftforge.fml.util.EnhancedRuntimeException ;
import net.minecraftforge.fml.util.thread.EffectiveSide ;
2019-09-06 23:39:14 -04:00
2019-01-11 23:52:30 +01:00
import org.apache.commons.lang3.Validate ;
import org.apache.logging.log4j.LogManager ;
import org.apache.logging.log4j.Logger ;
2017-06-19 15:02:18 -07:00
2019-01-11 23:52:30 +01:00
import javax.annotation.Nullable ;
2019-09-06 23:39:14 -04:00
2017-07-05 14:40:43 -07:00
import java.lang.reflect.Field ;
2020-10-04 15:50:15 -04:00
import java.util.concurrent.CompletableFuture ;
import java.util.concurrent.Executor ;
2017-06-20 18:39:55 -07:00
import java.util.function.BiConsumer ;
2020-09-03 12:08:59 -04:00
import java.util.function.Function ;
2017-06-19 15:02:18 -07:00
import java.util.stream.Collectors ;
2020-08-30 21:39:06 -04:00
import java.util.stream.Stream ;
2017-06-19 15:02:18 -07:00
2019-01-27 00:06:57 -05:00
import static net.minecraftforge.registries.ForgeRegistry.REGISTRIES ;
2020-08-13 00:13:48 -07:00
import static net.minecraftforge.registries.ForgeRegistries.Keys.* ;
2019-01-26 22:18:28 -05:00
2021-07-17 00:08:49 -05:00
import net.minecraft.core.IdMapper ;
import net.minecraft.resources.ResourceKey ;
import net.minecraft.resources.ResourceLocation ;
import net.minecraft.sounds.SoundEvent ;
2021-03-09 13:37:23 -08:00
2017-06-19 15:02:18 -07:00
/**
* INTERNAL ONLY
* MODDERS SHOULD HAVE NO REASON TO USE THIS CLASS
*/
public class GameData
{
2018-08-27 13:10:07 -04:00
private static final Logger LOGGER = LogManager . getLogger ();
2019-05-23 16:02:15 -07:00
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.
2017-06-19 15:02:18 -07:00
2019-06-09 03:23:00 -04:00
private static final ResourceLocation BLOCK_TO_ITEM = new ResourceLocation ( "minecraft:blocktoitemmap" );
2017-06-19 15:02:18 -07:00
private static final ResourceLocation BLOCKSTATE_TO_ID = new ResourceLocation ( "minecraft:blockstatetoid" );
2020-12-28 15:17:51 -05:00
private static final ResourceLocation BLOCKSTATE_TO_POINT_OF_INTEREST_TYPE = new ResourceLocation ( "minecraft:blockstatetopointofinteresttype" );
2019-06-09 03:23:00 -04:00
private static final ResourceLocation SERIALIZER_TO_ENTRY = new ResourceLocation ( "forge:serializer_to_entry" );
2019-09-06 23:39:14 -04:00
private static final ResourceLocation STRUCTURES = new ResourceLocation ( "minecraft:structures" );
2019-04-11 13:33:12 +01:00
2017-06-19 15:02:18 -07:00
private static boolean hasInit = false ;
private static final boolean DISABLE_VANILLA_REGISTRIES = Boolean . parseBoolean ( System . getProperty ( "forge.disableVanillaGameData" , "false" )); // Use for unit tests/debugging
2017-06-20 18:39:55 -07:00
private static final BiConsumer < ResourceLocation , ForgeRegistry <?>> LOCK_VANILLA = ( name , reg ) -> reg . slaves . values (). stream (). filter ( o -> o instanceof ILockableRegistry ). forEach ( o -> (( ILockableRegistry ) o ). lock ());
2017-06-19 15:02:18 -07:00
static {
init ();
}
public static void init ()
{
2019-01-27 00:06:57 -05:00
if ( DISABLE_VANILLA_REGISTRIES )
2017-06-19 15:02:18 -07:00
{
2019-01-27 00:06:57 -05:00
LOGGER . warn ( REGISTRIES , "DISABLING VANILLA REGISTRY CREATION AS PER SYSTEM VARIABLE SETTING! forge.disableVanillaGameData" );
2017-06-19 15:02:18 -07:00
return ;
}
if ( hasInit )
return ;
hasInit = true ;
2020-06-19 10:58:45 -04:00
2019-06-09 03:23:00 -04:00
// Game objects
2022-03-01 14:59:27 -06:00
makeRegistry ( BLOCKS , Block . class , "air" ). addCallback ( BlockCallbacks . INSTANCE ). legacyName ( "blocks" ). vanillaHolder ( Block :: builtInRegistryHolder ). create ();
makeRegistry ( FLUIDS , Fluid . class , "empty" ). vanillaHolder ( Fluid :: builtInRegistryHolder ). create ();
makeRegistry ( ITEMS , Item . class , "air" ). addCallback ( ItemCallbacks . INSTANCE ). legacyName ( "items" ). vanillaHolder ( Item :: builtInRegistryHolder ). create ();
2022-03-16 15:36:00 -05:00
makeRegistry ( MOB_EFFECTS , MobEffect . class ). legacyName ( "potions" ). create ();
2020-08-13 00:13:48 -07:00
//makeRegistry(BIOMES, Biome.class).legacyName("biomes").create();
makeRegistry ( SOUND_EVENTS , SoundEvent . class ). legacyName ( "soundevents" ). create ();
2022-03-16 15:36:00 -05:00
makeRegistry ( POTIONS , Potion . class , "empty" ). legacyName ( "potiontypes" ). create ();
makeRegistry ( ENCHANTMENTS , Enchantment . class ). legacyName ( "enchantments" ). create ();
2022-03-01 14:59:27 -06:00
makeRegistry ( ENTITY_TYPES , c ( EntityType . class ), "pig" ). legacyName ( "entities" ). vanillaHolder ( EntityType :: builtInRegistryHolder ). create ();
2022-03-16 15:36:00 -05:00
makeRegistry ( BLOCK_ENTITY_TYPES , c ( BlockEntityType . class )). disableSaving (). legacyName ( "blockentities" ). create ();
2020-08-13 00:13:48 -07:00
makeRegistry ( PARTICLE_TYPES , c ( ParticleType . class )). disableSaving (). create ();
2021-07-17 00:08:49 -05:00
makeRegistry ( CONTAINER_TYPES , c ( MenuType . class )). disableSaving (). create ();
makeRegistry ( PAINTING_TYPES , Motive . class , "kebab" ). create ();
makeRegistry ( RECIPE_SERIALIZERS , c ( RecipeSerializer . class )). disableSaving (). create ();
2020-06-23 20:56:24 -04:00
makeRegistry ( ATTRIBUTES , Attribute . class ). onValidate ( AttributeCallbacks . INSTANCE ). disableSaving (). disableSync (). create ();
2020-08-13 00:13:48 -07:00
makeRegistry ( STAT_TYPES , c ( StatType . class )). create ();
2020-06-19 10:58:45 -04:00
2019-06-09 03:23:00 -04:00
// Villagers
2020-08-13 00:13:48 -07:00
makeRegistry ( VILLAGER_PROFESSIONS , VillagerProfession . class , "none" ). create ();
2021-07-17 00:08:49 -05:00
makeRegistry ( POI_TYPES , PoiType . class , "unemployed" ). addCallback ( PointOfInterestTypeCallbacks . INSTANCE ). disableSync (). create ();
2020-08-13 00:13:48 -07:00
makeRegistry ( MEMORY_MODULE_TYPES , c ( MemoryModuleType . class ), "dummy" ). disableSync (). create ();
makeRegistry ( SENSOR_TYPES , c ( SensorType . class ), "dummy" ). disableSaving (). disableSync (). create ();
2019-06-09 03:23:00 -04:00
makeRegistry ( SCHEDULES , Schedule . class ). disableSaving (). disableSync (). create ();
makeRegistry ( ACTIVITIES , Activity . class ). disableSaving (). disableSync (). create ();
// Worldgen
2020-08-13 00:13:48 -07:00
makeRegistry ( WORLD_CARVERS , c ( WorldCarver . class )). disableSaving (). disableSync (). create ();
2021-02-14 22:05:11 -05:00
makeRegistry ( FEATURES , c ( Feature . class )). addCallback ( FeatureCallbacks . INSTANCE ). disableSaving (). disableSync (). create ();
2020-08-13 00:13:48 -07:00
makeRegistry ( CHUNK_STATUS , ChunkStatus . class , "empty" ). disableSaving (). disableSync (). create ();
2022-03-16 15:36:00 -05:00
makeRegistry ( STRUCTURE_FEATURES , c ( StructureFeature . class )). disableSaving (). disableSync (). create ();
2020-08-13 00:13:48 -07:00
makeRegistry ( BLOCK_STATE_PROVIDER_TYPES , c ( BlockStateProviderType . class )). disableSaving (). disableSync (). create ();
makeRegistry ( FOLIAGE_PLACER_TYPES , c ( FoliagePlacerType . class )). disableSaving (). disableSync (). create ();
makeRegistry ( TREE_DECORATOR_TYPES , c ( TreeDecoratorType . class )). disableSaving (). disableSync (). create ();
2020-05-23 13:42:56 -04:00
2020-08-26 09:49:34 -07:00
// Dynamic Worldgen
2021-02-14 22:05:11 -05:00
makeRegistry ( BIOMES , Biome . class ). disableSync (). create ();
2022-03-16 15:36:00 -05:00
}
2020-08-26 09:49:34 -07:00
2022-03-16 15:36:00 -05:00
static RegistryBuilder < DataSerializerEntry > getDataSerializersRegistryBuilder ()
{
return makeRegistry ( DATA_SERIALIZERS , DataSerializerEntry . class , 256 /*vanilla space*/ , MAX_VARINT ). disableSaving (). disableOverrides ()
. addCallback ( SerializerCallbacks . INSTANCE );
}
static RegistryBuilder < GlobalLootModifierSerializer <?>> getGLMSerializersRegistryBuilder ()
{
return makeRegistry ( LOOT_MODIFIER_SERIALIZERS , c ( GlobalLootModifierSerializer . class )). disableSaving (). disableSync ();
2019-05-23 16:02:15 -07:00
}
2022-03-16 15:36:00 -05:00
static RegistryBuilder < ForgeWorldPreset > getWorldTypesRegistryBuilder ()
{
return makeRegistry ( WORLD_TYPES , ForgeWorldPreset . class ). disableSaving (). disableSync ();
}
2020-08-13 00:13:48 -07:00
@SuppressWarnings ( "unchecked" ) //Ugly hack to let us pass in a typed Class object. Remove when we remove type specific references.
2022-03-16 15:36:00 -05:00
static < T > Class < T > c ( Class <?> cls ) { return ( Class < T > ) cls ; }
2019-05-23 16:02:15 -07:00
2021-07-17 00:08:49 -05:00
private static < T extends IForgeRegistryEntry < T >> RegistryBuilder < T > makeRegistry ( ResourceKey <? extends Registry < T >> key , Class < T > type )
2017-06-19 15:02:18 -07:00
{
2022-03-16 15:36:00 -05:00
return new RegistryBuilder < T > (). setName ( key . location ()). setType ( type ). setMaxID ( MAX_VARINT ). hasWrapper ();
2017-06-19 15:02:18 -07:00
}
2021-07-17 00:08:49 -05:00
private static < T extends IForgeRegistryEntry < T >> RegistryBuilder < T > makeRegistry ( ResourceKey <? extends Registry < T >> key , Class < T > type , int min , int max )
2019-04-11 13:33:12 +01:00
{
2021-03-09 13:37:23 -08:00
return new RegistryBuilder < T > (). setName ( key . location ()). setType ( type ). setIDRange ( min , max ). hasWrapper ();
2019-04-11 13:33:12 +01:00
}
2021-07-17 00:08:49 -05:00
private static < T extends IForgeRegistryEntry < T >> RegistryBuilder < T > makeRegistry ( ResourceKey <? extends Registry < T >> key , Class < T > type , String _default )
2017-06-19 15:02:18 -07:00
{
2021-03-09 13:37:23 -08:00
return new RegistryBuilder < T > (). setName ( key . location ()). setType ( type ). setMaxID ( MAX_VARINT ). hasWrapper (). setDefaultKey ( new ResourceLocation ( _default ));
2017-06-19 15:02:18 -07:00
}
2021-07-17 00:08:49 -05:00
public static < T extends IForgeRegistryEntry < T >> MappedRegistry < T > getWrapper ( ResourceKey <? extends Registry < T >> key , Lifecycle lifecycle )
2017-06-19 15:02:18 -07:00
{
2020-08-13 00:13:48 -07:00
IForgeRegistry < T > reg = RegistryManager . ACTIVE . getRegistry ( key );
Validate . notNull ( reg , "Attempted to get vanilla wrapper for unknown registry: " + key . toString ());
2017-06-19 15:02:18 -07:00
@SuppressWarnings ( "unchecked" )
2021-07-17 00:08:49 -05:00
MappedRegistry < T > ret = reg . getSlaveMap ( NamespacedWrapper . Factory . ID , NamespacedWrapper . class );
2020-08-13 00:13:48 -07:00
Validate . notNull ( ret , "Attempted to get vanilla wrapper for registry created incorrectly: " + key . toString ());
2017-06-19 15:02:18 -07:00
return ret ;
}
2021-07-17 00:08:49 -05:00
public static < T extends IForgeRegistryEntry < T >> DefaultedRegistry < T > getWrapper ( ResourceKey <? extends Registry < T >> key , Lifecycle lifecycle , String defKey )
2017-06-19 15:02:18 -07:00
{
2020-08-13 00:13:48 -07:00
IForgeRegistry < T > reg = RegistryManager . ACTIVE . getRegistry ( key );
Validate . notNull ( reg , "Attempted to get vanilla wrapper for unknown registry: " + key . toString ());
2017-06-19 15:02:18 -07:00
@SuppressWarnings ( "unchecked" )
2020-08-13 00:13:48 -07:00
DefaultedRegistry < T > ret = reg . getSlaveMap ( NamespacedDefaultedWrapper . Factory . ID , NamespacedDefaultedWrapper . class );
Validate . notNull ( ret , "Attempted to get vanilla wrapper for registry created incorrectly: " + key . toString ());
2017-06-19 15:02:18 -07:00
return ret ;
}
@SuppressWarnings ( "unchecked" )
2018-09-10 13:08:35 -07:00
public static Map < Block , Item > getBlockItemMap ()
2017-06-19 15:02:18 -07:00
{
2022-03-16 15:36:00 -05:00
return RegistryManager . ACTIVE . getRegistry ( ITEMS ). getSlaveMap ( BLOCK_TO_ITEM , Map . class );
2017-06-19 15:02:18 -07:00
}
@SuppressWarnings ( "unchecked" )
2021-07-17 00:08:49 -05:00
public static IdMapper < BlockState > getBlockStateIDMap ()
2017-06-19 15:02:18 -07:00
{
2022-03-16 15:36:00 -05:00
return RegistryManager . ACTIVE . getRegistry ( BLOCKS ). getSlaveMap ( BLOCKSTATE_TO_ID , IdMapper . class );
2017-06-19 15:02:18 -07:00
}
2021-02-15 17:24:35 -08:00
2020-12-28 15:17:51 -05:00
@SuppressWarnings ( "unchecked" )
2021-07-17 00:08:49 -05:00
public static Map < BlockState , PoiType > getBlockStatePointOfInterestTypeMap ()
2020-12-28 15:17:51 -05:00
{
2022-03-16 15:36:00 -05:00
return RegistryManager . ACTIVE . getRegistry ( POI_TYPES ). getSlaveMap ( BLOCKSTATE_TO_POINT_OF_INTEREST_TYPE , Map . class );
2020-12-28 15:17:51 -05:00
}
2017-06-19 15:02:18 -07:00
2019-04-11 13:33:12 +01:00
@SuppressWarnings ( "unchecked" )
2021-07-17 00:08:49 -05:00
public static Map < EntityDataSerializer <?> , DataSerializerEntry > getSerializerMap ()
2019-04-11 13:33:12 +01:00
{
2022-03-16 15:36:00 -05:00
ForgeRegistry < DataSerializerEntry > registry = RegistryManager . ACTIVE . getRegistry ( DATA_SERIALIZERS );
return registry == null ? null : registry . getSlaveMap ( SERIALIZER_TO_ENTRY , Map . class );
2019-04-11 13:33:12 +01:00
}
2020-06-19 10:58:45 -04:00
2019-09-06 23:39:14 -04:00
@SuppressWarnings ( "unchecked" )
2021-07-17 00:08:49 -05:00
public static BiMap < String , StructureFeature <?>> getStructureMap ()
2019-09-06 23:39:14 -04:00
{
2022-03-16 15:36:00 -05:00
return ( BiMap < String , StructureFeature <?>> ) RegistryManager . ACTIVE . getRegistry ( FEATURES ). getSlaveMap ( STRUCTURES , BiMap . class );
2019-09-06 23:39:14 -04:00
}
2019-04-11 13:33:12 +01:00
2017-06-19 15:02:18 -07:00
public static < K extends IForgeRegistryEntry < K >> K register_impl ( K value )
{
Validate . notNull ( value , "Attempted to register a null object" );
2022-02-15 18:27:10 +01:00
Validate . notNull ( value . getRegistryName (), String . format ( Locale . ENGLISH , "Attempt to register object without having set a registry name %s (type %s)" , value , value . getClass (). getName ()));
2018-08-27 13:10:07 -04:00
final IForgeRegistry < K > registry = RegistryManager . ACTIVE . getRegistry ( value . getRegistryType ());
2017-06-19 15:02:18 -07:00
Validate . notNull ( registry , "Attempted to registry object without creating registry first: " + value . getRegistryType (). getName ());
registry . register ( value );
return value ;
}
@SuppressWarnings ({ "unchecked" , "rawtypes" })
public static void vanillaSnapshot ()
{
2019-01-27 00:06:57 -05:00
LOGGER . debug ( REGISTRIES , "Creating vanilla freeze snapshot" );
2018-09-05 20:06:18 -07:00
for ( Map . Entry < ResourceLocation , ForgeRegistry <? extends IForgeRegistryEntry <?>>> r : RegistryManager . ACTIVE . registries . entrySet ())
2017-06-19 15:02:18 -07:00
{
final Class <? extends IForgeRegistryEntry > clazz = RegistryManager . ACTIVE . getSuperType ( r . getKey ());
loadRegistry ( r . getKey (), RegistryManager . ACTIVE , RegistryManager . VANILLA , clazz , true );
}
2017-06-20 18:39:55 -07:00
RegistryManager . VANILLA . registries . forEach (( name , reg ) ->
{
reg . validateContent ( name );
reg . freeze ();
});
RegistryManager . VANILLA . registries . forEach ( LOCK_VANILLA );
RegistryManager . ACTIVE . registries . forEach ( LOCK_VANILLA );
2019-01-27 00:06:57 -05:00
LOGGER . debug ( REGISTRIES , "Vanilla freeze snapshot created" );
2017-06-19 15:02:18 -07:00
}
2022-03-01 14:59:27 -06:00
public static void unfreezeData ()
{
LOGGER . debug ( REGISTRIES , "Unfreezing vanilla registries" );
Registry . REGISTRY . stream (). filter ( r -> r instanceof MappedRegistry ). forEach ( r -> (( MappedRegistry <?> ) r ). unfreeze ());
}
2017-06-19 15:02:18 -07:00
@SuppressWarnings ({ "rawtypes" , "unchecked" })
public static void freezeData ()
{
2019-01-27 00:06:57 -05:00
LOGGER . debug ( REGISTRIES , "Freezing registries" );
2022-03-01 14:59:27 -06:00
Registry . REGISTRY . stream (). filter ( r -> r instanceof MappedRegistry ). forEach ( r -> (( MappedRegistry <?> ) r ). freeze ());
2017-06-19 15:02:18 -07:00
for ( Map . Entry < ResourceLocation , ForgeRegistry <? extends IForgeRegistryEntry <?>>> r : RegistryManager . ACTIVE . registries . entrySet ())
{
final Class <? extends IForgeRegistryEntry > clazz = RegistryManager . ACTIVE . getSuperType ( r . getKey ());
loadRegistry ( r . getKey (), RegistryManager . ACTIVE , RegistryManager . FROZEN , clazz , true );
}
2017-06-20 18:39:55 -07:00
RegistryManager . FROZEN . registries . forEach (( name , reg ) ->
{
reg . validateContent ( name );
reg . freeze ();
});
2019-01-11 23:52:30 +01:00
RegistryManager . ACTIVE . registries . forEach (( name , reg ) -> {
reg . freeze ();
reg . bake ();
2019-01-27 00:06:57 -05:00
reg . dump ( name );
2019-01-11 23:52:30 +01:00
});
2017-07-13 14:45:51 -07:00
2018-08-29 21:30:15 -04:00
// the id mapping is finalized, no ids actually changed but this is a good place to tell everyone to 'bake' their stuff.
2019-03-25 21:41:28 -04:00
fireRemapEvent ( ImmutableMap . of (), true );
2017-07-13 14:45:51 -07:00
2019-01-27 00:06:57 -05:00
LOGGER . debug ( REGISTRIES , "All registries frozen" );
2017-06-19 15:02:18 -07:00
}
2020-10-18 13:37:28 -04:00
public static void revertToFrozen () {
revertTo ( RegistryManager . FROZEN , true );
}
2017-06-19 15:02:18 -07:00
@SuppressWarnings ({ "unchecked" , "rawtypes" })
2020-10-18 13:37:28 -04:00
public static void revertTo ( final RegistryManager target , boolean fireEvents )
2017-06-19 15:02:18 -07:00
{
2020-10-18 13:37:28 -04:00
if ( target . registries . isEmpty ())
2017-06-19 15:02:18 -07:00
{
2020-10-18 13:37:28 -04:00
LOGGER . warn ( REGISTRIES , "Can't revert to {} GameData state without a valid snapshot." , target . getName ());
2017-06-19 15:02:18 -07:00
return ;
}
2017-06-23 00:58:00 -07:00
RegistryManager . ACTIVE . registries . forEach (( name , reg ) -> reg . resetDelegates ());
2017-06-19 15:02:18 -07:00
2020-10-18 13:37:28 -04:00
LOGGER . debug ( REGISTRIES , "Reverting to {} data state." , target . getName ());
2018-09-05 20:06:18 -07:00
for ( Map . Entry < ResourceLocation , ForgeRegistry <? extends IForgeRegistryEntry <?>>> r : RegistryManager . ACTIVE . registries . entrySet ())
2017-06-19 15:02:18 -07:00
{
final Class <? extends IForgeRegistryEntry > clazz = RegistryManager . ACTIVE . getSuperType ( r . getKey ());
2020-10-18 13:37:28 -04:00
loadRegistry ( r . getKey (), target , RegistryManager . ACTIVE , clazz , true );
2017-06-19 15:02:18 -07:00
}
2019-01-11 23:52:30 +01:00
RegistryManager . ACTIVE . registries . forEach (( name , reg ) -> reg . bake ());
2017-06-19 15:02:18 -07:00
// the id mapping has reverted, fire remap events for those that care about id changes
2020-10-18 13:37:28 -04:00
if ( fireEvents ) {
2020-10-29 01:11:57 +01:00
fireRemapEvent ( ImmutableMap . of (), true );
2020-10-18 13:37:28 -04:00
ObjectHolderRegistry . applyObjectHolders ();
}
2017-06-19 15:02:18 -07:00
// the id mapping has reverted, ensure we sync up the object holders
2020-10-18 13:37:28 -04:00
LOGGER . debug ( REGISTRIES , "{} state restored." , target . getName ());
2017-06-19 15:02:18 -07:00
}
@SuppressWarnings ({ "rawtypes" , "unchecked" })
public static void revert ( RegistryManager state , ResourceLocation registry , boolean lock )
{
2019-01-27 00:06:57 -05:00
LOGGER . debug ( REGISTRIES , "Reverting {} to {}" , registry , state . getName ());
2017-06-19 15:02:18 -07:00
final Class <? extends IForgeRegistryEntry > clazz = RegistryManager . ACTIVE . getSuperType ( registry );
2017-10-31 14:29:35 -04:00
loadRegistry ( registry , state , RegistryManager . ACTIVE , clazz , lock );
2019-01-27 00:06:57 -05:00
LOGGER . debug ( REGISTRIES , "Reverting complete" );
2017-06-19 15:02:18 -07:00
}
2021-07-17 00:08:49 -05:00
public static Stream < IModStateTransition . EventGenerator <?>> generateRegistryEvents () {
2020-08-30 21:39:06 -04:00
List < ResourceLocation > keys = Lists . newArrayList ( RegistryManager . ACTIVE . registries . keySet ());
keys . sort (( o1 , o2 ) -> String . valueOf ( o1 ). compareToIgnoreCase ( String . valueOf ( o2 )));
//Move Blocks to first, and Items to second.
2021-03-09 13:37:23 -08:00
keys . remove ( BLOCKS . location ());
keys . remove ( ITEMS . location ());
2020-08-30 21:39:06 -04:00
2021-03-09 13:37:23 -08:00
keys . add ( 0 , BLOCKS . location ());
keys . add ( 1 , ITEMS . location ());
2020-08-30 21:39:06 -04:00
2020-10-04 15:50:15 -04:00
final Function < ResourceLocation , ? extends RegistryEvent . Register <?>> registerEventGenerator = rl -> RegistryManager . ACTIVE . getRegistry ( rl ). getRegisterEvent ( rl );
2021-07-17 00:08:49 -05:00
return keys . stream (). map ( rl -> IModStateTransition . EventGenerator . fromFunction ( mc -> registerEventGenerator . apply ( rl )));
2020-08-30 21:39:06 -04:00
}
2021-07-17 00:08:49 -05:00
public static CompletableFuture < List < Throwable >> preRegistryEventDispatch ( final Executor executor , final IModStateTransition . EventGenerator <? extends RegistryEvent . Register <?>> eventGenerator ) {
2020-10-04 15:50:15 -04:00
return CompletableFuture . runAsync (() -> {
final RegistryEvent . Register <?> event = eventGenerator . apply ( null );
final ResourceLocation rl = event . getName ();
ForgeRegistry <?> fr = ( ForgeRegistry <?> ) event . getRegistry ();
StartupMessageManager . modLoaderConsumer (). ifPresent ( s -> s . accept ( "REGISTERING " + rl ));
fr . unfreeze ();
}, executor ). thenApply ( v -> Collections . emptyList ());
}
2020-10-09 12:56:17 -07:00
2021-07-17 00:08:49 -05:00
public static CompletableFuture < List < Throwable >> postRegistryEventDispatch ( final Executor executor , final IModStateTransition . EventGenerator <? extends RegistryEvent . Register <?>> eventGenerator ) {
2020-10-04 15:50:15 -04:00
return CompletableFuture . runAsync (() -> {
final RegistryEvent . Register <?> event = eventGenerator . apply ( null );
final ResourceLocation rl = event . getName ();
ForgeRegistry <?> fr = ( ForgeRegistry <?> ) event . getRegistry ();
2020-08-30 21:39:06 -04:00
fr . freeze ();
2022-04-01 15:49:46 -05:00
applyHolderLookups ( rl );
2020-10-18 13:37:28 -04:00
}, executor ). handle (( v , t ) -> t != null ? Collections . singletonList ( t ): Collections . emptyList ());
}
2022-04-01 15:49:46 -05:00
private static void applyHolderLookups ( ResourceLocation registryName )
{
LOGGER . debug ( REGISTRIES , "Applying holder lookups: {}" , registryName );
ObjectHolderRegistry . applyObjectHolders ( registryName :: equals );
LOGGER . debug ( REGISTRIES , "Holder lookups applied: {}" , registryName );
}
2021-02-15 17:24:35 -08:00
@SuppressWarnings ( "deprecation" )
2020-10-18 13:37:28 -04:00
public static CompletableFuture < List < Throwable >> checkForRevertToVanilla ( final Executor executor , final CompletableFuture < List < Throwable >> listCompletableFuture ) {
2020-11-01 19:51:56 -05:00
return listCompletableFuture . whenCompleteAsync (( errors , except ) -> {
if ( except != null ) {
LOGGER . fatal ( "Detected errors during registry event dispatch, rolling back to VANILLA state" );
2020-10-18 13:37:28 -04:00
revertTo ( RegistryManager . VANILLA , false );
2020-11-01 19:51:56 -05:00
LOGGER . fatal ( "Detected errors during registry event dispatch, roll back to VANILLA complete" );
2021-02-15 17:24:35 -08:00
} else {
2022-04-01 15:49:46 -05:00
RegistryManager . getVanillaRegistryKeys (). forEach ( registryName -> {
Registry <?> registry = Registry . REGISTRY . get ( registryName );
if ( registry == null )
return ;
postVanillaRegisterEvent ( registry );
});
BuiltinRegistries . REGISTRY . forEach ( GameData :: postVanillaRegisterEvent );
2021-02-15 17:24:35 -08:00
net . minecraftforge . common . ForgeHooks . modifyAttributes ();
2020-10-18 13:37:28 -04:00
}
}, executor );
2020-08-30 21:39:06 -04:00
}
2022-04-01 15:49:46 -05:00
@SuppressWarnings ( "removal" )
private static void postVanillaRegisterEvent ( Registry <?> registry )
{
if ( RegistryManager . ACTIVE . getRegistry ( registry . key (). location ()) != null )
return ;
ModLoader . get (). postEvent ( new VanillaRegisterEvent ( registry ));
applyHolderLookups ( registry . key (). location ());
}
2017-06-19 15:02:18 -07:00
//Lets us clear the map so we can rebuild it.
2021-07-17 00:08:49 -05:00
private static class ClearableObjectIntIdentityMap < I > extends IdMapper < I >
2017-06-19 15:02:18 -07:00
{
void clear ()
{
2021-03-09 13:37:23 -08:00
this . tToId . clear ();
this . idToT . clear ();
2019-01-11 23:52:30 +01:00
this . nextId = 0 ;
2017-06-19 15:02:18 -07:00
}
2019-01-04 01:36:32 +00:00
void remove ( I key )
{
2021-03-09 13:37:23 -08:00
Integer prev = this . tToId . remove ( key );
2019-01-04 01:36:32 +00:00
if ( prev != null )
{
2021-03-09 13:37:23 -08:00
this . idToT . set ( prev , null );
2019-01-04 01:36:32 +00:00
}
}
2017-06-19 15:02:18 -07:00
}
2019-01-11 23:52:30 +01:00
private static class BlockCallbacks implements IForgeRegistry . AddCallback < Block > , IForgeRegistry . ClearCallback < Block > , IForgeRegistry . BakeCallback < Block > , IForgeRegistry . CreateCallback < Block > , IForgeRegistry . DummyFactory < Block >
2017-06-19 15:02:18 -07:00
{
static final BlockCallbacks INSTANCE = new BlockCallbacks ();
@Override
2017-06-25 20:45:48 -07:00
public void onAdd ( IForgeRegistryInternal < Block > owner , RegistryManager stage , int id , Block block , @Nullable Block oldBlock )
2017-06-19 15:02:18 -07:00
{
2019-01-11 23:52:30 +01:00
if ( oldBlock != null )
{
2021-07-17 00:08:49 -05:00
StateDefinition < Block , BlockState > oldContainer = oldBlock . getStateDefinition ();
StateDefinition < Block , BlockState > newContainer = block . getStateDefinition ();
2019-01-11 23:52:30 +01:00
// Test vanilla blockstates, if the number matches, make sure they also match in their string representations
2019-07-23 04:23:20 +02:00
if ( block . getRegistryName (). getNamespace (). equals ( "minecraft" ) && ! oldContainer . getProperties (). equals ( newContainer . getProperties ()))
2019-01-11 23:52:30 +01:00
{
String oldSequence = oldContainer . getProperties (). stream ()
2022-02-15 18:27:10 +01:00
. map ( s -> String . format ( Locale . ENGLISH , "%s={%s}" , s . getName (),
2021-03-09 13:37:23 -08:00
s . getPossibleValues (). stream (). map ( Object :: toString ). collect ( Collectors . joining ( "," ))))
2019-01-11 23:52:30 +01:00
. collect ( Collectors . joining ( ";" ));
String newSequence = newContainer . getProperties (). stream ()
2022-02-15 18:27:10 +01:00
. map ( s -> String . format ( Locale . ENGLISH , "%s={%s}" , s . getName (),
2021-03-09 13:37:23 -08:00
s . getPossibleValues (). stream (). map ( Object :: toString ). collect ( Collectors . joining ( "," ))))
2019-01-11 23:52:30 +01:00
. collect ( Collectors . joining ( ";" ));
2021-07-17 00:08:49 -05:00
LOGGER . error ( REGISTRIES ,() -> LogMessageAdapter . adapt ( sb -> {
2019-01-27 00:06:57 -05:00
sb . append ( "Registry replacements for vanilla block '" ). append ( block . getRegistryName ()).
append ( "' must not change the number or order of blockstates.\n" );
sb . append ( "\tOld: " ). append ( oldSequence ). append ( '\n' );
sb . append ( "\tNew: " ). append ( newSequence );
}));
2019-01-11 23:52:30 +01:00
throw new RuntimeException ( "Invalid vanilla replacement. See log for details." );
}
}
2017-06-19 15:02:18 -07:00
}
@Override
public void onClear ( IForgeRegistryInternal < Block > owner , RegistryManager stage )
{
2018-11-16 23:15:39 -08:00
owner . getSlaveMap ( BLOCKSTATE_TO_ID , ClearableObjectIntIdentityMap . class ). clear ();
2017-06-19 15:02:18 -07:00
}
@Override
public void onCreate ( IForgeRegistryInternal < Block > owner , RegistryManager stage )
{
2019-05-23 16:02:15 -07:00
final ClearableObjectIntIdentityMap < BlockState > idMap = new ClearableObjectIntIdentityMap < BlockState > ()
2017-06-19 15:02:18 -07:00
{
@Override
2020-08-13 00:13:48 -07:00
public int getId ( BlockState key )
2017-06-19 15:02:18 -07:00
{
2021-03-09 13:37:23 -08:00
Integer integer = ( Integer ) this . tToId . get ( key );
2017-06-19 15:02:18 -07:00
// 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
2018-11-16 23:15:39 -08:00
//if (integer == null && key != null)
// integer = this.identityMap.get(key.getBlock().getStateFromMeta(key.getBlock().getMetaFromState(key)));
2017-06-19 15:02:18 -07:00
return integer == null ? - 1 : integer . intValue ();
}
};
owner . setSlaveMap ( BLOCKSTATE_TO_ID , idMap );
2018-09-10 13:08:35 -07:00
owner . setSlaveMap ( BLOCK_TO_ITEM , Maps . newHashMap ());
2017-06-19 15:02:18 -07:00
}
@Override
public Block createDummy ( ResourceLocation key )
{
2021-03-09 13:37:23 -08:00
Block ret = new BlockDummyAir ( Block . Properties . of ( Material . AIR ));
2017-08-15 05:10:07 -07:00
GameData . forceRegistryName ( ret , key );
2017-07-05 14:40:43 -07:00
return ret ;
2017-06-20 23:45:32 -07:00
}
2019-01-11 23:52:30 +01:00
@Override
public void onBake ( IForgeRegistryInternal < Block > owner , RegistryManager stage )
{
@SuppressWarnings ( "unchecked" )
2019-05-23 16:02:15 -07:00
ClearableObjectIntIdentityMap < BlockState > blockstateMap = owner . getSlaveMap ( BLOCKSTATE_TO_ID , ClearableObjectIntIdentityMap . class );
2019-01-11 23:52:30 +01:00
for ( Block block : owner )
{
2021-03-09 13:37:23 -08:00
for ( BlockState state : block . getStateDefinition (). getPossibleStates ())
2019-01-11 23:52:30 +01:00
{
blockstateMap . add ( state );
2021-03-09 13:37:23 -08:00
state . initCache ();
2019-01-11 23:52:30 +01:00
}
2019-05-23 16:02:15 -07:00
2019-06-08 10:45:28 -04:00
block . getLootTable ();
2019-01-11 23:52:30 +01:00
}
2021-07-17 00:08:49 -05:00
DebugLevelSource . initValidStates ();
2019-01-11 23:52:30 +01:00
}
2019-05-23 16:02:15 -07:00
private static class BlockDummyAir extends AirBlock //A named class so DummyBlockReplacementTest can detect if its a dummy
2017-06-20 23:45:32 -07:00
{
2019-02-14 15:08:53 -08:00
private BlockDummyAir ( Block . Properties properties )
2017-06-20 23:45:32 -07:00
{
2019-02-14 15:08:53 -08:00
super ( properties );
2018-08-29 21:30:15 -04:00
}
@Override
2021-03-09 13:37:23 -08:00
public String getDescriptionId ()
2018-08-29 21:30:15 -04:00
{
return "block.minecraft.air" ;
2017-06-20 23:45:32 -07:00
}
2017-06-19 15:02:18 -07:00
}
}
private static class ItemCallbacks implements IForgeRegistry . AddCallback < Item > , IForgeRegistry . ClearCallback < Item > , IForgeRegistry . CreateCallback < Item >
{
static final ItemCallbacks INSTANCE = new ItemCallbacks ();
@Override
2017-06-25 20:45:48 -07:00
public void onAdd ( IForgeRegistryInternal < Item > owner , RegistryManager stage , int id , Item item , @Nullable Item oldItem )
2017-06-19 15:02:18 -07:00
{
2019-05-23 16:02:15 -07:00
if ( oldItem instanceof BlockItem )
2019-01-04 01:36:32 +00:00
{
@SuppressWarnings ( "unchecked" )
2019-07-23 04:23:20 +02:00
Map < Block , Item > blockToItem = owner . getSlaveMap ( BLOCK_TO_ITEM , Map . class );
(( BlockItem ) oldItem ). removeFromBlockToItemMap ( blockToItem , item );
2019-01-04 01:36:32 +00:00
}
2019-05-23 16:02:15 -07:00
if ( item instanceof BlockItem )
2017-06-19 15:02:18 -07:00
{
@SuppressWarnings ( "unchecked" )
2018-09-10 13:08:35 -07:00
Map < Block , Item > blockToItem = owner . getSlaveMap ( BLOCK_TO_ITEM , Map . class );
2021-03-09 13:37:23 -08:00
(( BlockItem ) item ). registerBlocks ( blockToItem , item );
2017-06-19 15:02:18 -07:00
}
}
@Override
public void onClear ( IForgeRegistryInternal < Item > owner , RegistryManager stage )
{
2018-09-10 13:08:35 -07:00
owner . getSlaveMap ( BLOCK_TO_ITEM , Map . class ). clear ();
2017-06-19 15:02:18 -07:00
}
@Override
public void onCreate ( IForgeRegistryInternal < Item > owner , RegistryManager stage )
{
// We share the blockItem map between items and blocks registries
2018-09-10 13:08:35 -07:00
Map <? , ?> map = stage . getRegistry ( BLOCKS ). getSlaveMap ( BLOCK_TO_ITEM , Map . class );
2017-06-19 15:02:18 -07:00
owner . setSlaveMap ( BLOCK_TO_ITEM , map );
}
}
2020-06-23 20:56:24 -04:00
private static class AttributeCallbacks implements IForgeRegistry . ValidateCallback < Attribute > {
2017-08-15 05:10:07 -07:00
2020-06-23 20:56:24 -04:00
static final AttributeCallbacks INSTANCE = new AttributeCallbacks ();
2017-06-19 15:02:18 -07:00
@Override
2020-06-23 20:56:24 -04:00
public void onValidate ( IForgeRegistryInternal < Attribute > owner , RegistryManager stage , int id , ResourceLocation key , Attribute obj )
2017-06-19 15:02:18 -07:00
{
2020-10-18 13:37:28 -04:00
// some stuff hard patched in can cause this to derp if it's JUST vanilla, so skip
2021-07-17 00:08:49 -05:00
if ( stage != RegistryManager . VANILLA ) DefaultAttributes . validate ();
2017-06-19 15:02:18 -07:00
}
}
2019-04-11 13:33:12 +01:00
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" )
2021-07-17 00:08:49 -05:00
Map < EntityDataSerializer <?> , DataSerializerEntry > map = owner . getSlaveMap ( SERIALIZER_TO_ENTRY , Map . class );
2019-04-11 13:33:12 +01:00
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 <> ());
}
}
2020-06-19 10:58:45 -04:00
2020-06-24 21:25:55 -04:00
private static class FeatureCallbacks implements IForgeRegistry . ClearCallback < Feature <?>> , IForgeRegistry . CreateCallback < Feature <?>>
2019-09-06 23:39:14 -04:00
{
static final FeatureCallbacks INSTANCE = new FeatureCallbacks ();
2020-06-19 10:58:45 -04:00
2019-09-06 23:39:14 -04:00
@Override
public void onClear ( IForgeRegistryInternal < Feature <?>> owner , RegistryManager stage )
{
owner . getSlaveMap ( STRUCTURES , BiMap . class ). clear ();
}
@Override
public void onCreate ( IForgeRegistryInternal < Feature <?>> owner , RegistryManager stage )
{
owner . setSlaveMap ( STRUCTURES , HashBiMap . create ());
}
}
2019-04-11 13:33:12 +01:00
2021-07-17 00:08:49 -05:00
private static class PointOfInterestTypeCallbacks implements IForgeRegistry . AddCallback < PoiType > , IForgeRegistry . ClearCallback < PoiType > , IForgeRegistry . CreateCallback < PoiType >
2020-12-28 15:17:51 -05:00
{
static final PointOfInterestTypeCallbacks INSTANCE = new PointOfInterestTypeCallbacks ();
2021-02-15 17:24:35 -08:00
2020-12-28 15:17:51 -05:00
@Override
2021-07-17 00:08:49 -05:00
public void onAdd ( IForgeRegistryInternal < PoiType > owner , RegistryManager stage , int id , PoiType obj , @Nullable PoiType oldObj )
2020-12-28 15:17:51 -05:00
{
2021-07-17 00:08:49 -05:00
Map < BlockState , PoiType > map = owner . getSlaveMap ( BLOCKSTATE_TO_POINT_OF_INTEREST_TYPE , Map . class );
2020-12-28 15:17:51 -05:00
if ( oldObj != null )
{
oldObj . getBlockStates (). forEach ( map :: remove );
}
2021-02-15 17:24:35 -08:00
obj . getBlockStates (). forEach (( state ) ->
2020-12-28 15:17:51 -05:00
{
2021-07-17 00:08:49 -05:00
PoiType oldType = map . put ( state , obj );
2020-12-28 15:17:51 -05:00
if ( oldType != null )
{
2022-02-15 18:27:10 +01:00
throw new IllegalStateException ( String . format ( Locale . ENGLISH , "Point of interest types %s and %s both list %s in their blockstates, this is not allowed. Blockstates can only have one point of interest type each." , oldType , obj , state ));
2020-12-28 15:17:51 -05:00
}
});
}
@Override
2021-07-17 00:08:49 -05:00
public void onClear ( IForgeRegistryInternal < PoiType > owner , RegistryManager stage )
2020-12-28 15:17:51 -05:00
{
owner . getSlaveMap ( BLOCKSTATE_TO_POINT_OF_INTEREST_TYPE , Map . class ). clear ();
}
@Override
2021-07-17 00:08:49 -05:00
public void onCreate ( IForgeRegistryInternal < PoiType > owner , RegistryManager stage )
2020-12-28 15:17:51 -05:00
{
owner . setSlaveMap ( BLOCKSTATE_TO_POINT_OF_INTEREST_TYPE , new HashMap <> ());
}
}
2021-02-15 17:24:35 -08:00
2017-06-19 15:02:18 -07:00
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 );
if ( fromRegistry == null )
{
ForgeRegistry < T > toRegistry = to . getRegistry ( registryName );
if ( toRegistry == null )
{
throw new EnhancedRuntimeException ( "Could not find registry to load: " + registryName ){
private static final long serialVersionUID = 1L ;
@Override
protected void printStackTrace ( WrappedPrintStream stream )
{
stream . println ( "Looking For: " + registryName );
stream . println ( "Found From:" );
for ( ResourceLocation name : from . registries . keySet ())
stream . println ( " " + name );
stream . println ( "Found To:" );
for ( ResourceLocation name : to . registries . keySet ())
stream . println ( " " + name );
}
};
}
// We found it in to, so lets trust to's state...
// This happens when connecting to a server that doesn't have this registry.
// Such as a 1.8.0 Forge server with 1.8.8+ Forge.
// We must however, re-fire the callbacks as some internal data may be corrupted {potions}
//TODO: With my rework of how registries add callbacks are done.. I don't think this is necessary.
//fire addCallback for each entry
}
else
{
ForgeRegistry < T > toRegistry = to . getRegistry ( registryName , from );
toRegistry . sync ( registryName , fromRegistry );
if ( freeze )
toRegistry . isFrozen = true ;
}
}
@SuppressWarnings ({ "unchecked" , "rawtypes" })
public static Multimap < ResourceLocation , ResourceLocation > injectSnapshot ( Map < ResourceLocation , ForgeRegistry . Snapshot > snapshot , boolean injectFrozenData , boolean isLocalWorld )
{
2019-01-27 00:06:57 -05:00
LOGGER . info ( REGISTRIES , "Injecting existing registry data into this {} instance" , EffectiveSide . get ());
2017-06-19 15:02:18 -07:00
RegistryManager . ACTIVE . registries . forEach (( name , reg ) -> reg . validateContent ( name ));
RegistryManager . ACTIVE . registries . forEach (( name , reg ) -> reg . dump ( name ));
RegistryManager . ACTIVE . registries . forEach (( name , reg ) -> reg . resetDelegates ());
2020-06-19 10:58:45 -04:00
2019-06-09 03:23:00 -04:00
// Update legacy names
snapshot = snapshot . entrySet (). stream ()
. sorted ( Map . Entry . comparingByKey ()) // FIXME Registries need dependency ordering, this makes sure blocks are done before items (for ItemCallbacks) but it's lazy as hell
. collect ( Collectors . toMap ( e -> RegistryManager . ACTIVE . updateLegacyName ( e . getKey ()), Map . Entry :: getValue , ( k1 , k2 ) -> k1 , LinkedHashMap :: new ));
2017-06-19 15:02:18 -07:00
2019-03-12 04:34:29 +00:00
if ( isLocalWorld )
2017-06-19 15:02:18 -07:00
{
2019-03-12 04:34:29 +00:00
List < ResourceLocation > missingRegs = snapshot . keySet (). stream (). filter ( name -> ! RegistryManager . ACTIVE . registries . containsKey ( name )). collect ( Collectors . toList ());
if ( missingRegs . size () > 0 )
{
2020-05-23 16:00:22 -04:00
String header = "Forge Mod Loader detected missing/unknown registrie(s).\n\n" +
2019-03-12 04:34:29 +00:00
"There are " + missingRegs . size () + " missing registries in this save.\n" +
"If you continue the missing registries will get removed.\n" +
2020-05-23 16:00:22 -04:00
"This may cause issues, it is advised that you create a world backup before continuing.\n\n" ;
StringBuilder text = new StringBuilder ( "Missing Registries:\n" );
2017-06-19 15:02:18 -07:00
2019-03-12 04:34:29 +00:00
for ( ResourceLocation s : missingRegs )
2020-05-23 16:00:22 -04:00
text . append ( s ). append ( "\n" );
2020-11-10 11:13:38 -08:00
LOGGER . warn ( REGISTRIES , header );
LOGGER . warn ( REGISTRIES , text . toString ());
2019-03-12 04:34:29 +00:00
}
2017-06-19 15:02:18 -07:00
}
RegistryManager STAGING = new RegistryManager ( "STAGING" );
final Map < ResourceLocation , Map < ResourceLocation , Integer []>> remaps = Maps . newHashMap ();
final LinkedHashMap < ResourceLocation , Map < ResourceLocation , Integer >> missing = Maps . newLinkedHashMap ();
// Load the snapshot into the "STAGING" registry
2017-06-28 00:14:10 -07:00
snapshot . forEach (( key , value ) ->
2017-06-19 15:02:18 -07:00
{
2017-06-28 00:14:10 -07:00
final Class <? extends IForgeRegistryEntry > clazz = RegistryManager . ACTIVE . getSuperType ( key );
remaps . put ( key , Maps . newLinkedHashMap ());
2020-11-10 11:13:38 -08:00
missing . put ( key , Maps . newLinkedHashMap ());
2017-06-28 00:14:10 -07:00
loadPersistentDataToStagingRegistry ( RegistryManager . ACTIVE , STAGING , remaps . get ( key ), missing . get ( key ), key , value , clazz );
2017-06-19 15:02:18 -07:00
});
2017-06-28 00:14:10 -07:00
snapshot . forEach (( key , value ) ->
2017-06-19 15:02:18 -07:00
{
2017-06-28 00:14:10 -07:00
value . dummied . forEach ( dummy ->
2017-06-19 15:02:18 -07:00
{
2017-06-28 00:14:10 -07:00
Map < ResourceLocation , Integer > m = missing . get ( key );
ForgeRegistry <?> reg = STAGING . getRegistry ( key );
2017-06-19 15:02:18 -07:00
// Currently missing locally, we just inject and carry on
if ( m . containsKey ( dummy ))
{
if ( reg . markDummy ( dummy , m . get ( dummy )))
m . remove ( dummy );
}
else if ( isLocalWorld )
{
2019-01-27 00:06:57 -05:00
LOGGER . debug ( REGISTRIES , "Registry {}: Resuscitating dummy entry {}" , key , dummy );
2017-06-19 15:02:18 -07:00
}
else
{
// The server believes this is a dummy block identity, but we seem to have one locally. This is likely a conflict
// in mod setup - Mark this entry as a dummy
int id = reg . getID ( dummy );
2019-01-27 00:06:57 -05:00
LOGGER . warn ( REGISTRIES , "Registry {}: The ID {} @ {} is currently locally mapped - it will be replaced with a dummy for this session" , dummy , key , id );
2017-06-19 15:02:18 -07:00
reg . markDummy ( dummy , id );
}
});
});
2017-06-28 00:14:10 -07:00
int count = missing . values (). stream (). mapToInt ( Map :: size ). sum ();
2017-06-19 15:02:18 -07:00
if ( count > 0 )
{
2019-01-27 00:06:57 -05:00
LOGGER . debug ( REGISTRIES , "There are {} mappings missing - attempting a mod remap" , count );
2017-06-19 15:02:18 -07:00
Multimap < ResourceLocation , ResourceLocation > defaulted = ArrayListMultimap . create ();
Multimap < ResourceLocation , ResourceLocation > failed = ArrayListMultimap . create ();
missing . entrySet (). stream (). filter ( e -> e . getValue (). size () > 0 ). forEach ( m ->
{
ResourceLocation name = m . getKey ();
ForgeRegistry <?> reg = STAGING . getRegistry ( name );
RegistryEvent . MissingMappings <?> event = reg . getMissingEvent ( name , m . getValue ());
MinecraftForge . EVENT_BUS . post ( event );
2017-09-25 12:56:09 -07:00
List < MissingMappings . Mapping <?>> lst = event . getAllMappings (). stream (). filter ( e -> e . getAction () == MissingMappings . Action . DEFAULT ). sorted (( a , b ) -> a . toString (). compareTo ( b . toString ())). collect ( Collectors . toList ());
2017-06-19 15:02:18 -07:00
if ( ! lst . isEmpty ())
{
2021-07-17 00:08:49 -05:00
LOGGER . error ( REGISTRIES ,() -> LogMessageAdapter . adapt ( sb -> {
2019-02-23 20:42:45 -05:00
sb . append ( "Unidentified mapping from registry " ). append ( name ). append ( '\n' );
2020-10-09 12:56:17 -07:00
lst . stream (). sorted (). forEach ( map -> sb . append ( '\t' ). append ( map . key ). append ( ": " ). append ( map . id ). append ( '\n' ));
2019-01-27 00:06:57 -05:00
}));
2017-06-19 15:02:18 -07:00
}
event . getAllMappings (). stream (). filter ( e -> e . getAction () == MissingMappings . Action . FAIL ). forEach ( fail -> failed . put ( name , fail . key ));
final Class <? extends IForgeRegistryEntry > clazz = RegistryManager . ACTIVE . getSuperType ( name );
2017-08-15 05:10:07 -07:00
processMissing ( clazz , name , STAGING , event , m . getValue (), remaps . get ( name ), defaulted . get ( name ), failed . get ( name ), ! isLocalWorld );
2017-06-19 15:02:18 -07:00
});
if ( ! defaulted . isEmpty () && ! isLocalWorld )
return defaulted ;
if ( ! defaulted . isEmpty ())
{
2020-05-23 16:00:22 -04:00
String header = "Forge Mod Loader detected missing registry entries.\n\n" +
"There are " + defaulted . size () + " missing entries in this save.\n" +
"If you continue the missing entries will get removed.\n" +
"A world backup will be automatically created in your saves directory.\n\n" ;
2017-06-19 15:02:18 -07:00
2020-05-23 16:00:22 -04:00
StringBuilder buf = new StringBuilder ();
2017-06-19 15:02:18 -07:00
defaulted . asMap (). forEach (( name , entries ) ->
{
buf . append ( "Missing " ). append ( name ). append ( ":\n" );
2020-10-09 12:56:17 -07:00
entries . stream (). sorted (( o1 , o2 ) -> o1 . compareNamespaced ( o2 )). forEach ( rl -> buf . append ( " " ). append ( rl ). append ( "\n" ));
2020-05-23 16:00:22 -04:00
buf . append ( "\n" );
2017-06-19 15:02:18 -07:00
});
2020-11-10 11:13:38 -08:00
LOGGER . warn ( REGISTRIES , header );
LOGGER . warn ( REGISTRIES , buf . toString ());
2017-06-19 15:02:18 -07:00
}
if ( ! defaulted . isEmpty ())
{
if ( isLocalWorld )
2019-01-27 00:06:57 -05:00
LOGGER . error ( REGISTRIES , "There are unidentified mappings in this world - we are going to attempt to process anyway" );
2017-06-19 15:02:18 -07:00
}
}
if ( injectFrozenData )
{
// If we're loading from disk, we can actually substitute air in the block map for anything that is otherwise "missing". This keeps the reference in the map, in case
// the block comes back later
missing . forEach (( name , m ) ->
{
2021-07-19 21:15:19 -07:00
if ( m . isEmpty ())
return ;
2017-06-19 15:02:18 -07:00
ForgeRegistry <?> reg = STAGING . getRegistry ( name );
m . forEach (( rl , id ) -> reg . markDummy ( rl , id ));
});
// If we're loading up the world from disk, we want to add in the new data that might have been provisioned by mods
// So we load it from the frozen persistent registry
RegistryManager . ACTIVE . registries . forEach (( name , reg ) ->
{
final Class <? extends IForgeRegistryEntry > clazz = RegistryManager . ACTIVE . getSuperType ( name );
loadFrozenDataToStagingRegistry ( STAGING , name , remaps . get ( name ), clazz );
});
}
// Validate that all the STAGING data is good
2017-06-20 18:39:55 -07:00
STAGING . registries . forEach (( name , reg ) -> reg . validateContent ( name ));
2017-06-19 15:02:18 -07:00
// Load the STAGING registry into the ACTIVE registry
2018-09-05 20:06:18 -07:00
//for (Map.Entry<ResourceLocation, IForgeRegistry<? extends IForgeRegistryEntry<?>>> r : RegistryManager.ACTIVE.registries.entrySet())
RegistryManager . ACTIVE . registries . forEach (( key , value ) ->
2017-06-19 15:02:18 -07:00
{
2018-09-05 20:06:18 -07:00
final Class <? extends IForgeRegistryEntry > registrySuperType = RegistryManager . ACTIVE . getSuperType ( key );
loadRegistry ( key , STAGING , RegistryManager . ACTIVE , registrySuperType , true );
});
2017-06-19 15:02:18 -07:00
2019-01-11 23:52:30 +01:00
RegistryManager . ACTIVE . registries . forEach (( name , reg ) -> {
reg . bake ();
// Dump the active registry
reg . dump ( name );
});
2017-06-19 15:02:18 -07:00
// Tell mods that the ids have changed
2019-03-25 21:41:28 -04:00
fireRemapEvent ( remaps , false );
2017-06-19 15:02:18 -07:00
// The id map changed, ensure we apply object holders
2019-01-09 20:57:01 -08:00
ObjectHolderRegistry . applyObjectHolders ();
2017-06-19 15:02:18 -07:00
// Return an empty list, because we're good
return ArrayListMultimap . create ();
}
2019-03-25 21:41:28 -04:00
private static void fireRemapEvent ( final Map < ResourceLocation , Map < ResourceLocation , Integer []>> remaps , final boolean isFreezing ) {
2020-04-26 21:03:43 -04:00
StartupMessageManager . modLoaderConsumer (). ifPresent ( s -> s . accept ( "Remapping mod data" ));
2021-11-26 18:57:41 +00:00
MinecraftForge . EVENT_BUS . post ( new RegistryEvent . IdMappingEvent ( remaps , isFreezing ));
2020-04-26 21:03:43 -04:00
StartupMessageManager . modLoaderConsumer (). ifPresent ( s -> s . accept ( "Remap complete" ));
2019-03-25 21:41:28 -04:00
}
2017-06-19 15:02:18 -07:00
//Has to be split because of generics, Yay!
2018-09-05 20:06:18 -07:00
private static < T extends IForgeRegistryEntry < T >> void loadPersistentDataToStagingRegistry ( RegistryManager pool , RegistryManager to , Map < ResourceLocation , Integer []> remaps , Map < ResourceLocation , Integer > missing , ResourceLocation name , ForgeRegistry . Snapshot snap , Class < T > regType )
2017-06-19 15:02:18 -07:00
{
ForgeRegistry < T > active = pool . getRegistry ( name );
if ( active == null )
return ; // We've already asked the user if they wish to continue. So if the reg isnt found just assume the user knows and accepted it.
ForgeRegistry < T > _new = to . getRegistry ( name , RegistryManager . ACTIVE );
2017-06-28 00:14:10 -07:00
snap . aliases . forEach ( _new :: addAlias );
snap . blocked . forEach ( _new :: block );
2017-06-19 15:02:18 -07:00
// Load current dummies BEFORE the snapshot is loaded so that add() will remove from the list.
2017-06-28 00:14:10 -07:00
snap . dummied . forEach ( _new :: addDummy );
2017-06-23 00:58:00 -07:00
_new . loadIds ( snap . ids , snap . overrides , missing , remaps , active , name );
2017-06-19 15:02:18 -07:00
}
//Another bouncer for generic reasons
@SuppressWarnings ( "unchecked" )
2018-09-05 20:06:18 -07:00
private static < T extends IForgeRegistryEntry < T >> void processMissing ( Class < T > clazz , ResourceLocation name , RegistryManager STAGING , MissingMappings <?> e , Map < ResourceLocation , Integer > missing , Map < ResourceLocation , Integer []> remaps , Collection < ResourceLocation > defaulted , Collection < ResourceLocation > failed , boolean injectNetworkDummies )
2017-06-19 15:02:18 -07:00
{
List < MissingMappings . Mapping < T >> mappings = (( MissingMappings < T > ) e ). getAllMappings ();
ForgeRegistry < T > active = RegistryManager . ACTIVE . getRegistry ( name );
ForgeRegistry < T > staging = STAGING . getRegistry ( name );
2017-08-15 05:10:07 -07:00
staging . processMissingEvent ( name , active , mappings , missing , remaps , defaulted , failed , injectNetworkDummies );
2017-06-19 15:02:18 -07:00
}
2018-09-05 20:06:18 -07:00
private static < T extends IForgeRegistryEntry < T >> void loadFrozenDataToStagingRegistry ( RegistryManager STAGING , ResourceLocation name , Map < ResourceLocation , Integer []> remaps , Class < T > clazz )
2017-06-19 15:02:18 -07:00
{
ForgeRegistry < T > frozen = RegistryManager . FROZEN . getRegistry ( name );
ForgeRegistry < T > newRegistry = STAGING . getRegistry ( name , RegistryManager . FROZEN );
2020-11-10 11:13:38 -08:00
Map < ResourceLocation , Integer > _new = Maps . newLinkedHashMap ();
2017-06-19 15:02:18 -07:00
frozen . getKeys (). stream (). filter ( key -> ! newRegistry . containsKey ( key )). forEach ( key -> _new . put ( key , frozen . getID ( key )));
2017-06-23 00:58:00 -07:00
newRegistry . loadIds ( _new , frozen . getOverrideOwners (), Maps . newLinkedHashMap (), remaps , frozen , name );
2017-06-19 15:02:18 -07:00
}
2018-12-02 00:46:19 +00:00
/**
* Check a name for a domain prefix, and if not present infer it from the
* current active mod container.
2019-05-23 16:02:15 -07:00
*
2018-12-02 00:46:19 +00:00
* @param name The name or resource location
* @param warnOverrides If true, logs a warning if domain differs from that of
* the currently currently active mod container
2019-05-23 16:02:15 -07:00
*
2018-12-02 00:46:19 +00:00
* @return The {@link ResourceLocation} with given or inferred domain
*/
public static ResourceLocation checkPrefix ( String name , boolean warnOverrides )
2018-05-17 06:52:32 +01:00
{
int index = name . lastIndexOf ( ':' );
String oldPrefix = index == - 1 ? "" : name . substring ( 0 , index ). toLowerCase ( Locale . ROOT );
name = index == - 1 ? name : name . substring ( index + 1 );
2019-08-04 20:16:01 -04:00
String prefix = ModLoadingContext . get (). getActiveNamespace ();
2018-12-02 00:46:19 +00:00
if ( warnOverrides && ! oldPrefix . equals ( prefix ) && oldPrefix . length () > 0 )
2018-05-17 06:52:32 +01:00
{
2018-09-05 20:06:18 -07:00
LogManager . getLogger (). info ( "Potentially Dangerous alternative prefix `{}` for name `{}`, expected `{}`. This could be a intended override, but in most cases indicates a broken mod." , oldPrefix , name , prefix );
2018-05-17 06:52:32 +01:00
prefix = oldPrefix ;
}
return new ResourceLocation ( prefix , name );
}
2017-08-15 05:10:07 -07:00
private static Field regName ;
private static void forceRegistryName ( IForgeRegistryEntry <?> entry , ResourceLocation name )
{
if ( regName == null )
{
try
{
2018-09-05 20:06:18 -07:00
regName = ForgeRegistryEntry . class . getDeclaredField ( "registryName" );
2017-08-15 05:10:07 -07:00
regName . setAccessible ( true );
}
catch ( NoSuchFieldException | SecurityException e )
{
2019-01-27 00:06:57 -05:00
LOGGER . error ( REGISTRIES , "Could not get `registryName` field from IForgeRegistryEntry.Impl" , e );
2017-08-15 05:10:07 -07:00
throw new RuntimeException ( e );
}
}
try
{
regName . set ( entry , name );
}
catch ( IllegalArgumentException | IllegalAccessException e )
{
2019-01-27 00:06:57 -05:00
LOGGER . error ( REGISTRIES , "Could not set `registryName` field in IForgeRegistryEntry.Impl to `{}`" , name . toString (), e );
2017-08-15 05:10:07 -07:00
throw new RuntimeException ( e );
}
}
2017-06-19 15:02:18 -07:00
}