2013-12-09 06:22:24 +00:00
package cpw.mods.fml.common.registry ;
import java.util.ArrayList ;
import java.util.BitSet ;
2014-03-20 11:41:59 +00:00
import java.util.Collections ;
import java.util.HashMap ;
2013-12-10 02:36:49 +00:00
import java.util.List ;
2013-12-09 06:22:24 +00:00
import java.util.Map ;
2014-04-01 05:00:20 +00:00
2013-12-10 02:36:49 +00:00
import net.minecraft.util.ObjectIntIdentityMap ;
import net.minecraft.util.RegistryNamespaced ;
2014-03-20 11:41:59 +00:00
2014-03-24 23:36:37 +00:00
import com.google.common.collect.ImmutableMap ;
2014-04-01 05:00:20 +00:00
2013-12-26 17:41:49 +00:00
import cpw.mods.fml.common.FMLLog ;
2013-12-09 06:22:24 +00:00
import cpw.mods.fml.common.Loader ;
import cpw.mods.fml.common.ModContainer ;
public class FMLControlledNamespacedRegistry < I > extends RegistryNamespaced {
private final Class < I > superType ;
private String optionalDefaultName ;
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 ;
2013-12-10 02:36:49 +00:00
private char discriminator ;
2014-03-27 07:30:55 +00:00
// aliases redirecting legacy names to the actual name, may need recursive application to find the final name.
// these need to be registry specific, it's possible to only have a loosely linked item for a block which may get renamed by itself.
2014-03-24 23:36:37 +00:00
private final Map < String , String > aliases = new HashMap < String , String > ( ) ;
2013-12-09 06:22:24 +00:00
2014-03-20 11:41:59 +00:00
FMLControlledNamespacedRegistry ( String optionalDefault , int maxIdValue , int minIdValue , Class < I > type , char discriminator )
2013-12-09 06:22:24 +00:00
{
this . superType = type ;
2013-12-10 02:36:49 +00:00
this . discriminator = discriminator ;
2013-12-09 06:22:24 +00:00
this . optionalDefaultName = optionalDefault ;
this . maxId = maxIdValue ;
this . minId = minIdValue ;
}
2014-03-27 07:30:55 +00:00
@SuppressWarnings ( " unchecked " )
2014-03-20 11:41:59 +00:00
void set ( FMLControlledNamespacedRegistry < I > registry )
2013-12-09 06:22:24 +00:00
{
2014-03-20 11:41:59 +00:00
if ( this . superType ! = registry . superType ) throw new IllegalArgumentException ( " incompatible registry " ) ;
2013-12-09 06:22:24 +00:00
2014-03-20 11:41:59 +00:00
this . discriminator = registry . discriminator ;
this . optionalDefaultName = registry . optionalDefaultName ;
this . maxId = registry . maxId ;
this . minId = registry . minId ;
2014-03-27 07:30:55 +00:00
this . aliases . clear ( ) ;
2014-03-24 23:36:37 +00:00
this . aliases . putAll ( registry . aliases ) ;
2014-04-01 05:00:20 +00:00
underlyingIntegerMap = new ObjectIntIdentityMap ( ) ;
registryObjects . clear ( ) ;
2013-12-26 17:41:49 +00:00
2014-03-27 07:30:55 +00:00
for ( I thing : ( Iterable < I > ) registry )
2013-12-26 17:41:49 +00:00
{
2014-04-06 15:11:23 +00:00
addObjectRaw ( registry . getId ( thing ) , registry . getNameForObject ( thing ) , thing ) ;
2013-12-26 17:41:49 +00:00
}
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 .
*
* @deprecated register through { @link GameRegistry } instead .
* /
@Override
@Deprecated
2014-04-01 05:00:20 +00:00
public void addObject ( int id , String name , Object thing )
2014-03-20 11:41:59 +00:00
{
GameData . getMain ( ) . register ( thing , name , id ) ;
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
public void putObject ( Object objName , Object obj )
{
String name = ( String ) objName ;
I thing = ( I ) obj ;
if ( name = = null ) throw new NullPointerException ( " Can't use a null-name for the registry. " ) ;
if ( name . isEmpty ( ) ) throw new IllegalArgumentException ( " Can't use an empty name for the registry. " ) ;
if ( thing = = null ) throw new NullPointerException ( " Can't add null-object to the registry. " ) ;
String existingName = getNameForObject ( thing ) ;
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 ) ;
addAlias ( name , existingName ) ;
}
}
2014-04-07 15:30:38 +00:00
/ * *
* Fetch the object identified by the specified name or the default object .
*
* 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
2014-03-19 07:15:53 +00:00
public I getObject ( String name )
2013-12-09 06:22:24 +00:00
{
2014-03-24 23:36:37 +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 .
*
* 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
/ * *
2014-04-01 05:00:20 +00:00
* @deprecated use getObjectById instead
2014-03-24 23:36:37 +00:00
* /
2014-04-01 05:00:20 +00:00
@Deprecated
2014-03-24 23:36:37 +00:00
public I get ( int id )
{
2014-04-01 05:00:20 +00:00
return getObjectById ( id ) ;
2014-03-24 23:36:37 +00:00
}
/ * *
2014-04-01 05:00:20 +00:00
* @deprecated use getObject instead
2014-03-24 23:36:37 +00:00
* /
2014-04-01 05:00:20 +00:00
@Deprecated
2014-03-24 23:36:37 +00:00
public I get ( String name )
{
2014-04-01 05:00:20 +00:00
return getObject ( name ) ;
2014-03-24 23:36:37 +00:00
}
2013-12-09 06:22:24 +00:00
2014-03-24 23:36:37 +00:00
/ * *
* Get the id for the specified object .
*
* Don ' t hold onto the id across the world , it ' s being dynamically re - mapped as needed .
*
* 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
{
2014-04-01 05:00:20 +00:00
return getIDForObject ( 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
{
2014-04-01 05:00:20 +00:00
return superType . cast ( super . getObjectById ( id ) ) ;
2013-12-10 02:36:49 +00:00
}
2013-12-09 06:22:24 +00:00
2014-03-24 23:36:37 +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 .
* /
public I getRaw ( String name )
2013-12-10 02:36:49 +00:00
{
2014-04-01 05:00:20 +00:00
I ret = superType . cast ( 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
{
2014-03-24 23:36:37 +00:00
name = aliases . get ( name ) ;
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 .
*
* 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
2014-04-01 05:00:20 +00:00
public boolean containsKey ( String 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
2014-04-01 05:00:20 +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 .
*
* Don ' t hold onto the id across the world , it ' s being dynamically re - mapped as needed .
*
* 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 .
* /
2014-03-24 23:36:37 +00:00
public int getId ( String itemName )
2013-12-09 06:22:24 +00:00
{
2014-03-24 23:36:37 +00:00
I obj = getRaw ( itemName ) ;
if ( obj = = null ) return - 1 ;
return getId ( obj ) ;
2013-12-09 06:22:24 +00:00
}
2013-12-10 02:36:49 +00:00
2014-04-01 05:00:20 +00:00
/ * *
* @deprecated use containsKey instead
* /
@Deprecated
2014-03-24 23:36:37 +00:00
public boolean contains ( String itemName )
2013-12-10 02:36:49 +00:00
{
2014-04-01 05:00:20 +00:00
return containsKey ( itemName ) ;
2013-12-10 02:36:49 +00:00
}
2014-03-24 23:36:37 +00:00
// internal
2014-03-27 07:30:55 +00:00
@SuppressWarnings ( " unchecked " )
2014-04-07 15:30:38 +00:00
public void serializeInto ( Map < String , Integer > idMapping ) // for saving
2013-12-10 02:36:49 +00:00
{
2014-03-27 07:30:55 +00:00
for ( I thing : ( Iterable < I > ) this )
2014-03-20 11:41:59 +00:00
{
2014-04-01 05:00:20 +00:00
idMapping . put ( discriminator + getNameForObject ( thing ) , getId ( thing ) ) ;
2014-03-20 11:41:59 +00:00
}
2013-12-10 02:36:49 +00:00
}
2014-04-07 15:30:38 +00:00
public Map < String , String > getAliases ( ) // for saving
2013-12-10 02:36:49 +00:00
{
2014-03-24 23:36:37 +00:00
return ImmutableMap . copyOf ( aliases ) ;
}
2014-03-20 11:41:59 +00:00
2014-04-07 15:30:38 +00:00
/ * *
* Add the specified object to the registry .
*
* @param id ID to use if available , auto - assigned otherwise .
* @param name Name to use , prefixed by the mod id .
* @param thing Object to add .
* @param availabilityMap Map marking available IDs for auto assignment .
* @return ID eventually allocated .
* /
2014-03-24 23:36:37 +00:00
int add ( int id , String name , I thing , BitSet availabilityMap )
{
2014-04-01 12:40:24 +00:00
if ( name = = null ) throw new NullPointerException ( " Can't use a null-name for the registry. " ) ;
if ( name . isEmpty ( ) ) throw new IllegalArgumentException ( " Can't use an empty name for the registry. " ) ;
2014-04-01 05:00:20 +00:00
if ( thing = = null ) throw new NullPointerException ( " Can't add null-object to the registry. " ) ;
2014-03-24 23:36:37 +00:00
if ( name . equals ( optionalDefaultName ) )
{
this . optionalDefaultObject = thing ;
}
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
}
ModContainer mc = Loader . instance ( ) . activeModContainer ( ) ;
if ( mc ! = null )
{
String prefix = mc . getModId ( ) ;
2014-04-09 20:21:04 +00:00
if ( name . contains ( " : " ) ) FMLLog . bigWarning ( " Illegal extra prefix %s for name %s, invalid registry invocation/invalid name? " , prefix , name ) ;
2014-03-24 23:36:37 +00:00
name = prefix + " : " + name ;
}
2014-04-01 12:40:24 +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-04-11 04:33:36 +00:00
if ( getId ( thing ) > = 0 ) // duplicate object
2014-04-01 12:40:24 +00:00
{
2014-04-11 04:33:36 +00:00
throw new IllegalArgumentException ( String . format ( " The object %s has been registered twice, using the names %s and %s. " , thing , getNameForObject ( thing ) , name ) ) ;
2014-04-01 12:40:24 +00:00
}
2014-04-06 12:49:59 +00:00
if ( GameData . isFrozen ( this ) )
{
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-04-06 15:11:23 +00:00
addObjectRaw ( idToUse , name , thing ) ;
2014-04-09 20:21:04 +00:00
FMLLog . finer ( " Registry add: %s %d %s (req. id %d) " , name , idToUse , thing , id ) ;
2014-03-24 23:36:37 +00:00
return idToUse ;
2013-12-10 02:36:49 +00:00
}
2014-03-24 23:36:37 +00:00
void addAlias ( String from , String to )
2013-12-10 02:36:49 +00:00
{
2014-03-24 23:36:37 +00:00
aliases . put ( from , to ) ;
2014-04-06 15:11:23 +00:00
FMLLog . finer ( " Registry alias: %s -> %s " , from , to ) ;
2014-03-24 23:36:37 +00:00
}
2014-03-27 07:30:55 +00:00
@SuppressWarnings ( " unchecked " )
2014-03-24 23:36:37 +00:00
Map < String , Integer > getEntriesNotIn ( FMLControlledNamespacedRegistry < I > registry )
{
Map < String , Integer > ret = new HashMap < String , Integer > ( ) ;
2014-03-27 07:30:55 +00:00
for ( I thing : ( Iterable < I > ) this )
2014-03-24 23:36:37 +00:00
{
2014-04-01 05:00:20 +00:00
if ( ! registry . field_148758_b . containsKey ( thing ) ) ret . put ( getNameForObject ( thing ) , getId ( thing ) ) ;
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
2014-03-27 07:30:55 +00:00
@SuppressWarnings ( " unchecked " )
2013-12-26 17:41:49 +00:00
void dump ( )
{
2014-03-20 11:41:59 +00:00
List < Integer > ids = new ArrayList < Integer > ( ) ;
2014-03-27 07:30:55 +00:00
for ( I thing : ( Iterable < I > ) this )
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 ) ;
for ( int id : ids )
{
I thing = getRaw ( id ) ;
2014-04-06 15:11:23 +00:00
FMLLog . finer ( " Registry: %s %d %s " , getNameForObject ( thing ) , id , 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 .
* /
private void addObjectRaw ( int id , String name , I thing )
{
2014-04-09 20:21:04 +00:00
if ( name = = null ) throw new NullPointerException ( " internal registry bug " ) ;
if ( thing = = null ) throw new NullPointerException ( " internal registry bug " ) ;
2014-04-06 15:11:23 +00:00
underlyingIntegerMap . func_148746_a ( thing , id ) ; // obj <-> id
super . putObject ( ensureNamespaced ( name ) , thing ) ; // name <-> obj
}
2013-12-09 06:22:24 +00:00
}