Registry: Protect against putObject misuse, handle duplicate registrations better

This commit is contained in:
Player 2014-04-06 17:11:23 +02:00
parent 6ffbcc5903
commit 07d5d5c7af
3 changed files with 96 additions and 46 deletions

View file

@ -45,6 +45,13 @@ public class FMLLog
log(Level.ERROR, format, data);
}
public static void bigWarning(String format, Object... data)
{
log(Level.WARN, "****************************************");
log(Level.WARN, "* "+format, data);
log(Level.WARN, "****************************************");
}
public static void warning(String format, Object... data)
{
log(Level.WARN, format, data);

View file

@ -52,7 +52,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
for (I thing : (Iterable<I>) registry)
{
super.addObject(registry.getId(thing), registry.getNameForObject(thing), thing);
addObjectRaw(registry.getId(thing), registry.getNameForObject(thing), thing);
}
}
@ -70,6 +70,39 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
GameData.getMain().register(thing, name, id);
}
/**
* 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);
}
}
@Override
public I getObject(String name)
{
@ -235,33 +268,34 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
name = prefix + ":"+ name;
}
if (getRaw(name) != null)
if (getRaw(name) == thing) // already registered, return prev registration's id
{
FMLLog.warning("****************************************");
FMLLog.warning("* The name %s has been registered twice, for %s and %s.", name, getRaw(name), thing);
FMLLog.warning("****************************************");
FMLLog.bigWarning("The object %s has been registered twice for the same name %s.", thing, name);
return getId(thing);
}
if (getId(thing) >= 0)
if (getRaw(name) != null) // duplicate name, will crash later due to the BiMap
{
FMLLog.warning("****************************************");
FMLLog.warning("* The object %s has been registered twice, using the names %s and %s.", thing, getNameForObject(thing), name);
FMLLog.warning("****************************************");
FMLLog.bigWarning("The name %s has been registered twice, for %s and %s.", name, getRaw(name), thing);
}
if (getId(thing) >= 0) // duplicate object, will crash later due to the BiMap
{
FMLLog.bigWarning("The object %s has been registered twice, using the names %s and %s.", thing, getNameForObject(thing), name);
}
if (GameData.isFrozen(this))
{
FMLLog.warning("****************************************");
FMLLog.warning("* The object %s (name %s) is being added too late.", thing, name);
FMLLog.warning("****************************************");
FMLLog.bigWarning("The object %s (name %s) is being added too late.", thing, name);
}
super.addObject(idToUse, name, thing);
FMLLog.finer("Add : %s %d %s", name, idToUse, thing);
addObjectRaw(idToUse, name, thing);
FMLLog.finer("Registry add: %s %d %s", name, idToUse, thing);
return idToUse;
}
void addAlias(String from, String to)
{
aliases.put(from, to);
FMLLog.finer("Registry alias: %s -> %s", from, to);
}
@SuppressWarnings("unchecked")
@ -293,7 +327,19 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
for (int id : ids)
{
I thing = getRaw(id);
FMLLog.finer("Registry : %s %d %s", getNameForObject(thing), id, thing);
FMLLog.finer("Registry: %s %d %s", getNameForObject(thing), id, thing);
}
}
/**
* 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
}
}

View file

@ -740,10 +740,7 @@ public class GameData {
throw new IllegalStateException(String.format("The Item Registry slot %d is already used by %s", idHint, iItemRegistry.getObjectById(idHint)));
}
if (!freeSlot(idHint)) // temporarily free the slot occupied by the Block for the ItemBlock registration
{
throw new IllegalStateException(String.format("The Registry slot %d is supposed to be blocked by the ItemBlock's Block's blockId at this point.", idHint));
}
freeSlot(idHint); // temporarily free the slot occupied by the Block for the item registration
}
int itemId = iItemRegistry.add(idHint, name, item, availabilityMap);
@ -756,11 +753,8 @@ public class GameData {
}
}
// normal item, block the Block Registry slot with the same id
if (useSlot(itemId))
{
throw new IllegalStateException(String.format("Registry slot %d is supposed to be empty when adding a non-ItemBlock with the same id.", itemId));
}
// block the Block Registry slot with the same id
useSlot(itemId);
return itemId;
}
@ -779,10 +773,7 @@ public class GameData {
}
int blockId = iBlockRegistry.add(idHint, name, block, availabilityMap);
if (useSlot(blockId))
{
throw new IllegalStateException(String.format("Registry slot %d is supposed to be empty when adding a Block with the same id.", blockId));
}
useSlot(blockId);
return blockId;
}
@ -796,18 +787,14 @@ public class GameData {
useSlot(id);
}
private boolean useSlot(int id)
private void useSlot(int id)
{
boolean oldValue = availabilityMap.get(id);
availabilityMap.set(id);
return oldValue;
}
private boolean freeSlot(int id)
private void freeSlot(int id)
{
boolean oldValue = availabilityMap.get(id);
availabilityMap.clear(id);
return oldValue;
}
@SuppressWarnings("unchecked")
@ -825,14 +812,19 @@ public class GameData {
for (Block block : (Iterable<Block>) iBlockRegistry)
{
int id = iBlockRegistry.getId(block);
String name = iBlockRegistry.getNameForObject(block);
if (!availabilityMap.get(id))
{
throw new IllegalStateException(String.format("Registry entry for block %s, id %d, marked as empty.", block, id));
if (id < 0) {
throw new IllegalStateException(String.format("Registry entry for block %s, name %s, doesn't yield an id", block, name));
}
if (blockedIds.contains(id))
{
throw new IllegalStateException(String.format("Registry entry for block %s, id %d, marked as dangling.", block, id));
if (name == null) {
throw new IllegalStateException(String.format("Registry entry for block %s, id %d, doesn't yield a name", block, id));
}
if (!availabilityMap.get(id)) {
throw new IllegalStateException(String.format("Registry entry for block %s, id %d, name %s, marked as empty.", block, id, name));
}
if (blockedIds.contains(id)) {
throw new IllegalStateException(String.format("Registry entry for block %s, id %d, name %s, marked as dangling.", block, id, name));
}
}
@ -841,14 +833,19 @@ public class GameData {
for (Item item : (Iterable<Item>) iItemRegistry)
{
int id = iItemRegistry.getId(item);
String name = iItemRegistry.getNameForObject(item);
if (!availabilityMap.get(id))
{
throw new IllegalStateException(String.format("Registry entry for item %s, id %d, marked as empty.", item, id));
if (id < 0) {
throw new IllegalStateException(String.format("Registry entry for item %s, name %s, doesn't yield an id", item, name));
}
if (blockedIds.contains(id))
{
throw new IllegalStateException(String.format("Registry entry for item %s, id %d, marked as dangling.", item, id));
if (name == null) {
throw new IllegalStateException(String.format("Registry entry for item %s, id %d, doesn't yield a name", item, id));
}
if (!availabilityMap.get(id)) {
throw new IllegalStateException(String.format("Registry entry for item %s, id %d, name %s, marked as empty.", item, id, name));
}
if (blockedIds.contains(id)) {
throw new IllegalStateException(String.format("Registry entry for item %s, id %d, name %s, marked as dangling.", item, id, name));
}
if (item instanceof ItemBlock)