ItemStack swapping

This commit is contained in:
cpw 2014-08-20 10:28:39 -04:00
parent 2ca75b3fa4
commit dddbbd3bac
11 changed files with 313 additions and 81 deletions

View file

@ -30,9 +30,9 @@ import net.minecraft.world.storage.WorldInfo;
import org.apache.logging.log4j.Level;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
@ -105,8 +105,8 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
// name <-> id mappings
NBTTagList dataList = new NBTTagList();
FMLLog.fine("Gathering id map for writing to world save %s", info.getWorldName());
Map<String,Integer> itemList = GameData.buildItemDataList();
for (Entry<String, Integer> item : itemList.entrySet())
GameData.GameDataSnapshot dataSnapshot = GameData.buildItemDataList();
for (Entry<String, Integer> item : dataSnapshot.idMap.entrySet())
{
NBTTagCompound tag = new NBTTagCompound();
tag.setString("K",item.getKey());
@ -126,15 +126,14 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
blockAliasList.appendTag(tag);
}
fmlData.setTag("BlockAliases", blockAliasList);
NBTTagList blockPersistentAliasList = new NBTTagList();
for (Entry<String, String> entry : GameData.getBlockRegistry().getPersistentAliases().entrySet())
NBTTagList blockSubstitutionsList = new NBTTagList();
for (String entry : dataSnapshot.blockSubstitutions)
{
NBTTagCompound tag = new NBTTagCompound();
tag.setString("K", entry.getKey());
tag.setString("V", entry.getValue());
blockPersistentAliasList.appendTag(tag);
tag.setString("K", entry);
blockSubstitutionsList.appendTag(tag);
}
fmlData.setTag("PersistentBlockAliases", blockPersistentAliasList);
fmlData.setTag("BlockSubstitutions", blockSubstitutionsList);
// item aliases
NBTTagList itemAliasList = new NBTTagList();
for (Entry<String, String> entry : GameData.getItemRegistry().getAliases().entrySet())
@ -146,15 +145,14 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
}
fmlData.setTag("ItemAliases", itemAliasList);
NBTTagList itemPersistentAliasList = new NBTTagList();
for (Entry<String, String> entry : GameData.getItemRegistry().getPersistentAliases().entrySet())
NBTTagList itemSubstitutionsList = new NBTTagList();
for (String entry : dataSnapshot.itemSubstitutions)
{
NBTTagCompound tag = new NBTTagCompound();
tag.setString("K", entry.getKey());
tag.setString("V", entry.getValue());
itemPersistentAliasList.appendTag(tag);
tag.setString("K", entry);
itemSubstitutionsList.appendTag(tag);
}
fmlData.setTag("ItemPersistentAliases", itemPersistentAliasList);
fmlData.setTag("ItemSubstitutions", itemSubstitutionsList);
return fmlData;
}
@ -209,7 +207,7 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
dataList.put(itemLabel, itemId);
}
}
failedElements = GameData.injectWorldIDMap(dataList, true, true);
failedElements = GameData.injectWorldIDMap(dataList, ImmutableSet.<String>of(), ImmutableSet.<String>of(), true, true);
}
else if (tag.hasKey("ItemData"))
@ -245,14 +243,14 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
NBTTagCompound dataTag = list.getCompoundTagAt(i);
blockAliases.put(dataTag.getString("K"), dataTag.getString("V"));
}
BiMap<String, String> blockPersistentAliases = HashBiMap.create();
if (tag.hasKey("BlockPersistentAliases", 10))
Set<String> blockSubstitutions = Sets.newHashSet();
if (tag.hasKey("BlockSubstitutions", 9))
{
list = tag.getTagList("BlockPersistentAliases", 10);
list = tag.getTagList("BlockSubstitutions", 10);
for (int i = 0; i < list.tagCount(); i++)
{
NBTTagCompound dataTag = list.getCompoundTagAt(i);
blockPersistentAliases.put(dataTag.getString("K"), dataTag.getString("V"));
blockSubstitutions.add(dataTag.getString("K"));
}
}
// item aliases
@ -264,17 +262,17 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
itemAliases.put(dataTag.getString("K"), dataTag.getString("V"));
}
BiMap<String, String> itemPersistentAliases = HashBiMap.create();
if (tag.hasKey("ItemPersistentAliases", 10))
Set<String> itemSubstitutions = Sets.newHashSet();
if (tag.hasKey("ItemSubstitutions", 9))
{
list = tag.getTagList("ItemPersistentAliases", 10);
list = tag.getTagList("ItemSubstitutions", 10);
for (int i = 0; i < list.tagCount(); i++)
{
NBTTagCompound dataTag = list.getCompoundTagAt(i);
itemPersistentAliases.put(dataTag.getString("K"), dataTag.getString("V"));
itemSubstitutions.add(dataTag.getString("K"));
}
}
failedElements = GameData.injectWorldIDMap(dataList, blockedIds, blockAliases, itemAliases, true, true);
failedElements = GameData.injectWorldIDMap(dataList, blockedIds, blockAliases, itemAliases, blockSubstitutions, itemSubstitutions, true, true);
}
if (failedElements != null && !failedElements.isEmpty())

