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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
@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-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-03-20 11:41:59 +00:00
|
|
|
public void serializeInto(Map<String, Integer> idMapping)
|
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-03-24 23:36:37 +00:00
|
|
|
public Map<String, String> getAliases()
|
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-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;
|
|
|
|
if (id == 0 || availabilityMap.get(id))
|
|
|
|
{
|
|
|
|
idToUse = availabilityMap.nextClearBit(minId);
|
|
|
|
}
|
|
|
|
if (idToUse >= maxId)
|
|
|
|
{
|
|
|
|
throw new RuntimeException(String.format("Invalid id %s - not accepted",id));
|
|
|
|
}
|
|
|
|
|
|
|
|
ModContainer mc = Loader.instance().activeModContainer();
|
|
|
|
if (mc != null)
|
|
|
|
{
|
|
|
|
String prefix = mc.getModId();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
if (getRaw(name) != null) // duplicate name, will crash later due to the BiMap
|
2014-04-01 12:40:24 +00:00
|
|
|
{
|
2014-04-06 15:11:23 +00:00
|
|
|
FMLLog.bigWarning("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-06 15:11:23 +00:00
|
|
|
if (getId(thing) >= 0) // duplicate object, will crash later due to the BiMap
|
2014-04-01 12:40:24 +00:00
|
|
|
{
|
2014-04-06 15:11:23 +00:00
|
|
|
FMLLog.bigWarning("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);
|
|
|
|
|
|
|
|
FMLLog.finer("Registry add: %s %d %s", name, idToUse, thing);
|
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)
|
|
|
|
{
|
|
|
|
if (name == null) throw new NullPointerException();
|
|
|
|
if (thing == null) throw new NullPointerException();
|
|
|
|
|
|
|
|
underlyingIntegerMap.func_148746_a(thing, id); // obj <-> id
|
|
|
|
super.putObject(ensureNamespaced(name), thing); // name <-> obj
|
|
|
|
}
|
2013-12-09 06:22:24 +00:00
|
|
|
}
|