Registry: Add support for registering ItemBlocks before their Blocks
This commit is contained in:
parent
07d5d5c7af
commit
ea2972725a
2 changed files with 114 additions and 24 deletions
|
@ -103,6 +103,14 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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-
|
||||
*/
|
||||
@Override
|
||||
public I getObject(String name)
|
||||
{
|
||||
|
@ -110,6 +118,14 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
|
|||
return object == null ? this.optionalDefaultObject : object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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-
|
||||
*/
|
||||
@Override
|
||||
public I getObjectById(int id)
|
||||
{
|
||||
|
@ -182,6 +198,14 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public boolean containsKey(String name)
|
||||
{
|
||||
|
@ -228,7 +252,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
|
|||
// internal
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void serializeInto(Map<String, Integer> idMapping)
|
||||
public void serializeInto(Map<String, Integer> idMapping) // for saving
|
||||
{
|
||||
for (I thing : (Iterable<I>) this)
|
||||
{
|
||||
|
@ -236,11 +260,20 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
|
|||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getAliases()
|
||||
public Map<String, String> getAliases() // for saving
|
||||
{
|
||||
return ImmutableMap.copyOf(aliases);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
int add(int id, String name, I thing, BitSet availabilityMap)
|
||||
{
|
||||
if (name == null) throw new NullPointerException("Can't use a null-name for the registry.");
|
||||
|
@ -256,9 +289,9 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
|
|||
{
|
||||
idToUse = availabilityMap.nextClearBit(minId);
|
||||
}
|
||||
if (idToUse >= maxId)
|
||||
if (idToUse > maxId)
|
||||
{
|
||||
throw new RuntimeException(String.format("Invalid id %s - not accepted",id));
|
||||
throw new RuntimeException(String.format("Invalid id %d - maximum id range exceeded.", id));
|
||||
}
|
||||
|
||||
ModContainer mc = Loader.instance().activeModContainer();
|
||||
|
|
|
@ -56,6 +56,11 @@ import cpw.mods.fml.common.registry.GameRegistry.Type;
|
|||
import cpw.mods.fml.common.registry.GameRegistry.UniqueIdentifier;
|
||||
|
||||
public class GameData {
|
||||
private static final int MIN_BLOCK_ID = 0;
|
||||
private static final int MAX_BLOCK_ID = 4095;
|
||||
private static final int MIN_ITEM_ID = 4096;
|
||||
private static final int MAX_ITEM_ID = 31999;
|
||||
|
||||
private static final GameData mainData = new GameData();
|
||||
|
||||
/**
|
||||
|
@ -233,7 +238,7 @@ public class GameData {
|
|||
*/
|
||||
public static void fixBrokenIds(Map<String, Integer> dataList, Set<Integer> blockedIds)
|
||||
{
|
||||
BitSet availabilityMap = new BitSet(32000);
|
||||
BitSet availabilityMap = new BitSet(MAX_ITEM_ID + 1);
|
||||
|
||||
// reserve all ids occupied by blocks
|
||||
for (Entry<String, Integer> entry : dataList.entrySet())
|
||||
|
@ -675,9 +680,9 @@ public class GameData {
|
|||
|
||||
private GameData()
|
||||
{
|
||||
iBlockRegistry = new FMLControlledNamespacedRegistry<Block>("air", 4095, 0, Block.class,'\u0001');
|
||||
iItemRegistry = new FMLControlledNamespacedRegistry<Item>(null, 32000, 4096, Item.class,'\u0002');
|
||||
availabilityMap = new BitSet(32000);
|
||||
iBlockRegistry = new FMLControlledNamespacedRegistry<Block>("air", MAX_BLOCK_ID, MIN_BLOCK_ID, Block.class,'\u0001');
|
||||
iItemRegistry = new FMLControlledNamespacedRegistry<Item>(null, MAX_ITEM_ID, MIN_ITEM_ID, Item.class,'\u0002');
|
||||
availabilityMap = new BitSet(MAX_ITEM_ID + 1);
|
||||
blockedIds = new HashSet<Integer>();
|
||||
}
|
||||
|
||||
|
@ -725,32 +730,29 @@ public class GameData {
|
|||
ModContainer mc = Loader.instance().activeModContainer();
|
||||
customOwners.put(new UniqueIdentifier(modId, name), mc);
|
||||
}
|
||||
if (item instanceof ItemBlock)
|
||||
if (item instanceof ItemBlock) // ItemBlock, adjust id and clear the slot already occupied by the corresponding block
|
||||
{
|
||||
// ItemBlock, clear the item slot already occupied by the corresponding block
|
||||
idHint = iBlockRegistry.getId(((ItemBlock) item).field_150939_a);
|
||||
Block block = ((ItemBlock) item).field_150939_a;
|
||||
idHint = iBlockRegistry.getId(block);
|
||||
|
||||
if (idHint == -1)
|
||||
if (idHint == -1) // ItemBlock before its Block
|
||||
{
|
||||
throw new RuntimeException("Cannot register an itemblock before its block");
|
||||
idHint = availabilityMap.nextClearBit(MIN_BLOCK_ID); // find suitable id here, iItemRegistry would search from MIN_ITEM_ID
|
||||
if (idHint > MAX_BLOCK_ID) throw new RuntimeException(String.format("Invalid id %d - maximum id range exceeded.", idHint));
|
||||
}
|
||||
|
||||
if (iItemRegistry.getObjectById(idHint) != null)
|
||||
else // ItemBlock after its Block
|
||||
{
|
||||
throw new IllegalStateException(String.format("The Item Registry slot %d is already used by %s", idHint, iItemRegistry.getObjectById(idHint)));
|
||||
FMLLog.fine("Found matching Block %s for ItemBlock %s at id %d", block, item, idHint);
|
||||
freeSlot(idHint, item); // temporarily free the slot occupied by the Block for the item registration
|
||||
}
|
||||
|
||||
freeSlot(idHint); // temporarily free the slot occupied by the Block for the item registration
|
||||
}
|
||||
|
||||
int itemId = iItemRegistry.add(idHint, name, item, availabilityMap);
|
||||
|
||||
if (item instanceof ItemBlock)
|
||||
if (item instanceof ItemBlock) // verify
|
||||
{
|
||||
if (itemId != idHint) // just in case of bugs...
|
||||
{
|
||||
throw new IllegalStateException("ItemBlock insertion failed.");
|
||||
}
|
||||
if (itemId != idHint) throw new IllegalStateException("Block -> ItemBlock insertion failed.");
|
||||
verifyItemBlockName((ItemBlock) item);
|
||||
}
|
||||
|
||||
// block the Block Registry slot with the same id
|
||||
|
@ -771,8 +773,35 @@ public class GameData {
|
|||
ModContainer mc = Loader.instance().activeModContainer();
|
||||
customOwners.put(new UniqueIdentifier(modId, name), mc);
|
||||
}
|
||||
|
||||
// handle ItemBlock-before-Block registrations
|
||||
ItemBlock itemBlock = null;
|
||||
|
||||
for (Item item : (Iterable<Item>) iItemRegistry) // find matching ItemBlock
|
||||
{
|
||||
if (item instanceof ItemBlock && ((ItemBlock) item).field_150939_a == block)
|
||||
{
|
||||
itemBlock = (ItemBlock) item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (itemBlock != null) // has ItemBlock, adjust id and clear the slot already occupied by the corresponding item
|
||||
{
|
||||
idHint = iItemRegistry.getId(itemBlock);
|
||||
FMLLog.fine("Found matching ItemBlock %s for Block %s at id %d", itemBlock, block, idHint);
|
||||
freeSlot(idHint, block); // temporarily free the slot occupied by the Item for the block registration
|
||||
}
|
||||
|
||||
// add
|
||||
int blockId = iBlockRegistry.add(idHint, name, block, availabilityMap);
|
||||
|
||||
if (itemBlock != null) // verify
|
||||
{
|
||||
if (blockId != idHint) throw new IllegalStateException("ItemBlock -> Block insertion failed.");
|
||||
verifyItemBlockName(itemBlock);
|
||||
}
|
||||
|
||||
useSlot(blockId);
|
||||
|
||||
return blockId;
|
||||
|
@ -792,11 +821,39 @@ public class GameData {
|
|||
availabilityMap.set(id);
|
||||
}
|
||||
|
||||
private void freeSlot(int id)
|
||||
/**
|
||||
* Free the specified slot.
|
||||
*
|
||||
* The slot must not be occupied by something else than the specified object within the same type.
|
||||
* The same object is permitted for handling duplicate registrations.
|
||||
*
|
||||
* @param id id to free
|
||||
* @param obj object allowed besides different types (block vs item)
|
||||
*/
|
||||
private void freeSlot(int id, Object obj)
|
||||
{
|
||||
FMLControlledNamespacedRegistry<?> registry = (obj instanceof Block) ? iBlockRegistry : iItemRegistry;
|
||||
Object thing = registry.getRaw(id);
|
||||
|
||||
if (thing != null && thing != obj)
|
||||
{
|
||||
throw new IllegalStateException(String.format("Can't free registry slot %d occupied by %s", id, thing));
|
||||
}
|
||||
|
||||
availabilityMap.clear(id);
|
||||
}
|
||||
|
||||
private void verifyItemBlockName(ItemBlock item)
|
||||
{
|
||||
String blockName = iBlockRegistry.getNameForObject(item.field_150939_a);
|
||||
String itemName = iItemRegistry.getNameForObject(item);
|
||||
|
||||
if (blockName != null && !blockName.equals(itemName))
|
||||
{
|
||||
FMLLog.bigWarning("Block <-> ItemBlock name mismatch, block name %s, item name %s", blockName, itemName);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void testConsistency() {
|
||||
// test if there's an entry for every set bit in availabilityMap
|
||||
|
|
Loading…
Reference in a new issue