2016-06-23 03:49:47 +00:00
/ *
* Minecraft Forge
* Copyright ( c ) 2016 .
*
* 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
* /
2014-09-23 05:01:24 +00:00
package net.minecraftforge.fml.common.registry ;
2013-12-09 06:22:24 +00:00
2015-11-28 08:01:31 +00:00
import java.lang.reflect.Field ;
2013-12-09 06:22:24 +00:00
import java.util.ArrayList ;
import java.util.BitSet ;
2014-03-20 11:41:59 +00:00
import java.util.Collections ;
import java.util.HashMap ;
2015-03-22 16:54:34 +00:00
import java.util.Iterator ;
2013-12-10 02:36:49 +00:00
import java.util.List ;
2013-12-09 06:22:24 +00:00
import java.util.Map ;
2016-04-01 21:13:06 +00:00
import java.util.Map.Entry ;
2014-04-30 22:24:58 +00:00
import java.util.Set ;
2014-04-01 05:00:20 +00:00
2016-02-25 00:56:20 +00:00
import com.google.common.base.Joiner ;
2015-11-28 08:01:31 +00:00
import com.google.common.base.Throwables ;
2015-11-28 21:30:58 +00:00
import com.google.common.collect.BiMap ;
import com.google.common.collect.HashBiMap ;
import com.google.common.collect.Iterators ;
2016-04-01 21:13:06 +00:00
import com.google.common.collect.Lists ;
2015-11-28 21:30:58 +00:00
import com.google.common.collect.Maps ;
import com.google.common.collect.Sets ;
2016-04-01 21:13:06 +00:00
import org.apache.commons.lang3.Validate ;
import org.apache.logging.log4j.Level ;
2014-03-20 11:41:59 +00:00
2016-04-01 21:13:06 +00:00
import net.minecraft.util.ResourceLocation ;
import net.minecraft.util.registry.RegistryNamespacedDefaultedByKey ;
import net.minecraftforge.fml.common.FMLLog ;
import net.minecraftforge.fml.common.functions.GenericIterableFactory ;
import net.minecraftforge.fml.common.registry.RegistryDelegate.Delegate ;
public class FMLControlledNamespacedRegistry < I extends IForgeRegistryEntry < I > > extends RegistryNamespacedDefaultedByKey < ResourceLocation , I > implements IForgeRegistry < I >
2015-11-28 21:30:58 +00:00
{
2015-11-30 19:14:33 +00:00
public static final boolean DEBUG = Boolean . parseBoolean ( System . getProperty ( " fml.debugRegistryEntries " , " false " ) ) ;
2013-12-09 06:22:24 +00:00
private final Class < I > superType ;
2015-11-28 08:01:31 +00:00
private final boolean isDelegated ;
private ResourceLocation optionalDefaultKey ;
2013-12-09 06:22:24 +00:00
private I optionalDefaultObject ;
2014-03-24 23:36:37 +00:00
private int maxId ;
2013-12-09 06:22:24 +00:00
private int minId ;
2015-11-28 08:01:31 +00:00
/ * *
* Aliases are resource location to resource location pointers , allowing for alternative names to be supplied
* pointing at the same thing . They are used to allow programmatic migration of an ID .
* /
2015-11-28 21:30:58 +00:00
private final Map < ResourceLocation , ResourceLocation > aliases = Maps . newHashMap ( ) ;
2015-11-28 08:01:31 +00:00
/ * *
* Persistent substitutions are the mechanism to allow mods to override specific behaviours with new behaviours .
* /
private final BiMap < ResourceLocation , I > persistentSubstitutions = HashBiMap . create ( ) ;
/ * *
* This is the current active substitution set for a particular world . It will change as worlds come and go .
* /
private final BiMap < ResourceLocation , I > activeSubstitutions = HashBiMap . create ( ) ;
/ * *
* The list of IDs blocked for this world . IDs will never be allocated in this set .
* /
private final Set < Integer > blockedIds = Sets . newHashSet ( ) ;
2013-12-09 06:22:24 +00:00
2015-12-31 22:58:30 +00:00
private final Set < ResourceLocation > dummiedLocations = Sets . newHashSet ( ) ;
2015-11-28 08:01:31 +00:00
private final BitSet availabilityMap ;
2015-11-28 21:30:58 +00:00
2016-04-01 21:13:06 +00:00
private final Map < ResourceLocation , ? > slaves = Maps . newHashMap ( ) ;
2015-11-28 21:30:58 +00:00
private final AddCallback < I > addCallback ;
2016-04-01 21:13:06 +00:00
private final ClearCallback < I > clearCallback ;
2015-11-28 21:30:58 +00:00
2016-04-01 21:13:06 +00:00
private final CreateCallback < I > createCallback ;
2015-11-28 21:30:58 +00:00
2016-04-01 21:13:06 +00:00
FMLControlledNamespacedRegistry ( ResourceLocation defaultKey , int minIdValue , int maxIdValue , Class < I > type , AddCallback < I > addCallback , ClearCallback < I > clearCallback , CreateCallback < I > createCallback )
2013-12-09 06:22:24 +00:00
{
2014-09-20 00:24:36 +00:00
super ( defaultKey ) ;
2013-12-09 06:22:24 +00:00
this . superType = type ;
2014-09-20 00:24:36 +00:00
this . optionalDefaultKey = defaultKey ;
2013-12-09 06:22:24 +00:00
this . minId = minIdValue ;
2016-04-01 21:13:06 +00:00
this . maxId = maxIdValue ;
2015-11-28 08:01:31 +00:00
this . availabilityMap = new BitSet ( maxIdValue + 1 ) ;
2016-04-01 21:13:06 +00:00
this . isDelegated = IForgeRegistryEntry . Impl . class . isAssignableFrom ( type ) ;
this . addCallback = addCallback ;
this . clearCallback = clearCallback ;
this . createCallback = createCallback ;
if ( createCallback ! = null )
2015-11-28 21:30:58 +00:00
{
2016-04-01 21:13:06 +00:00
createCallback . onCreate ( slaves ) ;
2015-11-28 08:01:31 +00:00
}
2013-12-09 06:22:24 +00:00
}
2015-11-28 08:01:31 +00:00
void validateContent ( ResourceLocation registryName )
2014-04-30 22:24:58 +00:00
{
for ( I obj : typeSafeIterable ( ) )
{
int id = getId ( obj ) ;
2015-11-28 08:01:31 +00:00
ResourceLocation name = getNameForObject ( obj ) ;
2015-10-29 12:46:23 +00:00
boolean isSubstituted = activeSubstitutions . containsKey ( name ) ;
2014-09-20 00:24:36 +00:00
// name lookup failed -> obj is not in the obj<->name map
2015-11-28 21:30:58 +00:00
if ( name = = null )
{
throw new IllegalStateException ( String . format ( " Registry entry for %s %s, id %d, doesn't yield a name. " , registryName , obj , id ) ) ;
}
2014-04-30 22:24:58 +00:00
// id lookup failed -> obj is not in the obj<->id map
2015-11-28 21:30:58 +00:00
if ( ! isSubstituted & & id < 0 )
{
throw new IllegalStateException ( String . format ( " Registry entry for %s %s, name %s, doesn't yield an id. " , registryName , obj , name ) ) ;
}
2014-04-30 22:24:58 +00:00
// id is too high
2015-11-28 21:30:58 +00:00
if ( id > maxId )
{
throw new IllegalStateException ( String . format ( " Registry entry for %s %s, name %s uses the too large id %d. " , registryName , obj , name , id ) ) ;
}
2015-10-29 12:46:23 +00:00
// the rest of the tests don't really work for substituted items or blocks
2015-11-28 21:30:58 +00:00
if ( isSubstituted )
{
continue ;
}
2014-04-30 22:24:58 +00:00
// id -> obj lookup is inconsistent
2015-11-28 21:30:58 +00:00
if ( getRaw ( id ) ! = obj )
{
throw new IllegalStateException ( String . format ( " Registry entry for id %d, name %s, doesn't yield the expected %s %s. " , id , name , registryName , obj ) ) ;
}
2014-04-30 22:24:58 +00:00
// name -> obj lookup is inconsistent
2015-11-28 21:30:58 +00:00
if ( getRaw ( name ) ! = obj )
{
throw new IllegalStateException ( String . format ( " Registry entry for name %s, id %d, doesn't yield the expected %s %s. " , name , id , registryName , obj ) ) ;
}
2014-04-30 22:24:58 +00:00
// name -> id lookup is inconsistent
2015-11-28 21:30:58 +00:00
if ( getId ( name ) ! = id )
{
throw new IllegalStateException ( String . format ( " Registry entry for name %s doesn't yield the expected id %d. " , name , id ) ) ;
}
2015-12-23 16:18:54 +00:00
/ *
2014-04-30 22:24:58 +00:00
// entry is blocked, thus should be empty
2015-11-28 21:30:58 +00:00
if ( blockedIds . contains ( id ) )
{
throw new IllegalStateException ( String . format ( " Registry entry for %s %s, id %d, name %s, marked as dangling. " , registryName , obj , id , name ) ) ;
}
2015-12-23 16:18:54 +00:00
* /
2014-04-30 22:24:58 +00:00
}
}
2015-03-15 20:22:28 +00:00
2015-11-28 08:01:31 +00:00
void set ( FMLControlledNamespacedRegistry < I > otherRegistry )
2013-12-09 06:22:24 +00:00
{
2015-11-28 21:30:58 +00:00
if ( this . superType ! = otherRegistry . superType )
{
throw new IllegalArgumentException ( " incompatible registry " ) ;
}
2013-12-09 06:22:24 +00:00
2015-11-28 08:01:31 +00:00
this . optionalDefaultKey = otherRegistry . optionalDefaultKey ;
this . maxId = otherRegistry . maxId ;
this . minId = otherRegistry . minId ;
2014-03-27 07:30:55 +00:00
this . aliases . clear ( ) ;
2015-11-28 08:01:31 +00:00
this . aliases . putAll ( otherRegistry . aliases ) ;
2015-12-23 15:37:11 +00:00
this . persistentSubstitutions . clear ( ) ;
this . persistentSubstitutions . putAll ( otherRegistry . getPersistentSubstitutions ( ) ) ;
2015-03-22 16:03:37 +00:00
this . activeSubstitutions . clear ( ) ;
2015-12-31 22:58:30 +00:00
this . dummiedLocations . clear ( ) ;
this . dummiedLocations . addAll ( otherRegistry . dummiedLocations ) ;
2015-03-22 16:03:37 +00:00
2016-05-18 12:11:56 +00:00
underlyingIntegerMap . clear ( ) ;
2014-04-01 05:00:20 +00:00
registryObjects . clear ( ) ;
2013-12-26 17:41:49 +00:00
2015-11-28 08:01:31 +00:00
for ( I thing : otherRegistry . typeSafeIterable ( ) )
2013-12-26 17:41:49 +00:00
{
2015-11-28 08:01:31 +00:00
addObjectRaw ( otherRegistry . getId ( thing ) , otherRegistry . getNameForObject ( thing ) , thing ) ;
2013-12-26 17:41:49 +00:00
}
2015-11-28 08:01:31 +00:00
this . activeSubstitutions . putAll ( otherRegistry . activeSubstitutions ) ;
2014-03-20 11:41:59 +00:00
}
2013-12-26 17:41:49 +00:00
2014-03-24 23:36:37 +00:00
// public api
2014-03-20 11:41:59 +00:00
/ * *
* Add an object to the registry , trying to use the specified id .
2015-11-28 08:01:31 +00:00
* This is required , to re - route vanilla block and item registration through to
* the { @link # add } method .
2014-03-20 11:41:59 +00:00
*
* @deprecated register through { @link GameRegistry } instead .
* /
@Override
@Deprecated
2015-11-28 08:01:31 +00:00
public void register ( int id , ResourceLocation name , I thing )
2014-03-20 11:41:59 +00:00
{
2015-11-28 08:01:31 +00:00
add ( id , name , thing ) ;
2013-12-24 05:47:10 +00:00
}
2014-03-20 11:41:59 +00:00
2014-04-06 15:11:23 +00:00
/ * *
* DANGEROUS ! EVIL ! DO NOT USE !
*
* @deprecated register through { @link GameRegistry } instead .
* /
@Override
@Deprecated
2015-11-28 08:01:31 +00:00
public void putObject ( ResourceLocation name , I thing )
2014-04-06 15:11:23 +00:00
{
2015-11-28 21:30:58 +00:00
if ( name = = null )
{
throw new NullPointerException ( " Can't use a null-name for the registry. " ) ;
}
if ( thing = = null )
{
throw new NullPointerException ( " Can't add null-object to the registry. " ) ;
}
2014-04-06 15:11:23 +00:00
2015-11-28 08:01:31 +00:00
ResourceLocation existingName = getNameForObject ( thing ) ;
2014-04-06 15:11:23 +00:00
if ( existingName = = null )
{
FMLLog . bigWarning ( " Ignoring putObject(%s, %s), not resolvable " , name , thing ) ;
}
else if ( existingName . equals ( name ) )
{
FMLLog . bigWarning ( " Ignoring putObject(%s, %s), already added " , name , thing ) ;
}
else
{
FMLLog . bigWarning ( " Ignoring putObject(%s, %s), adding alias to %s instead " , name , thing , existingName ) ;
2015-11-28 08:01:31 +00:00
addAlias ( name , existingName ) ;
2014-04-06 15:11:23 +00:00
}
}
2014-04-07 15:30:38 +00:00
/ * *
* Fetch the object identified by the specified name or the default object .
2015-11-28 21:30:58 +00:00
* < p / >
2014-04-07 15:30:38 +00:00
* For blocks the default object is the air block , for items it ' s null .
*
* @param name Unique name identifying the object .
* @return Registered object of the default object if it wasn ' t found -
* /
2013-12-09 06:22:24 +00:00
@Override
2015-11-28 08:01:31 +00:00
public I getObject ( ResourceLocation name )
2013-12-09 06:22:24 +00:00
{
2015-11-28 08:01:31 +00:00
I object = getRaw ( name ) ;
2013-12-09 06:22:24 +00:00
return object = = null ? this . optionalDefaultObject : object ;
}
2014-04-07 15:30:38 +00:00
/ * *
* Fetch the object identified by the specified id or the default object .
2015-11-28 21:30:58 +00:00
* < p / >
2014-04-07 15:30:38 +00:00
* For blocks the default object is the air block , for items it ' s null .
*
* @param id ID identifying the object .
* @return Registered object of the default object if it wasn ' t found -
* /
2013-12-09 06:22:24 +00:00
@Override
2014-03-19 07:15:53 +00:00
public I getObjectById ( int id )
2013-12-09 06:22:24 +00:00
{
2014-03-24 23:36:37 +00:00
I object = getRaw ( id ) ;
2013-12-09 06:22:24 +00:00
return object = = null ? this . optionalDefaultObject : object ;
}
2014-03-24 23:36:37 +00:00
/ * *
* Get the id for the specified object .
2015-11-28 21:30:58 +00:00
* < p / >
2014-03-24 23:36:37 +00:00
* Don ' t hold onto the id across the world , it ' s being dynamically re - mapped as needed .
2015-11-28 21:30:58 +00:00
* < p / >
2014-03-24 23:36:37 +00:00
* Usually the name should be used instead of the id , if using the Block / Item object itself is
* not suitable for the task .
*
2014-03-27 07:30:55 +00:00
* @param thing Block / Item object .
2014-03-24 23:36:37 +00:00
* @return Block / Item id or - 1 if it wasn ' t found .
* /
public int getId ( I thing )
2013-12-09 06:22:24 +00:00
{
2016-03-09 22:41:13 +00:00
return getIDForObjectBypass ( thing ) ;
2013-12-10 02:36:49 +00:00
}
2014-03-24 23:36:37 +00:00
/ * *
* Get the object identified by the specified id .
*
* @param id Block / Item id .
* @return Block / Item object or null if it wasn ' t found .
* /
public I getRaw ( int id )
2013-12-10 02:36:49 +00:00
{
2015-11-28 08:01:31 +00:00
return super . getObjectById ( id ) ;
2014-09-20 00:24:36 +00:00
}
/ * *
* Get the object identified by the specified name .
*
* @param name Block / Item name .
* @return Block / Item object or null if it wasn ' t found .
* /
2015-11-28 08:01:31 +00:00
private I getRaw ( ResourceLocation name )
2014-09-20 00:24:36 +00:00
{
2015-11-28 08:01:31 +00:00
I ret = super . getObject ( name ) ;
2013-12-10 02:36:49 +00:00
2014-03-24 23:36:37 +00:00
if ( ret = = null ) // no match, try aliases recursively
2013-12-24 05:47:10 +00:00
{
2015-11-28 08:01:31 +00:00
name = aliases . get ( name ) ;
2014-03-24 23:36:37 +00:00
2015-11-28 21:30:58 +00:00
if ( name ! = null )
{
return getRaw ( name ) ;
}
2013-12-24 05:47:10 +00:00
}
2013-12-09 06:22:24 +00:00
2014-03-20 11:41:59 +00:00
return ret ;
2013-12-18 16:15:03 +00:00
}
2014-04-07 15:30:38 +00:00
/ * *
* Determine if the registry has an entry for the specified name .
2015-11-28 21:30:58 +00:00
* < p / >
2014-04-07 15:30:38 +00:00
* Aliased names will be resolved as well .
*
* @param name Object name to check .
* @return true if a matching entry was found .
* /
2014-03-24 23:36:37 +00:00
@Override
2015-11-28 08:01:31 +00:00
public boolean containsKey ( ResourceLocation name )
2013-12-09 06:22:24 +00:00
{
2014-04-01 05:00:20 +00:00
boolean ret = super . containsKey ( name ) ;
2013-12-09 06:22:24 +00:00
2014-03-24 23:36:37 +00:00
if ( ! ret ) // no match, try aliases recursively
{
name = aliases . get ( name ) ;
2013-12-09 06:22:24 +00:00
2015-11-28 21:30:58 +00:00
if ( name ! = null )
{
return containsKey ( name ) ;
}
2014-03-24 23:36:37 +00:00
}
return ret ;
2013-12-09 06:22:24 +00:00
}
2013-12-10 02:36:49 +00:00
2014-03-27 07:30:55 +00:00
/ * *
* Get the id for the specified object .
2015-11-28 21:30:58 +00:00
* < p / >
2014-03-27 07:30:55 +00:00
* Don ' t hold onto the id across the world , it ' s being dynamically re - mapped as needed .
2015-11-28 21:30:58 +00:00
* < p / >
2014-03-27 07:30:55 +00:00
* Usually the name should be used instead of the id , if using the Block / Item object itself is
* not suitable for the task .
*
* @param itemName Block / Item registry name .
* @return Block / Item id or - 1 if it wasn ' t found .
* /
2015-11-28 08:01:31 +00:00
public int getId ( ResourceLocation itemName )
2013-12-09 06:22:24 +00:00
{
2014-03-24 23:36:37 +00:00
I obj = getRaw ( itemName ) ;
2015-11-28 21:30:58 +00:00
if ( obj = = null )
{
return - 1 ;
}
2014-03-24 23:36:37 +00:00
return getId ( obj ) ;
2013-12-09 06:22:24 +00:00
}
2013-12-10 02:36:49 +00:00
2015-03-22 16:54:34 +00:00
/ *
* This iterator is used by FML to visit the actual block sets , it should use the super . iterator method instead
* Compare # iterator ( )
* /
2014-04-22 23:49:07 +00:00
public Iterable < I > typeSafeIterable ( )
{
2015-03-22 16:54:34 +00:00
return GenericIterableFactory . newCastingIterable ( super . iterator ( ) , superType ) ;
2014-04-22 23:49:07 +00:00
}
2014-03-24 23:36:37 +00:00
// internal
2015-11-28 08:01:31 +00:00
public void serializeIds ( Map < ResourceLocation , Integer > idMapping ) // for saving
2013-12-10 02:36:49 +00:00
{
2014-04-22 23:49:07 +00:00
for ( I thing : this . typeSafeIterable ( ) )
2014-03-20 11:41:59 +00:00
{
2015-11-28 08:01:31 +00:00
idMapping . put ( getNameForObject ( thing ) , getId ( thing ) ) ;
2014-03-20 11:41:59 +00:00
}
2013-12-10 02:36:49 +00:00
}
2015-11-28 21:30:58 +00:00
2015-11-28 08:01:31 +00:00
public void serializeAliases ( Map < ResourceLocation , ResourceLocation > map )
2014-10-01 08:07:23 +00:00
{
map . putAll ( this . aliases ) ;
}
2015-11-28 08:01:31 +00:00
public void serializeSubstitutions ( Set < ResourceLocation > set )
2013-12-10 02:36:49 +00:00
{
2014-10-01 08:07:23 +00:00
set . addAll ( activeSubstitutions . keySet ( ) ) ;
2014-03-24 23:36:37 +00:00
}
2014-03-20 11:41:59 +00:00
2015-12-31 22:58:30 +00:00
public void serializeDummied ( Set < ResourceLocation > set ) { set . addAll ( this . dummiedLocations ) ; }
2014-04-07 15:30:38 +00:00
/ * *
* Add the specified object to the registry .
*
2015-11-28 21:30:58 +00:00
* @param id ID to use if available , auto - assigned otherwise .
* @param name Name to use , prefixed by the mod id .
2014-04-07 15:30:38 +00:00
* @param thing Object to add .
* @return ID eventually allocated .
* /
2015-11-28 08:01:31 +00:00
int add ( int id , ResourceLocation name , I thing )
2014-03-24 23:36:37 +00:00
{
2015-11-28 21:30:58 +00:00
if ( name = = null )
{
throw new NullPointerException ( String . format ( " Can't use a null-name for the registry, object %s. " , thing ) ) ;
}
if ( thing = = null )
{
throw new NullPointerException ( String . format ( " Can't add null-object to the registry, name %s. " , name ) ) ;
}
2015-11-28 08:01:31 +00:00
if ( optionalDefaultKey ! = null & & optionalDefaultKey . equals ( name ) & & this . optionalDefaultObject = = null )
2014-03-24 23:36:37 +00:00
{
this . optionalDefaultObject = thing ;
}
2014-08-20 14:28:39 +00:00
if ( getPersistentSubstitutions ( ) . containsValue ( thing ) )
{
throw new IllegalArgumentException ( String . format ( " The object %s (%s) cannot be added to the registry. It is already being used as a substitute for %s " , thing . getClass ( ) , name , getPersistentSubstitutions ( ) . inverse ( ) . get ( thing ) ) ) ;
}
2014-03-24 23:36:37 +00:00
int idToUse = id ;
2014-04-09 20:21:04 +00:00
if ( idToUse < 0 | | availabilityMap . get ( idToUse ) )
2014-03-24 23:36:37 +00:00
{
idToUse = availabilityMap . nextClearBit ( minId ) ;
}
2014-04-07 15:30:38 +00:00
if ( idToUse > maxId )
2014-03-24 23:36:37 +00:00
{
2014-04-09 20:21:04 +00:00
throw new RuntimeException ( String . format ( " Invalid id %d - maximum id range exceeded. " , idToUse ) ) ;
2014-03-24 23:36:37 +00:00
}
2014-04-06 15:11:23 +00:00
if ( getRaw ( name ) = = thing ) // already registered, return prev registration's id
{
FMLLog . bigWarning ( " The object %s has been registered twice for the same name %s. " , thing , name ) ;
return getId ( thing ) ;
}
2014-04-11 04:33:36 +00:00
if ( getRaw ( name ) ! = null ) // duplicate name
2014-04-01 12:40:24 +00:00
{
2014-04-11 04:33:36 +00:00
throw new IllegalArgumentException ( String . format ( " The name %s has been registered twice, for %s and %s. " , name , getRaw ( name ) , thing ) ) ;
2014-04-01 12:40:24 +00:00
}
2014-08-20 14:28:39 +00:00
if ( getId ( thing ) > = 0 ) // duplicate object - but only if it's not being substituted
2014-04-01 12:40:24 +00:00
{
2014-05-10 18:53:08 +00:00
int foundId = getId ( thing ) ;
2015-11-28 08:01:31 +00:00
I otherThing = getRaw ( foundId ) ;
2014-09-30 09:20:56 +00:00
throw new IllegalArgumentException ( String . format ( " The object %s{%x} has been registered twice, using the names %s and %s. (Other object at this id is %s{%x}) " , thing , System . identityHashCode ( thing ) , getNameForObject ( thing ) , name , otherThing , System . identityHashCode ( otherThing ) ) ) ;
2014-04-01 12:40:24 +00:00
}
2015-11-28 08:01:31 +00:00
if ( PersistentRegistryManager . isFrozen ( this ) )
2014-04-06 12:49:59 +00:00
{
2014-04-06 15:11:23 +00:00
FMLLog . bigWarning ( " The object %s (name %s) is being added too late. " , thing , name ) ;
2014-04-06 12:49:59 +00:00
}
2014-04-01 12:40:24 +00:00
2014-08-20 14:28:39 +00:00
if ( activeSubstitutions . containsKey ( name ) )
{
2015-11-28 08:01:31 +00:00
I oldThing = thing ;
2014-08-20 14:28:39 +00:00
thing = activeSubstitutions . get ( name ) ;
2015-11-28 21:30:58 +00:00
if ( DEBUG )
{
FMLLog . getLogger ( ) . log ( Level . DEBUG , " Active substitution: {} {}@{} -> {}@{} " , name , oldThing . getClass ( ) . getName ( ) , System . identityHashCode ( oldThing ) , thing . getClass ( ) . getName ( ) , System . identityHashCode ( thing ) ) ;
}
2014-08-20 14:28:39 +00:00
}
2014-04-06 15:11:23 +00:00
2015-11-28 08:01:31 +00:00
addObjectRaw ( idToUse , name , thing ) ;
if ( isDelegated )
{
2016-04-01 21:13:06 +00:00
getExistingDelegate ( thing ) . setName ( name ) ;
2015-11-28 08:01:31 +00:00
}
2016-02-25 00:56:20 +00:00
if ( this . dummiedLocations . remove ( name ) & & DEBUG )
{
FMLLog . fine ( " Registry Dummy Remove: %s " , name ) ;
}
2015-12-31 22:58:30 +00:00
2015-06-10 04:32:40 +00:00
if ( DEBUG )
2015-11-28 21:30:58 +00:00
{
2015-06-10 04:32:40 +00:00
FMLLog . finer ( " Registry add: %s %d %s (req. id %d) " , name , idToUse , thing , id ) ;
2015-11-28 21:30:58 +00:00
}
2014-03-24 23:36:37 +00:00
return idToUse ;
2013-12-10 02:36:49 +00:00
}
2015-12-31 22:58:30 +00:00
void markDummy ( ResourceLocation rl , Integer id , I thing )
{
2016-02-25 00:56:20 +00:00
if ( DEBUG )
{
FMLLog . finer ( " Registry Dummy Add: %s %d -> %s " , rl , id , thing ) ;
}
2015-12-31 22:58:30 +00:00
this . dummiedLocations . add ( rl ) ;
this . addObjectRaw ( id , rl , thing ) ;
}
2015-11-28 08:01:31 +00:00
void addAlias ( ResourceLocation from , ResourceLocation to )
2013-12-10 02:36:49 +00:00
{
2014-03-24 23:36:37 +00:00
aliases . put ( from , to ) ;
2015-06-10 04:32:40 +00:00
if ( DEBUG )
2015-11-28 21:30:58 +00:00
{
2015-06-10 04:32:40 +00:00
FMLLog . finer ( " Registry alias: %s -> %s " , from , to ) ;
2015-11-28 21:30:58 +00:00
}
2014-03-24 23:36:37 +00:00
}
2015-11-28 21:30:58 +00:00
Map < ResourceLocation , Integer > getEntriesNotIn ( FMLControlledNamespacedRegistry < I > registry )
2014-03-24 23:36:37 +00:00
{
2015-11-28 21:30:58 +00:00
Map < ResourceLocation , Integer > ret = new HashMap < ResourceLocation , Integer > ( ) ;
2014-03-24 23:36:37 +00:00
2014-04-22 23:49:07 +00:00
for ( I thing : this . typeSafeIterable ( ) )
2014-03-24 23:36:37 +00:00
{
2015-11-24 04:18:52 +00:00
if ( ! registry . inverseObjectRegistry . containsKey ( thing ) )
2014-08-20 14:28:39 +00:00
{
2015-11-28 08:01:31 +00:00
if ( ! registry . activeSubstitutions . containsKey ( getNameForObject ( thing ) ) )
2014-08-20 14:28:39 +00:00
{
2015-11-28 08:01:31 +00:00
ret . put ( getNameForObject ( thing ) , getId ( thing ) ) ;
2014-08-20 14:28:39 +00:00
}
}
2014-03-24 23:36:37 +00:00
}
return ret ;
2013-12-10 02:36:49 +00:00
}
2013-12-26 17:41:49 +00:00
2015-11-28 08:01:31 +00:00
void dump ( ResourceLocation registryName )
2013-12-26 17:41:49 +00:00
{
2015-06-10 04:32:40 +00:00
if ( ! DEBUG )
2015-11-28 21:30:58 +00:00
{
2015-06-10 04:32:40 +00:00
return ;
2015-11-28 21:30:58 +00:00
}
2015-06-10 04:32:40 +00:00
2014-03-20 11:41:59 +00:00
List < Integer > ids = new ArrayList < Integer > ( ) ;
2014-04-22 23:49:07 +00:00
for ( I thing : this . typeSafeIterable ( ) )
2013-12-26 17:41:49 +00:00
{
2014-03-27 07:30:55 +00:00
ids . add ( getId ( thing ) ) ;
2014-03-20 11:41:59 +00:00
}
// sort by id
Collections . sort ( ids ) ;
2015-11-28 08:01:31 +00:00
FMLLog . finer ( " Registry Name : {} " , registryName ) ;
2014-03-20 11:41:59 +00:00
for ( int id : ids )
{
I thing = getRaw ( id ) ;
2015-06-10 04:32:40 +00:00
FMLLog . finer ( " Registry: %d %s %s " , id , getNameForObject ( thing ) , thing ) ;
2013-12-26 17:41:49 +00:00
}
2014-02-01 11:05:33 +00:00
}
2014-04-06 15:11:23 +00:00
/ * *
* Version of addObject not using the API restricting overrides .
* /
2015-11-28 08:01:31 +00:00
private void addObjectRaw ( int id , ResourceLocation name , I thing )
2014-04-06 15:11:23 +00:00
{
2015-11-28 21:30:58 +00:00
if ( name = = null )
{
throw new NullPointerException ( " The name to be added to the registry is null. This can only happen with a corrupted registry state. Reflection/ASM hackery? Registry bug? " ) ;
}
if ( thing = = null )
{
throw new NullPointerException ( " The object to be added to the registry is null. This can only happen with a corrupted registry state. Reflection/ASM hackery? Registry bug? " ) ;
}
if ( ! superType . isInstance ( thing ) )
{
throw new IllegalArgumentException ( " The object to be added to the registry is not of the right type. Reflection/ASM hackery? Registry bug? " ) ;
}
2014-04-06 15:11:23 +00:00
2016-03-13 01:40:03 +00:00
underlyingIntegerMap . put ( thing , id ) ; // obj <-> id
2014-04-22 23:49:07 +00:00
super . putObject ( name , thing ) ; // name <-> obj
2015-11-28 08:01:31 +00:00
availabilityMap . set ( id ) ;
2015-11-28 21:30:58 +00:00
if ( addCallback ! = null )
{
2016-04-01 21:13:06 +00:00
addCallback . onAdd ( thing , id , slaves ) ;
2015-11-28 21:30:58 +00:00
}
2014-04-22 23:49:07 +00:00
}
2014-05-26 14:58:13 +00:00
public I getDefaultValue ( )
{
return optionalDefaultObject ;
}
2014-07-30 23:48:31 +00:00
2015-11-28 21:30:58 +00:00
public RegistryDelegate < I > getDelegate ( I thing , Class < I > clazz )
{
2015-11-28 08:01:31 +00:00
return new RegistryDelegate . Delegate < I > ( thing , clazz ) ;
2014-07-30 23:48:31 +00:00
}
2014-08-01 23:36:18 +00:00
2015-11-28 08:01:31 +00:00
@SuppressWarnings ( " unchecked " )
2016-04-01 21:13:06 +00:00
private Delegate < I > getExistingDelegate ( I thing )
2015-11-28 21:30:58 +00:00
{
2016-04-01 21:13:06 +00:00
if ( isDelegated )
2015-11-28 21:30:58 +00:00
{
2016-04-01 21:13:06 +00:00
return ( Delegate < I > ) ( ( IForgeRegistryEntry . Impl < I > ) thing ) . delegate ;
}
else
2015-11-28 21:30:58 +00:00
{
2016-04-01 21:13:06 +00:00
return null ;
2015-11-28 08:01:31 +00:00
}
}
2015-11-28 21:30:58 +00:00
2015-12-23 21:41:53 +00:00
I activateSubstitution ( ResourceLocation nameToReplace )
2014-08-20 14:28:39 +00:00
{
if ( getPersistentSubstitutions ( ) . containsKey ( nameToReplace ) )
{
2015-10-29 12:46:23 +00:00
I original = getRaw ( nameToReplace ) ;
2015-11-28 08:01:31 +00:00
I sub = getPersistentSubstitutions ( ) . get ( nameToReplace ) ;
getExistingDelegate ( original ) . changeReference ( sub ) ;
activeSubstitutions . put ( nameToReplace , sub ) ;
2015-12-23 21:41:53 +00:00
return original ;
2014-08-20 14:28:39 +00:00
}
2015-12-23 21:41:53 +00:00
return null ;
2014-08-20 14:28:39 +00:00
}
2015-11-28 21:30:58 +00:00
void addSubstitutionAlias ( String modId , ResourceLocation nameToReplace , I replacement ) throws ExistingSubstitutionException
{
2015-11-28 08:01:31 +00:00
if ( getPersistentSubstitutions ( ) . containsKey ( nameToReplace ) | | getPersistentSubstitutions ( ) . containsValue ( replacement ) )
2014-08-20 14:28:39 +00:00
{
2015-11-28 08:01:31 +00:00
FMLLog . severe ( " The substitution of %s has already occurred. You cannot duplicate substitutions " , nameToReplace ) ;
throw new ExistingSubstitutionException ( nameToReplace , replacement ) ;
2014-08-20 14:28:39 +00:00
}
I original = getRaw ( nameToReplace ) ;
2014-08-21 02:46:39 +00:00
if ( original = = null )
{
throw new NullPointerException ( " The replacement target is not present. This won't work " ) ;
}
2014-08-20 14:28:39 +00:00
if ( ! original . getClass ( ) . isAssignableFrom ( replacement . getClass ( ) ) )
{
FMLLog . severe ( " The substitute %s for %s (type %s) is type incompatible. This won't work " , replacement . getClass ( ) . getName ( ) , nameToReplace , original . getClass ( ) . getName ( ) ) ;
throw new IncompatibleSubstitutionException ( nameToReplace , replacement , original ) ;
}
int existingId = getId ( replacement ) ;
if ( existingId ! = - 1 )
{
FMLLog . severe ( " The substitute %s for %s is registered into the game independently. This won't work " , replacement . getClass ( ) . getName ( ) , nameToReplace ) ;
throw new IllegalArgumentException ( " The object substitution is already registered. This won't work " ) ;
}
2015-10-29 12:46:23 +00:00
FMLLog . log ( Level . DEBUG , " Adding substitution %s with %s (name %s) " , original , replacement , nameToReplace ) ;
2014-08-20 14:28:39 +00:00
getPersistentSubstitutions ( ) . put ( nameToReplace , replacement ) ;
}
2015-12-23 15:37:11 +00:00
BiMap < ResourceLocation , I > getPersistentSubstitutions ( )
2014-08-20 14:28:39 +00:00
{
return persistentSubstitutions ;
2014-08-01 23:36:18 +00:00
}
2014-09-20 00:24:36 +00:00
@Override
2014-09-30 09:20:56 +00:00
public void validateKey ( )
2014-09-20 00:24:36 +00:00
{
if ( this . optionalDefaultKey ! = null )
2015-11-28 21:30:58 +00:00
{
2014-09-20 00:24:36 +00:00
Validate . notNull ( this . optionalDefaultObject ) ;
2015-11-28 21:30:58 +00:00
}
2014-09-20 00:24:36 +00:00
}
2015-11-28 21:30:58 +00:00
2015-03-22 16:54:34 +00:00
/ *
* This iterator is used by some regular MC methods to visit all blocks , we need to include substitutions
* Compare # typeSafeIterable ( )
* /
@Override
public Iterator < I > iterator ( )
{
2015-11-28 21:30:58 +00:00
return Iterators . concat ( super . iterator ( ) , getPersistentSubstitutions ( ) . values ( ) . iterator ( ) ) ;
2015-03-22 16:54:34 +00:00
}
2015-10-29 12:46:23 +00:00
2015-03-15 20:22:28 +00:00
2015-11-28 21:30:58 +00:00
FMLControlledNamespacedRegistry < I > makeShallowCopy ( )
{
2016-04-01 21:13:06 +00:00
return new FMLControlledNamespacedRegistry < I > ( optionalDefaultKey , minId , maxId , superType , addCallback , clearCallback , createCallback ) ;
2015-03-15 20:22:28 +00:00
}
2015-11-28 08:01:31 +00:00
2015-10-29 12:46:23 +00:00
void resetSubstitutionDelegates ( )
{
2015-11-28 21:30:58 +00:00
if ( ! isDelegated )
{
return ;
}
for ( I obj : typeSafeIterable ( ) )
{
2015-11-28 08:01:31 +00:00
Delegate < I > delegate = getExistingDelegate ( obj ) ;
delegate . changeReference ( obj ) ;
2015-10-29 12:46:23 +00:00
}
}
2015-11-28 08:01:31 +00:00
@SuppressWarnings ( " unchecked " )
2016-04-01 21:13:06 +00:00
public < T extends IForgeRegistryEntry < T > > FMLControlledNamespacedRegistry < T > asType ( Class < ? extends T > type )
2015-11-28 08:01:31 +00:00
{
2015-11-28 21:30:58 +00:00
return ( FMLControlledNamespacedRegistry < T > ) this ;
2015-11-28 08:01:31 +00:00
}
2015-11-28 21:30:58 +00:00
public void serializeBlockList ( Set < Integer > blocked )
{
2015-11-28 08:01:31 +00:00
blocked . addAll ( this . blockedIds ) ;
}
2015-11-28 21:30:58 +00:00
public Set < ? extends ResourceLocation > getActiveSubstitutions ( )
{
2015-11-28 08:01:31 +00:00
return activeSubstitutions . keySet ( ) ;
}
2015-11-28 21:30:58 +00:00
public void loadAliases ( Map < ResourceLocation , ResourceLocation > aliases )
{
for ( Map . Entry < ResourceLocation , ResourceLocation > alias : aliases . entrySet ( ) )
{
2015-11-28 08:01:31 +00:00
addAlias ( alias . getKey ( ) , alias . getValue ( ) ) ;
}
}
2015-11-28 21:30:58 +00:00
public void loadSubstitutions ( Set < ResourceLocation > substitutions )
{
for ( ResourceLocation rl : substitutions )
{
2015-11-28 08:01:31 +00:00
activateSubstitution ( rl ) ;
}
}
2015-11-28 21:30:58 +00:00
public void loadBlocked ( Set < Integer > blocked )
{
for ( Integer id : blocked )
{
2015-11-28 08:01:31 +00:00
blockedIds . add ( id ) ;
availabilityMap . set ( id ) ;
}
}
2015-12-31 22:58:30 +00:00
public void loadDummied ( Set < ResourceLocation > dummied )
{
2016-02-25 00:56:20 +00:00
if ( DEBUG & & dummied . size ( ) > 0 )
{
FMLLog . fine ( " Registry Dummy Load: [%s] " , Joiner . on ( " , " ) . join ( dummied ) ) ;
}
2015-12-31 22:58:30 +00:00
this . dummiedLocations . addAll ( dummied ) ;
}
2015-11-28 21:30:58 +00:00
public void loadIds ( Map < ResourceLocation , Integer > ids , Map < ResourceLocation , Integer > missingIds , Map < ResourceLocation , Integer [ ] > remappedIds , FMLControlledNamespacedRegistry < I > currentRegistry , ResourceLocation registryName )
{
for ( Map . Entry < ResourceLocation , Integer > entry : ids . entrySet ( ) )
{
2015-11-28 08:01:31 +00:00
ResourceLocation itemName = entry . getKey ( ) ;
int newId = entry . getValue ( ) ;
int currId = currentRegistry . getId ( itemName ) ;
2015-11-28 21:30:58 +00:00
if ( currId = = - 1 )
{
2015-11-28 08:01:31 +00:00
FMLLog . info ( " Found a missing id from the world %s " , itemName ) ;
missingIds . put ( entry . getKey ( ) , newId ) ;
continue ; // no block/item -> nothing to add
2015-11-28 21:30:58 +00:00
}
else if ( currId ! = newId )
{
2015-11-28 08:01:31 +00:00
FMLLog . fine ( " Fixed %s id mismatch %s: %d (init) -> %d (map). " , registryName , itemName , currId , newId ) ;
2015-11-28 21:30:58 +00:00
remappedIds . put ( itemName , new Integer [ ] { currId , newId } ) ;
2015-11-28 08:01:31 +00:00
}
I obj = currentRegistry . getRaw ( itemName ) ;
add ( newId , itemName , obj ) ;
}
}
2015-11-28 21:30:58 +00:00
public void blockId ( int id )
{
2015-11-28 08:01:31 +00:00
blockedIds . add ( id ) ;
}
2015-12-21 21:42:40 +00:00
2015-12-23 19:11:17 +00:00
public void notifyCallbacks ( )
2015-12-21 21:42:40 +00:00
{
if ( addCallback = = null )
return ;
for ( I i : this . underlyingIntegerMap )
{
2016-04-01 21:13:06 +00:00
addCallback . onAdd ( i , this . underlyingIntegerMap . add ( i ) , slaves ) ;
2015-12-21 21:42:40 +00:00
}
}
2015-12-23 19:11:17 +00:00
@Override
public ResourceLocation getNameForObject ( I p_177774_1_ )
{
2016-04-01 21:13:06 +00:00
ResourceLocation rl = super . getNameForObjectBypass ( p_177774_1_ ) ;
2015-12-23 19:11:17 +00:00
if ( rl = = null )
{
rl = activeSubstitutions . inverse ( ) . get ( p_177774_1_ ) ;
}
return rl ;
}
2016-04-01 21:13:06 +00:00
@Override
public Class < I > getRegistrySuperType ( )
{
return superType ;
}
// IForgeRegistry: Modders should only interfaces with these methods
@Override
public void register ( I value )
{
ResourceLocation key = value . getRegistryName ( ) ;
if ( key = = null )
{
FMLLog . severe ( " Attempted to register a entry with a null name: %s " , value ) ;
throw new NullPointerException ( String . format ( " Attempted to register a entry with a null name: %s " , value ) ) ;
}
add ( - 1 , key , value ) ;
}
@Override
public boolean containsValue ( I value )
{
return getKey ( value ) ! = null ;
}
@Override
public I getValue ( ResourceLocation key )
{
return getObject ( key ) ;
}
@Override
public ResourceLocation getKey ( I value )
{
return getNameForObject ( value ) ;
}
@Override
public List < I > getValues ( )
{
return Lists . newArrayList ( this . iterator ( ) ) ;
}
@Override
public Set < Entry < ResourceLocation , I > > getEntries ( )
{
return Sets . newHashSet ( new Iterator < Entry < ResourceLocation , I > > ( )
{
Iterator < I > itr = FMLControlledNamespacedRegistry . this . iterator ( ) ;
@Override
public boolean hasNext ( )
{
return itr . hasNext ( ) ;
}
@Override
public Entry < ResourceLocation , I > next ( )
{
final I value = itr . next ( ) ;
final ResourceLocation key = FMLControlledNamespacedRegistry . this . getKey ( value ) ;
return new Entry < ResourceLocation , I > ( )
{
@Override
public ResourceLocation getKey ( )
{
return key ;
}
@Override
public I getValue ( )
{
return value ;
}
@Override
public I setValue ( I value )
{
throw new UnsupportedOperationException ( " Setting the value in an iterator is not allowed " ) ;
}
} ;
}
@Override
public void remove ( )
{
throw new UnsupportedOperationException ( " This is a READ ONLY view of this registry. " ) ;
}
} ) ;
}
@SuppressWarnings ( " unchecked " )
@Override
public < T > T getSlaveMap ( ResourceLocation slaveMapName , Class < T > type )
{
return ( T ) slaves . get ( slaveMapName ) ;
}
2013-12-09 06:22:24 +00:00
}