View file

@ -32,7 +32,28 @@ public class FMLMissingMappingsEvent extends FMLEvent {
* @author cpw
*
*/
public static enum Action { DEFAULT, IGNORE, WARN, FAIL, REMAP }
public static enum Action {
/**
* Take the default action
*/
DEFAULT,
/**
* Ignore this missing mapping. This means the mapping will be abandoned
*/
IGNORE,
/**
* Generate a warning but allow loading to continue
*/
WARN,
/**
* Fail to load
*/
FAIL,
/**
* Remap this name to a new name (add a migration mapping)
*/
REMAP
}
public static class MissingMapping {
public final GameRegistry.Type type;
public final String name;

View file

@ -85,7 +85,7 @@ enum FMLHandshakeClientState implements IHandshakeState<FMLHandshakeClientState>
public FMLHandshakeClientState accept(ChannelHandlerContext ctx, FMLHandshakeMessage msg)
{
FMLHandshakeMessage.ModIdData modIds = (FMLHandshakeMessage.ModIdData)msg;
List<String> locallyMissing = GameData.injectWorldIDMap(modIds.dataList(), false, false);
List<String> locallyMissing = GameData.injectWorldIDMap(modIds.dataList(), modIds.blockSubstitutions(), modIds.itemSubstitutions(), false, false);
if (!locallyMissing.isEmpty())
{
NetworkDispatcher dispatcher = ctx.channel().attr(NetworkDispatcher.FML_DISPATCHER).get();

View file

@ -13,11 +13,13 @@ import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
import cpw.mods.fml.common.registry.GameData;
public abstract class FMLHandshakeMessage {
public static FMLProxyPacket makeCustomChannelRegistration(Set<String> channels)
@ -128,22 +130,43 @@ public abstract class FMLHandshakeMessage {
}
public ModIdData(Map<String,Integer> modIds)
public ModIdData(GameData.GameDataSnapshot snapshot)
{
this.modIds = modIds;
this.modIds = snapshot.idMap;
this.blockSubstitutions = snapshot.blockSubstitutions;
this.itemSubstitutions = snapshot.itemSubstitutions;
}
private Map<String,Integer> modIds;
private Set<String> blockSubstitutions;
private Set<String> itemSubstitutions;
@Override
public void fromBytes(ByteBuf buffer)
{
int length = ByteBufUtils.readVarInt(buffer, 3);
modIds = Maps.newHashMap();
blockSubstitutions = Sets.newHashSet();
itemSubstitutions = Sets.newHashSet();
for (int i = 0; i < length; i++)
{
modIds.put(ByteBufUtils.readUTF8String(buffer),ByteBufUtils.readVarInt(buffer, 3));
}
// we don't have any more data to read
if (!buffer.isReadable())
{
return;
}
length = ByteBufUtils.readVarInt(buffer, 3);
for (int i = 0; i < length; i++)
{
blockSubstitutions.add(ByteBufUtils.readUTF8String(buffer));
}
length = ByteBufUtils.readVarInt(buffer, 3);
for (int i = 0; i < length; i++)
{
itemSubstitutions.add(ByteBufUtils.readUTF8String(buffer));
}
}
@Override
@ -155,12 +178,33 @@ public abstract class FMLHandshakeMessage {
ByteBufUtils.writeUTF8String(buffer, entry.getKey());
ByteBufUtils.writeVarInt(buffer, entry.getValue(), 3);
}
ByteBufUtils.writeVarInt(buffer, blockSubstitutions.size(), 3);
for (String entry: blockSubstitutions)
{
ByteBufUtils.writeUTF8String(buffer, entry);
}
ByteBufUtils.writeVarInt(buffer, blockSubstitutions.size(), 3);
for (String entry: itemSubstitutions)
{
ByteBufUtils.writeUTF8String(buffer, entry);
}
}
public Map<String,Integer> dataList()
{
return modIds;
}
public Set<String> blockSubstitutions()
{
return blockSubstitutions;
}
public Set<String> itemSubstitutions()
{
return itemSubstitutions;
}
@Override
public String toString(Class<? extends Enum<?>> side)
{

View file

@ -1,9 +0,0 @@
package cpw.mods.fml.common.registry;
public class ExistingAliasException extends Exception {
public ExistingAliasException(String fromName, String toName) {
}
private static final long serialVersionUID = 1L;
}

View file

@ -0,0 +1,9 @@
package cpw.mods.fml.common.registry;
public class ExistingSubstitutionException extends Exception {
public ExistingSubstitutionException(String fromName, Object toReplace) {
}
private static final long serialVersionUID = 1L;
}

View file

@ -15,7 +15,6 @@ import net.minecraft.util.RegistryNamespaced;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableMap;
import cpw.mods.fml.common.FMLLog;
@ -31,7 +30,8 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
// 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.
private final Map<String, String> aliases = new HashMap<String, String>();
private BiMap<String, String> persistentAliases = HashBiMap.create();
private BiMap<String, I> persistentSubstitutions;
private BiMap<String, I> activeSubstitutions = HashBiMap.create();
FMLControlledNamespacedRegistry(String optionalDefault, int maxIdValue, int minIdValue, Class<I> type, char discriminator)
{
@ -62,9 +62,9 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
// id -> obj lookup is inconsistent
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, type, obj));
// name -> obj lookup is inconsistent
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, type, obj));
if (!(activeSubstitutions.containsKey(name) || activeSubstitutions.containsValue(name)) && getRaw(name) != obj ) throw new IllegalStateException(String.format("Registry entry for name %s, id %d, doesn't yield the expected %s %s.", name, id, type, obj));
// name -> id lookup is inconsistent
if (getId(name) != id) throw new IllegalStateException(String.format("Registry entry for name %s doesn't yield the expected id %d.", name, id));
if (!(activeSubstitutions.containsKey(name) || activeSubstitutions.containsValue(name)) && getId(name) != id) throw new IllegalStateException(String.format("Registry entry for name %s doesn't yield the expected id %d.", name, id));
// id isn't marked as unavailable
if (!availabilityMap.get(id)) throw new IllegalStateException(String.format("Registry entry for %s %s, id %d, name %s, marked as empty.", type, obj, id, name));
// entry is blocked, thus should be empty
@ -235,9 +235,6 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
*/
public I getRaw(String name)
{
String aliasName = persistentAliases.get(name);
name = aliasName != null ? aliasName : name;
I ret = superType.cast(super.getObject(name));
if (ret == null) // no match, try aliases recursively
@ -322,10 +319,6 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
return ImmutableMap.copyOf(aliases);
}
public Map<String, String> getPersistentAliases()
{
return ImmutableBiMap.copyOf(persistentAliases);
}
/**
* Add the specified object to the registry.
*
@ -345,7 +338,10 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
{
this.optionalDefaultObject = thing;
}
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)));
}
int idToUse = id;
if (idToUse < 0 || availabilityMap.get(idToUse))
{
@ -365,7 +361,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
{
throw new IllegalArgumentException(String.format("The name %s has been registered twice, for %s and %s.", name, getRaw(name), thing));
}
if (getId(thing) >= 0) // duplicate object
if (getId(thing) >= 0) // duplicate object - but only if it's not being substituted
{
int foundId = getId(thing);
Object otherThing = getRaw(foundId);
@ -376,6 +372,10 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
FMLLog.bigWarning("The object %s (name %s) is being added too late.", thing, name);
}
if (activeSubstitutions.containsKey(name))
{
thing = activeSubstitutions.get(name);
}
addObjectRaw(idToUse, name, thing);
FMLLog.finer("Registry add: %s %d %s (req. id %d)", name, idToUse, thing, id);
@ -394,7 +394,13 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
for (I thing : this.typeSafeIterable())
{
if (!registry.field_148758_b.containsKey(thing)) ret.put(getNameForObject(thing), getId(thing));
if (!registry.field_148758_b.containsKey(thing))
{
if (!registry.activeSubstitutions.containsKey(getNameForObject(thing)))
{
ret.put(getNameForObject(thing), getId(thing));
}
}
}
return ret;
@ -441,11 +447,54 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
return GameData.buildDelegate(thing, clazz);
}
public void addPersistentAlias(String fromName, String toName) throws ExistingAliasException {
if (persistentAliases.containsKey(fromName) || persistentAliases.containsKey(toName) || persistentAliases.containsValue(fromName) || persistentAliases.containsValue(toName))
void activateSubstitution(String nameToReplace)
{
if (getPersistentSubstitutions().containsKey(nameToReplace))
{
throw new ExistingAliasException(fromName, toName);
activeSubstitutions.put(nameToReplace, getPersistentSubstitutions().get(nameToReplace));
}
persistentAliases.put(fromName, toName);
}
public void addSubstitutionAlias(String modId, String nameToReplace, Object toReplace) throws ExistingSubstitutionException {
if (getPersistentSubstitutions().containsKey(nameToReplace) || getPersistentSubstitutions().containsValue(toReplace))
{
FMLLog.severe("The substitution of %s has already occured. You cannot duplicate substitutions", nameToReplace);
throw new ExistingSubstitutionException(nameToReplace, toReplace);
}
I replacement = superType.cast(toReplace);
I original = getRaw(nameToReplace);
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");
}
getPersistentSubstitutions().put(nameToReplace, replacement);
}
public void serializeSubstitutions(Set<String> blockSubs)
{
blockSubs.addAll(activeSubstitutions.keySet());
}
@Override
public int getIDForObject(Object p_148757_1_)
{
int id = super.getIDForObject(p_148757_1_);
return id;
}
private BiMap<String, I> getPersistentSubstitutions()
{
if (persistentSubstitutions == null)
{
persistentSubstitutions = GameData.getMain().getPersistentSubstitutionMap(superType);
}
return persistentSubstitutions;
}
}

View file

@ -34,11 +34,14 @@ import org.apache.logging.log4j.Level;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Joiner.MapJoiner;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Table;
import com.google.common.io.Files;
@ -112,12 +115,27 @@ public class GameData {
// internal from here
public static Map<String,Integer> buildItemDataList()
public static class GameDataSnapshot {
public final Map<String,Integer> idMap;
public final Set<String> blockSubstitutions;
public final Set<String> itemSubstitutions;
public GameDataSnapshot(Map<String, Integer> idMap, Set<String> blockSubstitutions, Set<String> itemSubstitutions)
{
this.idMap = idMap;
this.blockSubstitutions = blockSubstitutions;
this.itemSubstitutions = itemSubstitutions;
}
}
public static GameDataSnapshot buildItemDataList()
{
Map<String,Integer> idMapping = Maps.newHashMap();
getMain().iBlockRegistry.serializeInto(idMapping);
getMain().iItemRegistry.serializeInto(idMapping);
return idMapping;
Set<String> blockSubs = Sets.newHashSet();
getMain().iBlockRegistry.serializeSubstitutions(blockSubs);
Set<String> itemSubs = Sets.newHashSet();
getMain().iItemRegistry.serializeSubstitutions(itemSubs);
return new GameDataSnapshot(idMapping, blockSubs, itemSubs);
}
public static int[] getBlockedIds()
@ -407,12 +425,12 @@ public class GameData {
blockedIds.addAll(newBlockedIds);
}
public static List<String> injectWorldIDMap(Map<String, Integer> dataList, boolean injectFrozenData, boolean isLocalWorld)
public static List<String> injectWorldIDMap(Map<String, Integer> dataList, Set<String> blockSubstitutions, Set<String> itemSubstitutions, boolean injectFrozenData, boolean isLocalWorld)
{
return injectWorldIDMap(dataList, new HashSet<Integer>(), new HashMap<String, String>(), new HashMap<String, String>(), injectFrozenData, isLocalWorld);
return injectWorldIDMap(dataList, new HashSet<Integer>(), new HashMap<String, String>(), new HashMap<String, String>(), blockSubstitutions, itemSubstitutions, injectFrozenData, isLocalWorld);
}
public static List<String> injectWorldIDMap(Map<String, Integer> dataList, Set<Integer> blockedIds, Map<String, String> blockAliases, Map<String, String> itemAliases, boolean injectFrozenData, boolean isLocalWorld)
public static List<String> injectWorldIDMap(Map<String, Integer> dataList, Set<Integer> blockedIds, Map<String, String> blockAliases, Map<String, String> itemAliases, Set<String> blockSubstitutions, Set<String> itemSubstitutions, boolean injectFrozenData, boolean isLocalWorld)
{
FMLLog.info("Injecting existing block and item data into this %s instance", FMLCommonHandler.instance().getEffectiveSide().isServer() ? "server" : "client");
Map<String, Integer[]> remaps = Maps.newHashMap();
@ -438,6 +456,31 @@ public class GameData {
newData.iItemRegistry.addAlias(entry.getKey(), entry.getValue());
}
for (String entry : blockSubstitutions)
{
newData.iBlockRegistry.activateSubstitution(entry);
}
for (String entry : itemSubstitutions)
{
newData.iItemRegistry.activateSubstitution(entry);
}
if (injectFrozenData)
{
for (String newBlockSubstitution : getMain().blockSubstitutions.keySet())
{
if (!blockSubstitutions.contains(newBlockSubstitution))
{
newData.iBlockRegistry.activateSubstitution(newBlockSubstitution);
}
}
for (String newItemSubstitution : getMain().itemSubstitutions.keySet())
{
if (!itemSubstitutions.contains(newItemSubstitution))
{
newData.iItemRegistry.activateSubstitution(newItemSubstitution);
}
}
}
// process blocks and items in the world, blocks in the first pass, items in the second
// blocks need to be added first for proper ItemBlock handling
for (int pass = 0; pass < 2; pass++)
@ -479,10 +522,11 @@ public class GameData {
if (currId != newId)
{
throw new IllegalStateException(String.format("Can't map %s %s to id %d, already occupied by %s, blocked %b, ItemBlock %b",
throw new IllegalStateException(String.format("Can't map %s %s to id %d (seen at: %d), already occupied by %s, blocked %b, ItemBlock %b",
isBlock ? "block" : "item",
itemName,
newId,
currId,
isBlock ? newData.iBlockRegistry.getRaw(newId) : newData.iItemRegistry.getRaw(newId),
newData.blockedIds.contains(newId),
isBlock ? false : (getMain().iItemRegistry.getRaw(currId) instanceof ItemBlock)));
@ -763,6 +807,10 @@ public class GameData {
if (item instanceof ItemBlock) // ItemBlock, adjust id and clear the slot already occupied by the corresponding block
{
Block block = ((ItemBlock) item).field_150939_a;
if (idHint != -1 && getMain().blockSubstitutions.containsKey(name))
{
block = getMain().blockSubstitutions.get(name);
}
int id = iBlockRegistry.getId(block);
if (id == -1) // ItemBlock before its Block
@ -948,13 +996,32 @@ public class GameData {
FMLLog.fine("Registry consistency check successful");
}
void registerPersistentAlias(String fromName, String toName, GameRegistry.Type type) throws ExistingAliasException
void registerSubstitutionAlias(String nameToSubstitute, Type type, Object toReplace) throws ExistingSubstitutionException
{
type.getRegistry().addPersistentAlias(fromName, toName);
type.getRegistry().addSubstitutionAlias(Loader.instance().activeModContainer().getModId(),nameToSubstitute, toReplace);
}
static <T> RegistryDelegate<T> buildDelegate(T referant, Class<T> type)
{
return new RegistryDelegate.Delegate<T>(referant, type);
}
private BiMap<String, Item> itemSubstitutions = HashBiMap.create();
private BiMap<String, Block> blockSubstitutions = HashBiMap.create();
@SuppressWarnings("unchecked")
<T> BiMap<String, T> getPersistentSubstitutionMap(Class<T> type)
{
if (type.equals(Item.class))
{
return (BiMap<String, T>) itemSubstitutions;
}
else if (type.equals(Block.class))
{
return (BiMap<String, T>) blockSubstitutions;
}
else
{
throw new RuntimeException("WHAT?");
}
}
}

View file

@ -146,18 +146,19 @@ public class GameRegistry
/**
* Add a forced persistent alias for the block or item to another block or item. This will have
* the effect of using the substituted block or item instead of the original, whereever it is
* Add a forced persistent substitution alias for the block or item to another block or item. This will have
* the effect of using the substituted block or item instead of the original, where ever it is
* referenced.
*
* @param toName The name to link to (this is the NEW block or item)
* @param fromName The name to link from (this is the OLD block or item being substituted)
*
* @param nameToSubstitute The name to link to (this is the NEW block or item)
* @param type The type (Block or Item)
* @throws ExistingAliasException if someone else has already registered an alias either from or to one of the names
* @param object a NEW instance that is type compatible with the existing instance
* @throws ExistingSubstitutionException if someone else has already registered an alias either from or to one of the names
* @throws IncompatibleSubstitutionException if the substitution is incompatible
*/
public static void addAlias(String toName, String fromName, GameRegistry.Type type) throws ExistingAliasException
public static void addSubstitutionAlias(String nameToSubstitute, GameRegistry.Type type, Object object) throws ExistingSubstitutionException
{
GameData.getMain().registerPersistentAlias(fromName, toName, type);
GameData.getMain().registerSubstitutionAlias(nameToSubstitute, type, object);
}
/**
@ -406,7 +407,7 @@ public class GameRegistry
}
}
public static enum Type {
public static enum Type {
BLOCK
{
@Override

View file

@ -0,0 +1,10 @@
package cpw.mods.fml.common.registry;
public class IncompatibleSubstitutionException extends RuntimeException {
public IncompatibleSubstitutionException(String fromName, Object replacement, Object original)
{
}
private static final long serialVersionUID = 1L;
}

View file

@ -1,29 +1,53 @@
package cpw.mods.fml.common.registry;
import com.google.common.base.Objects;
/**
* A registry delegate for holding references to items or blocks
*
* These should be safe to use in things like lists though aliased items and blocks will not
* have object identity with respect to their delegate.
*
* @author cpw
*
* @param <T> the type of thing we're holding onto
*/
public interface RegistryDelegate<T> {
/**
* Get the referent pointed at by this delegate. This will be the currently active item or block, and will change
* as world saves come and go. Note that item.delegate.get() may NOT be the same object as item, due to item and
* block substitution.
*
* @return The referred object
*/
T get();
/**
* Get the name of this delegate. This is completely static after registration has completed and will never change.
* @return The name
*/
String name();
/**
* Get the delegate type. It will be Item or Block.
* @return The type of delegate
*/
Class<T> type();
/*
* This is the internal implementation class of the delegate.
*/
final class Delegate<T> implements RegistryDelegate<T>
{
private T referant;
private String name;
private final Class<T> type;
public Delegate(T referant, Class<T> type) {
this.referant = referant;
this.type = type;
}
@Override
public T get() {
return referant;
@ -34,19 +58,37 @@ public interface RegistryDelegate<T> {
return name;
}
@Override
public Class<T> type()
{
return this.type;
}
void changeReference(T newTarget)
{
this.referant = newTarget;
}
void setName(String name)
{
this.name = name;
}
@Override
public boolean equals(Object obj)
{
if (obj instanceof Delegate)
{
Delegate<?> other = (Delegate<?>) obj;
return Objects.equal(other.name, name);
}
return false;
}
@Override
public int hashCode()
{
return Objects.hashCode(name);
}
}
}