2017-06-19 22:02:18 +00:00
/ *
* Minecraft Forge
2020-07-02 17:49:11 +00:00
* Copyright ( c ) 2016 - 2020 .
2017-06-19 22:02:18 +00:00
*
* 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 ;
2019-01-11 22:52:30 +00:00
import com.google.common.collect.* ;
2020-08-13 07:13:48 +00:00
import com.mojang.serialization.Lifecycle ;
2019-09-07 03:39:14 +00:00
2020-10-04 19:50:15 +00:00
import java.util.* ;
2019-05-23 23:02:15 +00:00
import net.minecraft.block.AirBlock ;
2019-09-07 03:39:14 +00:00
import net.minecraft.block.Block ;
2019-05-23 23:02:15 +00:00
import net.minecraft.block.BlockState ;
2019-09-07 03:39:14 +00:00
import net.minecraft.block.material.Material ;
2017-06-19 22:02:18 +00:00
import net.minecraft.enchantment.Enchantment ;
2018-09-14 16:30:56 +00:00
import net.minecraft.entity.EntityType ;
2020-06-24 00:56:24 +00:00
import net.minecraft.entity.ai.attributes.Attribute ;
import net.minecraft.entity.ai.attributes.GlobalEntityTypeAttributes ;
2019-06-09 07:23:00 +00:00
import net.minecraft.entity.ai.brain.memory.MemoryModuleType ;
import net.minecraft.entity.ai.brain.schedule.Activity ;
import net.minecraft.entity.ai.brain.schedule.Schedule ;
import net.minecraft.entity.ai.brain.sensor.SensorType ;
import net.minecraft.entity.item.PaintingType ;
import net.minecraft.entity.merchant.villager.VillagerProfession ;
import net.minecraft.fluid.Fluid ;
2019-06-09 04:19:17 +00:00
import net.minecraft.inventory.container.ContainerType ;
2019-09-07 03:39:14 +00:00
import net.minecraft.item.BlockItem ;
2017-06-19 22:02:18 +00:00
import net.minecraft.item.Item ;
2019-06-09 07:23:00 +00:00
import net.minecraft.item.crafting.IRecipeSerializer ;
2019-05-23 23:02:15 +00:00
import net.minecraft.network.datasync.IDataSerializer ;
2019-06-09 07:23:00 +00:00
import net.minecraft.particles.ParticleType ;
2019-05-23 23:02:15 +00:00
import net.minecraft.potion.Effect ;
2017-06-19 22:02:18 +00:00
import net.minecraft.potion.Potion ;
2019-01-11 22:52:30 +00:00
import net.minecraft.state.StateContainer ;
2019-06-09 07:23:00 +00:00
import net.minecraft.stats.StatType ;
2020-09-09 02:10:36 +00:00
import net.minecraft.tags.TagRegistryManager ;
2018-09-15 07:59:19 +00:00
import net.minecraft.tileentity.TileEntityType ;
2017-06-19 22:02:18 +00:00
import net.minecraft.util.ObjectIntIdentityMap ;
2020-08-13 07:13:48 +00:00
import net.minecraft.util.RegistryKey ;
2017-06-19 22:02:18 +00:00
import net.minecraft.util.ResourceLocation ;
import net.minecraft.util.SoundEvent ;
2019-09-07 03:39:14 +00:00
import net.minecraft.util.registry.DefaultedRegistry ;
2020-09-01 01:26:54 +00:00
import net.minecraft.util.registry.Registry ;
2019-05-23 23:02:15 +00:00
import net.minecraft.util.registry.SimpleRegistry ;
2019-06-09 07:23:00 +00:00
import net.minecraft.village.PointOfInterestType ;
2020-08-26 16:49:34 +00:00
import net.minecraft.world.biome.Biome ;
2019-06-09 07:23:00 +00:00
import net.minecraft.world.chunk.ChunkStatus ;
2020-08-04 00:00:31 +00:00
import net.minecraft.world.gen.DebugChunkGenerator ;
2020-05-23 17:42:56 +00:00
import net.minecraft.world.gen.blockplacer.BlockPlacerType ;
import net.minecraft.world.gen.blockstateprovider.BlockStateProviderType ;
2019-06-09 07:23:00 +00:00
import net.minecraft.world.gen.carver.WorldCarver ;
import net.minecraft.world.gen.feature.Feature ;
2019-09-07 03:39:14 +00:00
import net.minecraft.world.gen.feature.structure.Structure ;
2020-05-23 17:42:56 +00:00
import net.minecraft.world.gen.foliageplacer.FoliagePlacerType ;
2019-06-09 07:23:00 +00:00
import net.minecraft.world.gen.placement.Placement ;
import net.minecraft.world.gen.surfacebuilders.SurfaceBuilder ;
2020-05-23 17:42:56 +00:00
import net.minecraft.world.gen.treedecorator.TreeDecoratorType ;
2020-09-09 02:10:36 +00:00
import net.minecraftforge.common.ForgeTagHandler ;
2017-06-19 22:02:18 +00:00
import net.minecraftforge.common.MinecraftForge ;
2020-02-27 06:13:36 +00:00
import net.minecraftforge.common.loot.GlobalLootModifierSerializer ;
2017-06-19 22:02:18 +00:00
import net.minecraftforge.event.RegistryEvent ;
import net.minecraftforge.event.RegistryEvent.MissingMappings ;
2020-09-03 16:08:59 +00:00
import net.minecraftforge.fml.ModContainer ;
2019-02-14 02:06:39 +00:00
import net.minecraftforge.fml.ModLoadingContext ;
2020-08-31 01:39:06 +00:00
import net.minecraftforge.fml.ModLoadingStage ;
2019-01-11 22:52:30 +00:00
import net.minecraftforge.fml.common.EnhancedRuntimeException ;
import net.minecraftforge.fml.common.thread.EffectiveSide ;
2019-03-26 01:41:28 +00:00
import net.minecraftforge.fml.event.lifecycle.FMLModIdMappingEvent ;
2019-01-27 05:06:57 +00:00
import net.minecraftforge.fml.loading.AdvancedLogMessageAdapter ;
2019-09-07 03:39:14 +00:00
2020-04-27 01:03:43 +00:00
import net.minecraftforge.fml.loading.progress.StartupMessageManager ;
2019-01-11 22:52:30 +00:00
import org.apache.commons.lang3.Validate ;
import org.apache.logging.log4j.LogManager ;
import org.apache.logging.log4j.Logger ;
2017-06-19 22:02:18 +00:00
2019-01-11 22:52:30 +00:00
import javax.annotation.Nullable ;
2019-09-07 03:39:14 +00:00
2017-07-05 21:40:43 +00:00
import java.lang.reflect.Field ;
2020-10-04 19:50:15 +00:00
import java.util.concurrent.CompletableFuture ;
import java.util.concurrent.Executor ;
2017-06-21 01:39:55 +00:00
import java.util.function.BiConsumer ;
2020-09-03 16:08:59 +00:00
import java.util.function.BiFunction ;
import java.util.function.Function ;
2017-06-19 22:02:18 +00:00
import java.util.stream.Collectors ;
2020-08-31 01:39:06 +00:00
import java.util.stream.Stream ;
2017-06-19 22:02:18 +00:00
2019-01-27 05:06:57 +00:00
import static net.minecraftforge.registries.ForgeRegistry.REGISTRIES ;
2020-08-13 07:13:48 +00:00
import static net.minecraftforge.registries.ForgeRegistries.Keys.* ;
2019-01-27 03:18:28 +00:00
2017-06-19 22:02:18 +00:00
/ * *
* INTERNAL ONLY
* MODDERS SHOULD HAVE NO REASON TO USE THIS CLASS
* /
public class GameData
{
2018-08-27 17:10:07 +00:00
private static final Logger LOGGER = LogManager . getLogger ( ) ;
2019-05-23 23:02:15 +00: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 22:02:18 +00:00
2019-06-09 07:23:00 +00:00
private static final ResourceLocation BLOCK_TO_ITEM = new ResourceLocation ( " minecraft:blocktoitemmap " ) ;
2017-06-19 22:02:18 +00:00
private static final ResourceLocation BLOCKSTATE_TO_ID = new ResourceLocation ( " minecraft:blockstatetoid " ) ;
2019-06-09 07:23:00 +00:00
private static final ResourceLocation SERIALIZER_TO_ENTRY = new ResourceLocation ( " forge:serializer_to_entry " ) ;
2019-09-07 03:39:14 +00:00
private static final ResourceLocation STRUCTURES = new ResourceLocation ( " minecraft:structures " ) ;
2019-04-11 12:33:12 +00:00
2017-06-19 22:02:18 +00: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-21 01:39:55 +00: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 22:02:18 +00:00
static {
init ( ) ;
}
public static void init ( )
{
2019-01-27 05:06:57 +00:00
if ( DISABLE_VANILLA_REGISTRIES )
2017-06-19 22:02:18 +00:00
{
2019-01-27 05:06:57 +00:00
LOGGER . warn ( REGISTRIES , " DISABLING VANILLA REGISTRY CREATION AS PER SYSTEM VARIABLE SETTING! forge.disableVanillaGameData " ) ;
2017-06-19 22:02:18 +00:00
return ;
}
if ( hasInit )
return ;
hasInit = true ;
2020-06-19 14:58:45 +00:00
2019-06-09 07:23:00 +00:00
// Game objects
2020-08-13 07:13:48 +00:00
makeRegistry ( BLOCKS , Block . class , " air " ) . addCallback ( BlockCallbacks . INSTANCE ) . legacyName ( " blocks " ) . create ( ) ;
makeRegistry ( FLUIDS , Fluid . class , " empty " ) . create ( ) ;
makeRegistry ( ITEMS , Item . class , " air " ) . addCallback ( ItemCallbacks . INSTANCE ) . legacyName ( " items " ) . create ( ) ;
makeRegistry ( EFFECTS , Effect . class ) . legacyName ( " potions " ) . create ( ) ;
//makeRegistry(BIOMES, Biome.class).legacyName("biomes").create();
makeRegistry ( SOUND_EVENTS , SoundEvent . class ) . legacyName ( " soundevents " ) . create ( ) ;
makeRegistry ( POTIONS , Potion . class , " empty " ) . legacyName ( " potiontypes " ) . create ( ) ;
2019-06-09 07:23:00 +00:00
makeRegistry ( ENCHANTMENTS , Enchantment . class ) . legacyName ( " enchantments " ) . create ( ) ;
2020-08-13 07:13:48 +00:00
makeRegistry ( ENTITY_TYPES , c ( EntityType . class ) , " pig " ) . legacyName ( " entities " ) . create ( ) ;
makeRegistry ( TILE_ENTITY_TYPES , c ( TileEntityType . class ) ) . disableSaving ( ) . legacyName ( " tileentities " ) . create ( ) ;
makeRegistry ( PARTICLE_TYPES , c ( ParticleType . class ) ) . disableSaving ( ) . create ( ) ;
makeRegistry ( CONTAINER_TYPES , c ( ContainerType . class ) ) . disableSaving ( ) . create ( ) ;
makeRegistry ( PAINTING_TYPES , PaintingType . class , " kebab " ) . create ( ) ;
makeRegistry ( RECIPE_SERIALIZERS , c ( IRecipeSerializer . class ) ) . disableSaving ( ) . create ( ) ;
2020-06-24 00:56:24 +00:00
makeRegistry ( ATTRIBUTES , Attribute . class ) . onValidate ( AttributeCallbacks . INSTANCE ) . disableSaving ( ) . disableSync ( ) . create ( ) ;
2020-08-13 07:13:48 +00:00
makeRegistry ( STAT_TYPES , c ( StatType . class ) ) . create ( ) ;
2020-06-19 14:58:45 +00:00
2019-06-09 07:23:00 +00:00
// Villagers
2020-08-13 07:13:48 +00:00
makeRegistry ( VILLAGER_PROFESSIONS , VillagerProfession . class , " none " ) . create ( ) ;
makeRegistry ( POI_TYPES , PointOfInterestType . class , " unemployed " ) . disableSync ( ) . create ( ) ;
makeRegistry ( MEMORY_MODULE_TYPES , c ( MemoryModuleType . class ) , " dummy " ) . disableSync ( ) . create ( ) ;
makeRegistry ( SENSOR_TYPES , c ( SensorType . class ) , " dummy " ) . disableSaving ( ) . disableSync ( ) . create ( ) ;
2019-06-09 07:23:00 +00:00
makeRegistry ( SCHEDULES , Schedule . class ) . disableSaving ( ) . disableSync ( ) . create ( ) ;
makeRegistry ( ACTIVITIES , Activity . class ) . disableSaving ( ) . disableSync ( ) . create ( ) ;
// Worldgen
2020-08-13 07:13:48 +00:00
makeRegistry ( WORLD_CARVERS , c ( WorldCarver . class ) ) . disableSaving ( ) . disableSync ( ) . create ( ) ;
makeRegistry ( SURFACE_BUILDERS , c ( SurfaceBuilder . class ) ) . disableSaving ( ) . disableSync ( ) . create ( ) ;
makeRegistry ( FEATURES , c ( Feature . class ) ) . addCallback ( FeatureCallbacks . INSTANCE ) . disableSaving ( ) . create ( ) ;
makeRegistry ( DECORATORS , c ( Placement . class ) ) . disableSaving ( ) . disableSync ( ) . create ( ) ;
makeRegistry ( CHUNK_STATUS , ChunkStatus . class , " empty " ) . disableSaving ( ) . disableSync ( ) . create ( ) ;
makeRegistry ( STRUCTURE_FEATURES , c ( Structure . class ) ) . disableSaving ( ) . disableSync ( ) . create ( ) ;
makeRegistry ( BLOCK_STATE_PROVIDER_TYPES , c ( BlockStateProviderType . class ) ) . disableSaving ( ) . disableSync ( ) . create ( ) ;
makeRegistry ( BLOCK_PLACER_TYPES , c ( BlockPlacerType . 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 17:42:56 +00:00
2020-08-26 16:49:34 +00:00
// Dynamic Worldgen
2020-09-24 03:12:11 +00:00
makeRegistry ( BIOMES , Biome . class ) . create ( ) ;
2020-08-26 16:49:34 +00:00
2019-06-09 07:23:00 +00:00
// Custom forge registries
2020-08-13 07:13:48 +00:00
makeRegistry ( DATA_SERIALIZERS , DataSerializerEntry . class , 256 /*vanilla space*/ , MAX_VARINT ) . disableSaving ( ) . disableOverrides ( ) . addCallback ( SerializerCallbacks . INSTANCE ) . create ( ) ;
makeRegistry ( LOOT_MODIFIER_SERIALIZERS , c ( GlobalLootModifierSerializer . class ) ) . disableSaving ( ) . disableSync ( ) . create ( ) ;
2019-05-23 23:02:15 +00:00
}
2020-08-13 07:13:48 +00:00
@SuppressWarnings ( " unchecked " ) //Ugly hack to let us pass in a typed Class object. Remove when we remove type specific references.
private static < T > Class < T > c ( Class < ? > cls ) { return ( Class < T > ) cls ; }
2019-05-23 23:02:15 +00:00
2020-08-13 07:13:48 +00:00
private static < T extends IForgeRegistryEntry < T > > RegistryBuilder < T > makeRegistry ( RegistryKey < ? extends Registry < T > > key , Class < T > type )
2017-06-19 22:02:18 +00:00
{
2020-08-13 07:13:48 +00:00
return new RegistryBuilder < T > ( ) . setName ( key . func_240901_a_ ( ) ) . setType ( type ) . setMaxID ( MAX_VARINT ) . addCallback ( new NamespacedWrapper . Factory < T > ( ) ) ;
2017-06-19 22:02:18 +00:00
}
2020-08-13 07:13:48 +00:00
private static < T extends IForgeRegistryEntry < T > > RegistryBuilder < T > makeRegistry ( RegistryKey < ? extends Registry < T > > key , Class < T > type , int min , int max )
2019-04-11 12:33:12 +00:00
{
2020-09-09 02:10:36 +00:00
return new RegistryBuilder < T > ( ) . setName ( key . func_240901_a_ ( ) ) . setType ( type ) . setIDRange ( min , max ) . hasWrapper ( ) ;
2019-04-11 12:33:12 +00:00
}
2020-08-13 07:13:48 +00:00
private static < T extends IForgeRegistryEntry < T > > RegistryBuilder < T > makeRegistry ( RegistryKey < ? extends Registry < T > > key , Class < T > type , String _default )
2017-06-19 22:02:18 +00:00
{
2020-09-09 02:10:36 +00:00
return new RegistryBuilder < T > ( ) . setName ( key . func_240901_a_ ( ) ) . setType ( type ) . setMaxID ( MAX_VARINT ) . hasWrapper ( ) . setDefaultKey ( new ResourceLocation ( _default ) ) ;
2017-06-19 22:02:18 +00:00
}
2020-08-13 07:13:48 +00:00
public static < T extends IForgeRegistryEntry < T > > SimpleRegistry < T > getWrapper ( RegistryKey < ? extends Registry < T > > key , Lifecycle lifecycle )
2017-06-19 22:02:18 +00:00
{
2020-08-13 07:13:48 +00:00
IForgeRegistry < T > reg = RegistryManager . ACTIVE . getRegistry ( key ) ;
Validate . notNull ( reg , " Attempted to get vanilla wrapper for unknown registry: " + key . toString ( ) ) ;
2017-06-19 22:02:18 +00:00
@SuppressWarnings ( " unchecked " )
2020-08-13 07:13:48 +00:00
SimpleRegistry < T > ret = reg . getSlaveMap ( NamespacedWrapper . Factory . ID , NamespacedWrapper . class ) ;
Validate . notNull ( ret , " Attempted to get vanilla wrapper for registry created incorrectly: " + key . toString ( ) ) ;
2017-06-19 22:02:18 +00:00
return ret ;
}
2020-08-13 07:13:48 +00:00
public static < T extends IForgeRegistryEntry < T > > DefaultedRegistry < T > getWrapper ( RegistryKey < ? extends Registry < T > > key , Lifecycle lifecycle , String defKey )
2017-06-19 22:02:18 +00:00
{
2020-08-13 07:13:48 +00:00
IForgeRegistry < T > reg = RegistryManager . ACTIVE . getRegistry ( key ) ;
Validate . notNull ( reg , " Attempted to get vanilla wrapper for unknown registry: " + key . toString ( ) ) ;
2017-06-19 22:02:18 +00:00
@SuppressWarnings ( " unchecked " )
2020-08-13 07:13:48 +00: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 22:02:18 +00:00
return ret ;
}
@SuppressWarnings ( " unchecked " )
2018-09-10 20:08:35 +00:00
public static Map < Block , Item > getBlockItemMap ( )
2017-06-19 22:02:18 +00:00
{
2018-09-10 20:08:35 +00:00
return RegistryManager . ACTIVE . getRegistry ( Item . class ) . getSlaveMap ( BLOCK_TO_ITEM , Map . class ) ;
2017-06-19 22:02:18 +00:00
}
@SuppressWarnings ( " unchecked " )
2019-05-23 23:02:15 +00:00
public static ObjectIntIdentityMap < BlockState > getBlockStateIDMap ( )
2017-06-19 22:02:18 +00:00
{
2018-08-30 01:30:15 +00:00
return RegistryManager . ACTIVE . getRegistry ( Block . class ) . getSlaveMap ( BLOCKSTATE_TO_ID , ObjectIntIdentityMap . class ) ;
2017-06-19 22:02:18 +00:00
}
2019-04-11 12:33:12 +00:00
@SuppressWarnings ( " unchecked " )
2019-05-23 23:02:15 +00:00
public static Map < IDataSerializer < ? > , DataSerializerEntry > getSerializerMap ( )
2019-04-11 12:33:12 +00:00
{
return RegistryManager . ACTIVE . getRegistry ( DataSerializerEntry . class ) . getSlaveMap ( SERIALIZER_TO_ENTRY , Map . class ) ;
}
2020-06-19 14:58:45 +00:00
2019-09-07 03:39:14 +00:00
@SuppressWarnings ( " unchecked " )
public static BiMap < String , Structure < ? > > getStructureMap ( )
{
return ( BiMap < String , Structure < ? > > ) RegistryManager . ACTIVE . getRegistry ( Feature . class ) . getSlaveMap ( STRUCTURES , BiMap . class ) ;
}
2019-04-11 12:33:12 +00:00
2017-06-19 22:02:18 +00:00
public static < K extends IForgeRegistryEntry < K > > K register_impl ( K value )
{
Validate . notNull ( value , " Attempted to register a null object " ) ;
Validate . notNull ( value . getRegistryName ( ) , String . format ( " Attempt to register object without having set a registry name %s (type %s) " , value , value . getClass ( ) . getName ( ) ) ) ;
2018-08-27 17:10:07 +00:00
final IForgeRegistry < K > registry = RegistryManager . ACTIVE . getRegistry ( value . getRegistryType ( ) ) ;
2017-06-19 22:02:18 +00: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 05:06:57 +00:00
LOGGER . debug ( REGISTRIES , " Creating vanilla freeze snapshot " ) ;
2018-09-06 03:06:18 +00:00
for ( Map . Entry < ResourceLocation , ForgeRegistry < ? extends IForgeRegistryEntry < ? > > > r : RegistryManager . ACTIVE . registries . entrySet ( ) )
2017-06-19 22:02:18 +00:00
{
final Class < ? extends IForgeRegistryEntry > clazz = RegistryManager . ACTIVE . getSuperType ( r . getKey ( ) ) ;
loadRegistry ( r . getKey ( ) , RegistryManager . ACTIVE , RegistryManager . VANILLA , clazz , true ) ;
}
2017-06-21 01:39:55 +00: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 05:06:57 +00:00
LOGGER . debug ( REGISTRIES , " Vanilla freeze snapshot created " ) ;
2017-06-19 22:02:18 +00:00
}
@SuppressWarnings ( { " rawtypes " , " unchecked " } )
public static void freezeData ( )
{
2019-01-27 05:06:57 +00:00
LOGGER . debug ( REGISTRIES , " Freezing registries " ) ;
2017-06-19 22:02:18 +00: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-21 01:39:55 +00:00
RegistryManager . FROZEN . registries . forEach ( ( name , reg ) - >
{
reg . validateContent ( name ) ;
reg . freeze ( ) ;
} ) ;
2019-01-11 22:52:30 +00:00
RegistryManager . ACTIVE . registries . forEach ( ( name , reg ) - > {
reg . freeze ( ) ;
reg . bake ( ) ;
2019-01-27 05:06:57 +00:00
reg . dump ( name ) ;
2019-01-11 22:52:30 +00:00
} ) ;
2017-07-13 21:45:51 +00:00
2018-08-30 01:30:15 +00: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-26 01:41:28 +00:00
fireRemapEvent ( ImmutableMap . of ( ) , true ) ;
2017-07-13 21:45:51 +00:00
2019-01-27 05:06:57 +00:00
LOGGER . debug ( REGISTRIES , " All registries frozen " ) ;
2017-06-19 22:02:18 +00:00
}
@SuppressWarnings ( { " unchecked " , " rawtypes " } )
public static void revertToFrozen ( )
{
if ( RegistryManager . FROZEN . registries . isEmpty ( ) )
{
2019-01-27 05:06:57 +00:00
LOGGER . warn ( REGISTRIES , " Can't revert to frozen GameData state without freezing first. " ) ;
2017-06-19 22:02:18 +00:00
return ;
}
2017-06-23 07:58:00 +00:00
RegistryManager . ACTIVE . registries . forEach ( ( name , reg ) - > reg . resetDelegates ( ) ) ;
2017-06-19 22:02:18 +00:00
2019-01-27 05:06:57 +00:00
LOGGER . debug ( REGISTRIES , " Reverting to frozen data state. " ) ;
2018-09-06 03:06:18 +00:00
for ( Map . Entry < ResourceLocation , ForgeRegistry < ? extends IForgeRegistryEntry < ? > > > r : RegistryManager . ACTIVE . registries . entrySet ( ) )
2017-06-19 22:02:18 +00:00
{
final Class < ? extends IForgeRegistryEntry > clazz = RegistryManager . ACTIVE . getSuperType ( r . getKey ( ) ) ;
loadRegistry ( r . getKey ( ) , RegistryManager . FROZEN , RegistryManager . ACTIVE , clazz , true ) ;
}
2019-01-11 22:52:30 +00:00
RegistryManager . ACTIVE . registries . forEach ( ( name , reg ) - > reg . bake ( ) ) ;
2017-06-19 22:02:18 +00:00
// the id mapping has reverted, fire remap events for those that care about id changes
2019-03-26 01:41:28 +00:00
fireRemapEvent ( ImmutableMap . of ( ) , true ) ;
2017-06-19 22:02:18 +00:00
2019-01-16 20:28:13 +00:00
ObjectHolderRegistry . applyObjectHolders ( ) ;
2017-06-19 22:02:18 +00:00
// the id mapping has reverted, ensure we sync up the object holders
2019-01-27 05:06:57 +00:00
LOGGER . debug ( REGISTRIES , " Frozen state restored. " ) ;
2017-06-19 22:02:18 +00:00
}
@SuppressWarnings ( { " rawtypes " , " unchecked " } )
public static void revert ( RegistryManager state , ResourceLocation registry , boolean lock )
{
2019-01-27 05:06:57 +00:00
LOGGER . debug ( REGISTRIES , " Reverting {} to {} " , registry , state . getName ( ) ) ;
2017-06-19 22:02:18 +00:00
final Class < ? extends IForgeRegistryEntry > clazz = RegistryManager . ACTIVE . getSuperType ( registry ) ;
2017-10-31 18:29:35 +00:00
loadRegistry ( registry , state , RegistryManager . ACTIVE , clazz , lock ) ;
2019-01-27 05:06:57 +00:00
LOGGER . debug ( REGISTRIES , " Reverting complete " ) ;
2017-06-19 22:02:18 +00:00
}
2020-09-03 04:15:16 +00:00
@SuppressWarnings ( " rawtypes " ) //Eclipse compiler generics issue.
2020-08-31 01:39:06 +00:00
public static Stream < ModLoadingStage . EventGenerator < ? > > generateRegistryEvents ( ) {
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.
2020-09-01 01:26:54 +00:00
keys . remove ( BLOCKS . func_240901_a_ ( ) ) ;
keys . remove ( ITEMS . func_240901_a_ ( ) ) ;
2020-08-31 01:39:06 +00:00
2020-09-01 01:26:54 +00:00
keys . add ( 0 , BLOCKS . func_240901_a_ ( ) ) ;
keys . add ( 1 , ITEMS . func_240901_a_ ( ) ) ;
2020-08-31 01:39:06 +00:00
2020-10-04 19:50:15 +00:00
final Function < ResourceLocation , ? extends RegistryEvent . Register < ? > > registerEventGenerator = rl - > RegistryManager . ACTIVE . getRegistry ( rl ) . getRegisterEvent ( rl ) ;
return keys . stream ( ) . map ( rl - > ModLoadingStage . EventGenerator . fromFunction ( mc - > registerEventGenerator . apply ( rl ) ) ) ;
2020-08-31 01:39:06 +00:00
}
2020-10-04 19:50:15 +00:00
public static CompletableFuture < List < Throwable > > preRegistryEventDispatch ( final Executor executor , final ModLoadingStage . EventGenerator < ? extends RegistryEvent . Register < ? > > eventGenerator ) {
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 ( ) ) ;
}
public static CompletableFuture < List < Throwable > > postRegistryEventDispatch ( final Executor executor , final ModLoadingStage . EventGenerator < ? extends RegistryEvent . Register < ? > > eventGenerator ) {
return CompletableFuture . runAsync ( ( ) - > {
final RegistryEvent . Register < ? > event = eventGenerator . apply ( null ) ;
final ResourceLocation rl = event . getName ( ) ;
ForgeRegistry < ? > fr = ( ForgeRegistry < ? > ) event . getRegistry ( ) ;
2020-08-31 01:39:06 +00:00
fr . freeze ( ) ;
2020-10-04 19:50:15 +00:00
LOGGER . debug ( REGISTRIES , " Applying holder lookups: {} " , rl . toString ( ) ) ;
2020-08-31 01:39:06 +00:00
ObjectHolderRegistry . applyObjectHolders ( rl : : equals ) ;
2020-10-04 19:50:15 +00:00
LOGGER . debug ( REGISTRIES , " Holder lookups applied: {} " , rl . toString ( ) ) ;
} , executor ) . thenApply ( v - > Collections . emptyList ( ) ) ;
2020-08-31 01:39:06 +00:00
}
2020-09-09 02:10:36 +00:00
public static void setCustomTagTypesFromRegistries ( )
{
Set < ResourceLocation > customTagTypes = new HashSet < > ( ) ;
for ( Map . Entry < ResourceLocation , ForgeRegistry < ? extends IForgeRegistryEntry < ? > > > entry : RegistryManager . ACTIVE . registries . entrySet ( ) )
{
ResourceLocation registryName = entry . getKey ( ) ;
if ( entry . getValue ( ) . getTagFolder ( ) ! = null & & TagRegistryManager . get ( registryName ) = = null )
{
LOGGER . debug ( REGISTRIES , " Registering custom tag type for: {} " , registryName ) ;
customTagTypes . add ( registryName ) ;
TagRegistryManager . func_242196_a ( registryName , tagCollectionSupplier - > tagCollectionSupplier . getCustomTypeCollection ( registryName ) ) ;
}
}
ForgeTagHandler . setCustomTagTypes ( customTagTypes ) ;
}
2017-06-19 22:02:18 +00:00
//Lets us clear the map so we can rebuild it.
2020-06-26 19:52:50 +00:00
private static class ClearableObjectIntIdentityMap < I > extends ObjectIntIdentityMap < I >
2017-06-19 22:02:18 +00:00
{
void clear ( )
{
this . identityMap . clear ( ) ;
this . objectList . clear ( ) ;
2019-01-11 22:52:30 +00:00
this . nextId = 0 ;
2017-06-19 22:02:18 +00:00
}
2019-01-04 01:36:32 +00:00
void remove ( I key )
{
Integer prev = this . identityMap . remove ( key ) ;
if ( prev ! = null )
{
this . objectList . set ( prev , null ) ;
}
}
2017-06-19 22:02:18 +00:00
}
2019-01-11 22:52:30 +00:00
private static class BlockCallbacks implements IForgeRegistry . AddCallback < Block > , IForgeRegistry . ClearCallback < Block > , IForgeRegistry . BakeCallback < Block > , IForgeRegistry . CreateCallback < Block > , IForgeRegistry . DummyFactory < Block >
2017-06-19 22:02:18 +00:00
{
static final BlockCallbacks INSTANCE = new BlockCallbacks ( ) ;
@Override
2017-06-26 03:45:48 +00:00
public void onAdd ( IForgeRegistryInternal < Block > owner , RegistryManager stage , int id , Block block , @Nullable Block oldBlock )
2017-06-19 22:02:18 +00:00
{
2019-01-11 22:52:30 +00:00
if ( oldBlock ! = null )
{
2019-05-23 23:02:15 +00:00
StateContainer < Block , BlockState > oldContainer = oldBlock . getStateContainer ( ) ;
StateContainer < Block , BlockState > newContainer = block . getStateContainer ( ) ;
2019-01-11 22:52:30 +00:00
// Test vanilla blockstates, if the number matches, make sure they also match in their string representations
2019-07-23 02:23:20 +00:00
if ( block . getRegistryName ( ) . getNamespace ( ) . equals ( " minecraft " ) & & ! oldContainer . getProperties ( ) . equals ( newContainer . getProperties ( ) ) )
2019-01-11 22:52:30 +00:00
{
String oldSequence = oldContainer . getProperties ( ) . stream ( )
. map ( s - > String . format ( " %s={%s} " , s . getName ( ) ,
s . getAllowedValues ( ) . stream ( ) . map ( Object : : toString ) . collect ( Collectors . joining ( " , " ) ) ) )
. collect ( Collectors . joining ( " ; " ) ) ;
String newSequence = newContainer . getProperties ( ) . stream ( )
. map ( s - > String . format ( " %s={%s} " , s . getName ( ) ,
s . getAllowedValues ( ) . stream ( ) . map ( Object : : toString ) . collect ( Collectors . joining ( " , " ) ) ) )
. collect ( Collectors . joining ( " ; " ) ) ;
2019-01-27 05:06:57 +00:00
LOGGER . error ( REGISTRIES , ( ) - > new AdvancedLogMessageAdapter ( sb - > {
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 22:52:30 +00:00
throw new RuntimeException ( " Invalid vanilla replacement. See log for details. " ) ;
}
}
2017-06-19 22:02:18 +00:00
}
@Override
public void onClear ( IForgeRegistryInternal < Block > owner , RegistryManager stage )
{
2018-11-17 07:15:39 +00:00
owner . getSlaveMap ( BLOCKSTATE_TO_ID , ClearableObjectIntIdentityMap . class ) . clear ( ) ;
2017-06-19 22:02:18 +00:00
}
@Override
public void onCreate ( IForgeRegistryInternal < Block > owner , RegistryManager stage )
{
2019-05-23 23:02:15 +00:00
final ClearableObjectIntIdentityMap < BlockState > idMap = new ClearableObjectIntIdentityMap < BlockState > ( )
2017-06-19 22:02:18 +00:00
{
@Override
2020-08-13 07:13:48 +00:00
public int getId ( BlockState key )
2017-06-19 22:02:18 +00:00
{
Integer integer = ( Integer ) this . identityMap . 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
2018-11-17 07:15:39 +00:00
//if (integer == null && key != null)
// integer = this.identityMap.get(key.getBlock().getStateFromMeta(key.getBlock().getMetaFromState(key)));
2017-06-19 22:02:18 +00:00
return integer = = null ? - 1 : integer . intValue ( ) ;
}
} ;
owner . setSlaveMap ( BLOCKSTATE_TO_ID , idMap ) ;
2018-09-10 20:08:35 +00:00
owner . setSlaveMap ( BLOCK_TO_ITEM , Maps . newHashMap ( ) ) ;
2017-06-19 22:02:18 +00:00
}
@Override
public Block createDummy ( ResourceLocation key )
{
2019-02-14 23:08:53 +00:00
Block ret = new BlockDummyAir ( Block . Properties . create ( Material . AIR ) ) ;
2017-08-15 12:10:07 +00:00
GameData . forceRegistryName ( ret , key ) ;
2017-07-05 21:40:43 +00:00
return ret ;
2017-06-21 06:45:32 +00:00
}
2019-01-11 22:52:30 +00:00
@Override
public void onBake ( IForgeRegistryInternal < Block > owner , RegistryManager stage )
{
@SuppressWarnings ( " unchecked " )
2019-05-23 23:02:15 +00:00
ClearableObjectIntIdentityMap < BlockState > blockstateMap = owner . getSlaveMap ( BLOCKSTATE_TO_ID , ClearableObjectIntIdentityMap . class ) ;
2019-01-11 22:52:30 +00:00
for ( Block block : owner )
{
2019-05-23 23:02:15 +00:00
for ( BlockState state : block . getStateContainer ( ) . getValidStates ( ) )
2019-01-11 22:52:30 +00:00
{
blockstateMap . add ( state ) ;
2020-02-26 03:45:14 +00:00
state . cacheState ( ) ;
2019-01-11 22:52:30 +00:00
}
2019-05-23 23:02:15 +00:00
2019-06-08 14:45:28 +00:00
block . getLootTable ( ) ;
2019-01-11 22:52:30 +00:00
}
2020-08-04 00:00:31 +00:00
DebugChunkGenerator . initValidStates ( ) ;
2019-01-11 22:52:30 +00:00
}
2019-05-23 23:02:15 +00:00
private static class BlockDummyAir extends AirBlock //A named class so DummyBlockReplacementTest can detect if its a dummy
2017-06-21 06:45:32 +00:00
{
2019-02-14 23:08:53 +00:00
private BlockDummyAir ( Block . Properties properties )
2017-06-21 06:45:32 +00:00
{
2019-02-14 23:08:53 +00:00
super ( properties ) ;
2018-08-30 01:30:15 +00:00
}
@Override
public String getTranslationKey ( )
{
return " block.minecraft.air " ;
2017-06-21 06:45:32 +00:00
}
2017-06-19 22:02:18 +00:00
}
}
private static class ItemCallbacks implements IForgeRegistry . AddCallback < Item > , IForgeRegistry . ClearCallback < Item > , IForgeRegistry . CreateCallback < Item >
{
static final ItemCallbacks INSTANCE = new ItemCallbacks ( ) ;
@Override
2017-06-26 03:45:48 +00:00
public void onAdd ( IForgeRegistryInternal < Item > owner , RegistryManager stage , int id , Item item , @Nullable Item oldItem )
2017-06-19 22:02:18 +00:00
{
2019-05-23 23:02:15 +00:00
if ( oldItem instanceof BlockItem )
2019-01-04 01:36:32 +00:00
{
@SuppressWarnings ( " unchecked " )
2019-07-23 02:23:20 +00: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 23:02:15 +00:00
if ( item instanceof BlockItem )
2017-06-19 22:02:18 +00:00
{
@SuppressWarnings ( " unchecked " )
2018-09-10 20:08:35 +00:00
Map < Block , Item > blockToItem = owner . getSlaveMap ( BLOCK_TO_ITEM , Map . class ) ;
2019-05-23 23:02:15 +00:00
( ( BlockItem ) item ) . addToBlockToItemMap ( blockToItem , item ) ;
2017-06-19 22:02:18 +00:00
}
}
@Override
public void onClear ( IForgeRegistryInternal < Item > owner , RegistryManager stage )
{
2018-09-10 20:08:35 +00:00
owner . getSlaveMap ( BLOCK_TO_ITEM , Map . class ) . clear ( ) ;
2017-06-19 22:02:18 +00:00
}
@Override
public void onCreate ( IForgeRegistryInternal < Item > owner , RegistryManager stage )
{
// We share the blockItem map between items and blocks registries
2018-09-10 20:08:35 +00:00
Map < ? , ? > map = stage . getRegistry ( BLOCKS ) . getSlaveMap ( BLOCK_TO_ITEM , Map . class ) ;
2017-06-19 22:02:18 +00:00
owner . setSlaveMap ( BLOCK_TO_ITEM , map ) ;
}
}
2020-06-24 00:56:24 +00:00
private static class AttributeCallbacks implements IForgeRegistry . ValidateCallback < Attribute > {
2017-08-15 12:10:07 +00:00
2020-06-24 00:56:24 +00:00
static final AttributeCallbacks INSTANCE = new AttributeCallbacks ( ) ;
2017-06-19 22:02:18 +00:00
@Override
2020-06-24 00:56:24 +00:00
public void onValidate ( IForgeRegistryInternal < Attribute > owner , RegistryManager stage , int id , ResourceLocation key , Attribute obj )
2017-06-19 22:02:18 +00:00
{
2020-06-24 00:56:24 +00:00
GlobalEntityTypeAttributes . func_233834_a_ ( ) ;
2017-06-19 22:02:18 +00:00
}
}
2019-04-11 12:33:12 +00: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 " )
2019-05-23 23:02:15 +00:00
Map < IDataSerializer < ? > , DataSerializerEntry > map = owner . getSlaveMap ( SERIALIZER_TO_ENTRY , Map . class ) ;
2019-04-11 12:33:12 +00: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 14:58:45 +00:00
2020-06-25 01:25:55 +00:00
private static class FeatureCallbacks implements IForgeRegistry . ClearCallback < Feature < ? > > , IForgeRegistry . CreateCallback < Feature < ? > >
2019-09-07 03:39:14 +00:00
{
static final FeatureCallbacks INSTANCE = new FeatureCallbacks ( ) ;
2020-06-19 14:58:45 +00:00
2019-09-07 03:39:14 +00: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 12:33:12 +00:00
2017-06-19 22:02:18 +00: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 05:06:57 +00:00
LOGGER . info ( REGISTRIES , " Injecting existing registry data into this {} instance " , EffectiveSide . get ( ) ) ;
2017-06-19 22:02:18 +00: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 14:58:45 +00:00
2019-06-09 07:23:00 +00: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 22:02:18 +00:00
2019-03-12 04:34:29 +00:00
if ( isLocalWorld )
2017-06-19 22:02:18 +00: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 20:00:22 +00: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 20:00:22 +00: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 22:02:18 +00:00
2019-03-12 04:34:29 +00:00
for ( ResourceLocation s : missingRegs )
2020-05-23 20:00:22 +00:00
text . append ( s ) . append ( " \ n " ) ;
2019-03-12 04:34:29 +00:00
}
2017-06-19 22:02:18 +00: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 07:14:10 +00:00
snapshot . forEach ( ( key , value ) - >
2017-06-19 22:02:18 +00:00
{
2017-06-28 07:14:10 +00:00
final Class < ? extends IForgeRegistryEntry > clazz = RegistryManager . ACTIVE . getSuperType ( key ) ;
remaps . put ( key , Maps . newLinkedHashMap ( ) ) ;
missing . put ( key , Maps . newHashMap ( ) ) ;
loadPersistentDataToStagingRegistry ( RegistryManager . ACTIVE , STAGING , remaps . get ( key ) , missing . get ( key ) , key , value , clazz ) ;
2017-06-19 22:02:18 +00:00
} ) ;
2017-06-28 07:14:10 +00:00
snapshot . forEach ( ( key , value ) - >
2017-06-19 22:02:18 +00:00
{
2017-06-28 07:14:10 +00:00
value . dummied . forEach ( dummy - >
2017-06-19 22:02:18 +00:00
{
2017-06-28 07:14:10 +00:00
Map < ResourceLocation , Integer > m = missing . get ( key ) ;
ForgeRegistry < ? > reg = STAGING . getRegistry ( key ) ;
2017-06-19 22:02:18 +00: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 05:06:57 +00:00
LOGGER . debug ( REGISTRIES , " Registry {}: Resuscitating dummy entry {} " , key , dummy ) ;
2017-06-19 22:02:18 +00: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 05:06:57 +00: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 22:02:18 +00:00
reg . markDummy ( dummy , id ) ;
}
} ) ;
} ) ;
2017-06-28 07:14:10 +00:00
int count = missing . values ( ) . stream ( ) . mapToInt ( Map : : size ) . sum ( ) ;
2017-06-19 22:02:18 +00:00
if ( count > 0 )
{
2019-01-27 05:06:57 +00:00
LOGGER . debug ( REGISTRIES , " There are {} mappings missing - attempting a mod remap " , count ) ;
2017-06-19 22:02:18 +00: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 19:56:09 +00: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 22:02:18 +00:00
if ( ! lst . isEmpty ( ) )
{
2019-01-27 05:06:57 +00:00
LOGGER . error ( REGISTRIES , ( ) - > new AdvancedLogMessageAdapter ( sb - > {
2019-02-24 01:42:45 +00:00
sb . append ( " Unidentified mapping from registry " ) . append ( name ) . append ( '\n' ) ;
lst . forEach ( map - > sb . append ( '\t' ) . append ( map . key ) . append ( " : " ) . append ( map . id ) . append ( '\n' ) ) ;
2019-01-27 05:06:57 +00:00
} ) ) ;
2017-06-19 22:02:18 +00: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 12:10:07 +00:00
processMissing ( clazz , name , STAGING , event , m . getValue ( ) , remaps . get ( name ) , defaulted . get ( name ) , failed . get ( name ) , ! isLocalWorld ) ;
2017-06-19 22:02:18 +00:00
} ) ;
if ( ! defaulted . isEmpty ( ) & & ! isLocalWorld )
return defaulted ;
if ( ! defaulted . isEmpty ( ) )
{
2020-05-23 20:00:22 +00: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 22:02:18 +00:00
2020-05-23 20:00:22 +00:00
StringBuilder buf = new StringBuilder ( ) ;
2017-06-19 22:02:18 +00:00
defaulted . asMap ( ) . forEach ( ( name , entries ) - >
{
buf . append ( " Missing " ) . append ( name ) . append ( " : \ n " ) ;
entries . forEach ( rl - > buf . append ( " " ) . append ( rl ) . append ( " \ n " ) ) ;
2020-05-23 20:00:22 +00:00
buf . append ( " \ n " ) ;
2017-06-19 22:02:18 +00:00
} ) ;
}
if ( ! defaulted . isEmpty ( ) )
{
if ( isLocalWorld )
2019-01-27 05:06:57 +00:00
LOGGER . error ( REGISTRIES , " There are unidentified mappings in this world - we are going to attempt to process anyway " ) ;
2017-06-19 22:02:18 +00: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 ) - >
{
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-21 01:39:55 +00:00
STAGING . registries . forEach ( ( name , reg ) - > reg . validateContent ( name ) ) ;
2017-06-19 22:02:18 +00:00
// Load the STAGING registry into the ACTIVE registry
2018-09-06 03:06:18 +00:00
//for (Map.Entry<ResourceLocation, IForgeRegistry<? extends IForgeRegistryEntry<?>>> r : RegistryManager.ACTIVE.registries.entrySet())
RegistryManager . ACTIVE . registries . forEach ( ( key , value ) - >
2017-06-19 22:02:18 +00:00
{
2018-09-06 03:06:18 +00:00
final Class < ? extends IForgeRegistryEntry > registrySuperType = RegistryManager . ACTIVE . getSuperType ( key ) ;
loadRegistry ( key , STAGING , RegistryManager . ACTIVE , registrySuperType , true ) ;
} ) ;
2017-06-19 22:02:18 +00:00
2019-01-11 22:52:30 +00:00
RegistryManager . ACTIVE . registries . forEach ( ( name , reg ) - > {
reg . bake ( ) ;
// Dump the active registry
reg . dump ( name ) ;
} ) ;
2017-06-19 22:02:18 +00:00
// Tell mods that the ids have changed
2019-03-26 01:41:28 +00:00
fireRemapEvent ( remaps , false ) ;
2017-06-19 22:02:18 +00:00
// The id map changed, ensure we apply object holders
2019-01-10 04:57:01 +00:00
ObjectHolderRegistry . applyObjectHolders ( ) ;
2017-06-19 22:02:18 +00:00
// Return an empty list, because we're good
return ArrayListMultimap . create ( ) ;
}
2019-03-26 01:41:28 +00:00
private static void fireRemapEvent ( final Map < ResourceLocation , Map < ResourceLocation , Integer [ ] > > remaps , final boolean isFreezing ) {
2020-04-27 01:03:43 +00:00
StartupMessageManager . modLoaderConsumer ( ) . ifPresent ( s - > s . accept ( " Remapping mod data " ) ) ;
2019-03-26 01:41:28 +00:00
MinecraftForge . EVENT_BUS . post ( new FMLModIdMappingEvent ( remaps , isFreezing ) ) ;
2020-04-27 01:03:43 +00:00
StartupMessageManager . modLoaderConsumer ( ) . ifPresent ( s - > s . accept ( " Remap complete " ) ) ;
2019-03-26 01:41:28 +00:00
}
2017-06-19 22:02:18 +00:00
//Has to be split because of generics, Yay!
2018-09-06 03:06:18 +00: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 22:02:18 +00: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 07:14:10 +00:00
snap . aliases . forEach ( _new : : addAlias ) ;
snap . blocked . forEach ( _new : : block ) ;
2017-06-19 22:02:18 +00:00
// Load current dummies BEFORE the snapshot is loaded so that add() will remove from the list.
2017-06-28 07:14:10 +00:00
snap . dummied . forEach ( _new : : addDummy ) ;
2017-06-23 07:58:00 +00:00
_new . loadIds ( snap . ids , snap . overrides , missing , remaps , active , name ) ;
2017-06-19 22:02:18 +00:00
}
//Another bouncer for generic reasons
@SuppressWarnings ( " unchecked " )
2018-09-06 03:06:18 +00: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 22:02:18 +00: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 12:10:07 +00:00
staging . processMissingEvent ( name , active , mappings , missing , remaps , defaulted , failed , injectNetworkDummies ) ;
2017-06-19 22:02:18 +00:00
}
2018-09-06 03:06:18 +00:00
private static < T extends IForgeRegistryEntry < T > > void loadFrozenDataToStagingRegistry ( RegistryManager STAGING , ResourceLocation name , Map < ResourceLocation , Integer [ ] > remaps , Class < T > clazz )
2017-06-19 22:02:18 +00:00
{
ForgeRegistry < T > frozen = RegistryManager . FROZEN . getRegistry ( name ) ;
ForgeRegistry < T > newRegistry = STAGING . getRegistry ( name , RegistryManager . FROZEN ) ;
Map < ResourceLocation , Integer > _new = Maps . newHashMap ( ) ;
frozen . getKeys ( ) . stream ( ) . filter ( key - > ! newRegistry . containsKey ( key ) ) . forEach ( key - > _new . put ( key , frozen . getID ( key ) ) ) ;
2017-06-23 07:58:00 +00:00
newRegistry . loadIds ( _new , frozen . getOverrideOwners ( ) , Maps . newLinkedHashMap ( ) , remaps , frozen , name ) ;
2017-06-19 22:02:18 +00: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 23:02:15 +00: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 23:02:15 +00: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 05:52:32 +00: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-05 00:16:01 +00: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 05:52:32 +00:00
{
2018-09-06 03:06:18 +00: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 05:52:32 +00:00
prefix = oldPrefix ;
}
return new ResourceLocation ( prefix , name ) ;
}
2017-08-15 12:10:07 +00:00
private static Field regName ;
private static void forceRegistryName ( IForgeRegistryEntry < ? > entry , ResourceLocation name )
{
if ( regName = = null )
{
try
{
2018-09-06 03:06:18 +00:00
regName = ForgeRegistryEntry . class . getDeclaredField ( " registryName " ) ;
2017-08-15 12:10:07 +00:00
regName . setAccessible ( true ) ;
}
catch ( NoSuchFieldException | SecurityException e )
{
2019-01-27 05:06:57 +00:00
LOGGER . error ( REGISTRIES , " Could not get `registryName` field from IForgeRegistryEntry.Impl " , e ) ;
2017-08-15 12:10:07 +00:00
throw new RuntimeException ( e ) ;
}
}
try
{
regName . set ( entry , name ) ;
}
catch ( IllegalArgumentException | IllegalAccessException e )
{
2019-01-27 05:06:57 +00:00
LOGGER . error ( REGISTRIES , " Could not set `registryName` field in IForgeRegistryEntry.Impl to `{}` " , name . toString ( ) , e ) ;
2017-08-15 12:10:07 +00:00
throw new RuntimeException ( e ) ;
}
}
2017-06-19 22:02:18 +00:00
}